@sechroom/cli 2026.9.26-rc.fa5538238 → 2026.9.27-rc.1ea98ba09
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 +77 -20
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8308,7 +8308,7 @@ function str(v) {
|
|
|
8308
8308
|
}
|
|
8309
8309
|
|
|
8310
8310
|
// src/commands/hook.ts
|
|
8311
|
-
import { createHash as
|
|
8311
|
+
import { createHash as createHash5 } from "crypto";
|
|
8312
8312
|
import { existsSync as existsSync13, mkdirSync as mkdirSync15, readFileSync as readFileSync14, statSync as statSync4, writeFileSync as writeFileSync14 } from "fs";
|
|
8313
8313
|
import { dirname as dirname14, join as join17 } from "path";
|
|
8314
8314
|
|
|
@@ -8454,7 +8454,7 @@ function installLaneCommitHook(start) {
|
|
|
8454
8454
|
}
|
|
8455
8455
|
|
|
8456
8456
|
// src/commands/session-context.ts
|
|
8457
|
-
import { randomUUID as randomUUID3 } from "crypto";
|
|
8457
|
+
import { createHash as createHash4, randomUUID as randomUUID3 } from "crypto";
|
|
8458
8458
|
import { mkdirSync as mkdirSync14, renameSync as renameSync3, rmSync as rmSync8, writeFileSync as writeFileSync13 } from "fs";
|
|
8459
8459
|
import { dirname as dirname13, join as join16 } from "path";
|
|
8460
8460
|
|
|
@@ -8795,6 +8795,31 @@ function removeDirectoryIfEmpty(path) {
|
|
|
8795
8795
|
|
|
8796
8796
|
// src/commands/session-context.ts
|
|
8797
8797
|
var DYNAMIC_AGENT_CONTEXT_FILE = join16(".sechroom", "CLAUDE.md");
|
|
8798
|
+
function deliveredContext(result, lane) {
|
|
8799
|
+
if (result.status !== "ready") return renderSessionContext(result, lane);
|
|
8800
|
+
const contract = [
|
|
8801
|
+
result.renderVersion,
|
|
8802
|
+
result.text,
|
|
8803
|
+
result.digest,
|
|
8804
|
+
result.revision
|
|
8805
|
+
];
|
|
8806
|
+
if (contract.every((value) => value === void 0)) {
|
|
8807
|
+
return renderSessionContext(result, lane);
|
|
8808
|
+
}
|
|
8809
|
+
if (contract.some((value) => typeof value !== "string" || value.length === 0)) {
|
|
8810
|
+
throw new Error(
|
|
8811
|
+
"session context resolution returned a partial or malformed render contract (renderVersion, text, digest and revision must all be present); refusing to write it and preserving existing compiled skills"
|
|
8812
|
+
);
|
|
8813
|
+
}
|
|
8814
|
+
const text2 = result.text;
|
|
8815
|
+
const actual = createHash4("sha256").update(text2, "utf8").digest("hex");
|
|
8816
|
+
if (result.digest !== actual) {
|
|
8817
|
+
throw new Error(
|
|
8818
|
+
"session context text does not match its digest; refusing to write it and preserving existing compiled skills"
|
|
8819
|
+
);
|
|
8820
|
+
}
|
|
8821
|
+
return text2;
|
|
8822
|
+
}
|
|
8798
8823
|
function checkoutRoot(start) {
|
|
8799
8824
|
const semPath = resolveSemPathForRead(start);
|
|
8800
8825
|
return semPath ? dirname13(dirname13(semPath)) : start;
|
|
@@ -8819,6 +8844,9 @@ function renderSessionContext(result, lane) {
|
|
|
8819
8844
|
`<!-- sechroom-context lane=${JSON.stringify(lane)} workspace=${JSON.stringify(result.workspaceId ?? "")} -->`,
|
|
8820
8845
|
""
|
|
8821
8846
|
];
|
|
8847
|
+
for (const notice of result.notices ?? []) {
|
|
8848
|
+
lines.push(`> Notice: ${notice}`, "");
|
|
8849
|
+
}
|
|
8822
8850
|
for (const member of result.members) {
|
|
8823
8851
|
lines.push(
|
|
8824
8852
|
`<!-- sechroom-context-member key=${JSON.stringify(member.key)} layer=${JSON.stringify(member.layer)} bundle=${JSON.stringify(`${member.bundleSlug}@${member.bundleVersion}`)} component=${JSON.stringify(member.componentSlug)} id=${JSON.stringify(member.sourceId)} sourceVersion=${member.sourceVersion} -->`
|
|
@@ -8832,39 +8860,54 @@ function renderSessionContext(result, lane) {
|
|
|
8832
8860
|
function writeSessionContext(start, lane, result, options = {}) {
|
|
8833
8861
|
const root = checkoutRoot(start);
|
|
8834
8862
|
const path = join16(root, DYNAMIC_AGENT_CONTEXT_FILE);
|
|
8863
|
+
const context = deliveredContext(result, lane);
|
|
8835
8864
|
const skills = materialiseCompiledSkillCompositions(
|
|
8836
8865
|
root,
|
|
8837
8866
|
result.status === "hold" ? {
|
|
8838
8867
|
skills: [],
|
|
8839
|
-
holds: [
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8868
|
+
holds: [
|
|
8869
|
+
{
|
|
8870
|
+
code: "session-context-hold",
|
|
8871
|
+
reason: result.reason?.trim() || "Session context resolution held without a reason.",
|
|
8872
|
+
skillName: null
|
|
8873
|
+
}
|
|
8874
|
+
],
|
|
8844
8875
|
preserveExisting: true
|
|
8845
8876
|
} : { skills: result.skills },
|
|
8846
8877
|
options
|
|
8847
8878
|
);
|
|
8848
|
-
const context = renderSessionContext(result, lane);
|
|
8849
8879
|
mkdirSync14(dirname13(path), { recursive: true });
|
|
8850
8880
|
const temporaryPath = `${path}.${process.pid}.${randomUUID3()}.tmp`;
|
|
8851
8881
|
try {
|
|
8852
|
-
writeFileSync13(
|
|
8853
|
-
|
|
8882
|
+
writeFileSync13(
|
|
8883
|
+
temporaryPath,
|
|
8884
|
+
context.endsWith("\n") ? context : `${context}
|
|
8885
|
+
`,
|
|
8886
|
+
"utf8"
|
|
8887
|
+
);
|
|
8854
8888
|
renameSync3(temporaryPath, path);
|
|
8855
8889
|
} catch (error) {
|
|
8856
8890
|
rmSync8(temporaryPath, { force: true });
|
|
8857
8891
|
throw error;
|
|
8858
8892
|
}
|
|
8859
|
-
return {
|
|
8893
|
+
return {
|
|
8894
|
+
status: result.status,
|
|
8895
|
+
path,
|
|
8896
|
+
context,
|
|
8897
|
+
skills,
|
|
8898
|
+
revision: result.revision ?? null
|
|
8899
|
+
};
|
|
8860
8900
|
}
|
|
8861
8901
|
async function materializeSessionContext(client, cfg, lane, start, options = {}) {
|
|
8862
|
-
const { data, error, response } = await client.POST(
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
|
|
8902
|
+
const { data, error, response } = await client.POST(
|
|
8903
|
+
"/session-context/resolve",
|
|
8904
|
+
{
|
|
8905
|
+
body: {
|
|
8906
|
+
laneId: lane,
|
|
8907
|
+
workspaceId: cfg.workspaceId ?? null
|
|
8908
|
+
}
|
|
8866
8909
|
}
|
|
8867
|
-
|
|
8910
|
+
);
|
|
8868
8911
|
if (!data) {
|
|
8869
8912
|
const detail = error ? JSON.stringify(error) : `HTTP ${response?.status ?? "unknown"}`;
|
|
8870
8913
|
throw new Error(`session context resolution failed: ${detail}`);
|
|
@@ -8873,7 +8916,9 @@ async function materializeSessionContext(client, cfg, lane, start, options = {})
|
|
|
8873
8916
|
return writeSessionContext(start, lane, data, options);
|
|
8874
8917
|
}
|
|
8875
8918
|
function assertSessionContextResult(value) {
|
|
8876
|
-
if (value === null || typeof value !== "object" || !["ready", "hold"].includes(
|
|
8919
|
+
if (value === null || typeof value !== "object" || !["ready", "hold"].includes(
|
|
8920
|
+
String(value.status)
|
|
8921
|
+
) || !Array.isArray(value.members) || !Array.isArray(value.skills)) {
|
|
8877
8922
|
throw new Error(
|
|
8878
8923
|
"session context resolution returned an invalid payload; preserving existing compiled skills"
|
|
8879
8924
|
);
|
|
@@ -9062,7 +9107,7 @@ function intentHash(i) {
|
|
|
9062
9107
|
artifacts: i.artifacts ?? [],
|
|
9063
9108
|
confidence: i.confidence ?? null
|
|
9064
9109
|
});
|
|
9065
|
-
return
|
|
9110
|
+
return createHash5("sha256").update(canonical, "utf8").digest("hex");
|
|
9066
9111
|
}
|
|
9067
9112
|
function recentlyCheckpointed(start, minutes) {
|
|
9068
9113
|
const { lastEpochMs } = readLedger(start);
|
|
@@ -9879,6 +9924,18 @@ Displaced snapshot recovery surfaces:
|
|
|
9879
9924
|
});
|
|
9880
9925
|
emit(data, cmd.optsWithGlobals().json);
|
|
9881
9926
|
});
|
|
9927
|
+
continuity.command("snapshot-seed <id>").description(
|
|
9928
|
+
"Render a snapshot you own or were granted as seed text, at most 16 KiB, with its revision and sha256 digest (GET /continuity/snapshots/{id}/seed)"
|
|
9929
|
+
).action(async (id, _opts, cmd) => {
|
|
9930
|
+
const cfg = resolveConfig(cmd.optsWithGlobals());
|
|
9931
|
+
const data = await runApi(
|
|
9932
|
+
"Rendering snapshot seed",
|
|
9933
|
+
async () => (await makeClient(cfg)).GET("/continuity/snapshots/{id}/seed", {
|
|
9934
|
+
params: { path: { id } }
|
|
9935
|
+
})
|
|
9936
|
+
);
|
|
9937
|
+
emit(data, cmd.optsWithGlobals().json);
|
|
9938
|
+
});
|
|
9882
9939
|
const snapshots = continuity.command("snapshots").description(
|
|
9883
9940
|
"List the caller's own snapshots, including displaced recovery candidates (GET /me/continuity/snapshots)"
|
|
9884
9941
|
).option("--scope <scope>", "Filter by scope").option("--lane <laneId>", "Filter by lane id").action(async (opts, cmd) => {
|
|
@@ -12987,7 +13044,7 @@ Note: CLI memory get omits relationships by default; MCP get_memory includes the
|
|
|
12987
13044
|
}
|
|
12988
13045
|
|
|
12989
13046
|
// src/setup/apply.ts
|
|
12990
|
-
import { createHash as
|
|
13047
|
+
import { createHash as createHash6, randomUUID as randomUUID4 } from "crypto";
|
|
12991
13048
|
import {
|
|
12992
13049
|
chmodSync as chmodSync2,
|
|
12993
13050
|
copyFileSync,
|
|
@@ -13014,7 +13071,7 @@ function normalizeBody(s) {
|
|
|
13014
13071
|
return s.replace(/\r\n/g, "\n").trim();
|
|
13015
13072
|
}
|
|
13016
13073
|
function bodySha256(body) {
|
|
13017
|
-
return
|
|
13074
|
+
return createHash6("sha256").update(normalizeBody(body), "utf8").digest("hex");
|
|
13018
13075
|
}
|
|
13019
13076
|
function renderBlock(write) {
|
|
13020
13077
|
const body = normalizeBody(write.body);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sechroom/cli",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.27-rc.1ea98ba09",
|
|
4
4
|
"description": "Command-line interface for Sechroom — sign in, wire your AI tools, and work with your sechroom from the terminal.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|