@sechroom/cli 2026.6.136-rc.c2c1009c → 2026.6.138-rc.a8484373
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 +75 -28
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2943,57 +2943,104 @@ I can pin this checkout's lane so operator skills + the continuity hook resolve
|
|
|
2943
2943
|
writePin(code || void 0, design || void 0);
|
|
2944
2944
|
}
|
|
2945
2945
|
|
|
2946
|
-
// src/setup/
|
|
2946
|
+
// src/setup/skill-resolution.ts
|
|
2947
|
+
var SYSTEM_WORKSPACE_ID = "wsp_system";
|
|
2947
2948
|
var ROLE_TAG = "sechroom:role:skill-template";
|
|
2949
|
+
function tagsOf(row) {
|
|
2950
|
+
const m = row?.item ?? row;
|
|
2951
|
+
return m?.tags ?? m?.Tags ?? [];
|
|
2952
|
+
}
|
|
2948
2953
|
function tagValue(tags, prefix) {
|
|
2949
2954
|
return tags.find((t) => t.startsWith(prefix))?.slice(prefix.length);
|
|
2950
2955
|
}
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2956
|
+
function bodyOf(row) {
|
|
2957
|
+
const m = row?.item ?? row;
|
|
2958
|
+
return m?.text ?? m?.Text ?? "";
|
|
2959
|
+
}
|
|
2960
|
+
function skillsFromRows(rows, surface, source) {
|
|
2961
|
+
const out = /* @__PURE__ */ new Map();
|
|
2962
|
+
for (const row of rows ?? []) {
|
|
2963
|
+
const tags = tagsOf(row);
|
|
2964
|
+
if (!tags.includes(ROLE_TAG)) continue;
|
|
2965
|
+
if (tagValue(tags, "target:") !== surface) continue;
|
|
2966
|
+
const name = tagValue(tags, "skill:");
|
|
2967
|
+
if (!name) continue;
|
|
2968
|
+
out.set(name, { name, body: bodyOf(row), source });
|
|
2969
|
+
}
|
|
2970
|
+
return out;
|
|
2971
|
+
}
|
|
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);
|
|
2980
|
+
}
|
|
2981
|
+
return [...merged.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2984
|
+
// src/setup/skills-offer.ts
|
|
2985
|
+
async function fetchFeedRows(cfg, workspaceId) {
|
|
2955
2986
|
try {
|
|
2956
2987
|
const client = await makeClient(cfg);
|
|
2957
2988
|
const feed = await client.GET("/workspaces/{workspaceId}/memories/feed", {
|
|
2958
2989
|
params: {
|
|
2959
|
-
path: { workspaceId
|
|
2990
|
+
path: { workspaceId },
|
|
2991
|
+
// cascadeWorkspaces: skills land in an "Operator Skills" SUB-workspace;
|
|
2992
|
+
// includeText: the feed omits bodies by default, we need them for SKILL.md.
|
|
2960
2993
|
query: { limit: 200, cascadeWorkspaces: true, includeText: true }
|
|
2961
2994
|
}
|
|
2962
2995
|
}).then((r) => r.data).catch(() => void 0);
|
|
2963
|
-
|
|
2996
|
+
return feed?.results ?? feed?.Results ?? [];
|
|
2964
2997
|
} catch {
|
|
2965
|
-
return;
|
|
2998
|
+
return [];
|
|
2966
2999
|
}
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
3000
|
+
}
|
|
3001
|
+
async function maybeOfferSkills(cfg, personalWorkspaceId, opts) {
|
|
3002
|
+
const surface = opts.surface ?? "claude-code";
|
|
3003
|
+
const [systemRows, personalRows] = await Promise.all([
|
|
3004
|
+
fetchFeedRows(cfg, SYSTEM_WORKSPACE_ID),
|
|
3005
|
+
personalWorkspaceId ? fetchFeedRows(cfg, personalWorkspaceId) : Promise.resolve([])
|
|
3006
|
+
]);
|
|
3007
|
+
const resolved = resolveSkills(systemRows, personalRows, surface);
|
|
3008
|
+
if (resolved.length === 0) return;
|
|
3009
|
+
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
|
+
);
|
|
3015
|
+
return;
|
|
2976
3016
|
}
|
|
2977
|
-
const names =
|
|
2978
|
-
if (names.length === 0) return;
|
|
3017
|
+
const names = resolved.map((s) => s.name);
|
|
2979
3018
|
process.stderr.write(
|
|
2980
3019
|
`
|
|
2981
|
-
Found ${style.bold(String(names.length))} operator skill(s)
|
|
3020
|
+
Found ${style.bold(String(names.length))} operator skill(s) available to you: ${names.join(", ")}.
|
|
2982
3021
|
`
|
|
2983
3022
|
);
|
|
2984
3023
|
const dir = join5(homedir5(), ".claude", "skills");
|
|
2985
3024
|
const materialise = opts.yes ? true : canPrompt() ? await promptYesNo(`Write them to ${dir}/ so ${surface} can use them?`) : false;
|
|
2986
3025
|
if (!materialise) return;
|
|
2987
3026
|
const written = [];
|
|
2988
|
-
for (const
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
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);
|
|
2993
3034
|
}
|
|
2994
|
-
process.stderr.write(
|
|
2995
|
-
|
|
2996
|
-
|
|
3035
|
+
process.stderr.write(
|
|
3036
|
+
`${style.green("\u2713")} wrote ${written.length} skill(s) to ${dir}
|
|
3037
|
+
`
|
|
3038
|
+
);
|
|
3039
|
+
await ensureLanePin(cfg, {
|
|
3040
|
+
yes: opts.yes,
|
|
3041
|
+
dryRun: opts.dryRun,
|
|
3042
|
+
clients: [surface]
|
|
3043
|
+
});
|
|
2997
3044
|
}
|
|
2998
3045
|
|
|
2999
3046
|
// src/commands/setup.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sechroom/cli",
|
|
3
|
-
"version": "2026.6.
|
|
3
|
+
"version": "2026.6.138-rc.a8484373",
|
|
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",
|