@sechroom/cli 2026.6.140-rc.176770e1 → 2026.6.142-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 +142 -173
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2859,9 +2859,8 @@ auto-resumes where you left off and checkpoints working state before compacting.
2859
2859
  }
2860
2860
 
2861
2861
  // src/setup/skills-offer.ts
2862
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
2863
- import { homedir as homedir5 } from "os";
2864
- import { join as join5 } from "path";
2862
+ import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "fs";
2863
+ import { join as join6 } from "path";
2865
2864
 
2866
2865
  // src/setup/lane-pin.ts
2867
2866
  var CODE_LANE_PREFIX_BY_CLIENT = {
@@ -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,62 @@ 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
+ }
2987
+
2988
+ // src/setup/skills-lock.ts
2989
+ import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
2990
+ import { homedir as homedir5 } from "os";
2991
+ import { join as join5 } from "path";
2992
+ var SKILLS_LOCK = ".sechroom-skills.json";
2993
+ var DEFAULT_SKILLS_SLUG = "operator-skills";
2994
+ function skillsDir(global) {
2995
+ return global ? join5(homedir5(), ".claude", "skills") : join5(process.cwd(), ".claude", "skills");
2996
+ }
2997
+ function agentsDir(global) {
2998
+ return global ? join5(homedir5(), ".claude", "agents") : join5(process.cwd(), ".claude", "agents");
2999
+ }
3000
+ function readSkillsLock(dir) {
3001
+ const lockPath = join5(dir, SKILLS_LOCK);
3002
+ if (!existsSync6(lockPath)) return {};
3003
+ try {
3004
+ return JSON.parse(readFileSync5(lockPath, "utf8"));
3005
+ } catch {
3006
+ return {};
3007
+ }
3008
+ }
3009
+ function writeSkillsLock(dir, lock) {
3010
+ mkdirSync5(dir, { recursive: true });
3011
+ writeFileSync5(join5(dir, SKILLS_LOCK), JSON.stringify(lock, null, 2) + "\n");
3012
+ }
3013
+ function recordMaterialisedSkills(dir, slug, skills, meta = {}) {
3014
+ const lock = readSkillsLock(dir);
3015
+ lock[slug] = { surface: meta.surface, skills: [...skills].sort() };
3016
+ writeSkillsLock(dir, lock);
3017
+ }
2983
3018
 
2984
3019
  // src/setup/skills-offer.ts
2985
3020
  async function fetchFeedRows(cfg, workspaceId) {
@@ -3004,38 +3039,55 @@ async function maybeOfferSkills(cfg, personalWorkspaceId, opts) {
3004
3039
  fetchFeedRows(cfg, SYSTEM_WORKSPACE_ID),
3005
3040
  personalWorkspaceId ? fetchFeedRows(cfg, personalWorkspaceId) : Promise.resolve([])
3006
3041
  ]);
3007
- const resolved = resolveSkills(systemRows, personalRows, surface);
3008
- 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);
3009
3047
  if (opts.dryRun) {
3010
- process.stderr.write(
3011
- `
3012
- Would materialise ${style.bold(String(resolved.length))} operator skill(s) for ${surface}:
3013
- ` + resolved.map((s) => ` ${s.name} ${style.dim(`[${s.source}]`)}`).join("\n") + "\n"
3014
- );
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));
3015
3052
  return;
3016
3053
  }
3017
- const names = resolved.map((s) => s.name);
3018
- process.stderr.write(
3019
- `
3020
- Found ${style.bold(String(names.length))} operator skill(s) available to you: ${names.join(", ")}.
3021
- `
3022
- );
3023
- const dir = join5(homedir5(), ".claude", "skills");
3024
- 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;
3025
3067
  if (!materialise) return;
3026
- const written = [];
3027
- for (const s of resolved) {
3028
- mkdirSync5(join5(dir, s.name), { recursive: true });
3029
- writeFileSync5(
3030
- join5(dir, s.name, "SKILL.md"),
3031
- s.body.endsWith("\n") ? s.body : s.body + "\n"
3032
- );
3033
- 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
+ `);
3034
3090
  }
3035
- process.stderr.write(
3036
- `${style.green("\u2713")} wrote ${written.length} skill(s) to ${dir}
3037
- `
3038
- );
3039
3091
  await ensureLanePin(cfg, {
3040
3092
  yes: opts.yes,
3041
3093
  dryRun: opts.dryRun,
@@ -3191,13 +3243,13 @@ async function runClients(clients, cmd, opts) {
3191
3243
  }
3192
3244
 
3193
3245
  // src/commands/onboard.ts
3194
- import { existsSync as existsSync7 } from "fs";
3195
- import { basename as basename3, join as join7 } from "path";
3246
+ import { existsSync as existsSync8 } from "fs";
3247
+ import { basename as basename3, join as join8 } from "path";
3196
3248
 
3197
3249
  // src/commands/fanout.ts
3198
3250
  import { spawnSync } from "child_process";
3199
- import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync, statSync } from "fs";
3200
- import { isAbsolute, join as join6, resolve } from "path";
3251
+ import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync, statSync } from "fs";
3252
+ import { isAbsolute, join as join7, resolve } from "path";
3201
3253
  var ICON = {
3202
3254
  refresh: "\u21BB",
3203
3255
  bind: "+",
@@ -3217,21 +3269,21 @@ function discoverChildren(root) {
3217
3269
  const out = [];
3218
3270
  for (const name of names.sort()) {
3219
3271
  if (name.startsWith(".") || name === "node_modules") continue;
3220
- const dir = join6(root, name);
3272
+ const dir = join7(root, name);
3221
3273
  try {
3222
3274
  if (!statSync(dir).isDirectory()) continue;
3223
3275
  } catch {
3224
3276
  continue;
3225
3277
  }
3226
- if (existsSync6(join6(dir, ".git")) || committedBindingPath(dir)) out.push(name);
3278
+ if (existsSync7(join7(dir, ".git")) || committedBindingPath(dir)) out.push(name);
3227
3279
  }
3228
3280
  return out;
3229
3281
  }
3230
3282
  function readManifest(path) {
3231
- if (!existsSync6(path)) return null;
3283
+ if (!existsSync7(path)) return null;
3232
3284
  let parsed;
3233
3285
  try {
3234
- parsed = JSON.parse(readFileSync5(path, "utf8"));
3286
+ parsed = JSON.parse(readFileSync6(path, "utf8"));
3235
3287
  } catch (err2) {
3236
3288
  throw new Error(`couldn't parse ${path}: ${err2 instanceof Error ? err2.message : String(err2)}`);
3237
3289
  }
@@ -3596,10 +3648,10 @@ async function chooseClients(clientFlag, yes, cwd) {
3596
3648
  }
3597
3649
  async function planRecurseChild(entry, root, client, opts) {
3598
3650
  const dir = resolveChildDir(entry.path, root);
3599
- if (!existsSync7(dir)) {
3651
+ if (!existsSync8(dir)) {
3600
3652
  return { label: entry.path, dir, disposition: "skip-missing", argv: [], reason: "directory does not exist" };
3601
3653
  }
3602
- if (existsSync7(join7(dir, ".sechroom.json"))) {
3654
+ if (existsSync8(join8(dir, ".sechroom.json"))) {
3603
3655
  return {
3604
3656
  label: entry.path,
3605
3657
  dir,
@@ -3672,7 +3724,7 @@ This fan-out will pin the same lane in every repo:
3672
3724
  async function runRecurse(cfg, g, opts) {
3673
3725
  const { yes, dryRun, json } = opts;
3674
3726
  const root = process.cwd();
3675
- const manifestPath = join7(root, ".sechroom", "repos.json");
3727
+ const manifestPath = join8(root, ".sechroom", "repos.json");
3676
3728
  const fromManifest = readManifest(manifestPath);
3677
3729
  const entries = fromManifest ?? discoverChildren(root).map((path) => ({ path }));
3678
3730
  const sourceLabel = fromManifest ? `manifest ${manifestPath}` : `auto-discovered under ${root}`;
@@ -3886,12 +3938,12 @@ async function printStarterPrompt(mode, cfg) {
3886
3938
  }
3887
3939
 
3888
3940
  // src/commands/sweep.ts
3889
- import { existsSync as existsSync8 } from "fs";
3890
- import { dirname as dirname6, join as join8, resolve as resolve2 } from "path";
3891
- var DEFAULT_MANIFEST = join8(".sechroom", "repos.json");
3941
+ import { existsSync as existsSync9 } from "fs";
3942
+ import { dirname as dirname6, join as join9, resolve as resolve2 } from "path";
3943
+ var DEFAULT_MANIFEST = join9(".sechroom", "repos.json");
3892
3944
  function planEntry(entry, root) {
3893
3945
  const dir = resolveChildDir(entry.path, root);
3894
- if (!existsSync8(dir)) {
3946
+ if (!existsSync9(dir)) {
3895
3947
  return { label: entry.path, dir, disposition: "skip-missing", argv: [], reason: "directory does not exist" };
3896
3948
  }
3897
3949
  if (committedBindingPath(dir)) {
@@ -3985,106 +4037,21 @@ Examples:
3985
4037
  }
3986
4038
 
3987
4039
  // src/commands/skills.ts
3988
- import { homedir as homedir6 } from "os";
3989
- import { join as join9 } from "path";
3990
- import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, rmSync as rmSync2, existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
3991
- var DEFAULT_SLUG = "operator-skills";
3992
- var ROLE_TAGS = ["sechroom:role:skill-template", "role:skill-template"];
3993
- var LOCK = ".sechroom-skills.json";
3994
- function skillsDir(global) {
3995
- return global ? join9(homedir6(), ".claude", "skills") : join9(process.cwd(), ".claude", "skills");
3996
- }
3997
- function tagValue2(tags, prefix) {
3998
- return (tags ?? []).find((t) => t.startsWith(prefix))?.slice(prefix.length);
3999
- }
4000
- function hasAny(tags, candidates) {
4001
- return (tags ?? []).some((t) => candidates.includes(t));
4002
- }
4040
+ import { join as join10 } from "path";
4041
+ import { existsSync as existsSync10, rmSync as rmSync2 } from "fs";
4003
4042
  function registerSkills(program2) {
4004
- const skills = program2.command("skills").description("Install + manage operator skills from a bundle");
4043
+ const skills = program2.command("skills").description("Manage operator skills (materialised by `onboard`)");
4005
4044
  skills.addHelpText(
4006
4045
  "after",
4007
4046
  `
4008
4047
  Examples:
4009
- $ sechroom skills install --code-lane claude-code-chris --design-lane claude-design-chris
4010
- $ sechroom skills install operator-skills --surface claude-code --local
4011
4048
  $ sechroom skills list
4012
4049
  $ sechroom skills set-lane --code-lane claude-code-chris --design-lane claude-design-chris
4013
4050
  $ sechroom skills lane
4014
- $ sechroom skills clean`
4051
+ $ sechroom skills clean
4052
+
4053
+ To install/refresh skills, run 'sechroom onboard' (it offers to materialise them).`
4015
4054
  );
4016
- skills.command("install [slug]").description(`Install a skills bundle (default ${DEFAULT_SLUG}) into your personal workspace + write SKILL.md files`).option("--version <v>", "bundle version (default: latest published in the catalogue)").option("--instance <name>", "install as a named, separate instance (install the same bundle more than once)").option("--code-lane <id>", "identity.code-lane binding (e.g. claude-code-chris)").option("--design-lane <id>", "identity.design-lane binding (e.g. claude-design-chris)").option("--surface <s>", "skill target surface to materialise", "claude-code").option("--local", "write to ./.claude/skills instead of ~/.claude/skills").option("--json", "machine output").action(async (slugArg, opts, cmd) => {
4017
- const slug = slugArg || DEFAULT_SLUG;
4018
- const client = await makeClient(resolveConfig(cmd.optsWithGlobals()));
4019
- const pw = await runApi("resolving personal workspace", () => client.GET("/me/personal-workspace", {}));
4020
- const personalWsId = pw?.id || pw?.workspaceId || pw?.personalWorkspaceId || pw?.item?.id;
4021
- if (!personalWsId) fail("Could not resolve your personal workspace.");
4022
- let version = opts.version;
4023
- if (!version) {
4024
- const cat = await runApi("reading the bundle catalogue", () => client.GET("/me/bundles", {}));
4025
- const item = (cat?.bundles ?? cat?.Bundles ?? []).find((b) => (b.slug ?? b.Slug) === slug);
4026
- if (!item) fail(`Bundle '${slug}' is not in your self-serve catalogue (must be UserInstallable + Published).`);
4027
- version = item.latestVersion ?? item.LatestVersion;
4028
- if (!version) fail(`Bundle '${slug}' has no installable (Published) version.`);
4029
- }
4030
- const installOptions = {};
4031
- if (opts.codeLane) installOptions["identity.code-lane"] = opts.codeLane;
4032
- if (opts.designLane) installOptions["identity.design-lane"] = opts.designLane;
4033
- const res = await runApi(
4034
- `installing ${slug}@${version}${opts.instance ? ` (${opts.instance})` : ""}`,
4035
- () => client.POST("/me/bundles/{slug}/versions/{version}/install", {
4036
- params: { path: { slug, version } },
4037
- // instance: null/absent = the default instance (reinstall updates in
4038
- // place); a name installs a separate instance.
4039
- body: { installOptions, instance: opts.instance ?? null }
4040
- })
4041
- );
4042
- const status = String(res?.status ?? res?.Status ?? "");
4043
- if (status && status.toLowerCase() !== "completed") {
4044
- fail(`Install did not complete (status=${status}; ${res?.failureReason ?? res?.FailureReason ?? ""}).`);
4045
- }
4046
- const feed = await runApi(
4047
- "materialising skill files",
4048
- () => client.GET("/workspaces/{workspaceId}/memories/feed", {
4049
- // cascadeWorkspaces: skills land in an "Operator Skills" SUB-workspace of
4050
- // the personal workspace, so we recurse from the personal-ws root.
4051
- // includeText: the feed omits bodies by default; we need them for SKILL.md.
4052
- params: {
4053
- path: { workspaceId: personalWsId },
4054
- query: { limit: 200, cascadeWorkspaces: true, includeText: true }
4055
- }
4056
- })
4057
- );
4058
- const rows = feed?.results ?? feed?.Results ?? [];
4059
- const dir = skillsDir(!opts.local);
4060
- const wantInstance = opts.instance || "default";
4061
- const written = [];
4062
- const bundleTagPrefix = `sechroom:bundle:${slug}@`;
4063
- for (const r of rows) {
4064
- const m = r.item ?? r;
4065
- const tags = m.tags ?? m.Tags ?? [];
4066
- if (!hasAny(tags, ROLE_TAGS)) continue;
4067
- if (tagValue2(tags, "target:") !== opts.surface) continue;
4068
- if (!tags.some((t) => t.startsWith(bundleTagPrefix))) continue;
4069
- if ((tagValue2(tags, "sechroom:skill-instance:") ?? "default") !== wantInstance) continue;
4070
- const name = tagValue2(tags, "skill:");
4071
- if (!name) continue;
4072
- const body = m.text ?? m.Text ?? "";
4073
- mkdirSync6(join9(dir, name), { recursive: true });
4074
- writeFileSync6(join9(dir, name, "SKILL.md"), body.endsWith("\n") ? body : body + "\n");
4075
- written.push(name);
4076
- }
4077
- mkdirSync6(dir, { recursive: true });
4078
- const lockPath = join9(dir, LOCK);
4079
- const lock = existsSync9(lockPath) ? JSON.parse(readFileSync6(lockPath, "utf8")) : {};
4080
- lock[slug] = { surface: opts.surface, version, instance: wantInstance, skills: written.sort() };
4081
- writeFileSync6(lockPath, JSON.stringify(lock, null, 2) + "\n");
4082
- if (opts.json) return emit({ slug, version, instance: wantInstance, surface: opts.surface, dir, installed: written }, true);
4083
- const instanceNote = opts.instance ? ` (${opts.instance})` : "";
4084
- console.log(style.green(`Installed ${slug}@${version}${instanceNote} \u2014 ${written.length} skill(s) \u2192 ${dir}`));
4085
- written.forEach((n) => console.log(" " + style.dim("\u2022") + " " + n));
4086
- if (written.length === 0) console.log(style.dim(` (no '${opts.surface}' skill bodies found; check --surface)`));
4087
- });
4088
4055
  skills.command("list").description("List your installed bundles (GET /me/bundle-installs)").option("--json", "machine output").action(async (opts, cmd) => {
4089
4056
  const client = await makeClient(resolveConfig(cmd.optsWithGlobals()));
4090
4057
  const data = await runApi("reading your installs", () => client.GET("/me/bundle-installs", {}));
@@ -4097,24 +4064,22 @@ Examples:
4097
4064
  console.log(` ${i.bundleSlug ?? i.BundleSlug}@${i.bundleVersion ?? i.BundleVersion ?? "?"}${tag}`);
4098
4065
  });
4099
4066
  });
4100
- skills.command("clean [slug]").description(`Remove materialised skill files written by install (default ${DEFAULT_SLUG})`).option("--local", "clean ./.claude/skills instead of ~/.claude/skills").option("--json", "machine output").action(async (slugArg, opts) => {
4101
- const slug = slugArg || DEFAULT_SLUG;
4067
+ skills.command("clean [slug]").description(`Remove skill files materialised by onboard (default ${DEFAULT_SKILLS_SLUG})`).option("--local", "clean ./.claude/skills instead of ~/.claude/skills").option("--json", "machine output").action(async (slugArg, opts) => {
4068
+ const slug = slugArg || DEFAULT_SKILLS_SLUG;
4102
4069
  const dir = skillsDir(!opts.local);
4103
- const lockPath = join9(dir, LOCK);
4104
- if (!existsSync9(lockPath)) fail(`No skills lockfile at ${lockPath}; nothing to clean.`);
4105
- const lock = JSON.parse(readFileSync6(lockPath, "utf8"));
4070
+ const lock = readSkillsLock(dir);
4106
4071
  const entry = lock[slug];
4107
- if (!entry) fail(`No installed record for '${slug}' in ${lockPath}.`);
4072
+ if (!entry) fail(`No materialised skills recorded for '${slug}' in ${join10(dir, SKILLS_LOCK)}.`);
4108
4073
  const removed = [];
4109
4074
  for (const name of entry.skills) {
4110
- const skillPath = join9(dir, name);
4111
- if (existsSync9(skillPath)) {
4075
+ const skillPath = join10(dir, name);
4076
+ if (existsSync10(skillPath)) {
4112
4077
  rmSync2(skillPath, { recursive: true, force: true });
4113
4078
  removed.push(name);
4114
4079
  }
4115
4080
  }
4116
4081
  delete lock[slug];
4117
- writeFileSync6(lockPath, JSON.stringify(lock, null, 2) + "\n");
4082
+ writeSkillsLock(dir, lock);
4118
4083
  if (opts.json) return emit({ slug, removed, dir }, true);
4119
4084
  console.log(style.green(`Removed ${removed.length} skill(s) for ${slug} from ${dir}`));
4120
4085
  });
@@ -4203,22 +4168,24 @@ Examples:
4203
4168
  }
4204
4169
 
4205
4170
  // src/commands/reset.ts
4206
- import { homedir as homedir7 } from "os";
4207
- import { join as join10 } from "path";
4208
- import { existsSync as existsSync10, readFileSync as readFileSync7, rmSync as rmSync3 } from "fs";
4209
- var SKILLS_LOCK = ".sechroom-skills.json";
4210
- var localSkillsDir = () => join10(process.cwd(), ".claude", "skills");
4211
- var globalSkillsDir = () => join10(homedir7(), ".claude", "skills");
4171
+ import { homedir as homedir6 } from "os";
4172
+ import { join as join11 } from "path";
4173
+ import { existsSync as existsSync11, readFileSync as readFileSync7, rmSync as rmSync3 } from "fs";
4174
+ var SKILLS_LOCK2 = ".sechroom-skills.json";
4175
+ var localSkillsDir = () => join11(process.cwd(), ".claude", "skills");
4176
+ var globalSkillsDir = () => join11(homedir6(), ".claude", "skills");
4177
+ var localAgentsDir = () => join11(process.cwd(), ".claude", "agents");
4178
+ var globalAgentsDir = () => join11(homedir6(), ".claude", "agents");
4212
4179
  function removeMaterialisedSkills(dir) {
4213
4180
  const removed = [];
4214
- const lockPath = join10(dir, SKILLS_LOCK);
4215
- if (!existsSync10(lockPath)) return removed;
4181
+ const lockPath = join11(dir, SKILLS_LOCK2);
4182
+ if (!existsSync11(lockPath)) return removed;
4216
4183
  try {
4217
4184
  const lock = JSON.parse(readFileSync7(lockPath, "utf8"));
4218
4185
  for (const entry of Object.values(lock)) {
4219
4186
  for (const name of entry.skills ?? []) {
4220
- const p = join10(dir, name);
4221
- if (existsSync10(p)) {
4187
+ const p = join11(dir, name);
4188
+ if (existsSync11(p)) {
4222
4189
  rmSync3(p, { recursive: true, force: true });
4223
4190
  removed.push(p);
4224
4191
  }
@@ -4263,28 +4230,30 @@ function registerReset(program2) {
4263
4230
  }
4264
4231
  }
4265
4232
  const removed = [];
4266
- const stateDir = join10(process.cwd(), ".sechroom");
4267
- if (existsSync10(stateDir)) {
4233
+ const stateDir = join11(process.cwd(), ".sechroom");
4234
+ if (existsSync11(stateDir)) {
4268
4235
  rmSync3(stateDir, { recursive: true, force: true });
4269
4236
  removed.push(stateDir);
4270
4237
  }
4271
- const legacyCfg = join10(process.cwd(), ".sechroom.json");
4272
- if (existsSync10(legacyCfg)) {
4238
+ const legacyCfg = join11(process.cwd(), ".sechroom.json");
4239
+ if (existsSync11(legacyCfg)) {
4273
4240
  rmSync3(legacyCfg, { force: true });
4274
4241
  removed.push(legacyCfg);
4275
4242
  }
4276
- const legacySem = join10(process.cwd(), ".sem");
4277
- if (existsSync10(legacySem)) {
4243
+ const legacySem = join11(process.cwd(), ".sem");
4244
+ if (existsSync11(legacySem)) {
4278
4245
  rmSync3(legacySem, { force: true });
4279
4246
  removed.push(legacySem);
4280
4247
  }
4281
4248
  removed.push(...removeMaterialisedSkills(localSkillsDir()));
4249
+ removed.push(...removeMaterialisedSkills(localAgentsDir()));
4282
4250
  if (global) {
4283
4251
  const tok = clearToken();
4284
4252
  if (tok) removed.push(tok);
4285
4253
  const cfg = clearPersisted();
4286
4254
  if (cfg) removed.push(cfg);
4287
4255
  removed.push(...removeMaterialisedSkills(globalSkillsDir()));
4256
+ removed.push(...removeMaterialisedSkills(globalAgentsDir()));
4288
4257
  }
4289
4258
  if (json) return emit({ global, removed }, true);
4290
4259
  if (removed.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sechroom/cli",
3
- "version": "2026.6.140-rc.176770e1",
3
+ "version": "2026.6.142-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",