@neuralnomads/codenomad-dev 0.20.0-dev-20260921-63bbdbb1 → 0.20.0-dev-20260922-e68ac524
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/automation/developer-inspection-targets.js +25 -0
- package/dist/automation/developer-inspection-targets.js.map +1 -0
- package/dist/developer-cdp.js +5 -4
- package/dist/developer-cdp.js.map +1 -1
- package/dist/developer-cdp.test.js +18 -0
- package/dist/developer-cdp.test.js.map +1 -1
- package/dist/opencode/session-pruning/navigation-contract.js +1 -0
- package/dist/opencode/session-pruning/navigation-contract.js.map +1 -1
- package/dist/opencode/session-pruning/navigation.test.js +12 -1
- package/dist/opencode/session-pruning/navigation.test.js.map +1 -1
- package/dist/opencode/session-pruning/outline-index.js +14 -1
- package/dist/opencode/session-pruning/outline-index.js.map +1 -1
- package/dist/plugins/session-pruning/plugin.mjs +16 -3
- package/dist/server/__tests__/instance-proxy.test.js +32 -0
- package/dist/server/__tests__/instance-proxy.test.js.map +1 -1
- package/dist/server/http-server.js +1 -1
- package/dist/server/http-server.js.map +1 -1
- package/dist/server/routes/automation-plugin.js +28 -15
- package/dist/server/routes/automation-plugin.js.map +1 -1
- package/dist/server/routes/automation-plugin.test.js +10 -6
- package/dist/server/routes/automation-plugin.test.js.map +1 -1
- package/dist/workspaces/__tests__/git-common-directory.test.js +86 -0
- package/dist/workspaces/__tests__/git-common-directory.test.js.map +1 -0
- package/dist/workspaces/__tests__/git-worktree-config.test.js +130 -0
- package/dist/workspaces/__tests__/git-worktree-config.test.js.map +1 -0
- package/dist/workspaces/__tests__/git-worktrees.test.js +49 -1
- package/dist/workspaces/__tests__/git-worktrees.test.js.map +1 -1
- package/dist/workspaces/__tests__/native-worktree-fixture.js +2 -2
- package/dist/workspaces/__tests__/native-worktree-fixture.js.map +1 -1
- package/dist/workspaces/git-common-directory.js +18 -0
- package/dist/workspaces/git-common-directory.js.map +1 -0
- package/dist/workspaces/git-process.js +80 -0
- package/dist/workspaces/git-process.js.map +1 -0
- package/dist/workspaces/git-worktrees.js +64 -10
- package/dist/workspaces/git-worktrees.js.map +1 -1
- package/dist/workspaces/native-worktrees.js +24 -9
- package/dist/workspaces/native-worktrees.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/App-BSkmbNUC.js +51 -0
- package/public/assets/App-BSkmbNUC.js.map +1 -0
- package/public/assets/FilesTab-CznSFRW_.js +3 -0
- package/public/assets/{FilesTab-DOOT4Own.js.map → FilesTab-CznSFRW_.js.map} +1 -1
- package/public/assets/{GitChangesTab-DqS17ZG_.js → GitChangesTab-DLtyzpX0.js} +3 -3
- package/public/assets/{GitChangesTab-DqS17ZG_.js.map → GitChangesTab-DLtyzpX0.js.map} +1 -1
- package/public/assets/{SplitFilePanel-DpXPYY4L.js → SplitFilePanel-BHkyIER4.js} +2 -2
- package/public/assets/{SplitFilePanel-DpXPYY4L.js.map → SplitFilePanel-BHkyIER4.js.map} +1 -1
- package/public/assets/{StatusTab-CynqW2pr.js → StatusTab-BB3L4UEF.js} +2 -2
- package/public/assets/{StatusTab-CynqW2pr.js.map → StatusTab-BB3L4UEF.js.map} +1 -1
- package/public/assets/{align-justify-C_MrQdWv.js → align-justify-BGcr8Y3G.js} +2 -2
- package/public/assets/{align-justify-C_MrQdWv.js.map → align-justify-BGcr8Y3G.js.map} +1 -1
- package/public/assets/{bundle-full-CVPoVh_h.js → bundle-full-CwHbX2Tz.js} +2 -2
- package/public/assets/{bundle-full-CVPoVh_h.js.map → bundle-full-CwHbX2Tz.js.map} +1 -1
- package/public/assets/client-state-CjVIIkWh.js +2 -0
- package/public/assets/client-state-CjVIIkWh.js.map +1 -0
- package/public/assets/{diff-viewer-BzgxNlWD.js → diff-viewer-FNBCogHl.js} +2 -2
- package/public/assets/{diff-viewer-BzgxNlWD.js.map → diff-viewer-FNBCogHl.js.map} +1 -1
- package/public/assets/index-AeE49W2c.js +2 -0
- package/public/assets/index-AeE49W2c.js.map +1 -0
- package/public/assets/index-B875QQLi.js +2 -0
- package/public/assets/index-B875QQLi.js.map +1 -0
- package/public/assets/index-BhInW6hR.js +3 -0
- package/public/assets/index-BhInW6hR.js.map +1 -0
- package/public/assets/index-C2jBtFkI.js +2 -0
- package/public/assets/{index-CrjSY1y2.js.map → index-C2jBtFkI.js.map} +1 -1
- package/public/assets/index-C8zCyB6Z.js +2 -0
- package/public/assets/index-C8zCyB6Z.js.map +1 -0
- package/public/assets/index-C9vJvaFa.js +2 -0
- package/public/assets/index-C9vJvaFa.js.map +1 -0
- package/public/assets/index-CLdQSSfU.js +2 -0
- package/public/assets/index-CLdQSSfU.js.map +1 -0
- package/public/assets/{index-Ce-SrKvP.js → index-CLgpBTF6.js} +2 -2
- package/public/assets/{index-Ce-SrKvP.js.map → index-CLgpBTF6.js.map} +1 -1
- package/public/assets/index-CaYFZAN4.js +2 -0
- package/public/assets/index-CaYFZAN4.js.map +1 -0
- package/public/assets/index-ChudAs0f.js +2 -0
- package/public/assets/index-ChudAs0f.js.map +1 -0
- package/public/assets/index-D292-iMl.js +2 -0
- package/public/assets/index-D292-iMl.js.map +1 -0
- package/public/assets/index-DYBqUC9X.css +1 -0
- package/public/assets/index-Dk3HFhZs.js +2 -0
- package/public/assets/index-Dk3HFhZs.js.map +1 -0
- package/public/assets/{loading-BWjkEyUD.js → loading-D8BcUQaM.js} +2 -2
- package/public/assets/{loading-BWjkEyUD.js.map → loading-D8BcUQaM.js.map} +1 -1
- package/public/assets/main-DRbjgAo8.js +42 -0
- package/public/assets/main-DRbjgAo8.js.map +1 -0
- package/public/assets/{markdown-Bkm0F3oO.js → markdown-CRPEbAqL.js} +4 -4
- package/public/assets/{markdown-Bkm0F3oO.js.map → markdown-CRPEbAqL.js.map} +1 -1
- package/public/assets/{monaco-viewer-C10fFymA.js → monaco-viewer-CG0aPZ-r.js} +2 -2
- package/public/assets/{monaco-viewer-C10fFymA.js.map → monaco-viewer-CG0aPZ-r.js.map} +1 -1
- package/public/assets/{startup-state-settings-card-BTfYhHov.js → startup-state-settings-card-CHqS2Pmg.js} +2 -2
- package/public/assets/{startup-state-settings-card-BTfYhHov.js.map → startup-state-settings-card-CHqS2Pmg.js.map} +1 -1
- package/public/assets/{terminal-square-Dhdgf3hj.js → terminal-square-DhmNJqNG.js} +2 -2
- package/public/assets/{terminal-square-Dhdgf3hj.js.map → terminal-square-DhmNJqNG.js.map} +1 -1
- package/public/assets/{todo-pfT9OVP8.js → todo-DXJ5kP_Z.js} +2 -2
- package/public/assets/{todo-pfT9OVP8.js.map → todo-DXJ5kP_Z.js.map} +1 -1
- package/public/assets/{tool-call-ja_vg-Y6.js → tool-call-Bjo9DalZ.js} +5 -5
- package/public/assets/{tool-call-ja_vg-Y6.js.map → tool-call-Bjo9DalZ.js.map} +1 -1
- package/public/assets/{unified-picker-Bi-fpJBA.js → unified-picker-CxrTM_tY.js} +2 -2
- package/public/assets/{unified-picker-Bi-fpJBA.js.map → unified-picker-CxrTM_tY.js.map} +1 -1
- package/public/assets/{wrap-text-DJHeAvj4.js → wrap-text-BznZeD4J.js} +2 -2
- package/public/assets/{wrap-text-DJHeAvj4.js.map → wrap-text-BznZeD4J.js.map} +1 -1
- package/public/index.html +4 -4
- package/public/loading.html +4 -4
- package/public/sw.js +1 -1
- package/public/sw.js.map +1 -1
- package/public/assets/App-bGIUQ-dD.js +0 -49
- package/public/assets/App-bGIUQ-dD.js.map +0 -1
- package/public/assets/FilesTab-DOOT4Own.js +0 -3
- package/public/assets/client-state-DHHjx28k.js +0 -2
- package/public/assets/client-state-DHHjx28k.js.map +0 -1
- package/public/assets/index-B5KIA1QZ.js +0 -2
- package/public/assets/index-B5KIA1QZ.js.map +0 -1
- package/public/assets/index-BO3LYyge.js +0 -2
- package/public/assets/index-BO3LYyge.js.map +0 -1
- package/public/assets/index-Bzngra1L.js +0 -3
- package/public/assets/index-Bzngra1L.js.map +0 -1
- package/public/assets/index-C6-rb6B7.css +0 -1
- package/public/assets/index-CI6ZE9xs.js +0 -2
- package/public/assets/index-CI6ZE9xs.js.map +0 -1
- package/public/assets/index-CSUBS-o9.js +0 -2
- package/public/assets/index-CSUBS-o9.js.map +0 -1
- package/public/assets/index-Cl4PCYg4.js +0 -2
- package/public/assets/index-Cl4PCYg4.js.map +0 -1
- package/public/assets/index-CrjSY1y2.js +0 -2
- package/public/assets/index-D7SuJgSm.js +0 -2
- package/public/assets/index-D7SuJgSm.js.map +0 -1
- package/public/assets/index-Daf72P6o.js +0 -2
- package/public/assets/index-Daf72P6o.js.map +0 -1
- package/public/assets/index-WIaMCSWq.js +0 -2
- package/public/assets/index-WIaMCSWq.js.map +0 -1
- package/public/assets/index-WsSXkxQ_.js +0 -2
- package/public/assets/index-WsSXkxQ_.js.map +0 -1
- package/public/assets/main-Hn7UJb2f.js +0 -42
- package/public/assets/main-Hn7UJb2f.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.test.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/navigation.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 { readNavigationWindow, readSessionOutline } from \"./navigation-store\"\nimport { readOutlinePreviews } from \"./outline-preview\"\n\nconst scope = { directory: \"/repo\", projectID: \"p\", sessionID: \"s\" }\nconst id = (n: number) => `message-${String(n).padStart(5, \"0\")}`\nfunction fixture(count = 1500) {\n const db = new DatabaseSync(\":memory:\")\n db.exec(`CREATE TABLE session_v2(id TEXT,directory TEXT,project_id TEXT,workspace_id TEXT,revert TEXT);\n CREATE TABLE session_message(id TEXT PRIMARY KEY,session_id TEXT,type TEXT,seq INTEGER,data TEXT,time_updated INTEGER DEFAULT 0);\n CREATE UNIQUE INDEX session_message_session_seq_idx ON session_message(session_id,seq);\n INSERT INTO session_v2 VALUES ('s','/repo','p',NULL,NULL);`)\n const insert = db.prepare(\"INSERT INTO session_message(id,session_id,type,seq,data) VALUES (?,'s','user',?,?)\")\n for (let n = 0; n < count; n++) insert.run(id(n), n * 7, JSON.stringify({ text: `Passage ${n}`, time: { created: n + 1 } }))\n return db\n}\nconst signal = () => new AbortController().signal\ntest(\"direct distant windows retain native sequence order, bound content and overlap adjacent windows\", async () => {\n const db = fixture()\n try {\n const around = await readNavigationWindow(db, scope, { kind: \"around\", messageID: id(1000) }, signal())\n assert.equal(around.status, \"window\")\n if (around.status !== \"window\") return\n assert.equal(around.messages.length, 200)\n assert.equal(around.messages[80].id, id(1000))\n assert.equal(around.messages[0].id, id(920))\n assert.equal(around.messages.at(-1)?.id, id(1119))\n assert.equal(around.latest, false)\n assert.deepEqual(await readNavigationWindow(db, scope, around.resume, signal()), around)\n const before = await readNavigationWindow(db, scope, around.older!, signal())\n assert.equal(before.status, \"window\")\n if (before.status !== \"window\") return\n assert.equal(before.messages.length, 200)\n assert(before.messages.some(message => message.id === around.messages[0].id))\n const after = await readNavigationWindow(db, scope, around.newer!, signal())\n assert.equal(after.status, \"window\")\n if (after.status !== \"window\") return\n assert(after.messages.some(message => message.id === around.messages.at(-1)?.id))\n assert.equal(after.messages.at(-1)?.id, id(1303))\n assert.equal(db.isTransaction, false)\n } finally { db.close() }\n})\ntest(\"structural index pages stay bounded without excerpts and exclude newly appended rows\", async (t) => {\n const db = fixture(18000)\n let clock = 0\n t.mock.method(performance, \"now\", () => clock += 100)\n try {\n const first = await readSessionOutline(db, scope, undefined, signal())\n assert.equal(first.status, \"outline\")\n if (first.status !== \"outline\") return\n assert.equal(first.total, 18000)\n assert.equal(first.entries.length, 16384, \"structural metadata must not require hundreds of excerpt-sized pages\")\n assert(first.cursor)\n db.prepare(\"INSERT INTO session_message(id,session_id,type,seq,data) VALUES (?,'s','user',?,?)\").run(id(18000), 18000 * 7, JSON.stringify({ text: \"Later\", time: { created: 20000 } }))\n const ids = first.entries.map(entry => entry.id)\n let cursor: { after: number; through: number } | null = first.cursor\n while (cursor) {\n const page = await readSessionOutline(db, scope, cursor, signal())\n assert.equal(page.status, \"outline\")\n if (page.status !== \"outline\") break\n assert(page.entries.length <= 16384)\n assert(page.entries.every(entry => !(\"preview\" in entry) && !(\"content\" in entry)))\n ids.push(...page.entries.map(entry => entry.id)); cursor = page.cursor\n }\n assert.equal(ids.length, 18000)\n assert.equal(new Set(ids).size, ids.length)\n assert.equal(ids.at(-1), id(17999))\n const delta = await readSessionOutline(db, scope, undefined, signal(), 17998 * 7)\n if (delta.status !== \"outline\") assert.fail(\"Expected delta\")\n assert.deepEqual(delta.entries.map(entry => entry.id), [id(17999), id(18000)])\n } finally { db.close() }\n})\ntest(\"navigation enforces ownership, message membership and staged undo visibility\", async () => {\n const db = fixture()\n try {\n await assert.rejects(readNavigationWindow(db, { ...scope, directory: \"/foreign\" }, { kind: \"latest\" }, signal()))\n assert.equal(db.isTransaction, false)\n assert.deepEqual(await readNavigationWindow(db, scope, { kind: \"around\", messageID: \"foreign\" }, signal()), { status: \"blocked\", reason: \"anchor_missing\" })\n db.prepare(\"UPDATE session_v2 SET revert=?\").run(JSON.stringify({ messageID: id(300) }))\n const latest = await readNavigationWindow(db, scope, { kind: \"latest\" }, signal())\n assert.equal(latest.status, \"window\")\n if (latest.status === \"window\") {\n assert.equal(latest.messages.at(-1)?.id, id(299))\n assert.equal(latest.newer, null)\n assert.equal(latest.latest, true)\n }\n assert.equal((await readNavigationWindow(db, scope, { kind: \"around\", messageID: id(1000) }, signal())).status, \"blocked\")\n const outline = await readSessionOutline(db, scope, undefined, signal())\n if (outline.status === \"outline\") assert.equal(outline.total, 300)\n } finally { db.close() }\n})\ntest(\"oversized windows fail explicitly and cancelled reads release their transaction\", async () => {\n const db = fixture(1)\n try {\n db.prepare(\"UPDATE session_message SET data=?\").run(JSON.stringify({ text: \"x\".repeat(16 * 1024 * 1024), time: { created: 1 } }))\n assert.equal((await readNavigationWindow(db, scope, { kind: \"latest\" }, signal())).status, \"blocked\")\n const cancelled = new AbortController(); cancelled.abort()\n await assert.rejects(readNavigationWindow(db, scope, { kind: \"latest\" }, cancelled.signal), /abort/i)\n assert.equal(db.isTransaction, false)\n } finally { db.close() }\n})\n\ntest(\"navigation yields for cancellation and large bodies do not delay index pagination\", async () => {\n const db = fixture(300)\n try {\n const controller = new AbortController()\n setImmediate(() => controller.abort())\n await assert.rejects(readNavigationWindow(db, scope, { kind: \"latest\" }, controller.signal), /abort/i)\n assert.equal(db.isTransaction, false)\n const data = JSON.stringify({ text: \"large\".repeat(2 * 1024 * 1024), time: { created: 1 } })\n for (let n = 0; n < 3; n++) db.prepare(\"UPDATE session_message SET data=? WHERE id=?\").run(data, id(n))\n const first = await readSessionOutline(db, scope, undefined, signal())\n assert.equal(first.status, \"outline\")\n if (first.status !== \"outline\") return\n assert.equal(first.entries.length, 300)\n assert.equal(first.cursor, null)\n assert(!JSON.stringify(first).includes(\"large\"))\n } finally { db.close() }\n})\n\ntest(\"demand excerpts preserve Markdown, bound tool output and enforce ownership/undo\", async () => {\n const db = fixture(3)\n try {\n db.prepare(\"UPDATE session_message SET type='assistant', data=? WHERE id=?\").run(JSON.stringify({ content: [\n { type: \"text\", text: \"**Rich** [link](https://example.org)\\n\\n\" + \"text \".repeat(2000) },\n { type: \"tool\", name: \"shell\", state: { content: [{ type: \"text\", text: \"output\".repeat(2000) }] } },\n ] }), id(1))\n const index = await readSessionOutline(db, scope, undefined, signal())\n if (index.status !== \"outline\") assert.fail(\"Expected index\")\n assert.equal(index.entries[1].tools, 1)\n const previews = await readOutlinePreviews(db, scope, [id(1), \"foreign\"], signal())\n if (previews.status !== \"previews\") assert.fail(\"Expected previews\")\n assert.equal(previews.entries.length, 1)\n assert(previews.entries[0].text.startsWith(\"**Rich** [link]\"))\n assert.equal(previews.entries[0].text.length, 4096)\n assert.equal(previews.entries[0].tools.length, 4096)\n await assert.rejects(readOutlinePreviews(db, { ...scope, directory: \"/foreign\" }, [id(1)], signal()))\n db.prepare(\"UPDATE session_v2 SET revert=?\").run(JSON.stringify({ messageID: id(1) }))\n assert.deepEqual(await readOutlinePreviews(db, scope, [id(1)], signal()), { status: \"previews\", entries: [] })\n } finally { db.close() }\n})\n\ntest(\"persisted checkpoints reconcile offline edits, pruning, deletions and appends without replaying unchanged ranges\", async () => {\n const db = fixture(1500)\n try {\n const first = await readSessionOutline(db, scope, undefined, signal())\n if (first.status !== \"outline\") assert.fail(\"Expected index\")\n const known = first.checkpoints.map(({ changed: _, ...checkpoint }) => checkpoint)\n const unchanged = await readSessionOutline(db, scope, undefined, signal(), -1, known)\n if (unchanged.status !== \"outline\") assert.fail(\"Expected revalidation\")\n assert.equal(unchanged.entries.length, 476, \"only the live tail is conservatively refreshed\")\n db.prepare(\"DELETE FROM session_message WHERE id=?\").run(id(250))\n db.prepare(\"UPDATE session_message SET type='assistant',data=?,time_updated=1 WHERE id=?\").run(\n JSON.stringify({ content: [{ type: \"tool\", name: \"read\" }] }), id(260))\n db.prepare(\"INSERT INTO session_message(id,session_id,type,seq,data) VALUES (?,'s','user',?,?)\").run(id(1500), 1500 * 7, '{\"text\":\"new\"}')\n const delta = await readSessionOutline(db, scope, undefined, signal(), -1, known)\n if (delta.status !== \"outline\") assert.fail(\"Expected delta\")\n assert.equal(delta.total, 1500)\n assert.equal(delta.entries.length, 988)\n assert.equal(delta.checkpoints.filter(checkpoint => !checkpoint.changed).length, 1)\n assert(!delta.entries.some(entry => entry.id === id(250)))\n assert.equal(delta.entries.find(entry => entry.id === id(260))?.tools, 1)\n // Pruning uses a conditional data update, without changing native timestamps.\n db.prepare(\"UPDATE session_message SET data=? WHERE id=?\").run('{\"content\":[]}', id(260))\n const pruned = await readSessionOutline(db, scope, undefined, signal(), -1,\n delta.checkpoints.map(({ changed: _, ...checkpoint }) => checkpoint))\n if (pruned.status !== \"outline\") assert.fail(\"Expected prune delta\")\n assert.equal(pruned.entries.find(entry => entry.id === id(260))?.tools, 0)\n assert.equal(db.isTransaction, false)\n } finally { db.close() }\n})\n\ntest(\"appending across repeated refreshes fills the tail checkpoint instead of growing one per message\", async () => {\n const db = fixture(1025)\n try {\n let known: import(\"./navigation-contract\").OutlineCheckpoint[] = []\n for (let seq = 1025; seq < 1065; seq++) {\n db.prepare(\"INSERT INTO session_message(id,session_id,type,seq,data) VALUES (?,'s','user',?,?)\")\n .run(id(seq), seq * 7, '{\"text\":\"new\"}')\n const page = await readSessionOutline(db, scope, undefined, signal(), -1, known)\n if (page.status !== \"outline\") assert.fail(\"Expected index\")\n assert.equal(page.checkpoints.length, 3)\n known = page.checkpoints.map(({ changed: _, ...checkpoint }) => checkpoint)\n }\n } finally { db.close() }\n})\n\ntest(\"changed checkpoints with deletion holes never exceed the RPC page limit\", async () => {\n const db = fixture(18000)\n try {\n const { outlineResultSchema } = await import(\"./navigation-contract\")\n const known: import(\"./navigation-contract\").OutlineCheckpoint[] = []\n let cursor: { after: number; through: number } | undefined\n do {\n const page = await readSessionOutline(db, scope, cursor, signal())\n if (page.status !== \"outline\") assert.fail(\"Expected index\")\n known.push(...page.checkpoints.map(({ changed: _, ...checkpoint }) => checkpoint))\n cursor = page.cursor ?? undefined\n } while (cursor)\n db.prepare(\"DELETE FROM session_message WHERE id=?\").run(id(250))\n db.exec(\"UPDATE session_message SET time_updated=1\")\n let count = 0\n do {\n const page = await readSessionOutline(db, scope, cursor, signal(), -1, known)\n assert(outlineResultSchema.safeParse(page).success, \"every delta page satisfies the actual RPC contract\")\n if (page.status !== \"outline\") assert.fail(\"Expected delta\")\n count += page.entries.length\n cursor = page.cursor ?? undefined\n } while (cursor)\n assert.equal(count, 17999)\n } finally { db.close() }\n})\n"]}
|
|
1
|
+
{"version":3,"file":"navigation.test.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/navigation.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 { readNavigationWindow, readSessionOutline } from \"./navigation-store\"\nimport { readOutlinePreviews } from \"./outline-preview\"\n\nconst scope = { directory: \"/repo\", projectID: \"p\", sessionID: \"s\" }\nconst id = (n: number) => `message-${String(n).padStart(5, \"0\")}`\nfunction fixture(count = 1500) {\n const db = new DatabaseSync(\":memory:\")\n db.exec(`CREATE TABLE session_v2(id TEXT,directory TEXT,project_id TEXT,workspace_id TEXT,revert TEXT);\n CREATE TABLE session_message(id TEXT PRIMARY KEY,session_id TEXT,type TEXT,seq INTEGER,data TEXT,time_updated INTEGER DEFAULT 0);\n CREATE UNIQUE INDEX session_message_session_seq_idx ON session_message(session_id,seq);\n INSERT INTO session_v2 VALUES ('s','/repo','p',NULL,NULL);`)\n const insert = db.prepare(\"INSERT INTO session_message(id,session_id,type,seq,data) VALUES (?,'s','user',?,?)\")\n for (let n = 0; n < count; n++) insert.run(id(n), n * 7, JSON.stringify({ text: `Passage ${n}`, time: { created: n + 1 } }))\n return db\n}\nconst signal = () => new AbortController().signal\ntest(\"direct distant windows retain native sequence order, bound content and overlap adjacent windows\", async () => {\n const db = fixture()\n try {\n const around = await readNavigationWindow(db, scope, { kind: \"around\", messageID: id(1000) }, signal())\n assert.equal(around.status, \"window\")\n if (around.status !== \"window\") return\n assert.equal(around.messages.length, 200)\n assert.equal(around.messages[80].id, id(1000))\n assert.equal(around.messages[0].id, id(920))\n assert.equal(around.messages.at(-1)?.id, id(1119))\n assert.equal(around.latest, false)\n assert.deepEqual(await readNavigationWindow(db, scope, around.resume, signal()), around)\n const before = await readNavigationWindow(db, scope, around.older!, signal())\n assert.equal(before.status, \"window\")\n if (before.status !== \"window\") return\n assert.equal(before.messages.length, 200)\n assert(before.messages.some(message => message.id === around.messages[0].id))\n const after = await readNavigationWindow(db, scope, around.newer!, signal())\n assert.equal(after.status, \"window\")\n if (after.status !== \"window\") return\n assert(after.messages.some(message => message.id === around.messages.at(-1)?.id))\n assert.equal(after.messages.at(-1)?.id, id(1303))\n assert.equal(db.isTransaction, false)\n } finally { db.close() }\n})\ntest(\"structural index pages stay bounded without excerpts and exclude newly appended rows\", async (t) => {\n const db = fixture(18000)\n let clock = 0\n t.mock.method(performance, \"now\", () => clock += 100)\n try {\n const first = await readSessionOutline(db, scope, undefined, signal())\n assert.equal(first.status, \"outline\")\n if (first.status !== \"outline\") return\n assert.equal(first.total, 18000)\n assert.equal(first.entries.length, 16384, \"structural metadata must not require hundreds of excerpt-sized pages\")\n assert(first.cursor)\n db.prepare(\"INSERT INTO session_message(id,session_id,type,seq,data) VALUES (?,'s','user',?,?)\").run(id(18000), 18000 * 7, JSON.stringify({ text: \"Later\", time: { created: 20000 } }))\n const ids = first.entries.map(entry => entry.id)\n let cursor: { after: number; through: number } | null = first.cursor\n while (cursor) {\n const page = await readSessionOutline(db, scope, cursor, signal())\n assert.equal(page.status, \"outline\")\n if (page.status !== \"outline\") break\n assert(page.entries.length <= 16384)\n assert(page.entries.every(entry => !(\"preview\" in entry) && !(\"content\" in entry)))\n ids.push(...page.entries.map(entry => entry.id)); cursor = page.cursor\n }\n assert.equal(ids.length, 18000)\n assert.equal(new Set(ids).size, ids.length)\n assert.equal(ids.at(-1), id(17999))\n const delta = await readSessionOutline(db, scope, undefined, signal(), 17998 * 7)\n if (delta.status !== \"outline\") assert.fail(\"Expected delta\")\n assert.deepEqual(delta.entries.map(entry => entry.id), [id(17999), id(18000)])\n } finally { db.close() }\n})\ntest(\"navigation enforces ownership, message membership and staged undo visibility\", async () => {\n const db = fixture()\n try {\n await assert.rejects(readNavigationWindow(db, { ...scope, directory: \"/foreign\" }, { kind: \"latest\" }, signal()))\n assert.equal(db.isTransaction, false)\n assert.deepEqual(await readNavigationWindow(db, scope, { kind: \"around\", messageID: \"foreign\" }, signal()), { status: \"blocked\", reason: \"anchor_missing\" })\n db.prepare(\"UPDATE session_v2 SET revert=?\").run(JSON.stringify({ messageID: id(300) }))\n const latest = await readNavigationWindow(db, scope, { kind: \"latest\" }, signal())\n assert.equal(latest.status, \"window\")\n if (latest.status === \"window\") {\n assert.equal(latest.messages.at(-1)?.id, id(299))\n assert.equal(latest.newer, null)\n assert.equal(latest.latest, true)\n }\n assert.equal((await readNavigationWindow(db, scope, { kind: \"around\", messageID: id(1000) }, signal())).status, \"blocked\")\n const outline = await readSessionOutline(db, scope, undefined, signal())\n if (outline.status === \"outline\") assert.equal(outline.total, 300)\n } finally { db.close() }\n})\ntest(\"oversized windows fail explicitly and cancelled reads release their transaction\", async () => {\n const db = fixture(1)\n try {\n db.prepare(\"UPDATE session_message SET data=?\").run(JSON.stringify({ text: \"x\".repeat(16 * 1024 * 1024), time: { created: 1 } }))\n assert.equal((await readNavigationWindow(db, scope, { kind: \"latest\" }, signal())).status, \"blocked\")\n const cancelled = new AbortController(); cancelled.abort()\n await assert.rejects(readNavigationWindow(db, scope, { kind: \"latest\" }, cancelled.signal), /abort/i)\n assert.equal(db.isTransaction, false)\n } finally { db.close() }\n})\n\ntest(\"navigation yields for cancellation and large bodies do not delay index pagination\", async () => {\n const db = fixture(300)\n try {\n const controller = new AbortController()\n setImmediate(() => controller.abort())\n await assert.rejects(readNavigationWindow(db, scope, { kind: \"latest\" }, controller.signal), /abort/i)\n assert.equal(db.isTransaction, false)\n const data = JSON.stringify({ text: \"large\".repeat(2 * 1024 * 1024), time: { created: 1 } })\n for (let n = 0; n < 3; n++) db.prepare(\"UPDATE session_message SET data=? WHERE id=?\").run(data, id(n))\n const first = await readSessionOutline(db, scope, undefined, signal())\n assert.equal(first.status, \"outline\")\n if (first.status !== \"outline\") return\n assert.equal(first.entries.length, 300)\n assert.equal(first.cursor, null)\n assert(!JSON.stringify(first).includes(\"large\"))\n } finally { db.close() }\n})\n\ntest(\"demand excerpts preserve Markdown, bound tool output and enforce ownership/undo\", async () => {\n const db = fixture(3)\n try {\n db.prepare(\"UPDATE session_message SET type='assistant', data=? WHERE id=?\").run(JSON.stringify({ content: [\n { type: \"text\", text: \"**Rich** [link](https://example.org)\\n\\n\" + \"text \".repeat(2000) },\n { type: \"tool\", tool: \"shell\", state: { content: [{ type: \"text\", text: \"output\".repeat(2000) }] } },\n ] }), id(1))\n const index = await readSessionOutline(db, scope, undefined, signal())\n if (index.status !== \"outline\") assert.fail(\"Expected index\")\n assert.equal(index.entries[1].tools, 1)\n assert.equal(index.entries[1].toolName, \"shell\")\n const unicodeName = \"🔧\".repeat(256)\n db.prepare(\"UPDATE session_message SET type='assistant', data=? WHERE id=?\").run(JSON.stringify({ content: [\n { type: \"tool\", name: unicodeName, state: {} },\n ] }), id(2))\n const unicodeIndex = await readSessionOutline(db, scope, undefined, signal())\n if (unicodeIndex.status !== \"outline\") assert.fail(\"Expected Unicode index\")\n assert.equal(unicodeIndex.entries[2].toolName, \"🔧\".repeat(128), \"tool metadata must satisfy its UTF-16 RPC bound\")\n const previews = await readOutlinePreviews(db, scope, [id(1), \"foreign\"], signal())\n if (previews.status !== \"previews\") assert.fail(\"Expected previews\")\n assert.equal(previews.entries.length, 1)\n assert(previews.entries[0].text.startsWith(\"**Rich** [link]\"))\n assert.equal(previews.entries[0].text.length, 4096)\n assert.equal(previews.entries[0].tools.length, 4096)\n await assert.rejects(readOutlinePreviews(db, { ...scope, directory: \"/foreign\" }, [id(1)], signal()))\n db.prepare(\"UPDATE session_v2 SET revert=?\").run(JSON.stringify({ messageID: id(1) }))\n assert.deepEqual(await readOutlinePreviews(db, scope, [id(1)], signal()), { status: \"previews\", entries: [] })\n } finally { db.close() }\n})\n\ntest(\"persisted checkpoints reconcile offline edits, pruning, deletions and appends without replaying unchanged ranges\", async () => {\n const db = fixture(1500)\n try {\n const first = await readSessionOutline(db, scope, undefined, signal())\n if (first.status !== \"outline\") assert.fail(\"Expected index\")\n const known = first.checkpoints.map(({ changed: _, ...checkpoint }) => checkpoint)\n const unchanged = await readSessionOutline(db, scope, undefined, signal(), -1, known)\n if (unchanged.status !== \"outline\") assert.fail(\"Expected revalidation\")\n assert.equal(unchanged.entries.length, 476, \"only the live tail is conservatively refreshed\")\n db.prepare(\"DELETE FROM session_message WHERE id=?\").run(id(250))\n db.prepare(\"UPDATE session_message SET type='assistant',data=?,time_updated=1 WHERE id=?\").run(\n JSON.stringify({ content: [{ type: \"tool\", name: \"read\" }] }), id(260))\n db.prepare(\"INSERT INTO session_message(id,session_id,type,seq,data) VALUES (?,'s','user',?,?)\").run(id(1500), 1500 * 7, '{\"text\":\"new\"}')\n const delta = await readSessionOutline(db, scope, undefined, signal(), -1, known)\n if (delta.status !== \"outline\") assert.fail(\"Expected delta\")\n assert.equal(delta.total, 1500)\n assert.equal(delta.entries.length, 988)\n assert.equal(delta.checkpoints.filter(checkpoint => !checkpoint.changed).length, 1)\n assert(!delta.entries.some(entry => entry.id === id(250)))\n assert.equal(delta.entries.find(entry => entry.id === id(260))?.tools, 1)\n assert.equal(delta.entries.find(entry => entry.id === id(260))?.toolName, \"read\")\n // Pruning uses a conditional data update, without changing native timestamps.\n db.prepare(\"UPDATE session_message SET data=? WHERE id=?\").run('{\"content\":[]}', id(260))\n const pruned = await readSessionOutline(db, scope, undefined, signal(), -1,\n delta.checkpoints.map(({ changed: _, ...checkpoint }) => checkpoint))\n if (pruned.status !== \"outline\") assert.fail(\"Expected prune delta\")\n assert.equal(pruned.entries.find(entry => entry.id === id(260))?.tools, 0)\n assert.equal(pruned.entries.find(entry => entry.id === id(260))?.toolName, undefined)\n assert.equal(db.isTransaction, false)\n } finally { db.close() }\n})\n\ntest(\"appending across repeated refreshes fills the tail checkpoint instead of growing one per message\", async () => {\n const db = fixture(1025)\n try {\n let known: import(\"./navigation-contract\").OutlineCheckpoint[] = []\n for (let seq = 1025; seq < 1065; seq++) {\n db.prepare(\"INSERT INTO session_message(id,session_id,type,seq,data) VALUES (?,'s','user',?,?)\")\n .run(id(seq), seq * 7, '{\"text\":\"new\"}')\n const page = await readSessionOutline(db, scope, undefined, signal(), -1, known)\n if (page.status !== \"outline\") assert.fail(\"Expected index\")\n assert.equal(page.checkpoints.length, 3)\n known = page.checkpoints.map(({ changed: _, ...checkpoint }) => checkpoint)\n }\n } finally { db.close() }\n})\n\ntest(\"changed checkpoints with deletion holes never exceed the RPC page limit\", async () => {\n const db = fixture(18000)\n try {\n const { outlineResultSchema } = await import(\"./navigation-contract\")\n const known: import(\"./navigation-contract\").OutlineCheckpoint[] = []\n let cursor: { after: number; through: number } | undefined\n do {\n const page = await readSessionOutline(db, scope, cursor, signal())\n if (page.status !== \"outline\") assert.fail(\"Expected index\")\n known.push(...page.checkpoints.map(({ changed: _, ...checkpoint }) => checkpoint))\n cursor = page.cursor ?? undefined\n } while (cursor)\n db.prepare(\"DELETE FROM session_message WHERE id=?\").run(id(250))\n db.exec(\"UPDATE session_message SET time_updated=1\")\n let count = 0\n do {\n const page = await readSessionOutline(db, scope, cursor, signal(), -1, known)\n assert(outlineResultSchema.safeParse(page).success, \"every delta page satisfies the actual RPC contract\")\n if (page.status !== \"outline\") assert.fail(\"Expected delta\")\n count += page.entries.length\n cursor = page.cursor ?? undefined\n } while (cursor)\n assert.equal(count, 17999)\n } finally { db.close() }\n})\n"]}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { setImmediate as yieldTurn } from "node:timers/promises";
|
|
3
3
|
import { ownedSession } from "./navigation-scope";
|
|
4
|
+
function boundedToolName(value) {
|
|
5
|
+
if (typeof value !== "string")
|
|
6
|
+
return "";
|
|
7
|
+
const truncated = value.slice(0, 256);
|
|
8
|
+
return /[\uD800-\uDBFF]$/.test(truncated) ? truncated.slice(0, -1) : truncated;
|
|
9
|
+
}
|
|
4
10
|
// Checkpoint boundaries survive deletion: removing an early row must not shift
|
|
5
11
|
// every later chunk. Only changed chunks need technical-part JSON projection.
|
|
6
12
|
export async function readSessionOutline(db, scope, cursor, signal, startAfter = -1, known = []) {
|
|
@@ -21,6 +27,11 @@ export async function readSessionOutline(db, scope, cursor, signal, startAfter =
|
|
|
21
27
|
FROM session_message WHERE ${where} AND seq>? AND seq<=? ORDER BY seq LIMIT 512`);
|
|
22
28
|
const project = db.prepare(`SELECT id,type,seq,
|
|
23
29
|
CASE WHEN type='assistant' THEN (SELECT count(*) FROM json_each(data,'$.content') WHERE json_extract(value,'$.type')='tool') ELSE 0 END AS tools,
|
|
30
|
+
CASE WHEN type='assistant' THEN coalesce((SELECT substr(CASE
|
|
31
|
+
WHEN json_type(value,'$.name')='text' THEN json_extract(value,'$.name')
|
|
32
|
+
WHEN json_type(value,'$.tool')='text' THEN json_extract(value,'$.tool') END,1,256)
|
|
33
|
+
FROM json_each(data,'$.content') WHERE json_extract(value,'$.type')='tool'
|
|
34
|
+
AND (json_type(value,'$.name')='text' OR json_type(value,'$.tool')='text') LIMIT 1),'') ELSE '' END AS tool_name,
|
|
24
35
|
CASE WHEN type='assistant' THEN (SELECT count(*) FROM json_each(data,'$.content') WHERE json_extract(value,'$.type')='reasoning') ELSE 0 END AS reasoning
|
|
25
36
|
FROM session_message WHERE ${where} AND seq>? AND seq<=? ORDER BY seq LIMIT 512`);
|
|
26
37
|
const entries = [], checkpoints = [];
|
|
@@ -42,8 +53,10 @@ export async function readSessionOutline(db, scope, cursor, signal, startAfter =
|
|
|
42
53
|
|| chunkEnd >= maximum;
|
|
43
54
|
if (changed) {
|
|
44
55
|
for (const row of project.iterate(...params, after, chunkEnd)) {
|
|
56
|
+
const tools = Number(row.tools);
|
|
45
57
|
entries.push({ id: String(row.id), seq: Number(row.seq), type: row.type,
|
|
46
|
-
tools
|
|
58
|
+
tools, reasoning: Number(row.reasoning),
|
|
59
|
+
...(tools ? { toolName: boundedToolName(row.tool_name) } : {}) });
|
|
47
60
|
if (entries.length % 128 === 0)
|
|
48
61
|
await yieldTurn(undefined, { signal });
|
|
49
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outline-index.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/outline-index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,EAAE,YAAY,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAGhE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,+EAA+E;AAC/E,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EAAgB,EAAE,KAAmB,EAC5E,MAAsD,EAAE,MAAmB,EAAE,UAAU,GAAG,CAAC,CAAC,EAC5F,QAA6B,EAAE;IAC/B,MAAM,CAAC,cAAc,EAAE,CAAA;IACvB,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAClH,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,CAAA;IAClD,CAAC;IACD,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAChB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;QACxC,MAAM,KAAK,GAAG,cAAc,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QAC9D,MAAM,MAAM,GAAoB,CAAC,KAAK,CAAC,SAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACnF,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,mEAAmE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,EAAE,KAAK,CAAC,CAAA;QACpI,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,CAAA;QAChF,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,uDAAuD,KAAK,aAAa,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,CAAA;QAC1I,IAAI,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,UAAU,CAAA;QACvC,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;mCACI,KAAK,8CAA8C,CAAC,CAAA;QACnF,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC
|
|
1
|
+
{"version":3,"file":"outline-index.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/outline-index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,EAAE,YAAY,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAGhE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAA;IACxC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IACrC,OAAO,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AAChF,CAAC;AAED,+EAA+E;AAC/E,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,EAAgB,EAAE,KAAmB,EAC5E,MAAsD,EAAE,MAAmB,EAAE,UAAU,GAAG,CAAC,CAAC,EAC5F,QAA6B,EAAE;IAC/B,MAAM,CAAC,cAAc,EAAE,CAAA;IACvB,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAClH,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,CAAA;IAClD,CAAC;IACD,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAChB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;QACxC,MAAM,KAAK,GAAG,cAAc,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QAC9D,MAAM,MAAM,GAAoB,CAAC,KAAK,CAAC,SAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACnF,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,mEAAmE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,EAAE,KAAK,CAAC,CAAA;QACpI,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,CAAA;QAChF,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,uDAAuD,KAAK,aAAa,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,CAAA;QAC1I,IAAI,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,UAAU,CAAA;QACvC,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;mCACI,KAAK,8CAA8C,CAAC,CAAA;QACnF,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;;mCAQI,KAAK,8CAA8C,CAAC,CAAA;QACnF,MAAM,OAAO,GAAmB,EAAE,EAAE,WAAW,GAAoD,EAAE,CAAA;QACrG,IAAI,QAAQ,GAAG,CAAC,CAAA;QAChB,GAAG,CAAC;YACF,MAAM,CAAC,cAAc,EAAE,CAAA;YACvB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,CAAA;YACzD,sEAAsE;YACtE,4EAA4E;YAC5E,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,QAAQ,KAAK,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YACjG,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,CAAA;YAC/C,sEAAsE;YACtE,yCAAyC;YACzC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;YACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;YAC9D,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAC9E,MAAM,OAAO,GAAG,QAAQ,EAAE,OAAO,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM;gBAC1E,oEAAoE;mBACjE,QAAQ,IAAI,OAAO,CAAA;YACxB,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC;oBAC9D,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;oBAC/B,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAA4B;wBAC7F,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC;wBACvC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;oBACnE,IAAI,OAAO,CAAC,MAAM,GAAG,GAAG,KAAK,CAAC;wBAAE,MAAM,SAAS,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;gBACxE,CAAC;YACH,CAAC;YACD,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;YAC/D,KAAK,GAAG,QAAQ,CAAA;YAChB,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAA;YACvB,MAAM,SAAS,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;YACxC,0EAA0E;YAC1E,yEAAyE;QACzE,CAAC,QAAQ,KAAK,GAAG,OAAO,IAAI,QAAQ,IAAI,KAAK,GAAG,GAAG,IAAI,WAAW,CAAC,MAAM,GAAG,GAAG,EAAC;QAChF,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAChH,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IAAC,CAAC;AACnC,CAAC","sourcesContent":["import { createHash } from \"node:crypto\"\nimport type { DatabaseSync, SQLInputValue } from \"node:sqlite\"\nimport { setImmediate as yieldTurn } from \"node:timers/promises\"\nimport type { HistoryScope } from \"./history-store\"\nimport type { OutlineCheckpoint, OutlineEntry, OutlineResult } from \"./navigation-contract\"\nimport { ownedSession } from \"./navigation-scope\"\n\nfunction boundedToolName(value: unknown): string {\n if (typeof value !== \"string\") return \"\"\n const truncated = value.slice(0, 256)\n return /[\\uD800-\\uDBFF]$/.test(truncated) ? truncated.slice(0, -1) : truncated\n}\n\n// Checkpoint boundaries survive deletion: removing an early row must not shift\n// every later chunk. Only changed chunks need technical-part JSON projection.\nexport async function readSessionOutline(db: DatabaseSync, scope: HistoryScope,\n cursor: { after: number; through: number } | undefined, signal: AbortSignal, startAfter = -1,\n known: OutlineCheckpoint[] = []): Promise<OutlineResult> {\n signal.throwIfAborted()\n if (known.some((item, index) => item.through <= item.after || (index && item.after !== known[index - 1].through))) {\n return { status: \"blocked\", reason: \"conflict\" }\n }\n db.exec(\"BEGIN\")\n try {\n const boundary = ownedSession(db, scope)\n const where = \"session_id=?\" + (boundary ? \" AND id < ?\" : \"\")\n const params: SQLInputValue[] = [scope.sessionID!, ...(boundary ? [boundary] : [])]\n const maximum = Number(db.prepare(`SELECT coalesce(max(seq),0) AS value FROM session_message WHERE ${where}`).get(...params)?.value)\n const through = cursor?.through ?? Math.max(maximum, known.at(-1)?.through ?? 0)\n const total = Number(db.prepare(`SELECT count(*) AS value FROM session_message WHERE ${where} AND seq<=?`).get(...params, through)?.value)\n let after = cursor?.after ?? startAfter\n const headers = db.prepare(`SELECT id,type,seq,time_updated,length(CAST(data AS BLOB)) AS bytes\n FROM session_message WHERE ${where} AND seq>? AND seq<=? ORDER BY seq LIMIT 512`)\n const project = db.prepare(`SELECT id,type,seq,\n CASE WHEN type='assistant' THEN (SELECT count(*) FROM json_each(data,'$.content') WHERE json_extract(value,'$.type')='tool') ELSE 0 END AS tools,\n CASE WHEN type='assistant' THEN coalesce((SELECT substr(CASE\n WHEN json_type(value,'$.name')='text' THEN json_extract(value,'$.name')\n WHEN json_type(value,'$.tool')='text' THEN json_extract(value,'$.tool') END,1,256)\n FROM json_each(data,'$.content') WHERE json_extract(value,'$.type')='tool'\n AND (json_type(value,'$.name')='text' OR json_type(value,'$.tool')='text') LIMIT 1),'') ELSE '' END AS tool_name,\n CASE WHEN type='assistant' THEN (SELECT count(*) FROM json_each(data,'$.content') WHERE json_extract(value,'$.type')='reasoning') ELSE 0 END AS reasoning\n FROM session_message WHERE ${where} AND seq>? AND seq<=? ORDER BY seq LIMIT 512`)\n const entries: OutlineEntry[] = [], checkpoints: Array<OutlineCheckpoint & { changed: boolean }> = []\n let examined = 0\n do {\n signal.throwIfAborted()\n const previous = known.find(item => item.after === after)\n // Grow the last range to 512 rows before creating another checkpoint.\n // Otherwise one append per refresh eventually exhausts the manifest budget.\n const end = Math.min(previous && previous !== known.at(-1) ? previous.through : through, through)\n const rows = headers.all(...params, after, end)\n // If a cached range gained >512 rows, split and rebuild it instead of\n // declaring the unseen suffix unchanged.\n const last = rows.at(-1)\n const chunkEnd = rows.length === 512 ? Number(last!.seq) : end\n const digest = createHash(\"sha256\").update(JSON.stringify(rows)).digest(\"hex\")\n const changed = previous?.through !== chunkEnd || previous.digest !== digest\n // The live tail is cheap and may change twice within a millisecond.\n || chunkEnd >= maximum\n if (changed) {\n for (const row of project.iterate(...params, after, chunkEnd)) {\n const tools = Number(row.tools)\n entries.push({ id: String(row.id), seq: Number(row.seq), type: row.type as OutlineEntry[\"type\"],\n tools, reasoning: Number(row.reasoning),\n ...(tools ? { toolName: boundedToolName(row.tool_name) } : {}) })\n if (entries.length % 128 === 0) await yieldTurn(undefined, { signal })\n }\n }\n checkpoints.push({ after, through: chunkEnd, digest, changed })\n after = chunkEnd\n examined += rows.length\n await yieldTurn(undefined, { signal })\n // Old ranges shrink after deletions. Reserve a whole block before reading\n // another; the page budget is not necessarily a multiple of 512 anymore.\n } while (after < through && examined <= 16384 - 512 && checkpoints.length < 512)\n return { status: \"outline\", entries, checkpoints, total, cursor: after < through ? { after, through } : null }\n } finally { db.exec(\"ROLLBACK\") }\n}\n"]}
|
|
@@ -26902,7 +26902,8 @@ var outlineEntrySchema = external_exports.object({
|
|
|
26902
26902
|
seq: external_exports.number().int().nonnegative(),
|
|
26903
26903
|
type: messageType,
|
|
26904
26904
|
tools: external_exports.number().int().nonnegative(),
|
|
26905
|
-
reasoning: external_exports.number().int().nonnegative()
|
|
26905
|
+
reasoning: external_exports.number().int().nonnegative(),
|
|
26906
|
+
toolName: external_exports.string().max(256).optional()
|
|
26906
26907
|
}).strict();
|
|
26907
26908
|
var outlineResultSchema = external_exports.union([pruningBlockedSchema, external_exports.object({
|
|
26908
26909
|
status: external_exports.literal("outline"),
|
|
@@ -26979,6 +26980,11 @@ import { setImmediate as yieldTurn4 } from "node:timers/promises";
|
|
|
26979
26980
|
// src/opencode/session-pruning/outline-index.ts
|
|
26980
26981
|
import { createHash as createHash4 } from "node:crypto";
|
|
26981
26982
|
import { setImmediate as yieldTurn3 } from "node:timers/promises";
|
|
26983
|
+
function boundedToolName(value3) {
|
|
26984
|
+
if (typeof value3 !== "string") return "";
|
|
26985
|
+
const truncated = value3.slice(0, 256);
|
|
26986
|
+
return /[\uD800-\uDBFF]$/.test(truncated) ? truncated.slice(0, -1) : truncated;
|
|
26987
|
+
}
|
|
26982
26988
|
async function readSessionOutline(db, scope3, cursor, signal, startAfter = -1, known = []) {
|
|
26983
26989
|
signal.throwIfAborted();
|
|
26984
26990
|
if (known.some((item, index2) => item.through <= item.after || index2 && item.after !== known[index2 - 1].through)) {
|
|
@@ -26997,6 +27003,11 @@ async function readSessionOutline(db, scope3, cursor, signal, startAfter = -1, k
|
|
|
26997
27003
|
FROM session_message WHERE ${where} AND seq>? AND seq<=? ORDER BY seq LIMIT 512`);
|
|
26998
27004
|
const project = db.prepare(`SELECT id,type,seq,
|
|
26999
27005
|
CASE WHEN type='assistant' THEN (SELECT count(*) FROM json_each(data,'$.content') WHERE json_extract(value,'$.type')='tool') ELSE 0 END AS tools,
|
|
27006
|
+
CASE WHEN type='assistant' THEN coalesce((SELECT substr(CASE
|
|
27007
|
+
WHEN json_type(value,'$.name')='text' THEN json_extract(value,'$.name')
|
|
27008
|
+
WHEN json_type(value,'$.tool')='text' THEN json_extract(value,'$.tool') END,1,256)
|
|
27009
|
+
FROM json_each(data,'$.content') WHERE json_extract(value,'$.type')='tool'
|
|
27010
|
+
AND (json_type(value,'$.name')='text' OR json_type(value,'$.tool')='text') LIMIT 1),'') ELSE '' END AS tool_name,
|
|
27000
27011
|
CASE WHEN type='assistant' THEN (SELECT count(*) FROM json_each(data,'$.content') WHERE json_extract(value,'$.type')='reasoning') ELSE 0 END AS reasoning
|
|
27001
27012
|
FROM session_message WHERE ${where} AND seq>? AND seq<=? ORDER BY seq LIMIT 512`);
|
|
27002
27013
|
const entries3 = [], checkpoints = [];
|
|
@@ -27012,12 +27023,14 @@ async function readSessionOutline(db, scope3, cursor, signal, startAfter = -1, k
|
|
|
27012
27023
|
const changed = previous?.through !== chunkEnd || previous.digest !== digest || chunkEnd >= maximum;
|
|
27013
27024
|
if (changed) {
|
|
27014
27025
|
for (const row of project.iterate(...params, after, chunkEnd)) {
|
|
27026
|
+
const tools = Number(row.tools);
|
|
27015
27027
|
entries3.push({
|
|
27016
27028
|
id: String(row.id),
|
|
27017
27029
|
seq: Number(row.seq),
|
|
27018
27030
|
type: row.type,
|
|
27019
|
-
tools
|
|
27020
|
-
reasoning: Number(row.reasoning)
|
|
27031
|
+
tools,
|
|
27032
|
+
reasoning: Number(row.reasoning),
|
|
27033
|
+
...tools ? { toolName: boundedToolName(row.tool_name) } : {}
|
|
27021
27034
|
});
|
|
27022
27035
|
if (entries3.length % 128 === 0) await yieldTurn3(void 0, { signal });
|
|
27023
27036
|
}
|
|
@@ -160,6 +160,38 @@ async function harness(sessionDirectory = "/repo/worktree", activeSessions = {},
|
|
|
160
160
|
};
|
|
161
161
|
}
|
|
162
162
|
describe("instance proxy location enforcement", () => {
|
|
163
|
+
it("forwards side generation for an owned busy session without mutating its environment", async () => {
|
|
164
|
+
const { app, manager, sessionGets, requestCount } = await harness("/repo/worktree", { owned: { type: "running" } });
|
|
165
|
+
manager.getSessionEnvironment = async () => { throw new Error("Side generation must not replace the session environment"); };
|
|
166
|
+
const response = await app.inject({ method: "POST", url: "/workspaces/workspace/instance/api/session/owned/generate",
|
|
167
|
+
payload: { prompt: "Explain the current approach" } });
|
|
168
|
+
assert.equal(response.statusCode, 200);
|
|
169
|
+
assert.deepEqual(sessionGets, ["owned"]);
|
|
170
|
+
assert.deepEqual(response.json().body, { prompt: "Explain the current approach" });
|
|
171
|
+
assert.equal(response.json().url, "/api/session/owned/generate");
|
|
172
|
+
assert.equal(requestCount(), 1);
|
|
173
|
+
// Only the reviewed session-scoped route is opened, never generic generation.
|
|
174
|
+
const generic = await app.inject({ method: "POST", url: "/workspaces/workspace/instance/api/experimental/generate", payload: { prompt: "test" } });
|
|
175
|
+
assert.equal(generic.statusCode, 403);
|
|
176
|
+
assert.equal(requestCount(), 1);
|
|
177
|
+
});
|
|
178
|
+
it("rejects side generation for a foreign session and during worktree deletion", async () => {
|
|
179
|
+
const { app, requestCount, worktreeDeletionFence } = await harness("/repo/worktree", {}, { foreign: "/other" });
|
|
180
|
+
const foreign = await app.inject({ method: "POST", url: "/workspaces/workspace/instance/api/session/foreign/generate", payload: { prompt: "test" } });
|
|
181
|
+
assert.equal(foreign.statusCode, 403);
|
|
182
|
+
assert.equal(requestCount(), 0);
|
|
183
|
+
let release;
|
|
184
|
+
const deletion = worktreeDeletionFence.run("workspace:worktree", ["workspace:worktree"], () => (new Promise(resolve => { release = resolve; })));
|
|
185
|
+
try {
|
|
186
|
+
const deleting = await app.inject({ method: "POST", url: "/workspaces/workspace/instance/api/session/owned/generate", payload: { prompt: "test" } });
|
|
187
|
+
assert.equal(deleting.statusCode, 409);
|
|
188
|
+
assert.equal(requestCount(), 0);
|
|
189
|
+
}
|
|
190
|
+
finally {
|
|
191
|
+
release();
|
|
192
|
+
await deletion;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
163
195
|
it("authorizes transcript reads without resolving the mutation checkout identity", async () => {
|
|
164
196
|
const { app, manager, sessionGets } = await harness();
|
|
165
197
|
manager.getWorktreeIdentityForPath = async () => { throw new Error("Unexpected Git mutation identity read"); };
|