@sechroom/cli 2026.6.141-rc.6cc560b2 → 2026.6.143-rc.770caa0e

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 +70 -43
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2860,7 +2860,6 @@ auto-resumes where you left off and checkpoints working state before compacting.
2860
2860
 
2861
2861
  // src/setup/skills-offer.ts
2862
2862
  import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "fs";
2863
- import { homedir as homedir6 } from "os";
2864
2863
  import { join as join6 } from "path";
2865
2864
 
2866
2865
  // src/setup/lane-pin.ts
@@ -2945,7 +2944,10 @@ I can pin this checkout's lane so operator skills + the continuity hook resolve
2945
2944
 
2946
2945
  // src/setup/skill-resolution.ts
2947
2946
  var SYSTEM_WORKSPACE_ID = "wsp_system";
2948
- var ROLE_TAG = "sechroom:role:skill-template";
2947
+ var SKILL_ROLE_TAG = "sechroom:role:skill-template";
2948
+ var SKILL_NAME_PREFIX = "skill:";
2949
+ var AGENT_ROLE_TAG = "sechroom:role:agent-template";
2950
+ var AGENT_NAME_PREFIX = "agent:";
2949
2951
  function tagsOf(row) {
2950
2952
  const m = row?.item ?? row;
2951
2953
  return m?.tags ?? m?.Tags ?? [];
@@ -2957,29 +2959,31 @@ function bodyOf(row) {
2957
2959
  const m = row?.item ?? row;
2958
2960
  return m?.text ?? m?.Text ?? "";
2959
2961
  }
2960
- function skillsFromRows(rows, surface, source) {
2962
+ function entriesFromRows(rows, surface, source, roleTag, namePrefix) {
2961
2963
  const out = /* @__PURE__ */ new Map();
2962
2964
  for (const row of rows ?? []) {
2963
2965
  const tags = tagsOf(row);
2964
- if (!tags.includes(ROLE_TAG)) continue;
2966
+ if (!tags.includes(roleTag)) continue;
2965
2967
  if (tagValue(tags, "target:") !== surface) continue;
2966
- const name = tagValue(tags, "skill:");
2968
+ const name = tagValue(tags, namePrefix);
2967
2969
  if (!name) continue;
2968
2970
  out.set(name, { name, body: bodyOf(row), source });
2969
2971
  }
2970
2972
  return out;
2971
2973
  }
2972
- function resolveSkills(systemRows, personalRows, surface) {
2973
- const merged = skillsFromRows(systemRows, surface, "system");
2974
- for (const [name, skill] of skillsFromRows(
2975
- personalRows,
2976
- surface,
2977
- "personal"
2978
- )) {
2979
- merged.set(name, skill);
2974
+ function resolveByRole(systemRows, personalRows, surface, roleTag, namePrefix) {
2975
+ const merged = entriesFromRows(systemRows, surface, "system", roleTag, namePrefix);
2976
+ for (const [name, item] of entriesFromRows(personalRows, surface, "personal", roleTag, namePrefix)) {
2977
+ merged.set(name, item);
2980
2978
  }
2981
2979
  return [...merged.values()].sort((a, b) => a.name.localeCompare(b.name));
2982
2980
  }
2981
+ function resolveSkills(systemRows, personalRows, surface) {
2982
+ return resolveByRole(systemRows, personalRows, surface, SKILL_ROLE_TAG, SKILL_NAME_PREFIX);
2983
+ }
2984
+ function resolveAgents(systemRows, personalRows, surface) {
2985
+ return resolveByRole(systemRows, personalRows, surface, AGENT_ROLE_TAG, AGENT_NAME_PREFIX);
2986
+ }
2983
2987
 
2984
2988
  // src/setup/skills-lock.ts
2985
2989
  import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
@@ -2990,6 +2994,9 @@ var DEFAULT_SKILLS_SLUG = "operator-skills";
2990
2994
  function skillsDir(global) {
2991
2995
  return global ? join5(homedir5(), ".claude", "skills") : join5(process.cwd(), ".claude", "skills");
2992
2996
  }
2997
+ function agentsDir(global) {
2998
+ return global ? join5(homedir5(), ".claude", "agents") : join5(process.cwd(), ".claude", "agents");
2999
+ }
2993
3000
  function readSkillsLock(dir) {
2994
3001
  const lockPath = join5(dir, SKILLS_LOCK);
2995
3002
  if (!existsSync6(lockPath)) return {};
@@ -3032,39 +3039,55 @@ async function maybeOfferSkills(cfg, personalWorkspaceId, opts) {
3032
3039
  fetchFeedRows(cfg, SYSTEM_WORKSPACE_ID),
3033
3040
  personalWorkspaceId ? fetchFeedRows(cfg, personalWorkspaceId) : Promise.resolve([])
3034
3041
  ]);
3035
- const resolved = resolveSkills(systemRows, personalRows, surface);
3036
- if (resolved.length === 0) return;
3042
+ const skills = resolveSkills(systemRows, personalRows, surface);
3043
+ const agents = resolveAgents(systemRows, personalRows, surface);
3044
+ if (skills.length === 0 && agents.length === 0) return;
3045
+ const sDir = skillsDir(true);
3046
+ const aDir = agentsDir(true);
3037
3047
  if (opts.dryRun) {
3038
- process.stderr.write(
3039
- `
3040
- Would materialise ${style.bold(String(resolved.length))} operator skill(s) for ${surface}:
3041
- ` + resolved.map((s) => ` ${s.name} ${style.dim(`[${s.source}]`)}`).join("\n") + "\n"
3042
- );
3048
+ const lines = (label, items) => items.length === 0 ? "" : `
3049
+ Would materialise ${style.bold(String(items.length))} ${label} for ${surface}:
3050
+ ` + items.map((s) => ` ${s.name} ${style.dim(`[${s.source}]`)}`).join("\n") + "\n";
3051
+ process.stderr.write(lines("operator skill(s)", skills) + lines("agent(s)", agents));
3043
3052
  return;
3044
3053
  }
3045
- const names = resolved.map((s) => s.name);
3046
- process.stderr.write(
3047
- `
3048
- Found ${style.bold(String(names.length))} operator skill(s) available to you: ${names.join(", ")}.
3049
- `
3050
- );
3051
- const dir = join6(homedir6(), ".claude", "skills");
3052
- const materialise = opts.yes ? true : canPrompt() ? await promptYesNo(`Write them to ${dir}/ so ${surface} can use them?`) : false;
3054
+ const summary = [
3055
+ skills.length > 0 ? `${style.bold(String(skills.length))} skill(s)` : "",
3056
+ agents.length > 0 ? `${style.bold(String(agents.length))} agent(s)` : ""
3057
+ ].filter(Boolean).join(" + ");
3058
+ process.stderr.write(`
3059
+ Found ${summary} available to you for ${surface}.
3060
+ `);
3061
+ if (skills.length > 0) process.stderr.write(` skills: ${skills.map((s) => s.name).join(", ")}
3062
+ `);
3063
+ if (agents.length > 0) process.stderr.write(` agents: ${agents.map((a) => a.name).join(", ")}
3064
+ `);
3065
+ const dest = [skills.length > 0 ? `${sDir}/` : "", agents.length > 0 ? `${aDir}/` : ""].filter(Boolean).join(" + ");
3066
+ const materialise = opts.yes ? true : canPrompt() ? await promptYesNo(`Write them to ${dest} so ${surface} can use them?`) : false;
3053
3067
  if (!materialise) return;
3054
- const written = [];
3055
- for (const s of resolved) {
3056
- mkdirSync6(join6(dir, s.name), { recursive: true });
3057
- writeFileSync6(
3058
- join6(dir, s.name, "SKILL.md"),
3059
- s.body.endsWith("\n") ? s.body : s.body + "\n"
3060
- );
3061
- written.push(s.name);
3068
+ if (skills.length > 0) {
3069
+ const written = [];
3070
+ for (const s of skills) {
3071
+ mkdirSync6(join6(sDir, s.name), { recursive: true });
3072
+ writeFileSync6(join6(sDir, s.name, "SKILL.md"), s.body.endsWith("\n") ? s.body : s.body + "\n");
3073
+ written.push(s.name);
3074
+ }
3075
+ recordMaterialisedSkills(sDir, DEFAULT_SKILLS_SLUG, written, { surface });
3076
+ process.stderr.write(`${style.green("\u2713")} wrote ${written.length} skill(s) to ${sDir}
3077
+ `);
3078
+ }
3079
+ if (agents.length > 0) {
3080
+ mkdirSync6(aDir, { recursive: true });
3081
+ const written = [];
3082
+ for (const a of agents) {
3083
+ const file = `${a.name}.md`;
3084
+ writeFileSync6(join6(aDir, file), a.body.endsWith("\n") ? a.body : a.body + "\n");
3085
+ written.push(file);
3086
+ }
3087
+ recordMaterialisedSkills(aDir, DEFAULT_SKILLS_SLUG, written, { surface });
3088
+ process.stderr.write(`${style.green("\u2713")} wrote ${written.length} agent(s) to ${aDir}
3089
+ `);
3062
3090
  }
3063
- recordMaterialisedSkills(dir, DEFAULT_SKILLS_SLUG, written, { surface });
3064
- process.stderr.write(
3065
- `${style.green("\u2713")} wrote ${written.length} skill(s) to ${dir}
3066
- `
3067
- );
3068
3091
  await ensureLanePin(cfg, {
3069
3092
  yes: opts.yes,
3070
3093
  dryRun: opts.dryRun,
@@ -4145,12 +4168,14 @@ To install/refresh skills, run 'sechroom onboard' (it offers to materialise them
4145
4168
  }
4146
4169
 
4147
4170
  // src/commands/reset.ts
4148
- import { homedir as homedir7 } from "os";
4171
+ import { homedir as homedir6 } from "os";
4149
4172
  import { join as join11 } from "path";
4150
4173
  import { existsSync as existsSync11, readFileSync as readFileSync7, rmSync as rmSync3 } from "fs";
4151
4174
  var SKILLS_LOCK2 = ".sechroom-skills.json";
4152
4175
  var localSkillsDir = () => join11(process.cwd(), ".claude", "skills");
4153
- var globalSkillsDir = () => join11(homedir7(), ".claude", "skills");
4176
+ var globalSkillsDir = () => join11(homedir6(), ".claude", "skills");
4177
+ var localAgentsDir = () => join11(process.cwd(), ".claude", "agents");
4178
+ var globalAgentsDir = () => join11(homedir6(), ".claude", "agents");
4154
4179
  function removeMaterialisedSkills(dir) {
4155
4180
  const removed = [];
4156
4181
  const lockPath = join11(dir, SKILLS_LOCK2);
@@ -4221,12 +4246,14 @@ function registerReset(program2) {
4221
4246
  removed.push(legacySem);
4222
4247
  }
4223
4248
  removed.push(...removeMaterialisedSkills(localSkillsDir()));
4249
+ removed.push(...removeMaterialisedSkills(localAgentsDir()));
4224
4250
  if (global) {
4225
4251
  const tok = clearToken();
4226
4252
  if (tok) removed.push(tok);
4227
4253
  const cfg = clearPersisted();
4228
4254
  if (cfg) removed.push(cfg);
4229
4255
  removed.push(...removeMaterialisedSkills(globalSkillsDir()));
4256
+ removed.push(...removeMaterialisedSkills(globalAgentsDir()));
4230
4257
  }
4231
4258
  if (json) return emit({ global, removed }, true);
4232
4259
  if (removed.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sechroom/cli",
3
- "version": "2026.6.141-rc.6cc560b2",
3
+ "version": "2026.6.143-rc.770caa0e",
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",