gsd-pi 2.80.0-dev.8b3a59f5c → 2.80.0-dev.b2a374d5b

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 (222) hide show
  1. package/dist/resources/.managed-resources-content-hash +1 -1
  2. package/dist/resources/GSD-WORKFLOW.md +2 -2
  3. package/dist/resources/extensions/gsd/auto/loop.js +32 -1
  4. package/dist/resources/extensions/gsd/auto/phases.js +37 -30
  5. package/dist/resources/extensions/gsd/auto-dispatch.js +10 -0
  6. package/dist/resources/extensions/gsd/auto-post-unit.js +10 -10
  7. package/dist/resources/extensions/gsd/auto-prompts.js +111 -1
  8. package/dist/resources/extensions/gsd/auto-start.js +2 -3
  9. package/dist/resources/extensions/gsd/auto.js +16 -3
  10. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +21 -0
  11. package/dist/resources/extensions/gsd/clean-root-preflight.js +42 -4
  12. package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
  13. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  14. package/dist/resources/extensions/gsd/detection.js +106 -0
  15. package/dist/resources/extensions/gsd/guided-flow.js +63 -12
  16. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  17. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  18. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  19. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
  20. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  21. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  22. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  23. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  24. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  25. package/dist/resources/extensions/gsd/quick.js +34 -2
  26. package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
  27. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  28. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  29. package/dist/resources/extensions/gsd/unit-runtime.js +11 -0
  30. package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
  31. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  32. package/dist/web/standalone/.next/BUILD_ID +1 -1
  33. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  34. package/dist/web/standalone/.next/build-manifest.json +2 -2
  35. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  36. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/index.html +1 -1
  53. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  60. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  61. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  62. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  63. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  64. package/package.json +4 -2
  65. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  66. package/packages/pi-coding-agent/dist/core/agent-session.js +3 -0
  67. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  68. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +32 -0
  69. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  70. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  71. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  72. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  73. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  74. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  75. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  76. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  77. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  78. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  79. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  80. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  81. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  82. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  83. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  84. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  85. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  86. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -0
  87. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  88. package/packages/pi-coding-agent/dist/core/extensions/runner.js +17 -1
  89. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  90. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +99 -0
  91. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  92. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
  93. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  94. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  95. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  96. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  97. package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
  98. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  99. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
  100. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
  101. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +25 -20
  102. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  103. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +2 -2
  104. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
  105. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  106. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  107. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  108. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +2 -1
  109. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  110. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +7 -6
  111. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  112. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  113. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  114. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +26 -13
  115. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  116. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  117. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +15 -5
  118. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  119. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
  120. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  121. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  122. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -0
  123. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  124. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  125. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
  126. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +21 -0
  128. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
  129. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  130. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  131. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
  132. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  133. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  134. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  135. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  136. package/packages/pi-coding-agent/src/core/agent-session.ts +3 -0
  137. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +38 -0
  138. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  139. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  140. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  141. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  142. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +110 -0
  143. package/packages/pi-coding-agent/src/core/extensions/runner.ts +19 -1
  144. package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
  145. package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
  146. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
  147. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +25 -20
  148. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +2 -2
  149. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
  150. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +2 -1
  151. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +10 -9
  152. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +33 -13
  153. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
  154. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +24 -7
  155. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
  156. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
  157. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +25 -0
  158. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
  159. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  160. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  161. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  162. package/packages/pi-tui/dist/tui.js +17 -7
  163. package/packages/pi-tui/dist/tui.js.map +1 -1
  164. package/packages/pi-tui/src/tui.ts +19 -7
  165. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  166. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  167. package/pkg/dist/modes/interactive/theme/themes.js +36 -27
  168. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  169. package/src/resources/GSD-WORKFLOW.md +2 -2
  170. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  171. package/src/resources/extensions/gsd/auto/loop.ts +50 -8
  172. package/src/resources/extensions/gsd/auto/phases.ts +42 -28
  173. package/src/resources/extensions/gsd/auto-dispatch.ts +17 -0
  174. package/src/resources/extensions/gsd/auto-post-unit.ts +10 -10
  175. package/src/resources/extensions/gsd/auto-prompts.ts +116 -1
  176. package/src/resources/extensions/gsd/auto-start.ts +7 -6
  177. package/src/resources/extensions/gsd/auto.ts +23 -3
  178. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
  179. package/src/resources/extensions/gsd/clean-root-preflight.ts +41 -3
  180. package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
  181. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  182. package/src/resources/extensions/gsd/detection.ts +128 -0
  183. package/src/resources/extensions/gsd/guided-flow.ts +66 -12
  184. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  185. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  186. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  187. package/src/resources/extensions/gsd/prompts/complete-milestone.md +7 -8
  188. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  189. package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  190. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  191. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  192. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
  193. package/src/resources/extensions/gsd/quick.ts +37 -2
  194. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
  195. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1 -1
  196. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +88 -2
  197. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
  198. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  199. package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
  200. package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
  201. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  202. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  203. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  204. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  205. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  206. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  207. package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
  208. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
  209. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +38 -0
  210. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +63 -2
  211. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
  212. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +7 -0
  213. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
  214. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +37 -6
  215. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
  216. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
  217. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  218. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  219. package/src/resources/extensions/gsd/unit-runtime.ts +14 -0
  220. package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
  221. /package/dist/web/standalone/.next/static/{k-MDjzPMF62Rg1-FR437h → FU0iL9dhdc2IBzEYBDOlY}/_buildManifest.js +0 -0
  222. /package/dist/web/standalone/.next/static/{k-MDjzPMF62Rg1-FR437h → FU0iL9dhdc2IBzEYBDOlY}/_ssgManifest.js +0 -0
@@ -1,3 +1,4 @@
1
+ // GSD2 TUI Tests - Runtime coverage for tool-card cleanup and success notification rendering.
1
2
  // Runtime regression tests for the post-compaction tool-card cleanup and the
2
3
  // green-bordered success-notification rendering. Replaces the source-grep
3
4
  // `src/tests/tui-running-and-success-box.test.ts` that was deleted in #4875
@@ -74,7 +75,7 @@ function makeMockTUI(): MockTui {
74
75
  // ─── Bug 1: tool cards stuck in "Running" after compaction ──────────────
75
76
 
76
77
  describe("ToolExecutionComponent post-compaction cleanup", () => {
77
- it("renders 'Running' status while the tool call has no result", () => {
78
+ it("renders 'running' status while the tool call has no result", () => {
78
79
  // Baseline: a freshly-constructed component (mid-stream) must show
79
80
  // the running badge — this is the state we need to flip OUT of when
80
81
  // compaction removes the result message.
@@ -88,12 +89,12 @@ describe("ToolExecutionComponent post-compaction cleanup", () => {
88
89
  );
89
90
  const rendered = c.render(60).map(stripAnsi).join("\n");
90
91
  assert.ok(
91
- rendered.includes("Running"),
92
- "freshly constructed component should render 'Running' badge",
92
+ rendered.includes("running"),
93
+ "freshly constructed component should render 'running' badge",
93
94
  );
94
95
  });
95
96
 
96
- it("markHistoricalNoResult flips a stuck tool card OUT of 'Running'", () => {
97
+ it("markHistoricalNoResult flips a stuck tool card OUT of 'running'", () => {
97
98
  // Real bug: after session-history replay (post-compaction or session
98
99
  // switch), tool calls without matching tool_result messages stay in
99
100
  // isPartial = true forever. markHistoricalNoResult must produce a
@@ -111,13 +112,13 @@ describe("ToolExecutionComponent post-compaction cleanup", () => {
111
112
 
112
113
  const rendered = c.render(60).map(stripAnsi).join("\n");
113
114
  assert.ok(
114
- !rendered.includes("Running"),
115
- "after markHistoricalNoResult, the tool card must NOT render 'Running' got:\n" +
115
+ !rendered.includes("running"),
116
+ "after markHistoricalNoResult, the tool card must NOT render 'running' -- got:\n" +
116
117
  rendered,
117
118
  );
118
119
  assert.ok(
119
- rendered.includes("Done"),
120
- "flipped card should render 'Done' status (no-result success)",
120
+ rendered.includes("success"),
121
+ "flipped card should render 'success' status (no-result success)",
121
122
  );
122
123
  });
123
124
 
@@ -145,7 +146,7 @@ describe("ToolExecutionComponent post-compaction cleanup", () => {
145
146
  );
146
147
 
147
148
  const before = c.render(60).map(stripAnsi).join("\n");
148
- assert.ok(before.includes("Done"), "after complete(), card shows 'Done'");
149
+ assert.ok(before.includes("success"), "after complete(), card shows 'success'");
149
150
 
150
151
  c.markHistoricalNoResult(); // must early-return
151
152
  const after = c.render(60).map(stripAnsi).join("\n");
@@ -107,9 +107,9 @@ function renderToolFrame(
107
107
 
108
108
  const borderColor = opts.tone === "error" ? "toolError" : opts.tone === "pending" ? "toolRunning" : "toolSuccess";
109
109
  const topColor = borderColor;
110
- const labelColor = opts.tone === "error" ? "toolError" : "surfaceTitle";
110
+ const labelColor = opts.tone === "error" ? "toolError" : opts.tone === "pending" ? "toolRunning" : "toolSuccess";
111
111
  const statusColor = opts.tone === "error" ? "toolError" : opts.tone === "pending" ? "toolRunning" : "toolSuccess";
112
- const leftStyled = theme.fg(labelColor, theme.bold(`• ${opts.label}`));
112
+ const leftStyled = theme.fg(labelColor, theme.bold(opts.label));
113
113
  const rightStyled = theme.fg(statusColor, opts.status);
114
114
  const gap = Math.max(1, outerWidth - visibleWidth(leftStyled) - visibleWidth(rightStyled));
115
115
  const headerRow = `${leftStyled}${" ".repeat(gap)}${rightStyled}`;
@@ -128,6 +128,27 @@ function renderToolFrame(
128
128
  .render(bodyLines, outerWidth);
129
129
  }
130
130
 
131
+ function renderCollapsedToolRow(
132
+ label: string,
133
+ status: string,
134
+ width: number,
135
+ tone: Extract<ToolFrameTone, "success">,
136
+ ): string[] {
137
+ const outerWidth = Math.max(20, width);
138
+ const contentWidth = Math.max(1, outerWidth - 2);
139
+ const statusColor = tone === "success" ? "toolSuccess" : "toolMuted";
140
+ const labelStyled = theme.fg(statusColor, label);
141
+ const statusStyled = theme.fg(statusColor, status);
142
+ const labelWidth = Math.max(1, contentWidth - visibleWidth(statusStyled) - 1);
143
+ const clippedLabel = truncateToWidth(labelStyled, labelWidth, "");
144
+ const gap = Math.max(1, contentWidth - visibleWidth(clippedLabel) - visibleWidth(statusStyled));
145
+ const line = `${clippedLabel}${" ".repeat(gap)}${statusStyled}`;
146
+ return style()
147
+ .border("minimal")
148
+ .borderColor((text) => theme.fg(statusColor, text))
149
+ .render([line], outerWidth);
150
+ }
151
+
131
152
  const COMPACT_ARG_VALUE_LIMIT = 60;
132
153
  const GENERIC_OUTPUT_PREVIEW_LINES = 10;
133
154
  const GENERIC_ARGS_JSON_PREVIEW_LINES = 10;
@@ -559,18 +580,13 @@ export class ToolExecutionComponent extends Container {
559
580
  const frameTone: ToolFrameTone =
560
581
  this.result?.isError ? "error" : this.isPartial || !this.result ? "pending" : "success";
561
582
  const elapsed = formatElapsed((this.endedAt ?? Date.now()) - this.startedAt);
562
- const frameStatus = `${this.isPartial || !this.result ? "Running" : this.result.isError ? "Error" : "Done"} · ${elapsed}`;
583
+ const frameStatus = `${this.isPartial || !this.result ? "running" : this.result.isError ? "failed" : "success"} · ${elapsed}`;
563
584
  const parsed = parseMcpToolName(this.toolName);
564
585
  const frameLabel = parsed
565
- ? `Tool ${parsed.server}·${parsed.tool}`
566
- : `Tool ${prettifyToolName(this.toolName, this.toolDefinition?.label) || "unknown"}`;
586
+ ? `${parsed.server}·${parsed.tool}`
587
+ : prettifyToolName(this.toolName, this.toolDefinition?.label) || "unknown";
567
588
  if (this.shouldRenderCompactSuccess()) {
568
- const availableWidth = Math.max(1, frameWidth - 2);
569
- const summaryWidth = Math.max(1, availableWidth - visibleWidth(frameStatus) - 1);
570
- const summary = truncateToWidth(this.getCompactSummary(frameLabel), summaryWidth, "");
571
- const gap = Math.max(1, availableWidth - visibleWidth(summary) - visibleWidth(frameStatus));
572
- const line = `${theme.fg("toolSuccess", summary)}${" ".repeat(gap)}${theme.fg("toolSuccess", frameStatus)}`;
573
- return ["", ...style().border("minimal").borderColor((text) => theme.fg("toolSuccess", text)).render([line], frameWidth)];
589
+ return ["", ...renderCollapsedToolRow(this.getCompactSummary(frameLabel), frameStatus, frameWidth, "success")];
574
590
  }
575
591
  const lines = super.render(contentWidth);
576
592
  const framed = renderToolFrame(lines, frameWidth, {
@@ -584,7 +600,7 @@ export class ToolExecutionComponent extends Container {
584
600
  private shouldRenderCompactSuccess(): boolean {
585
601
  if (this.expanded || this.isPartial || !this.result || this.result.isError) return false;
586
602
  const hasImages = this.result.content?.some((block) => block.type === "image") ?? false;
587
- return !hasImages && this.getTextOutput().trim().length === 0;
603
+ return !hasImages;
588
604
  }
589
605
 
590
606
  getRollupPhase(): ToolExecutionPhase | null {
@@ -615,7 +631,7 @@ export class ToolExecutionComponent extends Container {
615
631
  }
616
632
 
617
633
  private getCompactSummary(frameLabel: string): string {
618
- return `${frameLabel} Completed`;
634
+ return frameLabel;
619
635
  }
620
636
 
621
637
  private updateDisplay(): void {
@@ -1271,6 +1287,10 @@ export class ToolPhaseSummaryComponent extends Container {
1271
1287
  super();
1272
1288
  }
1273
1289
 
1290
+ getPhases(): ToolExecutionPhase[] {
1291
+ return this.phases.map((phase) => ({ ...phase }));
1292
+ }
1293
+
1274
1294
  override render(width: number): string[] {
1275
1295
  const frameWidth = Math.max(20, width);
1276
1296
  const rows = this.phases.map((phase) => {
@@ -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;
@@ -894,6 +909,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
894
909
  component.setExpanded(host.toolOutputExpanded);
895
910
  host.chatContainer.addChild(component);
896
911
  host.pendingTools.set(event.toolCallId, component);
912
+ renderedSegments.push({ kind: "tool", contentIndex: Number.MAX_SAFE_INTEGER, component });
897
913
  host.ui.requestRender();
898
914
  }
899
915
  break;
@@ -911,7 +927,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
911
927
  const component = host.pendingTools.get(event.toolCallId);
912
928
  if (component) {
913
929
  component.updateResult({ ...event.result, isError: event.isError });
914
- host.pendingTools.delete(event.toolCallId);
930
+ replaceCompactToolRowsWithPhaseSummary(host);
915
931
  host.ui.requestRender();
916
932
  }
917
933
  break;
@@ -927,6 +943,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
927
943
  host.streamingComponent.setShowMetadata(true);
928
944
  host.streamingComponent.updateContent(host.streamingMessage);
929
945
  }
946
+ replaceCompactToolRowsWithPhaseSummary(host);
930
947
  host.streamingComponent = undefined;
931
948
  host.streamingMessage = undefined;
932
949
  renderedSegments = [];
@@ -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
@@ -1,3 +1,4 @@
1
+ // GSD2 TUI - Built-in terminal theme definitions.
1
2
  /**
2
3
  * Built-in theme definitions.
3
4
  *
@@ -18,27 +19,30 @@ import type { ThemeJson } from "./theme-schema.js";
18
19
  const dark: ThemeJson = {
19
20
  name: "dark",
20
21
  vars: {
21
- cyan: "#22d3ee",
22
- blue: "#60a5fa",
23
- green: "#34d399",
24
- red: "#fb7185",
25
- yellow: "#facc15",
26
- gray: "#a1a1aa",
27
- dimGray: "#8b93a7",
28
- darkGray: "#4b5563",
29
- accent: "#2dd4bf",
30
- selectedBg: "#1f2a44",
31
- userMsgBg: "#1e2535",
32
- toolPendingBg: "#1f2330",
33
- toolSuccessBg: "#1f3128",
34
- toolErrorBg: "#3a202a",
35
- customMsgBg: "#2a2140",
22
+ cyan: "#5cc8c8",
23
+ blue: "#79b8ff",
24
+ green: "#7ad38b",
25
+ red: "#f27b7b",
26
+ yellow: "#d6b85f",
27
+ gray: "#87949b",
28
+ dimGray: "#657178",
29
+ darkGray: "#303a40",
30
+ line: "#52616a",
31
+ lineSoft: "#303a40",
32
+ textSoft: "#cbd6dc",
33
+ accent: "#5cc8c8",
34
+ selectedBg: "#1d282a",
35
+ userMsgBg: "#202a2f",
36
+ toolPendingBg: "#252721",
37
+ toolSuccessBg: "#1c251f",
38
+ toolErrorBg: "#251e20",
39
+ customMsgBg: "#202a2f",
36
40
  },
37
41
  colors: {
38
42
  accent: "accent",
39
- border: "blue",
40
- borderAccent: "cyan",
41
- borderMuted: "darkGray",
43
+ border: "line",
44
+ borderAccent: "accent",
45
+ borderMuted: "lineSoft",
42
46
  success: "green",
43
47
  error: "red",
44
48
  warning: "yellow",
@@ -49,16 +53,21 @@ const dark: ThemeJson = {
49
53
 
50
54
  selectedBg: "selectedBg",
51
55
  userMessageBg: "userMsgBg",
52
- userMessageText: "gray",
53
- assistantMessageText: "",
56
+ userMessageText: "textSoft",
57
+ assistantMessageText: "textSoft",
54
58
  customMessageBg: "customMsgBg",
55
- customMessageText: "",
56
- customMessageLabel: "#c084fc",
59
+ customMessageText: "textSoft",
60
+ customMessageLabel: "blue",
57
61
  toolPendingBg: "toolPendingBg",
58
62
  toolSuccessBg: "toolSuccessBg",
59
63
  toolErrorBg: "toolErrorBg",
60
- toolTitle: "#8a8a8a",
61
- toolOutput: "#6e6e6e",
64
+ toolTitle: "gray",
65
+ toolOutput: "textSoft",
66
+ surfaceTitle: "accent",
67
+ surfaceAccent: "accent",
68
+ toolRunning: "yellow",
69
+ toolSuccess: "green",
70
+ toolError: "red",
62
71
 
63
72
  mdHeading: "#fbbf24",
64
73
  mdLink: "#93c5fd",
@@ -95,9 +104,9 @@ const dark: ThemeJson = {
95
104
  bashMode: "green",
96
105
  },
97
106
  export: {
98
- pageBg: "#101522",
99
- cardBg: "#171f33",
100
- infoBg: "#3b321d",
107
+ pageBg: "#111416",
108
+ cardBg: "#1e2529",
109
+ infoBg: "#252721",
101
110
  },
102
111
  };
103
112
 
@@ -2,9 +2,14 @@
2
2
 
3
3
  import assert from "node:assert/strict";
4
4
  import { describe, test } from "node:test";
5
+ import stripAnsi from "strip-ansi";
5
6
 
7
+ import { AdaptiveLayoutComponent } from "./components/adaptive-layout.js";
8
+ import { initTheme } from "./theme/theme.js";
6
9
  import { resolveTuiMode } from "./tui-mode.js";
7
10
 
11
+ initTheme("dark", false);
12
+
8
13
  describe("resolveTuiMode", () => {
9
14
  test("explicit overrides beat auto selection", () => {
10
15
  assert.equal(
@@ -38,3 +43,23 @@ describe("resolveTuiMode", () => {
38
43
  assert.equal(resolveTuiMode({ terminalWidth: 100 }), "chat");
39
44
  });
40
45
  });
46
+
47
+ describe("AdaptiveLayoutComponent", () => {
48
+ test("renders workflow layout with prototype rule frames", () => {
49
+ const layout = new AdaptiveLayoutComponent(() => ({
50
+ override: "workflow",
51
+ activeToolCount: 2,
52
+ gsdPhase: "execute-task",
53
+ sessionName: "main",
54
+ cwd: "/Users/example/project",
55
+ }));
56
+
57
+ const plain = layout.render(120).map(stripAnsi);
58
+
59
+ assert.match(plain[0], /^─+/, "workflow layout should start with a rule frame");
60
+ assert.ok(plain.some((line) => line.includes("GSD Command Center")), "workflow title should render");
61
+ assert.ok(plain.some((line) => line.includes("signals")), "inspector title should render");
62
+ assert.ok(plain.some((line) => line.includes("│ Active")), "body rows should keep prototype gutter");
63
+ assert.ok(!plain.some((line) => /[╭╮╰╯]/.test(line)), "workflow layout should not use rounded box corners");
64
+ });
65
+ });
@@ -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 {