gsd-pi 2.10.12 → 2.12.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 (504) hide show
  1. package/dist/bundled-extension-paths.d.ts +2 -0
  2. package/dist/bundled-extension-paths.js +10 -0
  3. package/dist/loader.js +45 -28
  4. package/dist/onboarding.js +100 -0
  5. package/dist/resource-loader.js +12 -3
  6. package/dist/resources/GSD-WORKFLOW.md +661 -0
  7. package/dist/resources/agents/researcher.md +29 -0
  8. package/dist/resources/agents/scout.md +56 -0
  9. package/dist/resources/agents/worker.md +31 -0
  10. package/dist/resources/extensions/ask-user-questions.ts +289 -0
  11. package/dist/resources/extensions/async-jobs/async-bash-tool.ts +211 -0
  12. package/dist/resources/extensions/async-jobs/await-tool.ts +101 -0
  13. package/dist/resources/extensions/async-jobs/cancel-job-tool.ts +34 -0
  14. package/dist/resources/extensions/async-jobs/index.ts +133 -0
  15. package/dist/resources/extensions/async-jobs/job-manager.ts +211 -0
  16. package/dist/resources/extensions/bg-shell/index.ts +3179 -0
  17. package/dist/resources/extensions/browser-tools/BROWSER-TOOLS-V2-PROPOSAL.md +1277 -0
  18. package/dist/resources/extensions/browser-tools/capture.ts +165 -0
  19. package/dist/resources/extensions/browser-tools/core.d.ts +205 -0
  20. package/dist/resources/extensions/browser-tools/core.js +1057 -0
  21. package/dist/resources/extensions/browser-tools/evaluate-helpers.ts +184 -0
  22. package/dist/resources/extensions/browser-tools/index.ts +51 -0
  23. package/dist/resources/extensions/browser-tools/lifecycle.ts +270 -0
  24. package/dist/resources/extensions/browser-tools/package.json +24 -0
  25. package/dist/resources/extensions/browser-tools/refs.ts +264 -0
  26. package/dist/resources/extensions/browser-tools/settle.ts +197 -0
  27. package/dist/resources/extensions/browser-tools/state.ts +408 -0
  28. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +652 -0
  29. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +614 -0
  30. package/dist/resources/extensions/browser-tools/tools/assertions.ts +342 -0
  31. package/dist/resources/extensions/browser-tools/tools/forms.ts +801 -0
  32. package/dist/resources/extensions/browser-tools/tools/inspection.ts +492 -0
  33. package/dist/resources/extensions/browser-tools/tools/intent.ts +614 -0
  34. package/dist/resources/extensions/browser-tools/tools/interaction.ts +865 -0
  35. package/dist/resources/extensions/browser-tools/tools/navigation.ts +232 -0
  36. package/dist/resources/extensions/browser-tools/tools/pages.ts +303 -0
  37. package/dist/resources/extensions/browser-tools/tools/refs.ts +541 -0
  38. package/dist/resources/extensions/browser-tools/tools/screenshot.ts +83 -0
  39. package/dist/resources/extensions/browser-tools/tools/session.ts +400 -0
  40. package/dist/resources/extensions/browser-tools/tools/wait.ts +247 -0
  41. package/dist/resources/extensions/browser-tools/utils.ts +660 -0
  42. package/dist/resources/extensions/context7/index.ts +428 -0
  43. package/dist/resources/extensions/context7/package.json +11 -0
  44. package/dist/resources/extensions/get-secrets-from-user.ts +625 -0
  45. package/dist/resources/extensions/google-search/index.ts +336 -0
  46. package/dist/resources/extensions/google-search/package.json +9 -0
  47. package/dist/resources/extensions/gsd/activity-log.ts +116 -0
  48. package/dist/resources/extensions/gsd/auto.ts +3732 -0
  49. package/dist/resources/extensions/gsd/commands.ts +544 -0
  50. package/dist/resources/extensions/gsd/crash-recovery.ts +105 -0
  51. package/dist/resources/extensions/gsd/dashboard-overlay.ts +564 -0
  52. package/dist/resources/extensions/gsd/dispatch-guard.ts +78 -0
  53. package/dist/resources/extensions/gsd/docs/preferences-reference.md +278 -0
  54. package/dist/resources/extensions/gsd/doctor.ts +766 -0
  55. package/dist/resources/extensions/gsd/exit-command.ts +18 -0
  56. package/dist/resources/extensions/gsd/files.ts +857 -0
  57. package/dist/resources/extensions/gsd/git-service.ts +904 -0
  58. package/dist/resources/extensions/gsd/gitignore.ts +200 -0
  59. package/dist/resources/extensions/gsd/guided-flow.ts +1054 -0
  60. package/dist/resources/extensions/gsd/index.ts +735 -0
  61. package/dist/resources/extensions/gsd/metrics.ts +374 -0
  62. package/dist/resources/extensions/gsd/migrate/command.ts +218 -0
  63. package/dist/resources/extensions/gsd/migrate/index.ts +42 -0
  64. package/dist/resources/extensions/gsd/migrate/parser.ts +323 -0
  65. package/dist/resources/extensions/gsd/migrate/parsers.ts +624 -0
  66. package/dist/resources/extensions/gsd/migrate/preview.ts +48 -0
  67. package/dist/resources/extensions/gsd/migrate/transformer.ts +346 -0
  68. package/dist/resources/extensions/gsd/migrate/types.ts +370 -0
  69. package/dist/resources/extensions/gsd/migrate/validator.ts +55 -0
  70. package/dist/resources/extensions/gsd/migrate/writer.ts +539 -0
  71. package/dist/resources/extensions/gsd/native-git-bridge.ts +181 -0
  72. package/dist/resources/extensions/gsd/native-parser-bridge.ts +135 -0
  73. package/dist/resources/extensions/gsd/observability-validator.ts +408 -0
  74. package/dist/resources/extensions/gsd/package.json +11 -0
  75. package/dist/resources/extensions/gsd/paths.ts +339 -0
  76. package/dist/resources/extensions/gsd/post-unit-hooks.ts +449 -0
  77. package/dist/resources/extensions/gsd/preferences.ts +988 -0
  78. package/dist/resources/extensions/gsd/prompt-loader.ts +92 -0
  79. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +25 -0
  80. package/dist/resources/extensions/gsd/prompts/complete-slice.md +27 -0
  81. package/dist/resources/extensions/gsd/prompts/discuss.md +237 -0
  82. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +29 -0
  83. package/dist/resources/extensions/gsd/prompts/execute-task.md +63 -0
  84. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +3 -0
  85. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -0
  86. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +61 -0
  87. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +3 -0
  88. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +29 -0
  89. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +3 -0
  90. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +13 -0
  91. package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -0
  92. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +78 -0
  93. package/dist/resources/extensions/gsd/prompts/plan-slice.md +55 -0
  94. package/dist/resources/extensions/gsd/prompts/queue.md +100 -0
  95. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +48 -0
  96. package/dist/resources/extensions/gsd/prompts/replan-slice.md +39 -0
  97. package/dist/resources/extensions/gsd/prompts/research-milestone.md +37 -0
  98. package/dist/resources/extensions/gsd/prompts/research-slice.md +28 -0
  99. package/dist/resources/extensions/gsd/prompts/review-migration.md +66 -0
  100. package/dist/resources/extensions/gsd/prompts/run-uat.md +109 -0
  101. package/dist/resources/extensions/gsd/prompts/system.md +190 -0
  102. package/dist/resources/extensions/gsd/prompts/worktree-merge.md +123 -0
  103. package/dist/resources/extensions/gsd/roadmap-slices.ts +50 -0
  104. package/dist/resources/extensions/gsd/session-forensics.ts +500 -0
  105. package/dist/resources/extensions/gsd/skill-discovery.ts +137 -0
  106. package/dist/resources/extensions/gsd/state.ts +569 -0
  107. package/dist/resources/extensions/gsd/templates/context.md +76 -0
  108. package/dist/resources/extensions/gsd/templates/decisions.md +8 -0
  109. package/dist/resources/extensions/gsd/templates/milestone-summary.md +73 -0
  110. package/dist/resources/extensions/gsd/templates/plan.md +131 -0
  111. package/dist/resources/extensions/gsd/templates/preferences.md +23 -0
  112. package/dist/resources/extensions/gsd/templates/project.md +31 -0
  113. package/dist/resources/extensions/gsd/templates/reassessment.md +28 -0
  114. package/dist/resources/extensions/gsd/templates/requirements.md +81 -0
  115. package/dist/resources/extensions/gsd/templates/research.md +46 -0
  116. package/dist/resources/extensions/gsd/templates/roadmap.md +118 -0
  117. package/dist/resources/extensions/gsd/templates/secrets-manifest.md +22 -0
  118. package/dist/resources/extensions/gsd/templates/slice-context.md +58 -0
  119. package/dist/resources/extensions/gsd/templates/slice-summary.md +99 -0
  120. package/dist/resources/extensions/gsd/templates/state.md +19 -0
  121. package/dist/resources/extensions/gsd/templates/task-plan.md +52 -0
  122. package/dist/resources/extensions/gsd/templates/task-summary.md +57 -0
  123. package/dist/resources/extensions/gsd/templates/uat.md +54 -0
  124. package/dist/resources/extensions/gsd/tests/activity-log-prune.test.ts +297 -0
  125. package/dist/resources/extensions/gsd/tests/activity-log-save.test.ts +127 -0
  126. package/dist/resources/extensions/gsd/tests/auto-draft-pause.test.ts +109 -0
  127. package/dist/resources/extensions/gsd/tests/auto-preflight.test.ts +45 -0
  128. package/dist/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +196 -0
  129. package/dist/resources/extensions/gsd/tests/auto-supervisor.test.mjs +53 -0
  130. package/dist/resources/extensions/gsd/tests/collect-from-manifest.test.ts +469 -0
  131. package/dist/resources/extensions/gsd/tests/complete-milestone.test.ts +200 -0
  132. package/dist/resources/extensions/gsd/tests/cost-projection.test.ts +134 -0
  133. package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +312 -0
  134. package/dist/resources/extensions/gsd/tests/derive-state-draft.test.ts +299 -0
  135. package/dist/resources/extensions/gsd/tests/derive-state.test.ts +660 -0
  136. package/dist/resources/extensions/gsd/tests/discuss-prompt.test.ts +27 -0
  137. package/dist/resources/extensions/gsd/tests/dispatch-guard.test.ts +91 -0
  138. package/dist/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +170 -0
  139. package/dist/resources/extensions/gsd/tests/doctor.test.ts +594 -0
  140. package/dist/resources/extensions/gsd/tests/draft-promotion.test.ts +169 -0
  141. package/dist/resources/extensions/gsd/tests/exit-command.test.ts +50 -0
  142. package/dist/resources/extensions/gsd/tests/git-service.test.ts +1788 -0
  143. package/dist/resources/extensions/gsd/tests/idle-recovery.test.ts +577 -0
  144. package/dist/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +580 -0
  145. package/dist/resources/extensions/gsd/tests/manifest-status.test.ts +283 -0
  146. package/dist/resources/extensions/gsd/tests/metrics-io.test.ts +176 -0
  147. package/dist/resources/extensions/gsd/tests/metrics.test.ts +188 -0
  148. package/dist/resources/extensions/gsd/tests/migrate-command.test.ts +369 -0
  149. package/dist/resources/extensions/gsd/tests/migrate-parser.test.ts +757 -0
  150. package/dist/resources/extensions/gsd/tests/migrate-transformer.test.ts +635 -0
  151. package/dist/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +414 -0
  152. package/dist/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +297 -0
  153. package/dist/resources/extensions/gsd/tests/migrate-writer.test.ts +398 -0
  154. package/dist/resources/extensions/gsd/tests/must-have-parser.test.ts +291 -0
  155. package/dist/resources/extensions/gsd/tests/network-error-fallback.test.ts +54 -0
  156. package/dist/resources/extensions/gsd/tests/next-milestone-id.test.ts +66 -0
  157. package/dist/resources/extensions/gsd/tests/orphaned-branch.test.ts +353 -0
  158. package/dist/resources/extensions/gsd/tests/parsers.test.ts +1664 -0
  159. package/dist/resources/extensions/gsd/tests/plan-milestone.test.ts +133 -0
  160. package/dist/resources/extensions/gsd/tests/plan-quality-validator.test.ts +363 -0
  161. package/dist/resources/extensions/gsd/tests/post-unit-hooks.test.ts +297 -0
  162. package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +226 -0
  163. package/dist/resources/extensions/gsd/tests/queue-draft-detection.test.ts +126 -0
  164. package/dist/resources/extensions/gsd/tests/reassess-prompt.test.ts +142 -0
  165. package/dist/resources/extensions/gsd/tests/regex-hardening.test.ts +281 -0
  166. package/dist/resources/extensions/gsd/tests/remote-questions.test.ts +155 -0
  167. package/dist/resources/extensions/gsd/tests/remote-status.test.ts +99 -0
  168. package/dist/resources/extensions/gsd/tests/replan-slice.test.ts +493 -0
  169. package/dist/resources/extensions/gsd/tests/requirements.test.ts +106 -0
  170. package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +35 -0
  171. package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +11 -0
  172. package/dist/resources/extensions/gsd/tests/roadmap-slices.test.ts +41 -0
  173. package/dist/resources/extensions/gsd/tests/run-uat.test.ts +316 -0
  174. package/dist/resources/extensions/gsd/tests/secure-env-collect.test.ts +185 -0
  175. package/dist/resources/extensions/gsd/tests/smart-entry-draft.test.ts +123 -0
  176. package/dist/resources/extensions/gsd/tests/test-helpers.ts +61 -0
  177. package/dist/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +219 -0
  178. package/dist/resources/extensions/gsd/tests/unit-runtime.test.ts +234 -0
  179. package/dist/resources/extensions/gsd/tests/workspace-index.test.ts +75 -0
  180. package/dist/resources/extensions/gsd/tests/worktree-integration.test.ts +234 -0
  181. package/dist/resources/extensions/gsd/tests/worktree-manager.test.ts +141 -0
  182. package/dist/resources/extensions/gsd/tests/worktree.test.ts +597 -0
  183. package/dist/resources/extensions/gsd/tests/write-gate.test.ts +122 -0
  184. package/dist/resources/extensions/gsd/types.ts +296 -0
  185. package/dist/resources/extensions/gsd/unit-runtime.ts +184 -0
  186. package/dist/resources/extensions/gsd/workspace-index.ts +189 -0
  187. package/dist/resources/extensions/gsd/worktree-command.ts +845 -0
  188. package/dist/resources/extensions/gsd/worktree-manager.ts +459 -0
  189. package/dist/resources/extensions/gsd/{worktree.js → worktree.ts} +92 -61
  190. package/dist/resources/extensions/mac-tools/index.ts +852 -0
  191. package/dist/resources/extensions/mac-tools/swift-cli/Package.swift +22 -0
  192. package/dist/resources/extensions/mac-tools/swift-cli/Sources/main.swift +1318 -0
  193. package/dist/resources/extensions/mcporter/index.ts +429 -0
  194. package/dist/resources/extensions/remote-questions/config.ts +81 -0
  195. package/dist/resources/extensions/remote-questions/discord-adapter.ts +128 -0
  196. package/dist/resources/extensions/remote-questions/format.ts +163 -0
  197. package/dist/resources/extensions/remote-questions/manager.ts +192 -0
  198. package/dist/resources/extensions/remote-questions/remote-command.ts +361 -0
  199. package/dist/resources/extensions/remote-questions/slack-adapter.ts +92 -0
  200. package/dist/resources/extensions/remote-questions/status.ts +31 -0
  201. package/dist/resources/extensions/remote-questions/store.ts +77 -0
  202. package/dist/resources/extensions/remote-questions/types.ts +75 -0
  203. package/dist/resources/extensions/search-the-web/cache.ts +78 -0
  204. package/dist/resources/extensions/search-the-web/command-search-provider.ts +99 -0
  205. package/dist/resources/extensions/search-the-web/format.ts +258 -0
  206. package/dist/resources/extensions/search-the-web/http.ts +238 -0
  207. package/dist/resources/extensions/search-the-web/index.ts +65 -0
  208. package/dist/resources/extensions/search-the-web/native-search.ts +165 -0
  209. package/dist/resources/extensions/search-the-web/provider.ts +136 -0
  210. package/dist/resources/extensions/search-the-web/tavily.ts +116 -0
  211. package/dist/resources/extensions/search-the-web/tool-fetch-page.ts +581 -0
  212. package/dist/resources/extensions/search-the-web/tool-llm-context.ts +620 -0
  213. package/dist/resources/extensions/search-the-web/tool-search.ts +635 -0
  214. package/dist/resources/extensions/search-the-web/url-utils.ts +91 -0
  215. package/dist/resources/extensions/shared/bundled-extension-paths.ts +11 -0
  216. package/dist/resources/extensions/shared/confirm-ui.ts +126 -0
  217. package/dist/resources/extensions/shared/interview-ui.ts +613 -0
  218. package/dist/resources/extensions/shared/next-action-ui.ts +197 -0
  219. package/dist/resources/extensions/shared/progress-widget.ts +282 -0
  220. package/dist/resources/extensions/shared/terminal.ts +23 -0
  221. package/dist/resources/extensions/shared/thinking-widget.ts +107 -0
  222. package/dist/resources/extensions/shared/ui.ts +400 -0
  223. package/dist/resources/extensions/shared/wizard-ui.ts +551 -0
  224. package/dist/resources/extensions/slash-commands/audit.ts +88 -0
  225. package/dist/resources/extensions/slash-commands/clear.ts +10 -0
  226. package/dist/resources/extensions/slash-commands/create-extension.ts +297 -0
  227. package/dist/resources/extensions/slash-commands/create-slash-command.ts +234 -0
  228. package/dist/resources/extensions/slash-commands/index.ts +12 -0
  229. package/dist/resources/extensions/subagent/agents.ts +126 -0
  230. package/dist/resources/extensions/subagent/index.ts +1072 -0
  231. package/dist/resources/extensions/subagent/isolation.ts +498 -0
  232. package/dist/resources/extensions/ttsr/index.ts +163 -0
  233. package/dist/resources/extensions/ttsr/rule-loader.ts +121 -0
  234. package/dist/resources/extensions/ttsr/ttsr-interrupt.md +6 -0
  235. package/dist/resources/extensions/ttsr/ttsr-manager.ts +430 -0
  236. package/dist/resources/extensions/universal-config/discovery.ts +78 -0
  237. package/dist/resources/extensions/universal-config/format.ts +160 -0
  238. package/dist/resources/extensions/universal-config/index.ts +118 -0
  239. package/dist/resources/extensions/universal-config/package.json +11 -0
  240. package/dist/resources/extensions/universal-config/scanners.ts +579 -0
  241. package/dist/resources/extensions/universal-config/tests/discovery.test.ts +111 -0
  242. package/dist/resources/extensions/universal-config/tests/format.test.ts +111 -0
  243. package/dist/resources/extensions/universal-config/tests/scanners.test.ts +438 -0
  244. package/dist/resources/extensions/universal-config/tools.ts +60 -0
  245. package/dist/resources/extensions/universal-config/types.ts +116 -0
  246. package/dist/resources/extensions/voice/index.ts +271 -0
  247. package/dist/resources/extensions/voice/speech-recognizer.py +504 -0
  248. package/dist/resources/extensions/voice/speech-recognizer.swift +154 -0
  249. package/dist/resources/skills/debug-like-expert/SKILL.md +231 -0
  250. package/dist/resources/skills/debug-like-expert/references/debugging-mindset.md +253 -0
  251. package/dist/resources/skills/debug-like-expert/references/hypothesis-testing.md +373 -0
  252. package/dist/resources/skills/debug-like-expert/references/investigation-techniques.md +337 -0
  253. package/dist/resources/skills/debug-like-expert/references/verification-patterns.md +425 -0
  254. package/dist/resources/skills/debug-like-expert/references/when-to-research.md +361 -0
  255. package/dist/resources/skills/frontend-design/SKILL.md +45 -0
  256. package/dist/resources/skills/github-workflows/SKILL.md +92 -0
  257. package/dist/resources/skills/github-workflows/references/gh/SKILL.md +255 -0
  258. package/dist/resources/skills/github-workflows/references/gh/references/issue-stories.md +204 -0
  259. package/dist/resources/skills/github-workflows/references/gh/references/labels.md +170 -0
  260. package/dist/resources/skills/github-workflows/references/gh/references/milestones.md +158 -0
  261. package/dist/resources/skills/github-workflows/references/gh/references/projects-v2.md +177 -0
  262. package/dist/resources/skills/github-workflows/references/gh/scripts/experiment_cleanup.py +191 -0
  263. package/dist/resources/skills/github-workflows/references/gh/scripts/github_project_setup.py +799 -0
  264. package/dist/resources/skills/github-workflows/references/gh/tests/__init__.py +0 -0
  265. package/dist/resources/skills/github-workflows/references/gh/tests/test_github_project_setup.py +608 -0
  266. package/dist/resources/skills/swiftui/SKILL.md +208 -0
  267. package/dist/resources/skills/swiftui/references/animations.md +921 -0
  268. package/dist/resources/skills/swiftui/references/architecture.md +1561 -0
  269. package/dist/resources/skills/swiftui/references/layout-system.md +1186 -0
  270. package/dist/resources/skills/swiftui/references/navigation.md +1492 -0
  271. package/dist/resources/skills/swiftui/references/networking-async.md +214 -0
  272. package/dist/resources/skills/swiftui/references/performance.md +1706 -0
  273. package/dist/resources/skills/swiftui/references/platform-integration.md +204 -0
  274. package/dist/resources/skills/swiftui/references/state-management.md +1443 -0
  275. package/dist/resources/skills/swiftui/references/swiftdata.md +297 -0
  276. package/dist/resources/skills/swiftui/references/testing-debugging.md +247 -0
  277. package/dist/resources/skills/swiftui/references/uikit-appkit-interop.md +218 -0
  278. package/dist/resources/skills/swiftui/workflows/add-feature.md +191 -0
  279. package/dist/resources/skills/swiftui/workflows/build-new-app.md +311 -0
  280. package/dist/resources/skills/swiftui/workflows/debug-swiftui.md +192 -0
  281. package/dist/resources/skills/swiftui/workflows/optimize-performance.md +197 -0
  282. package/dist/resources/skills/swiftui/workflows/ship-app.md +203 -0
  283. package/dist/resources/skills/swiftui/workflows/write-tests.md +235 -0
  284. package/dist/wizard.js +1 -0
  285. package/package.json +8 -6
  286. package/packages/native/dist/fd/index.d.ts +1 -0
  287. package/packages/native/dist/fd/index.js +1 -0
  288. package/packages/native/dist/grep/index.d.ts +2 -1
  289. package/packages/native/dist/grep/index.js +1 -0
  290. package/packages/native/src/__tests__/fd.test.mjs +35 -0
  291. package/packages/native/src/__tests__/grep.test.mjs +26 -9
  292. package/packages/native/src/fd/index.ts +1 -0
  293. package/packages/native/src/grep/index.ts +3 -2
  294. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  295. package/packages/pi-agent-core/dist/agent-loop.js +169 -55
  296. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  297. package/packages/pi-agent-core/dist/agent.d.ts +13 -1
  298. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  299. package/packages/pi-agent-core/dist/agent.js +16 -0
  300. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  301. package/packages/pi-agent-core/dist/types.d.ts +91 -1
  302. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  303. package/packages/pi-agent-core/dist/types.js.map +1 -1
  304. package/packages/pi-agent-core/src/agent-loop.ts +273 -63
  305. package/packages/pi-agent-core/src/agent.ts +24 -0
  306. package/packages/pi-agent-core/src/types.ts +98 -0
  307. package/packages/pi-ai/dist/env-api-keys.js +2 -0
  308. package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
  309. package/packages/pi-ai/dist/models.generated.d.ts +314 -0
  310. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  311. package/packages/pi-ai/dist/models.generated.js +236 -0
  312. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  313. package/packages/pi-ai/dist/providers/google-gemini-cli.d.ts.map +1 -1
  314. package/packages/pi-ai/dist/providers/google-gemini-cli.js +6 -0
  315. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  316. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  317. package/packages/pi-ai/dist/providers/openai-completions.js +2 -0
  318. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  319. package/packages/pi-ai/dist/types.d.ts +1 -1
  320. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  321. package/packages/pi-ai/dist/types.js.map +1 -1
  322. package/packages/pi-ai/src/env-api-keys.ts +2 -0
  323. package/packages/pi-ai/src/models.generated.ts +236 -0
  324. package/packages/pi-ai/src/providers/google-gemini-cli.ts +8 -0
  325. package/packages/pi-ai/src/providers/openai-completions.ts +3 -0
  326. package/packages/pi-ai/src/types.ts +2 -1
  327. package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
  328. package/packages/pi-coding-agent/dist/cli/args.js +1 -0
  329. package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
  330. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +26 -0
  331. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  332. package/packages/pi-coding-agent/dist/core/agent-session.js +137 -22
  333. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  334. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +20 -0
  335. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  336. package/packages/pi-coding-agent/dist/core/auth-storage.js +43 -0
  337. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  338. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts +51 -0
  339. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -0
  340. package/packages/pi-coding-agent/dist/core/fallback-resolver.js +119 -0
  341. package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -0
  342. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.d.ts +2 -0
  343. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.d.ts.map +1 -0
  344. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +183 -0
  345. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -0
  346. package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
  347. package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
  348. package/packages/pi-coding-agent/dist/core/index.js +1 -0
  349. package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
  350. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  351. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
  352. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  353. package/packages/pi-coding-agent/dist/core/session-manager.d.ts +12 -1
  354. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  355. package/packages/pi-coding-agent/dist/core/session-manager.js +37 -1
  356. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  357. package/packages/pi-coding-agent/dist/core/session-manager.test.d.ts +2 -0
  358. package/packages/pi-coding-agent/dist/core/session-manager.test.d.ts.map +1 -0
  359. package/packages/pi-coding-agent/dist/core/session-manager.test.js +61 -0
  360. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -0
  361. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
  362. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  363. package/packages/pi-coding-agent/dist/core/settings-manager.js +47 -0
  364. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  365. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  366. package/packages/pi-coding-agent/dist/core/tools/find.js +1 -0
  367. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  368. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  369. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +6 -15
  370. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  371. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +18 -1
  372. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  373. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +46 -4
  374. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  375. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  376. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +25 -2
  377. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  378. package/packages/pi-coding-agent/src/cli/args.ts +1 -0
  379. package/packages/pi-coding-agent/src/core/agent-session.ts +167 -22
  380. package/packages/pi-coding-agent/src/core/auth-storage.ts +45 -0
  381. package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +229 -0
  382. package/packages/pi-coding-agent/src/core/fallback-resolver.ts +165 -0
  383. package/packages/pi-coding-agent/src/core/index.ts +1 -0
  384. package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
  385. package/packages/pi-coding-agent/src/core/session-manager.test.ts +65 -0
  386. package/packages/pi-coding-agent/src/core/session-manager.ts +51 -1
  387. package/packages/pi-coding-agent/src/core/settings-manager.ts +66 -0
  388. package/packages/pi-coding-agent/src/core/tools/find.ts +1 -0
  389. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +6 -16
  390. package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +49 -4
  391. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +28 -2
  392. package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
  393. package/packages/pi-tui/dist/autocomplete.js +3 -4
  394. package/packages/pi-tui/dist/autocomplete.js.map +1 -1
  395. package/packages/pi-tui/dist/components/editor.d.ts +7 -0
  396. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  397. package/packages/pi-tui/dist/components/editor.js +57 -50
  398. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  399. package/packages/pi-tui/src/autocomplete.ts +3 -5
  400. package/packages/pi-tui/src/components/editor.ts +70 -49
  401. package/pkg/dist/core/export-html/ansi-to-html.d.ts +22 -0
  402. package/pkg/dist/core/export-html/ansi-to-html.d.ts.map +1 -0
  403. package/pkg/dist/core/export-html/ansi-to-html.js +249 -0
  404. package/pkg/dist/core/export-html/ansi-to-html.js.map +1 -0
  405. package/pkg/dist/core/export-html/index.d.ts +37 -0
  406. package/pkg/dist/core/export-html/index.d.ts.map +1 -0
  407. package/pkg/dist/core/export-html/index.js +223 -0
  408. package/pkg/dist/core/export-html/index.js.map +1 -0
  409. package/pkg/dist/core/export-html/template.css +971 -0
  410. package/pkg/dist/core/export-html/template.html +54 -0
  411. package/pkg/dist/core/export-html/template.js +1583 -0
  412. package/pkg/dist/core/export-html/tool-renderer.d.ts +38 -0
  413. package/pkg/dist/core/export-html/tool-renderer.d.ts.map +1 -0
  414. package/pkg/dist/core/export-html/tool-renderer.js +70 -0
  415. package/pkg/dist/core/export-html/tool-renderer.js.map +1 -0
  416. package/pkg/dist/core/export-html/vendor/highlight.min.js +1213 -0
  417. package/pkg/dist/core/export-html/vendor/marked.min.js +6 -0
  418. package/scripts/postinstall.js +30 -17
  419. package/src/resources/extensions/bg-shell/index.ts +51 -7
  420. package/src/resources/extensions/gsd/activity-log.ts +61 -14
  421. package/src/resources/extensions/gsd/auto.ts +288 -19
  422. package/src/resources/extensions/gsd/commands.ts +9 -3
  423. package/src/resources/extensions/gsd/dashboard-overlay.ts +55 -12
  424. package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -0
  425. package/src/resources/extensions/gsd/doctor.ts +60 -3
  426. package/src/resources/extensions/gsd/files.ts +45 -1
  427. package/src/resources/extensions/gsd/git-service.ts +46 -41
  428. package/src/resources/extensions/gsd/guided-flow.ts +81 -9
  429. package/src/resources/extensions/gsd/index.ts +62 -1
  430. package/src/resources/extensions/gsd/native-git-bridge.ts +181 -0
  431. package/src/resources/extensions/gsd/paths.ts +35 -4
  432. package/src/resources/extensions/gsd/post-unit-hooks.ts +449 -0
  433. package/src/resources/extensions/gsd/preferences.ts +232 -1
  434. package/src/resources/extensions/gsd/prompt-loader.ts +45 -3
  435. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  436. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -3
  437. package/src/resources/extensions/gsd/prompts/discuss.md +10 -8
  438. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
  439. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +3 -1
  440. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -1
  441. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
  442. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +3 -1
  443. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +4 -2
  444. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +3 -1
  445. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +3 -1
  446. package/src/resources/extensions/gsd/prompts/plan-milestone.md +9 -12
  447. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -3
  448. package/src/resources/extensions/gsd/prompts/queue.md +3 -1
  449. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  450. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  451. package/src/resources/extensions/gsd/state.ts +130 -18
  452. package/src/resources/extensions/gsd/templates/context.md +1 -1
  453. package/src/resources/extensions/gsd/templates/state.md +3 -3
  454. package/src/resources/extensions/gsd/tests/activity-log-save.test.ts +127 -0
  455. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +5 -1
  456. package/src/resources/extensions/gsd/tests/doctor.test.ts +115 -1
  457. package/src/resources/extensions/gsd/tests/draft-promotion.test.ts +6 -2
  458. package/src/resources/extensions/gsd/tests/git-service.test.ts +35 -35
  459. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +8 -8
  460. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +4 -1
  461. package/src/resources/extensions/gsd/tests/network-error-fallback.test.ts +54 -0
  462. package/src/resources/extensions/gsd/tests/orphaned-branch.test.ts +5 -5
  463. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +297 -0
  464. package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +226 -0
  465. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +12 -0
  466. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +6 -0
  467. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +4 -4
  468. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +4 -4
  469. package/src/resources/extensions/gsd/tests/worktree.test.ts +19 -19
  470. package/src/resources/extensions/gsd/types.ts +109 -0
  471. package/src/resources/extensions/gsd/worktree-manager.ts +72 -13
  472. package/src/resources/extensions/gsd/worktree.ts +5 -4
  473. package/src/resources/extensions/search-the-web/command-search-provider.ts +8 -4
  474. package/src/resources/extensions/search-the-web/native-search.ts +32 -23
  475. package/src/resources/extensions/search-the-web/provider.ts +19 -2
  476. package/src/resources/extensions/search-the-web/tool-fetch-page.ts +62 -0
  477. package/src/resources/extensions/search-the-web/tool-llm-context.ts +62 -3
  478. package/src/resources/extensions/search-the-web/tool-search.ts +62 -3
  479. package/src/resources/extensions/shared/bundled-extension-paths.ts +11 -0
  480. package/src/resources/extensions/subagent/index.ts +2 -1
  481. package/src/resources/skills/github-workflows/SKILL.md +5 -0
  482. package/dist/resources/extensions/gsd/git-service.d.ts +0 -225
  483. package/dist/resources/extensions/gsd/git-service.js +0 -756
  484. package/dist/resources/extensions/gsd/preferences.d.ts +0 -122
  485. package/dist/resources/extensions/gsd/preferences.js +0 -616
  486. package/dist/resources/extensions/gsd/worktree.d.ts +0 -106
  487. package/dist/resources/extensions/remote-questions/config.d.ts +0 -14
  488. package/dist/resources/extensions/remote-questions/config.js +0 -68
  489. package/dist/resources/extensions/remote-questions/discord-adapter.d.ts +0 -17
  490. package/dist/resources/extensions/remote-questions/discord-adapter.js +0 -118
  491. package/dist/resources/extensions/remote-questions/format.d.ts +0 -38
  492. package/dist/resources/extensions/remote-questions/format.js +0 -119
  493. package/dist/resources/extensions/remote-questions/manager.d.ts +0 -23
  494. package/dist/resources/extensions/remote-questions/manager.js +0 -161
  495. package/dist/resources/extensions/remote-questions/remote-command.d.ts +0 -6
  496. package/dist/resources/extensions/remote-questions/remote-command.js +0 -358
  497. package/dist/resources/extensions/remote-questions/slack-adapter.d.ts +0 -15
  498. package/dist/resources/extensions/remote-questions/slack-adapter.js +0 -82
  499. package/dist/resources/extensions/remote-questions/status.d.ts +0 -9
  500. package/dist/resources/extensions/remote-questions/status.js +0 -25
  501. package/dist/resources/extensions/remote-questions/store.d.ts +0 -11
  502. package/dist/resources/extensions/remote-questions/store.js +0 -66
  503. package/dist/resources/extensions/remote-questions/types.d.ts +0 -68
  504. package/dist/resources/extensions/remote-questions/types.js +0 -4
@@ -0,0 +1,735 @@
1
+ /**
2
+ * GSD Extension — /gsd
3
+ *
4
+ * One command, one wizard. Reads state from disk, shows contextual options,
5
+ * dispatches through GSD-WORKFLOW.md. The LLM does the rest.
6
+ *
7
+ * Auto-mode: /gsd auto loops fresh sessions until milestone complete.
8
+ *
9
+ * Commands:
10
+ * /gsd — contextual wizard (smart entry point)
11
+ * /gsd auto — start auto-mode (fresh session per unit)
12
+ * /gsd stop — stop auto-mode gracefully
13
+ * /gsd status — progress dashboard
14
+ *
15
+ * Hooks:
16
+ * before_agent_start — inject GSD system context for GSD projects
17
+ * agent_end — auto-mode advancement
18
+ * session_before_compact — save continue.md OR block during auto
19
+ */
20
+
21
+ import type {
22
+ ExtensionAPI,
23
+ ExtensionCommandContext,
24
+ ExtensionContext,
25
+ } from "@gsd/pi-coding-agent";
26
+ import { createBashTool, createWriteTool, createReadTool, createEditTool, isToolCallEventType } from "@gsd/pi-coding-agent";
27
+
28
+ import { registerGSDCommand } from "./commands.js";
29
+ import { registerExitCommand } from "./exit-command.js";
30
+ import { registerWorktreeCommand, getWorktreeOriginalCwd, getActiveWorktreeName } from "./worktree-command.js";
31
+ import { saveFile, formatContinue, loadFile, parseContinue, parseSummary } from "./files.js";
32
+ import { loadPrompt } from "./prompt-loader.js";
33
+ import { deriveState } from "./state.js";
34
+ import { isAutoActive, isAutoPaused, handleAgentEnd, pauseAuto, getAutoDashboardData } from "./auto.js";
35
+ import { saveActivityLog } from "./activity-log.js";
36
+ import { checkAutoStartAfterDiscuss, getDiscussionMilestoneId } from "./guided-flow.js";
37
+ import { GSDDashboardOverlay } from "./dashboard-overlay.js";
38
+ import {
39
+ loadEffectiveGSDPreferences,
40
+ renderPreferencesForSystemPrompt,
41
+ resolveAllSkillReferences,
42
+ resolveModelWithFallbacksForUnit,
43
+ getNextFallbackModel,
44
+ } from "./preferences.js";
45
+ import { hasSkillSnapshot, detectNewSkills, formatSkillsXml } from "./skill-discovery.js";
46
+ import {
47
+ resolveSlicePath, resolveSliceFile, resolveTaskFile, resolveTaskFiles, resolveTasksDir,
48
+ relSliceFile, relSlicePath, relTaskFile,
49
+ buildSliceFileName, buildMilestoneFileName, gsdRoot, resolveMilestonePath,
50
+ } from "./paths.js";
51
+ import { Key } from "@gsd/pi-tui";
52
+ import { join } from "node:path";
53
+ import { existsSync } from "node:fs";
54
+ import { shortcutDesc } from "../shared/terminal.js";
55
+ import { Text } from "@gsd/pi-tui";
56
+
57
+ // ── Depth verification state ──────────────────────────────────────────────
58
+ let depthVerificationDone = false;
59
+
60
+ export function isDepthVerified(): boolean {
61
+ return depthVerificationDone;
62
+ }
63
+
64
+ // ── Write-gate: block CONTEXT.md writes during discussion without depth verification ──
65
+ const MILESTONE_CONTEXT_RE = /M\d+(?:-[a-z0-9]{6})?-CONTEXT\.md$/;
66
+
67
+ export function shouldBlockContextWrite(
68
+ toolName: string,
69
+ inputPath: string,
70
+ milestoneId: string | null,
71
+ depthVerified: boolean,
72
+ ): { block: boolean; reason?: string } {
73
+ if (toolName !== "write") return { block: false };
74
+ if (!milestoneId) return { block: false };
75
+ if (!MILESTONE_CONTEXT_RE.test(inputPath)) return { block: false };
76
+ if (depthVerified) return { block: false };
77
+ return {
78
+ block: true,
79
+ reason: `Blocked: Cannot write to milestone CONTEXT.md during discussion phase without depth verification. Call ask_user_questions with question id "depth_verification" first to confirm discussion depth before writing context.`,
80
+ };
81
+ }
82
+
83
+ // ── ASCII logo ────────────────────────────────────────────────────────────
84
+ const GSD_LOGO_LINES = [
85
+ " ██████╗ ███████╗██████╗ ",
86
+ " ██╔════╝ ██╔════╝██╔══██╗",
87
+ " ██║ ███╗███████╗██║ ██║",
88
+ " ██║ ██║╚════██║██║ ██║",
89
+ " ╚██████╔╝███████║██████╔╝",
90
+ " ╚═════╝ ╚══════╝╚═════╝ ",
91
+ ];
92
+
93
+ export default function (pi: ExtensionAPI) {
94
+ registerGSDCommand(pi);
95
+ registerWorktreeCommand(pi);
96
+ registerExitCommand(pi);
97
+
98
+ // ── /kill — immediate exit (bypass cleanup) ─────────────────────────────
99
+ pi.registerCommand("kill", {
100
+ description: "Exit GSD immediately (no cleanup)",
101
+ handler: async (_args: string, _ctx: ExtensionCommandContext) => {
102
+ process.exit(0);
103
+ },
104
+ });
105
+
106
+ // ── Dynamic-cwd bash tool with default timeout ────────────────────────
107
+ // The built-in bash tool captures cwd at startup. This replacement uses
108
+ // a spawnHook to read process.cwd() dynamically so that process.chdir()
109
+ // (used by /worktree switch) propagates to shell commands.
110
+ //
111
+ // The upstream SDK's bash tool has no default timeout — if the LLM omits
112
+ // the timeout parameter, commands run indefinitely, causing hangs on
113
+ // Windows where process killing is unreliable (see #40). We wrap execute
114
+ // to inject a 120-second default when no timeout is provided.
115
+ const DEFAULT_BASH_TIMEOUT_SECS = 120;
116
+ const baseBash = createBashTool(process.cwd(), {
117
+ spawnHook: (ctx) => ({ ...ctx, cwd: process.cwd() }),
118
+ });
119
+ const dynamicBash = {
120
+ ...baseBash,
121
+ execute: async (
122
+ toolCallId: string,
123
+ params: { command: string; timeout?: number },
124
+ signal?: AbortSignal,
125
+ onUpdate?: any,
126
+ ctx?: any,
127
+ ) => {
128
+ const paramsWithTimeout = {
129
+ ...params,
130
+ timeout: params.timeout ?? DEFAULT_BASH_TIMEOUT_SECS,
131
+ };
132
+ return (baseBash as any).execute(toolCallId, paramsWithTimeout, signal, onUpdate, ctx);
133
+ },
134
+ };
135
+ pi.registerTool(dynamicBash as any);
136
+
137
+ // ── Dynamic-cwd file tools (write, read, edit) ────────────────────────
138
+ // The built-in file tools capture cwd at startup. When process.chdir()
139
+ // moves us into a worktree, relative paths still resolve against the
140
+ // original launch directory. These replacements delegate to freshly-
141
+ // created tools on each call so that process.cwd() is read dynamically.
142
+ const baseWrite = createWriteTool(process.cwd());
143
+ const dynamicWrite = {
144
+ ...baseWrite,
145
+ execute: async (
146
+ toolCallId: string,
147
+ params: { path: string; content: string },
148
+ signal?: AbortSignal,
149
+ onUpdate?: any,
150
+ ctx?: any,
151
+ ) => {
152
+ const fresh = createWriteTool(process.cwd());
153
+ return (fresh as any).execute(toolCallId, params, signal, onUpdate, ctx);
154
+ },
155
+ };
156
+ pi.registerTool(dynamicWrite as any);
157
+
158
+ const baseRead = createReadTool(process.cwd());
159
+ const dynamicRead = {
160
+ ...baseRead,
161
+ execute: async (
162
+ toolCallId: string,
163
+ params: { path: string; offset?: number; limit?: number },
164
+ signal?: AbortSignal,
165
+ onUpdate?: any,
166
+ ctx?: any,
167
+ ) => {
168
+ const fresh = createReadTool(process.cwd());
169
+ return (fresh as any).execute(toolCallId, params, signal, onUpdate, ctx);
170
+ },
171
+ };
172
+ pi.registerTool(dynamicRead as any);
173
+
174
+ const baseEdit = createEditTool(process.cwd());
175
+ const dynamicEdit = {
176
+ ...baseEdit,
177
+ execute: async (
178
+ toolCallId: string,
179
+ params: { path: string; oldText: string; newText: string },
180
+ signal?: AbortSignal,
181
+ onUpdate?: any,
182
+ ctx?: any,
183
+ ) => {
184
+ const fresh = createEditTool(process.cwd());
185
+ return (fresh as any).execute(toolCallId, params, signal, onUpdate, ctx);
186
+ },
187
+ };
188
+ pi.registerTool(dynamicEdit as any);
189
+
190
+ // ── session_start: render branded GSD header + remote channel status ──
191
+ pi.on("session_start", async (_event, ctx) => {
192
+ // Theme access throws in RPC mode (no TUI) — header is decorative, skip it
193
+ try {
194
+ const theme = ctx.ui.theme;
195
+ const version = process.env.GSD_VERSION || "0.0.0";
196
+
197
+ const logoText = GSD_LOGO_LINES.map((line) => theme.fg("accent", line)).join("\n");
198
+ const titleLine = ` ${theme.bold("Get Shit Done")} ${theme.fg("dim", `v${version}`)}`;
199
+
200
+ const headerContent = `${logoText}\n${titleLine}`;
201
+ ctx.ui.setHeader((_ui, _theme) => new Text(headerContent, 1, 0));
202
+ } catch {
203
+ // RPC mode — no TUI, skip header rendering
204
+ }
205
+
206
+ // Notify remote questions status if configured
207
+ try {
208
+ const [{ getRemoteConfigStatus }, { getLatestPromptSummary }] = await Promise.all([
209
+ import("../remote-questions/config.js"),
210
+ import("../remote-questions/status.js"),
211
+ ]);
212
+ const status = getRemoteConfigStatus();
213
+ const latest = getLatestPromptSummary();
214
+ if (!status.includes("not configured")) {
215
+ const suffix = latest ? `\nLast remote prompt: ${latest.id} (${latest.status})` : "";
216
+ ctx.ui.notify(`${status}${suffix}`, status.includes("disabled") ? "warning" : "info");
217
+ }
218
+ } catch {
219
+ // Remote questions module not available — ignore
220
+ }
221
+ });
222
+
223
+ // ── Ctrl+Alt+G shortcut — GSD dashboard overlay ────────────────────────
224
+ pi.registerShortcut(Key.ctrlAlt("g"), {
225
+ description: shortcutDesc("Open GSD dashboard", "/gsd status"),
226
+ handler: async (ctx) => {
227
+ // Only show if .gsd/ exists
228
+ if (!existsSync(join(process.cwd(), ".gsd"))) {
229
+ ctx.ui.notify("No .gsd/ directory found. Run /gsd to start.", "info");
230
+ return;
231
+ }
232
+
233
+ await ctx.ui.custom<void>(
234
+ (tui, theme, _kb, done) => {
235
+ return new GSDDashboardOverlay(tui, theme, () => done());
236
+ },
237
+ {
238
+ overlay: true,
239
+ overlayOptions: {
240
+ width: "90%",
241
+ minWidth: 80,
242
+ maxHeight: "92%",
243
+ anchor: "center",
244
+ },
245
+ },
246
+ );
247
+ },
248
+ });
249
+
250
+ // ── before_agent_start: inject GSD contract into true system prompt ─────
251
+ pi.on("before_agent_start", async (event, ctx: ExtensionContext) => {
252
+ if (!existsSync(join(process.cwd(), ".gsd"))) return;
253
+
254
+ const systemContent = loadPrompt("system");
255
+ const loadedPreferences = loadEffectiveGSDPreferences();
256
+ let preferenceBlock = "";
257
+ if (loadedPreferences) {
258
+ const cwd = process.cwd();
259
+ const report = resolveAllSkillReferences(loadedPreferences.preferences, cwd);
260
+ preferenceBlock = `\n\n${renderPreferencesForSystemPrompt(loadedPreferences.preferences, report.resolutions)}`;
261
+
262
+ // Emit warnings for unresolved skill references
263
+ if (report.warnings.length > 0) {
264
+ ctx.ui.notify(
265
+ `GSD skill preferences: ${report.warnings.length} unresolved skill${report.warnings.length === 1 ? "" : "s"}: ${report.warnings.join(", ")}`,
266
+ "warning",
267
+ );
268
+ }
269
+ }
270
+
271
+ // Detect skills installed during this auto-mode session
272
+ let newSkillsBlock = "";
273
+ if (hasSkillSnapshot()) {
274
+ const newSkills = detectNewSkills();
275
+ if (newSkills.length > 0) {
276
+ newSkillsBlock = formatSkillsXml(newSkills);
277
+ }
278
+ }
279
+
280
+ const injection = await buildGuidedExecuteContextInjection(event.prompt, process.cwd());
281
+
282
+ // Worktree context — override the static CWD in the system prompt
283
+ let worktreeBlock = "";
284
+ const worktreeName = getActiveWorktreeName();
285
+ const worktreeMainCwd = getWorktreeOriginalCwd();
286
+ if (worktreeName && worktreeMainCwd) {
287
+ worktreeBlock = [
288
+ "",
289
+ "",
290
+ "[WORKTREE CONTEXT — OVERRIDES CURRENT WORKING DIRECTORY ABOVE]",
291
+ `IMPORTANT: Ignore the "Current working directory" shown earlier in this prompt.`,
292
+ `The actual current working directory is: ${process.cwd()}`,
293
+ "",
294
+ `You are working inside a GSD worktree.`,
295
+ `- Worktree name: ${worktreeName}`,
296
+ `- Worktree path (this is the real cwd): ${process.cwd()}`,
297
+ `- Main project: ${worktreeMainCwd}`,
298
+ `- Branch: worktree/${worktreeName}`,
299
+ "",
300
+ "All file operations, bash commands, and GSD state resolve against the worktree path above.",
301
+ "Use /worktree merge to merge changes back. Use /worktree return to switch back to the main tree.",
302
+ ].join("\n");
303
+ }
304
+
305
+ return {
306
+ systemPrompt: `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${newSkillsBlock}${worktreeBlock}`,
307
+ ...(injection
308
+ ? {
309
+ message: {
310
+ customType: "gsd-guided-context",
311
+ content: injection,
312
+ display: false,
313
+ },
314
+ }
315
+ : {}),
316
+ };
317
+ });
318
+
319
+ // ── agent_end: auto-mode advancement or auto-start after discuss ───────────
320
+ pi.on("agent_end", async (event, ctx: ExtensionContext) => {
321
+ // If discuss phase just finished, start auto-mode
322
+ if (checkAutoStartAfterDiscuss()) {
323
+ depthVerificationDone = false;
324
+ return;
325
+ }
326
+
327
+ // If auto-mode is already running, advance to next unit
328
+ if (!isAutoActive()) return;
329
+
330
+ // If the agent was aborted (user pressed Escape) or hit a provider
331
+ // error (fetch failure, rate limit, etc.), pause auto-mode instead of
332
+ // advancing. This preserves the conversation so the user can inspect
333
+ // what happened, interact with the agent, or resume.
334
+ const lastMsg = event.messages[event.messages.length - 1];
335
+ if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "aborted") {
336
+ await pauseAuto(ctx, pi);
337
+ return;
338
+ }
339
+ if (lastMsg && "stopReason" in lastMsg && lastMsg.stopReason === "error") {
340
+ const errorDetail =
341
+ "errorMessage" in lastMsg && lastMsg.errorMessage
342
+ ? `: ${lastMsg.errorMessage}`
343
+ : "";
344
+
345
+ const dash = getAutoDashboardData();
346
+ if (dash.currentUnit) {
347
+ const modelConfig = resolveModelWithFallbacksForUnit(dash.currentUnit.type);
348
+ if (modelConfig && modelConfig.fallbacks.length > 0) {
349
+ const availableModels = ctx.modelRegistry.getAvailable();
350
+ const currentModelId = ctx.model?.id;
351
+
352
+ const nextModelId = getNextFallbackModel(currentModelId, modelConfig);
353
+
354
+ if (nextModelId) {
355
+ let modelToSet;
356
+ const slashIdx = nextModelId.indexOf("/");
357
+ if (slashIdx !== -1) {
358
+ const provider = nextModelId.substring(0, slashIdx);
359
+ const id = nextModelId.substring(slashIdx + 1);
360
+ modelToSet = availableModels.find(
361
+ m => m.provider.toLowerCase() === provider.toLowerCase()
362
+ && m.id.toLowerCase() === id.toLowerCase()
363
+ );
364
+ } else {
365
+ const currentProvider = ctx.model?.provider;
366
+ const exactProviderMatch = availableModels.find(
367
+ m => m.id === nextModelId && m.provider === currentProvider
368
+ );
369
+ modelToSet = exactProviderMatch ?? availableModels.find(m => m.id === nextModelId);
370
+ }
371
+
372
+ if (modelToSet) {
373
+ const ok = await pi.setModel(modelToSet, { persist: false });
374
+ if (ok) {
375
+ ctx.ui.notify(`Model error${errorDetail}. Switched to fallback: ${nextModelId} and resuming.`, "warning");
376
+ // Trigger a generic "Continue execution" to resume the task since the previous attempt failed
377
+ pi.sendMessage(
378
+ { customType: "gsd-auto-timeout-recovery", content: "Continue execution.", display: false },
379
+ { triggerTurn: true }
380
+ );
381
+ return;
382
+ }
383
+ }
384
+ }
385
+ }
386
+ }
387
+
388
+ (ctx as any).log(`Auto-mode paused due to provider error${errorDetail}`);
389
+ await pauseAuto(ctx, pi);
390
+ return;
391
+ }
392
+
393
+ try {
394
+ await handleAgentEnd(ctx, pi);
395
+ } catch (err) {
396
+ // Safety net: if handleAgentEnd throws despite its internal try-catch,
397
+ // ensure auto-mode stops gracefully instead of silently stalling (#381).
398
+ const message = err instanceof Error ? err.message : String(err);
399
+ ctx.ui.notify(
400
+ `Auto-mode error in agent_end handler: ${message}. Stopping auto-mode.`,
401
+ "error",
402
+ );
403
+ try {
404
+ await pauseAuto(ctx, pi);
405
+ } catch {
406
+ // Last resort — at least log
407
+ }
408
+ }
409
+ });
410
+
411
+ // ── session_before_compact ────────────────────────────────────────────────
412
+ pi.on("session_before_compact", async (_event, _ctx: ExtensionContext) => {
413
+ // Block compaction during auto-mode — each unit is a fresh session
414
+ // Also block during paused state — context is valuable for the user
415
+ if (isAutoActive() || isAutoPaused()) {
416
+ return { cancel: true };
417
+ }
418
+
419
+ const basePath = process.cwd();
420
+ const state = await deriveState(basePath);
421
+
422
+ // Only save continue.md if we're actively executing a task
423
+ if (!state.activeMilestone || !state.activeSlice || !state.activeTask) return;
424
+ if (state.phase !== "executing") return;
425
+
426
+ const sDir = resolveSlicePath(basePath, state.activeMilestone.id, state.activeSlice.id);
427
+ if (!sDir) return;
428
+
429
+ // Check for existing continue file (new naming or legacy)
430
+ const existingFile = resolveSliceFile(basePath, state.activeMilestone.id, state.activeSlice.id, "CONTINUE");
431
+ if (existingFile && await loadFile(existingFile)) return;
432
+ const legacyContinue = join(sDir, "continue.md");
433
+ if (await loadFile(legacyContinue)) return;
434
+
435
+ const continuePath = join(sDir, buildSliceFileName(state.activeSlice.id, "CONTINUE"));
436
+
437
+ const continueData = {
438
+ frontmatter: {
439
+ milestone: state.activeMilestone.id,
440
+ slice: state.activeSlice.id,
441
+ task: state.activeTask.id,
442
+ step: 0,
443
+ totalSteps: 0,
444
+ status: "compacted" as const,
445
+ savedAt: new Date().toISOString(),
446
+ },
447
+ completedWork: `Task ${state.activeTask.id} (${state.activeTask.title}) was in progress when compaction occurred.`,
448
+ remainingWork: "Check the task plan for remaining steps.",
449
+ decisions: "Check task summary files for prior decisions.",
450
+ context: "Session was auto-compacted by Pi. Resume with /gsd.",
451
+ nextAction: `Resume task ${state.activeTask.id}: ${state.activeTask.title}.`,
452
+ };
453
+
454
+ await saveFile(continuePath, formatContinue(continueData));
455
+ });
456
+
457
+ // ── session_shutdown: save activity log on Ctrl+C / SIGTERM ─────────────
458
+ pi.on("session_shutdown", async (_event, ctx: ExtensionContext) => {
459
+ if (!isAutoActive() && !isAutoPaused()) return;
460
+
461
+ // Save the current session — the lock file stays on disk
462
+ // so the next /gsd auto knows it was interrupted
463
+ const dash = getAutoDashboardData();
464
+ if (dash.currentUnit) {
465
+ saveActivityLog(ctx, dash.basePath, dash.currentUnit.type, dash.currentUnit.id);
466
+ }
467
+ });
468
+
469
+ // ── tool_call: block CONTEXT.md writes during discussion without depth verification ──
470
+ pi.on("tool_call", async (event) => {
471
+ if (!isToolCallEventType("write", event)) return;
472
+ const result = shouldBlockContextWrite(
473
+ event.toolName,
474
+ event.input.path,
475
+ getDiscussionMilestoneId(),
476
+ isDepthVerified(),
477
+ );
478
+ if (result.block) return result;
479
+ });
480
+
481
+ // ── tool_result: persist discussion exchanges & detect depth gate ──────
482
+ pi.on("tool_result", async (event) => {
483
+ if (event.toolName !== "ask_user_questions") return;
484
+
485
+ const milestoneId = getDiscussionMilestoneId();
486
+ if (!milestoneId) return;
487
+
488
+ const details = event.details as any;
489
+ if (details?.cancelled || !details?.response) return;
490
+
491
+ // ── Depth gate detection ──────────────────────────────────────────
492
+ const questions: any[] = (event.input as any)?.questions ?? [];
493
+ for (const q of questions) {
494
+ if (typeof q.id === "string" && q.id.includes("depth_verification")) {
495
+ depthVerificationDone = true;
496
+ break;
497
+ }
498
+ }
499
+
500
+ // ── Persist exchange to DISCUSSION.md ──────────────────────────────
501
+ const basePath = process.cwd();
502
+ const milestoneDir = resolveMilestonePath(basePath, milestoneId);
503
+ if (!milestoneDir) return;
504
+
505
+ const fileName = buildMilestoneFileName(milestoneId, "DISCUSSION");
506
+ const discussionPath = join(milestoneDir, fileName);
507
+ const timestamp = new Date().toISOString();
508
+
509
+ // Format exchange as markdown
510
+ const lines: string[] = [`## Exchange — ${timestamp}`, ""];
511
+
512
+ for (const q of questions) {
513
+ lines.push(`### ${q.header ?? "Question"}`);
514
+ lines.push("");
515
+ lines.push(q.question ?? "");
516
+ if (Array.isArray(q.options)) {
517
+ lines.push("");
518
+ for (const opt of q.options) {
519
+ lines.push(`- **${opt.label}** — ${opt.description ?? ""}`);
520
+ }
521
+ }
522
+
523
+ // Append user response for this question
524
+ const answer = details.response?.answers?.[q.id];
525
+ if (answer) {
526
+ lines.push("");
527
+ const selected = Array.isArray(answer.selected) ? answer.selected.join(", ") : answer.selected;
528
+ lines.push(`**Selected:** ${selected}`);
529
+ if (answer.notes) {
530
+ lines.push(`**Notes:** ${answer.notes}`);
531
+ }
532
+ }
533
+ lines.push("");
534
+ }
535
+
536
+ lines.push("---", "");
537
+
538
+ const newBlock = lines.join("\n");
539
+ const existing = await loadFile(discussionPath) ?? `# ${milestoneId} Discussion Log\n\n`;
540
+ await saveFile(discussionPath, existing + newBlock);
541
+ });
542
+ }
543
+
544
+ async function buildGuidedExecuteContextInjection(prompt: string, basePath: string): Promise<string | null> {
545
+ const executeMatch = prompt.match(/Execute the next task:\s+(T\d+)\s+\("([^"]+)"\)\s+in slice\s+(S\d+)\s+of milestone\s+(M\d+(?:-[a-z0-9]{6})?)/i);
546
+ if (executeMatch) {
547
+ const [, taskId, taskTitle, sliceId, milestoneId] = executeMatch;
548
+ return buildTaskExecutionContextInjection(basePath, milestoneId, sliceId, taskId, taskTitle);
549
+ }
550
+
551
+ const resumeMatch = prompt.match(/Resume interrupted work\.[\s\S]*?slice\s+(S\d+)\s+of milestone\s+(M\d+(?:-[a-z0-9]{6})?)/i);
552
+ if (resumeMatch) {
553
+ const [, sliceId, milestoneId] = resumeMatch;
554
+ const state = await deriveState(basePath);
555
+ if (
556
+ state.activeMilestone?.id === milestoneId &&
557
+ state.activeSlice?.id === sliceId &&
558
+ state.activeTask
559
+ ) {
560
+ return buildTaskExecutionContextInjection(
561
+ basePath,
562
+ milestoneId,
563
+ sliceId,
564
+ state.activeTask.id,
565
+ state.activeTask.title,
566
+ );
567
+ }
568
+ }
569
+
570
+ return null;
571
+ }
572
+
573
+ async function buildTaskExecutionContextInjection(
574
+ basePath: string,
575
+ milestoneId: string,
576
+ sliceId: string,
577
+ taskId: string,
578
+ taskTitle: string,
579
+ ): Promise<string> {
580
+ const taskPlanPath = resolveTaskFile(basePath, milestoneId, sliceId, taskId, "PLAN");
581
+ const taskPlanRelPath = relTaskFile(basePath, milestoneId, sliceId, taskId, "PLAN");
582
+ const taskPlanContent = taskPlanPath ? await loadFile(taskPlanPath) : null;
583
+ const taskPlanInline = taskPlanContent
584
+ ? [
585
+ "## Inlined Task Plan (authoritative local execution contract)",
586
+ `Source: \`${taskPlanRelPath}\``,
587
+ "",
588
+ taskPlanContent.trim(),
589
+ ].join("\n")
590
+ : [
591
+ "## Inlined Task Plan (authoritative local execution contract)",
592
+ `Task plan not found at dispatch time. Read \`${taskPlanRelPath}\` before executing.`,
593
+ ].join("\n");
594
+
595
+ const slicePlanPath = resolveSliceFile(basePath, milestoneId, sliceId, "PLAN");
596
+ const slicePlanRelPath = relSliceFile(basePath, milestoneId, sliceId, "PLAN");
597
+ const slicePlanContent = slicePlanPath ? await loadFile(slicePlanPath) : null;
598
+ const slicePlanExcerpt = extractSliceExecutionExcerpt(slicePlanContent, slicePlanRelPath);
599
+
600
+ const priorTaskLines = await buildCarryForwardLines(basePath, milestoneId, sliceId, taskId);
601
+ const resumeSection = await buildResumeSection(basePath, milestoneId, sliceId);
602
+
603
+ return [
604
+ "[GSD Guided Execute Context]",
605
+ "Use this injected context as startup context for guided task execution. Treat the inlined task plan as the authoritative local execution contract. Use source artifacts to verify details and run checks.",
606
+ "",
607
+ resumeSection,
608
+ "",
609
+ "## Carry-Forward Context",
610
+ ...priorTaskLines,
611
+ "",
612
+ taskPlanInline,
613
+ "",
614
+ slicePlanExcerpt,
615
+ "",
616
+ "## Backing Source Artifacts",
617
+ `- Slice plan: \`${slicePlanRelPath}\``,
618
+ `- Task plan source: \`${taskPlanRelPath}\``,
619
+ ].join("\n");
620
+ }
621
+
622
+ async function buildCarryForwardLines(
623
+ basePath: string,
624
+ milestoneId: string,
625
+ sliceId: string,
626
+ taskId: string,
627
+ ): Promise<string[]> {
628
+ const tDir = resolveTasksDir(basePath, milestoneId, sliceId);
629
+ if (!tDir) return ["- No prior task summaries in this slice."];
630
+
631
+ const currentNum = parseInt(taskId.replace(/^T/, ""), 10);
632
+ const sRel = relSlicePath(basePath, milestoneId, sliceId);
633
+ const summaryFiles = resolveTaskFiles(tDir, "SUMMARY")
634
+ .filter((file) => parseInt(file.replace(/^T/, ""), 10) < currentNum)
635
+ .sort();
636
+
637
+ if (summaryFiles.length === 0) return ["- No prior task summaries in this slice."];
638
+
639
+ const lines = await Promise.all(summaryFiles.map(async (file) => {
640
+ const absPath = join(tDir, file);
641
+ const content = await loadFile(absPath);
642
+ const relPath = `${sRel}/tasks/${file}`;
643
+ if (!content) return `- \`${relPath}\``;
644
+
645
+ const summary = parseSummary(content);
646
+ const provided = summary.frontmatter.provides.slice(0, 2).join("; ");
647
+ const decisions = summary.frontmatter.key_decisions.slice(0, 2).join("; ");
648
+ const patterns = summary.frontmatter.patterns_established.slice(0, 2).join("; ");
649
+ const diagnostics = extractMarkdownSection(content, "Diagnostics");
650
+
651
+ const parts = [summary.title || relPath];
652
+ if (summary.oneLiner) parts.push(summary.oneLiner);
653
+ if (provided) parts.push(`provides: ${provided}`);
654
+ if (decisions) parts.push(`decisions: ${decisions}`);
655
+ if (patterns) parts.push(`patterns: ${patterns}`);
656
+ if (diagnostics) parts.push(`diagnostics: ${oneLine(diagnostics)}`);
657
+
658
+ return `- \`${relPath}\` — ${parts.join(" | ")}`;
659
+ }));
660
+
661
+ return lines;
662
+ }
663
+
664
+ async function buildResumeSection(basePath: string, milestoneId: string, sliceId: string): Promise<string> {
665
+ const continueFile = resolveSliceFile(basePath, milestoneId, sliceId, "CONTINUE");
666
+ const legacyDir = resolveSlicePath(basePath, milestoneId, sliceId);
667
+ const legacyPath = legacyDir ? join(legacyDir, "continue.md") : null;
668
+ const continueContent = continueFile ? await loadFile(continueFile) : null;
669
+ const legacyContent = !continueContent && legacyPath ? await loadFile(legacyPath) : null;
670
+ const resolvedContent = continueContent ?? legacyContent;
671
+ const resolvedRelPath = continueContent
672
+ ? relSliceFile(basePath, milestoneId, sliceId, "CONTINUE")
673
+ : (legacyPath ? `${relSlicePath(basePath, milestoneId, sliceId)}/continue.md` : null);
674
+
675
+ if (!resolvedContent || !resolvedRelPath) {
676
+ return ["## Resume State", "- No continue file present. Start from the top of the task plan."].join("\n");
677
+ }
678
+
679
+ const cont = parseContinue(resolvedContent);
680
+ const lines = [
681
+ "## Resume State",
682
+ `Source: \`${resolvedRelPath}\``,
683
+ `- Status: ${cont.frontmatter.status || "in_progress"}`,
684
+ ];
685
+
686
+ if (cont.frontmatter.step && cont.frontmatter.totalSteps) {
687
+ lines.push(`- Progress: step ${cont.frontmatter.step} of ${cont.frontmatter.totalSteps}`);
688
+ }
689
+ if (cont.completedWork) lines.push(`- Completed: ${oneLine(cont.completedWork)}`);
690
+ if (cont.remainingWork) lines.push(`- Remaining: ${oneLine(cont.remainingWork)}`);
691
+ if (cont.decisions) lines.push(`- Decisions: ${oneLine(cont.decisions)}`);
692
+ if (cont.nextAction) lines.push(`- Next action: ${oneLine(cont.nextAction)}`);
693
+
694
+ return lines.join("\n");
695
+ }
696
+
697
+ function extractSliceExecutionExcerpt(content: string | null, relPath: string): string {
698
+ if (!content) {
699
+ return [
700
+ "## Slice Plan Excerpt",
701
+ `Slice plan not found at dispatch time. Read \`${relPath}\` before running slice-level verification.`,
702
+ ].join("\n");
703
+ }
704
+
705
+ const lines = content.split("\n");
706
+ const goalLine = lines.find((line) => line.startsWith("**Goal:**"))?.trim();
707
+ const demoLine = lines.find((line) => line.startsWith("**Demo:**"))?.trim();
708
+ const verification = extractMarkdownSection(content, "Verification");
709
+ const observability = extractMarkdownSection(content, "Observability / Diagnostics");
710
+
711
+ const parts = ["## Slice Plan Excerpt", `Source: \`${relPath}\``];
712
+ if (goalLine) parts.push(goalLine);
713
+ if (demoLine) parts.push(demoLine);
714
+ if (verification) parts.push("", "### Slice Verification", verification.trim());
715
+ if (observability) parts.push("", "### Slice Observability / Diagnostics", observability.trim());
716
+ return parts.join("\n");
717
+ }
718
+
719
+ function extractMarkdownSection(content: string, heading: string): string | null {
720
+ const match = new RegExp(`^## ${escapeRegExp(heading)}\\s*$`, "m").exec(content);
721
+ if (!match) return null;
722
+ const start = match.index + match[0].length;
723
+ const rest = content.slice(start);
724
+ const nextHeading = rest.match(/^##\s+/m);
725
+ const end = nextHeading?.index ?? rest.length;
726
+ return rest.slice(0, end).trim();
727
+ }
728
+
729
+ function escapeRegExp(value: string): string {
730
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
731
+ }
732
+
733
+ function oneLine(text: string): string {
734
+ return text.replace(/\s+/g, " ").trim();
735
+ }