gsd-pi 2.80.0-dev.3065f7bfa → 2.80.0-dev.488219eb6

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 (376) hide show
  1. package/dist/claude-cli-check.d.ts +30 -0
  2. package/dist/claude-cli-check.js +18 -7
  3. package/dist/cli.js +0 -19
  4. package/dist/headless-query.d.ts +10 -0
  5. package/dist/headless-query.js +6 -4
  6. package/dist/loader-entrypoint.d.ts +8 -0
  7. package/dist/loader-entrypoint.js +27 -0
  8. package/dist/loader.js +2 -11
  9. package/dist/mcp-server.d.ts +1 -0
  10. package/dist/mcp-server.js +6 -3
  11. package/dist/resources/.managed-resources-content-hash +1 -1
  12. package/dist/resources/extensions/claude-code-cli/readiness.js +18 -7
  13. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +29 -0
  14. package/dist/resources/extensions/github-sync/sync.js +4 -1
  15. package/dist/resources/extensions/gsd/auto/loop.js +71 -8
  16. package/dist/resources/extensions/gsd/auto/phases.js +32 -8
  17. package/dist/resources/extensions/gsd/auto/resolve.js +12 -0
  18. package/dist/resources/extensions/gsd/auto/run-unit.js +3 -1
  19. package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +33 -1
  20. package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +9 -1
  21. package/dist/resources/extensions/gsd/auto-post-unit.js +81 -76
  22. package/dist/resources/extensions/gsd/auto-start.js +41 -6
  23. package/dist/resources/extensions/gsd/auto-worktree.js +98 -80
  24. package/dist/resources/extensions/gsd/auto.js +84 -29
  25. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +62 -13
  26. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +20 -26
  27. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +29 -12
  28. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +6 -9
  29. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -7
  30. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -10
  31. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -9
  32. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
  33. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +60 -26
  34. package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
  35. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  36. package/dist/resources/extensions/gsd/commands-config.js +1 -1
  37. package/dist/resources/extensions/gsd/commands-eval-review.js +2 -2
  38. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  39. package/dist/resources/extensions/gsd/db/unit-dispatches.js +53 -0
  40. package/dist/resources/extensions/gsd/git-service.js +37 -1
  41. package/dist/resources/extensions/gsd/guided-flow.js +14 -4
  42. package/dist/resources/extensions/gsd/init-wizard.js +4 -1
  43. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -4
  44. package/dist/resources/extensions/gsd/slice-cadence.js +45 -2
  45. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +15 -9
  46. package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -7
  47. package/dist/resources/extensions/gsd/tools/complete-task.js +1 -1
  48. package/dist/resources/extensions/gsd/worktree-resolver.js +22 -1
  49. package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  50. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  51. package/dist/web/standalone/.next/BUILD_ID +1 -1
  52. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  53. package/dist/web/standalone/.next/build-manifest.json +3 -3
  54. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  55. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  56. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/index.html +1 -1
  75. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  76. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  77. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  78. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  83. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/middleware.js +3 -3
  86. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  87. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  88. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  89. package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +10 -0
  90. package/dist/web/standalone/.next/static/chunks/app/{page-fab3ebb85b006001.js → page-752f1e2ebdaa3e45.js} +1 -1
  91. package/dist/web/standalone/.next/static/chunks/{webpack-0481f1221120a7c6.js → webpack-de742b64187e13fe.js} +1 -1
  92. package/dist/welcome-screen.d.ts +2 -0
  93. package/dist/welcome-screen.js +9 -7
  94. package/package.json +1 -1
  95. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +35 -13
  96. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  97. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +21 -11
  98. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -1
  99. package/packages/pi-ai/dist/providers/anthropic.d.ts +7 -0
  100. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  101. package/packages/pi-ai/dist/providers/anthropic.js +9 -7
  102. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  103. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +23 -14
  104. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -1
  105. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +48 -21
  106. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  107. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +22 -21
  108. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -1
  109. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +22 -21
  110. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -1
  111. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +39 -25
  112. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -22
  113. package/packages/pi-ai/src/providers/anthropic.ts +22 -9
  114. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +34 -21
  115. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +56 -22
  116. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +24 -28
  117. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +24 -28
  118. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  119. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
  120. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -2
  122. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  124. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +22 -56
  125. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -1
  126. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +1 -0
  127. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  128. package/packages/pi-coding-agent/dist/core/tools/bash.js +3 -1
  129. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  130. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts +2 -0
  131. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  132. package/packages/pi-coding-agent/dist/core/tools/edit.js +12 -1
  133. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/core/tools/find.d.ts +2 -0
  135. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  136. package/packages/pi-coding-agent/dist/core/tools/find.js +14 -6
  137. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  138. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts +2 -0
  139. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  140. package/packages/pi-coding-agent/dist/core/tools/grep.js +12 -3
  141. package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  142. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts +2 -0
  143. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
  144. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -1
  145. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
  146. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -1
  147. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  148. package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
  149. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  150. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts +2 -0
  151. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  152. package/packages/pi-coding-agent/dist/core/tools/ls.js +10 -3
  153. package/packages/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -0
  155. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  156. package/packages/pi-coding-agent/dist/core/tools/read.js +3 -1
  157. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  158. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +7 -62
  159. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts +2 -0
  161. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts.map +1 -0
  162. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js +115 -0
  163. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js.map +1 -0
  164. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts +19 -0
  165. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts.map +1 -0
  166. package/packages/pi-coding-agent/dist/core/tools/tool-target.js +20 -0
  167. package/packages/pi-coding-agent/dist/core/tools/tool-target.js.map +1 -0
  168. package/packages/pi-coding-agent/dist/core/tools/write.d.ts +4 -0
  169. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/tools/write.js +9 -1
  171. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  172. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +89 -2
  173. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +25 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  177. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +153 -8
  179. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  180. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  181. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +18 -1
  182. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +23 -5
  184. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +2 -0
  186. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  187. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +19 -0
  188. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +23 -5
  190. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -1
  191. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
  192. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
  193. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +22 -66
  194. package/packages/pi-coding-agent/src/core/tools/bash.ts +4 -1
  195. package/packages/pi-coding-agent/src/core/tools/edit.ts +13 -1
  196. package/packages/pi-coding-agent/src/core/tools/find.ts +15 -6
  197. package/packages/pi-coding-agent/src/core/tools/grep.ts +13 -3
  198. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +4 -1
  199. package/packages/pi-coding-agent/src/core/tools/index.ts +8 -0
  200. package/packages/pi-coding-agent/src/core/tools/ls.ts +11 -3
  201. package/packages/pi-coding-agent/src/core/tools/read.ts +4 -1
  202. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +11 -72
  203. package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
  204. package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
  205. package/packages/pi-coding-agent/src/core/tools/write.ts +14 -2
  206. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +119 -2
  207. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +31 -1
  208. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +177 -8
  209. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +24 -5
  210. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +17 -1
  211. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +21 -0
  212. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +25 -8
  213. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  214. package/src/resources/extensions/claude-code-cli/readiness.ts +25 -7
  215. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +30 -0
  216. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +26 -0
  217. package/src/resources/extensions/github-sync/sync.ts +8 -1
  218. package/src/resources/extensions/github-sync/tests/sync-source.test.ts +6 -18
  219. package/src/resources/extensions/gsd/auto/loop.ts +84 -8
  220. package/src/resources/extensions/gsd/auto/phases.ts +43 -8
  221. package/src/resources/extensions/gsd/auto/resolve.ts +19 -0
  222. package/src/resources/extensions/gsd/auto/run-unit.ts +3 -0
  223. package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +63 -1
  224. package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +14 -1
  225. package/src/resources/extensions/gsd/auto-post-unit.ts +93 -78
  226. package/src/resources/extensions/gsd/auto-start.ts +56 -6
  227. package/src/resources/extensions/gsd/auto-worktree.ts +118 -72
  228. package/src/resources/extensions/gsd/auto.ts +121 -29
  229. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +76 -12
  230. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +20 -26
  231. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +27 -12
  232. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +7 -9
  233. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +4 -7
  234. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +6 -10
  235. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -9
  236. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
  237. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +64 -26
  238. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
  239. package/src/resources/extensions/gsd/commands/handlers/ops.ts +4 -2
  240. package/src/resources/extensions/gsd/commands-config.ts +1 -1
  241. package/src/resources/extensions/gsd/commands-eval-review.ts +2 -2
  242. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  243. package/src/resources/extensions/gsd/db/unit-dispatches.ts +66 -0
  244. package/src/resources/extensions/gsd/git-service.ts +41 -2
  245. package/src/resources/extensions/gsd/guided-flow.ts +19 -4
  246. package/src/resources/extensions/gsd/init-wizard.ts +5 -1
  247. package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -4
  248. package/src/resources/extensions/gsd/slice-cadence.ts +49 -2
  249. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +23 -9
  250. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +59 -89
  251. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +47 -172
  252. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +0 -35
  253. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +35 -9
  254. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +15 -0
  255. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +80 -59
  256. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +3 -47
  257. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +76 -18
  258. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +106 -0
  259. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +54 -95
  260. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +67 -26
  261. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +32 -30
  262. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +32 -128
  263. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +20 -54
  264. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +20 -30
  265. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +17 -29
  266. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +138 -0
  267. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +21 -39
  268. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +15 -24
  269. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +44 -29
  270. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +39 -51
  271. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +1 -217
  272. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +15 -32
  273. package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -41
  274. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +34 -27
  275. package/src/resources/extensions/gsd/tests/cmux.test.ts +51 -53
  276. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +39 -61
  277. package/src/resources/extensions/gsd/tests/commands-config.test.ts +26 -19
  278. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
  279. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +29 -33
  280. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +45 -108
  281. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +35 -31
  282. package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
  283. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +4 -68
  284. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +4 -9
  285. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +14 -65
  286. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +44 -37
  287. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +58 -40
  288. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +25 -15
  289. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +35 -17
  290. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +16 -21
  291. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +15 -82
  292. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -20
  293. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +18 -26
  294. package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +9 -12
  295. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +40 -0
  296. package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +4 -2
  297. package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +31 -20
  298. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +12 -0
  299. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -47
  300. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +60 -202
  301. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +13 -59
  302. package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +44 -6
  303. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +21 -35
  304. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +79 -98
  305. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +70 -278
  306. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +37 -30
  307. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +32 -28
  308. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +24 -37
  309. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +9 -24
  310. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +113 -0
  311. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +36 -22
  312. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +36 -30
  313. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +74 -4
  314. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +20 -22
  315. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +130 -32
  316. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +18 -36
  317. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +35 -73
  318. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +76 -138
  319. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +70 -125
  320. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +59 -161
  321. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +33 -29
  322. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +22 -196
  323. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +23 -93
  324. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +50 -79
  325. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +27 -13
  326. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +151 -251
  327. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +41 -29
  328. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +58 -90
  329. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +32 -164
  330. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +57 -41
  331. package/src/resources/extensions/gsd/tests/session-model-override.test.ts +14 -9
  332. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
  333. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +61 -1
  334. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +44 -42
  335. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +56 -24
  336. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +51 -11
  337. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +23 -0
  338. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +66 -50
  339. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +68 -107
  340. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +115 -42
  341. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +21 -97
  342. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +25 -116
  343. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +21 -57
  344. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +29 -76
  345. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +33 -24
  346. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +39 -30
  347. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +33 -47
  348. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +48 -46
  349. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +14 -102
  350. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +78 -232
  351. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +32 -35
  352. package/src/resources/extensions/gsd/tests/token-profile.test.ts +84 -309
  353. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +134 -341
  354. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +8 -25
  355. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +50 -1
  356. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +6 -101
  357. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +43 -36
  358. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -444
  359. package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +142 -0
  360. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +44 -189
  361. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -57
  362. package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +32 -1
  363. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +21 -44
  364. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +27 -26
  365. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +14 -13
  366. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -18
  367. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +36 -0
  368. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -13
  369. package/src/resources/extensions/gsd/tools/complete-milestone.ts +14 -15
  370. package/src/resources/extensions/gsd/tools/complete-task.ts +1 -1
  371. package/src/resources/extensions/gsd/worktree-resolver.ts +34 -1
  372. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +86 -40
  373. package/src/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  374. package/dist/web/standalone/.next/static/chunks/8336.631939fb583761fa.js +0 -10
  375. /package/dist/web/standalone/.next/static/{O2WvnXROue6l7nAp_4dhC → G68KoLv5claox_Dyd4pZn}/_buildManifest.js +0 -0
  376. /package/dist/web/standalone/.next/static/{O2WvnXROue6l7nAp_4dhC → G68KoLv5claox_Dyd4pZn}/_ssgManifest.js +0 -0
@@ -0,0 +1,127 @@
1
+ // GSD-2 - Behavior coverage for tool target metadata.
2
+
3
+ import assert from "node:assert/strict";
4
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
5
+ import { tmpdir } from "node:os";
6
+ import { join } from "node:path";
7
+ import test from "node:test";
8
+
9
+ import { createEditTool } from "./edit.js";
10
+ import { createFindTool } from "./find.js";
11
+ import { createGrepTool } from "./grep.js";
12
+ import { createLsTool } from "./ls.js";
13
+ import { createReadTool } from "./read.js";
14
+ import { createWriteTool } from "./write.js";
15
+
16
+ test("read metadata records resolved path without changing output text", async () => {
17
+ const cwd = mkdtempSync(join(tmpdir(), "gsd-read-target-"));
18
+ try {
19
+ const filePath = join(cwd, "fixture.txt");
20
+ writeFileSync(filePath, "one\ntwo\nthree\n", "utf8");
21
+
22
+ const result = await createReadTool(cwd).execute("read-1", {
23
+ path: "fixture.txt",
24
+ offset: 2,
25
+ limit: 1,
26
+ });
27
+
28
+ assert.equal(result.details?.target?.resolvedPath, filePath);
29
+ assert.deepEqual(result.details?.target?.range, { start: 2, end: 2 });
30
+ assert.equal(result.content[0]?.type, "text");
31
+ assert.match(result.content[0]?.text ?? "", /^two/);
32
+ assert.equal((result.content[0]?.text ?? "").includes(filePath), false);
33
+
34
+ const zeroOffsetResult = await createReadTool(cwd).execute("read-zero-offset", {
35
+ path: "fixture.txt",
36
+ offset: 0,
37
+ limit: 1,
38
+ });
39
+
40
+ assert.deepEqual(zeroOffsetResult.details?.target?.range, { start: 1, end: 1 });
41
+ } finally {
42
+ rmSync(cwd, { recursive: true, force: true });
43
+ }
44
+ });
45
+
46
+ test("write metadata records resolved path without changing output text", async () => {
47
+ const cwd = mkdtempSync(join(tmpdir(), "gsd-write-target-"));
48
+ try {
49
+ const filePath = join(cwd, "out.txt");
50
+ const result = await createWriteTool(cwd).execute("write-1", {
51
+ path: "out.txt",
52
+ content: "hello",
53
+ });
54
+
55
+ assert.equal(result.details?.target?.resolvedPath, filePath);
56
+ assert.equal(result.content[0]?.type, "text");
57
+ assert.equal(result.content[0]?.text, "Successfully wrote 5 bytes to out.txt");
58
+ } finally {
59
+ rmSync(cwd, { recursive: true, force: true });
60
+ }
61
+ });
62
+
63
+ test("edit metadata records first changed line and resolved path", async () => {
64
+ const cwd = mkdtempSync(join(tmpdir(), "gsd-edit-target-"));
65
+ try {
66
+ const filePath = join(cwd, "edit.txt");
67
+ writeFileSync(filePath, "alpha\nbeta\ngamma\n", "utf8");
68
+
69
+ const result = await createEditTool(cwd).execute("edit-1", {
70
+ path: "edit.txt",
71
+ oldText: "beta",
72
+ newText: "delta",
73
+ });
74
+
75
+ assert.equal(result.details?.target?.resolvedPath, filePath);
76
+ assert.equal(result.details?.target?.line, 2);
77
+ assert.equal(result.details?.firstChangedLine, 2);
78
+ } finally {
79
+ rmSync(cwd, { recursive: true, force: true });
80
+ }
81
+ });
82
+
83
+ test("list and find metadata record resolved targets", async () => {
84
+ const cwd = mkdtempSync(join(tmpdir(), "gsd-search-target-"));
85
+ try {
86
+ const srcPath = join(cwd, "src");
87
+ const filePath = join(srcPath, "needle.txt");
88
+ mkdirSync(srcPath);
89
+ writeFileSync(filePath, "needle\n", "utf8");
90
+
91
+ const lsResult = await createLsTool(cwd).execute("ls-1", { path: "src" });
92
+ assert.equal(lsResult.details?.target?.resolvedPath, srcPath);
93
+
94
+ const findResult = await createFindTool(cwd, {
95
+ operations: {
96
+ exists: () => true,
97
+ glob: async () => [filePath],
98
+ },
99
+ }).execute("find-1", { path: "src", pattern: "needle" });
100
+ assert.equal(findResult.details?.target?.resolvedPath, srcPath);
101
+ assert.equal(findResult.details?.target?.pattern, "needle");
102
+ } finally {
103
+ rmSync(cwd, { recursive: true, force: true });
104
+ }
105
+ });
106
+
107
+ test("grep metadata records resolved search target", async () => {
108
+ const cwd = mkdtempSync(join(tmpdir(), "gsd-grep-target-"));
109
+ try {
110
+ const srcPath = join(cwd, "src");
111
+ mkdirSync(srcPath);
112
+ writeFileSync(join(srcPath, "needle.txt"), "needle\n", "utf8");
113
+
114
+ const result = await createGrepTool(cwd).execute("grep-1", {
115
+ path: "src",
116
+ pattern: "needle",
117
+ literal: true,
118
+ });
119
+
120
+ assert.equal(result.details?.target?.resolvedPath, srcPath);
121
+ assert.equal(result.details?.target?.pattern, "needle");
122
+ assert.equal(result.content[0]?.type, "text");
123
+ assert.match(result.content[0]?.text ?? "", /needle\.txt:1: needle/);
124
+ } finally {
125
+ rmSync(cwd, { recursive: true, force: true });
126
+ }
127
+ });
@@ -0,0 +1,48 @@
1
+ // GSD-2 - Shared target metadata for tool output rendering.
2
+
3
+ export type ToolTargetKind = "file" | "directory" | "search" | "command";
4
+
5
+ export type ToolTargetAction = "read" | "write" | "edit" | "list" | "find" | "grep" | "bash";
6
+
7
+ export interface ToolTargetRange {
8
+ start: number;
9
+ end?: number;
10
+ }
11
+
12
+ export interface ToolTargetMetadata {
13
+ kind: ToolTargetKind;
14
+ action: ToolTargetAction;
15
+ inputPath?: string;
16
+ resolvedPath?: string;
17
+ pattern?: string;
18
+ glob?: string;
19
+ line?: number;
20
+ range?: ToolTargetRange;
21
+ }
22
+
23
+ export function createToolTarget(target: ToolTargetMetadata): ToolTargetMetadata {
24
+ return target;
25
+ }
26
+
27
+ export function createReadFileTarget(
28
+ inputPath: string,
29
+ resolvedPath: string,
30
+ offset?: number,
31
+ limit?: number,
32
+ ): ToolTargetMetadata {
33
+ const effectiveOffset = Math.max(1, offset ?? 1);
34
+
35
+ return createToolTarget({
36
+ kind: "file",
37
+ action: "read",
38
+ inputPath,
39
+ resolvedPath,
40
+ range:
41
+ offset !== undefined || limit !== undefined
42
+ ? {
43
+ start: effectiveOffset,
44
+ end: limit !== undefined ? effectiveOffset + Math.max(0, limit - 1) : undefined,
45
+ }
46
+ : undefined,
47
+ });
48
+ }
@@ -4,6 +4,7 @@ import { mkdir as fsMkdir, writeFile as fsWriteFile } from "fs/promises";
4
4
  import { dirname } from "path";
5
5
  import { notifyFileChanged } from "../lsp/client.js";
6
6
  import { resolveToCwd } from "./path-utils.js";
7
+ import { createToolTarget, type ToolTargetMetadata } from "./tool-target.js";
7
8
 
8
9
  const writeSchema = Type.Object({
9
10
  path: Type.String({ description: "Path to the file to write (relative or absolute)" }),
@@ -12,6 +13,10 @@ const writeSchema = Type.Object({
12
13
 
13
14
  export type WriteToolInput = Static<typeof writeSchema>;
14
15
 
16
+ export interface WriteToolDetails {
17
+ target?: ToolTargetMetadata;
18
+ }
19
+
15
20
  /**
16
21
  * Pluggable operations for the write tool.
17
22
  * Override these to delegate file writing to remote systems (e.g., SSH).
@@ -50,7 +55,7 @@ export function createWriteTool(cwd: string, options?: WriteToolOptions): AgentT
50
55
  const absolutePath = resolveToCwd(path, cwd);
51
56
  const dir = dirname(absolutePath);
52
57
 
53
- return new Promise<{ content: Array<{ type: "text"; text: string }>; details: undefined }>(
58
+ return new Promise<{ content: Array<{ type: "text"; text: string }>; details: WriteToolDetails | undefined }>(
54
59
  (resolve, reject) => {
55
60
  // Check if already aborted
56
61
  if (signal?.aborted) {
@@ -98,7 +103,14 @@ export function createWriteTool(cwd: string, options?: WriteToolOptions): AgentT
98
103
 
99
104
  resolve({
100
105
  content: [{ type: "text", text: `Successfully wrote ${content.length} bytes to ${path}` }],
101
- details: undefined,
106
+ details: {
107
+ target: createToolTarget({
108
+ kind: "file",
109
+ action: "write",
110
+ inputPath: path,
111
+ resolvedPath: absolutePath,
112
+ }),
113
+ },
102
114
  });
103
115
  } catch (error: any) {
104
116
  // Clean up abort handler
@@ -113,10 +113,124 @@ describe("ToolExecutionComponent", () => {
113
113
  assert.deepEqual(component.getRollupPhase()?.label, "Other tool actions");
114
114
  });
115
115
 
116
+ test("renders compact read rows with target metadata", () => {
117
+ const rendered = renderToolCollapsed(
118
+ "read",
119
+ { path: "src/Inspector.tsx" },
120
+ {
121
+ content: [{ type: "text", text: "source" }],
122
+ isError: false,
123
+ details: {
124
+ target: {
125
+ kind: "file",
126
+ action: "read",
127
+ inputPath: "src/Inspector.tsx",
128
+ resolvedPath: "/tmp/project/src/Inspector.tsx",
129
+ range: { start: 4, end: 12 },
130
+ },
131
+ },
132
+ },
133
+ );
134
+
135
+ assert.match(rendered, /read .*src\/Inspector\.tsx:4-12/);
136
+ assert.doesNotMatch(rendered, /source/);
137
+ });
138
+
139
+ test("renders compact edit rows with target metadata", () => {
140
+ const rendered = renderToolCollapsed(
141
+ "edit",
142
+ { path: "src/Inspector.tsx" },
143
+ {
144
+ content: [{ type: "text", text: "Updated src/Inspector.tsx" }],
145
+ isError: false,
146
+ details: {
147
+ target: {
148
+ kind: "file",
149
+ action: "edit",
150
+ inputPath: "src/Inspector.tsx",
151
+ resolvedPath: "/tmp/project/src/Inspector.tsx",
152
+ line: 42,
153
+ },
154
+ },
155
+ },
156
+ );
157
+
158
+ assert.match(rendered, /edit .*src\/Inspector\.tsx:42/);
159
+ assert.doesNotMatch(rendered, /Updated src\/Inspector\.tsx/);
160
+ });
161
+
162
+ test("renders compact write rows with target metadata", () => {
163
+ const rendered = renderToolCollapsed(
164
+ "write",
165
+ { path: "src/output.ts", content: "ok" },
166
+ {
167
+ content: [{ type: "text", text: "Successfully wrote 2 bytes to src/output.ts" }],
168
+ isError: false,
169
+ details: {
170
+ target: {
171
+ kind: "file",
172
+ action: "write",
173
+ inputPath: "src/output.ts",
174
+ resolvedPath: "/tmp/project/src/output.ts",
175
+ },
176
+ },
177
+ },
178
+ );
179
+
180
+ assert.match(rendered, /write .*src\/output\.ts/);
181
+ assert.doesNotMatch(rendered, /Successfully wrote/);
182
+ });
183
+
184
+ test("renders compact bash rows with command preview", () => {
185
+ const rendered = renderToolCollapsed(
186
+ "bash",
187
+ { command: "npm run typecheck -- --watch false" },
188
+ { content: [{ type: "text", text: "ok" }], isError: false, details: { cwd: "/tmp/project" } },
189
+ );
190
+
191
+ assert.match(rendered, /bash npm run typecheck -- --watch false/);
192
+ assert.doesNotMatch(rendered, /\bok\b/);
193
+ });
194
+
195
+ test("keeps failed tools expanded and error visible", () => {
196
+ const rendered = renderToolCollapsed(
197
+ "edit",
198
+ { path: "src/Inspector.tsx" },
199
+ {
200
+ content: [{ type: "text", text: "Could not find target text" }],
201
+ isError: true,
202
+ details: {
203
+ target: {
204
+ kind: "file",
205
+ action: "edit",
206
+ inputPath: "src/Inspector.tsx",
207
+ resolvedPath: "/tmp/project/src/Inspector.tsx",
208
+ },
209
+ },
210
+ },
211
+ );
212
+
213
+ assert.match(rendered, /Could not find target text/);
214
+ assert.match(rendered, /edit/);
215
+ });
216
+
116
217
  test("renders phase-based summaries for rolled-up tool executions", () => {
117
218
  const phases: ToolExecutionPhase[] = [
118
219
  { label: "Setup / shell", count: 6, durationMs: 12 },
119
- { label: "Context reads", count: 4, durationMs: 6 },
220
+ {
221
+ label: "Context reads",
222
+ count: 4,
223
+ durationMs: 6,
224
+ actionLabel: "read",
225
+ targets: ["/tmp/project/src/a.ts", "/tmp/project/src/b.ts"],
226
+ },
227
+ {
228
+ label: "File changes",
229
+ count: 3,
230
+ durationMs: 5,
231
+ actionLabel: "edit",
232
+ targets: ["/tmp/project/src/Inspector.tsx:42", "/tmp/project/src/CompareView.tsx:8"],
233
+ },
120
234
  { label: "Requirement writes", count: 4, durationMs: 4 },
121
235
  { label: "Memory lookups", count: 4, durationMs: 4 },
122
236
  { label: "Finalization", count: 1, durationMs: 1 },
@@ -124,7 +238,10 @@ describe("ToolExecutionComponent", () => {
124
238
  const rendered = stripAnsi(new ToolPhaseSummaryComponent(phases).render(120).join("\n"));
125
239
 
126
240
  assert.match(rendered, /Setup \/ shell 6 actions\s+success · 12ms/);
127
- assert.match(rendered, /Context reads 4 actions\s+success · 6ms/);
241
+ assert.match(rendered, /Context reads · 2 files\s+success · 6ms/);
242
+ assert.match(rendered, /src\/a\.ts/);
243
+ assert.match(rendered, /File changes · 2 files, 3 edits\s+success · 5ms/);
244
+ assert.match(rendered, /src\/Inspector\.tsx:42/);
128
245
  assert.match(rendered, /Requirement writes 4 actions\s+success · 4ms/);
129
246
  assert.match(rendered, /Memory lookups 4 actions\s+success · 4ms/);
130
247
  assert.match(rendered, /Finalization 1 action\s+success · 1ms/);
@@ -1,3 +1,5 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: Runtime tests for TUI tool cards, success notifications, and blocking errors.
1
3
  // GSD2 TUI Tests - Runtime coverage for tool-card cleanup and success notification rendering.
2
4
  // Runtime regression tests for the post-compaction tool-card cleanup and the
3
5
  // green-bordered success-notification rendering. Replaces the source-grep
@@ -18,7 +20,7 @@ import { Container, Text } from "@gsd/pi-tui";
18
20
  import stripAnsi from "strip-ansi";
19
21
 
20
22
  import { initTheme, theme } from "../theme/theme.js";
21
- import { renderExtensionNotifyInChat, shouldRenderExtensionNotifyInChat } from "../interactive-mode.js";
23
+ import { renderBlockingErrorBanner, renderExtensionNotifyInChat, shouldRenderExtensionNotifyInChat } from "../interactive-mode.js";
22
24
  import { DynamicBorder } from "./dynamic-border.js";
23
25
  import { ToolExecutionComponent } from "./tool-execution.js";
24
26
 
@@ -58,6 +60,34 @@ describe("Extension warning notifications", () => {
58
60
  });
59
61
  });
60
62
 
63
+ describe("Blocking error banner", () => {
64
+ it("keeps full error notifications renderable outside chat history", () => {
65
+ const banner = new Container();
66
+ const message = [
67
+ "Pre-execution checks failed: 3 blocking issues found",
68
+ " - [file] lib/types.ts: Task T01 references 'lib/types.ts'",
69
+ "See .gsd/milestones/M001/slices/S02/S02-PRE-EXEC-VERIFY.json for full details.",
70
+ ].join("\n");
71
+
72
+ renderBlockingErrorBanner(banner, message);
73
+
74
+ const rendered = banner.render(140).map(stripAnsi).join("\n");
75
+ assert.match(rendered, /Error: Pre-execution checks failed: 3 blocking issues found/);
76
+ assert.match(rendered, /Task T01 references 'lib\/types\.ts'/);
77
+ assert.match(rendered, /S02-PRE-EXEC-VERIFY\.json/);
78
+ });
79
+
80
+ it("clears the sticky banner when the blocking error is cleared", () => {
81
+ const banner = new Container();
82
+
83
+ renderBlockingErrorBanner(banner, "Provider failed");
84
+ assert.match(banner.render(80).map(stripAnsi).join("\n"), /Provider failed/);
85
+
86
+ renderBlockingErrorBanner(banner, undefined);
87
+ assert.equal(banner.render(80).map(stripAnsi).join("\n"), "");
88
+ });
89
+ });
90
+
61
91
  interface MockTui {
62
92
  renderCount: number;
63
93
  requestRender(): void;
@@ -111,9 +111,10 @@ function renderToolFrame(
111
111
  const statusColor = opts.tone === "error" ? "toolError" : opts.tone === "pending" ? "toolRunning" : "toolSuccess";
112
112
  const leftStyled = theme.fg(labelColor, theme.bold(opts.label));
113
113
  const rightStyled = theme.fg(statusColor, opts.status);
114
- const gap = Math.max(1, outerWidth - visibleWidth(leftStyled) - visibleWidth(rightStyled));
114
+ const titleWidth = Math.max(1, outerWidth - 4);
115
+ const gap = Math.max(1, titleWidth - visibleWidth(leftStyled) - visibleWidth(rightStyled));
115
116
  const headerRow = `${leftStyled}${" ".repeat(gap)}${rightStyled}`;
116
- const headerPad = Math.max(0, outerWidth - visibleWidth(headerRow));
117
+ const headerPad = Math.max(0, titleWidth - visibleWidth(headerRow));
117
118
 
118
119
  const sourceLines = trimOuterBlankLines(contentLines);
119
120
  const bodyLines = (sourceLines.length > 0 ? sourceLines : [""]).map((line) => {
@@ -122,7 +123,7 @@ function renderToolFrame(
122
123
  });
123
124
 
124
125
  return style()
125
- .border("rule")
126
+ .border("rounded")
126
127
  .borderColor((line) => theme.fg(line.startsWith("─") ? topColor : borderColor, line))
127
128
  .title(headerRow + " ".repeat(headerPad))
128
129
  .render(bodyLines, outerWidth);
@@ -157,6 +158,22 @@ export type ToolExecutionPhase = {
157
158
  label: string;
158
159
  count: number;
159
160
  durationMs: number;
161
+ targets?: string[];
162
+ actionLabel?: string;
163
+ };
164
+
165
+ type ToolTargetMetadata = {
166
+ kind?: string;
167
+ action?: string;
168
+ inputPath?: string;
169
+ resolvedPath?: string;
170
+ pattern?: string;
171
+ glob?: string;
172
+ line?: number;
173
+ range?: {
174
+ start?: number;
175
+ end?: number;
176
+ };
160
177
  };
161
178
 
162
179
  function formatElapsed(ms: number): string {
@@ -164,6 +181,104 @@ function formatElapsed(ms: number): string {
164
181
  return `${Math.max(1, Math.round(ms / 1000))}s`;
165
182
  }
166
183
 
184
+ function formatCommandPreview(command: string): string {
185
+ return truncateToWidth(command.replace(/\s+/g, " ").trim(), 64, "");
186
+ }
187
+
188
+ function appendLineOrRange(displayPath: string | undefined, target: ToolTargetMetadata): string | undefined {
189
+ if (!displayPath) return undefined;
190
+ if (typeof target.line === "number" && Number.isFinite(target.line)) {
191
+ return `${displayPath}:${target.line}`;
192
+ }
193
+ const start = target.range?.start;
194
+ if (typeof start === "number" && Number.isFinite(start)) {
195
+ const end = target.range?.end;
196
+ const suffix =
197
+ typeof end === "number" && Number.isFinite(end) && end !== start
198
+ ? `${start}-${end}`
199
+ : `${start}`;
200
+ return `${displayPath}:${suffix}`;
201
+ }
202
+ return displayPath;
203
+ }
204
+
205
+ function formatToolTarget(target: ToolTargetMetadata): string | undefined {
206
+ const path = target.resolvedPath || target.inputPath;
207
+ const displayPath = path ? shortenPath(path) : undefined;
208
+ if (target.kind === "search") {
209
+ const searchTarget = displayPath ?? target.inputPath ?? ".";
210
+ const label = target.pattern ? `${target.pattern} in ${searchTarget}` : searchTarget;
211
+ return target.glob ? `${label} (${target.glob})` : label;
212
+ }
213
+ return appendLineOrRange(displayPath, target);
214
+ }
215
+
216
+ function formatArgsPathTarget(path: string | null, args: Record<string, unknown>): string | undefined {
217
+ if (!path) return undefined;
218
+ const start = typeof args.offset === "number" ? args.offset : undefined;
219
+ const limit = typeof args.limit === "number" ? args.limit : undefined;
220
+ const range =
221
+ start !== undefined || limit !== undefined
222
+ ? {
223
+ start: start ?? 1,
224
+ end: limit !== undefined ? (start ?? 1) + Math.max(0, limit - 1) : undefined,
225
+ }
226
+ : undefined;
227
+ return appendLineOrRange(shortenPath(path), { range });
228
+ }
229
+
230
+ function stripLineSuffix(target: string): string {
231
+ return target.replace(/:\d+(?:-\d+)?$/, "");
232
+ }
233
+
234
+ function uniqueTargets(targets: string[] | undefined): string[] {
235
+ const seen = new Set<string>();
236
+ const unique: string[] = [];
237
+ for (const target of targets ?? []) {
238
+ if (!target || seen.has(target)) continue;
239
+ seen.add(target);
240
+ unique.push(target);
241
+ }
242
+ return unique;
243
+ }
244
+
245
+ function summarizePhaseLabel(phase: ToolExecutionPhase): string {
246
+ const phaseTargets = uniqueTargets(phase.targets);
247
+ const baseTargets = uniqueTargets(phaseTargets.map(stripLineSuffix));
248
+ if (phase.label === "File changes" && baseTargets.length > 0) {
249
+ const fileWord = baseTargets.length === 1 ? "file" : "files";
250
+ const actionWord =
251
+ phase.actionLabel === "write"
252
+ ? phase.count === 1
253
+ ? "write"
254
+ : "writes"
255
+ : phase.actionLabel === undefined
256
+ ? phase.count === 1
257
+ ? "action"
258
+ : "actions"
259
+ : phase.count === 1
260
+ ? "edit"
261
+ : "edits";
262
+ return `${phase.label} · ${baseTargets.length} ${fileWord}, ${phase.count} ${actionWord}`;
263
+ }
264
+ if (phase.label === "Context reads" && baseTargets.length > 0) {
265
+ const fileWord = baseTargets.length === 1 ? "file" : "files";
266
+ return `${phase.label} · ${baseTargets.length} ${fileWord}`;
267
+ }
268
+ if (phase.label === "Setup / shell" && phaseTargets.length > 0) {
269
+ return `${phase.label} · ${phase.count} ${phase.count === 1 ? "command" : "commands"}`;
270
+ }
271
+ return `${phase.label} ${phase.count} ${phase.count === 1 ? "action" : "actions"}`;
272
+ }
273
+
274
+ function summarizePhaseTargets(phase: ToolExecutionPhase, width: number): string | undefined {
275
+ const phaseTargets = uniqueTargets(phase.targets);
276
+ if (phaseTargets.length === 0) return undefined;
277
+ const shown = phaseTargets.slice(0, 3);
278
+ const suffix = phaseTargets.length > shown.length ? ` +${phaseTargets.length - shown.length} more` : "";
279
+ return truncateToWidth(shown.join(" · ") + suffix, width, "");
280
+ }
281
+
167
282
  /**
168
283
  * Format tool args for the generic-renderer fallback. Produces a one-line
169
284
  * `k=v, k=v` summary when every value is a primitive that fits inline; falls
@@ -607,10 +722,13 @@ export class ToolExecutionComponent extends Container {
607
722
  if (!this.shouldRenderCompactSuccess()) return null;
608
723
  const label = this.getPhaseLabel();
609
724
  const endedAt = this.endedAt ?? Date.now();
725
+ const target = this.getCompactTarget();
610
726
  return {
611
727
  label,
612
728
  count: 1,
613
729
  durationMs: Math.max(0, endedAt - this.startedAt),
730
+ targets: target ? [target] : undefined,
731
+ actionLabel: this.getCompactAction(),
614
732
  };
615
733
  }
616
734
 
@@ -631,7 +749,52 @@ export class ToolExecutionComponent extends Container {
631
749
  }
632
750
 
633
751
  private getCompactSummary(frameLabel: string): string {
634
- return frameLabel;
752
+ if (this.normalizedToolName === "bash") {
753
+ const command = str(this.args?.command);
754
+ return command ? `bash ${formatCommandPreview(command)}` : frameLabel;
755
+ }
756
+ const target = this.getCompactTarget();
757
+ return target ? `${this.getCompactAction()} ${target}` : frameLabel;
758
+ }
759
+
760
+ private getCompactAction(): string {
761
+ const target = this.getTargetMetadata();
762
+ if (target?.action) return target.action === "list" ? "ls" : target.action;
763
+ return this.normalizedToolName;
764
+ }
765
+
766
+ private getTargetMetadata(): ToolTargetMetadata | undefined {
767
+ const target = this.result?.details?.target;
768
+ return target && typeof target === "object" ? target : undefined;
769
+ }
770
+
771
+ private getCompactTarget(): string | undefined {
772
+ const metadata = this.getTargetMetadata();
773
+ const metadataTarget = metadata ? formatToolTarget(metadata) : undefined;
774
+ if (metadataTarget) return metadataTarget;
775
+
776
+ const path = str(this.args?.file_path ?? this.args?.path);
777
+ if (path === null) return undefined;
778
+ if (this.normalizedToolName === "read" || this.normalizedToolName === "hashline_read") {
779
+ return formatArgsPathTarget(path, this.args);
780
+ }
781
+ if (this.normalizedToolName === "write" || this.normalizedToolName === "edit") {
782
+ return path ? shortenPath(path) : undefined;
783
+ }
784
+ if (this.normalizedToolName === "ls") {
785
+ return shortenPath(path || ".");
786
+ }
787
+ if (this.normalizedToolName === "find") {
788
+ const pattern = str(this.args?.pattern);
789
+ return pattern ? `${pattern} in ${shortenPath(path || ".")}` : shortenPath(path || ".");
790
+ }
791
+ if (this.normalizedToolName === "grep") {
792
+ const pattern = str(this.args?.pattern);
793
+ const glob = str(this.args?.glob);
794
+ const label = pattern ? `${pattern} in ${shortenPath(path || ".")}` : shortenPath(path || ".");
795
+ return glob ? `${label} (${glob})` : label;
796
+ }
797
+ return undefined;
635
798
  }
636
799
 
637
800
  private updateDisplay(): void {
@@ -861,6 +1024,10 @@ export class ToolExecutionComponent extends Container {
861
1024
  // Truncation warnings
862
1025
  const truncation = this.result.details?.truncation;
863
1026
  const fullOutputPath = this.result.details?.fullOutputPath;
1027
+ const cwd = this.result.details?.cwd;
1028
+ if (this.expanded && typeof cwd === "string" && cwd.length > 0) {
1029
+ this.contentBox.addChild(new Text(`\n${theme.fg("muted", `cwd ${shortenPath(cwd)}`)}`, 0, 0));
1030
+ }
864
1031
  if (truncation?.truncated || fullOutputPath) {
865
1032
  const warnings: string[] = [];
866
1033
  if (fullOutputPath) {
@@ -1288,19 +1455,21 @@ export class ToolPhaseSummaryComponent extends Container {
1288
1455
  }
1289
1456
 
1290
1457
  getPhases(): ToolExecutionPhase[] {
1291
- return this.phases.map((phase) => ({ ...phase }));
1458
+ return this.phases.map((phase) => ({ ...phase, targets: phase.targets ? [...phase.targets] : undefined }));
1292
1459
  }
1293
1460
 
1294
1461
  override render(width: number): string[] {
1295
1462
  const frameWidth = Math.max(20, width);
1296
- const rows = this.phases.map((phase) => {
1297
- const left = `${phase.label} ${phase.count} ${phase.count === 1 ? "action" : "actions"}`;
1463
+ const rows = this.phases.flatMap((phase) => {
1464
+ const left = summarizePhaseLabel(phase);
1298
1465
  const right = `success · ${formatElapsed(phase.durationMs)}`;
1299
1466
  const contentWidth = Math.max(1, frameWidth - 2);
1300
1467
  const leftWidth = Math.max(1, contentWidth - visibleWidth(right) - 1);
1301
1468
  const leftText = truncateToWidth(left, leftWidth, "");
1302
1469
  const gap = Math.max(1, contentWidth - visibleWidth(leftText) - visibleWidth(right));
1303
- return `${theme.fg("toolSuccess", leftText)}${" ".repeat(gap)}${theme.fg("toolSuccess", right)}`;
1470
+ const summaryRow = `${theme.fg("toolSuccess", leftText)}${" ".repeat(gap)}${theme.fg("toolSuccess", right)}`;
1471
+ const targetRow = summarizePhaseTargets(phase, contentWidth);
1472
+ return targetRow ? [summaryRow, theme.fg("muted", targetRow)] : [summaryRow];
1304
1473
  });
1305
1474
 
1306
1475
  return ["", ...style().border("minimal").borderColor((text) => theme.fg("toolSuccess", text)).render(rows, frameWidth)];