@sechroom/cli 2026.7.17 → 2026.7.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +75 -11
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -657,9 +657,14 @@ async function runApi(label, fn) {
657
657
  s.succeed();
658
658
  return res.data;
659
659
  }
660
- function fail(error) {
660
+ function formatFailureMessage(error) {
661
661
  let msg;
662
- if (typeof error === "object" && error !== null && "title" in error) {
662
+ if (error instanceof Error) {
663
+ msg = error.message || error.name;
664
+ if (error.cause instanceof Error && error.cause.message) {
665
+ msg += `: ${error.cause.message}`;
666
+ }
667
+ } else if (typeof error === "object" && error !== null && "title" in error) {
663
668
  const problem = error;
664
669
  msg = String(problem.title);
665
670
  if (problem.errors && typeof problem.errors === "object") {
@@ -674,6 +679,10 @@ ${detail.join("\n")}`;
674
679
  } else {
675
680
  msg = String(error);
676
681
  }
682
+ return msg;
683
+ }
684
+ function fail(error) {
685
+ const msg = formatFailureMessage(error);
677
686
  process.stderr.write(`error: ${msg}
678
687
  `);
679
688
  process.exit(1);
@@ -1140,7 +1149,10 @@ function resolveReferences(systemRows, personalRows, surface) {
1140
1149
  }
1141
1150
 
1142
1151
  // src/setup/skill-resolution-io.ts
1143
- var AGENT_TARGET = { "claude-code": "claude-agent" };
1152
+ var AGENT_TARGET = {
1153
+ "claude-code": "claude-agent",
1154
+ "gpt-codex": "gpt-codex-agent"
1155
+ };
1144
1156
  function agentTargetFor(surface) {
1145
1157
  return AGENT_TARGET[surface] ?? `${surface}-agent`;
1146
1158
  }
@@ -1205,12 +1217,58 @@ function writeSkills(dir, skills, surface) {
1205
1217
  if (written.length) recordMaterialisedSkills(dir, DEFAULT_SKILLS_SLUG, written, { surface });
1206
1218
  return written;
1207
1219
  }
1220
+ function splitAgentFrontmatter(body) {
1221
+ body = body.replaceAll("\r\n", "\n");
1222
+ if (!body.startsWith("---\n")) return { instructions: body };
1223
+ const end = body.indexOf("\n---\n", 4);
1224
+ if (end < 0) return { instructions: body };
1225
+ const frontmatter = body.slice(4, end);
1226
+ const field = (key) => {
1227
+ const line = frontmatter.split("\n").find((candidate) => candidate.startsWith(`${key}:`));
1228
+ return line?.slice(key.length + 1).trim().replace(/^(["'])(.*)\1$/, "$2");
1229
+ };
1230
+ return { name: field("name"), description: field("description"), instructions: body.slice(end + 5).trimStart() };
1231
+ }
1232
+ function validateCodexSkills(skills) {
1233
+ for (const skill of skills) {
1234
+ const parsed = splitAgentFrontmatter(skill.body);
1235
+ if (parsed.name !== skill.name || !parsed.description) {
1236
+ throw new Error(
1237
+ `Codex skill '${skill.name}' must begin with YAML frontmatter containing matching name and a description.`
1238
+ );
1239
+ }
1240
+ }
1241
+ }
1242
+ var WORKER_NAMES = ["substrate-drafter", "substrate-miner", "substrate-verifier"];
1243
+ function validateCodexWorkerDependencies(skills, agents) {
1244
+ const available = new Set(agents.map((agent) => agent.name));
1245
+ const missing = WORKER_NAMES.filter(
1246
+ (worker) => skills.some((skill) => skill.body.includes(worker)) && !available.has(worker)
1247
+ );
1248
+ if (missing.length) {
1249
+ throw new Error(`Codex skills reference missing agent template(s): ${missing.join(", ")}.`);
1250
+ }
1251
+ }
1252
+ function codexAgentToml(agent) {
1253
+ const parsed = splitAgentFrontmatter(agent.body);
1254
+ if (!parsed.description) {
1255
+ throw new Error(`Codex agent '${agent.name}' requires a description in its leading YAML frontmatter.`);
1256
+ }
1257
+ return [
1258
+ `name = ${JSON.stringify(parsed.name || agent.name)}`,
1259
+ `description = ${JSON.stringify(parsed.description)}`,
1260
+ `developer_instructions = ${JSON.stringify(parsed.instructions.trimEnd())}`,
1261
+ ""
1262
+ ].join("\n");
1263
+ }
1208
1264
  function writeAgents(dir, agents, surface) {
1209
1265
  if (agents.length) mkdirSync3(dir, { recursive: true });
1210
1266
  const written = [];
1211
1267
  for (const a of agents) {
1212
- const file = `${a.name}.md`;
1213
- writeFileSync3(join4(dir, file), a.body.endsWith("\n") ? a.body : a.body + "\n");
1268
+ const codex = surface === CLIENT_SURFACE.codex;
1269
+ const file = `${a.name}.${codex ? "toml" : "md"}`;
1270
+ const body = codex ? codexAgentToml(a) : a.body.endsWith("\n") ? a.body : a.body + "\n";
1271
+ writeFileSync3(join4(dir, file), body);
1214
1272
  written.push(file);
1215
1273
  }
1216
1274
  if (written.length) recordMaterialisedSkills(dir, DEFAULT_SKILLS_SLUG, written, { surface });
@@ -1239,7 +1297,7 @@ var AGENT_SPEC = {
1239
1297
  dir: agentsDir,
1240
1298
  resolve: resolveAgentSet,
1241
1299
  write: writeAgents,
1242
- supportsCodex: false
1300
+ supportsCodex: true
1243
1301
  };
1244
1302
  function scopeOf(opts) {
1245
1303
  return opts.local ? "project" : resolveScope(opts.scope);
@@ -1315,6 +1373,10 @@ async function runInstall(spec, cmd, opts) {
1315
1373
  const rows = await fetchTemplateRows(cfg, personalWorkspaceId);
1316
1374
  const results = targets.map((t) => {
1317
1375
  const items = spec.resolve(rows, t.surface);
1376
+ if (t.client === "codex" && spec.kind === "skill") {
1377
+ validateCodexSkills(items);
1378
+ validateCodexWorkerDependencies(items, resolveAgentSet(rows, t.surface));
1379
+ }
1318
1380
  const refs = spec.kind === "skill" ? resolveReferenceSet(rows, t.surface) : [];
1319
1381
  const written = dryRun ? items.map((i) => i.name) : spec.write(t.dir, items, t.surface);
1320
1382
  const refsWritten = dryRun ? refs.map((r) => r.name) : writeReferencesIntoSkillDirs(t.dir, items, refs);
@@ -1440,17 +1502,19 @@ function registerAgents(program2) {
1440
1502
  `
1441
1503
  Examples:
1442
1504
  $ sechroom agents install materialise your installed agents to ~/.claude/agents
1505
+ $ sechroom agents install --client codex materialise native TOML agents to ~/.codex/agents
1443
1506
  $ sechroom agents install --scope project write them to ./.claude/agents instead
1444
1507
  $ sechroom agents install --claude-config-dir ~/.claude-work target another instance
1445
1508
  $ sechroom agents list what's materialised on disk
1446
1509
  $ sechroom agents clean remove the materialised agent files
1447
1510
 
1448
- Agents are resolved from the agent target (target:claude-agent), the dispatchable
1449
- workers your loop skills call (e.g. find-prior-art \u2192 substrate-miner).`
1511
+ Agents are resolved from the client's agent target (target:claude-agent or
1512
+ target:gpt-codex-agent), the dispatchable workers your loop skills call
1513
+ (e.g. find-prior-art \u2192 substrate-miner).`
1450
1514
  );
1451
- agents.command("install").description("Materialise your installed subagents to disk (the already-installed bundle \u2014 no server install)").option("--scope <scope>", "global (config dir / CLAUDE_CONFIG_DIR) or project (<cwd>/.claude) \u2014 default global").option("--local", "alias for --scope project").option("--dry-run", "print what would be written; write nothing").option("--json", "machine output").action((opts, cmd) => runInstall(AGENT_SPEC, cmd, opts));
1452
- agents.command("list").description("List the subagents materialised on disk (per resolved config dir)").option("--scope <scope>", "global (config dir / CLAUDE_CONFIG_DIR) or project (<cwd>/.claude) \u2014 default global").option("--local", "alias for --scope project").option("--json", "machine output").action((opts, cmd) => runList(AGENT_SPEC, cmd, opts));
1453
- agents.command("clean [slug]").description(`Remove subagent files materialised to disk (default ${DEFAULT_SKILLS_SLUG})`).option("--scope <scope>", "global (config dir / CLAUDE_CONFIG_DIR) or project (<cwd>/.claude) \u2014 default global").option("--local", "alias for --scope project").option("--json", "machine output").action((slugArg, opts, cmd) => runClean(AGENT_SPEC, cmd, opts, slugArg));
1515
+ agents.command("install").description("Materialise your installed subagents to disk (the already-installed bundle \u2014 no server install)").option("--scope <scope>", "global (config dir / CLAUDE_CONFIG_DIR) or project (<cwd>/.claude) \u2014 default global").option("--local", "alias for --scope project").option("--dry-run", "print what would be written; write nothing").option("--client <client>", "claude, codex, or all").option("--json", "machine output").action((opts, cmd) => runInstall(AGENT_SPEC, cmd, opts));
1516
+ agents.command("list").description("List the subagents materialised on disk (per resolved config dir)").option("--scope <scope>", "global (config dir / CLAUDE_CONFIG_DIR) or project (<cwd>/.claude) \u2014 default global").option("--local", "alias for --scope project").option("--json", "machine output").option("--client <client>", "claude, codex, or all").action((opts, cmd) => runList(AGENT_SPEC, cmd, opts));
1517
+ agents.command("clean [slug]").description(`Remove subagent files materialised to disk (default ${DEFAULT_SKILLS_SLUG})`).option("--scope <scope>", "global (config dir / CLAUDE_CONFIG_DIR) or project (<cwd>/.claude) \u2014 default global").option("--local", "alias for --scope project").option("--json", "machine output").option("--client <client>", "claude, codex, or all").action((slugArg, opts, cmd) => runClean(AGENT_SPEC, cmd, opts, slugArg));
1454
1518
  }
1455
1519
 
1456
1520
  // src/commands/channel.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sechroom/cli",
3
- "version": "2026.7.17",
3
+ "version": "2026.7.19",
4
4
  "description": "Sechroom CLI — a thin, generated client over the Sechroom HTTP API. An agent/human surface alongside MCP.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",