Ctrl K
ComunidadGuías…

scripts/generate-codex-rpc.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env node
// Deterministic, dependency-free bindings for the stable protocol subset we use.
import fs from 'node:fs';
import path from 'node:path';
import crypto from 'node:crypto';
import {execFileSync} from 'node:child_process';
const root = path.resolve(import.meta.dirname, '../pkg/adapters/codexrpc');
const version = '0.153.0';
const inputs = ['v1/InitializeParams', 'v1/InitializeResponse', 'v2/ThreadStartParams', 'v2/ThreadStartResponse', 'v2/ThreadResumeParams', 'v2/ThreadResumeResponse', 'v2/TurnStartParams', 'v2/TurnStartResponse', 'v2/TurnInterruptParams', 'v2/TurnInterruptResponse', 'v2/TurnStartedNotification', 'v2/TurnCompletedNotification', 'v2/ItemStartedNotification', 'v2/ItemCompletedNotification', 'v2/ErrorNotification', 'v2/PluginInstallParams', 'v2/PluginInstallResponse'];
const schemaFile = path.join(root, 'schema/protocol.json');
if (process.argv[2] && process.argv[2] !== '--check') {
  const installed = execFileSync(process.env.CODEX_BIN || 'codex', ['--version'], {encoding:'utf8'}).trim();
  if (installed !== 'codex-cli ' + version) throw new Error('Schema refresh requires pinned Codex ' + version);
  const all = {}, selected = {};
  for (const name of inputs) {
    const schema = JSON.parse(fs.readFileSync(path.join(process.argv[2], name + '.json')));
    Object.assign(all, schema.definitions);
    const {$schema, definitions, ...body} = schema;
    all[schema.title] = body;
  }
  function visit(name) {
    if (selected[name]) return;
    if (!all[name]) throw new Error('Unresolved definition ' + name);
    selected[name] = all[name];
    function walk(value) {
      if (Array.isArray(value)) return value.forEach(walk);
      if (!value || typeof value !== 'object') return;
      if (value.$ref) visit(value.$ref.split('/').at(-1));
      Object.values(value).forEach(walk);
    }
    walk(all[name]);
  }
  inputs.forEach(name => visit(name.split('/').at(-1)));
  const ordered = Object.fromEntries(Object.keys(selected).sort().map(name => [name, selected[name]]));
  fs.writeFileSync(schemaFile, JSON.stringify({$schema:'http://json-schema.org/draft-07/schema#', codexVersion:version, sourceCommit:'41e22fee981a63b3698df7ed36bad393cda24715', generatedBy:'codex app-server generate-json-schema (stable)', definitions:ordered}, null, 2) + '\n');
}
const raw = fs.readFileSync(schemaFile);
const schema = JSON.parse(raw);
if (schema.codexVersion !== version || schema.sourceCommit !== '41e22fee981a63b3698df7ed36bad393cda24715') throw new Error('Unexpected Codex schema provenance');
const {definitions} = schema;
const names = s => s.replace(/(^|[^a-zA-Z0-9])([a-zA-Z0-9])/g, (_, a, b) => b.toUpperCase()).replace(/Id(s)?$/, (_, s) => 'ID' + (s || ''));
function nullable(s) {return Array.isArray(s.type) && s.type.includes('null') || (s.anyOf || []).some(v => v.type === 'null');}
function type(s) {
  if (s.$ref) return s.$ref.split('/').at(-1);
  if (s.anyOf) {
    const variants = s.anyOf.filter(v => v.type !== 'null');
    if (variants.length === 1) return type(variants[0]);
    return 'json.RawMessage';
  }
  if (s.oneOf) return s.oneOf.every(v => v.type === 'string') ? 'string' : 'json.RawMessage';
  const t = Array.isArray(s.type) ? s.type.find(t => t !== 'null') : s.type;
  switch (t) {
    case 'string': return 'string';
    case 'integer': return 'int64';
    case 'number': return 'float64';
    case 'boolean': return 'bool';
    case 'array': return '[]' + type(s.items);
    case 'object': {
      if (!s.properties) return 'map[string]' + (s.additionalProperties && typeof s.additionalProperties === 'object' ? type(s.additionalProperties) : 'json.RawMessage');
      return object(s);
    }
    default: return 'json.RawMessage';
  }
}
function object(s) {
  const required = new Set(s.required || []);
  return 'struct {\n' + Object.keys(s.properties).sort().map(key => {
    const v = s.properties[key];
    let t = type(v);
    const optional = !required.has(key) || nullable(v);
    // Pointers preserve explicit false/zero versus omitted override values.
    if (optional && !t.startsWith('[]') && !t.startsWith('map[') && t !== 'json.RawMessage') t = '*' + t;
    return names(key) + ' ' + t + ' `json:"' + key + (optional ? ',omitempty' : '') + '"`';
  }).join('\n') + '\n}';
}
let go = '// Code generated by scripts/generate-codex-rpc.mjs; DO NOT EDIT.\n// Stable Codex ' + version + '; schema SHA-256 ' + crypto.createHash('sha256').update(raw).digest('hex') + '\npackage codexrpc\n\nimport "encoding/json"\n\nconst ProtocolVersion = "' + version + '"\n';
for (const [name, original] of Object.entries(definitions)) {
  let s = original;
  // Tagged item/input variants share one envelope, retaining all schema fields.
  // Consumers MUST dispatch on Type before reading variant-specific fields.
  if (['ThreadItem', 'UserInput'].includes(name)) {
    const properties = {};
    for (const branch of s.oneOf) for (const [field, shape] of Object.entries(branch.properties)) {
      if (!(field in properties)) properties[field] = shape;
      else if (type(properties[field]) !== type(shape)) properties[field] = {};
    }
    properties.type = {type:'string'};
    s = {type:'object', properties, required:['type']};
  }
  const target = type(s);
  go += '\ntype ' + name + (target === 'json.RawMessage' ? ' = ' : ' ') + target + '\n';
}
const formatted = execFileSync('gofmt', [], {input:go,encoding:'utf8'});
const output = path.join(root, 'protocol.gen.go');
if (process.argv[2] === '--check') {
  if (fs.readFileSync(output,'utf8') !== formatted) throw new Error('Codex RPC bindings differ from the pinned schema; regenerate them');
} else fs.writeFileSync(output, formatted);