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,469 @@
1
+ /**
2
+ * Tests for S02 Enhanced Collection TUI functions:
3
+ * - collectSecretsFromManifest() orchestrator categorization and flow
4
+ * - showSecretsSummary() render output
5
+ * - collectOneSecret() guidance rendering
6
+ *
7
+ * These tests import functions that don't exist yet (T02/T03 will build them).
8
+ * They are expected to fail until implementation is complete.
9
+ *
10
+ * Uses dynamic imports so individual tests fail with clear messages
11
+ * instead of the entire file crashing at import time.
12
+ */
13
+
14
+ import test from "node:test";
15
+ import assert from "node:assert/strict";
16
+ import { mkdirSync, writeFileSync, readFileSync, rmSync } from "node:fs";
17
+ import { join } from "node:path";
18
+ import { tmpdir } from "node:os";
19
+ import type { SecretsManifest, SecretsManifestEntry } from "../types.ts";
20
+
21
+ // Dynamic imports for files.ts functions to avoid cascading failure
22
+ // when paths.js isn't available (files.ts statically imports paths.js)
23
+ async function loadFilesExports(): Promise<{
24
+ formatSecretsManifest: (m: SecretsManifest) => string;
25
+ parseSecretsManifest: (content: string) => SecretsManifest;
26
+ }> {
27
+ const mod = await import("../files.ts");
28
+ return {
29
+ formatSecretsManifest: mod.formatSecretsManifest,
30
+ parseSecretsManifest: mod.parseSecretsManifest,
31
+ };
32
+ }
33
+
34
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
35
+
36
+ function makeTempDir(prefix: string): string {
37
+ const dir = join(tmpdir(), `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
38
+ mkdirSync(dir, { recursive: true });
39
+ return dir;
40
+ }
41
+
42
+ function makeManifest(entries: Partial<SecretsManifestEntry>[]): SecretsManifest {
43
+ return {
44
+ milestone: "M001",
45
+ generatedAt: "2026-03-12T00:00:00Z",
46
+ entries: entries.map((e) => ({
47
+ key: e.key ?? "TEST_KEY",
48
+ service: e.service ?? "TestService",
49
+ dashboardUrl: e.dashboardUrl ?? "",
50
+ guidance: e.guidance ?? [],
51
+ formatHint: e.formatHint ?? "",
52
+ status: e.status ?? "pending",
53
+ destination: e.destination ?? "dotenv",
54
+ })),
55
+ };
56
+ }
57
+
58
+ async function writeManifestFile(dir: string, manifest: SecretsManifest): Promise<string> {
59
+ const { formatSecretsManifest } = await loadFilesExports();
60
+ const milestoneDir = join(dir, ".gsd", "milestones", "M001");
61
+ mkdirSync(milestoneDir, { recursive: true });
62
+ const filePath = join(milestoneDir, "M001-SECRETS.md");
63
+ writeFileSync(filePath, formatSecretsManifest(manifest));
64
+ return filePath;
65
+ }
66
+
67
+ async function loadOrchestrator(): Promise<{
68
+ collectSecretsFromManifest: Function;
69
+ showSecretsSummary: Function;
70
+ }> {
71
+ const mod = await import("../../get-secrets-from-user.ts");
72
+ if (typeof mod.collectSecretsFromManifest !== "function") {
73
+ throw new Error("collectSecretsFromManifest is not exported from get-secrets-from-user.ts — T03 will implement this");
74
+ }
75
+ if (typeof mod.showSecretsSummary !== "function") {
76
+ throw new Error("showSecretsSummary is not exported from get-secrets-from-user.ts — T03 will implement this");
77
+ }
78
+ return {
79
+ collectSecretsFromManifest: mod.collectSecretsFromManifest,
80
+ showSecretsSummary: mod.showSecretsSummary,
81
+ };
82
+ }
83
+
84
+ async function loadGuidanceExport(): Promise<{ collectOneSecretWithGuidance: Function }> {
85
+ const mod = await import("../../get-secrets-from-user.ts");
86
+ if (typeof mod.collectOneSecretWithGuidance !== "function") {
87
+ throw new Error("collectOneSecretWithGuidance is not exported from get-secrets-from-user.ts — T02 will implement this");
88
+ }
89
+ return { collectOneSecretWithGuidance: mod.collectOneSecretWithGuidance };
90
+ }
91
+
92
+ // ─── collectSecretsFromManifest: categorization ───────────────────────────────
93
+
94
+ test("collectSecretsFromManifest: categorizes entries — pending keys need collection, existing keys are skipped", async () => {
95
+ const { collectSecretsFromManifest } = await loadOrchestrator();
96
+
97
+ const tmp = makeTempDir("manifest-collect");
98
+ const savedA = process.env.EXISTING_KEY_A;
99
+ try {
100
+ process.env.EXISTING_KEY_A = "already-set";
101
+
102
+ const manifest = makeManifest([
103
+ { key: "EXISTING_KEY_A", status: "pending" },
104
+ { key: "PENDING_KEY_B", status: "pending", guidance: ["Step 1: Go to dashboard", "Step 2: Click create key"] },
105
+ { key: "SKIPPED_KEY_C", status: "skipped" },
106
+ ]);
107
+ await writeManifestFile(tmp, manifest);
108
+
109
+ let callIndex = 0;
110
+ const mockCtx = {
111
+ cwd: tmp,
112
+ hasUI: true,
113
+ ui: {
114
+ custom: async (_factory: any) => {
115
+ callIndex++;
116
+ if (callIndex <= 1) return null; // summary screen dismiss
117
+ return "mock-secret-value"; // collect pending key
118
+ },
119
+ },
120
+ };
121
+
122
+ const result = await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
123
+
124
+ // EXISTING_KEY_A should be in existingSkipped (it's in process.env)
125
+ assert.ok(result.existingSkipped?.includes("EXISTING_KEY_A"),
126
+ "EXISTING_KEY_A should be in existingSkipped");
127
+
128
+ // PENDING_KEY_B should have been collected (applied)
129
+ assert.ok(result.applied.includes("PENDING_KEY_B"),
130
+ "PENDING_KEY_B should be in applied");
131
+
132
+ // SKIPPED_KEY_C should remain skipped
133
+ assert.ok(result.skipped.includes("SKIPPED_KEY_C"),
134
+ "SKIPPED_KEY_C should be in skipped");
135
+ } finally {
136
+ delete process.env.EXISTING_KEY_A;
137
+ if (savedA !== undefined) process.env.EXISTING_KEY_A = savedA;
138
+ rmSync(tmp, { recursive: true, force: true });
139
+ }
140
+ });
141
+
142
+ test("collectSecretsFromManifest: existing keys are excluded from the collection list — not prompted", async () => {
143
+ const { collectSecretsFromManifest } = await loadOrchestrator();
144
+
145
+ const tmp = makeTempDir("manifest-collect-skip");
146
+ const savedA = process.env.ALREADY_SET_KEY;
147
+ try {
148
+ process.env.ALREADY_SET_KEY = "present";
149
+
150
+ const manifest = makeManifest([
151
+ { key: "ALREADY_SET_KEY", status: "pending" },
152
+ { key: "NEEDS_COLLECTION", status: "pending" },
153
+ ]);
154
+ await writeManifestFile(tmp, manifest);
155
+
156
+ const collectedKeyNames: string[] = [];
157
+ let summaryShown = false;
158
+ const mockCtx = {
159
+ cwd: tmp,
160
+ hasUI: true,
161
+ ui: {
162
+ custom: async (factory: any) => {
163
+ // Intercept the factory to check what key is being collected
164
+ if (!summaryShown) {
165
+ summaryShown = true;
166
+ return null; // dismiss summary
167
+ }
168
+ collectedKeyNames.push("prompted");
169
+ return "mock-value";
170
+ },
171
+ },
172
+ };
173
+
174
+ const result = await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
175
+
176
+ // ALREADY_SET_KEY should not have been prompted — only NEEDS_COLLECTION should
177
+ assert.ok(!result.applied.includes("ALREADY_SET_KEY"),
178
+ "ALREADY_SET_KEY should not be in applied (it was auto-skipped)");
179
+ assert.ok(result.existingSkipped?.includes("ALREADY_SET_KEY"),
180
+ "ALREADY_SET_KEY should be in existingSkipped");
181
+ } finally {
182
+ delete process.env.ALREADY_SET_KEY;
183
+ if (savedA !== undefined) process.env.ALREADY_SET_KEY = savedA;
184
+ rmSync(tmp, { recursive: true, force: true });
185
+ }
186
+ });
187
+
188
+ test("collectSecretsFromManifest: manifest statuses are updated after collection", async () => {
189
+ const { collectSecretsFromManifest } = await loadOrchestrator();
190
+
191
+ const tmp = makeTempDir("manifest-update");
192
+ try {
193
+ const manifest = makeManifest([
194
+ { key: "KEY_TO_COLLECT", status: "pending" },
195
+ { key: "KEY_TO_SKIP", status: "pending" },
196
+ ]);
197
+ const manifestPath = await writeManifestFile(tmp, manifest);
198
+
199
+ let callIndex = 0;
200
+ const mockCtx = {
201
+ cwd: tmp,
202
+ hasUI: true,
203
+ ui: {
204
+ custom: async (_factory: any) => {
205
+ callIndex++;
206
+ if (callIndex <= 1) return null; // summary screen dismiss
207
+ if (callIndex === 2) return "secret-value"; // KEY_TO_COLLECT
208
+ return null; // KEY_TO_SKIP — user skips
209
+ },
210
+ },
211
+ };
212
+
213
+ await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
214
+
215
+ // Read back the manifest file and verify statuses were updated
216
+ const { parseSecretsManifest } = await loadFilesExports();
217
+ const updatedContent = readFileSync(manifestPath, "utf8");
218
+ const updatedManifest = parseSecretsManifest(updatedContent);
219
+
220
+ const keyToCollect = updatedManifest.entries.find(e => e.key === "KEY_TO_COLLECT");
221
+ const keyToSkip = updatedManifest.entries.find(e => e.key === "KEY_TO_SKIP");
222
+
223
+ assert.equal(keyToCollect?.status, "collected",
224
+ "KEY_TO_COLLECT should have status 'collected' after providing a value");
225
+ assert.equal(keyToSkip?.status, "skipped",
226
+ "KEY_TO_SKIP should have status 'skipped' after user skipped it");
227
+ } finally {
228
+ rmSync(tmp, { recursive: true, force: true });
229
+ }
230
+ });
231
+
232
+ // ─── showSecretsSummary: render output ────────────────────────────────────────
233
+
234
+ test("showSecretsSummary: produces lines with correct status glyphs for each entry status", async () => {
235
+ const { showSecretsSummary } = await loadOrchestrator();
236
+
237
+ const entries: SecretsManifestEntry[] = [
238
+ { key: "PENDING_KEY", service: "Svc", dashboardUrl: "", guidance: [], formatHint: "", status: "pending", destination: "dotenv" },
239
+ { key: "COLLECTED_KEY", service: "Svc", dashboardUrl: "", guidance: [], formatHint: "", status: "collected", destination: "dotenv" },
240
+ { key: "SKIPPED_KEY", service: "Svc", dashboardUrl: "", guidance: [], formatHint: "", status: "skipped", destination: "dotenv" },
241
+ ];
242
+
243
+ // showSecretsSummary renders a ctx.ui.custom screen. We capture the render output.
244
+ let renderFn: ((width: number) => string[]) | undefined;
245
+ const mockCtx = {
246
+ hasUI: true,
247
+ ui: {
248
+ custom: async (factory: any) => {
249
+ const mockTheme = {
250
+ fg: (_color: string, text: string) => text,
251
+ bold: (text: string) => text,
252
+ };
253
+ const mockTui = { requestRender: () => {}, terminal: { rows: 24, columns: 80 } };
254
+ const component = factory(mockTui, mockTheme, {}, () => {});
255
+ renderFn = component.render;
256
+ // Simulate immediate dismiss
257
+ component.handleInput("\x1b"); // escape
258
+ },
259
+ },
260
+ };
261
+
262
+ await showSecretsSummary(mockCtx as any, entries, []);
263
+
264
+ assert.ok(renderFn, "render function should have been captured from factory");
265
+ const lines = renderFn!(80);
266
+
267
+ // Verify each key appears in the output
268
+ const output = lines.join("\n");
269
+ assert.ok(output.includes("PENDING_KEY"), "should include PENDING_KEY");
270
+ assert.ok(output.includes("COLLECTED_KEY"), "should include COLLECTED_KEY");
271
+ assert.ok(output.includes("SKIPPED_KEY"), "should include SKIPPED_KEY");
272
+
273
+ // Verify we have at least one line per entry plus header/footer
274
+ assert.ok(lines.length >= 5, `should have at least 5 lines (got ${lines.length})`);
275
+ });
276
+
277
+ test("showSecretsSummary: existing keys shown with distinct status indicator", async () => {
278
+ const { showSecretsSummary } = await loadOrchestrator();
279
+
280
+ const entries: SecretsManifestEntry[] = [
281
+ { key: "NEW_KEY", service: "Svc", dashboardUrl: "", guidance: [], formatHint: "", status: "pending", destination: "dotenv" },
282
+ { key: "OLD_KEY", service: "Svc", dashboardUrl: "", guidance: [], formatHint: "", status: "collected", destination: "dotenv" },
283
+ ];
284
+ const existingKeys = ["OLD_KEY"];
285
+
286
+ let renderFn: ((width: number) => string[]) | undefined;
287
+ const mockCtx = {
288
+ hasUI: true,
289
+ ui: {
290
+ custom: async (factory: any) => {
291
+ const mockTheme = {
292
+ fg: (_color: string, text: string) => text,
293
+ bold: (text: string) => text,
294
+ };
295
+ const mockTui = { requestRender: () => {}, terminal: { rows: 24, columns: 80 } };
296
+ const component = factory(mockTui, mockTheme, {}, () => {});
297
+ renderFn = component.render;
298
+ component.handleInput("\x1b");
299
+ },
300
+ },
301
+ };
302
+
303
+ await showSecretsSummary(mockCtx as any, entries, existingKeys);
304
+
305
+ assert.ok(renderFn, "render function should have been captured");
306
+ const lines = renderFn!(80);
307
+ const output = lines.join("\n");
308
+
309
+ assert.ok(output.includes("NEW_KEY"), "should include NEW_KEY");
310
+ assert.ok(output.includes("OLD_KEY"), "should include OLD_KEY");
311
+ });
312
+
313
+ // ─── collectOneSecret: guidance rendering ─────────────────────────────────────
314
+
315
+ test("collectOneSecret: guidance lines appear in render output when guidance is provided", async () => {
316
+ const { collectOneSecretWithGuidance } = await loadGuidanceExport();
317
+
318
+ const guidanceSteps = [
319
+ "Navigate to https://platform.openai.com/api-keys",
320
+ "Click 'Create new secret key'",
321
+ "Copy the key value",
322
+ ];
323
+
324
+ // Use the exported test helper to capture render output with guidance
325
+ let renderFn: ((width: number) => string[]) | undefined;
326
+ const mockCtx = {
327
+ hasUI: true,
328
+ ui: {
329
+ custom: async (factory: any) => {
330
+ const mockTheme = {
331
+ fg: (_color: string, text: string) => text,
332
+ bold: (text: string) => text,
333
+ };
334
+ const mockTui = { requestRender: () => {}, terminal: { rows: 24, columns: 80 } };
335
+ const component = factory(mockTui, mockTheme, {}, () => {});
336
+ renderFn = component.render;
337
+ component.handleInput("\x1b"); // escape to dismiss
338
+ },
339
+ },
340
+ };
341
+
342
+ await collectOneSecretWithGuidance(mockCtx, 0, 1, "OPENAI_API_KEY", "starts with sk-", guidanceSteps);
343
+
344
+ assert.ok(renderFn, "render function should have been captured");
345
+ const lines = renderFn!(80);
346
+ const output = lines.join("\n");
347
+
348
+ // Verify guidance steps appear in the output
349
+ assert.ok(output.includes("Navigate to"), "should include first guidance step");
350
+ assert.ok(output.includes("Create new secret key"), "should include second guidance step");
351
+ assert.ok(output.includes("Copy the key value"), "should include third guidance step");
352
+ });
353
+
354
+ test("collectOneSecret: guidance lines wrap long URLs instead of truncating", async () => {
355
+ const { collectOneSecretWithGuidance } = await loadGuidanceExport();
356
+
357
+ const longGuidance = [
358
+ "Navigate to https://platform.openai.com/account/api-keys and click 'Create new secret key'",
359
+ ];
360
+
361
+ let renderFn: ((width: number) => string[]) | undefined;
362
+ const mockCtx = {
363
+ hasUI: true,
364
+ ui: {
365
+ custom: async (factory: any) => {
366
+ const mockTheme = {
367
+ fg: (_color: string, text: string) => text,
368
+ bold: (text: string) => text,
369
+ };
370
+ const mockTui = { requestRender: () => {}, terminal: { rows: 24, columns: 80 } };
371
+ const component = factory(mockTui, mockTheme, {}, () => {});
372
+ renderFn = component.render;
373
+ component.handleInput("\x1b");
374
+ },
375
+ },
376
+ };
377
+
378
+ await collectOneSecretWithGuidance(mockCtx, 0, 1, "TEST_KEY", undefined, longGuidance);
379
+
380
+ assert.ok(renderFn, "render function should have been captured");
381
+ // Render at narrow width to force wrapping
382
+ const lines = renderFn!(50);
383
+ const output = lines.join("\n");
384
+
385
+ // The full URL should be present (wrapped, not truncated)
386
+ assert.ok(output.includes("platform.openai.com"), "URL should not be truncated");
387
+ assert.ok(output.includes("Create new secret key"), "text after URL should not be truncated");
388
+ });
389
+
390
+ test("collectOneSecret: no guidance provided — render output has no guidance section", async () => {
391
+ const { collectOneSecretWithGuidance } = await loadGuidanceExport();
392
+
393
+ let renderFn: ((width: number) => string[]) | undefined;
394
+ const mockCtx = {
395
+ hasUI: true,
396
+ ui: {
397
+ custom: async (factory: any) => {
398
+ const mockTheme = {
399
+ fg: (_color: string, text: string) => text,
400
+ bold: (text: string) => text,
401
+ };
402
+ const mockTui = { requestRender: () => {}, terminal: { rows: 24, columns: 80 } };
403
+ const component = factory(mockTui, mockTheme, {}, () => {});
404
+ renderFn = component.render;
405
+ component.handleInput("\x1b");
406
+ },
407
+ },
408
+ };
409
+
410
+ // Call without guidance (undefined)
411
+ await collectOneSecretWithGuidance(mockCtx, 0, 1, "SOME_KEY", "hint text", undefined);
412
+
413
+ assert.ok(renderFn, "render function should have been captured");
414
+ const lines = renderFn!(80);
415
+ const output = lines.join("\n");
416
+
417
+ // Should include the key name and hint but no numbered guidance steps
418
+ assert.ok(output.includes("SOME_KEY"), "should include key name");
419
+ assert.ok(output.includes("hint text"), "should include hint");
420
+ // Should NOT have numbered step indicators (1., 2., etc.) for guidance
421
+ assert.ok(!output.match(/^\s*1\.\s/m), "should not have numbered guidance steps when no guidance provided");
422
+ });
423
+
424
+ // ─── collectSecretsFromManifest: returns structured result ────────────────────
425
+
426
+ test("collectSecretsFromManifest: returns result with applied, skipped, and existingSkipped arrays", async () => {
427
+ const { collectSecretsFromManifest } = await loadOrchestrator();
428
+
429
+ const tmp = makeTempDir("manifest-result");
430
+ const savedKey = process.env.RESULT_TEST_EXISTING;
431
+ try {
432
+ process.env.RESULT_TEST_EXISTING = "already-here";
433
+
434
+ const manifest = makeManifest([
435
+ { key: "RESULT_TEST_EXISTING", status: "pending" },
436
+ { key: "RESULT_TEST_NEW", status: "pending" },
437
+ ]);
438
+ await writeManifestFile(tmp, manifest);
439
+
440
+ let callIndex = 0;
441
+ const mockCtx = {
442
+ cwd: tmp,
443
+ hasUI: true,
444
+ ui: {
445
+ custom: async (_factory: any) => {
446
+ callIndex++;
447
+ if (callIndex <= 1) return null; // summary dismiss
448
+ return "secret-value"; // collect the pending key
449
+ },
450
+ },
451
+ };
452
+
453
+ const result = await collectSecretsFromManifest(tmp, "M001", mockCtx as any);
454
+
455
+ // Verify result shape
456
+ assert.ok(Array.isArray(result.applied), "result should have applied array");
457
+ assert.ok(Array.isArray(result.skipped), "result should have skipped array");
458
+ assert.ok(Array.isArray(result.existingSkipped), "result should have existingSkipped array");
459
+
460
+ assert.ok(result.existingSkipped.includes("RESULT_TEST_EXISTING"),
461
+ "existing key should be in existingSkipped");
462
+ assert.ok(result.applied.includes("RESULT_TEST_NEW"),
463
+ "collected key should be in applied");
464
+ } finally {
465
+ delete process.env.RESULT_TEST_EXISTING;
466
+ if (savedKey !== undefined) process.env.RESULT_TEST_EXISTING = savedKey;
467
+ rmSync(tmp, { recursive: true, force: true });
468
+ }
469
+ });
@@ -0,0 +1,200 @@
1
+ import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { join, dirname } from "node:path";
3
+ import { tmpdir } from "node:os";
4
+ import { fileURLToPath } from "node:url";
5
+ import { createTestContext } from './test-helpers.ts';
6
+ import { clearPathCache } from '../paths.ts';
7
+ import { invalidateStateCache } from '../state.ts';
8
+
9
+ // loadPrompt reads from ~/.gsd/agent/extensions/gsd/prompts/ (main checkout).
10
+ // In a worktree the file may not exist there yet, so we resolve prompts
11
+ // relative to this test file's location (the worktree copy).
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const worktreePromptsDir = join(__dirname, "..", "prompts");
14
+
15
+ const { assertEq, assertTrue, report } = createTestContext();
16
+ /**
17
+ * Load a prompt template from the worktree prompts directory
18
+ * and apply variable substitution (mirrors loadPrompt logic).
19
+ */
20
+ function loadPromptFromWorktree(name: string, vars: Record<string, string> = {}): string {
21
+ const path = join(worktreePromptsDir, `${name}.md`);
22
+ let content = readFileSync(path, "utf-8");
23
+ for (const [key, value] of Object.entries(vars)) {
24
+ content = content.replaceAll(`{{${key}}}`, value);
25
+ }
26
+ return content.trim();
27
+ }
28
+
29
+ // ─── Fixture Helpers ───────────────────────────────────────────────────────
30
+
31
+ function createFixtureBase(): string {
32
+ const base = mkdtempSync(join(tmpdir(), "gsd-complete-ms-test-"));
33
+ mkdirSync(join(base, ".gsd", "milestones"), { recursive: true });
34
+ return base;
35
+ }
36
+
37
+ function writeRoadmap(base: string, mid: string, content: string): void {
38
+ const dir = join(base, ".gsd", "milestones", mid);
39
+ mkdirSync(dir, { recursive: true });
40
+ writeFileSync(join(dir, `${mid}-ROADMAP.md`), content);
41
+ }
42
+
43
+ function writeMilestoneSummary(base: string, mid: string, content: string): void {
44
+ const dir = join(base, ".gsd", "milestones", mid);
45
+ mkdirSync(dir, { recursive: true });
46
+ writeFileSync(join(dir, `${mid}-SUMMARY.md`), content);
47
+ }
48
+
49
+ function cleanup(base: string): void {
50
+ rmSync(base, { recursive: true, force: true });
51
+ }
52
+
53
+ // ═══════════════════════════════════════════════════════════════════════════
54
+ // Tests
55
+ // ═══════════════════════════════════════════════════════════════════════════
56
+
57
+ async function main(): Promise<void> {
58
+
59
+ // ─── Prompt Template Loading ───────────────────────────────────────────
60
+ console.log("\n=== complete-milestone prompt template exists ===");
61
+ {
62
+ let result: string;
63
+ let threw = false;
64
+ try {
65
+ result = loadPromptFromWorktree("complete-milestone", {
66
+ milestoneId: "M001",
67
+ milestoneTitle: "Test Milestone",
68
+ roadmapPath: ".gsd/milestones/M001/M001-ROADMAP.md",
69
+ inlinedContext: "test context block",
70
+ });
71
+ } catch (err) {
72
+ threw = true;
73
+ result = "";
74
+ console.error(` ERROR: loadPrompt threw: ${err}`);
75
+ }
76
+
77
+ assertTrue(!threw, "loadPrompt does not throw for complete-milestone");
78
+ assertTrue(typeof result === "string" && result.length > 0, "loadPrompt returns a non-empty string");
79
+ }
80
+
81
+ // ─── Variable Substitution ─────────────────────────────────────────────
82
+ console.log("\n=== prompt variable substitution ===");
83
+ {
84
+ const prompt = loadPromptFromWorktree("complete-milestone", {
85
+ milestoneId: "M001",
86
+ milestoneTitle: "Integration Feature",
87
+ roadmapPath: ".gsd/milestones/M001/M001-ROADMAP.md",
88
+ inlinedContext: "--- inlined slice summaries and context ---",
89
+ });
90
+
91
+ assertTrue(prompt.includes("M001"), "prompt contains milestoneId 'M001'");
92
+ assertTrue(prompt.includes("Integration Feature"), "prompt contains milestoneTitle");
93
+ assertTrue(prompt.includes(".gsd/milestones/M001/M001-ROADMAP.md"), "prompt contains roadmapPath");
94
+ assertTrue(prompt.includes("--- inlined slice summaries and context ---"), "prompt contains inlinedContext");
95
+ assertTrue(!prompt.includes("{{milestoneId}}"), "no un-substituted {{milestoneId}}");
96
+ assertTrue(!prompt.includes("{{milestoneTitle}}"), "no un-substituted {{milestoneTitle}}");
97
+ assertTrue(!prompt.includes("{{roadmapPath}}"), "no un-substituted {{roadmapPath}}");
98
+ assertTrue(!prompt.includes("{{inlinedContext}}"), "no un-substituted {{inlinedContext}}");
99
+ }
100
+
101
+ // ─── Prompt Content Integrity ──────────────────────────────────────────
102
+ console.log("\n=== prompt content integrity ===");
103
+ {
104
+ const prompt = loadPromptFromWorktree("complete-milestone", {
105
+ milestoneId: "M002",
106
+ milestoneTitle: "Completion Workflow",
107
+ roadmapPath: ".gsd/milestones/M002/M002-ROADMAP.md",
108
+ inlinedContext: "context",
109
+ });
110
+
111
+ assertTrue(prompt.includes("Complete Milestone"), "prompt contains 'Complete Milestone' heading");
112
+ assertTrue(prompt.includes("success criter") || prompt.includes("success criteria"), "prompt mentions success criteria verification");
113
+ assertTrue(prompt.includes("milestone-summary") || prompt.includes("milestoneSummary"), "prompt references milestone summary artifact");
114
+ assertTrue(prompt.includes("Milestone M002 complete"), "prompt contains completion sentinel for M002");
115
+ }
116
+
117
+ // ─── diagnoseExpectedArtifact behavior ─────────────────────────────────
118
+ // Since diagnoseExpectedArtifact is not exported from auto.ts, we test
119
+ // the same logic by reimplementing the switch case for complete-milestone
120
+ // and verifying against known path patterns.
121
+ console.log("\n=== diagnoseExpectedArtifact logic for complete-milestone ===");
122
+ {
123
+ // Import the path helpers used by diagnoseExpectedArtifact
124
+ const { relMilestoneFile } = await import("../paths.ts");
125
+
126
+ // Simulate diagnoseExpectedArtifact("complete-milestone", "M001", base) logic
127
+ const base = createFixtureBase();
128
+ try {
129
+ writeRoadmap(base, "M001", `# M001\n\n## Slices\n- [x] **S01: Done** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
130
+
131
+ const unitType = "complete-milestone";
132
+ const unitId = "M001";
133
+ const parts = unitId.split("/");
134
+ const mid = parts[0]!;
135
+
136
+ // This is the exact logic from diagnoseExpectedArtifact for "complete-milestone"
137
+ const result = `${relMilestoneFile(base, mid, "SUMMARY")} (milestone summary)`;
138
+
139
+ assertTrue(typeof result === "string", "diagnose returns a string");
140
+ assertTrue(result.includes("SUMMARY"), "diagnose result mentions SUMMARY");
141
+ assertTrue(result.includes("milestone"), "diagnose result mentions milestone");
142
+ assertTrue(result.includes("M001"), "diagnose result includes the milestone ID");
143
+ } finally {
144
+ cleanup(base);
145
+ }
146
+ }
147
+
148
+ // ─── deriveState integration: completing-milestone dispatches correctly ─
149
+ console.log("\n=== deriveState completing-milestone integration ===");
150
+ {
151
+ const { deriveState, isMilestoneComplete, invalidateStateCache } = await import("../state.ts");
152
+ const { parseRoadmap } = await import("../files.ts");
153
+
154
+ const base = createFixtureBase();
155
+ try {
156
+ writeRoadmap(base, "M001", `# M001: Integration Test
157
+
158
+ **Vision:** Test completing-milestone flow.
159
+
160
+ ## Slices
161
+
162
+ - [x] **S01: Slice One** \`risk:low\` \`depends:[]\`
163
+ > After this: done.
164
+
165
+ - [x] **S02: Slice Two** \`risk:low\` \`depends:[S01]\`
166
+ > After this: done.
167
+ `);
168
+
169
+ // Verify isMilestoneComplete returns true
170
+ const { loadFile } = await import("../files.ts");
171
+ const roadmapPath = join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md");
172
+ const roadmapContent = await loadFile(roadmapPath);
173
+ const roadmap = parseRoadmap(roadmapContent!);
174
+ assertTrue(isMilestoneComplete(roadmap), "isMilestoneComplete returns true when all slices are [x]");
175
+
176
+ // Verify deriveState returns completing-milestone phase
177
+ const state = await deriveState(base);
178
+ assertEq(state.phase, "completing-milestone", "deriveState returns completing-milestone when all slices done, no summary");
179
+ assertEq(state.activeMilestone?.id, "M001", "active milestone is M001");
180
+ assertEq(state.activeSlice, null, "no active slice in completing-milestone");
181
+
182
+ // Now add the summary and verify it transitions to complete
183
+ writeMilestoneSummary(base, "M001", "# M001 Summary\n\nDone.");
184
+ clearPathCache();
185
+ invalidateStateCache();
186
+ const stateAfter = await deriveState(base);
187
+ assertEq(stateAfter.phase, "complete", "deriveState returns complete after summary exists");
188
+ assertEq(stateAfter.registry[0]?.status, "complete", "registry shows complete status");
189
+ } finally {
190
+ cleanup(base);
191
+ }
192
+ }
193
+
194
+ report();
195
+ }
196
+
197
+ main().catch((error) => {
198
+ console.error(error);
199
+ process.exit(1);
200
+ });