@neuralnomads/codenomad-dev 0.20.0-dev-20260911-ea37f97b → 0.20.0-dev-20260917-aa51cbb9
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/README.md +2 -2
- package/dist/api-types.js.map +1 -1
- package/dist/opencode/automation-plugin.test.js +32 -38
- package/dist/opencode/automation-plugin.test.js.map +1 -1
- package/dist/opencode/compatibility/contract-fixture.js +15 -0
- package/dist/opencode/compatibility/contract-fixture.js.map +1 -0
- package/dist/opencode/compatibility/events.js +9 -0
- package/dist/opencode/compatibility/events.js.map +1 -0
- package/dist/opencode/compatibility/location.js +89 -0
- package/dist/opencode/compatibility/location.js.map +1 -0
- package/dist/opencode/compatibility/location.test.js +92 -0
- package/dist/opencode/compatibility/location.test.js.map +1 -0
- package/dist/opencode/compatibility/negotiate.js +73 -0
- package/dist/opencode/compatibility/negotiate.js.map +1 -0
- package/dist/opencode/compatibility/negotiate.test.js +61 -0
- package/dist/opencode/compatibility/negotiate.test.js.map +1 -0
- package/dist/opencode/compatibility/proxy-locations.js +137 -0
- package/dist/opencode/compatibility/proxy-locations.js.map +1 -0
- package/dist/opencode/compatibility/proxy-locations.test.js +42 -0
- package/dist/opencode/compatibility/proxy-locations.test.js.map +1 -0
- package/dist/opencode/compatibility/proxy.js +60 -0
- package/dist/opencode/compatibility/proxy.js.map +1 -0
- package/dist/opencode/compatibility/proxy.test.js +47 -0
- package/dist/opencode/compatibility/proxy.test.js.map +1 -0
- package/dist/opencode/compatibility/requests.js +54 -0
- package/dist/opencode/compatibility/requests.js.map +1 -0
- package/dist/opencode/compatibility/runtime.js +26 -0
- package/dist/opencode/compatibility/runtime.js.map +1 -0
- package/dist/opencode/compatibility/transport.js +112 -0
- package/dist/opencode/compatibility/transport.js.map +1 -0
- package/dist/opencode/compatibility/transport.test.js +83 -0
- package/dist/opencode/compatibility/transport.test.js.map +1 -0
- package/dist/opencode/session-pruning/location.js +16 -0
- package/dist/opencode/session-pruning/location.js.map +1 -0
- package/dist/opencode/session-pruning/package.test.js +37 -0
- package/dist/opencode/session-pruning/package.test.js.map +1 -0
- package/dist/opencode/session-pruning/plugin.js +5 -2
- package/dist/opencode/session-pruning/plugin.js.map +1 -1
- package/dist/opencode/session-pruning/preview-store.js +3 -2
- package/dist/opencode/session-pruning/preview-store.js.map +1 -1
- package/dist/opencode/session-pruning/pruning.test.js +7 -5
- package/dist/opencode/session-pruning/pruning.test.js.map +1 -1
- package/dist/opencode/session-pruning/service.js +5 -4
- package/dist/opencode/session-pruning/service.js.map +1 -1
- package/dist/opencode/session-pruning/service.test.js +65 -53
- package/dist/opencode/session-pruning/service.test.js.map +1 -1
- package/dist/permissions/opencode-replier.js +2 -2
- package/dist/permissions/opencode-replier.js.map +1 -1
- package/dist/permissions/opencode-replier.test.js +1 -1
- package/dist/permissions/opencode-replier.test.js.map +1 -1
- package/dist/permissions/opencode-yolo-metadata.js.map +1 -1
- package/dist/permissions/opencode-yolo-metadata.test.js.map +1 -1
- package/dist/plugins/session-pruning/plugin.mjs +422 -271
- package/dist/server/__tests__/instance-proxy-legacy.test.js +111 -0
- package/dist/server/__tests__/instance-proxy-legacy.test.js.map +1 -0
- package/dist/server/__tests__/instance-proxy.test.js +95 -34
- package/dist/server/__tests__/instance-proxy.test.js.map +1 -1
- package/dist/server/http-server.js +147 -237
- package/dist/server/http-server.js.map +1 -1
- package/dist/server/routes/session-pruning.js +4 -2
- package/dist/server/routes/session-pruning.js.map +1 -1
- package/dist/server/routes/session-pruning.test.js +16 -2
- package/dist/server/routes/session-pruning.test.js.map +1 -1
- package/dist/server/routes/worktrees.js +1 -0
- package/dist/server/routes/worktrees.js.map +1 -1
- package/dist/server/routes/worktrees.test.js +54 -1
- package/dist/server/routes/worktrees.test.js.map +1 -1
- package/dist/workspaces/host-opencode-service.test.js +56 -7
- package/dist/workspaces/host-opencode-service.test.js.map +1 -1
- package/dist/workspaces/instance-client.js.map +1 -1
- package/dist/workspaces/instance-events.js +71 -57
- package/dist/workspaces/instance-events.js.map +1 -1
- package/dist/workspaces/instance-events.test.js +122 -9
- package/dist/workspaces/instance-events.test.js.map +1 -1
- package/dist/workspaces/manager.js +24 -39
- package/dist/workspaces/manager.js.map +1 -1
- package/dist/workspaces/manager.test.js +43 -7
- package/dist/workspaces/manager.test.js.map +1 -1
- package/dist/workspaces/opencode-cli-service.js +56 -29
- package/dist/workspaces/opencode-cli-service.js.map +1 -1
- package/dist/workspaces/opencode-connection-generation.test.js +57 -0
- package/dist/workspaces/opencode-connection-generation.test.js.map +1 -0
- package/dist/workspaces/opencode-service.js +70 -16
- package/dist/workspaces/opencode-service.js.map +1 -1
- package/dist/workspaces/opencode-service.test.js +3 -4
- package/dist/workspaces/opencode-service.test.js.map +1 -1
- package/dist/workspaces/worktree-session-evacuation.js +31 -11
- package/dist/workspaces/worktree-session-evacuation.js.map +1 -1
- package/dist/workspaces/worktree-session-evacuation.test.js +211 -0
- package/dist/workspaces/worktree-session-evacuation.test.js.map +1 -1
- package/dist/workspaces/wsl-opencode-service.test.js +64 -24
- package/dist/workspaces/wsl-opencode-service.test.js.map +1 -1
- package/package.json +3 -3
- package/public/assets/App-BROhwPo9.js +54 -0
- package/public/assets/App-BROhwPo9.js.map +1 -0
- package/public/assets/{FilesTab-CRpGDs1B.js → FilesTab-DY3Vr-3r.js} +3 -3
- package/public/assets/{FilesTab-CRpGDs1B.js.map → FilesTab-DY3Vr-3r.js.map} +1 -1
- package/public/assets/{GitChangesTab-DxFebTiq.js → GitChangesTab-BD6CJngE.js} +3 -3
- package/public/assets/{GitChangesTab-DxFebTiq.js.map → GitChangesTab-BD6CJngE.js.map} +1 -1
- package/public/assets/{SplitFilePanel-DgTMrrO-.js → SplitFilePanel-BdY6d_6m.js} +2 -2
- package/public/assets/{SplitFilePanel-DgTMrrO-.js.map → SplitFilePanel-BdY6d_6m.js.map} +1 -1
- package/public/assets/StatusTab-C-_2yaPa.js +2 -0
- package/public/assets/StatusTab-C-_2yaPa.js.map +1 -0
- package/public/assets/{align-justify-v_yPXSys.js → align-justify-DI8VTZ4G.js} +2 -2
- package/public/assets/{align-justify-v_yPXSys.js.map → align-justify-DI8VTZ4G.js.map} +1 -1
- package/public/assets/{bundle-full-HzL_Jtqk.js → bundle-full-D_M65Eb_.js} +2 -2
- package/public/assets/{bundle-full-HzL_Jtqk.js.map → bundle-full-D_M65Eb_.js.map} +1 -1
- package/public/assets/{client-state-CF-PJ0GG.js → client-state-CWCzCOz6.js} +2 -2
- package/public/assets/{client-state-CF-PJ0GG.js.map → client-state-CWCzCOz6.js.map} +1 -1
- package/public/assets/{diff-viewer-BFDQBDVy.js → diff-viewer-CGPsYEr3.js} +2 -2
- package/public/assets/{diff-viewer-BFDQBDVy.js.map → diff-viewer-CGPsYEr3.js.map} +1 -1
- package/public/assets/index-B8-lAqjr.js +2 -0
- package/public/assets/index-B8-lAqjr.js.map +1 -0
- package/public/assets/index-BeUewQym.js +2 -0
- package/public/assets/index-BeUewQym.js.map +1 -0
- package/public/assets/index-BxRFHpJd.js +2 -0
- package/public/assets/{index-D2UHSOG5.js.map → index-BxRFHpJd.js.map} +1 -1
- package/public/assets/index-Bzv1kU-S.js +2 -0
- package/public/assets/{index-CTKYD_VJ.js.map → index-Bzv1kU-S.js.map} +1 -1
- package/public/assets/index-C9tI4CRG.js +2 -0
- package/public/assets/index-C9tI4CRG.js.map +1 -0
- package/public/assets/index-CGYHFZ6F.js +2 -0
- package/public/assets/index-CGYHFZ6F.js.map +1 -0
- package/public/assets/{index-CHYmKl10.js → index-CMEAjBFp.js} +2 -2
- package/public/assets/index-CMEAjBFp.js.map +1 -0
- package/public/assets/index-Cazypvyc.js +2 -0
- package/public/assets/index-Cazypvyc.js.map +1 -0
- package/public/assets/index-CwqzofWP.js +2 -0
- package/public/assets/index-CwqzofWP.js.map +1 -0
- package/public/assets/index-Da9yOa6q.js +2 -0
- package/public/assets/index-Da9yOa6q.js.map +1 -0
- package/public/assets/{index-RK9gf0uk.js → index-Ddjkirek.js} +2 -2
- package/public/assets/{index-RK9gf0uk.js.map → index-Ddjkirek.js.map} +1 -1
- package/public/assets/index-HHgvEOAH.js +3 -0
- package/public/assets/index-HHgvEOAH.js.map +1 -0
- package/public/assets/index-MeFffHqb.css +1 -0
- package/public/assets/loading-CdhHiSED.css +1 -0
- package/public/assets/{loading-BSB82snY.js → loading-Gqh6NPUr.js} +2 -2
- package/public/assets/{loading-BSB82snY.js.map → loading-Gqh6NPUr.js.map} +1 -1
- package/public/assets/main-Cbx7KdTr.js +38 -0
- package/public/assets/main-Cbx7KdTr.js.map +1 -0
- package/public/assets/{markdown-DtidoL2Z.js → markdown-BWnjyvnX.js} +4 -4
- package/public/assets/{markdown-DtidoL2Z.js.map → markdown-BWnjyvnX.js.map} +1 -1
- package/public/assets/monaco-viewer-BEJIiZWL.js +27 -0
- package/public/assets/monaco-viewer-BEJIiZWL.js.map +1 -0
- package/public/assets/{startup-state-settings-card-BY741Rt0.js → startup-state-settings-card-C4E2Itop.js} +2 -2
- package/public/assets/{startup-state-settings-card-BY741Rt0.js.map → startup-state-settings-card-C4E2Itop.js.map} +1 -1
- package/public/assets/{terminal-square-BdC_jwm3.js → terminal-square-C3wutdV0.js} +2 -2
- package/public/assets/{terminal-square-BdC_jwm3.js.map → terminal-square-C3wutdV0.js.map} +1 -1
- package/public/assets/tool-call-DNsAQ_m4.js +60 -0
- package/public/assets/tool-call-DNsAQ_m4.js.map +1 -0
- package/public/assets/{unified-picker-C0eo1chJ.js → unified-picker-tB7y17Qz.js} +2 -2
- package/public/assets/unified-picker-tB7y17Qz.js.map +1 -0
- package/public/assets/{wrap-text-BuMtdvMx.js → wrap-text-CkBxzt04.js} +2 -2
- package/public/assets/{wrap-text-BuMtdvMx.js.map → wrap-text-CkBxzt04.js.map} +1 -1
- package/public/index.html +4 -4
- package/public/loading.html +5 -5
- package/public/sw.js +1 -1
- package/public/sw.js.map +1 -1
- package/public/assets/App-0-FcHzPS.js +0 -44
- package/public/assets/App-0-FcHzPS.js.map +0 -1
- package/public/assets/StatusTab-LKUA9cbH.js +0 -2
- package/public/assets/StatusTab-LKUA9cbH.js.map +0 -1
- package/public/assets/index-8iPlm2r0.js +0 -2
- package/public/assets/index-8iPlm2r0.js.map +0 -1
- package/public/assets/index-B185mC7m.js +0 -2
- package/public/assets/index-B185mC7m.js.map +0 -1
- package/public/assets/index-Bbj1xF8i.js +0 -2
- package/public/assets/index-Bbj1xF8i.js.map +0 -1
- package/public/assets/index-BsmFN3k1.js +0 -2
- package/public/assets/index-BsmFN3k1.js.map +0 -1
- package/public/assets/index-Bz_OQJYA.css +0 -1
- package/public/assets/index-C52CfqK3.js +0 -2
- package/public/assets/index-C52CfqK3.js.map +0 -1
- package/public/assets/index-CHYmKl10.js.map +0 -1
- package/public/assets/index-CTKYD_VJ.js +0 -2
- package/public/assets/index-D2UHSOG5.js +0 -2
- package/public/assets/index-DDoB_Z36.js +0 -2
- package/public/assets/index-DDoB_Z36.js.map +0 -1
- package/public/assets/index-DcwAtZw-.js +0 -3
- package/public/assets/index-DcwAtZw-.js.map +0 -1
- package/public/assets/index-DxUD3RYr.js +0 -2
- package/public/assets/index-DxUD3RYr.js.map +0 -1
- package/public/assets/loading-CmEVQgyj.css +0 -1
- package/public/assets/main-CZztwrfv.js +0 -48
- package/public/assets/main-CZztwrfv.js.map +0 -1
- package/public/assets/monaco-viewer-CpxDfB-6.js +0 -27
- package/public/assets/monaco-viewer-CpxDfB-6.js.map +0 -1
- package/public/assets/tool-call-DbtCsJ4x.js +0 -60
- package/public/assets/tool-call-DbtCsJ4x.js.map +0 -1
- package/public/assets/unified-picker-C0eo1chJ.js.map +0 -1
|
@@ -19,10 +19,10 @@ const data = { content, time: { created: 1, completed: 3 }, tokens: { input: 123
|
|
|
19
19
|
const input = (indexes = [0, 1]) => ({ sessionID: "s", messageID: "m", revision: revision(content), indexes });
|
|
20
20
|
function fixture(filename = ":memory:") {
|
|
21
21
|
const db = new DatabaseSync(filename);
|
|
22
|
-
db.exec(`CREATE TABLE session_v2(id TEXT PRIMARY KEY, directory TEXT);
|
|
22
|
+
db.exec(`CREATE TABLE session_v2(id TEXT PRIMARY KEY, directory TEXT, project_id TEXT, workspace_id TEXT);
|
|
23
23
|
CREATE TABLE session_message(id TEXT PRIMARY KEY,session_id TEXT,type TEXT,seq INTEGER,data TEXT);
|
|
24
24
|
CREATE TABLE event(aggregate_id TEXT,data TEXT);
|
|
25
|
-
INSERT INTO session_v2 VALUES ('s','/work');`);
|
|
25
|
+
INSERT INTO session_v2 VALUES ('s','/work','p',NULL);`);
|
|
26
26
|
db.prepare("INSERT INTO session_message VALUES ('m','s','assistant',7,?)").run(JSON.stringify(data));
|
|
27
27
|
return db;
|
|
28
28
|
}
|
|
@@ -143,9 +143,11 @@ test("refuses file-backed writes, but supports explicit read-only preview", asyn
|
|
|
143
143
|
const db = fixture(filename);
|
|
144
144
|
try {
|
|
145
145
|
assert.deepEqual(pruneIsolatedMessage(db, input(), "/work"), { status: "blocked", reason: "maintenance_required" });
|
|
146
|
-
assert.deepEqual(await readPruningPreview(filename, input(), "/work"), data);
|
|
147
|
-
assert.equal(await readPruningPreview(filename, input(), "/other"), undefined);
|
|
148
|
-
assert.equal(await readPruningPreview(
|
|
146
|
+
assert.deepEqual(await readPruningPreview(filename, input(), { directory: "/work" }, "p"), data);
|
|
147
|
+
assert.equal(await readPruningPreview(filename, input(), { directory: "/other" }, "p"), undefined);
|
|
148
|
+
assert.equal(await readPruningPreview(filename, input(), { directory: "/work", workspaceID: "foreign" }, "p"), undefined);
|
|
149
|
+
assert.equal(await readPruningPreview(filename, input(), { directory: "/work" }, "foreign"), undefined);
|
|
150
|
+
assert.equal(await readPruningPreview(undefined, input(), { directory: "/work" }, "p"), undefined);
|
|
149
151
|
assert.deepEqual(stored(db), data);
|
|
150
152
|
}
|
|
151
153
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pruning.test.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/pruning.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\"\nimport { test } from \"node:test\"\nimport { DatabaseSync } from \"node:sqlite\"\nimport { mkdtemp, rm } from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\nimport { pruneIsolatedMessage } from \"./isolated-store\"\nimport { previewContent, revision } from \"./planner\"\nimport { contentRevision } from \"./revision\"\nimport { pruneRequestSchema } from \"./contract\"\nimport { readPruningPreview } from \"./preview-store\"\nimport plugin from \"./plugin\"\n\nconst content = [\n { type: \"reasoning\", text: \"thinking\", time: { created: 1, completed: 2 } },\n { type: \"tool\", id: \"call-1\", state: { status: \"completed\", content: [{ type: \"text\", text: \"logs\" }] } },\n { type: \"text\", text: \"Keep the conclusion\" },\n]\nconst data = { content, time: { created: 1, completed: 3 }, tokens: { input: 123 }, snapshot: { start: \"snapshot\" } }\nconst input = (indexes = [0, 1]) => ({ sessionID: \"s\", messageID: \"m\", revision: revision(content), indexes })\nfunction fixture(filename = \":memory:\") {\n const db = new DatabaseSync(filename)\n db.exec(`CREATE TABLE session_v2(id TEXT PRIMARY KEY, directory TEXT);\n CREATE TABLE session_message(id TEXT PRIMARY KEY,session_id TEXT,type TEXT,seq INTEGER,data TEXT);\n CREATE TABLE event(aggregate_id TEXT,data TEXT);\n INSERT INTO session_v2 VALUES ('s','/work');`)\n db.prepare(\"INSERT INTO session_message VALUES ('m','s','assistant',7,?)\").run(JSON.stringify(data))\n return db\n}\nfunction stored(db: DatabaseSync) {\n return JSON.parse(db.prepare(\"SELECT data FROM session_message WHERE id='m'\").get()!.data as string)\n}\n\ntest(\"browser and plugin revisions ignore key order but detect content/order changes\", async () => {\n assert.equal(await contentRevision(content), revision(content))\n assert.equal(revision([{ type: \"text\", text: \"é\" }]), revision([{ text: \"é\", type: \"text\" }]))\n assert.notEqual(revision(content), revision([...content].reverse()))\n})\n\ntest(\"preview reports technical parts only without changing storage\", () => {\n const before = JSON.stringify(data)\n const preview = previewContent(data)\n assert.equal(preview.status, \"preview\")\n if (preview.status !== \"preview\") assert.fail()\n assert.equal(preview.liveMutation, false)\n assert.deepEqual(preview.parts.map(p => [p.index, p.type]), [[0, \"reasoning\"], [1, \"tool\"]])\n assert.equal(JSON.stringify(data), before)\n})\n\ntest(\"isolated SQL prune preserves IDs, ordering, text and metadata\", () => {\n const db = fixture()\n try {\n const result = pruneIsolatedMessage(db, input(), \"/work\")\n assert.equal(result.status, \"pruned\")\n assert.deepEqual(stored(db), { ...data, content: [content[2]] })\n assert.equal(db.prepare(\"SELECT seq FROM session_message\").get()!.seq, 7)\n assert.equal(db.prepare(\"PRAGMA integrity_check\").get()!.integrity_check, \"ok\")\n assert.equal(db.isTransaction, false)\n } finally { db.close() }\n})\n\ntest(\"individual pruning and all-technical messages are supported\", () => {\n const db = fixture()\n try {\n assert.equal(pruneIsolatedMessage(db, input([1]), \"/work\").status, \"pruned\")\n assert.deepEqual(stored(db).content, [content[0], content[2]])\n db.prepare(\"UPDATE session_message SET data=?\").run(JSON.stringify({ ...data, content: [content[0]] }))\n assert.equal(pruneIsolatedMessage(db, { ...input([0]), revision: revision([content[0]]) }, \"/work\").status, \"pruned\")\n assert.deepEqual(stored(db).content, [])\n } finally { db.close() }\n})\n\nfor (const [name, change] of [\n [\"incomplete message\", (d: any) => { delete d.time.completed }],\n [\"running tool\", (d: any) => { d.content[1].state.status = \"running\" }],\n [\"unknown content kind\", (d: any) => { d.content.push({ type: \"future\" }) }],\n] as const) {\n test(`rejects ${name} without partial changes`, () => {\n const db = fixture()\n try {\n const changed = structuredClone(data); change(changed)\n db.prepare(\"UPDATE session_message SET data=?\").run(JSON.stringify(changed))\n assert.equal(pruneIsolatedMessage(db, input(), \"/work\").status, \"blocked\")\n assert.deepEqual(stored(db), changed)\n assert.equal(db.isTransaction, false)\n } finally { db.close() }\n })\n}\n\ntest(\"rejects stale revisions, text selections, out-of-range and wrong ownership\", () => {\n const db = fixture()\n try {\n for (const request of [input([2]), input([99]), { ...input(), revision: \"0\".repeat(64) }, { ...input(), sessionID: \"other\" }]) {\n assert.equal(pruneIsolatedMessage(db, request, \"/work\").status, \"blocked\")\n assert.deepEqual(stored(db), data)\n }\n assert.equal(pruneIsolatedMessage(db, input(), \"/elsewhere\").status, \"blocked\")\n } finally { db.close() }\n})\n\ntest(\"rejects replacement content, duplicate indexes and oversized selections at the contract\", () => {\n for (const invalid of [{ ...input(), content: [] }, input([]), input([1, 1]), input([-1]), input(Array.from({ length: 100_002 }, (_, i) => i))]) {\n assert.equal(pruneRequestSchema.safeParse(invalid).success, false)\n }\n})\n\ntest(\"retained events and triggers fail closed rather than silently corrupt replay\", () => {\n const db = fixture()\n try {\n db.exec(\"INSERT INTO event VALUES ('s','{}')\")\n assert.deepEqual(pruneIsolatedMessage(db, input(), \"/work\"), { status: \"blocked\", reason: \"unsupported_storage\" })\n db.exec(\"DELETE FROM event; CREATE TRIGGER guard AFTER UPDATE ON session_message BEGIN SELECT 1; END\")\n assert.equal(pruneIsolatedMessage(db, input(), \"/work\").status, \"blocked\")\n assert.deepEqual(stored(db), data)\n } finally { db.close() }\n})\n\ntest(\"whole-message cleanup supports more than 4096 technical parts\", () => {\n const db = fixture()\n try {\n const content = [...Array.from({ length: 5000 }, () => ({ type: \"reasoning\", text: \"remove\" })), { type: \"text\", text: \"keep\" }]\n db.prepare(\"UPDATE session_message SET data=?\").run(JSON.stringify({ ...data, content }))\n const result = pruneIsolatedMessage(db, { ...input(), revision: revision(content), indexes: Array.from({ length: 5000 }, (_, i) => i) }, \"/work\")\n assert.equal(result.status, \"pruned\")\n if (result.status === \"pruned\") assert.equal(result.removedCount, 5000)\n assert.deepEqual(stored(db).content, [content.at(-1)])\n } finally { db.close() }\n})\n\ntest(\"refuses file-backed writes, but supports explicit read-only preview\", async () => {\n const dir = await mkdtemp(path.join(os.tmpdir(), \"codenomad-pruning-test-\"))\n const filename = path.join(dir, \"fixture.db\")\n const db = fixture(filename)\n try {\n assert.deepEqual(pruneIsolatedMessage(db, input(), \"/work\"), { status: \"blocked\", reason: \"maintenance_required\" })\n assert.deepEqual(await readPruningPreview(filename, input(), \"/work\"), data)\n assert.equal(await readPruningPreview(filename, input(), \"/other\"), undefined)\n assert.equal(await readPruningPreview(undefined, input(), \"/work\"), undefined)\n assert.deepEqual(stored(db), data)\n } finally { db.close(); await rm(dir, { recursive: true, force: true }) }\n})\n\ntest(\"loading the plugin registers RPC without reading or writing a database\", async () => {\n let handlers: any\n let disposed = false\n const cleanup = await plugin.setup({\n location: { directory: \"/work\" }, options: {},\n rpc: { register: async (definition: any, implementation: any) => {\n assert.equal(definition.id, \"codenomad.session-pruning\")\n handlers = implementation\n return { dispose: () => { disposed = true } }\n } },\n } as any)\n assert.equal(typeof handlers.prune, \"function\")\n assert.equal(typeof handlers.preview, \"function\")\n await cleanup?.()\n assert.equal(disposed, true)\n})\n"]}
|
|
1
|
+
{"version":3,"file":"pruning.test.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/pruning.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\"\nimport { test } from \"node:test\"\nimport { DatabaseSync } from \"node:sqlite\"\nimport { mkdtemp, rm } from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\nimport { pruneIsolatedMessage } from \"./isolated-store\"\nimport { previewContent, revision } from \"./planner\"\nimport { contentRevision } from \"./revision\"\nimport { pruneRequestSchema } from \"./contract\"\nimport { readPruningPreview } from \"./preview-store\"\nimport plugin from \"./plugin\"\n\nconst content = [\n { type: \"reasoning\", text: \"thinking\", time: { created: 1, completed: 2 } },\n { type: \"tool\", id: \"call-1\", state: { status: \"completed\", content: [{ type: \"text\", text: \"logs\" }] } },\n { type: \"text\", text: \"Keep the conclusion\" },\n]\nconst data = { content, time: { created: 1, completed: 3 }, tokens: { input: 123 }, snapshot: { start: \"snapshot\" } }\nconst input = (indexes = [0, 1]) => ({ sessionID: \"s\", messageID: \"m\", revision: revision(content), indexes })\nfunction fixture(filename = \":memory:\") {\n const db = new DatabaseSync(filename)\n db.exec(`CREATE TABLE session_v2(id TEXT PRIMARY KEY, directory TEXT, project_id TEXT, workspace_id TEXT);\n CREATE TABLE session_message(id TEXT PRIMARY KEY,session_id TEXT,type TEXT,seq INTEGER,data TEXT);\n CREATE TABLE event(aggregate_id TEXT,data TEXT);\n INSERT INTO session_v2 VALUES ('s','/work','p',NULL);`)\n db.prepare(\"INSERT INTO session_message VALUES ('m','s','assistant',7,?)\").run(JSON.stringify(data))\n return db\n}\nfunction stored(db: DatabaseSync) {\n return JSON.parse(db.prepare(\"SELECT data FROM session_message WHERE id='m'\").get()!.data as string)\n}\n\ntest(\"browser and plugin revisions ignore key order but detect content/order changes\", async () => {\n assert.equal(await contentRevision(content), revision(content))\n assert.equal(revision([{ type: \"text\", text: \"é\" }]), revision([{ text: \"é\", type: \"text\" }]))\n assert.notEqual(revision(content), revision([...content].reverse()))\n})\n\ntest(\"preview reports technical parts only without changing storage\", () => {\n const before = JSON.stringify(data)\n const preview = previewContent(data)\n assert.equal(preview.status, \"preview\")\n if (preview.status !== \"preview\") assert.fail()\n assert.equal(preview.liveMutation, false)\n assert.deepEqual(preview.parts.map(p => [p.index, p.type]), [[0, \"reasoning\"], [1, \"tool\"]])\n assert.equal(JSON.stringify(data), before)\n})\n\ntest(\"isolated SQL prune preserves IDs, ordering, text and metadata\", () => {\n const db = fixture()\n try {\n const result = pruneIsolatedMessage(db, input(), \"/work\")\n assert.equal(result.status, \"pruned\")\n assert.deepEqual(stored(db), { ...data, content: [content[2]] })\n assert.equal(db.prepare(\"SELECT seq FROM session_message\").get()!.seq, 7)\n assert.equal(db.prepare(\"PRAGMA integrity_check\").get()!.integrity_check, \"ok\")\n assert.equal(db.isTransaction, false)\n } finally { db.close() }\n})\n\ntest(\"individual pruning and all-technical messages are supported\", () => {\n const db = fixture()\n try {\n assert.equal(pruneIsolatedMessage(db, input([1]), \"/work\").status, \"pruned\")\n assert.deepEqual(stored(db).content, [content[0], content[2]])\n db.prepare(\"UPDATE session_message SET data=?\").run(JSON.stringify({ ...data, content: [content[0]] }))\n assert.equal(pruneIsolatedMessage(db, { ...input([0]), revision: revision([content[0]]) }, \"/work\").status, \"pruned\")\n assert.deepEqual(stored(db).content, [])\n } finally { db.close() }\n})\n\nfor (const [name, change] of [\n [\"incomplete message\", (d: any) => { delete d.time.completed }],\n [\"running tool\", (d: any) => { d.content[1].state.status = \"running\" }],\n [\"unknown content kind\", (d: any) => { d.content.push({ type: \"future\" }) }],\n] as const) {\n test(`rejects ${name} without partial changes`, () => {\n const db = fixture()\n try {\n const changed = structuredClone(data); change(changed)\n db.prepare(\"UPDATE session_message SET data=?\").run(JSON.stringify(changed))\n assert.equal(pruneIsolatedMessage(db, input(), \"/work\").status, \"blocked\")\n assert.deepEqual(stored(db), changed)\n assert.equal(db.isTransaction, false)\n } finally { db.close() }\n })\n}\n\ntest(\"rejects stale revisions, text selections, out-of-range and wrong ownership\", () => {\n const db = fixture()\n try {\n for (const request of [input([2]), input([99]), { ...input(), revision: \"0\".repeat(64) }, { ...input(), sessionID: \"other\" }]) {\n assert.equal(pruneIsolatedMessage(db, request, \"/work\").status, \"blocked\")\n assert.deepEqual(stored(db), data)\n }\n assert.equal(pruneIsolatedMessage(db, input(), \"/elsewhere\").status, \"blocked\")\n } finally { db.close() }\n})\n\ntest(\"rejects replacement content, duplicate indexes and oversized selections at the contract\", () => {\n for (const invalid of [{ ...input(), content: [] }, input([]), input([1, 1]), input([-1]), input(Array.from({ length: 100_002 }, (_, i) => i))]) {\n assert.equal(pruneRequestSchema.safeParse(invalid).success, false)\n }\n})\n\ntest(\"retained events and triggers fail closed rather than silently corrupt replay\", () => {\n const db = fixture()\n try {\n db.exec(\"INSERT INTO event VALUES ('s','{}')\")\n assert.deepEqual(pruneIsolatedMessage(db, input(), \"/work\"), { status: \"blocked\", reason: \"unsupported_storage\" })\n db.exec(\"DELETE FROM event; CREATE TRIGGER guard AFTER UPDATE ON session_message BEGIN SELECT 1; END\")\n assert.equal(pruneIsolatedMessage(db, input(), \"/work\").status, \"blocked\")\n assert.deepEqual(stored(db), data)\n } finally { db.close() }\n})\n\ntest(\"whole-message cleanup supports more than 4096 technical parts\", () => {\n const db = fixture()\n try {\n const content = [...Array.from({ length: 5000 }, () => ({ type: \"reasoning\", text: \"remove\" })), { type: \"text\", text: \"keep\" }]\n db.prepare(\"UPDATE session_message SET data=?\").run(JSON.stringify({ ...data, content }))\n const result = pruneIsolatedMessage(db, { ...input(), revision: revision(content), indexes: Array.from({ length: 5000 }, (_, i) => i) }, \"/work\")\n assert.equal(result.status, \"pruned\")\n if (result.status === \"pruned\") assert.equal(result.removedCount, 5000)\n assert.deepEqual(stored(db).content, [content.at(-1)])\n } finally { db.close() }\n})\n\ntest(\"refuses file-backed writes, but supports explicit read-only preview\", async () => {\n const dir = await mkdtemp(path.join(os.tmpdir(), \"codenomad-pruning-test-\"))\n const filename = path.join(dir, \"fixture.db\")\n const db = fixture(filename)\n try {\n assert.deepEqual(pruneIsolatedMessage(db, input(), \"/work\"), { status: \"blocked\", reason: \"maintenance_required\" })\n assert.deepEqual(await readPruningPreview(filename, input(), { directory: \"/work\" }, \"p\"), data)\n assert.equal(await readPruningPreview(filename, input(), { directory: \"/other\" }, \"p\"), undefined)\n assert.equal(await readPruningPreview(filename, input(), { directory: \"/work\", workspaceID: \"foreign\" }, \"p\"), undefined)\n assert.equal(await readPruningPreview(filename, input(), { directory: \"/work\" }, \"foreign\"), undefined)\n assert.equal(await readPruningPreview(undefined, input(), { directory: \"/work\" }, \"p\"), undefined)\n assert.deepEqual(stored(db), data)\n } finally { db.close(); await rm(dir, { recursive: true, force: true }) }\n})\n\ntest(\"loading the plugin registers RPC without reading or writing a database\", async () => {\n let handlers: any\n let disposed = false\n const cleanup = await plugin.setup({\n location: { directory: \"/work\" }, options: {},\n rpc: { register: async (definition: any, implementation: any) => {\n assert.equal(definition.id, \"codenomad.session-pruning\")\n handlers = implementation\n return { dispose: () => { disposed = true } }\n } },\n } as any)\n assert.equal(typeof handlers.prune, \"function\")\n assert.equal(typeof handlers.preview, \"function\")\n await cleanup?.()\n assert.equal(disposed, true)\n})\n"]}
|
|
@@ -5,6 +5,7 @@ import { storageKey, validateClaimFence } from "./claim-fence";
|
|
|
5
5
|
import { pruneTransaction } from "./transaction";
|
|
6
6
|
import { pruneRequestSchema } from "./contract";
|
|
7
7
|
import { pruningDatabasePath } from "./database-path";
|
|
8
|
+
import { readLocationRef, sameLocation } from "./location";
|
|
8
9
|
// Only an explicit pruning RPC calls this service; loading the plugin never prunes.
|
|
9
10
|
// No database access is exposed through CodeNomad's HTTP broker.
|
|
10
11
|
export async function pruneBoundMessage(ctx, input, signal) {
|
|
@@ -15,9 +16,10 @@ export async function pruneBoundMessage(ctx, input, signal) {
|
|
|
15
16
|
return { status: "blocked", reason: "unsupported_storage" };
|
|
16
17
|
}
|
|
17
18
|
const session = await ctx.session.get({ sessionID: request.sessionID });
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
const location = readLocationRef(session.location);
|
|
20
|
+
if (!sameLocation(location, readLocationRef(ctx.location)) || session.projectID !== ctx.location.project.id) {
|
|
20
21
|
return { status: "blocked", reason: "not_deletable" };
|
|
22
|
+
}
|
|
21
23
|
const filename = await realpath(configured);
|
|
22
24
|
const { DatabaseSync } = await import("node:sqlite");
|
|
23
25
|
const key = `pruning/binding/${randomUUID()}`;
|
|
@@ -34,8 +36,7 @@ export async function pruneBoundMessage(ctx, input, signal) {
|
|
|
34
36
|
try {
|
|
35
37
|
return pruneTransaction(db, request, () => validateClaimFence(db, request.sessionID, {
|
|
36
38
|
key: storageKey(key), nonce,
|
|
37
|
-
directory:
|
|
38
|
-
workspaceID: session.location.workspaceID,
|
|
39
|
+
directory: location.directory, workspaceID: location.workspaceID, projectID: session.projectID,
|
|
39
40
|
}), storageKey("pruning/receipt/"));
|
|
40
41
|
}
|
|
41
42
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAoB,MAAM,YAAY,CAAA;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/service.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\"\nimport { realpath } from \"node:fs/promises\"\nimport path from \"node:path\"\nimport type { Plugin } from \"@opencode/plugin\"\nimport { storageKey, validateClaimFence } from \"./claim-fence\"\nimport { pruneTransaction } from \"./transaction\"\nimport { pruneRequestSchema, type PruneResult } from \"./contract\"\nimport { pruningDatabasePath } from \"./database-path\"\nimport { readLocationRef, sameLocation } from \"./location\"\n\n// Only an explicit pruning RPC calls this service; loading the plugin never prunes.\n// No database access is exposed through CodeNomad's HTTP broker.\nexport async function pruneBoundMessage(\n ctx: Plugin.Context, input: unknown, signal: AbortSignal,\n): Promise<PruneResult> {\n const request = pruneRequestSchema.parse(input)\n const configured = pruningDatabasePath(ctx.options.databasePath, ctx.app.channel)\n if (typeof configured !== \"string\" || !path.isAbsolute(configured)\n || (process.platform === \"win32\" && configured.replaceAll(\"/\", \"\\\\\").startsWith(\"\\\\\\\\\"))) {\n return { status: \"blocked\", reason: \"unsupported_storage\" }\n }\n const session = await ctx.session.get({ sessionID: request.sessionID })\n const location = readLocationRef(session.location)\n if (!sameLocation(location, readLocationRef(ctx.location)) || session.projectID !== ctx.location.project.id) {\n return { status: \"blocked\", reason: \"not_deletable\" }\n }\n const filename = await realpath(configured)\n const { DatabaseSync } = await import(\"node:sqlite\")\n const key = `pruning/binding/${randomUUID()}`\n const nonce = randomUUID()\n signal.throwIfAborted()\n await ctx.storage.set(key, nonce)\n try {\n signal.throwIfAborted()\n const db = new DatabaseSync(filename)\n try {\n // A blocking busy timeout could deadlock Core's async transaction on the\n // same event loop. Return busy immediately; don't interrupt native work.\n db.exec(\"PRAGMA busy_timeout=0\")\n try {\n return pruneTransaction(db, request, () => validateClaimFence(db, request.sessionID, {\n key: storageKey(key), nonce,\n directory: location.directory, workspaceID: location.workspaceID, projectID: session.projectID,\n }), storageKey(\"pruning/receipt/\"))\n } catch (error) {\n const code = (error as { errcode?: number; code?: string }).errcode\n return { status: \"blocked\", reason: code === 5 || code === 6 || (error as { code?: string }).code === \"SQLITE_BUSY\"\n ? \"maintenance_required\" : \"unsupported_storage\" }\n }\n } finally { db.close() }\n } finally {\n // Cleanup failure must not turn a committed prune into a failed response.\n await ctx.storage.remove(key).catch(() => {})\n }\n}\n"]}
|
|
@@ -11,64 +11,76 @@ import { revision } from "./planner";
|
|
|
11
11
|
// Exercise the real RPC handlers, storage challenge and file-backed transaction.
|
|
12
12
|
// No shared service, user configuration or real conversation is involved.
|
|
13
13
|
for (const version of ["0.0.0-beta-19425", "future-release", undefined]) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
for (const workspaceID of [undefined, "legacy-native-workspace"]) {
|
|
15
|
+
test(`pruning uses storage capabilities, not runtime version ${version}, workspace ${workspaceID}`, async () => {
|
|
16
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "pruning-capabilities-"));
|
|
17
|
+
const filename = path.join(root, "fixture.db");
|
|
18
|
+
const db = new DatabaseSync(filename);
|
|
19
|
+
const content = [{ type: "reasoning", text: "REMOVE" }, { type: "text", text: "KEEP" }];
|
|
20
|
+
const data = { time: { completed: 1 }, content };
|
|
21
|
+
const input = { sessionID: "s", messageID: "m", revision: revision(content), indexes: [0] };
|
|
22
|
+
let handlers;
|
|
23
|
+
const events = [];
|
|
24
|
+
let cleanup = undefined;
|
|
25
|
+
try {
|
|
26
|
+
db.exec(`CREATE TABLE session_v2(id TEXT PRIMARY KEY,directory TEXT,project_id TEXT,workspace_id TEXT,time_suspended INTEGER,time_compacting INTEGER,revert TEXT);
|
|
26
27
|
CREATE TABLE event_sequence(aggregate_id TEXT PRIMARY KEY,owner_id TEXT);
|
|
27
28
|
INSERT INTO event_sequence VALUES('s',NULL);
|
|
28
29
|
CREATE TABLE event(aggregate_id TEXT);
|
|
29
30
|
CREATE TABLE kv(key TEXT PRIMARY KEY,value TEXT,time_created INTEGER,time_updated INTEGER);
|
|
30
31
|
CREATE TABLE session_message(id TEXT PRIMARY KEY,session_id TEXT,type TEXT,data TEXT);`);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
db.prepare("INSERT INTO session_v2 VALUES('s',?,'p',?,NULL,NULL,NULL)").run(storageDirectory(root), workspaceID ?? null);
|
|
33
|
+
db.prepare("INSERT INTO session_message VALUES('m','s','assistant',?)").run(JSON.stringify(data));
|
|
34
|
+
const location = { directory: root, workspaceID, project: { id: "p" } };
|
|
35
|
+
cleanup = await plugin.setup({
|
|
36
|
+
app: { version },
|
|
37
|
+
options: { databasePath: filename },
|
|
38
|
+
location,
|
|
39
|
+
session: { get: async () => ({ location: { directory: root, workspaceID }, projectID: "p" }) },
|
|
40
|
+
storage: {
|
|
41
|
+
set: async (key, value) => {
|
|
42
|
+
db.prepare("INSERT INTO kv VALUES(?,?,1,1)").run(storageKey(key), JSON.stringify(value));
|
|
43
|
+
},
|
|
44
|
+
remove: async (key) => { db.prepare("DELETE FROM kv WHERE key=?").run(storageKey(key)); },
|
|
41
45
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
46
|
+
rpc: { register: async (_definition, implementation) => {
|
|
47
|
+
handlers = implementation;
|
|
48
|
+
return { dispose: async () => { }, events: { emit: async (...event) => { events.push(event); } } };
|
|
49
|
+
} },
|
|
50
|
+
});
|
|
51
|
+
assert.equal((await handlers.preview({ sessionID: "s", messageID: "m" })).liveMutation, true);
|
|
52
|
+
const call = { signal: new AbortController().signal };
|
|
53
|
+
location.workspaceID = "foreign-context";
|
|
54
|
+
assert.deepEqual(await handlers.preview({ sessionID: "s", messageID: "m" }), { status: "blocked", reason: "not_deletable" });
|
|
55
|
+
assert.deepEqual(await handlers.prune(input, call), { status: "blocked", reason: "not_deletable" });
|
|
56
|
+
assert.equal(db.prepare("SELECT count(*) AS n FROM kv").get().n, 0);
|
|
57
|
+
location.workspaceID = workspaceID;
|
|
58
|
+
db.exec("UPDATE session_v2 SET workspace_id='foreign-storage'");
|
|
59
|
+
assert.deepEqual(await handlers.preview({ sessionID: "s", messageID: "m" }), { status: "blocked", reason: "unavailable" });
|
|
60
|
+
assert.deepEqual(await handlers.prune(input, call), { status: "blocked", reason: "not_deletable" });
|
|
61
|
+
db.prepare("UPDATE session_v2 SET workspace_id=?").run(workspaceID ?? null);
|
|
62
|
+
// Native storage capabilities still fail closed irrespective of the label.
|
|
63
|
+
db.exec("ALTER TABLE session_v2 RENAME COLUMN time_suspended TO missing_claim");
|
|
64
|
+
assert.deepEqual(await handlers.prune(input, call), { status: "blocked", reason: "unsupported_storage" });
|
|
65
|
+
assert.deepEqual(JSON.parse(db.prepare("SELECT data FROM session_message").get().data), data);
|
|
66
|
+
assert.equal(events.length, 0);
|
|
67
|
+
db.exec("ALTER TABLE session_v2 RENAME COLUMN missing_claim TO time_suspended");
|
|
68
|
+
db.exec("UPDATE session_v2 SET time_suspended=1");
|
|
69
|
+
assert.deepEqual(await handlers.prune(input, call), { status: "blocked", reason: "maintenance_required" });
|
|
70
|
+
db.exec("UPDATE session_v2 SET time_suspended=NULL");
|
|
71
|
+
const result = await handlers.prune(input, call);
|
|
72
|
+
assert.equal(result.status, "pruned");
|
|
73
|
+
assert.deepEqual(await handlers.prune(input, call), result);
|
|
74
|
+
assert.deepEqual(JSON.parse(db.prepare("SELECT data FROM session_message").get().data).content, [content[1]]);
|
|
75
|
+
assert.equal(events.length, 2);
|
|
76
|
+
assert.equal(db.prepare("SELECT count(*) AS n FROM kv").get().n, 1, "only the atomic receipt remains");
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
await cleanup?.();
|
|
80
|
+
db.close();
|
|
81
|
+
await rm(root, { recursive: true, force: true });
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
73
85
|
}
|
|
74
86
|
//# sourceMappingURL=service.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.test.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/service.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\"\nimport { test } from \"node:test\"\nimport { DatabaseSync } from \"node:sqlite\"\nimport { mkdtemp, rm } from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\nimport plugin from \"./plugin\"\nimport { storageDirectory } from \"./storage-path\"\nimport { storageKey } from \"./claim-fence\"\nimport { revision } from \"./planner\"\n\n// Exercise the real RPC handlers, storage challenge and file-backed transaction.\n// No shared service, user configuration or real conversation is involved.\nfor (const version of [\"0.0.0-beta-19425\", \"future-release\", undefined]) {\n test(`pruning uses storage capabilities, not runtime version ${version}`, async () => {\n const root = await mkdtemp(path.join(os.tmpdir(), \"pruning-capabilities-\"))\n const filename = path.join(root, \"fixture.db\")\n const db = new DatabaseSync(filename)\n const content = [{ type: \"reasoning\", text: \"REMOVE\" }, { type: \"text\", text: \"KEEP\" }]\n const data = { time: { completed: 1 }, content }\n const input = { sessionID: \"s\", messageID: \"m\", revision: revision(content), indexes: [0] }\n let handlers: any\n const events: unknown[] = []\n let cleanup: (() => unknown) | void = undefined\n try {\n db.exec(`CREATE TABLE session_v2(id TEXT PRIMARY KEY,directory TEXT,project_id TEXT,workspace_id TEXT,time_suspended INTEGER,time_compacting INTEGER,revert TEXT);\n CREATE TABLE event_sequence(aggregate_id TEXT PRIMARY KEY,owner_id TEXT);\n INSERT INTO event_sequence VALUES('s',NULL);\n CREATE TABLE event(aggregate_id TEXT);\n CREATE TABLE kv(key TEXT PRIMARY KEY,value TEXT,time_created INTEGER,time_updated INTEGER);\n CREATE TABLE session_message(id TEXT PRIMARY KEY,session_id TEXT,type TEXT,data TEXT);`)\n db.prepare(\"INSERT INTO session_v2 VALUES('s',?,'p',NULL,NULL,NULL,NULL)\").run(storageDirectory(root))\n db.prepare(\"INSERT INTO session_message VALUES('m','s','assistant',?)\").run(JSON.stringify(data))\n cleanup = await plugin.setup({\n app: { version },\n options: { databasePath: filename },\n location: { directory: root, project: { id: \"p\" } },\n session: { get: async () => ({ location: { directory: root }, projectID: \"p\" }) },\n storage: {\n set: async (key: string, value: unknown) => {\n db.prepare(\"INSERT INTO kv VALUES(?,?,1,1)\").run(storageKey(key), JSON.stringify(value))\n },\n remove: async (key: string) => { db.prepare(\"DELETE FROM kv WHERE key=?\").run(storageKey(key)) },\n },\n rpc: { register: async (_definition: unknown, implementation: unknown) => {\n handlers = implementation\n return { dispose: async () => {}, events: { emit: async (...event: unknown[]) => { events.push(event) } } }\n } },\n } as any)\n assert.equal((await handlers.preview({ sessionID: \"s\", messageID: \"m\" })).liveMutation, true)\n const call = { signal: new AbortController().signal }\n // Native storage capabilities still fail closed irrespective of the label.\n db.exec(\"ALTER TABLE session_v2 RENAME COLUMN time_suspended TO missing_claim\")\n assert.deepEqual(await handlers.prune(input, call), { status: \"blocked\", reason: \"unsupported_storage\" })\n assert.deepEqual(JSON.parse(db.prepare(\"SELECT data FROM session_message\").get()!.data as string), data)\n assert.equal(events.length, 0)\n db.exec(\"ALTER TABLE session_v2 RENAME COLUMN missing_claim TO time_suspended\")\n db.exec(\"UPDATE session_v2 SET time_suspended=1\")\n assert.deepEqual(await handlers.prune(input, call), { status: \"blocked\", reason: \"maintenance_required\" })\n db.exec(\"UPDATE session_v2 SET time_suspended=NULL\")\n const result = await handlers.prune(input, call)\n assert.equal(result.status, \"pruned\")\n assert.deepEqual(await handlers.prune(input, call), result)\n assert.deepEqual(JSON.parse(db.prepare(\"SELECT data FROM session_message\").get()!.data as string).content, [content[1]])\n assert.equal(events.length, 2)\n assert.equal(db.prepare(\"SELECT count(*) AS n FROM kv\").get()!.n, 1, \"only the atomic receipt remains\")\n } finally {\n await cleanup?.()\n db.close()\n await rm(root, { recursive: true, force: true })\n }\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"service.test.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/service.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,MAAM,MAAM,UAAU,CAAA;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAEpC,iFAAiF;AACjF,0EAA0E;AAC1E,KAAK,MAAM,OAAO,IAAI,CAAC,kBAAkB,EAAE,gBAAgB,EAAE,SAAS,CAAC,EAAE,CAAC;IACzE,KAAK,MAAM,WAAW,IAAI,CAAC,SAAS,EAAE,yBAAyB,CAAC,EAAE,CAAC;QAClE,IAAI,CAAC,0DAA0D,OAAO,eAAe,WAAW,EAAE,EAAE,KAAK,IAAI,EAAE;YAC7G,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,uBAAuB,CAAC,CAAC,CAAA;YAC3E,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;YAC9C,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,QAAQ,CAAC,CAAA;YACrC,MAAM,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;YACvF,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,CAAA;YAChD,MAAM,KAAK,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;YAC3F,IAAI,QAAa,CAAA;YACjB,MAAM,MAAM,GAAc,EAAE,CAAA;YAC5B,IAAI,OAAO,GAA2B,SAAS,CAAA;YAC/C,IAAI,CAAC;gBACH,EAAE,CAAC,IAAI,CAAC;;;;;+FAKiF,CAAC,CAAA;gBAC1F,EAAE,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,WAAW,IAAI,IAAI,CAAC,CAAA;gBACxH,EAAE,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;gBACjG,MAAM,QAAQ,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,CAAA;gBACvE,OAAO,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;oBAC3B,GAAG,EAAE,EAAE,OAAO,EAAE;oBAChB,OAAO,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE;oBACnC,QAAQ;oBACR,OAAO,EAAE,EAAE,GAAG,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE;oBAC9F,OAAO,EAAE;wBACP,GAAG,EAAE,KAAK,EAAE,GAAW,EAAE,KAAc,EAAE,EAAE;4BACzC,EAAE,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAA;wBAC1F,CAAC;wBACD,MAAM,EAAE,KAAK,EAAE,GAAW,EAAE,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA,CAAC,CAAC;qBACjG;oBACD,GAAG,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAoB,EAAE,cAAuB,EAAE,EAAE;4BACvE,QAAQ,GAAG,cAAc,CAAA;4BACzB,OAAO,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAgB,EAAE,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC,EAAE,EAAE,CAAA;wBAC7G,CAAC,EAAE;iBACG,CAAC,CAAA;gBACT,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;gBAC7F,MAAM,IAAI,GAAG,EAAE,MAAM,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,EAAE,CAAA;gBACrD,QAAQ,CAAC,WAAW,GAAG,iBAAiB,CAAA;gBACxC,MAAM,CAAC,SAAS,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;gBAC5H,MAAM,CAAC,SAAS,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;gBACnG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC,GAAG,EAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;gBACpE,QAAQ,CAAC,WAAW,GAAG,WAAW,CAAA;gBAClC,EAAE,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAA;gBAC/D,MAAM,CAAC,SAAS,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAA;gBAC1H,MAAM,CAAC,SAAS,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;gBACnG,EAAE,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,CAAA;gBAC3E,2EAA2E;gBAC3E,EAAE,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAA;gBAC/E,MAAM,CAAC,SAAS,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAAA;gBACzG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,EAAG,CAAC,IAAc,CAAC,EAAE,IAAI,CAAC,CAAA;gBACxG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;gBAC9B,EAAE,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAA;gBAC/E,EAAE,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAA;gBACjD,MAAM,CAAC,SAAS,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC,CAAA;gBAC1G,EAAE,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAA;gBACpD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;gBAChD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;gBACrC,MAAM,CAAC,SAAS,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;gBAC3D,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,EAAG,CAAC,IAAc,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;gBACxH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;gBAC9B,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,8BAA8B,CAAC,CAAC,GAAG,EAAG,CAAC,CAAC,EAAE,CAAC,EAAE,iCAAiC,CAAC,CAAA;YACzG,CAAC;oBAAS,CAAC;gBACT,MAAM,OAAO,EAAE,EAAE,CAAA;gBACjB,EAAE,CAAC,KAAK,EAAE,CAAA;gBACV,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;YAClD,CAAC;QACH,CAAC,CAAC,CAAA;IACH,CAAC;AACF,CAAC","sourcesContent":["import assert from \"node:assert/strict\"\nimport { test } from \"node:test\"\nimport { DatabaseSync } from \"node:sqlite\"\nimport { mkdtemp, rm } from \"node:fs/promises\"\nimport os from \"node:os\"\nimport path from \"node:path\"\nimport plugin from \"./plugin\"\nimport { storageDirectory } from \"./storage-path\"\nimport { storageKey } from \"./claim-fence\"\nimport { revision } from \"./planner\"\n\n// Exercise the real RPC handlers, storage challenge and file-backed transaction.\n// No shared service, user configuration or real conversation is involved.\nfor (const version of [\"0.0.0-beta-19425\", \"future-release\", undefined]) {\n for (const workspaceID of [undefined, \"legacy-native-workspace\"]) {\n test(`pruning uses storage capabilities, not runtime version ${version}, workspace ${workspaceID}`, async () => {\n const root = await mkdtemp(path.join(os.tmpdir(), \"pruning-capabilities-\"))\n const filename = path.join(root, \"fixture.db\")\n const db = new DatabaseSync(filename)\n const content = [{ type: \"reasoning\", text: \"REMOVE\" }, { type: \"text\", text: \"KEEP\" }]\n const data = { time: { completed: 1 }, content }\n const input = { sessionID: \"s\", messageID: \"m\", revision: revision(content), indexes: [0] }\n let handlers: any\n const events: unknown[] = []\n let cleanup: (() => unknown) | void = undefined\n try {\n db.exec(`CREATE TABLE session_v2(id TEXT PRIMARY KEY,directory TEXT,project_id TEXT,workspace_id TEXT,time_suspended INTEGER,time_compacting INTEGER,revert TEXT);\n CREATE TABLE event_sequence(aggregate_id TEXT PRIMARY KEY,owner_id TEXT);\n INSERT INTO event_sequence VALUES('s',NULL);\n CREATE TABLE event(aggregate_id TEXT);\n CREATE TABLE kv(key TEXT PRIMARY KEY,value TEXT,time_created INTEGER,time_updated INTEGER);\n CREATE TABLE session_message(id TEXT PRIMARY KEY,session_id TEXT,type TEXT,data TEXT);`)\n db.prepare(\"INSERT INTO session_v2 VALUES('s',?,'p',?,NULL,NULL,NULL)\").run(storageDirectory(root), workspaceID ?? null)\n db.prepare(\"INSERT INTO session_message VALUES('m','s','assistant',?)\").run(JSON.stringify(data))\n const location = { directory: root, workspaceID, project: { id: \"p\" } }\n cleanup = await plugin.setup({\n app: { version },\n options: { databasePath: filename },\n location,\n session: { get: async () => ({ location: { directory: root, workspaceID }, projectID: \"p\" }) },\n storage: {\n set: async (key: string, value: unknown) => {\n db.prepare(\"INSERT INTO kv VALUES(?,?,1,1)\").run(storageKey(key), JSON.stringify(value))\n },\n remove: async (key: string) => { db.prepare(\"DELETE FROM kv WHERE key=?\").run(storageKey(key)) },\n },\n rpc: { register: async (_definition: unknown, implementation: unknown) => {\n handlers = implementation\n return { dispose: async () => {}, events: { emit: async (...event: unknown[]) => { events.push(event) } } }\n } },\n } as any)\n assert.equal((await handlers.preview({ sessionID: \"s\", messageID: \"m\" })).liveMutation, true)\n const call = { signal: new AbortController().signal }\n location.workspaceID = \"foreign-context\"\n assert.deepEqual(await handlers.preview({ sessionID: \"s\", messageID: \"m\" }), { status: \"blocked\", reason: \"not_deletable\" })\n assert.deepEqual(await handlers.prune(input, call), { status: \"blocked\", reason: \"not_deletable\" })\n assert.equal(db.prepare(\"SELECT count(*) AS n FROM kv\").get()!.n, 0)\n location.workspaceID = workspaceID\n db.exec(\"UPDATE session_v2 SET workspace_id='foreign-storage'\")\n assert.deepEqual(await handlers.preview({ sessionID: \"s\", messageID: \"m\" }), { status: \"blocked\", reason: \"unavailable\" })\n assert.deepEqual(await handlers.prune(input, call), { status: \"blocked\", reason: \"not_deletable\" })\n db.prepare(\"UPDATE session_v2 SET workspace_id=?\").run(workspaceID ?? null)\n // Native storage capabilities still fail closed irrespective of the label.\n db.exec(\"ALTER TABLE session_v2 RENAME COLUMN time_suspended TO missing_claim\")\n assert.deepEqual(await handlers.prune(input, call), { status: \"blocked\", reason: \"unsupported_storage\" })\n assert.deepEqual(JSON.parse(db.prepare(\"SELECT data FROM session_message\").get()!.data as string), data)\n assert.equal(events.length, 0)\n db.exec(\"ALTER TABLE session_v2 RENAME COLUMN missing_claim TO time_suspended\")\n db.exec(\"UPDATE session_v2 SET time_suspended=1\")\n assert.deepEqual(await handlers.prune(input, call), { status: \"blocked\", reason: \"maintenance_required\" })\n db.exec(\"UPDATE session_v2 SET time_suspended=NULL\")\n const result = await handlers.prune(input, call)\n assert.equal(result.status, \"pruned\")\n assert.deepEqual(await handlers.prune(input, call), result)\n assert.deepEqual(JSON.parse(db.prepare(\"SELECT data FROM session_message\").get()!.data as string).content, [content[1]])\n assert.equal(events.length, 2)\n assert.equal(db.prepare(\"SELECT count(*) AS n FROM kv\").get()!.n, 1, \"only the atomic receipt remains\")\n } finally {\n await cleanup?.()\n db.close()\n await rm(root, { recursive: true, force: true })\n }\n })\n }\n}\n"]}
|
|
@@ -10,13 +10,13 @@ export function createOpencodePermissionReplier(deps) {
|
|
|
10
10
|
throw new Error(`Yolo: instance ${reply.instanceId} is not ready`);
|
|
11
11
|
}
|
|
12
12
|
const session = await client.session.get({ sessionID: reply.sessionId });
|
|
13
|
-
if (!(await deps.workspaceManager.
|
|
13
|
+
if (!(await deps.workspaceManager.ownsLocation(reply.instanceId, session.location))) {
|
|
14
14
|
throw new Error(`Yolo: session ${reply.sessionId} does not belong to workspace ${reply.instanceId}`);
|
|
15
15
|
}
|
|
16
16
|
await client.permission.reply({
|
|
17
17
|
sessionID: reply.sessionId,
|
|
18
18
|
requestID: reply.permissionId,
|
|
19
|
-
|
|
19
|
+
decision: "once",
|
|
20
20
|
});
|
|
21
21
|
};
|
|
22
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-replier.js","sourceRoot":"","sources":["../../src/permissions/opencode-replier.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AAOpE;;;GAGG;AACH,MAAM,UAAU,+BAA+B,CAAC,IAAyB;IACvE,OAAO,KAAK,EAAE,KAAsB,EAAE,EAAE;QACtC,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;QAClF,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,CAAC,UAAU,eAAe,CAAC,CAAA;QACpE,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;QACxE,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,
|
|
1
|
+
{"version":3,"file":"opencode-replier.js","sourceRoot":"","sources":["../../src/permissions/opencode-replier.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA;AAOpE;;;GAGG;AACH,MAAM,UAAU,+BAA+B,CAAC,IAAyB;IACvE,OAAO,KAAK,EAAE,KAAsB,EAAE,EAAE;QACtC,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;QAClF,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,CAAC,UAAU,eAAe,CAAC,CAAA;QACpE,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;QACxE,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;YACpF,MAAM,IAAI,KAAK,CAAC,iBAAiB,KAAK,CAAC,SAAS,iCAAiC,KAAK,CAAC,UAAU,EAAE,CAAC,CAAA;QACtG,CAAC;QAED,MAAM,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC;YAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,SAAS,EAAE,KAAK,CAAC,YAAY;YAC7B,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC","sourcesContent":["import type { WorkspaceManager } from \"../workspaces/manager\"\nimport { createInstanceClient } from \"../workspaces/instance-client\"\nimport type { AutoAcceptReply, PermissionReplier } from \"./auto-accept-manager\"\n\ninterface OpencodeReplierDeps {\n workspaceManager: WorkspaceManager\n}\n\n/**\n * Default {@link PermissionReplier} that calls the OpenCode instance via the\n * native Promise client, using the same `\"once\"` reply the UI previously sent.\n */\nexport function createOpencodePermissionReplier(deps: OpencodeReplierDeps): PermissionReplier {\n return async (reply: AutoAcceptReply) => {\n const client = await createInstanceClient(deps.workspaceManager, reply.instanceId)\n if (!client) {\n throw new Error(`Yolo: instance ${reply.instanceId} is not ready`)\n }\n\n const session = await client.session.get({ sessionID: reply.sessionId })\n if (!(await deps.workspaceManager.ownsLocation(reply.instanceId, session.location))) {\n throw new Error(`Yolo: session ${reply.sessionId} does not belong to workspace ${reply.instanceId}`)\n }\n\n await client.permission.reply({\n sessionID: reply.sessionId,\n requestID: reply.permissionId,\n decision: \"once\",\n })\n }\n}\n"]}
|
|
@@ -11,7 +11,7 @@ describe("createOpencodePermissionReplier", () => {
|
|
|
11
11
|
const workspaceManager = {
|
|
12
12
|
get: () => ({ path: "/repo" }),
|
|
13
13
|
getSharedServiceClient: async () => client,
|
|
14
|
-
|
|
14
|
+
ownsLocation: async () => false,
|
|
15
15
|
};
|
|
16
16
|
const replier = createOpencodePermissionReplier({ workspaceManager });
|
|
17
17
|
await assert.rejects(replier({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-replier.test.js","sourceRoot":"","sources":["../../src/permissions/opencode-replier.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAA;AAIxC,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAA;AAEpE,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,KAAK,GAAmC,EAAE,CAAA;QAChD,MAAM,MAAM,GAAG;YACb,OAAO,EAAE,EAAE,GAAG,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE;YACrE,UAAU,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAA8B,EAAE,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC,EAAE;SAC1D,CAAA;QAC9B,MAAM,gBAAgB,GAAG;YACvB,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;YAC9B,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM;YAC1C,
|
|
1
|
+
{"version":3,"file":"opencode-replier.test.js","sourceRoot":"","sources":["../../src/permissions/opencode-replier.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAA;AAIxC,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAA;AAEpE,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,KAAK,GAAmC,EAAE,CAAA;QAChD,MAAM,MAAM,GAAG;YACb,OAAO,EAAE,EAAE,GAAG,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE;YACrE,UAAU,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAA8B,EAAE,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC,EAAE;SAC1D,CAAA;QAC9B,MAAM,gBAAgB,GAAG;YACvB,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;YAC9B,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM;YAC1C,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC,KAAK;SACD,CAAA;QAChC,MAAM,OAAO,GAAG,+BAA+B,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAA;QAErE,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;YAC3B,UAAU,EAAE,UAAU;YACtB,SAAS,EAAE,iBAAiB;YAC5B,YAAY,EAAE,YAAY;SAC3B,CAAC,EAAE,iBAAiB,CAAC,CAAA;QACtB,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import assert from \"node:assert/strict\"\nimport { describe, it } from \"node:test\"\nimport type { OpenCodeClient } from \"@opencode/client\"\n\nimport type { WorkspaceManager } from \"../workspaces/manager\"\nimport { createOpencodePermissionReplier } from \"./opencode-replier\"\n\ndescribe(\"createOpencodePermissionReplier\", () => {\n it(\"does not reply across logical workspace ownership\", async () => {\n const calls: Array<Record<string, unknown>> = []\n const client = {\n session: { get: async () => ({ location: { directory: \"/other\" } }) },\n permission: { reply: async (input: Record<string, unknown>) => { calls.push(input) } },\n } as unknown as OpenCodeClient\n const workspaceManager = {\n get: () => ({ path: \"/repo\" }),\n getSharedServiceClient: async () => client,\n ownsLocation: async () => false,\n } as unknown as WorkspaceManager\n const replier = createOpencodePermissionReplier({ workspaceManager })\n\n await assert.rejects(replier({\n instanceId: \"instance\",\n sessionId: \"foreign-session\",\n permissionId: \"permission\",\n }), /does not belong/)\n assert.deepEqual(calls, [])\n })\n})\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-yolo-metadata.js","sourceRoot":"","sources":["../../src/permissions/opencode-yolo-metadata.ts"],"names":[],"mappings":"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","sourcesContent":["import type { OpenCodeClient, SessionInfo } from \"@opencode
|
|
1
|
+
{"version":3,"file":"opencode-yolo-metadata.js","sourceRoot":"","sources":["../../src/permissions/opencode-yolo-metadata.ts"],"names":[],"mappings":"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","sourcesContent":["import type { OpenCodeClient, SessionInfo } from \"@opencode/client\"\nimport type { SettingsService } from \"../settings/service\"\nimport type { WorkspaceManager } from \"../workspaces/manager\"\nimport { createInstanceClient } from \"../workspaces/instance-client\"\nimport type { AutoAcceptPersistence, PersistedAutoAcceptSession } from \"./auto-accept-manager\"\n\nconst SESSION_LIST_LIMIT = 10_000\nconst STATE_OWNER = \"codenomad\"\n\ntype Metadata = Record<string, unknown>\n\ninterface PersistedSessionState {\n yoloEnabled?: boolean\n}\n\nexport type OpencodeYoloPersistence = AutoAcceptPersistence\n\nfunction record(value: unknown): Metadata {\n return value && typeof value === \"object\" && !Array.isArray(value) ? { ...(value as Metadata) } : {}\n}\n\nfunction sessionState(settings: SettingsService, sessionId: string): PersistedSessionState {\n const sessions = record(settings.getOwner(\"state\", STATE_OWNER).sessions)\n return record(sessions[sessionId]) as PersistedSessionState\n}\n\nfunction enabledSessionIds(settings: SettingsService): string[] {\n const sessions = record(settings.getOwner(\"state\", STATE_OWNER).sessions)\n return Object.keys(sessions).filter((sessionId) => record(sessions[sessionId]).yoloEnabled === true)\n}\n\nexport function createOpencodeYoloPersistence(\n workspaceManager: WorkspaceManager,\n settings: SettingsService,\n createClient: (manager: WorkspaceManager, instanceId: string) => Promise<OpenCodeClient | null> = createInstanceClient,\n): OpencodeYoloPersistence {\n const writes = new Map<string, Promise<unknown>>()\n const clientFor = async (instanceId: string) => {\n const client = await createClient(workspaceManager, instanceId)\n if (!client) throw new Error(`Yolo: instance ${instanceId} is not ready`)\n return client\n }\n const listSessions = async (instanceId: string) => {\n const workspace = workspaceManager.get(instanceId)\n if (!workspace) throw new Error(`Yolo: instance ${instanceId} is not ready`)\n const directory = workspaceManager.getServiceDirectory(instanceId)\n if (!directory) throw new Error(`Yolo: instance ${instanceId} has no service location`)\n const client = await clientFor(instanceId)\n const sessions: SessionInfo[] = []\n let cursor: string | undefined\n do {\n const page = await client.session.list({ directory, limit: SESSION_LIST_LIMIT, cursor })\n sessions.push(...page.data)\n cursor = page.cursor.next ?? undefined\n } while (cursor)\n return sessions\n }\n const persistedSession = (session: SessionInfo): PersistedAutoAcceptSession => ({\n id: session.id,\n parentId: session.parentID ?? null,\n fork: session.fork,\n yoloEnabled: sessionState(settings, session.id).yoloEnabled === true,\n })\n const updateYolo = (\n sessionId: string,\n enabled: boolean,\n ): Promise<void> => {\n const write = (writes.get(sessionId) ?? Promise.resolve()).catch(() => undefined).then(() => {\n const next = { ...sessionState(settings, sessionId), yoloEnabled: enabled }\n settings.mergePatchOwner(\"state\", STATE_OWNER, { sessions: { [sessionId]: next } })\n })\n const settled = write.finally(() => {\n if (writes.get(sessionId) === settled) writes.delete(sessionId)\n })\n writes.set(sessionId, settled)\n return settled\n }\n\n return {\n async loadSessions(instanceId): Promise<PersistedAutoAcceptSession[]> {\n const client = await clientFor(instanceId)\n const sessions = new Map((await listSessions(instanceId)).map((session) => [session.id, session]))\n await Promise.all(enabledSessionIds(settings).map(async (sessionId) => {\n if (sessions.has(sessionId)) return\n try {\n const session = await client.session.get({ sessionID: sessionId })\n if (await workspaceManager.ownsDirectory(instanceId, session.location.directory)) sessions.set(session.id, session)\n } catch {\n // Stale persisted IDs are harmless and may belong to a stopped workspace.\n }\n }))\n const owned = await Promise.all(Array.from(sessions.values()).map(async (session) => (\n await workspaceManager.ownsDirectory(instanceId, session.location.directory) ? persistedSession(session) : null\n )))\n return owned.filter((session): session is PersistedAutoAcceptSession => session !== null)\n },\n async loadSession(instanceId, sessionId): Promise<PersistedAutoAcceptSession | null> {\n try {\n const session = await (await clientFor(instanceId)).session.get({ sessionID: sessionId })\n if (!(await workspaceManager.ownsDirectory(instanceId, session.location.directory))) return null\n return persistedSession(session)\n } catch {\n return null\n }\n },\n persist(_instanceId, rootSessionId, enabled): Promise<void> {\n return updateYolo(rootSessionId, enabled)\n },\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-yolo-metadata.test.js","sourceRoot":"","sources":["../../src/permissions/opencode-yolo-metadata.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\"\nimport { describe, it } from \"node:test\"\nimport type { OpenCodeClient } from \"@opencode
|
|
1
|
+
{"version":3,"file":"opencode-yolo-metadata.test.js","sourceRoot":"","sources":["../../src/permissions/opencode-yolo-metadata.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\"\nimport { describe, it } from \"node:test\"\nimport type { OpenCodeClient } from \"@opencode/client\"\n\nimport type { SettingsService } from \"../settings/service\"\nimport type { WorkspaceManager } from \"../workspaces/manager\"\nimport { createOpencodeYoloPersistence } from \"./opencode-yolo-metadata\"\n\nfunction createHarness(serviceDirectory = \"/repo\") {\n let owner: Record<string, unknown> = {}\n const settings = {\n getOwner: () => owner,\n mergePatchOwner: (_kind: string, _owner: string, patch: { sessions: Record<string, unknown> }) => {\n owner = {\n ...owner,\n sessions: { ...((owner.sessions as Record<string, unknown>) ?? {}), ...patch.sessions },\n }\n return owner\n },\n } as unknown as SettingsService\n const listInputs: Record<string, unknown>[] = []\n const workspaceManager = {\n get: () => ({ path: \"/repo\" }),\n getServiceDirectory: () => serviceDirectory,\n ownsDirectory: async (_instanceId: string, directory: string) => directory === \"/repo\" || directory === \"/worktree\",\n } as unknown as WorkspaceManager\n const client = {\n session: {\n async list(input: Record<string, unknown>) {\n listInputs.push(input)\n const cursor = input.cursor\n return {\n data: cursor ? [\n {\n id: \"second-page\",\n parentID: undefined,\n fork: undefined,\n location: { directory: \"/repo\", workspaceID: \"workspace\" },\n },\n ] : [\n {\n id: \"root\",\n parentID: undefined,\n fork: undefined,\n location: { directory: \"/repo\", workspaceID: \"workspace\" },\n },\n ],\n cursor: { next: cursor ? null : \"page-2\" },\n }\n },\n async get({ sessionID }: { sessionID: string }) {\n return {\n id: sessionID,\n parentID: undefined,\n fork: sessionID === \"worktree\" ? {\n sessionID: \"root\",\n boundary: { type: \"through\", messageID: \"message\" },\n } : undefined,\n location: {\n directory: sessionID === \"foreign\" ? \"/other\" : sessionID === \"worktree\" ? \"/worktree\" : \"/repo\",\n workspaceID: \"workspace\",\n },\n }\n },\n },\n } as unknown as OpenCodeClient\n const persistence = createOpencodeYoloPersistence(\n workspaceManager,\n settings,\n async () => client,\n )\n return { persistence, listInputs }\n}\n\ndescribe(\"OpenCode Yolo persistence\", () => {\n it(\"loads native sessions and Yolo state from the CodeNomad store\", async () => {\n const { persistence, listInputs } = createHarness()\n await persistence.persist(\"instance\", \"root\", true)\n\n assert.deepEqual(await persistence.loadSessions(\"instance\"), [\n {\n id: \"root\",\n parentId: null,\n fork: undefined,\n yoloEnabled: true,\n },\n {\n id: \"second-page\",\n parentId: null,\n fork: undefined,\n yoloEnabled: false,\n },\n ])\n assert.deepEqual(listInputs, [\n { directory: \"/repo\", limit: 10_000, cursor: undefined },\n { directory: \"/repo\", limit: 10_000, cursor: \"page-2\" },\n ])\n })\n\n it(\"loads an exact session only when its native location belongs to the logical workspace\", async () => {\n const { persistence } = createHarness()\n assert.equal((await persistence.loadSession!(\"instance\", \"root\"))?.id, \"root\")\n assert.equal(await persistence.loadSession!(\"instance\", \"foreign\"), null)\n })\n\n it(\"restores a persisted Yolo session from an owned worktree\", async () => {\n const { persistence } = createHarness()\n await persistence.persist(\"instance\", \"worktree\", true)\n\n const worktree = (await persistence.loadSessions(\"instance\")).find((session) => session.id === \"worktree\")\n assert.deepEqual(worktree, {\n id: \"worktree\",\n parentId: null,\n fork: { sessionID: \"root\", boundary: { type: \"through\", messageID: \"message\" } },\n yoloEnabled: true,\n })\n })\n\n})\n"]}
|