gsd-pi 2.82.0 → 3.0.0

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 (555) hide show
  1. package/README.md +51 -32
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/GSD-WORKFLOW.md +10 -1
  4. package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
  5. package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
  6. package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
  7. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +1 -1
  8. package/dist/resources/extensions/cmux/index.js +5 -0
  9. package/dist/resources/extensions/gsd/auto/infra-errors.js +9 -3
  10. package/dist/resources/extensions/gsd/auto/loop.js +19 -6
  11. package/dist/resources/extensions/gsd/auto/orchestrator.js +124 -6
  12. package/dist/resources/extensions/gsd/auto/phases.js +90 -31
  13. package/dist/resources/extensions/gsd/auto/session.js +4 -0
  14. package/dist/resources/extensions/gsd/auto/workflow-kernel.js +3 -0
  15. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +12 -0
  16. package/dist/resources/extensions/gsd/auto-dashboard.js +66 -1
  17. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +1 -0
  18. package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
  19. package/dist/resources/extensions/gsd/auto-model-selection.js +2 -0
  20. package/dist/resources/extensions/gsd/auto-post-unit.js +246 -133
  21. package/dist/resources/extensions/gsd/auto-prompts.js +13 -5
  22. package/dist/resources/extensions/gsd/auto-recovery.js +71 -14
  23. package/dist/resources/extensions/gsd/auto-start.js +87 -14
  24. package/dist/resources/extensions/gsd/auto-verification.js +45 -26
  25. package/dist/resources/extensions/gsd/auto-worktree.js +176 -10
  26. package/dist/resources/extensions/gsd/auto.js +178 -63
  27. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +31 -7
  28. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -9
  29. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +9 -2
  30. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +21 -9
  31. package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
  32. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +17 -3
  33. package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
  34. package/dist/resources/extensions/gsd/commands/catalog.js +10 -1
  35. package/dist/resources/extensions/gsd/commands/handlers/core.js +39 -1
  36. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  37. package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
  38. package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
  39. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +7 -2
  40. package/dist/resources/extensions/gsd/commands-verdict.js +139 -0
  41. package/dist/resources/extensions/gsd/context-store.js +112 -0
  42. package/dist/resources/extensions/gsd/crash-recovery.js +43 -5
  43. package/dist/resources/extensions/gsd/db/milestone-leases.js +24 -0
  44. package/dist/resources/extensions/gsd/db/unit-dispatches.js +3 -2
  45. package/dist/resources/extensions/gsd/db-writer.js +150 -84
  46. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -2
  47. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  48. package/dist/resources/extensions/gsd/doctor-git-checks.js +87 -7
  49. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +28 -11
  50. package/dist/resources/extensions/gsd/doctor.js +2 -28
  51. package/dist/resources/extensions/gsd/export-html.js +27 -425
  52. package/dist/resources/extensions/gsd/forensics.js +3 -3
  53. package/dist/resources/extensions/gsd/git-service.js +45 -3
  54. package/dist/resources/extensions/gsd/gsd-db.js +21 -6
  55. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -3
  56. package/dist/resources/extensions/gsd/guided-flow.js +101 -116
  57. package/dist/resources/extensions/gsd/guided-unit-context.js +23 -0
  58. package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
  59. package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
  60. package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
  61. package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
  62. package/dist/resources/extensions/gsd/markdown-renderer.js +16 -9
  63. package/dist/resources/extensions/gsd/md-importer.js +1 -1
  64. package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
  65. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
  66. package/dist/resources/extensions/gsd/migrate/command.js +5 -0
  67. package/dist/resources/extensions/gsd/migrate/parsers.js +10 -0
  68. package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
  69. package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
  70. package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
  71. package/dist/resources/extensions/gsd/migration-auto-check.js +12 -17
  72. package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
  73. package/dist/resources/extensions/gsd/native-git-bridge.js +48 -12
  74. package/dist/resources/extensions/gsd/paths.js +4 -0
  75. package/dist/resources/extensions/gsd/pending-auto-start.js +52 -0
  76. package/dist/resources/extensions/gsd/post-execution-checks.js +73 -2
  77. package/dist/resources/extensions/gsd/pre-execution-checks.js +28 -1
  78. package/dist/resources/extensions/gsd/prompt-loader.js +1 -1
  79. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  80. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  81. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  82. package/dist/resources/extensions/gsd/prompts/discuss.md +9 -9
  83. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  84. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  85. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  86. package/dist/resources/extensions/gsd/prompts/queue.md +4 -4
  87. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  88. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  89. package/dist/resources/extensions/gsd/prompts/system.md +2 -2
  90. package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
  91. package/dist/resources/extensions/gsd/queue-reorder-ui.js +30 -13
  92. package/dist/resources/extensions/gsd/smart-entry-routing.js +36 -0
  93. package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
  94. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +9 -14
  95. package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +19 -24
  96. package/dist/resources/extensions/gsd/state.js +3 -3
  97. package/dist/resources/extensions/gsd/status-guards.js +11 -0
  98. package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
  99. package/dist/resources/extensions/gsd/templates/plan.md +9 -5
  100. package/dist/resources/extensions/gsd/templates/task-plan.md +10 -2
  101. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -8
  102. package/dist/resources/extensions/gsd/tools/complete-slice.js +6 -8
  103. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -1
  104. package/dist/resources/extensions/gsd/tools/plan-slice.js +87 -14
  105. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
  106. package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
  107. package/dist/resources/extensions/gsd/validation.js +23 -1
  108. package/dist/resources/extensions/gsd/verification-gate.js +68 -7
  109. package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
  110. package/dist/resources/extensions/gsd/workflow-mcp.js +17 -1
  111. package/dist/resources/extensions/gsd/workflow-projections.js +6 -8
  112. package/dist/resources/extensions/gsd/worktree-lifecycle.js +54 -10
  113. package/dist/resources/extensions/gsd/worktree-manager.js +1 -1
  114. package/dist/resources/extensions/shared/html-shell.js +388 -0
  115. package/dist/resources/extensions/subagent/index.js +448 -78
  116. package/dist/resources/extensions/subagent/launch.js +77 -0
  117. package/dist/resources/extensions/subagent/run-store.js +148 -0
  118. package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
  119. package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
  120. package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
  121. package/dist/resources/extensions/visual-brief/index.js +5 -0
  122. package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
  123. package/dist/resources/extensions/visual-brief/prompts.js +140 -0
  124. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  125. package/dist/web/standalone/.next/BUILD_ID +1 -1
  126. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  127. package/dist/web/standalone/.next/build-manifest.json +3 -3
  128. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  129. package/dist/web/standalone/.next/react-loadable-manifest.json +5 -5
  130. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  132. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  140. package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  143. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
  144. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
  145. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  146. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -5
  147. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  148. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  149. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -5
  150. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/index.html +1 -1
  153. package/dist/web/standalone/.next/server/app/index.rsc +4 -7
  154. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  155. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -7
  156. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  157. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -5
  158. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
  159. package/dist/web/standalone/.next/server/app/page.js +2 -2
  160. package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  163. package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
  164. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  168. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  169. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  170. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  171. package/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
  172. package/dist/web/standalone/.next/static/chunks/8359.65b24fac92188a6b.js +10 -0
  173. package/dist/web/standalone/.next/static/chunks/9441.ff70bb53f6835771.js +1 -0
  174. package/dist/web/standalone/.next/static/chunks/app/layout-b23b3f6858dc6dc8.js +1 -0
  175. package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-855d616060cb6e59.js} +1 -1
  176. package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
  177. package/package.json +6 -5
  178. package/packages/contracts/dist/rpc.test.js +7 -0
  179. package/packages/contracts/dist/rpc.test.js.map +1 -1
  180. package/packages/contracts/dist/workflow.d.ts +21 -0
  181. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  182. package/packages/contracts/dist/workflow.js +24 -0
  183. package/packages/contracts/dist/workflow.js.map +1 -1
  184. package/packages/contracts/src/rpc.test.ts +8 -0
  185. package/packages/contracts/src/workflow.ts +24 -0
  186. package/packages/daemon/package.json +2 -2
  187. package/packages/mcp-server/README.md +14 -3
  188. package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
  189. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  190. package/packages/mcp-server/dist/workflow-tools.js +80 -0
  191. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  192. package/packages/mcp-server/package.json +2 -2
  193. package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
  194. package/packages/mcp-server/src/workflow-tools.test.ts +23 -1
  195. package/packages/mcp-server/src/workflow-tools.ts +168 -0
  196. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  197. package/packages/native/package.json +1 -1
  198. package/packages/native/tsconfig.json +2 -1
  199. package/packages/native/tsconfig.tsbuildinfo +1 -1
  200. package/packages/pi-agent-core/package.json +1 -1
  201. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  202. package/packages/pi-ai/dist/index.d.ts +2 -2
  203. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  204. package/packages/pi-ai/dist/index.js +1 -1
  205. package/packages/pi-ai/dist/index.js.map +1 -1
  206. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  207. package/packages/pi-ai/dist/providers/google-gemini-cli.js +5 -0
  208. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  209. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts +2 -0
  210. package/packages/pi-ai/dist/providers/google-gemini-cli.test.d.ts.map +1 -0
  211. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js +41 -0
  212. package/packages/pi-ai/dist/providers/google-gemini-cli.test.js.map +1 -0
  213. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  214. package/packages/pi-ai/dist/providers/openai-codex-responses.js +82 -1
  215. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  216. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts +2 -0
  217. package/packages/pi-ai/dist/providers/openai-codex-responses.test.d.ts.map +1 -0
  218. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js +52 -0
  219. package/packages/pi-ai/dist/providers/openai-codex-responses.test.js.map +1 -0
  220. package/packages/pi-ai/dist/providers/simple-options.d.ts +2 -4
  221. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  222. package/packages/pi-ai/dist/providers/simple-options.js +5 -6
  223. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  224. package/packages/pi-ai/dist/providers/simple-options.test.d.ts +2 -0
  225. package/packages/pi-ai/dist/providers/simple-options.test.d.ts.map +1 -0
  226. package/packages/pi-ai/dist/providers/simple-options.test.js +50 -0
  227. package/packages/pi-ai/dist/providers/simple-options.test.js.map +1 -0
  228. package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
  229. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  230. package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
  231. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  232. package/packages/pi-ai/package.json +1 -1
  233. package/packages/pi-ai/src/index.ts +7 -2
  234. package/packages/pi-ai/src/providers/google-gemini-cli.test.ts +49 -0
  235. package/packages/pi-ai/src/providers/google-gemini-cli.ts +7 -0
  236. package/packages/pi-ai/src/providers/openai-codex-responses.test.ts +63 -0
  237. package/packages/pi-ai/src/providers/openai-codex-responses.ts +91 -1
  238. package/packages/pi-ai/src/providers/simple-options.test.ts +60 -0
  239. package/packages/pi-ai/src/providers/simple-options.ts +5 -6
  240. package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
  241. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  242. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts +2 -0
  243. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.d.ts.map +1 -0
  244. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js +66 -0
  245. package/packages/pi-coding-agent/dist/core/agent-session-thinking-level.test.js.map +1 -0
  246. package/packages/pi-coding-agent/dist/core/agent-session.js +1 -1
  247. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  248. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +44 -3
  249. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  250. package/packages/pi-coding-agent/dist/core/sdk.js +1 -1
  251. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  252. package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
  253. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  255. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +24 -6
  256. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  257. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  258. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +71 -97
  259. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  260. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js +25 -1
  261. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-ordering.test.js.map +1 -1
  262. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  263. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  264. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +24 -10
  265. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  266. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
  267. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
  268. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
  269. package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
  270. package/packages/pi-coding-agent/package.json +1 -1
  271. package/packages/pi-coding-agent/src/core/agent-session-thinking-level.test.ts +79 -0
  272. package/packages/pi-coding-agent/src/core/agent-session.ts +1 -1
  273. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +53 -3
  274. package/packages/pi-coding-agent/src/core/sdk.ts +1 -1
  275. package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
  276. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +23 -7
  277. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -102
  278. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-ordering.test.ts +30 -1
  279. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +29 -10
  280. package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
  281. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  282. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts +2 -0
  283. package/packages/pi-tui/dist/__tests__/terminal.test.d.ts.map +1 -0
  284. package/packages/pi-tui/dist/__tests__/terminal.test.js +103 -0
  285. package/packages/pi-tui/dist/__tests__/terminal.test.js.map +1 -0
  286. package/packages/pi-tui/dist/terminal.d.ts +2 -0
  287. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  288. package/packages/pi-tui/dist/terminal.js +12 -0
  289. package/packages/pi-tui/dist/terminal.js.map +1 -1
  290. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  291. package/packages/pi-tui/dist/tui.js +5 -0
  292. package/packages/pi-tui/dist/tui.js.map +1 -1
  293. package/packages/pi-tui/package.json +1 -1
  294. package/packages/pi-tui/src/__tests__/terminal.test.ts +121 -0
  295. package/packages/pi-tui/src/terminal.ts +11 -0
  296. package/packages/pi-tui/src/tui.ts +6 -0
  297. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  298. package/packages/rpc-client/package.json +1 -1
  299. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  300. package/pkg/package.json +1 -1
  301. package/src/resources/GSD-WORKFLOW.md +10 -1
  302. package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
  303. package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
  304. package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
  305. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +1 -1
  306. package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
  307. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +9 -0
  308. package/src/resources/extensions/cmux/index.ts +6 -0
  309. package/src/resources/extensions/gsd/auto/contracts.ts +59 -16
  310. package/src/resources/extensions/gsd/auto/infra-errors.ts +9 -3
  311. package/src/resources/extensions/gsd/auto/loop.ts +22 -6
  312. package/src/resources/extensions/gsd/auto/orchestrator.ts +129 -6
  313. package/src/resources/extensions/gsd/auto/phases.ts +104 -38
  314. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  315. package/src/resources/extensions/gsd/auto/workflow-kernel.ts +5 -1
  316. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +13 -0
  317. package/src/resources/extensions/gsd/auto-dashboard.ts +72 -1
  318. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +1 -0
  319. package/src/resources/extensions/gsd/auto-dispatch.ts +21 -19
  320. package/src/resources/extensions/gsd/auto-model-selection.ts +2 -1
  321. package/src/resources/extensions/gsd/auto-post-unit.ts +279 -144
  322. package/src/resources/extensions/gsd/auto-prompts.ts +13 -5
  323. package/src/resources/extensions/gsd/auto-recovery.ts +74 -11
  324. package/src/resources/extensions/gsd/auto-start.ts +94 -12
  325. package/src/resources/extensions/gsd/auto-verification.ts +58 -36
  326. package/src/resources/extensions/gsd/auto-worktree.ts +193 -10
  327. package/src/resources/extensions/gsd/auto.ts +187 -61
  328. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +42 -7
  329. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -9
  330. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +10 -2
  331. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +19 -7
  332. package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
  333. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +20 -4
  334. package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
  335. package/src/resources/extensions/gsd/commands/catalog.ts +10 -1
  336. package/src/resources/extensions/gsd/commands/handlers/core.ts +42 -1
  337. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  338. package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
  339. package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
  340. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +8 -3
  341. package/src/resources/extensions/gsd/commands-verdict.ts +202 -0
  342. package/src/resources/extensions/gsd/context-store.ts +120 -1
  343. package/src/resources/extensions/gsd/crash-recovery.ts +44 -4
  344. package/src/resources/extensions/gsd/db/milestone-leases.ts +26 -0
  345. package/src/resources/extensions/gsd/db/unit-dispatches.ts +4 -3
  346. package/src/resources/extensions/gsd/db-writer.ts +167 -84
  347. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -2
  348. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
  349. package/src/resources/extensions/gsd/doctor-git-checks.ts +89 -7
  350. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +25 -13
  351. package/src/resources/extensions/gsd/doctor-types.ts +3 -0
  352. package/src/resources/extensions/gsd/doctor.ts +2 -27
  353. package/src/resources/extensions/gsd/export-html.ts +27 -427
  354. package/src/resources/extensions/gsd/forensics.ts +3 -3
  355. package/src/resources/extensions/gsd/git-service.ts +51 -4
  356. package/src/resources/extensions/gsd/gsd-db.ts +21 -6
  357. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -3
  358. package/src/resources/extensions/gsd/guided-flow.ts +134 -133
  359. package/src/resources/extensions/gsd/guided-unit-context.ts +30 -0
  360. package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
  361. package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
  362. package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
  363. package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
  364. package/src/resources/extensions/gsd/markdown-renderer.ts +16 -9
  365. package/src/resources/extensions/gsd/md-importer.ts +1 -1
  366. package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
  367. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
  368. package/src/resources/extensions/gsd/migrate/command.ts +5 -0
  369. package/src/resources/extensions/gsd/migrate/parsers.ts +11 -0
  370. package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
  371. package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
  372. package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
  373. package/src/resources/extensions/gsd/migration-auto-check.ts +15 -23
  374. package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
  375. package/src/resources/extensions/gsd/native-git-bridge.ts +54 -12
  376. package/src/resources/extensions/gsd/paths.ts +5 -0
  377. package/src/resources/extensions/gsd/pending-auto-start.ts +79 -0
  378. package/src/resources/extensions/gsd/post-execution-checks.ts +87 -2
  379. package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -1
  380. package/src/resources/extensions/gsd/prompt-loader.ts +1 -1
  381. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  382. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  383. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -8
  384. package/src/resources/extensions/gsd/prompts/discuss.md +9 -9
  385. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +4 -4
  386. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +3 -3
  387. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -4
  388. package/src/resources/extensions/gsd/prompts/queue.md +4 -4
  389. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  390. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  391. package/src/resources/extensions/gsd/prompts/system.md +2 -2
  392. package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
  393. package/src/resources/extensions/gsd/queue-reorder-ui.ts +31 -13
  394. package/src/resources/extensions/gsd/smart-entry-routing.ts +77 -0
  395. package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
  396. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +12 -15
  397. package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +17 -25
  398. package/src/resources/extensions/gsd/state.ts +3 -3
  399. package/src/resources/extensions/gsd/status-guards.ts +13 -0
  400. package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
  401. package/src/resources/extensions/gsd/templates/plan.md +9 -5
  402. package/src/resources/extensions/gsd/templates/task-plan.md +10 -2
  403. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +71 -0
  404. package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
  405. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +131 -0
  406. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +487 -4
  407. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +151 -12
  408. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +53 -2
  409. package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +18 -6
  410. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +91 -6
  411. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
  412. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +1 -0
  413. package/src/resources/extensions/gsd/tests/auto-stop-notification.test.ts +20 -0
  414. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
  415. package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
  416. package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
  417. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +87 -0
  418. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
  419. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +11 -2
  420. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
  421. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +378 -0
  422. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +4 -1
  423. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +5 -9
  424. package/src/resources/extensions/gsd/tests/complete-task.test.ts +3 -1
  425. package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
  426. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +86 -2
  427. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  428. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +208 -0
  429. package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
  430. package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
  431. package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
  432. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +59 -2
  433. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +66 -0
  434. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +27 -0
  435. package/src/resources/extensions/gsd/tests/doctor-empty-worktree.test.ts +65 -0
  436. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
  437. package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
  438. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
  439. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +11 -0
  440. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
  441. package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +5 -2
  442. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +2 -0
  443. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +106 -0
  444. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +59 -11
  445. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +21 -0
  446. package/src/resources/extensions/gsd/tests/guided-tool-contract.test.ts +65 -0
  447. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +7 -7
  448. package/src/resources/extensions/gsd/tests/hook-model-resolution.test.ts +5 -0
  449. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -2
  450. package/src/resources/extensions/gsd/tests/infra-errors-cooldown.test.ts +9 -0
  451. package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
  452. package/src/resources/extensions/gsd/tests/integration/doctor-runtime.test.ts +20 -0
  453. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +112 -1
  454. package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
  455. package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
  456. package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +6 -1
  457. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +46 -0
  458. package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
  459. package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
  460. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
  461. package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
  462. package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
  463. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +179 -0
  464. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
  465. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +24 -1
  466. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
  467. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +26 -18
  468. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +63 -2
  469. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +121 -1
  470. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
  471. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +29 -5
  472. package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +2 -1
  473. package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
  474. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +26 -0
  475. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  476. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +251 -2
  477. package/src/resources/extensions/gsd/tests/plan-task.test.ts +17 -0
  478. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
  479. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +86 -0
  480. package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
  481. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +84 -0
  482. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +53 -0
  483. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +59 -0
  484. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -0
  485. package/src/resources/extensions/gsd/tests/prompt-loader.test.ts +23 -0
  486. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +37 -1
  487. package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
  488. package/src/resources/extensions/gsd/tests/quality-gates.test.ts +6 -0
  489. package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +54 -0
  490. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +89 -2
  491. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +2 -3
  492. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
  493. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
  494. package/src/resources/extensions/gsd/tests/smart-entry-routing.test.ts +113 -0
  495. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +53 -2
  496. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
  497. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +119 -23
  498. package/src/resources/extensions/gsd/tests/status-guards.test.ts +13 -1
  499. package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +64 -1
  500. package/src/resources/extensions/gsd/tests/summary-render-parity.test.ts +7 -3
  501. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +103 -7
  502. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +29 -2
  503. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +110 -1
  504. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
  505. package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
  506. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +19 -1
  507. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +21 -1
  508. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +1 -1
  509. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +39 -0
  510. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
  511. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
  512. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +54 -0
  513. package/src/resources/extensions/gsd/tools/complete-milestone.ts +8 -10
  514. package/src/resources/extensions/gsd/tools/complete-slice.ts +6 -8
  515. package/src/resources/extensions/gsd/tools/plan-milestone.ts +5 -1
  516. package/src/resources/extensions/gsd/tools/plan-slice.ts +97 -12
  517. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
  518. package/src/resources/extensions/gsd/types.ts +1 -1
  519. package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
  520. package/src/resources/extensions/gsd/validation.ts +23 -1
  521. package/src/resources/extensions/gsd/verification-gate.ts +78 -6
  522. package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
  523. package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
  524. package/src/resources/extensions/gsd/workflow-mcp.ts +18 -1
  525. package/src/resources/extensions/gsd/workflow-projections.ts +6 -8
  526. package/src/resources/extensions/gsd/worktree-lifecycle.ts +61 -10
  527. package/src/resources/extensions/gsd/worktree-manager.ts +1 -1
  528. package/src/resources/extensions/shared/html-shell.ts +412 -0
  529. package/src/resources/extensions/subagent/index.ts +567 -103
  530. package/src/resources/extensions/subagent/launch.ts +131 -0
  531. package/src/resources/extensions/subagent/run-store.ts +218 -0
  532. package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
  533. package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
  534. package/src/resources/extensions/ttsr/ttsr-manager.ts +5 -1
  535. package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
  536. package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
  537. package/src/resources/extensions/visual-brief/index.ts +8 -0
  538. package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
  539. package/src/resources/extensions/visual-brief/prompts.ts +183 -0
  540. package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
  541. package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
  542. package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
  543. package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +0 -10
  544. package/dist/web/standalone/.next/static/chunks/9441.1081da1125d1764f.js +0 -1
  545. package/dist/web/standalone/.next/static/chunks/app/layout-9ecfd95f343793f0.js +0 -1
  546. package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
  547. package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
  548. package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  549. package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  550. package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  551. package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  552. package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  553. package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  554. /package/dist/web/standalone/.next/static/{S44UQTFCUdA44dkjfYt6S → qoMxZh-xuwuvpFW0x0k01}/_buildManifest.js +0 -0
  555. /package/dist/web/standalone/.next/static/{S44UQTFCUdA44dkjfYt6S → qoMxZh-xuwuvpFW0x0k01}/_ssgManifest.js +0 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=system-prompt-file-safety.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-prompt-file-safety.test.d.ts","sourceRoot":"","sources":["../../src/tests/system-prompt-file-safety.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ // GSD-2 pi-coding-agent system prompt file-safety regression tests.
2
+ import test from "node:test";
3
+ import assert from "node:assert/strict";
4
+ import { buildSystemPrompt } from "../core/system-prompt.js";
5
+ test("buildSystemPrompt: read and write tools require reading before overwrite", () => {
6
+ const prompt = buildSystemPrompt({ selectedTools: ["read", "write"] });
7
+ assert.match(prompt, /before editing or overwriting/i);
8
+ assert.match(prompt, /Before write creates or replaces a file, verify the target path/i);
9
+ assert.match(prompt, /if it exists, read it first/i);
10
+ assert.match(prompt, /Use write only for new files or complete rewrites after verifying the target path/i);
11
+ });
12
+ test("buildSystemPrompt: write-only tool guidance does not reference unavailable read tool", () => {
13
+ const prompt = buildSystemPrompt({ selectedTools: ["write"] });
14
+ assert.doesNotMatch(prompt, /read it first/i);
15
+ assert.match(prompt, /Use write only for new files or complete rewrites after verifying the target path/i);
16
+ });
17
+ //# sourceMappingURL=system-prompt-file-safety.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-prompt-file-safety.test.js","sourceRoot":"","sources":["../../src/tests/system-prompt-file-safety.test.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAEpE,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AAExC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,IAAI,CAAC,0EAA0E,EAAE,GAAG,EAAE;IACrF,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IAEvE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,gCAAgC,CAAC,CAAC;IACvD,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,kEAAkE,CAAC,CAAC;IACzF,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,8BAA8B,CAAC,CAAC;IACrD,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,oFAAoF,CAAC,CAAC;AAC5G,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sFAAsF,EAAE,GAAG,EAAE;IACjG,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,aAAa,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAE/D,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,oFAAoF,CAAC,CAAC;AAC5G,CAAC,CAAC,CAAC","sourcesContent":["// GSD-2 pi-coding-agent system prompt file-safety regression tests.\n\nimport test from \"node:test\";\nimport assert from \"node:assert/strict\";\n\nimport { buildSystemPrompt } from \"../core/system-prompt.js\";\n\ntest(\"buildSystemPrompt: read and write tools require reading before overwrite\", () => {\n\tconst prompt = buildSystemPrompt({ selectedTools: [\"read\", \"write\"] });\n\n\tassert.match(prompt, /before editing or overwriting/i);\n\tassert.match(prompt, /Before write creates or replaces a file, verify the target path/i);\n\tassert.match(prompt, /if it exists, read it first/i);\n\tassert.match(prompt, /Use write only for new files or complete rewrites after verifying the target path/i);\n});\n\ntest(\"buildSystemPrompt: write-only tool guidance does not reference unavailable read tool\", () => {\n\tconst prompt = buildSystemPrompt({ selectedTools: [\"write\"] });\n\n\tassert.doesNotMatch(prompt, /read it first/i);\n\tassert.match(prompt, /Use write only for new files or complete rewrites after verifying the target path/i);\n});\n"]}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsd/pi-coding-agent",
3
- "version": "2.82.0",
3
+ "version": "3.0.0",
4
4
  "description": "Coding agent CLI (vendored from pi-mono)",
5
5
  "type": "module",
6
6
  "gsd": {
@@ -0,0 +1,79 @@
1
+ // Regression test for #5102: disabling thinking on one reasoning-capable
2
+ // model must not silently persist "off" as the global default.
3
+
4
+ import assert from "node:assert/strict";
5
+ import { mkdtempSync, rmSync } from "node:fs";
6
+ import { tmpdir } from "node:os";
7
+ import { join } from "node:path";
8
+ import { afterEach, beforeEach, describe, it } from "node:test";
9
+
10
+ import { Agent } from "@gsd/pi-agent-core";
11
+ import { getModel } from "@gsd/pi-ai";
12
+ import { AgentSession } from "./agent-session.js";
13
+ import { AuthStorage } from "./auth-storage.js";
14
+ import { ModelRegistry } from "./model-registry.js";
15
+ import { DefaultResourceLoader } from "./resource-loader.js";
16
+ import { SessionManager } from "./session-manager.js";
17
+ import { SettingsManager } from "./settings-manager.js";
18
+
19
+ let testDir: string;
20
+
21
+ async function createSession(): Promise<{ session: AgentSession; settingsManager: SettingsManager }> {
22
+ const agentDir = join(testDir, "agent-home");
23
+ const authStorage = AuthStorage.inMemory({});
24
+ const modelRegistry = new ModelRegistry(authStorage, join(agentDir, "models.json"));
25
+ const settingsManager = SettingsManager.inMemory({ defaultThinkingLevel: "high" });
26
+ const resourceLoader = new DefaultResourceLoader({
27
+ cwd: testDir,
28
+ agentDir,
29
+ settingsManager,
30
+ noExtensions: true,
31
+ noPromptTemplates: true,
32
+ noThemes: true,
33
+ });
34
+ await resourceLoader.reload();
35
+
36
+ const session = new AgentSession({
37
+ agent: new Agent({
38
+ initialState: {
39
+ model: getModel("zai", "glm-5.1" as any),
40
+ thinkingLevel: "high",
41
+ },
42
+ }),
43
+ sessionManager: SessionManager.inMemory(testDir),
44
+ settingsManager,
45
+ cwd: testDir,
46
+ resourceLoader,
47
+ modelRegistry,
48
+ });
49
+
50
+ return { session, settingsManager };
51
+ }
52
+
53
+ describe("AgentSession thinking level persistence", () => {
54
+ beforeEach(() => {
55
+ testDir = mkdtempSync(join(tmpdir(), "agent-session-thinking-level-"));
56
+ });
57
+
58
+ afterEach(() => {
59
+ rmSync(testDir, { recursive: true, force: true });
60
+ });
61
+
62
+ it("does not persist off as the global default for reasoning-capable models", async () => {
63
+ const { session, settingsManager } = await createSession();
64
+
65
+ session.setThinkingLevel("off");
66
+
67
+ assert.equal(session.thinkingLevel, "off");
68
+ assert.equal(settingsManager.getDefaultThinkingLevel(), "high");
69
+ });
70
+
71
+ it("still persists non-off thinking levels as the global default", async () => {
72
+ const { session, settingsManager } = await createSession();
73
+
74
+ session.setThinkingLevel("low");
75
+
76
+ assert.equal(session.thinkingLevel, "low");
77
+ assert.equal(settingsManager.getDefaultThinkingLevel(), "low");
78
+ });
79
+ });
@@ -1945,7 +1945,7 @@ export class AgentSession {
1945
1945
 
1946
1946
  if (isChanging) {
1947
1947
  this.sessionManager.appendThinkingLevelChange(effectiveLevel);
1948
- if (this.supportsThinking() || effectiveLevel !== "off") {
1948
+ if (effectiveLevel !== "off") {
1949
1949
  this.settingsManager.setDefaultThinkingLevel(effectiveLevel);
1950
1950
  }
1951
1951
  this._emitSessionStateChanged("set_thinking_level");
@@ -1,3 +1,5 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Regression tests for streamed interactive chat ordering.
1
3
  import assert from "node:assert/strict";
2
4
  import { test } from "node:test";
3
5
 
@@ -97,9 +99,7 @@ function createHost() {
97
99
  return host;
98
100
  }
99
101
 
100
- test("chat-controller renders content blocks in content[] index order (tool-first stream)", async () => {
101
- // ToolExecutionComponent uses the global theme singleton.
102
- // Install a minimal no-op theme implementation for this unit test.
102
+ function installTheme() {
103
103
  (globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
104
104
  fg: (_key: string, text: string) => text,
105
105
  bg: (_key: string, text: string) => text,
@@ -107,6 +107,12 @@ test("chat-controller renders content blocks in content[] index order (tool-firs
107
107
  italic: (text: string) => text,
108
108
  truncate: (text: string) => text,
109
109
  };
110
+ }
111
+
112
+ test("chat-controller renders content blocks in content[] index order (tool-first stream)", async () => {
113
+ // ToolExecutionComponent uses the global theme singleton.
114
+ // Install a minimal no-op theme implementation for this unit test.
115
+ installTheme();
110
116
 
111
117
  const host = createHost();
112
118
  const toolId = "mcp-tool-1";
@@ -168,6 +174,50 @@ test("chat-controller renders content blocks in content[] index order (tool-firs
168
174
  assert.equal(host.chatContainer.children[1]?.constructor?.name, "AssistantMessageComponent");
169
175
  });
170
176
 
177
+ test("chat-controller skips empty GPT reasoning blocks before tool-only turns", async () => {
178
+ installTheme();
179
+
180
+ const host = createHost();
181
+ host.getMarkdownThemeWithSettings = () => ({});
182
+ const toolId = "gpt-tool-1";
183
+ const toolCall = {
184
+ type: "toolCall",
185
+ id: toolId,
186
+ name: "read",
187
+ arguments: { filePath: "todo.js" },
188
+ };
189
+ const content = [
190
+ { type: "thinking", thinking: "", thinkingSignature: "encrypted" },
191
+ toolCall,
192
+ ];
193
+
194
+ await handleAgentEvent(host, { type: "message_start", message: makeAssistant([]) } as any);
195
+
196
+ await handleAgentEvent(
197
+ host,
198
+ {
199
+ type: "message_update",
200
+ message: makeAssistant(content),
201
+ assistantMessageEvent: {
202
+ type: "toolcall_end",
203
+ contentIndex: 1,
204
+ toolCall: {
205
+ ...toolCall,
206
+ externalResult: {
207
+ content: [{ type: "text", text: "todo contents" }],
208
+ details: {},
209
+ isError: false,
210
+ },
211
+ },
212
+ partial: makeAssistant(content),
213
+ },
214
+ } as any,
215
+ );
216
+
217
+ assert.equal(host.chatContainer.children.length, 1, "empty reasoning should not create a blank assistant block");
218
+ assert.equal(host.chatContainer.children[0]?.constructor?.name, "ToolExecutionComponent");
219
+ });
220
+
171
221
  test("chat-controller renders serverToolUse before trailing text matching content[] index order", async () => {
172
222
  (globalThis as any)[Symbol.for("@gsd/pi-coding-agent:theme")] = {
173
223
  fg: (_key: string, text: string) => text,
@@ -573,7 +573,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
573
573
  const removed = modelRegistry.authStorage.removeLegacyOAuthCredential(resolvedProvider);
574
574
  if (removed) {
575
575
  console.warn(
576
- `[auth] Removed unsupported Anthropic OAuth credential from auth.json (#3952).`,
576
+ `[auth] Removed unsupported Anthropic OAuth credential from auth.json.`,
577
577
  );
578
578
  }
579
579
  if (isClaudeCodeBinaryInPath()) {
@@ -203,9 +203,9 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
203
203
  addGuideline("Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)");
204
204
  }
205
205
 
206
- // Read before edit guideline
207
- if (hasRead && hasEdit) {
208
- addGuideline("Use read to examine files before editing. You must use this tool instead of cat or sed.");
206
+ // Read before file mutation guideline
207
+ if (hasRead && (hasEdit || hasWrite)) {
208
+ addGuideline("Use read to examine relevant existing files before editing or overwriting. Before write creates or replaces a file, verify the target path; if it exists, read it first. Use read instead of cat or sed for file inspection.");
209
209
  }
210
210
 
211
211
  // Edit guideline
@@ -215,7 +215,7 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
215
215
 
216
216
  // Write guideline
217
217
  if (hasWrite) {
218
- addGuideline("Use write only for new files or complete rewrites");
218
+ addGuideline("Use write only for new files or complete rewrites after verifying the target path");
219
219
  }
220
220
 
221
221
  // LSP guideline
@@ -20,6 +20,17 @@ function sanitizeStatusText(text: string): string {
20
20
  .trim();
21
21
  }
22
22
 
23
+ function truncateFooterPath(text: string, width: number): string {
24
+ if (visibleWidth(text) <= width) return text;
25
+ const tailMatch = text.match(/( \([^)]+\)(?: • .*)?)$/);
26
+ if (!tailMatch) return truncateToWidth(text, width, "...");
27
+ const tail = tailMatch[1];
28
+ const tailWidth = visibleWidth(tail);
29
+ if (tailWidth >= width - 4) return truncateToWidth(text, width, "...");
30
+ const head = text.slice(0, -tail.length);
31
+ return `${truncateToWidth(head, width - tailWidth, "...")}${tail}`;
32
+ }
33
+
23
34
  /**
24
35
  * Format token counts (similar to web-ui)
25
36
  */
@@ -222,10 +233,6 @@ export class FooterComponent implements Component {
222
233
  }
223
234
  }
224
235
 
225
- // Apply dim to the stats group before handing it to the shared footer strip.
226
- // statsLeft may contain color codes for context %, so keep coloring local to the group.
227
- const dimStatsLeft = theme.fg("dim", statsLeft);
228
-
229
236
  // Extension statuses right-aligned on the pwd line (sorted by key).
230
237
  // Keeps the footer compact by avoiding a dedicated row when the content
231
238
  // fits alongside pwd. Falls back to pwd-only if the combined line would
@@ -239,12 +246,21 @@ export class FooterComponent implements Component {
239
246
  .join(" ")
240
247
  : "";
241
248
 
249
+ const footerRight = [rightSide, extStatusText].filter(Boolean).join(" ");
250
+ const gsdSegment = theme.fg("accent", "● GSD");
251
+ const dimStatsLeft = theme.fg("dim", statsLeft);
252
+ const innerWidth = Math.max(1, width - 2);
253
+ const rightWidth = visibleWidth(footerRight);
254
+ const leftBudget = footerRight ? Math.max(1, innerWidth - rightWidth - 3) : innerWidth;
255
+ const sepWidth = visibleWidth(" │ ");
256
+ const pwdBudget = Math.max(1, leftBudget - visibleWidth(gsdSegment) - visibleWidth(dimStatsLeft) - sepWidth * 2);
257
+ const pwdSegment = theme.fg("dim", truncateFooterPath(pwd, pwdBudget));
258
+
242
259
  const leftSegments = [
243
- theme.fg("accent", "● GSD"),
244
- theme.fg("dim", pwd),
260
+ gsdSegment,
261
+ pwdSegment,
245
262
  dimStatsLeft,
246
263
  ];
247
- const footerRight = [rightSide, extStatusText].filter(Boolean).join(" ");
248
264
  return renderFooterStrip(leftSegments, footerRight, width);
249
265
  }
250
266
  }
@@ -1,4 +1,5 @@
1
- // GSD-2 Interactive Chat Controller
1
+ // Project/App: GSD-2
2
+ // File Purpose: Interactive TUI chat stream controller.
2
3
  import { Loader, Markdown, Spacer, Text } from "@gsd/pi-tui";
3
4
 
4
5
  import type { InteractiveModeEvent, InteractiveModeStateHost } from "../interactive-mode-state.js";
@@ -31,18 +32,77 @@ type RenderedSegment =
31
32
  | { kind: "tool"; contentIndex: number; component: ToolExecutionComponent }
32
33
  | { kind: "tool-summary"; component: ToolPhaseSummaryComponent; phases: ToolExecutionPhase[] };
33
34
 
35
+ type DesiredSegment =
36
+ | { kind: "text-run"; startIndex: number; endIndex: number; contentType: "text" | "thinking" }
37
+ | { kind: "tool"; contentIndex: number; toolId: string };
38
+
34
39
  let renderedSegments: RenderedSegment[] = [];
35
40
  // When providers reuse one assistant lifecycle across internal sub-turns,
36
41
  // a content[] shrink resets renderedSegments. Keep the displaced segments so
37
42
  // claude-code MCP pruning can remove stale provisional text later.
38
43
  let orphanedSegments: RenderedSegment[] = [];
39
44
 
45
+ function getVisibleTextLikeBlockType(block: any): "text" | "thinking" | undefined {
46
+ if (block?.type === "text" && typeof block.text === "string" && block.text.trim().length > 0) return "text";
47
+ if (block?.type === "thinking" && typeof block.thinking === "string" && block.thinking.trim().length > 0) return "thinking";
48
+ return undefined;
49
+ }
50
+
51
+ function buildDesiredSegments(
52
+ blocks: Array<any>,
53
+ options: { shouldSkipTextBlock?: (block: any, index: number) => boolean } = {},
54
+ ): DesiredSegment[] {
55
+ const desired: DesiredSegment[] = [];
56
+ let runStart = -1;
57
+ let runEnd = -1;
58
+ let runType: "text" | "thinking" | undefined;
59
+ const closeRun = () => {
60
+ if (runStart !== -1 && runType) {
61
+ desired.push({ kind: "text-run", startIndex: runStart, endIndex: runEnd, contentType: runType });
62
+ runStart = -1;
63
+ runEnd = -1;
64
+ runType = undefined;
65
+ }
66
+ };
67
+
68
+ for (let i = 0; i < blocks.length; i++) {
69
+ const block = blocks[i];
70
+ const blockType = getVisibleTextLikeBlockType(block);
71
+ const isInvisibleTextLike = blockType === undefined && (block?.type === "text" || block?.type === "thinking");
72
+ const isTool = block?.type === "toolCall" || block?.type === "serverToolUse";
73
+
74
+ if (blockType) {
75
+ if (options.shouldSkipTextBlock?.(block, i)) {
76
+ closeRun();
77
+ continue;
78
+ }
79
+ if (runStart === -1) {
80
+ runStart = i;
81
+ runEnd = i;
82
+ runType = blockType;
83
+ } else if (runType !== blockType) {
84
+ closeRun();
85
+ runStart = i;
86
+ runEnd = i;
87
+ runType = blockType;
88
+ } else {
89
+ runEnd = i;
90
+ }
91
+ } else {
92
+ if (isInvisibleTextLike) continue;
93
+ closeRun();
94
+ if (isTool) {
95
+ desired.push({ kind: "tool", contentIndex: i, toolId: block.id });
96
+ }
97
+ }
98
+ }
99
+ closeRun();
100
+
101
+ return desired;
102
+ }
103
+
40
104
  function hasVisibleAssistantContent(message: { content: Array<any> }): boolean {
41
- return message.content.some(
42
- (c) =>
43
- (c.type === "text" && typeof c.text === "string" && c.text.trim().length > 0)
44
- || (c.type === "thinking" && typeof c.thinking === "string" && c.thinking.trim().length > 0),
45
- );
105
+ return message.content.some((c) => getVisibleTextLikeBlockType(c) !== undefined);
46
106
  }
47
107
 
48
108
  function hasAssistantToolBlocks(message: { content: Array<any> }): boolean {
@@ -470,59 +530,14 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
470
530
  // Only prune provisional pre-tool prose after post-tool prose exists,
471
531
  // so MCP tool-only windows do not blank the assistant content.
472
532
  const shouldDropPreToolProse = isClaudeCodeProvider && hasMcpToolBlock && hasPostToolText;
473
- type DesiredSegment =
474
- | { kind: "text-run"; startIndex: number; endIndex: number; contentType: "text" | "thinking" }
475
- | { kind: "tool"; contentIndex: number; toolId: string };
476
- const desired: DesiredSegment[] = [];
477
- let runStart = -1;
478
- let runEnd = -1;
479
- let runType: "text" | "thinking" | undefined;
480
- const closeRun = () => {
481
- if (runStart !== -1 && runType) {
482
- desired.push({ kind: "text-run", startIndex: runStart, endIndex: runEnd, contentType: runType });
483
- runStart = -1;
484
- runEnd = -1;
485
- runType = undefined;
486
- }
487
- };
488
- for (let i = 0; i < blocks.length; i++) {
489
- const b = blocks[i];
490
- const blockType = b.type === "text" || b.type === "thinking" ? b.type : undefined;
491
- const isTextLike = blockType === "text" || blockType === "thinking";
492
- const isTool = b.type === "toolCall" || b.type === "serverToolUse";
493
- // For Claude Code MCP turns, prune only pre-tool prose, never thinking.
494
- const textValue = blockType === "text" && typeof b?.text === "string" ? b.text : "";
495
- const isLikelyQuestion = blockType === "text" && typeof textValue === "string" && /\?\s*$/.test(textValue.trim());
496
- const shouldSkipProse = shouldDropPreToolProse
497
- && firstToolIdx >= 0
498
- && i < firstToolIdx
499
- && blockType === "text"
500
- && !isLikelyQuestion;
501
- if (shouldSkipProse) {
502
- closeRun();
503
- continue;
504
- }
505
- if (isTextLike) {
506
- if (runStart === -1) {
507
- runStart = i;
508
- runEnd = i;
509
- runType = blockType;
510
- } else if (runType !== blockType) {
511
- closeRun();
512
- runStart = i;
513
- runEnd = i;
514
- runType = blockType;
515
- } else {
516
- runEnd = i;
517
- }
518
- } else {
519
- closeRun();
520
- if (isTool) {
521
- desired.push({ kind: "tool", contentIndex: i, toolId: b.id });
522
- }
523
- }
524
- }
525
- closeRun();
533
+ const desired = buildDesiredSegments(blocks, {
534
+ shouldSkipTextBlock: (block: any, index: number) => {
535
+ if (!shouldDropPreToolProse || firstToolIdx < 0 || index >= firstToolIdx) return false;
536
+ if (getVisibleTextLikeBlockType(block) !== "text") return false;
537
+ const textValue = typeof block?.text === "string" ? block.text : "";
538
+ return !/\?\s*$/.test(textValue.trim());
539
+ },
540
+ });
526
541
 
527
542
  // Claude Code MCP can emit provisional pre-tool prose that gets
528
543
  // superseded by post-tool output. Prune stale text-run segments so
@@ -742,49 +757,7 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
742
757
  // ranges/components don't keep stale partial indices.
743
758
  if (renderedSegments.length > 0) {
744
759
  const finalBlocks = host.streamingMessage.content;
745
- type DesiredSegment =
746
- | { kind: "text-run"; startIndex: number; endIndex: number; contentType: "text" | "thinking" }
747
- | { kind: "tool"; contentIndex: number; toolId: string };
748
- const desired: DesiredSegment[] = [];
749
- let runStart = -1;
750
- let runEnd = -1;
751
- let runType: "text" | "thinking" | undefined;
752
- const closeRun = () => {
753
- if (runStart !== -1 && runType) {
754
- desired.push({ kind: "text-run", startIndex: runStart, endIndex: runEnd, contentType: runType });
755
- runStart = -1;
756
- runEnd = -1;
757
- runType = undefined;
758
- }
759
- };
760
-
761
- for (let i = 0; i < finalBlocks.length; i++) {
762
- const block = finalBlocks[i] as any;
763
- const blockType = block?.type === "text" || block?.type === "thinking" ? block.type : undefined;
764
- const isTextLike = blockType === "text" || blockType === "thinking";
765
- const isTool = block?.type === "toolCall" || block?.type === "serverToolUse";
766
-
767
- if (isTextLike) {
768
- if (runStart === -1) {
769
- runStart = i;
770
- runEnd = i;
771
- runType = blockType;
772
- } else if (runType !== blockType) {
773
- closeRun();
774
- runStart = i;
775
- runEnd = i;
776
- runType = blockType;
777
- } else {
778
- runEnd = i;
779
- }
780
- } else {
781
- closeRun();
782
- if (isTool) {
783
- desired.push({ kind: "tool", contentIndex: i, toolId: block.id });
784
- }
785
- }
786
- }
787
- closeRun();
760
+ const desired = buildDesiredSegments(finalBlocks);
788
761
 
789
762
  const toolComponentsById = new Map<string, ToolExecutionComponent>();
790
763
  for (const [toolId, component] of host.pendingTools.entries()) {
@@ -1,7 +1,13 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Regression tests for interactive assistant replay ordering.
1
3
  import assert from "node:assert/strict";
2
4
  import { test } from "node:test";
5
+ import stripAnsi from "strip-ansi";
3
6
 
4
- import { buildAssistantReplaySegments } from "./interactive-mode.js";
7
+ import { buildAssistantReplaySegments, getToolExpansionStartupHint } from "./interactive-mode.js";
8
+ import { initTheme } from "./theme/theme.js";
9
+
10
+ initTheme("dark", false);
5
11
 
6
12
  test("buildAssistantReplaySegments preserves tool-first ordering", () => {
7
13
  const segments = buildAssistantReplaySegments([
@@ -42,3 +48,26 @@ test("buildAssistantReplaySegments ignores non-rendered non-tool blocks", () =>
42
48
  { kind: "assistant", startIndex: 2, endIndex: 2 },
43
49
  ]);
44
50
  });
51
+
52
+ test("buildAssistantReplaySegments skips empty GPT reasoning blocks before tools", () => {
53
+ const segments = buildAssistantReplaySegments([
54
+ { type: "thinking", thinking: "", thinkingSignature: "encrypted" },
55
+ { type: "text", text: " " },
56
+ { type: "toolCall", id: "t1", name: "read", arguments: { filePath: "todo.js" } },
57
+ ]);
58
+
59
+ assert.deepEqual(segments, [
60
+ { kind: "tool", contentIndex: 2 },
61
+ ]);
62
+ });
63
+
64
+ test("tool expansion startup hint reflects the default expansion state", () => {
65
+ const keybindings = {
66
+ getKeys(action: string) {
67
+ return action === "expandTools" ? ["ctrl+o"] : [];
68
+ },
69
+ } as any;
70
+
71
+ assert.match(stripAnsi(getToolExpansionStartupHint(true, keybindings)), /ctrl\+o.*collapse tools/);
72
+ assert.match(stripAnsi(getToolExpansionStartupHint(false, keybindings)), /ctrl\+o.*expand tools/);
73
+ });
@@ -134,6 +134,13 @@ export type AssistantReplaySegment =
134
134
  | { kind: "assistant"; startIndex: number; endIndex: number }
135
135
  | { kind: "tool"; contentIndex: number };
136
136
 
137
+ function isVisibleAssistantReplayText(block: any): boolean {
138
+ return (
139
+ (block?.type === "text" && typeof block.text === "string" && block.text.trim().length > 0)
140
+ || (block?.type === "thinking" && typeof block.thinking === "string" && block.thinking.trim().length > 0)
141
+ );
142
+ }
143
+
137
144
  /**
138
145
  * Build replay segments for historical assistant messages so rebuild paths
139
146
  * preserve the original content[] ordering between assistant prose and tools.
@@ -141,34 +148,46 @@ export type AssistantReplaySegment =
141
148
  export function buildAssistantReplaySegments(contentBlocks: Array<any>): AssistantReplaySegment[] {
142
149
  const segments: AssistantReplaySegment[] = [];
143
150
  let runStart = -1;
151
+ let runEnd = -1;
152
+
153
+ const closeRun = () => {
154
+ if (runStart !== -1) {
155
+ segments.push({ kind: "assistant", startIndex: runStart, endIndex: runEnd });
156
+ runStart = -1;
157
+ runEnd = -1;
158
+ }
159
+ };
144
160
 
145
161
  for (let i = 0; i < contentBlocks.length; i++) {
146
162
  const block = contentBlocks[i];
147
- const isAssistantText = block?.type === "text" || block?.type === "thinking";
163
+ const isAssistantText = isVisibleAssistantReplayText(block);
164
+ const isInvisibleAssistantText = block?.type === "text" || block?.type === "thinking";
148
165
  const isTool = block?.type === "toolCall" || block?.type === "serverToolUse";
149
166
 
150
167
  if (isAssistantText) {
151
168
  if (runStart === -1) runStart = i;
169
+ runEnd = i;
152
170
  continue;
153
171
  }
154
172
 
155
- if (runStart !== -1) {
156
- segments.push({ kind: "assistant", startIndex: runStart, endIndex: i - 1 });
157
- runStart = -1;
158
- }
173
+ if (isInvisibleAssistantText) continue;
174
+
175
+ closeRun();
159
176
 
160
177
  if (isTool) {
161
178
  segments.push({ kind: "tool", contentIndex: i });
162
179
  }
163
180
  }
164
181
 
165
- if (runStart !== -1) {
166
- segments.push({ kind: "assistant", startIndex: runStart, endIndex: contentBlocks.length - 1 });
167
- }
182
+ closeRun();
168
183
 
169
184
  return segments;
170
185
  }
171
186
 
187
+ export function getToolExpansionStartupHint(toolOutputExpanded: boolean, keybindings: KeybindingsManager): string {
188
+ return appKeyHint(keybindings, "expandTools", toolOutputExpanded ? "to collapse tools" : "to expand tools");
189
+ }
190
+
172
191
  type CompactionQueuedMessage = {
173
192
  text: string;
174
193
  mode: "steer" | "followUp";
@@ -293,7 +312,7 @@ export class InteractiveMode {
293
312
  private pendingTools = new Map<string, ToolExecutionComponent>();
294
313
 
295
314
  // Tool output expansion state
296
- private toolOutputExpanded = false;
315
+ private toolOutputExpanded = true;
297
316
 
298
317
  // Pasted image tracking
299
318
  private pendingImages: ImageContent[] = [];
@@ -545,7 +564,7 @@ export class InteractiveMode {
545
564
  hint("cycleThinkingLevel", "to cycle thinking level"),
546
565
  rawKeyHint(`${appKey(kb, "cycleModelForward")}/${appKey(kb, "cycleModelBackward")}`, "to cycle models"),
547
566
  hint("selectModel", "to select model"),
548
- hint("expandTools", "to expand tools"),
567
+ getToolExpansionStartupHint(this.toolOutputExpanded, kb),
549
568
  hint("toggleThinking", "to expand thinking"),
550
569
  hint("externalEditor", "for external editor"),
551
570
  rawKeyHint("/", "for commands"),
@@ -0,0 +1,22 @@
1
+ // GSD-2 pi-coding-agent system prompt file-safety regression tests.
2
+
3
+ import test from "node:test";
4
+ import assert from "node:assert/strict";
5
+
6
+ import { buildSystemPrompt } from "../core/system-prompt.js";
7
+
8
+ test("buildSystemPrompt: read and write tools require reading before overwrite", () => {
9
+ const prompt = buildSystemPrompt({ selectedTools: ["read", "write"] });
10
+
11
+ assert.match(prompt, /before editing or overwriting/i);
12
+ assert.match(prompt, /Before write creates or replaces a file, verify the target path/i);
13
+ assert.match(prompt, /if it exists, read it first/i);
14
+ assert.match(prompt, /Use write only for new files or complete rewrites after verifying the target path/i);
15
+ });
16
+
17
+ test("buildSystemPrompt: write-only tool guidance does not reference unavailable read tool", () => {
18
+ const prompt = buildSystemPrompt({ selectedTools: ["write"] });
19
+
20
+ assert.doesNotMatch(prompt, /read it first/i);
21
+ assert.match(prompt, /Use write only for new files or complete rewrites after verifying the target path/i);
22
+ });