gsd-pi 2.76.0-dev.82e249f7b → 2.76.0-dev.97f5583d9

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 (271) hide show
  1. package/dist/claude-cli-check.js +32 -3
  2. package/dist/mcp-server.d.ts +7 -0
  3. package/dist/mcp-server.js +35 -1
  4. package/dist/resource-loader.d.ts +1 -1
  5. package/dist/resource-loader.js +2 -8
  6. package/dist/resources/extensions/claude-code-cli/readiness.js +4 -3
  7. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +77 -17
  8. package/dist/resources/extensions/gsd/auto/phases.js +42 -1
  9. package/dist/resources/extensions/gsd/auto/run-unit.js +27 -0
  10. package/dist/resources/extensions/gsd/auto/session.js +12 -0
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -3
  12. package/dist/resources/extensions/gsd/auto-model-selection.js +1 -1
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -2
  14. package/dist/resources/extensions/gsd/auto-prompts.js +14 -0
  15. package/dist/resources/extensions/gsd/auto-recovery.js +13 -0
  16. package/dist/resources/extensions/gsd/auto-start.js +27 -18
  17. package/dist/resources/extensions/gsd/auto-worktree.js +51 -53
  18. package/dist/resources/extensions/gsd/auto.js +55 -27
  19. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -1
  20. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +39 -9
  21. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +93 -0
  22. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
  23. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +51 -5
  24. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +34 -2
  25. package/dist/resources/extensions/gsd/clean-root-preflight.js +93 -0
  26. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +968 -23
  27. package/dist/resources/extensions/gsd/compaction-snapshot.js +121 -0
  28. package/dist/resources/extensions/gsd/error-classifier.js +10 -3
  29. package/dist/resources/extensions/gsd/exec-history.js +120 -0
  30. package/dist/resources/extensions/gsd/exec-sandbox.js +258 -0
  31. package/dist/resources/extensions/gsd/gsd-db.js +115 -7
  32. package/dist/resources/extensions/gsd/guided-flow.js +189 -0
  33. package/dist/resources/extensions/gsd/health-widget.js +4 -1
  34. package/dist/resources/extensions/gsd/init-wizard.js +15 -1
  35. package/dist/resources/extensions/gsd/key-manager.js +6 -0
  36. package/dist/resources/extensions/gsd/model-router.js +36 -3
  37. package/dist/resources/extensions/gsd/pre-execution-checks.js +35 -9
  38. package/dist/resources/extensions/gsd/preferences-types.js +9 -0
  39. package/dist/resources/extensions/gsd/preferences-validation.js +83 -0
  40. package/dist/resources/extensions/gsd/preferences.js +17 -17
  41. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  42. package/dist/resources/extensions/gsd/prompts/discuss.md +29 -2
  43. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  44. package/dist/resources/extensions/gsd/safety/evidence-collector.js +96 -0
  45. package/dist/resources/extensions/gsd/safety/file-change-validator.js +13 -5
  46. package/dist/resources/extensions/gsd/safety/safety-harness.js +5 -1
  47. package/dist/resources/extensions/gsd/token-counter.js +22 -5
  48. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +59 -0
  49. package/dist/resources/extensions/gsd/tools/exec-tool.js +126 -0
  50. package/dist/resources/extensions/gsd/tools/resume-tool.js +23 -0
  51. package/dist/resources/extensions/gsd/uok/plan-v2.js +20 -3
  52. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -0
  53. package/dist/resources/skills/verify-before-complete/SKILL.md +2 -1
  54. package/dist/resources/skills/write-docs/SKILL.md +2 -1
  55. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  56. package/dist/web/standalone/.next/BUILD_ID +1 -1
  57. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  58. package/dist/web/standalone/.next/build-manifest.json +2 -2
  59. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  60. package/dist/web/standalone/.next/required-server-files.json +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  66. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/index.html +1 -1
  78. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  85. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  87. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  88. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  89. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  90. package/dist/web/standalone/server.js +1 -1
  91. package/package.json +1 -1
  92. package/packages/mcp-server/dist/remote-questions.d.ts +45 -0
  93. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -0
  94. package/packages/mcp-server/dist/remote-questions.js +732 -0
  95. package/packages/mcp-server/dist/remote-questions.js.map +1 -0
  96. package/packages/mcp-server/dist/server.d.ts +7 -0
  97. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  98. package/packages/mcp-server/dist/server.js +41 -4
  99. package/packages/mcp-server/dist/server.js.map +1 -1
  100. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  101. package/packages/mcp-server/dist/workflow-tools.js +64 -25
  102. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  103. package/packages/mcp-server/package.json +2 -1
  104. package/packages/mcp-server/src/mcp-server.test.ts +30 -0
  105. package/packages/mcp-server/src/remote-questions.test.ts +294 -0
  106. package/packages/mcp-server/src/remote-questions.ts +916 -0
  107. package/packages/mcp-server/src/server.ts +62 -10
  108. package/packages/mcp-server/src/workflow-tools.test.ts +146 -1
  109. package/packages/mcp-server/src/workflow-tools.ts +84 -43
  110. package/packages/mcp-server/tsconfig.test.json +19 -0
  111. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  112. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +1 -1
  113. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  114. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  115. package/packages/pi-ai/dist/providers/anthropic-shared.js +27 -4
  116. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  117. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  118. package/packages/pi-ai/dist/providers/anthropic.js +8 -3
  119. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  120. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts +2 -0
  121. package/packages/pi-ai/dist/providers/minimax-tool-name.test.d.ts.map +1 -0
  122. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +80 -0
  123. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -0
  124. package/packages/pi-ai/dist/providers/simple-options.d.ts +10 -0
  125. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  126. package/packages/pi-ai/dist/providers/simple-options.js +16 -1
  127. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  128. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +1 -1
  129. package/packages/pi-ai/src/providers/anthropic-shared.ts +26 -5
  130. package/packages/pi-ai/src/providers/anthropic.ts +9 -3
  131. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +98 -0
  132. package/packages/pi-ai/src/providers/simple-options.ts +17 -1
  133. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  134. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts +2 -0
  135. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.d.ts.map +1 -0
  136. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js +203 -0
  137. package/packages/pi-coding-agent/dist/core/model-registry-custom-caps.test.js.map +1 -0
  138. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  139. package/packages/pi-coding-agent/dist/core/model-registry.js +14 -0
  140. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  141. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts +2 -0
  142. package/packages/pi-coding-agent/dist/core/redact-secrets.d.ts.map +1 -0
  143. package/packages/pi-coding-agent/dist/core/redact-secrets.js +49 -0
  144. package/packages/pi-coding-agent/dist/core/redact-secrets.js.map +1 -0
  145. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts +2 -0
  146. package/packages/pi-coding-agent/dist/core/redact-secrets.test.d.ts.map +1 -0
  147. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js +67 -0
  148. package/packages/pi-coding-agent/dist/core/redact-secrets.test.js.map +1 -0
  149. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  150. package/packages/pi-coding-agent/dist/core/session-manager.js +9 -5
  151. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  152. package/packages/pi-coding-agent/dist/core/session-manager.test.js +25 -1
  153. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  154. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts +1 -1
  155. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  156. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +5 -4
  157. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  158. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts +7 -6
  159. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  160. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +29 -21
  161. package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  162. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  163. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -1
  164. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  165. package/packages/pi-coding-agent/src/core/model-registry-custom-caps.test.ts +245 -0
  166. package/packages/pi-coding-agent/src/core/model-registry.ts +16 -0
  167. package/packages/pi-coding-agent/src/core/redact-secrets.test.ts +86 -0
  168. package/packages/pi-coding-agent/src/core/redact-secrets.ts +58 -0
  169. package/packages/pi-coding-agent/src/core/session-manager.test.ts +36 -1
  170. package/packages/pi-coding-agent/src/core/session-manager.ts +9 -5
  171. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +6 -6
  172. package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +36 -22
  173. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +13 -1
  174. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  175. package/src/resources/extensions/claude-code-cli/readiness.ts +4 -3
  176. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +78 -17
  177. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +149 -5
  178. package/src/resources/extensions/gsd/auto/loop-deps.ts +13 -0
  179. package/src/resources/extensions/gsd/auto/phases.ts +66 -1
  180. package/src/resources/extensions/gsd/auto/run-unit.ts +29 -0
  181. package/src/resources/extensions/gsd/auto/session.ts +22 -0
  182. package/src/resources/extensions/gsd/auto-dispatch.ts +16 -3
  183. package/src/resources/extensions/gsd/auto-model-selection.ts +1 -1
  184. package/src/resources/extensions/gsd/auto-post-unit.ts +29 -3
  185. package/src/resources/extensions/gsd/auto-prompts.ts +28 -1
  186. package/src/resources/extensions/gsd/auto-recovery.ts +15 -0
  187. package/src/resources/extensions/gsd/auto-start.ts +29 -19
  188. package/src/resources/extensions/gsd/auto-worktree.ts +62 -63
  189. package/src/resources/extensions/gsd/auto.ts +58 -27
  190. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +23 -1
  191. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +40 -9
  192. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +109 -0
  193. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
  194. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +53 -5
  195. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +35 -2
  196. package/src/resources/extensions/gsd/clean-root-preflight.ts +111 -0
  197. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +898 -32
  198. package/src/resources/extensions/gsd/compaction-snapshot.ts +165 -0
  199. package/src/resources/extensions/gsd/error-classifier.ts +10 -3
  200. package/src/resources/extensions/gsd/exec-history.ts +153 -0
  201. package/src/resources/extensions/gsd/exec-sandbox.ts +326 -0
  202. package/src/resources/extensions/gsd/gsd-db.ts +122 -7
  203. package/src/resources/extensions/gsd/guided-flow.ts +221 -0
  204. package/src/resources/extensions/gsd/health-widget.ts +3 -1
  205. package/src/resources/extensions/gsd/init-wizard.ts +15 -1
  206. package/src/resources/extensions/gsd/journal.ts +2 -1
  207. package/src/resources/extensions/gsd/key-manager.ts +6 -0
  208. package/src/resources/extensions/gsd/model-router.ts +42 -1
  209. package/src/resources/extensions/gsd/pre-execution-checks.ts +36 -10
  210. package/src/resources/extensions/gsd/preferences-types.ts +46 -0
  211. package/src/resources/extensions/gsd/preferences-validation.ts +79 -0
  212. package/src/resources/extensions/gsd/preferences.ts +17 -17
  213. package/src/resources/extensions/gsd/prompts/discuss-headless.md +8 -0
  214. package/src/resources/extensions/gsd/prompts/discuss.md +29 -2
  215. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +5 -2
  216. package/src/resources/extensions/gsd/safety/evidence-collector.ts +119 -0
  217. package/src/resources/extensions/gsd/safety/file-change-validator.ts +17 -4
  218. package/src/resources/extensions/gsd/safety/safety-harness.ts +9 -0
  219. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +119 -1
  220. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +12 -0
  221. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +49 -0
  222. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +186 -0
  223. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +123 -0
  224. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  225. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  226. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +2 -0
  227. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +31 -0
  228. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +1 -1
  229. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +1 -1
  230. package/src/resources/extensions/gsd/tests/escalation.test.ts +1 -1
  231. package/src/resources/extensions/gsd/tests/exec-history.test.ts +124 -0
  232. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +210 -0
  233. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +58 -0
  234. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +152 -1
  235. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +27 -0
  236. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +1 -1
  237. package/src/resources/extensions/gsd/tests/issue-4540-regressions.test.ts +288 -0
  238. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +2 -0
  239. package/src/resources/extensions/gsd/tests/key-manager.test.ts +7 -0
  240. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  241. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  242. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +19 -0
  243. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +14 -0
  244. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +272 -0
  245. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +234 -0
  246. package/src/resources/extensions/gsd/tests/preferences.test.ts +110 -0
  247. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +44 -0
  248. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +48 -0
  249. package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +388 -0
  250. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +9 -3
  251. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +205 -0
  252. package/src/resources/extensions/gsd/tests/save-gate-result-render.test.ts +95 -0
  253. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +32 -40
  254. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +56 -0
  255. package/src/resources/extensions/gsd/tests/token-counter.test.ts +105 -1
  256. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +107 -0
  257. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +23 -0
  258. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +65 -2
  259. package/src/resources/extensions/gsd/tests/write-gate.test.ts +64 -0
  260. package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +3 -1
  261. package/src/resources/extensions/gsd/token-counter.ts +22 -5
  262. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +81 -0
  263. package/src/resources/extensions/gsd/tools/exec-tool.ts +183 -0
  264. package/src/resources/extensions/gsd/tools/resume-tool.ts +40 -0
  265. package/src/resources/extensions/gsd/uok/plan-v2.ts +26 -3
  266. package/src/resources/extensions/gsd/workflow-logger.ts +3 -1
  267. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -0
  268. package/src/resources/skills/verify-before-complete/SKILL.md +2 -1
  269. package/src/resources/skills/write-docs/SKILL.md +2 -1
  270. /package/dist/web/standalone/.next/static/{ecSsu49rxxcpbNmVP4mLD → lLdDRDspgYzfz0bJAmUSz}/_buildManifest.js +0 -0
  271. /package/dist/web/standalone/.next/static/{ecSsu49rxxcpbNmVP4mLD → lLdDRDspgYzfz0bJAmUSz}/_ssgManifest.js +0 -0
@@ -25,7 +25,8 @@
25
25
  },
26
26
  "scripts": {
27
27
  "build": "tsc",
28
- "test": "node --test dist/mcp-server.test.js"
28
+ "build:test": "tsc -p tsconfig.test.json",
29
+ "test": "npm run build:test && node --test dist/mcp-server.test.js dist/remote-questions.test.js"
29
30
  },
30
31
  "dependencies": {
31
32
  "@modelcontextprotocol/sdk": "^1.27.1",
@@ -20,6 +20,7 @@ import {
20
20
  buildAskUserQuestionsElicitRequest,
21
21
  createMcpServer,
22
22
  formatAskUserQuestionsElicitResult,
23
+ withElicitTimeout,
23
24
  } from './server.js';
24
25
  import { MAX_EVENTS } from './types.js';
25
26
  import type { ManagedSession, CostAccumulator, PendingBlocker } from './types.js';
@@ -746,3 +747,32 @@ describe('createMcpServer tool registration', () => {
746
747
  );
747
748
  });
748
749
  });
750
+
751
+ // ---------------------------------------------------------------------------
752
+ // withElicitTimeout
753
+ // ---------------------------------------------------------------------------
754
+
755
+ describe('withElicitTimeout', () => {
756
+ it('resolves with the promise value when it settles before the timeout', async () => {
757
+ const result = await withElicitTimeout(Promise.resolve(42), 'test', 5000);
758
+ assert.equal(result, 42);
759
+ });
760
+
761
+ it('rejects with a timeout error when the promise does not settle in time', async () => {
762
+ const never = new Promise<never>(() => {});
763
+ await assert.rejects(
764
+ () => withElicitTimeout(never, 'ask_user_questions', 1),
765
+ (err: Error) => {
766
+ assert.ok(err.message.includes('ask_user_questions'));
767
+ assert.ok(err.message.includes('timed out'));
768
+ return true;
769
+ },
770
+ );
771
+ });
772
+
773
+ it('clears the timer when the promise resolves (no dangling timer)', async () => {
774
+ const start = Date.now();
775
+ await withElicitTimeout(Promise.resolve('done'), 'test', 50);
776
+ assert.ok(Date.now() - start < 40, 'should not wait for the timeout');
777
+ });
778
+ });
@@ -0,0 +1,294 @@
1
+ /**
2
+ * packages/mcp-server — remote-questions regression tests (#4364)
3
+ *
4
+ * Verifies that the ask_user_questions MCP handler delegates to
5
+ * tryRemoteQuestions when a remote channel is configured, instead of going
6
+ * straight to elicitInput (which is unreachable in Claude Code-under-gsd
7
+ * sessions).
8
+ *
9
+ * Strategy: we cannot mock ES modules without --experimental-test-module-mocks,
10
+ * so we test the exported helpers from remote-questions.ts directly and verify
11
+ * the handler routing by observing mock side-effects injected via environment
12
+ * variables and a fake PREFERENCES.md file.
13
+ */
14
+
15
+ import { describe, it, before, after, beforeEach, afterEach } from 'node:test';
16
+ import assert from 'node:assert/strict';
17
+ import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
18
+ import { tmpdir } from 'node:os';
19
+ import { join } from 'node:path';
20
+
21
+ // We test the module's exported helpers directly.
22
+ // The real createMcpServer routing is tested separately via the
23
+ // ask_user_questions handler integration test further below.
24
+ import {
25
+ isRemoteConfigured,
26
+ tryRemoteQuestions,
27
+ type RemoteQuestion,
28
+ } from './remote-questions.js';
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Helpers
32
+ // ---------------------------------------------------------------------------
33
+
34
+ const SAMPLE_QUESTIONS: RemoteQuestion[] = [
35
+ {
36
+ id: 'approach',
37
+ header: 'Approach',
38
+ question: 'Which implementation approach should I use?',
39
+ options: [
40
+ { label: 'Option A (Recommended)', description: 'Faster, simpler path.' },
41
+ { label: 'Option B', description: 'More flexible but complex.' },
42
+ ],
43
+ },
44
+ ];
45
+
46
+ function makePrefsFile(dir: string, content: string): void {
47
+ writeFileSync(join(dir, 'PREFERENCES.md'), content, 'utf-8');
48
+ }
49
+
50
+ // ---------------------------------------------------------------------------
51
+ // isRemoteConfigured — unit tests
52
+ // ---------------------------------------------------------------------------
53
+
54
+ describe('isRemoteConfigured', () => {
55
+ let tmpDir: string;
56
+ const origGsdHome = process.env['GSD_HOME'];
57
+ const origToken = process.env['DISCORD_BOT_TOKEN'];
58
+
59
+ before(() => {
60
+ tmpDir = mkdtempSync(join(tmpdir(), 'gsd-rq-test-'));
61
+ });
62
+
63
+ after(() => {
64
+ rmSync(tmpDir, { recursive: true, force: true });
65
+ if (origGsdHome !== undefined) {
66
+ process.env['GSD_HOME'] = origGsdHome;
67
+ } else {
68
+ delete process.env['GSD_HOME'];
69
+ }
70
+ if (origToken !== undefined) {
71
+ process.env['DISCORD_BOT_TOKEN'] = origToken;
72
+ } else {
73
+ delete process.env['DISCORD_BOT_TOKEN'];
74
+ }
75
+ });
76
+
77
+ beforeEach(() => {
78
+ process.env['GSD_HOME'] = tmpDir;
79
+ delete process.env['DISCORD_BOT_TOKEN'];
80
+ delete process.env['SLACK_BOT_TOKEN'];
81
+ delete process.env['TELEGRAM_BOT_TOKEN'];
82
+ });
83
+
84
+ it('returns false when PREFERENCES.md is absent', () => {
85
+ assert.equal(isRemoteConfigured(), false);
86
+ });
87
+
88
+ it('returns false when PREFERENCES.md has no remote_questions block', () => {
89
+ makePrefsFile(tmpDir, '---\nsome_other_key: value\n---\n');
90
+ assert.equal(isRemoteConfigured(), false);
91
+ });
92
+
93
+ it('returns false when remote_questions lacks channel or channel_id', () => {
94
+ makePrefsFile(tmpDir, '---\nremote_questions:\n channel: discord\n---\n');
95
+ assert.equal(isRemoteConfigured(), false);
96
+ });
97
+
98
+ it('returns false when discord channel_id format is invalid', () => {
99
+ makePrefsFile(tmpDir, '---\nremote_questions:\n channel: discord\n channel_id: "not-a-snowflake"\n---\n');
100
+ process.env['DISCORD_BOT_TOKEN'] = 'Bot fake-token';
101
+ assert.equal(isRemoteConfigured(), false);
102
+ });
103
+
104
+ it('returns false when env token is absent even if prefs are valid', () => {
105
+ makePrefsFile(tmpDir, '---\nremote_questions:\n channel: discord\n channel_id: "123456789012345678"\n---\n');
106
+ // DISCORD_BOT_TOKEN not set
107
+ assert.equal(isRemoteConfigured(), false);
108
+ });
109
+
110
+ it('returns true when discord config and token are both present', () => {
111
+ makePrefsFile(tmpDir, '---\nremote_questions:\n channel: discord\n channel_id: "123456789012345678"\n---\n');
112
+ process.env['DISCORD_BOT_TOKEN'] = 'Bot fake-token';
113
+ assert.equal(isRemoteConfigured(), true);
114
+ });
115
+
116
+ it('returns true for slack config with valid channel ID and token', () => {
117
+ makePrefsFile(tmpDir, '---\nremote_questions:\n channel: slack\n channel_id: "C0123456789"\n---\n');
118
+ process.env['SLACK_BOT_TOKEN'] = 'xoxb-fake';
119
+ assert.equal(isRemoteConfigured(), true);
120
+ delete process.env['SLACK_BOT_TOKEN'];
121
+ });
122
+
123
+ it('returns true for telegram config with valid chat ID and token', () => {
124
+ makePrefsFile(tmpDir, '---\nremote_questions:\n channel: telegram\n channel_id: "-1001234567890"\n---\n');
125
+ process.env['TELEGRAM_BOT_TOKEN'] = 'fake-telegram-token';
126
+ assert.equal(isRemoteConfigured(), true);
127
+ delete process.env['TELEGRAM_BOT_TOKEN'];
128
+ });
129
+
130
+ it('returns false for unknown channel type', () => {
131
+ makePrefsFile(tmpDir, '---\nremote_questions:\n channel: whatsapp\n channel_id: "123456"\n---\n');
132
+ assert.equal(isRemoteConfigured(), false);
133
+ });
134
+ });
135
+
136
+ // ---------------------------------------------------------------------------
137
+ // tryRemoteQuestions — routing: returns null when not configured
138
+ // ---------------------------------------------------------------------------
139
+
140
+ describe('tryRemoteQuestions returns null when remote is not configured', () => {
141
+ let tmpDir: string;
142
+ const origGsdHome = process.env['GSD_HOME'];
143
+
144
+ before(() => {
145
+ tmpDir = mkdtempSync(join(tmpdir(), 'gsd-rq-null-test-'));
146
+ process.env['GSD_HOME'] = tmpDir;
147
+ // No PREFERENCES.md, no tokens
148
+ delete process.env['DISCORD_BOT_TOKEN'];
149
+ delete process.env['SLACK_BOT_TOKEN'];
150
+ delete process.env['TELEGRAM_BOT_TOKEN'];
151
+ });
152
+
153
+ after(() => {
154
+ rmSync(tmpDir, { recursive: true, force: true });
155
+ if (origGsdHome !== undefined) {
156
+ process.env['GSD_HOME'] = origGsdHome;
157
+ } else {
158
+ delete process.env['GSD_HOME'];
159
+ }
160
+ });
161
+
162
+ it('returns null when no remote channel is configured', async () => {
163
+ const result = await tryRemoteQuestions(SAMPLE_QUESTIONS);
164
+ assert.equal(result, null);
165
+ });
166
+ });
167
+
168
+ // ---------------------------------------------------------------------------
169
+ // tryRemoteQuestions — auth failure path
170
+ // ---------------------------------------------------------------------------
171
+
172
+ describe('tryRemoteQuestions returns error result on auth failure', () => {
173
+ let tmpDir: string;
174
+ const origGsdHome = process.env['GSD_HOME'];
175
+ const origToken = process.env['DISCORD_BOT_TOKEN'];
176
+
177
+ before(() => {
178
+ tmpDir = mkdtempSync(join(tmpdir(), 'gsd-rq-auth-test-'));
179
+ // Set up a valid discord config pointing at an unreachable/fake endpoint
180
+ makePrefsFile(tmpDir, '---\nremote_questions:\n channel: discord\n channel_id: "123456789012345678"\n---\n');
181
+ process.env['GSD_HOME'] = tmpDir;
182
+ // Use an obviously invalid token — the Discord API will reject it
183
+ // but we don't actually call the live Discord API in unit tests.
184
+ // Instead we rely on the fact that fetch() to Discord API will fail
185
+ // in a test environment (no network or invalid token → error result).
186
+ process.env['DISCORD_BOT_TOKEN'] = 'invalid-fake-token-for-test';
187
+ });
188
+
189
+ after(() => {
190
+ rmSync(tmpDir, { recursive: true, force: true });
191
+ if (origGsdHome !== undefined) {
192
+ process.env['GSD_HOME'] = origGsdHome;
193
+ } else {
194
+ delete process.env['GSD_HOME'];
195
+ }
196
+ if (origToken !== undefined) {
197
+ process.env['DISCORD_BOT_TOKEN'] = origToken;
198
+ } else {
199
+ delete process.env['DISCORD_BOT_TOKEN'];
200
+ }
201
+ });
202
+
203
+ it('returns an error result (not null) when auth fails', async () => {
204
+ const controller = new AbortController();
205
+ // Abort immediately so we don't actually poll
206
+ controller.abort();
207
+
208
+ const result = await tryRemoteQuestions(SAMPLE_QUESTIONS, controller.signal);
209
+
210
+ // When configured but auth/dispatch fails, we get a non-null error result
211
+ // rather than null (null means "not configured").
212
+ // The exact failure mode (network error vs HTTP 401) depends on the test
213
+ // environment, but the contract is: non-null result with error details or
214
+ // timed_out details.
215
+ assert.ok(result !== null, 'should return a result, not null, when configured');
216
+ assert.ok(Array.isArray(result.content), 'result.content should be an array');
217
+ assert.ok(result.content.length > 0, 'result.content should be non-empty');
218
+ assert.equal(result.content[0].type, 'text');
219
+ });
220
+ });
221
+
222
+ // ---------------------------------------------------------------------------
223
+ // Frontmatter parser — unit tests
224
+ // ---------------------------------------------------------------------------
225
+
226
+ describe('remote-questions YAML frontmatter parsing (via isRemoteConfigured)', () => {
227
+ let tmpDir: string;
228
+ const origGsdHome = process.env['GSD_HOME'];
229
+
230
+ before(() => {
231
+ tmpDir = mkdtempSync(join(tmpdir(), 'gsd-rq-yaml-test-'));
232
+ });
233
+
234
+ after(() => {
235
+ rmSync(tmpDir, { recursive: true, force: true });
236
+ if (origGsdHome !== undefined) {
237
+ process.env['GSD_HOME'] = origGsdHome;
238
+ } else {
239
+ delete process.env['GSD_HOME'];
240
+ }
241
+ delete process.env['DISCORD_BOT_TOKEN'];
242
+ });
243
+
244
+ beforeEach(() => {
245
+ process.env['GSD_HOME'] = tmpDir;
246
+ process.env['DISCORD_BOT_TOKEN'] = 'Bot fake-token';
247
+ });
248
+
249
+ afterEach(() => {
250
+ delete process.env['DISCORD_BOT_TOKEN'];
251
+ });
252
+
253
+ it('parses channel_id as a quoted string', () => {
254
+ makePrefsFile(tmpDir, '---\nremote_questions:\n channel: discord\n channel_id: "987654321098765432"\n---\n');
255
+ assert.equal(isRemoteConfigured(), true);
256
+ });
257
+
258
+ it('parses channel_id as a bare number', () => {
259
+ makePrefsFile(tmpDir, '---\nremote_questions:\n channel: discord\n channel_id: 987654321098765432\n---\n');
260
+ assert.equal(isRemoteConfigured(), true);
261
+ });
262
+
263
+ it('respects timeout_minutes and poll_interval_seconds presence without crashing', () => {
264
+ makePrefsFile(tmpDir, [
265
+ '---',
266
+ 'remote_questions:',
267
+ ' channel: discord',
268
+ ' channel_id: "123456789012345678"',
269
+ ' timeout_minutes: 10',
270
+ ' poll_interval_seconds: 3',
271
+ '---',
272
+ ].join('\n'));
273
+ assert.equal(isRemoteConfigured(), true);
274
+ });
275
+
276
+ it('ignores content after the closing --- fence', () => {
277
+ makePrefsFile(tmpDir, [
278
+ '---',
279
+ 'remote_questions:',
280
+ ' channel: discord',
281
+ ' channel_id: "123456789012345678"',
282
+ '---',
283
+ '# Markdown content after the fence is ignored',
284
+ 'Some prose text.',
285
+ ].join('\n'));
286
+ assert.equal(isRemoteConfigured(), true);
287
+ });
288
+
289
+ it('returns false when PREFERENCES.md has content but no frontmatter delimiters', () => {
290
+ makePrefsFile(tmpDir, 'remote_questions:\n channel: discord\n channel_id: "123456789012345678"\n');
291
+ // No --- fences — not recognized as frontmatter
292
+ assert.equal(isRemoteConfigured(), false);
293
+ });
294
+ });