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,361 @@
1
+ /**
2
+ * Remote Questions — /gsd remote command
3
+ */
4
+
5
+ import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
6
+ import { AuthStorage } from "@gsd/pi-coding-agent";
7
+ import { CURSOR_MARKER, Editor, type EditorTheme, Key, matchesKey, truncateToWidth } from "@gsd/pi-tui";
8
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
9
+ import { dirname, join } from "node:path";
10
+ import { getGlobalGSDPreferencesPath, loadEffectiveGSDPreferences } from "../gsd/preferences.js";
11
+ import { getRemoteConfigStatus, isValidChannelId, resolveRemoteConfig } from "./config.js";
12
+ import { sanitizeError } from "./manager.js";
13
+ import { getLatestPromptSummary } from "./status.js";
14
+
15
+ export async function handleRemote(
16
+ subcommand: string,
17
+ ctx: ExtensionCommandContext,
18
+ _pi: ExtensionAPI,
19
+ ): Promise<void> {
20
+ const trimmed = subcommand.trim();
21
+
22
+ if (trimmed === "slack") return handleSetupSlack(ctx);
23
+ if (trimmed === "discord") return handleSetupDiscord(ctx);
24
+ if (trimmed === "status") return handleRemoteStatus(ctx);
25
+ if (trimmed === "disconnect") return handleDisconnect(ctx);
26
+
27
+ return handleRemoteMenu(ctx);
28
+ }
29
+
30
+ async function handleSetupSlack(ctx: ExtensionCommandContext): Promise<void> {
31
+ const token = await promptMaskedInput(ctx, "Slack Bot Token", "Paste your xoxb-... token");
32
+ if (!token) return void ctx.ui.notify("Slack setup cancelled.", "info");
33
+ if (!token.startsWith("xoxb-")) return void ctx.ui.notify("Invalid token format — Slack bot tokens start with xoxb-.", "warning");
34
+
35
+ ctx.ui.notify("Validating token...", "info");
36
+ const auth = await fetchJson("https://slack.com/api/auth.test", { headers: { Authorization: `Bearer ${token}` } });
37
+ if (!auth?.ok) return void ctx.ui.notify("Token validation failed — check the token and app install.", "error");
38
+
39
+ const channelId = await promptInput(ctx, "Channel ID", "Paste the Slack channel ID (e.g. C0123456789)");
40
+ if (!channelId) return void ctx.ui.notify("Slack setup cancelled.", "info");
41
+ if (!isValidChannelId("slack", channelId)) return void ctx.ui.notify("Invalid Slack channel ID format — expected 9-12 uppercase alphanumeric characters.", "error");
42
+
43
+ const send = await fetchJson("https://slack.com/api/chat.postMessage", {
44
+ method: "POST",
45
+ headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json; charset=utf-8" },
46
+ body: JSON.stringify({ channel: channelId, text: "GSD remote questions connected." }),
47
+ });
48
+ if (!send?.ok) return void ctx.ui.notify(`Could not send to channel: ${send?.error ?? "unknown error"}`, "error");
49
+
50
+ saveProviderToken("slack_bot", token);
51
+ process.env.SLACK_BOT_TOKEN = token;
52
+ saveRemoteQuestionsConfig("slack", channelId);
53
+ ctx.ui.notify(`Slack connected — remote questions enabled for channel ${channelId}.`, "info");
54
+ }
55
+
56
+ async function handleSetupDiscord(ctx: ExtensionCommandContext): Promise<void> {
57
+ const token = await promptMaskedInput(ctx, "Discord Bot Token", "Paste your bot token");
58
+ if (!token) return void ctx.ui.notify("Discord setup cancelled.", "info");
59
+
60
+ ctx.ui.notify("Validating token...", "info");
61
+ const headers = { Authorization: `Bot ${token}` };
62
+ const auth = await fetchJson("https://discord.com/api/v10/users/@me", { headers });
63
+ if (!auth?.id) return void ctx.ui.notify("Token validation failed — check the bot token.", "error");
64
+
65
+ // Fetch guilds the bot is a member of
66
+ const guilds: Array<{ id: string; name: string }> | null = await fetchJson("https://discord.com/api/v10/users/@me/guilds", { headers });
67
+ if (!Array.isArray(guilds) || guilds.length === 0) {
68
+ return void ctx.ui.notify("Bot is not in any Discord servers.", "error");
69
+ }
70
+
71
+ let guildId: string;
72
+ let guildName: string;
73
+ if (guilds.length === 1) {
74
+ guildId = guilds[0].id;
75
+ guildName = guilds[0].name;
76
+ } else {
77
+ const guildOptions = guilds.map((g) => g.name);
78
+ const selectedGuild = await ctx.ui.select("Select a Discord server", guildOptions);
79
+ if (!selectedGuild) return void ctx.ui.notify("Discord setup cancelled.", "info");
80
+ const chosen = guilds.find((g) => g.name === selectedGuild);
81
+ if (!chosen) return void ctx.ui.notify("Discord setup cancelled.", "info");
82
+ guildId = chosen.id;
83
+ guildName = chosen.name;
84
+ }
85
+
86
+ // Fetch text and announcement channels in the selected guild
87
+ ctx.ui.notify(`Fetching channels for ${guildName}...`, "info");
88
+ const allChannels: Array<{ id: string; name: string; type: number }> | null = await fetchJson(
89
+ `https://discord.com/api/v10/guilds/${guildId}/channels`,
90
+ { headers },
91
+ );
92
+ const textChannels = Array.isArray(allChannels)
93
+ ? allChannels.filter((ch) => ch.type === 0 || ch.type === 5)
94
+ : [];
95
+
96
+ const MANUAL_OPTION = "Enter channel ID manually";
97
+ let channelId: string;
98
+
99
+ if (textChannels.length === 0) {
100
+ ctx.ui.notify("No text channels found — falling back to manual entry.", "warning");
101
+ const manualId = await promptInput(ctx, "Channel ID", "Paste the Discord channel ID (e.g. 1234567890123456789)");
102
+ if (!manualId) return void ctx.ui.notify("Discord setup cancelled.", "info");
103
+ if (!isValidChannelId("discord", manualId)) return void ctx.ui.notify("Invalid Discord channel ID format — expected 17-20 digit numeric ID.", "error");
104
+ channelId = manualId;
105
+ } else {
106
+ const channelOptions = [...textChannels.map((ch) => `#${ch.name}`), MANUAL_OPTION];
107
+ const selectedChannel = await ctx.ui.select("Select a channel", channelOptions);
108
+ if (!selectedChannel) return void ctx.ui.notify("Discord setup cancelled.", "info");
109
+
110
+ if (selectedChannel === MANUAL_OPTION) {
111
+ const manualId = await promptInput(ctx, "Channel ID", "Paste the Discord channel ID (e.g. 1234567890123456789)");
112
+ if (!manualId) return void ctx.ui.notify("Discord setup cancelled.", "info");
113
+ if (!isValidChannelId("discord", manualId)) return void ctx.ui.notify("Invalid Discord channel ID format — expected 17-20 digit numeric ID.", "error");
114
+ channelId = manualId;
115
+ } else {
116
+ const chosenChannel = textChannels.find((ch) => `#${ch.name}` === selectedChannel);
117
+ if (!chosenChannel) return void ctx.ui.notify("Discord setup cancelled.", "info");
118
+ channelId = chosenChannel.id;
119
+ }
120
+ }
121
+
122
+ const sendResponse = await fetch(`https://discord.com/api/v10/channels/${channelId}/messages`, {
123
+ method: "POST",
124
+ headers: { ...headers, "Content-Type": "application/json" },
125
+ body: JSON.stringify({ content: "GSD remote questions connected." }),
126
+ signal: AbortSignal.timeout(15_000),
127
+ });
128
+ if (!sendResponse.ok) {
129
+ const body = await sendResponse.text().catch(() => "");
130
+ return void ctx.ui.notify(`Could not send to channel (HTTP ${sendResponse.status}): ${sanitizeError(body).slice(0, 200)}`, "error");
131
+ }
132
+
133
+ saveProviderToken("discord_bot", token);
134
+ process.env.DISCORD_BOT_TOKEN = token;
135
+ saveRemoteQuestionsConfig("discord", channelId);
136
+ ctx.ui.notify(`Discord connected — remote questions enabled for channel ${channelId}.`, "info");
137
+ }
138
+
139
+ async function handleRemoteStatus(ctx: ExtensionCommandContext): Promise<void> {
140
+ const status = getRemoteConfigStatus();
141
+ const config = resolveRemoteConfig();
142
+ if (!config) {
143
+ ctx.ui.notify(status, status.includes("disabled") ? "warning" : "info");
144
+ return;
145
+ }
146
+
147
+ const latestPrompt = getLatestPromptSummary();
148
+ const lines = [status];
149
+ if (latestPrompt) {
150
+ lines.push(`Last prompt: ${latestPrompt.id}`);
151
+ lines.push(` status: ${latestPrompt.status}`);
152
+ if (latestPrompt.updatedAt) lines.push(` updated: ${new Date(latestPrompt.updatedAt).toLocaleString()}`);
153
+ }
154
+
155
+ ctx.ui.notify(lines.join("\n"), "info");
156
+ }
157
+
158
+ async function handleDisconnect(ctx: ExtensionCommandContext): Promise<void> {
159
+ const prefs = loadEffectiveGSDPreferences();
160
+ const channel = prefs?.preferences.remote_questions?.channel;
161
+ if (!channel) return void ctx.ui.notify("No remote channel configured — nothing to disconnect.", "info");
162
+
163
+ removeRemoteQuestionsConfig();
164
+ removeProviderToken(channel === "slack" ? "slack_bot" : "discord_bot");
165
+ if (channel === "slack") delete process.env.SLACK_BOT_TOKEN;
166
+ if (channel === "discord") delete process.env.DISCORD_BOT_TOKEN;
167
+ ctx.ui.notify(`Remote questions disconnected (${channel}).`, "info");
168
+ }
169
+
170
+ async function handleRemoteMenu(ctx: ExtensionCommandContext): Promise<void> {
171
+ const config = resolveRemoteConfig();
172
+ const latestPrompt = getLatestPromptSummary();
173
+ const lines = config
174
+ ? [
175
+ `Remote questions: ${config.channel} configured`,
176
+ ` Timeout: ${config.timeoutMs / 60000}m, poll: ${config.pollIntervalMs / 1000}s`,
177
+ latestPrompt ? ` Last prompt: ${latestPrompt.id} (${latestPrompt.status})` : " No remote prompts recorded yet",
178
+ "",
179
+ "Commands:",
180
+ " /gsd remote status",
181
+ " /gsd remote disconnect",
182
+ " /gsd remote slack",
183
+ " /gsd remote discord",
184
+ ]
185
+ : [
186
+ "No remote question channel configured.",
187
+ "",
188
+ "Commands:",
189
+ " /gsd remote slack",
190
+ " /gsd remote discord",
191
+ " /gsd remote status",
192
+ ];
193
+
194
+ ctx.ui.notify(lines.join("\n"), "info");
195
+ }
196
+
197
+ async function fetchJson(url: string, init?: RequestInit): Promise<any> {
198
+ try {
199
+ const response = await fetch(url, { ...init, signal: AbortSignal.timeout(15_000) });
200
+ return await response.json();
201
+ } catch {
202
+ return null;
203
+ }
204
+ }
205
+
206
+ function getAuthStorage(): AuthStorage {
207
+ const authPath = join(process.env.HOME ?? "", ".gsd", "agent", "auth.json");
208
+ mkdirSync(dirname(authPath), { recursive: true });
209
+ return AuthStorage.create(authPath);
210
+ }
211
+
212
+ function saveProviderToken(provider: string, token: string): void {
213
+ const auth = getAuthStorage();
214
+ auth.set(provider, { type: "api_key", key: token });
215
+ }
216
+
217
+ function removeProviderToken(provider: string): void {
218
+ const auth = getAuthStorage();
219
+ auth.set(provider, { type: "api_key", key: "" });
220
+ }
221
+
222
+ export function saveRemoteQuestionsConfig(channel: "slack" | "discord", channelId: string): void {
223
+ const prefsPath = getGlobalGSDPreferencesPath();
224
+ const block = [
225
+ "remote_questions:",
226
+ ` channel: ${channel}`,
227
+ ` channel_id: \"${channelId}\"`,
228
+ " timeout_minutes: 5",
229
+ " poll_interval_seconds: 5",
230
+ ].join("\n");
231
+
232
+ const content = existsSync(prefsPath) ? readFileSync(prefsPath, "utf-8") : "";
233
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
234
+ let next = content;
235
+
236
+ if (fmMatch) {
237
+ let frontmatter = fmMatch[1];
238
+ const regex = /remote_questions:[\s\S]*?(?=\n[a-zA-Z_]|\n---|$)/;
239
+ frontmatter = regex.test(frontmatter) ? frontmatter.replace(regex, block) : `${frontmatter.trimEnd()}\n${block}`;
240
+ next = `---\n${frontmatter}\n---${content.slice(fmMatch[0].length)}`;
241
+ } else {
242
+ next = `---\n${block}\n---\n\n${content}`;
243
+ }
244
+
245
+ mkdirSync(dirname(prefsPath), { recursive: true });
246
+ writeFileSync(prefsPath, next, "utf-8");
247
+ }
248
+
249
+ function removeRemoteQuestionsConfig(): void {
250
+ const prefsPath = getGlobalGSDPreferencesPath();
251
+ if (!existsSync(prefsPath)) return;
252
+ const content = readFileSync(prefsPath, "utf-8");
253
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
254
+ if (!fmMatch) return;
255
+ const frontmatter = fmMatch[1].replace(/remote_questions:[\s\S]*?(?=\n[a-zA-Z_]|\n---|$)/, "").trim();
256
+ const next = frontmatter ? `---\n${frontmatter}\n---${content.slice(fmMatch[0].length)}` : content.slice(fmMatch[0].length).replace(/^\n+/, "");
257
+ writeFileSync(prefsPath, next, "utf-8");
258
+ }
259
+
260
+ function maskEditorLine(line: string): string {
261
+ let output = "";
262
+ let i = 0;
263
+ while (i < line.length) {
264
+ if (line.startsWith(CURSOR_MARKER, i)) {
265
+ output += CURSOR_MARKER;
266
+ i += CURSOR_MARKER.length;
267
+ continue;
268
+ }
269
+ const ansiMatch = /^\x1b\[[0-9;]*m/.exec(line.slice(i));
270
+ if (ansiMatch) {
271
+ output += ansiMatch[0];
272
+ i += ansiMatch[0].length;
273
+ continue;
274
+ }
275
+ output += line[i] === " " ? " " : "*";
276
+ i += 1;
277
+ }
278
+ return output;
279
+ }
280
+
281
+ async function promptMaskedInput(ctx: ExtensionCommandContext, label: string, hint: string): Promise<string | null> {
282
+ if (!ctx.hasUI) return null;
283
+ return ctx.ui.custom<string | null>((tui: any, theme: any, _kb: any, done: (r: string | null) => void) => {
284
+ let cachedLines: string[] | undefined;
285
+ const editorTheme: EditorTheme = {
286
+ borderColor: (s: string) => theme.fg("accent", s),
287
+ selectList: {
288
+ selectedPrefix: (t: string) => theme.fg("accent", t),
289
+ selectedText: (t: string) => theme.fg("accent", t),
290
+ description: (t: string) => theme.fg("muted", t),
291
+ scrollInfo: (t: string) => theme.fg("dim", t),
292
+ noMatch: (t: string) => theme.fg("warning", t),
293
+ },
294
+ };
295
+ const editor = new Editor(tui, editorTheme, { paddingX: 1 });
296
+ const refresh = () => { cachedLines = undefined; tui.requestRender(); };
297
+ const handleInput = (data: string) => {
298
+ if (matchesKey(data, Key.enter)) return done(editor.getText().trim() || null);
299
+ if (matchesKey(data, Key.escape)) return done(null);
300
+ editor.handleInput(data); refresh();
301
+ };
302
+ const render = (width: number) => {
303
+ if (cachedLines) return cachedLines;
304
+ const lines: string[] = [];
305
+ const add = (s: string) => lines.push(truncateToWidth(s, width));
306
+ add(theme.fg("accent", "─".repeat(width)));
307
+ add(theme.fg("accent", theme.bold(` ${label}`)));
308
+ add(theme.fg("muted", ` ${hint}`));
309
+ lines.push("");
310
+ add(theme.fg("muted", " Enter value:"));
311
+ for (const line of editor.render(width - 2)) add(theme.fg("text", maskEditorLine(line)));
312
+ lines.push("");
313
+ add(theme.fg("dim", " enter to confirm | esc to cancel"));
314
+ add(theme.fg("accent", "─".repeat(width)));
315
+ cachedLines = lines;
316
+ return lines;
317
+ };
318
+ return { render, handleInput, invalidate: () => { cachedLines = undefined; } };
319
+ });
320
+ }
321
+
322
+ async function promptInput(ctx: ExtensionCommandContext, label: string, hint: string): Promise<string | null> {
323
+ if (!ctx.hasUI) return null;
324
+ return ctx.ui.custom<string | null>((tui: any, theme: any, _kb: any, done: (r: string | null) => void) => {
325
+ let cachedLines: string[] | undefined;
326
+ const editorTheme: EditorTheme = {
327
+ borderColor: (s: string) => theme.fg("accent", s),
328
+ selectList: {
329
+ selectedPrefix: (t: string) => theme.fg("accent", t),
330
+ selectedText: (t: string) => theme.fg("accent", t),
331
+ description: (t: string) => theme.fg("muted", t),
332
+ scrollInfo: (t: string) => theme.fg("dim", t),
333
+ noMatch: (t: string) => theme.fg("warning", t),
334
+ },
335
+ };
336
+ const editor = new Editor(tui, editorTheme, { paddingX: 1 });
337
+ const refresh = () => { cachedLines = undefined; tui.requestRender(); };
338
+ const handleInput = (data: string) => {
339
+ if (matchesKey(data, Key.enter)) return done(editor.getText().trim() || null);
340
+ if (matchesKey(data, Key.escape)) return done(null);
341
+ editor.handleInput(data); refresh();
342
+ };
343
+ const render = (width: number) => {
344
+ if (cachedLines) return cachedLines;
345
+ const lines: string[] = [];
346
+ const add = (s: string) => lines.push(truncateToWidth(s, width));
347
+ add(theme.fg("accent", "─".repeat(width)));
348
+ add(theme.fg("accent", theme.bold(` ${label}`)));
349
+ add(theme.fg("muted", ` ${hint}`));
350
+ lines.push("");
351
+ add(theme.fg("muted", " Enter value:"));
352
+ for (const line of editor.render(width - 2)) add(theme.fg("text", line));
353
+ lines.push("");
354
+ add(theme.fg("dim", " enter to confirm | esc to cancel"));
355
+ add(theme.fg("accent", "─".repeat(width)));
356
+ cachedLines = lines;
357
+ return lines;
358
+ };
359
+ return { render, handleInput, invalidate: () => { cachedLines = undefined; } };
360
+ });
361
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Remote Questions — Slack adapter
3
+ */
4
+
5
+ import type { ChannelAdapter, RemotePrompt, RemoteDispatchResult, RemoteAnswer, RemotePromptRef } from "./types.js";
6
+ import { formatForSlack, parseSlackReply } from "./format.js";
7
+
8
+ const SLACK_API = "https://slack.com/api";
9
+ const PER_REQUEST_TIMEOUT_MS = 15_000;
10
+
11
+ export class SlackAdapter implements ChannelAdapter {
12
+ readonly name = "slack" as const;
13
+ private botUserId: string | null = null;
14
+ private readonly token: string;
15
+ private readonly channelId: string;
16
+
17
+ constructor(token: string, channelId: string) {
18
+ this.token = token;
19
+ this.channelId = channelId;
20
+ }
21
+
22
+ async validate(): Promise<void> {
23
+ const res = await this.slackApi("auth.test", {});
24
+ if (!res.ok) throw new Error(`Slack auth failed: ${res.error ?? "invalid token"}`);
25
+ this.botUserId = String(res.user_id ?? "");
26
+ }
27
+
28
+ async sendPrompt(prompt: RemotePrompt): Promise<RemoteDispatchResult> {
29
+ const res = await this.slackApi("chat.postMessage", {
30
+ channel: this.channelId,
31
+ text: "GSD needs your input",
32
+ blocks: formatForSlack(prompt),
33
+ });
34
+
35
+ if (!res.ok) throw new Error(`Slack postMessage failed: ${res.error ?? "unknown"}`);
36
+
37
+ const ts = String(res.ts);
38
+ const channel = String(res.channel);
39
+ return {
40
+ ref: {
41
+ id: prompt.id,
42
+ channel: "slack",
43
+ messageId: ts,
44
+ threadTs: ts,
45
+ channelId: channel,
46
+ threadUrl: `https://slack.com/archives/${channel}/p${ts.replace(".", "")}`,
47
+ },
48
+ };
49
+ }
50
+
51
+ async pollAnswer(prompt: RemotePrompt, ref: RemotePromptRef): Promise<RemoteAnswer | null> {
52
+ if (!this.botUserId) await this.validate();
53
+
54
+ const res = await this.slackApi("conversations.replies", {
55
+ channel: ref.channelId,
56
+ ts: ref.threadTs!,
57
+ limit: "20",
58
+ });
59
+
60
+ if (!res.ok) return null;
61
+
62
+ const messages = (res.messages ?? []) as Array<{ user?: string; text?: string; ts: string }>;
63
+ const userReplies = messages.filter((m) => m.ts !== ref.threadTs && m.user && m.user !== this.botUserId && m.text);
64
+ if (userReplies.length === 0) return null;
65
+
66
+ return parseSlackReply(String(userReplies[0].text), prompt.questions);
67
+ }
68
+
69
+ private async slackApi(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> {
70
+ const url = `${SLACK_API}/${method}`;
71
+ const isGet = method === "conversations.replies" || method === "auth.test";
72
+
73
+ let response: Response;
74
+ if (isGet) {
75
+ const qs = new URLSearchParams(Object.fromEntries(Object.entries(params).map(([k, v]) => [k, String(v)]))).toString();
76
+ response = await fetch(`${url}?${qs}`, { method: "GET", headers: { Authorization: `Bearer ${this.token}` }, signal: AbortSignal.timeout(PER_REQUEST_TIMEOUT_MS) });
77
+ } else {
78
+ response = await fetch(url, {
79
+ method: "POST",
80
+ headers: {
81
+ Authorization: `Bearer ${this.token}`,
82
+ "Content-Type": "application/json; charset=utf-8",
83
+ },
84
+ body: JSON.stringify(params),
85
+ signal: AbortSignal.timeout(PER_REQUEST_TIMEOUT_MS),
86
+ });
87
+ }
88
+
89
+ if (!response.ok) throw new Error(`Slack API HTTP ${response.status}: ${response.statusText}`);
90
+ return (await response.json()) as Record<string, unknown>;
91
+ }
92
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Remote Questions — status helpers
3
+ */
4
+
5
+ import { existsSync, readdirSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { homedir } from "node:os";
8
+ import { readPromptRecord } from "./store.js";
9
+
10
+ export interface LatestPromptSummary {
11
+ id: string;
12
+ status: string;
13
+ updatedAt: number;
14
+ }
15
+
16
+ export function getLatestPromptSummary(): LatestPromptSummary | null {
17
+ const runtimeDir = join(homedir(), ".gsd", "runtime", "remote-questions");
18
+ if (!existsSync(runtimeDir)) return null;
19
+ const files = readdirSync(runtimeDir).filter((f) => f.endsWith(".json"));
20
+ if (files.length === 0) return null;
21
+
22
+ let latest: LatestPromptSummary | null = null;
23
+ for (const file of files) {
24
+ const record = readPromptRecord(file.replace(/\.json$/, ""));
25
+ if (!record) continue;
26
+ if (!latest || record.updatedAt > latest.updatedAt) {
27
+ latest = { id: record.id, status: record.status, updatedAt: record.updatedAt };
28
+ }
29
+ }
30
+ return latest;
31
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Remote Questions — durable prompt store
3
+ */
4
+
5
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { homedir } from "node:os";
8
+ import type { RemotePrompt, RemotePromptRecord, RemotePromptRef, RemoteAnswer, RemotePromptStatus } from "./types.js";
9
+
10
+ function runtimeDir(): string {
11
+ return join(homedir(), ".gsd", "runtime", "remote-questions");
12
+ }
13
+
14
+ function recordPath(id: string): string {
15
+ return join(runtimeDir(), `${id}.json`);
16
+ }
17
+
18
+ export function createPromptRecord(prompt: RemotePrompt): RemotePromptRecord {
19
+ return {
20
+ version: 1,
21
+ id: prompt.id,
22
+ createdAt: prompt.createdAt,
23
+ updatedAt: Date.now(),
24
+ status: "pending",
25
+ channel: prompt.channel,
26
+ timeoutAt: prompt.timeoutAt,
27
+ pollIntervalMs: prompt.pollIntervalMs,
28
+ questions: prompt.questions,
29
+ context: prompt.context,
30
+ };
31
+ }
32
+
33
+ export function writePromptRecord(record: RemotePromptRecord): void {
34
+ mkdirSync(runtimeDir(), { recursive: true });
35
+ writeFileSync(recordPath(record.id), JSON.stringify(record, null, 2) + "\n", "utf-8");
36
+ }
37
+
38
+ export function readPromptRecord(id: string): RemotePromptRecord | null {
39
+ const path = recordPath(id);
40
+ if (!existsSync(path)) return null;
41
+ try {
42
+ return JSON.parse(readFileSync(path, "utf-8")) as RemotePromptRecord;
43
+ } catch {
44
+ return null;
45
+ }
46
+ }
47
+
48
+ export function updatePromptRecord(
49
+ id: string,
50
+ updates: Partial<RemotePromptRecord>,
51
+ ): RemotePromptRecord | null {
52
+ const current = readPromptRecord(id);
53
+ if (!current) return null;
54
+ const next: RemotePromptRecord = {
55
+ ...current,
56
+ ...updates,
57
+ updatedAt: Date.now(),
58
+ };
59
+ writePromptRecord(next);
60
+ return next;
61
+ }
62
+
63
+ export function markPromptDispatched(id: string, ref: RemotePromptRef): RemotePromptRecord | null {
64
+ return updatePromptRecord(id, { ref, status: "pending" });
65
+ }
66
+
67
+ export function markPromptAnswered(id: string, response: RemoteAnswer): RemotePromptRecord | null {
68
+ return updatePromptRecord(id, { response, status: "answered", lastPollAt: Date.now() });
69
+ }
70
+
71
+ export function markPromptStatus(id: string, status: RemotePromptStatus, lastError?: string): RemotePromptRecord | null {
72
+ return updatePromptRecord(id, {
73
+ status,
74
+ lastPollAt: Date.now(),
75
+ ...(lastError ? { lastError } : {}),
76
+ });
77
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Remote Questions — shared types
3
+ */
4
+
5
+ export type RemoteChannel = "slack" | "discord";
6
+
7
+ export interface RemoteQuestionOption {
8
+ label: string;
9
+ description: string;
10
+ }
11
+
12
+ export interface RemoteQuestion {
13
+ id: string;
14
+ header: string;
15
+ question: string;
16
+ options: RemoteQuestionOption[];
17
+ allowMultiple: boolean;
18
+ }
19
+
20
+ export interface RemotePrompt {
21
+ id: string;
22
+ channel: RemoteChannel;
23
+ createdAt: number;
24
+ timeoutAt: number;
25
+ pollIntervalMs: number;
26
+ questions: RemoteQuestion[];
27
+ context?: {
28
+ source: string;
29
+ };
30
+ }
31
+
32
+ export interface RemotePromptRef {
33
+ id: string;
34
+ channel: RemoteChannel;
35
+ messageId: string;
36
+ channelId: string;
37
+ threadTs?: string;
38
+ threadUrl?: string;
39
+ }
40
+
41
+ export interface RemoteAnswer {
42
+ answers: Record<string, { answers: string[]; user_note?: string }>;
43
+ }
44
+
45
+ export type RemotePromptStatus = "pending" | "answered" | "timed_out" | "failed" | "cancelled";
46
+
47
+ export interface RemotePromptRecord {
48
+ version: 1;
49
+ id: string;
50
+ createdAt: number;
51
+ updatedAt: number;
52
+ status: RemotePromptStatus;
53
+ channel: RemoteChannel;
54
+ timeoutAt: number;
55
+ pollIntervalMs: number;
56
+ questions: RemoteQuestion[];
57
+ ref?: RemotePromptRef;
58
+ response?: RemoteAnswer;
59
+ lastPollAt?: number;
60
+ lastError?: string;
61
+ context?: {
62
+ source: string;
63
+ };
64
+ }
65
+
66
+ export interface RemoteDispatchResult {
67
+ ref: RemotePromptRef;
68
+ }
69
+
70
+ export interface ChannelAdapter {
71
+ readonly name: RemoteChannel;
72
+ validate(): Promise<void>;
73
+ sendPrompt(prompt: RemotePrompt): Promise<RemoteDispatchResult>;
74
+ pollAnswer(prompt: RemotePrompt, ref: RemotePromptRef): Promise<RemoteAnswer | null>;
75
+ }