gsd-pi 2.76.0-dev.fe143342a → 2.77.0-dev.1d17f366c

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 (597) hide show
  1. package/README.md +17 -35
  2. package/dist/claude-cli-check.js +32 -3
  3. package/dist/cli-web-branch.d.ts +1 -0
  4. package/dist/cli-web-branch.js +3 -0
  5. package/dist/cli.js +38 -2
  6. package/dist/extension-discovery.d.ts +6 -0
  7. package/dist/extension-discovery.js +37 -0
  8. package/dist/extension-registry.d.ts +3 -0
  9. package/dist/extension-sort.d.ts +18 -0
  10. package/dist/extension-sort.js +114 -0
  11. package/dist/extension-validator.d.ts +47 -0
  12. package/dist/extension-validator.js +127 -0
  13. package/dist/loader.js +35 -7
  14. package/dist/onboarding.js +45 -0
  15. package/dist/provider-migrations.d.ts +18 -0
  16. package/dist/provider-migrations.js +14 -0
  17. package/dist/resources/extensions/claude-code-cli/readiness.js +4 -3
  18. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +78 -59
  19. package/dist/resources/extensions/cmux/index.js +20 -0
  20. package/dist/resources/extensions/github-sync/templates.js +103 -0
  21. package/dist/resources/extensions/google-search/extension-manifest.json +5 -4
  22. package/dist/resources/extensions/google-search/index.js +3 -375
  23. package/dist/resources/extensions/gsd/abandon-detect.js +44 -0
  24. package/dist/resources/extensions/gsd/auto/loop.js +90 -2
  25. package/dist/resources/extensions/gsd/auto/phases.js +95 -21
  26. package/dist/resources/extensions/gsd/auto/resolve.js +24 -0
  27. package/dist/resources/extensions/gsd/auto/run-unit.js +48 -4
  28. package/dist/resources/extensions/gsd/auto/session.js +18 -1
  29. package/dist/resources/extensions/gsd/auto/turn-epoch.js +95 -0
  30. package/dist/resources/extensions/gsd/auto-dispatch.js +115 -17
  31. package/dist/resources/extensions/gsd/auto-loop.js +1 -1
  32. package/dist/resources/extensions/gsd/auto-model-selection.js +1 -1
  33. package/dist/resources/extensions/gsd/auto-post-unit.js +90 -2
  34. package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
  35. package/dist/resources/extensions/gsd/auto-recovery.js +46 -1
  36. package/dist/resources/extensions/gsd/auto-start.js +45 -39
  37. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +11 -5
  38. package/dist/resources/extensions/gsd/auto-unit-closeout.js +11 -2
  39. package/dist/resources/extensions/gsd/auto-worktree.js +109 -61
  40. package/dist/resources/extensions/gsd/auto.js +97 -31
  41. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +27 -1
  42. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +4 -2
  43. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +11 -0
  44. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -6
  45. package/dist/resources/extensions/gsd/bootstrap/system-context.js +11 -6
  46. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
  47. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  48. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +31 -4
  49. package/dist/resources/extensions/gsd/commands-cmux.js +9 -6
  50. package/dist/resources/extensions/gsd/commands-extensions.js +634 -43
  51. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  52. package/dist/resources/extensions/gsd/dispatch-guard.js +29 -3
  53. package/dist/resources/extensions/gsd/file-lock.js +49 -9
  54. package/dist/resources/extensions/gsd/git-service.js +1 -0
  55. package/dist/resources/extensions/gsd/gitignore.js +2 -0
  56. package/dist/resources/extensions/gsd/gsd-db.js +90 -30
  57. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -1
  58. package/dist/resources/extensions/gsd/guided-flow.js +212 -9
  59. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  60. package/dist/resources/extensions/gsd/journal.js +17 -2
  61. package/dist/resources/extensions/gsd/key-manager.js +22 -0
  62. package/dist/resources/extensions/gsd/milestone-actions.js +15 -0
  63. package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
  64. package/dist/resources/extensions/gsd/model-router.js +36 -3
  65. package/dist/resources/extensions/gsd/notifications.js +30 -16
  66. package/dist/resources/extensions/gsd/pre-execution-checks.js +31 -6
  67. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +29 -2
  68. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  69. package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  70. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  71. package/dist/resources/extensions/gsd/prompts/system.md +1 -0
  72. package/dist/resources/extensions/gsd/reports.js +5 -4
  73. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  74. package/dist/resources/extensions/gsd/safety/file-change-validator.js +12 -4
  75. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  76. package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
  77. package/dist/resources/extensions/gsd/state.js +25 -25
  78. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  79. package/dist/resources/extensions/gsd/tools/complete-milestone.js +16 -10
  80. package/dist/resources/extensions/gsd/tools/complete-slice.js +21 -0
  81. package/dist/resources/extensions/gsd/tools/complete-task.js +31 -0
  82. package/dist/resources/extensions/gsd/uok/audit.js +18 -2
  83. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
  84. package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
  85. package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
  86. package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
  87. package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
  88. package/dist/resources/extensions/gsd/uok/plan-v2.js +30 -7
  89. package/dist/resources/extensions/gsd/uok/writer.js +82 -0
  90. package/dist/resources/extensions/gsd/workflow-logger.js +10 -2
  91. package/dist/resources/extensions/gsd/worktree-manager.js +1 -0
  92. package/dist/resources/extensions/gsd/worktree-resolver.js +50 -10
  93. package/dist/resources/extensions/mcp-client/auth.js +10 -1
  94. package/dist/resources/extensions/mcp-client/index.js +118 -9
  95. package/dist/resources/extensions/shared/cmux-events.js +12 -0
  96. package/dist/resources/extensions/shared/rtk-session-stats.js +1 -2
  97. package/dist/resources/skills/create-skill/SKILL.md +2 -2
  98. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  99. package/dist/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  100. package/dist/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  101. package/dist/resources/skills/verify-before-complete/SKILL.md +2 -1
  102. package/dist/resources/skills/write-docs/SKILL.md +2 -1
  103. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  104. package/dist/web/standalone/.next/BUILD_ID +1 -1
  105. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  106. package/dist/web/standalone/.next/build-manifest.json +3 -3
  107. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  108. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  127. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  129. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  131. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  133. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  135. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  137. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  139. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  141. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  143. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  145. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  147. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  153. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/notifications/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  159. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/session/events/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  173. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  175. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  177. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  179. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  183. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  185. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  187. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  189. package/dist/web/standalone/.next/server/app/index.html +1 -1
  190. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  191. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  192. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  193. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  194. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  195. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  196. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  197. package/dist/web/standalone/.next/server/chunks/1926.js +1 -0
  198. package/dist/web/standalone/.next/server/chunks/6897.js +2 -2
  199. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  201. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  202. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  203. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  204. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  205. package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +11 -0
  206. package/dist/web/standalone/.next/static/chunks/{webpack-5fc74f13a25fa1bb.js → webpack-2e68521d7c82f7c2.js} +1 -1
  207. package/dist/welcome-screen.js +6 -1
  208. package/dist/wizard.js +2 -0
  209. package/package.json +16 -14
  210. package/packages/daemon/package.json +2 -2
  211. package/packages/mcp-server/README.md +3 -3
  212. package/packages/mcp-server/dist/env-writer.d.ts +1 -0
  213. package/packages/mcp-server/dist/env-writer.d.ts.map +1 -1
  214. package/packages/mcp-server/dist/env-writer.js +74 -6
  215. package/packages/mcp-server/dist/env-writer.js.map +1 -1
  216. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  217. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  218. package/packages/mcp-server/dist/remote-questions.js +732 -0
  219. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  220. package/packages/mcp-server/dist/server.d.ts +7 -0
  221. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  222. package/packages/mcp-server/dist/server.js +95 -10
  223. package/packages/mcp-server/dist/server.js.map +1 -1
  224. package/packages/mcp-server/dist/session-manager.d.ts +14 -0
  225. package/packages/mcp-server/dist/session-manager.d.ts.map +1 -1
  226. package/packages/mcp-server/dist/session-manager.js +49 -1
  227. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  228. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  229. package/packages/mcp-server/dist/workflow-tools.js +15 -6
  230. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  231. package/packages/mcp-server/package.json +9 -3
  232. package/packages/mcp-server/src/env-writer.test.ts +79 -1
  233. package/packages/mcp-server/src/env-writer.ts +76 -6
  234. package/packages/mcp-server/src/mcp-server.test.ts +67 -0
  235. package/packages/mcp-server/src/readers/readers.test.ts +5 -1
  236. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  237. package/packages/mcp-server/src/remote-questions.ts +916 -0
  238. package/packages/mcp-server/src/server.ts +118 -16
  239. package/packages/mcp-server/src/session-manager.ts +43 -1
  240. package/packages/mcp-server/src/workflow-tools.test.ts +44 -0
  241. package/packages/mcp-server/src/workflow-tools.ts +19 -6
  242. package/packages/mcp-server/tsconfig.test.json +19 -0
  243. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  244. package/packages/native/package.json +6 -1
  245. package/packages/native/src/__tests__/clipboard.test.mjs +69 -23
  246. package/packages/native/tsconfig.tsbuildinfo +1 -1
  247. package/packages/pi-agent-core/package.json +6 -1
  248. package/packages/pi-agent-core/src/agent-loop.test.ts +220 -15
  249. package/packages/pi-ai/dist/models/custom.d.ts +38 -0
  250. package/packages/pi-ai/dist/models/custom.d.ts.map +1 -1
  251. package/packages/pi-ai/dist/models/custom.js +41 -0
  252. package/packages/pi-ai/dist/models/custom.js.map +1 -1
  253. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  254. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  255. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  256. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  257. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  258. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  259. package/packages/pi-ai/dist/providers/anthropic.js +8 -3
  260. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  261. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  262. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  263. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  264. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  265. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  266. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  267. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  268. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  269. package/packages/pi-ai/package.json +6 -1
  270. package/packages/pi-ai/src/models/custom.ts +42 -0
  271. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  272. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  273. package/packages/pi-ai/src/providers/anthropic.ts +9 -3
  274. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  275. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  276. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  277. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +3 -2
  278. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  279. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +2 -0
  280. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  281. package/packages/pi-coding-agent/dist/core/agent-session.js +7 -0
  282. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +25 -0
  284. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +105 -6
  286. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js +230 -28
  288. package/packages/pi-coding-agent/dist/core/compaction/compaction.test.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts +30 -2
  290. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
  291. package/packages/pi-coding-agent/dist/core/compaction/utils.js +113 -12
  292. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  293. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +1 -0
  294. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  295. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +29 -18
  296. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  297. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts +2 -0
  298. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts.map +1 -0
  299. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js +130 -0
  300. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js.map +1 -0
  301. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +56 -1
  302. package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +8 -15
  304. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
  305. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts +25 -0
  306. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.d.ts.map +1 -0
  307. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js +109 -0
  308. package/packages/pi-coding-agent/dist/core/extensions/extension-discovery.js.map +1 -0
  309. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts +67 -0
  310. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.d.ts.map +1 -0
  311. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js +167 -0
  312. package/packages/pi-coding-agent/dist/core/extensions/extension-registry.js.map +1 -0
  313. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +3 -2
  314. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  315. package/packages/pi-coding-agent/dist/core/extensions/loader.js +24 -8
  316. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  317. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
  318. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  319. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  320. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +14 -0
  321. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  322. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  323. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +11 -0
  324. package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
  325. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +2 -2
  326. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  327. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  328. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  329. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  330. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  331. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  332. package/packages/pi-coding-agent/dist/core/model-registry.js +14 -0
  333. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  334. package/packages/pi-coding-agent/dist/core/resource-loader.js +1 -1
  335. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  336. package/packages/pi-coding-agent/dist/core/sdk.d.ts +1 -0
  337. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  338. package/packages/pi-coding-agent/dist/core/sdk.js +4 -1
  339. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  340. package/packages/pi-coding-agent/dist/core/sdk.test.js +19 -1
  341. package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
  342. package/packages/pi-coding-agent/dist/core/session-manager.js +1 -1
  343. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  344. package/packages/pi-coding-agent/dist/core/session-manager.test.js +21 -1
  345. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  346. package/packages/pi-coding-agent/dist/core/system-prompt.js +3 -3
  347. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  348. package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js +2 -1
  349. package/packages/pi-coding-agent/dist/core/tools/path-utils.test.js.map +1 -1
  350. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +15 -6
  351. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -1
  352. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  353. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
  354. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  355. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +7 -1
  356. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  357. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +31 -9
  358. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
  359. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +14 -0
  360. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  361. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  362. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  363. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  364. package/packages/pi-coding-agent/package.json +6 -1
  365. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +3 -2
  366. package/packages/pi-coding-agent/src/core/agent-session.ts +11 -0
  367. package/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +368 -28
  368. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +122 -6
  369. package/packages/pi-coding-agent/src/core/compaction/utils.ts +111 -13
  370. package/packages/pi-coding-agent/src/core/compaction-orchestrator.test.ts +154 -0
  371. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +32 -18
  372. package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +68 -1
  373. package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +9 -18
  374. package/packages/pi-coding-agent/src/core/extensions/extension-discovery.ts +119 -0
  375. package/packages/pi-coding-agent/src/core/extensions/extension-registry.ts +222 -0
  376. package/packages/pi-coding-agent/src/core/extensions/loader.ts +24 -11
  377. package/packages/pi-coding-agent/src/core/extensions/runner.ts +2 -0
  378. package/packages/pi-coding-agent/src/core/extensions/types.ts +15 -0
  379. package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +13 -0
  380. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +2 -2
  381. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  382. package/packages/pi-coding-agent/src/core/model-registry.ts +16 -0
  383. package/packages/pi-coding-agent/src/core/resource-loader.ts +1 -1
  384. package/packages/pi-coding-agent/src/core/sdk.test.ts +25 -1
  385. package/packages/pi-coding-agent/src/core/sdk.ts +10 -3
  386. package/packages/pi-coding-agent/src/core/session-manager.test.ts +30 -1
  387. package/packages/pi-coding-agent/src/core/session-manager.ts +1 -1
  388. package/packages/pi-coding-agent/src/core/system-prompt.ts +3 -3
  389. package/packages/pi-coding-agent/src/core/tools/path-utils.test.ts +2 -1
  390. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +17 -7
  391. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +14 -5
  392. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +45 -11
  393. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +14 -0
  394. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  395. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  396. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +12 -5
  397. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  398. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +21 -0
  399. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  400. package/packages/pi-tui/dist/stdin-buffer.d.ts +7 -0
  401. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  402. package/packages/pi-tui/dist/stdin-buffer.js +20 -0
  403. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  404. package/packages/pi-tui/package.json +6 -1
  405. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +20 -5
  406. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +27 -0
  407. package/packages/pi-tui/src/stdin-buffer.ts +26 -0
  408. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  409. package/packages/rpc-client/package.json +6 -1
  410. package/pkg/package.json +1 -1
  411. package/scripts/install.js +512 -0
  412. package/scripts/lib/workspace-manifest.cjs +86 -0
  413. package/scripts/link-workspace-packages.cjs +5 -17
  414. package/scripts/postinstall.js +9 -178
  415. package/src/resources/extensions/claude-code-cli/readiness.ts +4 -3
  416. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +91 -63
  417. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +114 -12
  418. package/src/resources/extensions/cmux/index.ts +35 -10
  419. package/src/resources/extensions/github-sync/templates.ts +151 -0
  420. package/src/resources/extensions/github-sync/tests/templates.test.ts +59 -0
  421. package/src/resources/extensions/google-search/extension-manifest.json +5 -4
  422. package/src/resources/extensions/google-search/index.ts +9 -470
  423. package/src/resources/extensions/gsd/abandon-detect.ts +62 -0
  424. package/src/resources/extensions/gsd/auto/loop-deps.ts +14 -1
  425. package/src/resources/extensions/gsd/auto/loop.ts +104 -2
  426. package/src/resources/extensions/gsd/auto/phases.ts +123 -21
  427. package/src/resources/extensions/gsd/auto/resolve.ts +29 -0
  428. package/src/resources/extensions/gsd/auto/run-unit.ts +56 -4
  429. package/src/resources/extensions/gsd/auto/session.ts +28 -1
  430. package/src/resources/extensions/gsd/auto/turn-epoch.ts +108 -0
  431. package/src/resources/extensions/gsd/auto/types.ts +1 -1
  432. package/src/resources/extensions/gsd/auto-dispatch.ts +117 -16
  433. package/src/resources/extensions/gsd/auto-loop.ts +1 -1
  434. package/src/resources/extensions/gsd/auto-model-selection.ts +1 -1
  435. package/src/resources/extensions/gsd/auto-post-unit.ts +92 -3
  436. package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
  437. package/src/resources/extensions/gsd/auto-recovery.ts +40 -1
  438. package/src/resources/extensions/gsd/auto-start.ts +48 -52
  439. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -5
  440. package/src/resources/extensions/gsd/auto-unit-closeout.ts +14 -3
  441. package/src/resources/extensions/gsd/auto-worktree.ts +122 -68
  442. package/src/resources/extensions/gsd/auto.ts +105 -35
  443. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -1
  444. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -2
  445. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +11 -0
  446. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +18 -6
  447. package/src/resources/extensions/gsd/bootstrap/system-context.ts +13 -9
  448. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
  449. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  450. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +27 -8
  451. package/src/resources/extensions/gsd/commands-cmux.ts +10 -6
  452. package/src/resources/extensions/gsd/commands-extensions.ts +747 -41
  453. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  454. package/src/resources/extensions/gsd/dispatch-guard.ts +26 -2
  455. package/src/resources/extensions/gsd/file-lock.ts +84 -11
  456. package/src/resources/extensions/gsd/git-service.ts +1 -0
  457. package/src/resources/extensions/gsd/gitignore.ts +2 -1
  458. package/src/resources/extensions/gsd/gsd-db.ts +92 -32
  459. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -1
  460. package/src/resources/extensions/gsd/guided-flow.ts +259 -10
  461. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  462. package/src/resources/extensions/gsd/journal.ts +29 -3
  463. package/src/resources/extensions/gsd/key-manager.ts +22 -0
  464. package/src/resources/extensions/gsd/milestone-actions.ts +18 -0
  465. package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
  466. package/src/resources/extensions/gsd/model-router.ts +42 -1
  467. package/src/resources/extensions/gsd/notifications.ts +27 -15
  468. package/src/resources/extensions/gsd/pre-execution-checks.ts +33 -7
  469. package/src/resources/extensions/gsd/preferences-types.ts +8 -0
  470. package/src/resources/extensions/gsd/prompts/discuss-headless.md +29 -2
  471. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  472. package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
  473. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  474. package/src/resources/extensions/gsd/prompts/system.md +1 -0
  475. package/src/resources/extensions/gsd/reports.ts +5 -4
  476. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  477. package/src/resources/extensions/gsd/safety/file-change-validator.ts +16 -3
  478. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  479. package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
  480. package/src/resources/extensions/gsd/state.ts +35 -30
  481. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +238 -4
  482. package/src/resources/extensions/gsd/tests/auto-mode-guards.test.ts +79 -0
  483. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  484. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +122 -0
  485. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +141 -0
  486. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +63 -0
  487. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +23 -0
  488. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  489. package/src/resources/extensions/gsd/tests/cmux.test.ts +5 -9
  490. package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +15 -0
  491. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +61 -1
  492. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  493. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  494. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +161 -0
  495. package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
  496. package/src/resources/extensions/gsd/tests/derive-state.test.ts +1 -2
  497. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +14 -9
  498. package/src/resources/extensions/gsd/tests/dispatch-guard-summary-db-mismatch.test.ts +77 -0
  499. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
  500. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
  501. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +31 -0
  502. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
  503. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +1 -1
  504. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  505. package/src/resources/extensions/gsd/tests/exec-history.test.ts +113 -0
  506. package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
  507. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +38 -0
  508. package/src/resources/extensions/gsd/tests/file-lock.test.ts +86 -12
  509. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +131 -0
  510. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +296 -1
  511. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
  512. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +30 -0
  513. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +4 -2
  514. package/src/resources/extensions/gsd/tests/integration/gitignore-tracked-gsd.test.ts +1 -0
  515. package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +30 -0
  516. package/src/resources/extensions/gsd/tests/integration/worktree-e2e.test.ts +11 -0
  517. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  518. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +66 -0
  519. package/src/resources/extensions/gsd/tests/key-manager.test.ts +2 -0
  520. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +76 -0
  521. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  522. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +12 -0
  523. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  524. package/src/resources/extensions/gsd/tests/milestone-status-authoritative.test.ts +3 -3
  525. package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
  526. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +4 -2
  527. package/src/resources/extensions/gsd/tests/parallel-commit-scope.test.ts +5 -0
  528. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
  529. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +150 -0
  530. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +37 -0
  531. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  532. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +337 -0
  533. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  534. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +39 -25
  535. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +181 -0
  536. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +13 -7
  537. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  538. package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +170 -0
  539. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  540. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +230 -0
  541. package/src/resources/extensions/gsd/tests/rewrite-docs-abandon-detect.test.ts +195 -0
  542. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  543. package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +413 -0
  544. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  545. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
  546. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  547. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +24 -0
  548. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
  549. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +2 -2
  550. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  551. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  552. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +50 -2
  553. package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +162 -0
  554. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
  555. package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
  556. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
  557. package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
  558. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +42 -2
  559. package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
  560. package/src/resources/extensions/gsd/tests/validate-extension-package.test.ts +168 -0
  561. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +138 -5
  562. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +25 -2
  563. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  564. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +35 -0
  565. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +6 -1
  566. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -5
  567. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  568. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  569. package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
  570. package/src/resources/extensions/gsd/tools/complete-slice.ts +38 -0
  571. package/src/resources/extensions/gsd/tools/complete-task.ts +49 -0
  572. package/src/resources/extensions/gsd/uok/audit.ts +20 -2
  573. package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
  574. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
  575. package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
  576. package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
  577. package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
  578. package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
  579. package/src/resources/extensions/gsd/uok/plan-v2.ts +39 -8
  580. package/src/resources/extensions/gsd/uok/writer.ts +113 -0
  581. package/src/resources/extensions/gsd/workflow-logger.ts +23 -3
  582. package/src/resources/extensions/gsd/worktree-manager.ts +1 -0
  583. package/src/resources/extensions/gsd/worktree-resolver.ts +54 -9
  584. package/src/resources/extensions/mcp-client/auth.ts +12 -1
  585. package/src/resources/extensions/mcp-client/index.ts +129 -10
  586. package/src/resources/extensions/shared/cmux-events.ts +59 -0
  587. package/src/resources/extensions/shared/rtk-session-stats.ts +1 -2
  588. package/src/resources/skills/create-skill/SKILL.md +2 -2
  589. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  590. package/src/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  591. package/src/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  592. package/src/resources/skills/verify-before-complete/SKILL.md +2 -1
  593. package/src/resources/skills/write-docs/SKILL.md +2 -1
  594. package/dist/web/standalone/.next/server/chunks/7461.js +0 -1
  595. package/dist/web/standalone/.next/static/chunks/2826.e59e8578e2e28639.js +0 -9
  596. /package/dist/web/standalone/.next/static/{n21VtX2hZlkpdEUO_nU4z → vidAVJkURvTJ0_V2-64ro}/_buildManifest.js +0 -0
  597. /package/dist/web/standalone/.next/static/{n21VtX2hZlkpdEUO_nU4z → vidAVJkURvTJ0_V2-64ro}/_ssgManifest.js +0 -0
@@ -0,0 +1,732 @@
1
+ /**
2
+ * Remote Questions — self-contained MCP-server adapter
3
+ *
4
+ * Mirrors the routing logic from src/resources/extensions/ask-user-questions.ts
5
+ * but without any dependency on @gsd/pi-coding-agent or the main src/ tree.
6
+ * All channel adapters (Discord, Slack, Telegram), config resolution, HTTP
7
+ * calls, and polling are inlined here so packages/mcp-server remains a
8
+ * standalone package.
9
+ *
10
+ * Entry points consumed by server.ts:
11
+ * isRemoteConfigured() — cheap synchronous config check
12
+ * tryRemoteQuestions(...) — dispatch + poll + return result
13
+ */
14
+ import { readFileSync } from 'node:fs';
15
+ import { homedir } from 'node:os';
16
+ import { join } from 'node:path';
17
+ import { randomUUID } from 'node:crypto';
18
+ // ---------------------------------------------------------------------------
19
+ // Constants
20
+ // ---------------------------------------------------------------------------
21
+ const PER_REQUEST_TIMEOUT_MS = 15_000;
22
+ const DISCORD_API = 'https://discord.com/api/v10';
23
+ const SLACK_API = 'https://slack.com/api';
24
+ const TELEGRAM_API = 'https://api.telegram.org';
25
+ const DISCORD_NUMBER_EMOJIS = ['1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣'];
26
+ const SLACK_NUMBER_REACTION_NAMES = ['one', 'two', 'three', 'four', 'five'];
27
+ const DEFAULT_TIMEOUT_MINUTES = 5;
28
+ const DEFAULT_POLL_INTERVAL_SECONDS = 5;
29
+ const MIN_TIMEOUT_MINUTES = 1;
30
+ const MAX_TIMEOUT_MINUTES = 30;
31
+ const MIN_POLL_INTERVAL_SECONDS = 2;
32
+ const MAX_POLL_INTERVAL_SECONDS = 30;
33
+ const CHANNEL_ID_PATTERNS = {
34
+ slack: /^[A-Z0-9]{9,12}$/,
35
+ discord: /^\d{17,20}$/,
36
+ telegram: /^-?\d{5,20}$/,
37
+ };
38
+ const ENV_KEYS = {
39
+ slack: 'SLACK_BOT_TOKEN',
40
+ discord: 'DISCORD_BOT_TOKEN',
41
+ telegram: 'TELEGRAM_BOT_TOKEN',
42
+ };
43
+ // ---------------------------------------------------------------------------
44
+ // Config resolution — reads ~/.gsd/PREFERENCES.md YAML frontmatter
45
+ // ---------------------------------------------------------------------------
46
+ function clampNumber(value, fallback, min, max) {
47
+ const n = typeof value === 'number' ? value : Number(value);
48
+ if (!Number.isFinite(n))
49
+ return fallback;
50
+ return Math.max(min, Math.min(max, n));
51
+ }
52
+ /**
53
+ * Minimal YAML frontmatter reader. Handles:
54
+ * ---
55
+ * key: value
56
+ * nested_key:
57
+ * child: value
58
+ * ---
59
+ * Sufficient for the flat remote_questions config block.
60
+ */
61
+ function parseSimpleFrontmatter(content) {
62
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/m);
63
+ if (!match)
64
+ return {};
65
+ const yaml = match[1];
66
+ const result = {};
67
+ let currentSection = null;
68
+ const sectionData = {};
69
+ for (const rawLine of yaml.split('\n')) {
70
+ const line = rawLine.replace(/\r$/, '');
71
+ if (!line.trim() || line.trim().startsWith('#'))
72
+ continue;
73
+ // Top-level key (no indent)
74
+ const topMatch = line.match(/^([a-zA-Z_][a-zA-Z0-9_]*):\s*(.*)$/);
75
+ if (topMatch) {
76
+ currentSection = topMatch[1];
77
+ const val = topMatch[2].trim();
78
+ if (val) {
79
+ result[currentSection] = parseSimpleScalar(val);
80
+ currentSection = null; // scalar, no children
81
+ }
82
+ else {
83
+ sectionData[currentSection] = {};
84
+ result[currentSection] = sectionData[currentSection];
85
+ }
86
+ continue;
87
+ }
88
+ // Indented child key
89
+ const childMatch = line.match(/^\s+([a-zA-Z_][a-zA-Z0-9_]*):\s*(.*)$/);
90
+ if (childMatch && currentSection && sectionData[currentSection]) {
91
+ const childKey = childMatch[1];
92
+ const childVal = childMatch[2].trim();
93
+ sectionData[currentSection][childKey] = parseSimpleScalar(childVal);
94
+ }
95
+ }
96
+ return result;
97
+ }
98
+ function parseSimpleScalar(raw) {
99
+ const s = raw.replace(/^["']|["']$/g, '').trim();
100
+ if (s === 'true')
101
+ return true;
102
+ if (s === 'false')
103
+ return false;
104
+ if (s === 'null' || s === '~')
105
+ return null;
106
+ const n = Number(s);
107
+ if (s !== '' && !Number.isNaN(n))
108
+ return n;
109
+ return s;
110
+ }
111
+ function loadPreferencesFromFile(path) {
112
+ try {
113
+ const content = readFileSync(path, 'utf-8');
114
+ return parseSimpleFrontmatter(content);
115
+ }
116
+ catch {
117
+ return null;
118
+ }
119
+ }
120
+ function resolveRemoteConfig() {
121
+ const gsdHome = process.env['GSD_HOME'] ?? join(homedir(), '.gsd');
122
+ const globalPath = join(gsdHome, 'PREFERENCES.md');
123
+ const prefs = loadPreferencesFromFile(globalPath);
124
+ if (!prefs)
125
+ return null;
126
+ const rq = prefs['remote_questions'];
127
+ if (!rq || !rq['channel'] || !rq['channel_id'])
128
+ return null;
129
+ const channel = String(rq['channel']);
130
+ if (channel !== 'slack' && channel !== 'discord' && channel !== 'telegram')
131
+ return null;
132
+ const channelId = String(rq['channel_id']);
133
+ if (!CHANNEL_ID_PATTERNS[channel].test(channelId))
134
+ return null;
135
+ const token = process.env[ENV_KEYS[channel]];
136
+ if (!token)
137
+ return null;
138
+ const timeoutMs = clampNumber(rq['timeout_minutes'], DEFAULT_TIMEOUT_MINUTES, MIN_TIMEOUT_MINUTES, MAX_TIMEOUT_MINUTES) * 60 * 1000;
139
+ const pollIntervalMs = clampNumber(rq['poll_interval_seconds'], DEFAULT_POLL_INTERVAL_SECONDS, MIN_POLL_INTERVAL_SECONDS, MAX_POLL_INTERVAL_SECONDS) * 1000;
140
+ return { channel, channelId, timeoutMs, pollIntervalMs, token };
141
+ }
142
+ /**
143
+ * Cheap synchronous check — does not make any HTTP requests.
144
+ */
145
+ export function isRemoteConfigured() {
146
+ return resolveRemoteConfig() !== null;
147
+ }
148
+ // ---------------------------------------------------------------------------
149
+ // HTTP helper
150
+ // ---------------------------------------------------------------------------
151
+ async function apiRequest(url, method, body, authScheme, authToken, errorLabel) {
152
+ const headers = {
153
+ Authorization: `${authScheme} ${authToken}`,
154
+ };
155
+ const init = {
156
+ method,
157
+ headers,
158
+ signal: AbortSignal.timeout(PER_REQUEST_TIMEOUT_MS),
159
+ };
160
+ if (body !== undefined) {
161
+ headers['Content-Type'] = 'application/json';
162
+ init.body = JSON.stringify(body);
163
+ }
164
+ const response = await fetch(url, init);
165
+ if (response.status === 204)
166
+ return {};
167
+ if (!response.ok) {
168
+ const text = await response.text().catch(() => '');
169
+ const safeText = text.length > 200 ? text.slice(0, 200) + '\u2026' : text;
170
+ throw new Error(`${errorLabel} HTTP ${response.status}: ${safeText}`);
171
+ }
172
+ return response.json();
173
+ }
174
+ // ---------------------------------------------------------------------------
175
+ // Payload formatting
176
+ // ---------------------------------------------------------------------------
177
+ function formatForDiscord(prompt) {
178
+ const reactionEmojis = [];
179
+ const embeds = prompt.questions.map((q, questionIndex) => {
180
+ const supportsReactions = prompt.questions.length === 1;
181
+ const optionLines = q.options.map((opt, i) => {
182
+ const emoji = DISCORD_NUMBER_EMOJIS[i] ?? `${i + 1}.`;
183
+ if (supportsReactions && DISCORD_NUMBER_EMOJIS[i])
184
+ reactionEmojis.push(DISCORD_NUMBER_EMOJIS[i]);
185
+ return `${emoji} **${opt.label}** — ${opt.description}`;
186
+ });
187
+ const footerParts = [];
188
+ if (supportsReactions) {
189
+ footerParts.push(q.allowMultiple
190
+ ? 'Reply with comma-separated choices (`1,3`) or react with matching numbers'
191
+ : 'Reply with a number or react with the matching number');
192
+ }
193
+ else {
194
+ footerParts.push(`Question ${questionIndex + 1}/${prompt.questions.length} — reply with one line per question or use semicolons`);
195
+ }
196
+ footerParts.push(`Source: ${prompt.context.source}`);
197
+ return {
198
+ title: q.header,
199
+ description: q.question,
200
+ color: 0x7c3aed,
201
+ fields: [{ name: 'Options', value: optionLines.join('\n') }],
202
+ footer: { text: footerParts.join(' · ') },
203
+ };
204
+ });
205
+ return { embeds, reactionEmojis };
206
+ }
207
+ function formatForSlack(prompt) {
208
+ const blocks = [
209
+ { type: 'header', text: { type: 'plain_text', text: 'GSD needs your input' } },
210
+ ];
211
+ if (prompt.questions.length > 1) {
212
+ blocks.push({
213
+ type: 'context',
214
+ elements: [{ type: 'mrkdwn', text: 'Reply once in thread using one line per question or semicolons (`1; 2; custom note`).' }],
215
+ });
216
+ }
217
+ for (const q of prompt.questions) {
218
+ const supportsReactions = prompt.questions.length === 1;
219
+ blocks.push({ type: 'section', text: { type: 'mrkdwn', text: `*${q.header}*\n${q.question}` } });
220
+ blocks.push({
221
+ type: 'section',
222
+ text: { type: 'mrkdwn', text: q.options.map((opt, i) => `${i + 1}. *${opt.label}* — ${opt.description}`).join('\n') },
223
+ });
224
+ blocks.push({
225
+ type: 'context',
226
+ elements: [{
227
+ type: 'mrkdwn',
228
+ text: prompt.questions.length > 1
229
+ ? (q.allowMultiple ? 'For this question, use comma-separated numbers (`1,3`) or free text.' : 'For this question, use one number (`1`) or free text.')
230
+ : (q.allowMultiple
231
+ ? (supportsReactions ? 'Reply in thread with comma-separated numbers (`1,3`) or react with matching number emoji.' : 'Reply in thread with comma-separated numbers (`1,3`) or free text.')
232
+ : (supportsReactions ? 'Reply in thread with a number (`1`) or react with the matching number emoji.' : 'Reply in thread with a number (`1`) or free text.')),
233
+ }],
234
+ });
235
+ blocks.push({ type: 'divider' });
236
+ }
237
+ return blocks;
238
+ }
239
+ function formatForTelegram(prompt) {
240
+ const escape = (s) => s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
241
+ const lines = ['<b>GSD needs your input</b>', ''];
242
+ for (let qi = 0; qi < prompt.questions.length; qi++) {
243
+ const q = prompt.questions[qi];
244
+ lines.push(`<b>${escape(q.header)}</b>`);
245
+ lines.push(escape(q.question));
246
+ lines.push('');
247
+ for (let i = 0; i < q.options.length; i++) {
248
+ lines.push(`${i + 1}. <b>${escape(q.options[i].label)}</b> — ${escape(q.options[i].description)}`);
249
+ }
250
+ lines.push('');
251
+ if (prompt.questions.length === 1) {
252
+ lines.push(q.allowMultiple ? 'Reply with comma-separated numbers (1,3) or free text.' : 'Reply with a number or tap a button below.');
253
+ }
254
+ else {
255
+ lines.push(`Question ${qi + 1}/${prompt.questions.length} — reply with one line per question or use semicolons.`);
256
+ }
257
+ if (qi < prompt.questions.length - 1)
258
+ lines.push('');
259
+ }
260
+ const result = {
261
+ text: lines.join('\n'),
262
+ parse_mode: 'HTML',
263
+ };
264
+ if (prompt.questions.length === 1 && prompt.questions[0].options.length <= 5) {
265
+ result.reply_markup = {
266
+ inline_keyboard: prompt.questions[0].options.map((opt, i) => [{
267
+ text: `${i + 1}. ${opt.label}`,
268
+ callback_data: `${prompt.id}:${i}`,
269
+ }]),
270
+ };
271
+ }
272
+ return result;
273
+ }
274
+ // ---------------------------------------------------------------------------
275
+ // Response parsing
276
+ // ---------------------------------------------------------------------------
277
+ function parseAnswerForQuestion(text, q) {
278
+ if (!text)
279
+ return { answers: [], user_note: 'No response provided' };
280
+ if (/^[\d,\s]+$/.test(text)) {
281
+ const nums = text
282
+ .split(',')
283
+ .map((s) => parseInt(s.trim(), 10))
284
+ .filter((n) => !Number.isNaN(n) && n >= 1 && n <= q.options.length);
285
+ if (nums.length > 0) {
286
+ const selected = nums.map((n) => q.options[n - 1].label);
287
+ return { answers: q.allowMultiple ? selected : [selected[0]] };
288
+ }
289
+ }
290
+ const single = parseInt(text, 10);
291
+ if (!Number.isNaN(single) && single >= 1 && single <= q.options.length) {
292
+ return { answers: [q.options[single - 1].label] };
293
+ }
294
+ const truncated = text.length > 500 ? text.slice(0, 500) + '\u2026' : text;
295
+ return { answers: [], user_note: truncated };
296
+ }
297
+ function parseTextReply(text, questions) {
298
+ const answers = {};
299
+ const trimmed = text.trim();
300
+ if (questions.length === 1) {
301
+ answers[questions[0].id] = parseAnswerForQuestion(trimmed, questions[0]);
302
+ return { answers };
303
+ }
304
+ const parts = trimmed.includes(';')
305
+ ? trimmed.split(';').map((s) => s.trim()).filter(Boolean)
306
+ : trimmed.split('\n').map((s) => s.trim()).filter(Boolean);
307
+ for (let i = 0; i < questions.length; i++) {
308
+ answers[questions[i].id] = parseAnswerForQuestion(parts[i] ?? '', questions[i]);
309
+ }
310
+ return { answers };
311
+ }
312
+ function parseDiscordReactions(reactions, questions) {
313
+ const answers = {};
314
+ if (questions.length !== 1) {
315
+ for (const q of questions) {
316
+ answers[q.id] = { answers: [], user_note: 'Discord reactions are only supported for single-question prompts' };
317
+ }
318
+ return { answers };
319
+ }
320
+ const q = questions[0];
321
+ const picked = reactions
322
+ .filter((r) => DISCORD_NUMBER_EMOJIS.includes(r.emoji) && r.count > 0)
323
+ .map((r) => q.options[DISCORD_NUMBER_EMOJIS.indexOf(r.emoji)]?.label)
324
+ .filter((l) => Boolean(l));
325
+ answers[q.id] = picked.length > 0
326
+ ? { answers: q.allowMultiple ? picked : [picked[0]] }
327
+ : { answers: [], user_note: 'No clear response via reactions' };
328
+ return { answers };
329
+ }
330
+ function parseSlackReactions(reactionNames, questions) {
331
+ const answers = {};
332
+ if (questions.length !== 1) {
333
+ for (const q of questions) {
334
+ answers[q.id] = { answers: [], user_note: 'Slack reactions are only supported for single-question prompts' };
335
+ }
336
+ return { answers };
337
+ }
338
+ const q = questions[0];
339
+ const picked = reactionNames
340
+ .filter((name) => SLACK_NUMBER_REACTION_NAMES.includes(name))
341
+ .map((name) => q.options[SLACK_NUMBER_REACTION_NAMES.indexOf(name)]?.label)
342
+ .filter((l) => Boolean(l));
343
+ answers[q.id] = picked.length > 0
344
+ ? { answers: q.allowMultiple ? picked : [picked[0]] }
345
+ : { answers: [], user_note: 'No clear response via reactions' };
346
+ return { answers };
347
+ }
348
+ function parseTelegramCallbackData(callbackData, questions, promptId) {
349
+ const pattern = new RegExp(`^${promptId.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}:(\\d+)$`);
350
+ const match = callbackData.match(pattern);
351
+ if (match && questions.length === 1) {
352
+ const idx = parseInt(match[1], 10);
353
+ const q = questions[0];
354
+ if (idx >= 0 && idx < q.options.length) {
355
+ return { answers: { [q.id]: { answers: [q.options[idx].label] } } };
356
+ }
357
+ }
358
+ return null;
359
+ }
360
+ // --- Discord ---
361
+ async function discordValidate(token, channelId) {
362
+ const meRes = await apiRequest(`${DISCORD_API}/users/@me`, 'GET', undefined, 'Bot', token, 'Discord API');
363
+ if (!meRes['id'])
364
+ throw new Error('Discord auth failed: invalid token');
365
+ const botUserId = String(meRes['id']);
366
+ let guildId = null;
367
+ try {
368
+ const chanRes = await apiRequest(`${DISCORD_API}/channels/${channelId}`, 'GET', undefined, 'Bot', token, 'Discord API');
369
+ if (chanRes['guild_id'])
370
+ guildId = String(chanRes['guild_id']);
371
+ }
372
+ catch { /* non-fatal */ }
373
+ return { botUserId, guildId };
374
+ }
375
+ async function discordSend(prompt, token, channelId, guildId) {
376
+ const { embeds, reactionEmojis } = formatForDiscord(prompt);
377
+ const res = await apiRequest(`${DISCORD_API}/channels/${channelId}/messages`, 'POST', { content: '**GSD needs your input** — reply to this message with your answer', embeds }, 'Bot', token, 'Discord API');
378
+ if (!res['id'])
379
+ throw new Error(`Discord send failed: ${JSON.stringify(res)}`);
380
+ const messageId = String(res['id']);
381
+ if (prompt.questions.length === 1) {
382
+ for (const emoji of reactionEmojis) {
383
+ try {
384
+ await apiRequest(`${DISCORD_API}/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}/@me`, 'PUT', undefined, 'Bot', token, 'Discord API');
385
+ }
386
+ catch { /* best-effort */ }
387
+ }
388
+ }
389
+ const threadUrl = guildId ? `https://discord.com/channels/${guildId}/${channelId}/${messageId}` : undefined;
390
+ return { ref: { id: prompt.id, channel: 'discord', messageId, channelId, threadUrl } };
391
+ }
392
+ async function discordPoll(prompt, ref, token, botUserId) {
393
+ // Try reactions first for single-question prompts
394
+ if (prompt.questions.length === 1) {
395
+ const reactions = [];
396
+ for (const emoji of DISCORD_NUMBER_EMOJIS) {
397
+ try {
398
+ const users = await apiRequest(`${DISCORD_API}/channels/${ref.channelId}/messages/${ref.messageId}/reactions/${encodeURIComponent(emoji)}`, 'GET', undefined, 'Bot', token, 'Discord API');
399
+ if (Array.isArray(users)) {
400
+ const humanUsers = users.filter((u) => u['id'] !== botUserId);
401
+ if (humanUsers.length > 0)
402
+ reactions.push({ emoji, count: humanUsers.length });
403
+ }
404
+ }
405
+ catch (err) {
406
+ const msg = String(err.message ?? '');
407
+ if (msg.includes('HTTP 404'))
408
+ continue;
409
+ if (msg.includes('HTTP 401') || msg.includes('HTTP 403'))
410
+ throw err;
411
+ }
412
+ }
413
+ if (reactions.length > 0)
414
+ return parseDiscordReactions(reactions, prompt.questions);
415
+ }
416
+ // Try text replies
417
+ const messages = await apiRequest(`${DISCORD_API}/channels/${ref.channelId}/messages?after=${ref.messageId}&limit=10`, 'GET', undefined, 'Bot', token, 'Discord API');
418
+ if (!Array.isArray(messages))
419
+ return null;
420
+ const replies = messages.filter((m) => {
421
+ const msg = m;
422
+ const author = msg['author'];
423
+ const msgRef = msg['message_reference'];
424
+ return author?.['id'] && author['id'] !== botUserId && msgRef?.['message_id'] === ref.messageId && msg['content'];
425
+ });
426
+ if (replies.length === 0)
427
+ return null;
428
+ const first = replies[0];
429
+ return parseTextReply(String(first['content']), prompt.questions);
430
+ }
431
+ async function discordAcknowledge(ref, token) {
432
+ try {
433
+ await apiRequest(`${DISCORD_API}/channels/${ref.channelId}/messages/${ref.messageId}/reactions/${encodeURIComponent('✅')}/@me`, 'PUT', undefined, 'Bot', token, 'Discord API');
434
+ }
435
+ catch { /* best-effort */ }
436
+ }
437
+ // --- Slack ---
438
+ async function slackValidate(token) {
439
+ const res = await apiRequest(`${SLACK_API}/auth.test`, 'GET', undefined, 'Bearer', token, 'Slack API');
440
+ if (!res['ok'])
441
+ throw new Error(`Slack auth failed: ${res['error'] ?? 'invalid token'}`);
442
+ return String(res['user_id'] ?? '');
443
+ }
444
+ async function slackSend(prompt, token, channelId) {
445
+ const res = await apiRequest(`${SLACK_API}/chat.postMessage`, 'POST', { channel: channelId, text: 'GSD needs your input', blocks: formatForSlack(prompt) }, 'Bearer', token, 'Slack API');
446
+ if (!res['ok'])
447
+ throw new Error(`Slack postMessage failed: ${res['error'] ?? 'unknown'}`);
448
+ const ts = String(res['ts']);
449
+ const channel = String(res['channel']);
450
+ if (prompt.questions.length === 1) {
451
+ const reactionNames = SLACK_NUMBER_REACTION_NAMES.slice(0, prompt.questions[0].options.length);
452
+ for (const name of reactionNames) {
453
+ try {
454
+ await apiRequest(`${SLACK_API}/reactions.add`, 'POST', { channel, timestamp: ts, name }, 'Bearer', token, 'Slack API');
455
+ }
456
+ catch { /* best-effort */ }
457
+ }
458
+ }
459
+ return {
460
+ ref: {
461
+ id: prompt.id,
462
+ channel: 'slack',
463
+ messageId: ts,
464
+ threadTs: ts,
465
+ channelId: channel,
466
+ threadUrl: `https://slack.com/archives/${channel}/p${ts.replace('.', '')}`,
467
+ },
468
+ };
469
+ }
470
+ async function slackPoll(prompt, ref, token, botUserId) {
471
+ // Check reactions for single-question prompts
472
+ if (prompt.questions.length === 1) {
473
+ const qs = new URLSearchParams({ channel: ref.channelId, timestamp: ref.messageId, full: 'true' }).toString();
474
+ const res = await apiRequest(`${SLACK_API}/reactions.get?${qs}`, 'GET', undefined, 'Bearer', token, 'Slack API');
475
+ if (res['ok']) {
476
+ const message = (res['message'] ?? {});
477
+ const reactions = Array.isArray(message.reactions) ? message.reactions : [];
478
+ const picked = reactions
479
+ .filter((r) => r.name && SLACK_NUMBER_REACTION_NAMES.includes(r.name))
480
+ .filter((r) => {
481
+ const count = Number(r.count ?? 0);
482
+ const users = Array.isArray(r.users) ? r.users.map(String) : [];
483
+ const botIncluded = botUserId ? users.includes(botUserId) : false;
484
+ return count > (botIncluded ? 1 : 0);
485
+ })
486
+ .map((r) => String(r.name));
487
+ if (picked.length > 0)
488
+ return parseSlackReactions(picked, prompt.questions);
489
+ }
490
+ }
491
+ // Check thread replies
492
+ const qs = new URLSearchParams({ channel: ref.channelId, ts: ref.threadTs, limit: '20' }).toString();
493
+ const res = await apiRequest(`${SLACK_API}/conversations.replies?${qs}`, 'GET', undefined, 'Bearer', token, 'Slack API');
494
+ if (!res['ok'])
495
+ return null;
496
+ const messages = (res['messages'] ?? []);
497
+ const userReplies = messages.filter((m) => m.ts !== ref.threadTs && m.user && m.user !== botUserId && m.text);
498
+ if (userReplies.length === 0)
499
+ return null;
500
+ return parseTextReply(String(userReplies[0].text), prompt.questions);
501
+ }
502
+ async function slackAcknowledge(ref, token) {
503
+ try {
504
+ await apiRequest(`${SLACK_API}/reactions.add`, 'POST', { channel: ref.channelId, timestamp: ref.messageId, name: 'white_check_mark' }, 'Bearer', token, 'Slack API');
505
+ }
506
+ catch { /* best-effort */ }
507
+ }
508
+ // --- Telegram ---
509
+ async function telegramValidate(token) {
510
+ const res = await apiRequest(`${TELEGRAM_API}/bot${token}/getMe`, 'GET', undefined, 'Bearer', token, 'Telegram API');
511
+ const result = res['result'];
512
+ if (!res['ok'] || !result?.['id'])
513
+ throw new Error('Telegram auth failed: invalid bot token');
514
+ return result['id'];
515
+ }
516
+ async function telegramSend(prompt, token, chatId) {
517
+ const payload = formatForTelegram(prompt);
518
+ const params = { chat_id: chatId, text: payload.text, parse_mode: payload.parse_mode };
519
+ if (payload.reply_markup)
520
+ params['reply_markup'] = payload.reply_markup;
521
+ const res = await apiRequest(`${TELEGRAM_API}/bot${token}/sendMessage`, 'POST', params, 'Bearer', token, 'Telegram API');
522
+ const result = res['result'];
523
+ if (!res['ok'] || !result?.['message_id'])
524
+ throw new Error(`Telegram sendMessage failed: ${JSON.stringify(res)}`);
525
+ const messageId = String(result['message_id']);
526
+ // Build public URL only for public channels (negative IDs are private groups)
527
+ const isPublic = !chatId.startsWith('-');
528
+ const messageUrl = isPublic ? `https://t.me/${chatId.replace('@', '')}/${messageId}` : undefined;
529
+ return { ref: { id: prompt.id, channel: 'telegram', messageId, channelId: chatId, threadUrl: messageUrl } };
530
+ }
531
+ async function telegramPoll(prompt, ref, token, botUserId, lastUpdateId) {
532
+ const params = {
533
+ offset: lastUpdateId.value + 1,
534
+ timeout: 0,
535
+ allowed_updates: ['message', 'callback_query'],
536
+ };
537
+ const res = await apiRequest(`${TELEGRAM_API}/bot${token}/getUpdates`, 'POST', params, 'Bearer', token, 'Telegram API');
538
+ if (!res['ok'] || !Array.isArray(res['result']))
539
+ return null;
540
+ for (const update of res['result']) {
541
+ if (update['update_id'] > lastUpdateId.value) {
542
+ lastUpdateId.value = update['update_id'];
543
+ }
544
+ // Callback query (inline keyboard button press)
545
+ if (update['callback_query']) {
546
+ const cq = update['callback_query'];
547
+ const msg = cq['message'];
548
+ const from = cq['from'];
549
+ if (msg && String(msg['chat']?.['id']) === ref.channelId &&
550
+ String(msg['message_id']) === ref.messageId && from?.['id'] !== botUserId) {
551
+ // Dismiss loading spinner
552
+ try {
553
+ await apiRequest(`${TELEGRAM_API}/bot${token}/answerCallbackQuery`, 'POST', { callback_query_id: cq['id'] }, 'Bearer', token, 'Telegram API');
554
+ }
555
+ catch { /* best-effort */ }
556
+ const callbackData = cq['data'] ? String(cq['data']) : null;
557
+ if (callbackData) {
558
+ const parsed = parseTelegramCallbackData(callbackData, prompt.questions, prompt.id);
559
+ if (parsed)
560
+ return parsed;
561
+ }
562
+ }
563
+ }
564
+ // Text message reply
565
+ if (update['message']) {
566
+ const msg = update['message'];
567
+ const from = msg['from'];
568
+ if (String(msg['chat']?.['id']) === ref.channelId &&
569
+ from?.['id'] !== botUserId && msg['text']) {
570
+ return parseTextReply(String(msg['text']), prompt.questions);
571
+ }
572
+ }
573
+ }
574
+ return null;
575
+ }
576
+ // ---------------------------------------------------------------------------
577
+ // Polling loop
578
+ // ---------------------------------------------------------------------------
579
+ function sleep(ms, signal) {
580
+ return new Promise((resolve) => {
581
+ if (signal?.aborted)
582
+ return resolve();
583
+ const timer = setTimeout(() => {
584
+ signal?.removeEventListener('abort', onAbort);
585
+ resolve();
586
+ }, ms);
587
+ const onAbort = () => { clearTimeout(timer); resolve(); };
588
+ signal?.addEventListener('abort', onAbort, { once: true });
589
+ });
590
+ }
591
+ async function pollUntilDone(config, prompt, ref, state, signal) {
592
+ while (Date.now() < prompt.timeoutAt && !signal?.aborted) {
593
+ try {
594
+ let answer = null;
595
+ if (config.channel === 'discord') {
596
+ answer = await discordPoll(prompt, ref, config.token, String(state.botUserId));
597
+ }
598
+ else if (config.channel === 'slack') {
599
+ answer = await slackPoll(prompt, ref, config.token, String(state.botUserId));
600
+ }
601
+ else {
602
+ answer = await telegramPoll(prompt, ref, config.token, state.botUserId, state.lastUpdateId);
603
+ }
604
+ if (answer)
605
+ return answer;
606
+ }
607
+ catch {
608
+ // Non-fatal poll error — wait and retry
609
+ }
610
+ await sleep(prompt.pollIntervalMs, signal);
611
+ }
612
+ return null;
613
+ }
614
+ // ---------------------------------------------------------------------------
615
+ // Public entry point
616
+ // ---------------------------------------------------------------------------
617
+ function buildPrompt(questions, config) {
618
+ const createdAt = Date.now();
619
+ return {
620
+ id: randomUUID(),
621
+ channel: config.channel,
622
+ createdAt,
623
+ timeoutAt: createdAt + config.timeoutMs,
624
+ pollIntervalMs: config.pollIntervalMs,
625
+ context: { source: 'ask_user_questions' },
626
+ questions: questions.map((q) => ({
627
+ id: q.id,
628
+ header: q.header,
629
+ question: q.question,
630
+ options: q.options,
631
+ allowMultiple: q.allowMultiple ?? false,
632
+ })),
633
+ };
634
+ }
635
+ function formatForTool(answer) {
636
+ const out = {};
637
+ for (const [id, data] of Object.entries(answer.answers)) {
638
+ const list = [...data.answers];
639
+ if (data.user_note)
640
+ list.push(`user_note: ${data.user_note}`);
641
+ out[id] = { answers: list };
642
+ }
643
+ return out;
644
+ }
645
+ /**
646
+ * Dispatch questions to the configured remote channel and wait for a response.
647
+ *
648
+ * Returns null when no remote channel is configured.
649
+ * Returns a tool result shaped like { content, details } on success or
650
+ * timeout — callers should check details.timed_out before trusting the result.
651
+ */
652
+ export async function tryRemoteQuestions(questions, signal) {
653
+ const config = resolveRemoteConfig();
654
+ if (!config)
655
+ return null;
656
+ const prompt = buildPrompt(questions, config);
657
+ // Validate auth and send the prompt
658
+ let ref;
659
+ let state;
660
+ try {
661
+ if (config.channel === 'discord') {
662
+ const { botUserId, guildId } = await discordValidate(config.token, config.channelId);
663
+ state = { botUserId, guildId };
664
+ const dispatch = await discordSend(prompt, config.token, config.channelId, guildId);
665
+ ref = dispatch.ref;
666
+ }
667
+ else if (config.channel === 'slack') {
668
+ const botUserId = await slackValidate(config.token);
669
+ state = { botUserId };
670
+ const dispatch = await slackSend(prompt, config.token, config.channelId);
671
+ ref = dispatch.ref;
672
+ }
673
+ else {
674
+ const botUserId = await telegramValidate(config.token);
675
+ state = { botUserId, lastUpdateId: { value: 0 } };
676
+ const dispatch = await telegramSend(prompt, config.token, config.channelId);
677
+ ref = dispatch.ref;
678
+ }
679
+ }
680
+ catch (err) {
681
+ return {
682
+ content: [{ type: 'text', text: `Remote questions failed (${config.channel}): ${err.message}` }],
683
+ details: { remote: true, channel: config.channel, error: true, status: 'failed' },
684
+ };
685
+ }
686
+ const answer = await pollUntilDone(config, prompt, ref, state, signal);
687
+ if (!answer) {
688
+ const timedOut = !signal?.aborted;
689
+ return {
690
+ content: [{
691
+ type: 'text',
692
+ text: JSON.stringify({
693
+ timed_out: timedOut,
694
+ channel: config.channel,
695
+ prompt_id: prompt.id,
696
+ timeout_minutes: config.timeoutMs / 60000,
697
+ thread_url: ref.threadUrl ?? null,
698
+ message: `User did not respond within ${config.timeoutMs / 60000} minutes.`,
699
+ }),
700
+ }],
701
+ details: {
702
+ remote: true,
703
+ channel: config.channel,
704
+ timed_out: timedOut,
705
+ promptId: prompt.id,
706
+ threadUrl: ref.threadUrl ?? null,
707
+ status: signal?.aborted ? 'cancelled' : 'timed_out',
708
+ },
709
+ };
710
+ }
711
+ // Best-effort acknowledgement
712
+ try {
713
+ if (config.channel === 'discord')
714
+ await discordAcknowledge(ref, config.token);
715
+ else if (config.channel === 'slack')
716
+ await slackAcknowledge(ref, config.token);
717
+ }
718
+ catch { /* best-effort */ }
719
+ return {
720
+ content: [{ type: 'text', text: JSON.stringify({ answers: formatForTool(answer) }) }],
721
+ details: {
722
+ remote: true,
723
+ channel: config.channel,
724
+ timed_out: false,
725
+ promptId: prompt.id,
726
+ threadUrl: ref.threadUrl ?? null,
727
+ questions,
728
+ status: 'answered',
729
+ },
730
+ };
731
+ }
732
+ //# sourceMappingURL=remote-questions.js.map