@sechroom/cli 2026.7.17 → 2026.7.18
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.
- package/dist/index.js +64 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1140,7 +1140,10 @@ function resolveReferences(systemRows, personalRows, surface) {
|
|
|
1140
1140
|
}
|
|
1141
1141
|
|
|
1142
1142
|
// src/setup/skill-resolution-io.ts
|
|
1143
|
-
var AGENT_TARGET = {
|
|
1143
|
+
var AGENT_TARGET = {
|
|
1144
|
+
"claude-code": "claude-agent",
|
|
1145
|
+
"gpt-codex": "gpt-codex-agent"
|
|
1146
|
+
};
|
|
1144
1147
|
function agentTargetFor(surface) {
|
|
1145
1148
|
return AGENT_TARGET[surface] ?? `${surface}-agent`;
|
|
1146
1149
|
}
|
|
@@ -1205,12 +1208,58 @@ function writeSkills(dir, skills, surface) {
|
|
|
1205
1208
|
if (written.length) recordMaterialisedSkills(dir, DEFAULT_SKILLS_SLUG, written, { surface });
|
|
1206
1209
|
return written;
|
|
1207
1210
|
}
|
|
1211
|
+
function splitAgentFrontmatter(body) {
|
|
1212
|
+
body = body.replaceAll("\r\n", "\n");
|
|
1213
|
+
if (!body.startsWith("---\n")) return { instructions: body };
|
|
1214
|
+
const end = body.indexOf("\n---\n", 4);
|
|
1215
|
+
if (end < 0) return { instructions: body };
|
|
1216
|
+
const frontmatter = body.slice(4, end);
|
|
1217
|
+
const field = (key) => {
|
|
1218
|
+
const line = frontmatter.split("\n").find((candidate) => candidate.startsWith(`${key}:`));
|
|
1219
|
+
return line?.slice(key.length + 1).trim().replace(/^(["'])(.*)\1$/, "$2");
|
|
1220
|
+
};
|
|
1221
|
+
return { name: field("name"), description: field("description"), instructions: body.slice(end + 5).trimStart() };
|
|
1222
|
+
}
|
|
1223
|
+
function validateCodexSkills(skills) {
|
|
1224
|
+
for (const skill of skills) {
|
|
1225
|
+
const parsed = splitAgentFrontmatter(skill.body);
|
|
1226
|
+
if (parsed.name !== skill.name || !parsed.description) {
|
|
1227
|
+
throw new Error(
|
|
1228
|
+
`Codex skill '${skill.name}' must begin with YAML frontmatter containing matching name and a description.`
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
var WORKER_NAMES = ["substrate-drafter", "substrate-miner", "substrate-verifier"];
|
|
1234
|
+
function validateCodexWorkerDependencies(skills, agents) {
|
|
1235
|
+
const available = new Set(agents.map((agent) => agent.name));
|
|
1236
|
+
const missing = WORKER_NAMES.filter(
|
|
1237
|
+
(worker) => skills.some((skill) => skill.body.includes(worker)) && !available.has(worker)
|
|
1238
|
+
);
|
|
1239
|
+
if (missing.length) {
|
|
1240
|
+
throw new Error(`Codex skills reference missing agent template(s): ${missing.join(", ")}.`);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
function codexAgentToml(agent) {
|
|
1244
|
+
const parsed = splitAgentFrontmatter(agent.body);
|
|
1245
|
+
if (!parsed.description) {
|
|
1246
|
+
throw new Error(`Codex agent '${agent.name}' requires a description in its leading YAML frontmatter.`);
|
|
1247
|
+
}
|
|
1248
|
+
return [
|
|
1249
|
+
`name = ${JSON.stringify(parsed.name || agent.name)}`,
|
|
1250
|
+
`description = ${JSON.stringify(parsed.description)}`,
|
|
1251
|
+
`developer_instructions = ${JSON.stringify(parsed.instructions.trimEnd())}`,
|
|
1252
|
+
""
|
|
1253
|
+
].join("\n");
|
|
1254
|
+
}
|
|
1208
1255
|
function writeAgents(dir, agents, surface) {
|
|
1209
1256
|
if (agents.length) mkdirSync3(dir, { recursive: true });
|
|
1210
1257
|
const written = [];
|
|
1211
1258
|
for (const a of agents) {
|
|
1212
|
-
const
|
|
1213
|
-
|
|
1259
|
+
const codex = surface === CLIENT_SURFACE.codex;
|
|
1260
|
+
const file = `${a.name}.${codex ? "toml" : "md"}`;
|
|
1261
|
+
const body = codex ? codexAgentToml(a) : a.body.endsWith("\n") ? a.body : a.body + "\n";
|
|
1262
|
+
writeFileSync3(join4(dir, file), body);
|
|
1214
1263
|
written.push(file);
|
|
1215
1264
|
}
|
|
1216
1265
|
if (written.length) recordMaterialisedSkills(dir, DEFAULT_SKILLS_SLUG, written, { surface });
|
|
@@ -1239,7 +1288,7 @@ var AGENT_SPEC = {
|
|
|
1239
1288
|
dir: agentsDir,
|
|
1240
1289
|
resolve: resolveAgentSet,
|
|
1241
1290
|
write: writeAgents,
|
|
1242
|
-
supportsCodex:
|
|
1291
|
+
supportsCodex: true
|
|
1243
1292
|
};
|
|
1244
1293
|
function scopeOf(opts) {
|
|
1245
1294
|
return opts.local ? "project" : resolveScope(opts.scope);
|
|
@@ -1315,6 +1364,10 @@ async function runInstall(spec, cmd, opts) {
|
|
|
1315
1364
|
const rows = await fetchTemplateRows(cfg, personalWorkspaceId);
|
|
1316
1365
|
const results = targets.map((t) => {
|
|
1317
1366
|
const items = spec.resolve(rows, t.surface);
|
|
1367
|
+
if (t.client === "codex" && spec.kind === "skill") {
|
|
1368
|
+
validateCodexSkills(items);
|
|
1369
|
+
validateCodexWorkerDependencies(items, resolveAgentSet(rows, t.surface));
|
|
1370
|
+
}
|
|
1318
1371
|
const refs = spec.kind === "skill" ? resolveReferenceSet(rows, t.surface) : [];
|
|
1319
1372
|
const written = dryRun ? items.map((i) => i.name) : spec.write(t.dir, items, t.surface);
|
|
1320
1373
|
const refsWritten = dryRun ? refs.map((r) => r.name) : writeReferencesIntoSkillDirs(t.dir, items, refs);
|
|
@@ -1440,17 +1493,19 @@ function registerAgents(program2) {
|
|
|
1440
1493
|
`
|
|
1441
1494
|
Examples:
|
|
1442
1495
|
$ sechroom agents install materialise your installed agents to ~/.claude/agents
|
|
1496
|
+
$ sechroom agents install --client codex materialise native TOML agents to ~/.codex/agents
|
|
1443
1497
|
$ sechroom agents install --scope project write them to ./.claude/agents instead
|
|
1444
1498
|
$ sechroom agents install --claude-config-dir ~/.claude-work target another instance
|
|
1445
1499
|
$ sechroom agents list what's materialised on disk
|
|
1446
1500
|
$ sechroom agents clean remove the materialised agent files
|
|
1447
1501
|
|
|
1448
|
-
Agents are resolved from the agent target (target:claude-agent
|
|
1449
|
-
workers your loop skills call
|
|
1502
|
+
Agents are resolved from the client's agent target (target:claude-agent or
|
|
1503
|
+
target:gpt-codex-agent), the dispatchable workers your loop skills call
|
|
1504
|
+
(e.g. find-prior-art \u2192 substrate-miner).`
|
|
1450
1505
|
);
|
|
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));
|
|
1506
|
+
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));
|
|
1507
|
+
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));
|
|
1508
|
+
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
1509
|
}
|
|
1455
1510
|
|
|
1456
1511
|
// src/commands/channel.ts
|
package/package.json
CHANGED