gsd-pi 2.80.0-dev.2848d9009 → 2.80.0-dev.2be7caf18

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 (182) hide show
  1. package/README.md +3 -2
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/gsd/auto/loop.js +32 -1
  4. package/dist/resources/extensions/gsd/auto-prompts.js +13 -1
  5. package/dist/resources/extensions/gsd/auto.js +7 -2
  6. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +27 -20
  7. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +21 -0
  8. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  9. package/dist/resources/extensions/gsd/guided-flow.js +33 -6
  10. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  11. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  12. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  13. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  14. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  15. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  16. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  17. package/dist/resources/extensions/gsd/quick.js +34 -2
  18. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  19. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  20. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  21. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  22. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  23. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  24. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  25. package/dist/resources/extensions/gsd/unit-runtime.js +11 -0
  26. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  27. package/dist/web/standalone/.next/BUILD_ID +1 -1
  28. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  29. package/dist/web/standalone/.next/build-manifest.json +2 -2
  30. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  31. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  32. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  40. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/index.html +1 -1
  48. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  55. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  56. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  57. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  58. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  59. package/package.json +1 -1
  60. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  61. package/packages/mcp-server/dist/workflow-tools.js +22 -17
  62. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  63. package/packages/mcp-server/src/workflow-tools.test.ts +66 -0
  64. package/packages/mcp-server/src/workflow-tools.ts +30 -16
  65. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  66. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  67. package/packages/pi-coding-agent/dist/core/agent-session.js +3 -0
  68. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  69. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
  70. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  71. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  72. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  73. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  74. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  75. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  76. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  77. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  78. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  79. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  80. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  81. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  82. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  83. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  84. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  85. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  86. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  87. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -0
  88. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  89. package/packages/pi-coding-agent/dist/core/extensions/runner.js +3 -0
  90. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  91. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +2 -0
  92. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  93. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
  94. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  95. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  96. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  97. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  98. package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
  99. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  100. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  101. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  102. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +3 -0
  103. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  104. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  105. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +13 -5
  106. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  107. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
  108. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  109. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  110. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -0
  111. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  112. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  113. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  114. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
  115. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  116. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  117. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  118. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  119. package/packages/pi-coding-agent/src/core/agent-session.ts +3 -0
  120. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
  121. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  122. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  123. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  124. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  125. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +2 -0
  126. package/packages/pi-coding-agent/src/core/extensions/runner.ts +3 -0
  127. package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
  128. package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
  129. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +4 -0
  130. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
  131. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +22 -7
  132. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
  133. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
  134. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  135. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  136. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  137. package/packages/pi-tui/dist/tui.js +18 -8
  138. package/packages/pi-tui/dist/tui.js.map +1 -1
  139. package/packages/pi-tui/src/tui.ts +20 -8
  140. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  141. package/src/resources/extensions/gsd/auto/loop.ts +50 -8
  142. package/src/resources/extensions/gsd/auto-prompts.ts +17 -1
  143. package/src/resources/extensions/gsd/auto.ts +11 -2
  144. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +27 -19
  145. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
  146. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  147. package/src/resources/extensions/gsd/guided-flow.ts +39 -6
  148. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  149. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  150. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  151. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  152. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  153. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  154. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  155. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  156. package/src/resources/extensions/gsd/quick.ts +37 -2
  157. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +11 -0
  158. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
  159. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  160. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  161. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  162. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  163. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  164. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  165. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  166. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  167. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  168. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +20 -0
  169. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +17 -0
  170. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
  171. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
  172. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +7 -0
  173. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  174. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  175. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  176. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  177. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  178. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  179. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  180. package/src/resources/extensions/gsd/unit-runtime.ts +14 -0
  181. /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → 3EDDd9ULaybSupPoA_vf-}/_buildManifest.js +0 -0
  182. /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → 3EDDd9ULaybSupPoA_vf-}/_ssgManifest.js +0 -0
@@ -1,5 +1,7 @@
1
1
  import assert from "node:assert/strict";
2
2
  import test from "node:test";
3
+ import { Container } from "@gsd/pi-tui";
4
+ import stripAnsi from "strip-ansi";
3
5
 
4
6
  import { findLatestPinnableText, handleAgentEvent } from "./chat-controller.js";
5
7
  import { initTheme } from "../theme/theme.js";
@@ -111,3 +113,57 @@ test("handleAgentEvent: agent_start clears stale adaptive blocking error", async
111
113
  assert.equal(cleared, true);
112
114
  assert.equal(requestedRender, true);
113
115
  });
116
+
117
+ test("handleAgentEvent: standalone completed tool events roll up incrementally", async () => {
118
+ initTheme("dark", false);
119
+ const chatContainer = new Container();
120
+ let renderCount = 0;
121
+ const host = {
122
+ isInitialized: true,
123
+ footer: { invalidate() {} },
124
+ settingsManager: {
125
+ getTimestampFormat() {
126
+ return "date-time-iso";
127
+ },
128
+ getShowImages() {
129
+ return false;
130
+ },
131
+ },
132
+ getRegisteredToolDefinition() {
133
+ return undefined;
134
+ },
135
+ chatContainer,
136
+ pendingTools: new Map(),
137
+ ui: {
138
+ requestRender() {
139
+ renderCount++;
140
+ },
141
+ },
142
+ } as any;
143
+
144
+ for (const [toolCallId, toolName] of [
145
+ ["read-1", "read"],
146
+ ["read-2", "read"],
147
+ ["edit-1", "edit"],
148
+ ] as const) {
149
+ await handleAgentEvent(host, {
150
+ type: "tool_execution_start",
151
+ toolCallId,
152
+ toolName,
153
+ args: { path: `/tmp/${toolCallId}.txt` },
154
+ } as any);
155
+ await handleAgentEvent(host, {
156
+ type: "tool_execution_end",
157
+ toolCallId,
158
+ toolName,
159
+ result: { content: [], isError: false },
160
+ isError: false,
161
+ } as any);
162
+ }
163
+
164
+ const rendered = stripAnsi(chatContainer.render(100).join("\n"));
165
+ assert.match(rendered, /Context reads 2 actions\s+success · \d+(ms|s)/);
166
+ assert.match(rendered, /File changes 1 action\s+success · \d+(ms|s)/);
167
+ assert.doesNotMatch(rendered, /\bread\s+success ·/);
168
+ assert.ok(renderCount > 0);
169
+ });
@@ -28,7 +28,8 @@ type RenderedSegment =
28
28
  contentType: "text" | "thinking";
29
29
  component: AssistantMessageComponent;
30
30
  }
31
- | { kind: "tool"; contentIndex: number; component: ToolExecutionComponent };
31
+ | { kind: "tool"; contentIndex: number; component: ToolExecutionComponent }
32
+ | { kind: "tool-summary"; component: ToolPhaseSummaryComponent; phases: ToolExecutionPhase[] };
32
33
 
33
34
  let renderedSegments: RenderedSegment[] = [];
34
35
  // When providers reuse one assistant lifecycle across internal sub-turns,
@@ -124,17 +125,25 @@ function replaceCompactToolRowsWithPhaseSummary(
124
125
  ): void {
125
126
  let changed = false;
126
127
  const nextRenderedSegments: RenderedSegment[] = [];
127
- let rollupRun: Array<{ seg: Extract<RenderedSegment, { kind: "tool" }>; phase: ToolExecutionPhase }> = [];
128
+ let rollupRun: Array<{
129
+ seg: Extract<RenderedSegment, { kind: "tool" | "tool-summary" }>;
130
+ phases: ToolExecutionPhase[];
131
+ }> = [];
128
132
 
129
133
  const flushRollupRun = () => {
130
- if (rollupRun.length < 2) {
134
+ const actionCount = rollupRun.reduce(
135
+ (total, item) => total + item.phases.reduce((sum, phase) => sum + phase.count, 0),
136
+ 0,
137
+ );
138
+ if (actionCount < 2) {
131
139
  nextRenderedSegments.push(...rollupRun.map((item) => item.seg));
132
140
  rollupRun = [];
133
141
  return;
134
142
  }
135
143
 
136
144
  const firstIndex = Math.max(0, host.chatContainer.children.indexOf(rollupRun[0].seg.component));
137
- const summary = new ToolPhaseSummaryComponent(mergeToolPhases(rollupRun.map((item) => item.phase)));
145
+ const phases = mergeToolPhases(rollupRun.flatMap((item) => item.phases));
146
+ const summary = new ToolPhaseSummaryComponent(phases);
138
147
 
139
148
  for (const { seg } of rollupRun) {
140
149
  host.chatContainer.removeChild(seg.component);
@@ -149,13 +158,18 @@ function replaceCompactToolRowsWithPhaseSummary(
149
158
  }
150
159
 
151
160
  changed = true;
161
+ nextRenderedSegments.push({ kind: "tool-summary", component: summary, phases });
152
162
  rollupRun = [];
153
163
  };
154
164
 
155
165
  for (const seg of renderedSegments) {
156
166
  const phase = seg.kind === "tool" ? seg.component.getRollupPhase() : null;
157
167
  if (seg.kind === "tool" && phase) {
158
- rollupRun.push({ seg, phase });
168
+ rollupRun.push({ seg, phases: [phase] });
169
+ continue;
170
+ }
171
+ if (seg.kind === "tool-summary") {
172
+ rollupRun.push({ seg, phases: seg.component.getPhases() });
159
173
  continue;
160
174
  }
161
175
 
@@ -409,6 +423,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
409
423
  details: externalToolResult.details,
410
424
  isError: externalToolResult.isError,
411
425
  });
426
+ replaceCompactToolRowsWithPhaseSummary(host);
412
427
  }
413
428
  }
414
429
 
@@ -843,7 +858,6 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
843
858
  host.streamingComponent.setShowMetadata(true);
844
859
  host.streamingComponent.updateContent(host.streamingMessage);
845
860
  }
846
- replaceCompactToolRowsWithPhaseSummary(host);
847
861
 
848
862
  if (host.streamingMessage.stopReason === "aborted" || host.streamingMessage.stopReason === "error") {
849
863
  if (!errorMessage) {
@@ -862,6 +876,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
862
876
  for (const [, component] of host.pendingTools.entries()) {
863
877
  component.setArgsComplete();
864
878
  }
879
+ replaceCompactToolRowsWithPhaseSummary(host);
865
880
  }
866
881
  host.streamingComponent = undefined;
867
882
  host.streamingMessage = undefined;
@@ -912,7 +927,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
912
927
  const component = host.pendingTools.get(event.toolCallId);
913
928
  if (component) {
914
929
  component.updateResult({ ...event.result, isError: event.isError });
915
- host.pendingTools.delete(event.toolCallId);
930
+ replaceCompactToolRowsWithPhaseSummary(host);
916
931
  host.ui.requestRender();
917
932
  }
918
933
  break;
@@ -1378,6 +1378,9 @@ export class InteractiveMode {
1378
1378
  })();
1379
1379
  },
1380
1380
  getSystemPrompt: () => this.session.systemPrompt,
1381
+ setCompactionThresholdOverride: (percent) => {
1382
+ this.session.settingsManager.setCompactionThresholdOverride(percent);
1383
+ },
1381
1384
  });
1382
1385
 
1383
1386
  // Set up the extension shortcut handler on the default editor
@@ -0,0 +1,14 @@
1
+ import assert from "node:assert/strict";
2
+ import { readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import test from "node:test";
5
+
6
+ test("MemoryStorage persists sql.js snapshots through the atomic DB snapshot writer", () => {
7
+ const src = readFileSync(
8
+ join(process.cwd(), "packages", "pi-coding-agent", "src", "resources", "extensions", "memory", "storage.ts"),
9
+ "utf-8",
10
+ );
11
+
12
+ assert.match(src, /atomicWriteDbSnapshotSync\(/, "storage must use atomic DB snapshot writes");
13
+ assert.doesNotMatch(src, /writeFileSync\(this\.dbPath/, "direct live DB overwrite is forbidden");
14
+ });
@@ -9,8 +9,9 @@
9
9
 
10
10
  import initSqlJs, { type Database as SqlJsDatabase } from "sql.js";
11
11
  import { randomUUID } from "crypto";
12
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
12
+ import { existsSync, mkdirSync, readFileSync } from "fs";
13
13
  import { dirname } from "path";
14
+ import { atomicWriteDbSnapshotSync } from "../../../core/db-snapshot.js";
14
15
 
15
16
  export interface ThreadRow {
16
17
  thread_id: string;
@@ -74,7 +75,7 @@ export class MemoryStorage {
74
75
 
75
76
  private persist(): void {
76
77
  const data = this.db.export();
77
- writeFileSync(this.dbPath, Buffer.from(data));
78
+ atomicWriteDbSnapshotSync(this.dbPath, data);
78
79
  }
79
80
 
80
81
  private schedulePersist(): void {