@neuralnomads/codenomad-dev 0.20.0-dev-20260921-63bbdbb1 → 0.20.0-dev-20260922-f3834dd2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dist/opencode/session-pruning/navigation-contract.js +1 -0
  2. package/dist/opencode/session-pruning/navigation-contract.js.map +1 -1
  3. package/dist/opencode/session-pruning/navigation.test.js +12 -1
  4. package/dist/opencode/session-pruning/navigation.test.js.map +1 -1
  5. package/dist/opencode/session-pruning/outline-index.js +14 -1
  6. package/dist/opencode/session-pruning/outline-index.js.map +1 -1
  7. package/dist/plugins/session-pruning/plugin.mjs +16 -3
  8. package/dist/server/__tests__/instance-proxy.test.js +32 -0
  9. package/dist/server/__tests__/instance-proxy.test.js.map +1 -1
  10. package/dist/server/http-server.js +1 -1
  11. package/dist/server/http-server.js.map +1 -1
  12. package/dist/workspaces/__tests__/git-worktree-config.test.js +130 -0
  13. package/dist/workspaces/__tests__/git-worktree-config.test.js.map +1 -0
  14. package/dist/workspaces/__tests__/git-worktrees.test.js +49 -1
  15. package/dist/workspaces/__tests__/git-worktrees.test.js.map +1 -1
  16. package/dist/workspaces/__tests__/native-worktree-fixture.js +2 -2
  17. package/dist/workspaces/__tests__/native-worktree-fixture.js.map +1 -1
  18. package/dist/workspaces/git-worktrees.js +61 -1
  19. package/dist/workspaces/git-worktrees.js.map +1 -1
  20. package/dist/workspaces/native-worktrees.js +24 -9
  21. package/dist/workspaces/native-worktrees.js.map +1 -1
  22. package/package.json +1 -1
  23. package/public/assets/App-DljM3SwE.js +51 -0
  24. package/public/assets/App-DljM3SwE.js.map +1 -0
  25. package/public/assets/FilesTab-CP3GICgc.js +3 -0
  26. package/public/assets/{FilesTab-DOOT4Own.js.map → FilesTab-CP3GICgc.js.map} +1 -1
  27. package/public/assets/{GitChangesTab-DqS17ZG_.js → GitChangesTab-DC5uIAYI.js} +3 -3
  28. package/public/assets/{GitChangesTab-DqS17ZG_.js.map → GitChangesTab-DC5uIAYI.js.map} +1 -1
  29. package/public/assets/{SplitFilePanel-DpXPYY4L.js → SplitFilePanel-D4kbA67I.js} +2 -2
  30. package/public/assets/{SplitFilePanel-DpXPYY4L.js.map → SplitFilePanel-D4kbA67I.js.map} +1 -1
  31. package/public/assets/{StatusTab-CynqW2pr.js → StatusTab-B7-e7Jym.js} +2 -2
  32. package/public/assets/{StatusTab-CynqW2pr.js.map → StatusTab-B7-e7Jym.js.map} +1 -1
  33. package/public/assets/{align-justify-C_MrQdWv.js → align-justify-t6BvuuGq.js} +2 -2
  34. package/public/assets/{align-justify-C_MrQdWv.js.map → align-justify-t6BvuuGq.js.map} +1 -1
  35. package/public/assets/{bundle-full-CVPoVh_h.js → bundle-full-LA4LRJvC.js} +2 -2
  36. package/public/assets/{bundle-full-CVPoVh_h.js.map → bundle-full-LA4LRJvC.js.map} +1 -1
  37. package/public/assets/client-state-BELVPVQK.js +2 -0
  38. package/public/assets/client-state-BELVPVQK.js.map +1 -0
  39. package/public/assets/{diff-viewer-BzgxNlWD.js → diff-viewer-n0toXKZF.js} +2 -2
  40. package/public/assets/{diff-viewer-BzgxNlWD.js.map → diff-viewer-n0toXKZF.js.map} +1 -1
  41. package/public/assets/index-BRo0m4HH.js +2 -0
  42. package/public/assets/index-BRo0m4HH.js.map +1 -0
  43. package/public/assets/index-BT4hx4H9.js +2 -0
  44. package/public/assets/index-BT4hx4H9.js.map +1 -0
  45. package/public/assets/index-CQPkLT1b.js +2 -0
  46. package/public/assets/index-CQPkLT1b.js.map +1 -0
  47. package/public/assets/index-CYrgGxN5.js +3 -0
  48. package/public/assets/index-CYrgGxN5.js.map +1 -0
  49. package/public/assets/index-CjsBXyUr.js +2 -0
  50. package/public/assets/index-CjsBXyUr.js.map +1 -0
  51. package/public/assets/index-CyxtFA9R.js +2 -0
  52. package/public/assets/index-CyxtFA9R.js.map +1 -0
  53. package/public/assets/index-DINKO8rw.js +2 -0
  54. package/public/assets/index-DINKO8rw.js.map +1 -0
  55. package/public/assets/index-DYBqUC9X.css +1 -0
  56. package/public/assets/index-DjwZf3Yh.js +2 -0
  57. package/public/assets/index-DjwZf3Yh.js.map +1 -0
  58. package/public/assets/index-fkx7BwtE.js +2 -0
  59. package/public/assets/index-fkx7BwtE.js.map +1 -0
  60. package/public/assets/{index-Ce-SrKvP.js → index-mN9OrWRM.js} +2 -2
  61. package/public/assets/{index-Ce-SrKvP.js.map → index-mN9OrWRM.js.map} +1 -1
  62. package/public/assets/index-mSrN15cu.js +2 -0
  63. package/public/assets/{index-CrjSY1y2.js.map → index-mSrN15cu.js.map} +1 -1
  64. package/public/assets/index-sYGWeU2B.js +2 -0
  65. package/public/assets/index-sYGWeU2B.js.map +1 -0
  66. package/public/assets/{loading-BWjkEyUD.js → loading-D4az9Vmg.js} +2 -2
  67. package/public/assets/{loading-BWjkEyUD.js.map → loading-D4az9Vmg.js.map} +1 -1
  68. package/public/assets/main-pe2tFxvx.js +42 -0
  69. package/public/assets/main-pe2tFxvx.js.map +1 -0
  70. package/public/assets/{markdown-Bkm0F3oO.js → markdown-Dtp2_t2x.js} +4 -4
  71. package/public/assets/{markdown-Bkm0F3oO.js.map → markdown-Dtp2_t2x.js.map} +1 -1
  72. package/public/assets/{monaco-viewer-C10fFymA.js → monaco-viewer-ChA_iFmw.js} +2 -2
  73. package/public/assets/{monaco-viewer-C10fFymA.js.map → monaco-viewer-ChA_iFmw.js.map} +1 -1
  74. package/public/assets/{startup-state-settings-card-BTfYhHov.js → startup-state-settings-card-CwqMz9iE.js} +2 -2
  75. package/public/assets/{startup-state-settings-card-BTfYhHov.js.map → startup-state-settings-card-CwqMz9iE.js.map} +1 -1
  76. package/public/assets/{terminal-square-Dhdgf3hj.js → terminal-square-5uHstmTD.js} +2 -2
  77. package/public/assets/{terminal-square-Dhdgf3hj.js.map → terminal-square-5uHstmTD.js.map} +1 -1
  78. package/public/assets/{todo-pfT9OVP8.js → todo-rWdKPGRD.js} +2 -2
  79. package/public/assets/{todo-pfT9OVP8.js.map → todo-rWdKPGRD.js.map} +1 -1
  80. package/public/assets/{tool-call-ja_vg-Y6.js → tool-call-B2lbL8ZE.js} +5 -5
  81. package/public/assets/{tool-call-ja_vg-Y6.js.map → tool-call-B2lbL8ZE.js.map} +1 -1
  82. package/public/assets/{unified-picker-Bi-fpJBA.js → unified-picker-CyMBKInh.js} +2 -2
  83. package/public/assets/{unified-picker-Bi-fpJBA.js.map → unified-picker-CyMBKInh.js.map} +1 -1
  84. package/public/assets/{wrap-text-DJHeAvj4.js → wrap-text-CSz4eer6.js} +2 -2
  85. package/public/assets/{wrap-text-DJHeAvj4.js.map → wrap-text-CSz4eer6.js.map} +1 -1
  86. package/public/index.html +4 -4
  87. package/public/loading.html +4 -4
  88. package/public/sw.js +1 -1
  89. package/public/sw.js.map +1 -1
  90. package/public/assets/App-bGIUQ-dD.js +0 -49
  91. package/public/assets/App-bGIUQ-dD.js.map +0 -1
  92. package/public/assets/FilesTab-DOOT4Own.js +0 -3
  93. package/public/assets/client-state-DHHjx28k.js +0 -2
  94. package/public/assets/client-state-DHHjx28k.js.map +0 -1
  95. package/public/assets/index-B5KIA1QZ.js +0 -2
  96. package/public/assets/index-B5KIA1QZ.js.map +0 -1
  97. package/public/assets/index-BO3LYyge.js +0 -2
  98. package/public/assets/index-BO3LYyge.js.map +0 -1
  99. package/public/assets/index-Bzngra1L.js +0 -3
  100. package/public/assets/index-Bzngra1L.js.map +0 -1
  101. package/public/assets/index-C6-rb6B7.css +0 -1
  102. package/public/assets/index-CI6ZE9xs.js +0 -2
  103. package/public/assets/index-CI6ZE9xs.js.map +0 -1
  104. package/public/assets/index-CSUBS-o9.js +0 -2
  105. package/public/assets/index-CSUBS-o9.js.map +0 -1
  106. package/public/assets/index-Cl4PCYg4.js +0 -2
  107. package/public/assets/index-Cl4PCYg4.js.map +0 -1
  108. package/public/assets/index-CrjSY1y2.js +0 -2
  109. package/public/assets/index-D7SuJgSm.js +0 -2
  110. package/public/assets/index-D7SuJgSm.js.map +0 -1
  111. package/public/assets/index-Daf72P6o.js +0 -2
  112. package/public/assets/index-Daf72P6o.js.map +0 -1
  113. package/public/assets/index-WIaMCSWq.js +0 -2
  114. package/public/assets/index-WIaMCSWq.js.map +0 -1
  115. package/public/assets/index-WsSXkxQ_.js +0 -2
  116. package/public/assets/index-WsSXkxQ_.js.map +0 -1
  117. package/public/assets/main-Hn7UJb2f.js +0 -42
  118. package/public/assets/main-Hn7UJb2f.js.map +0 -1
@@ -21,6 +21,7 @@ const messageType = z.enum(["user", "assistant", "system", "synthetic", "skill",
21
21
  export const outlineEntrySchema = z.object({
22
22
  id, seq: z.number().int().nonnegative(), type: messageType,
23
23
  tools: z.number().int().nonnegative(), reasoning: z.number().int().nonnegative(),
24
+ toolName: z.string().max(256).optional(),
24
25
  }).strict();
25
26
  export const outlineResultSchema = z.union([pruningBlockedSchema, z.object({
26
27
  status: z.literal("outline"), entries: z.array(outlineEntrySchema).max(16384),
@@ -1 +1 @@
1
- {"version":3,"file":"navigation-contract.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/navigation-contract.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\"\nimport { pruningBlockedSchema } from \"./contract\"\n\nconst id = z.string().min(1).max(256)\nexport const navigationTargetSchema = z.discriminatedUnion(\"kind\", [\n z.object({ kind: z.literal(\"latest\") }).strict(),\n z.object({ kind: z.literal(\"oldest\") }).strict(),\n z.object({ kind: z.literal(\"around\"), messageID: id }).strict(),\n z.object({ kind: z.literal(\"before\"), messageID: id }).strict(),\n z.object({ kind: z.literal(\"after\"), messageID: id }).strict(),\n])\nexport type NavigationTarget = z.infer<typeof navigationTargetSchema>\nexport const navigationWindowInputSchema = z.object({ sessionID: id, target: navigationTargetSchema }).strict()\nconst outlineCursorSchema = z.object({ after: z.number().int().nonnegative(), through: z.number().int().nonnegative() }).strict()\nexport const outlineCheckpointSchema = z.object({ after: z.number().int().min(-1), through: z.number().int().nonnegative(),\n digest: z.string().regex(/^[a-f0-9]{64}$/) }).strict()\nexport type OutlineCheckpoint = z.infer<typeof outlineCheckpointSchema>\nexport const outlineInputSchema = z.object({ sessionID: id,\n cursor: outlineCursorSchema.optional(),\n after: z.number().int().min(-1).optional(),\n known: z.array(outlineCheckpointSchema).max(512).optional(),\n}).strict()\nconst messageType = z.enum([\"user\", \"assistant\", \"system\", \"synthetic\", \"skill\", \"shell\", \"compaction\", \"idle\", \"agent-switched\", \"model-switched\", \"location-switched\"])\nexport const outlineEntrySchema = z.object({\n id, seq: z.number().int().nonnegative(), type: messageType,\n tools: z.number().int().nonnegative(), reasoning: z.number().int().nonnegative(),\n}).strict()\nexport type OutlineEntry = z.infer<typeof outlineEntrySchema>\nexport const outlineResultSchema = z.union([pruningBlockedSchema, z.object({\n status: z.literal(\"outline\"), entries: z.array(outlineEntrySchema).max(16384),\n total: z.number().int().nonnegative(), cursor: outlineCursorSchema.nullable(),\n checkpoints: z.array(outlineCheckpointSchema.extend({ changed: z.boolean() })).max(512),\n}).strict()])\nexport type OutlineResult = z.infer<typeof outlineResultSchema>\nexport const outlinePreviewInputSchema = z.object({ sessionID: id, messageIDs: z.array(id).min(1).max(12) }).strict()\nexport const outlinePreviewResultSchema = z.union([pruningBlockedSchema, z.object({\n status: z.literal(\"previews\"), entries: z.array(z.object({ id, text: z.string().max(4096), tools: z.string().max(4096) }).strict()).max(12),\n}).strict()])\nexport type OutlinePreviewResult = z.infer<typeof outlinePreviewResultSchema>\nexport const navigationWindowResultSchema = z.union([pruningBlockedSchema,\n z.object({ status: z.literal(\"blocked\"), reason: z.literal(\"anchor_missing\") }).strict(), z.object({\n status: z.literal(\"window\"),\n messages: z.array(z.object({ id, type: messageType, time: z.object({ created: z.number() }).passthrough() }).passthrough()).max(200),\n older: navigationTargetSchema.nullable(), newer: navigationTargetSchema.nullable(),\n resume: navigationTargetSchema, latest: z.boolean(),\n}).strict()])\nexport type NavigationWindowResult = z.infer<typeof navigationWindowResultSchema>\n"]}
1
+ {"version":3,"file":"navigation-contract.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/navigation-contract.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\"\nimport { pruningBlockedSchema } from \"./contract\"\n\nconst id = z.string().min(1).max(256)\nexport const navigationTargetSchema = z.discriminatedUnion(\"kind\", [\n z.object({ kind: z.literal(\"latest\") }).strict(),\n z.object({ kind: z.literal(\"oldest\") }).strict(),\n z.object({ kind: z.literal(\"around\"), messageID: id }).strict(),\n z.object({ kind: z.literal(\"before\"), messageID: id }).strict(),\n z.object({ kind: z.literal(\"after\"), messageID: id }).strict(),\n])\nexport type NavigationTarget = z.infer<typeof navigationTargetSchema>\nexport const navigationWindowInputSchema = z.object({ sessionID: id, target: navigationTargetSchema }).strict()\nconst outlineCursorSchema = z.object({ after: z.number().int().nonnegative(), through: z.number().int().nonnegative() }).strict()\nexport const outlineCheckpointSchema = z.object({ after: z.number().int().min(-1), through: z.number().int().nonnegative(),\n digest: z.string().regex(/^[a-f0-9]{64}$/) }).strict()\nexport type OutlineCheckpoint = z.infer<typeof outlineCheckpointSchema>\nexport const outlineInputSchema = z.object({ sessionID: id,\n cursor: outlineCursorSchema.optional(),\n after: z.number().int().min(-1).optional(),\n known: z.array(outlineCheckpointSchema).max(512).optional(),\n}).strict()\nconst messageType = z.enum([\"user\", \"assistant\", \"system\", \"synthetic\", \"skill\", \"shell\", \"compaction\", \"idle\", \"agent-switched\", \"model-switched\", \"location-switched\"])\nexport const outlineEntrySchema = z.object({\n id, seq: z.number().int().nonnegative(), type: messageType,\n tools: z.number().int().nonnegative(), reasoning: z.number().int().nonnegative(),\n toolName: z.string().max(256).optional(),\n}).strict()\nexport type OutlineEntry = z.infer<typeof outlineEntrySchema>\nexport const outlineResultSchema = z.union([pruningBlockedSchema, z.object({\n status: z.literal(\"outline\"), entries: z.array(outlineEntrySchema).max(16384),\n total: z.number().int().nonnegative(), cursor: outlineCursorSchema.nullable(),\n checkpoints: z.array(outlineCheckpointSchema.extend({ changed: z.boolean() })).max(512),\n}).strict()])\nexport type OutlineResult = z.infer<typeof outlineResultSchema>\nexport const outlinePreviewInputSchema = z.object({ sessionID: id, messageIDs: z.array(id).min(1).max(12) }).strict()\nexport const outlinePreviewResultSchema = z.union([pruningBlockedSchema, z.object({\n status: z.literal(\"previews\"), entries: z.array(z.object({ id, text: z.string().max(4096), tools: z.string().max(4096) }).strict()).max(12),\n}).strict()])\nexport type OutlinePreviewResult = z.infer<typeof outlinePreviewResultSchema>\nexport const navigationWindowResultSchema = z.union([pruningBlockedSchema,\n z.object({ status: z.literal(\"blocked\"), reason: z.literal(\"anchor_missing\") }).strict(), z.object({\n status: z.literal(\"window\"),\n messages: z.array(z.object({ id, type: messageType, time: z.object({ created: z.number() }).passthrough() }).passthrough()).max(200),\n older: navigationTargetSchema.nullable(), newer: navigationTargetSchema.nullable(),\n resume: navigationTargetSchema, latest: z.boolean(),\n}).strict()])\nexport type NavigationWindowResult = z.infer<typeof navigationWindowResultSchema>\n"]}
@@ -149,12 +149,21 @@ test("demand excerpts preserve Markdown, bound tool output and enforce ownership
149
149
  try {
150
150
  db.prepare("UPDATE session_message SET type='assistant', data=? WHERE id=?").run(JSON.stringify({ content: [
151
151
  { type: "text", text: "**Rich** [link](https://example.org)\n\n" + "text ".repeat(2000) },
152
- { type: "tool", name: "shell", state: { content: [{ type: "text", text: "output".repeat(2000) }] } },
152
+ { type: "tool", tool: "shell", state: { content: [{ type: "text", text: "output".repeat(2000) }] } },
153
153
  ] }), id(1));
154
154
  const index = await readSessionOutline(db, scope, undefined, signal());
155
155
  if (index.status !== "outline")
156
156
  assert.fail("Expected index");
157
157
  assert.equal(index.entries[1].tools, 1);
158
+ assert.equal(index.entries[1].toolName, "shell");
159
+ const unicodeName = "🔧".repeat(256);
160
+ db.prepare("UPDATE session_message SET type='assistant', data=? WHERE id=?").run(JSON.stringify({ content: [
161
+ { type: "tool", name: unicodeName, state: {} },
162
+ ] }), id(2));
163
+ const unicodeIndex = await readSessionOutline(db, scope, undefined, signal());
164
+ if (unicodeIndex.status !== "outline")
165
+ assert.fail("Expected Unicode index");
166
+ assert.equal(unicodeIndex.entries[2].toolName, "🔧".repeat(128), "tool metadata must satisfy its UTF-16 RPC bound");
158
167
  const previews = await readOutlinePreviews(db, scope, [id(1), "foreign"], signal());
159
168
  if (previews.status !== "previews")
160
169
  assert.fail("Expected previews");
@@ -192,12 +201,14 @@ test("persisted checkpoints reconcile offline edits, pruning, deletions and appe
192
201
  assert.equal(delta.checkpoints.filter(checkpoint => !checkpoint.changed).length, 1);
193
202
  assert(!delta.entries.some(entry => entry.id === id(250)));
194
203
  assert.equal(delta.entries.find(entry => entry.id === id(260))?.tools, 1);
204
+ assert.equal(delta.entries.find(entry => entry.id === id(260))?.toolName, "read");
195
205
  // Pruning uses a conditional data update, without changing native timestamps.
196
206
  db.prepare("UPDATE session_message SET data=? WHERE id=?").run('{"content":[]}', id(260));
197
207
  const pruned = await readSessionOutline(db, scope, undefined, signal(), -1, delta.checkpoints.map(({ changed: _, ...checkpoint }) => checkpoint));
198
208
  if (pruned.status !== "outline")
199
209
  assert.fail("Expected prune delta");
200
210
  assert.equal(pruned.entries.find(entry => entry.id === id(260))?.tools, 0);
211
+ assert.equal(pruned.entries.find(entry => entry.id === id(260))?.toolName, undefined);
201
212
  assert.equal(db.isTransaction, false);
202
213
  }
203
214
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.test.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/navigation.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,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAC7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAEvD,MAAM,KAAK,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAA;AACpE,MAAM,EAAE,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,WAAW,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAA;AACjE,SAAS,OAAO,CAAC,KAAK,GAAG,IAAI;IAC3B,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,UAAU,CAAC,CAAA;IACvC,EAAE,CAAC,IAAI,CAAC;;;+DAGqD,CAAC,CAAA;IAC9D,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,oFAAoF,CAAC,CAAA;IAC/G,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE;QAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;IAC5H,OAAO,EAAE,CAAA;AACX,CAAC;AACD,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,eAAe,EAAE,CAAC,MAAM,CAAA;AACjD,IAAI,CAAC,iGAAiG,EAAE,KAAK,IAAI,EAAE;IACjH,MAAM,EAAE,GAAG,OAAO,EAAE,CAAA;IACpB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;QACvG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QACrC,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAM;QACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QACzC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;QAC9C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;QAC5C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;QAClD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QAClC,MAAM,CAAC,SAAS,CAAC,MAAM,oBAAoB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAA;QACxF,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAM,EAAE,MAAM,EAAE,CAAC,CAAA;QAC7E,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QACrC,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAM;QACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QACzC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC7E,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAM,EAAE,MAAM,EAAE,CAAC,CAAA;QAC5E,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QACpC,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAM;QACrC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;QACjF,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;QACjD,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;IACvC,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAA;IAAC,CAAC;AAC1B,CAAC,CAAC,CAAA;AACF,IAAI,CAAC,sFAAsF,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IACvG,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;IACzB,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,IAAI,GAAG,CAAC,CAAA;IACrD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAA;QACtE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QACrC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,OAAM;QACtC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAChC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,sEAAsE,CAAC,CAAA;QACjH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QACpB,EAAE,CAAC,OAAO,CAAC,oFAAoF,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAA;QACvL,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAChD,IAAI,MAAM,GAA8C,KAAK,CAAC,MAAM,CAAA;QACpE,OAAO,MAAM,EAAE,CAAC;YACd,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;YAClE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;YACpC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAK;YACpC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,CAAA;YACpC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,CAAA;YACnF,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;YAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QACxE,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QAC/B,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;QAC3C,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;QACnC,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,KAAK,GAAG,CAAC,CAAC,CAAA;QACjF,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;QAC7D,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAChF,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAA;IAAC,CAAC;AAC1B,CAAC,CAAC,CAAA;AACF,IAAI,CAAC,8EAA8E,EAAE,KAAK,IAAI,EAAE;IAC9F,MAAM,EAAE,GAAG,OAAO,EAAE,CAAA;IACpB,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;QACjH,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;QACrC,MAAM,CAAC,SAAS,CAAC,MAAM,oBAAoB,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAA;QAC5J,EAAE,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;QACxF,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;QAClF,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;QACrC,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;YACjD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;YAChC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QACnC,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,oBAAoB,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QAC1H,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAA;QACxE,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACpE,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAA;IAAC,CAAC;AAC1B,CAAC,CAAC,CAAA;AACF,IAAI,CAAC,iFAAiF,EAAE,KAAK,IAAI,EAAE;IACjG,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACrB,IAAI,CAAC;QACH,EAAE,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;QACjI,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,oBAAoB,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QACrG,MAAM,SAAS,GAAG,IAAI,eAAe,EAAE,CAAC;QAAC,SAAS,CAAC,KAAK,EAAE,CAAA;QAC1D,MAAM,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAA;QACrG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;IACvC,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAA;IAAC,CAAC;AAC1B,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,mFAAmF,EAAE,KAAK,IAAI,EAAE;IACnG,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;IACvB,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,YAAY,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAA;QACtC,MAAM,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAA;QACtG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,CAAA;QAC5F,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;YAAE,EAAE,CAAC,OAAO,CAAC,8CAA8C,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QACvG,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAA;QACtE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QACrC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,OAAM;QACtC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QACvC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QAChC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;IAClD,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAA;IAAC,CAAC;AAC1B,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,iFAAiF,EAAE,KAAK,IAAI,EAAE;IACjG,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACrB,IAAI,CAAC;QACH,EAAE,CAAC,OAAO,CAAC,gEAAgE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE;gBACzG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,0CAA0C,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;gBACzF,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;aACrG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QACZ,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAA;QACtE,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;QAC7D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QACvC,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;QACnF,IAAI,QAAQ,CAAC,MAAM,KAAK,UAAU;YAAE,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;QACpE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QACxC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAA;QAC9D,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QACnD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;QACpD,MAAM,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;QACrG,EAAE,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACtF,MAAM,CAAC,SAAS,CAAC,MAAM,mBAAmB,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAA;IAChH,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAA;IAAC,CAAC;AAC1B,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,kHAAkH,EAAE,KAAK,IAAI,EAAE;IAClI,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAA;QACtE,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;QAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,CAAA;QAClF,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;QACrF,IAAI,SAAS,CAAC,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;QACxE,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,gDAAgD,CAAC,CAAA;QAC7F,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;QACjE,EAAE,CAAC,OAAO,CAAC,8EAA8E,CAAC,CAAC,GAAG,CAC5F,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;QACzE,EAAE,CAAC,OAAO,CAAC,oFAAoF,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAA;QAC1I,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;QACjF,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;QAC7D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QAC/B,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QACvC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QACnF,MAAM,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;QAC1D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;QACzE,8EAA8E;QAC9E,EAAE,CAAC,OAAO,CAAC,8CAA8C,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;QACzF,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,EACxE,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;QACvE,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAA;QACpE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;QAC1E,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;IACvC,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAA;IAAC,CAAC;AAC1B,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,kGAAkG,EAAE,KAAK,IAAI,EAAE;IAClH,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxB,IAAI,CAAC;QACH,IAAI,KAAK,GAAwD,EAAE,CAAA;QACnE,KAAK,IAAI,GAAG,GAAG,IAAI,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;YACvC,EAAE,CAAC,OAAO,CAAC,oFAAoF,CAAC;iBAC7F,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAA;YAC1C,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;YAChF,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;YAC5D,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;YACxC,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAA;IAAC,CAAC;AAC1B,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;IACzF,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAA;IACzB,IAAI,CAAC;QACH,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAA;QACrE,MAAM,KAAK,GAAwD,EAAE,CAAA;QACrE,IAAI,MAAsD,CAAA;QAC1D,GAAG,CAAC;YACF,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;YAClE,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;YAC5D,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,UAAU,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;YAClF,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,SAAS,CAAA;QACnC,CAAC,QAAQ,MAAM,EAAC;QAChB,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;QACjE,EAAE,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAA;QACpD,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,GAAG,CAAC;YACF,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;YAC7E,MAAM,CAAC,mBAAmB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,oDAAoD,CAAC,CAAA;YACzG,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;gBAAE,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;YAC5D,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAA;YAC5B,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,SAAS,CAAA;QACnC,CAAC,QAAQ,MAAM,EAAC;QAChB,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;IAC5B,CAAC;YAAS,CAAC;QAAC,EAAE,CAAC,KAAK,EAAE,CAAA;IAAC,CAAC;AAC1B,CAAC,CAAC,CAAA","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: Number(row.tools), reasoning: Number(row.reasoning) });
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":"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","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\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 (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 entries.push({ id: String(row.id), seq: Number(row.seq), type: row.type as OutlineEntry[\"type\"],\n tools: Number(row.tools), reasoning: Number(row.reasoning) })\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"]}
1
+ {"version":3,"file":"outline-index.js","sourceRoot":"","sources":["../../../src/opencode/session-pruning/outline-index.ts"],"names":[],"mappings":"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","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: Number(row.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"); };