@opengsd/gsd-pi 1.5.0 → 1.6.0-dev.aa7f94e8

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 (633) hide show
  1. package/README.md +10 -10
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/ask-user-questions.js +1 -1
  4. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +114 -36
  5. package/dist/resources/extensions/gsd/activity-log.js +1 -1
  6. package/dist/resources/extensions/gsd/auto/closeout.js +97 -5
  7. package/dist/resources/extensions/gsd/auto/orchestrator.js +20 -13
  8. package/dist/resources/extensions/gsd/auto/pre-dispatch.js +6 -3
  9. package/dist/resources/extensions/gsd/auto/unit-phase.js +5 -9
  10. package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -5
  11. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -7
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +69 -17
  13. package/dist/resources/extensions/gsd/auto-model-selection.js +28 -1
  14. package/dist/resources/extensions/gsd/auto-post-unit.js +23 -6
  15. package/dist/resources/extensions/gsd/auto-prompts.js +49 -117
  16. package/dist/resources/extensions/gsd/auto-recovery.js +50 -6
  17. package/dist/resources/extensions/gsd/auto-start.js +57 -33
  18. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +12 -2
  19. package/dist/resources/extensions/gsd/auto-timers.js +9 -2
  20. package/dist/resources/extensions/gsd/auto-worktree-branch-lifecycle.js +189 -0
  21. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +133 -0
  22. package/dist/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.js +35 -0
  23. package/dist/resources/extensions/gsd/auto-worktree-creation.js +130 -0
  24. package/dist/resources/extensions/gsd/auto-worktree-entry.js +118 -0
  25. package/dist/resources/extensions/gsd/auto-worktree-merge-already-merged.js +98 -0
  26. package/dist/resources/extensions/gsd/auto-worktree-merge-branch-head.js +52 -0
  27. package/dist/resources/extensions/gsd/auto-worktree-merge-cleanup.js +87 -0
  28. package/dist/resources/extensions/gsd/auto-worktree-merge-code-changes.js +46 -0
  29. package/dist/resources/extensions/gsd/auto-worktree-merge-db-ready.js +68 -0
  30. package/dist/resources/extensions/gsd/auto-worktree-merge-integration-branch.js +51 -0
  31. package/dist/resources/extensions/gsd/auto-worktree-merge-message.js +106 -0
  32. package/dist/resources/extensions/gsd/auto-worktree-merge-pre-teardown.js +64 -0
  33. package/dist/resources/extensions/gsd/auto-worktree-merge-stash.js +168 -0
  34. package/dist/resources/extensions/gsd/auto-worktree-merge.js +302 -0
  35. package/dist/resources/extensions/gsd/auto-worktree-milestone-shelter.js +119 -0
  36. package/dist/resources/extensions/gsd/auto-worktree-path-resolution.js +5 -0
  37. package/dist/resources/extensions/gsd/auto-worktree-path-utils.js +5 -0
  38. package/dist/resources/extensions/gsd/auto-worktree-resource-version.js +41 -0
  39. package/dist/resources/extensions/gsd/auto-worktree-runtime-cleanup.js +99 -0
  40. package/dist/resources/extensions/gsd/auto-worktree-session-registry.js +57 -0
  41. package/dist/resources/extensions/gsd/auto-worktree-sync.js +249 -0
  42. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +120 -0
  43. package/dist/resources/extensions/gsd/auto-worktree.js +20 -2073
  44. package/dist/resources/extensions/gsd/auto.js +118 -34
  45. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -1
  46. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +20 -2
  47. package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
  48. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +185 -27
  49. package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +68 -2
  50. package/dist/resources/extensions/gsd/codebase-generator.js +7 -1
  51. package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
  52. package/dist/resources/extensions/gsd/commands-workflow-templates.js +3 -3
  53. package/dist/resources/extensions/gsd/compat/compat-marker.js +44 -0
  54. package/dist/resources/extensions/gsd/config-overlay.js +7 -2
  55. package/dist/resources/extensions/gsd/db/engine.js +33 -0
  56. package/dist/resources/extensions/gsd/db/queries.js +9 -9
  57. package/dist/resources/extensions/gsd/db/writers/cascades.js +20 -2
  58. package/dist/resources/extensions/gsd/db-adapter.js +30 -3
  59. package/dist/resources/extensions/gsd/docs/preferences-reference.md +3 -3
  60. package/dist/resources/extensions/gsd/doctor-engine-checks.js +93 -11
  61. package/dist/resources/extensions/gsd/flat-phase-migration.js +32 -3
  62. package/dist/resources/extensions/gsd/forensics.js +1 -1
  63. package/dist/resources/extensions/gsd/git-conflict-resolve.js +2 -2
  64. package/dist/resources/extensions/gsd/git-service.js +45 -0
  65. package/dist/resources/extensions/gsd/gsd-db.js +23 -11
  66. package/dist/resources/extensions/gsd/guided-flow.js +22 -17
  67. package/dist/resources/extensions/gsd/journal.js +1 -1
  68. package/dist/resources/extensions/gsd/markdown-renderer.js +34 -79
  69. package/dist/resources/extensions/gsd/md-importer.js +89 -23
  70. package/dist/resources/extensions/gsd/metrics.js +2 -2
  71. package/dist/resources/extensions/gsd/migration-auto-check.js +30 -3
  72. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +11 -0
  73. package/dist/resources/extensions/gsd/milestone-settlement.js +1 -1
  74. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  75. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -1
  76. package/dist/resources/extensions/gsd/paths.js +87 -52
  77. package/dist/resources/extensions/gsd/post-unit-hooks.js +27 -0
  78. package/dist/resources/extensions/gsd/preferences-models.js +66 -15
  79. package/dist/resources/extensions/gsd/preferences-skills.js +10 -16
  80. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  81. package/dist/resources/extensions/gsd/preferences-validation.js +148 -10
  82. package/dist/resources/extensions/gsd/preferences.js +20 -0
  83. package/dist/resources/extensions/gsd/prompts/system.md +6 -6
  84. package/dist/resources/extensions/gsd/quick.js +12 -3
  85. package/dist/resources/extensions/gsd/reopen-reason.js +98 -0
  86. package/dist/resources/extensions/gsd/rule-registry.js +106 -10
  87. package/dist/resources/extensions/gsd/session-status-io.js +31 -0
  88. package/dist/resources/extensions/gsd/skill-discovery.js +36 -23
  89. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +2 -1
  90. package/dist/resources/extensions/gsd/state/derive/from-db.js +88 -153
  91. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +1 -10
  92. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +3 -24
  93. package/dist/resources/extensions/gsd/state-reconciliation/index.js +10 -0
  94. package/dist/resources/extensions/gsd/tool-contract.js +14 -0
  95. package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -5
  96. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +16 -10
  97. package/dist/resources/extensions/gsd/tools/reopen-slice.js +5 -0
  98. package/dist/resources/extensions/gsd/tools/reopen-task.js +28 -5
  99. package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -8
  100. package/dist/resources/extensions/gsd/uat-dispatch.js +94 -0
  101. package/dist/resources/extensions/gsd/unit-registry.js +12 -2
  102. package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +1 -1
  103. package/dist/resources/extensions/gsd/uok/audit-toggle.js +31 -2
  104. package/dist/resources/extensions/gsd/uok/audit.js +3 -0
  105. package/dist/resources/extensions/gsd/uok/gate-runner.js +22 -30
  106. package/dist/resources/extensions/gsd/uok/gitops.js +18 -15
  107. package/dist/resources/extensions/gsd/uok/kernel.js +120 -46
  108. package/dist/resources/extensions/gsd/uok/model-policy.js +17 -14
  109. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -1
  110. package/dist/resources/extensions/gsd/workflow-event-ledger.js +1 -1
  111. package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
  112. package/dist/resources/extensions/gsd/workflow-projections.js +9 -26
  113. package/dist/resources/extensions/gsd/workspace-git-preflight.js +2 -2
  114. package/dist/resources/extensions/gsd/workspace.js +5 -14
  115. package/dist/resources/extensions/gsd/worktree-command.js +1 -1
  116. package/dist/resources/extensions/gsd/worktree-lifecycle.js +14 -9
  117. package/dist/resources/extensions/gsd/worktree-reentry.js +2 -1
  118. package/dist/resources/extensions/shared/gsd-browser-cli.js +51 -5
  119. package/dist/resources/extensions/shared/interview-ui.js +62 -9
  120. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  121. package/dist/web/standalone/.next/BUILD_ID +1 -1
  122. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  123. package/dist/web/standalone/.next/build-manifest.json +3 -3
  124. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  125. package/dist/web/standalone/.next/required-server-files.json +3 -3
  126. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  127. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  129. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  137. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  139. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  140. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  143. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  145. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  146. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  148. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  154. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  156. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  162. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  170. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  172. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  175. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  178. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  184. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  187. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  190. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  193. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  196. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  199. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  202. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  203. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  204. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  205. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  206. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  207. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  208. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  210. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  211. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  212. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  213. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  214. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  215. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  216. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  217. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  218. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  219. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  220. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  221. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  222. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  223. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  224. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  225. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  226. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  227. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  228. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  229. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  230. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  231. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  232. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  233. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  234. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  235. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  236. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  237. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  238. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  239. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  240. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  241. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  242. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  243. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  244. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  245. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  246. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  247. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  248. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  249. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  250. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  251. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  252. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  253. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  254. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  255. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  256. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  257. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  258. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  259. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  260. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  261. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  262. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  263. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  264. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  265. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  266. package/dist/web/standalone/.next/server/app/index.html +1 -1
  267. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  268. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  269. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  270. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  271. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  272. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  273. package/dist/web/standalone/.next/server/app/page.js +2 -2
  274. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  275. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  276. package/dist/web/standalone/.next/server/chunks/{1128.js → 1991.js} +1 -1
  277. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  278. package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
  279. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  280. package/dist/web/standalone/.next/server/middleware.js +3 -3
  281. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  282. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  283. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  284. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
  285. package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
  286. package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
  287. package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
  288. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
  289. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  290. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  291. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  292. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  293. package/dist/web/standalone/server.js +1 -1
  294. package/dist/worktree-cli-create.d.ts +10 -0
  295. package/dist/worktree-cli-create.js +11 -0
  296. package/dist/worktree-cli-format.d.ts +12 -0
  297. package/dist/worktree-cli-format.js +38 -0
  298. package/dist/worktree-cli-plan.d.ts +16 -0
  299. package/dist/worktree-cli-plan.js +19 -0
  300. package/dist/worktree-cli-session.d.ts +13 -0
  301. package/dist/worktree-cli-session.js +18 -0
  302. package/dist/worktree-cli-status.d.ts +35 -0
  303. package/dist/worktree-cli-status.js +54 -0
  304. package/dist/worktree-cli.d.ts +1 -16
  305. package/dist/worktree-cli.js +28 -122
  306. package/integrations/hermes/open_gsd_hermes/gsd_client.py +25 -36
  307. package/integrations/hermes/pyproject.toml +1 -1
  308. package/integrations/hermes/tests/test_gsd_client_timeout.py +4 -4
  309. package/package.json +6 -6
  310. package/packages/cloud-mcp-gateway/package.json +2 -2
  311. package/packages/contracts/package.json +1 -1
  312. package/packages/daemon/dist/cloud-cli.d.ts +1 -1
  313. package/packages/daemon/dist/cloud-cli.d.ts.map +1 -1
  314. package/packages/daemon/dist/cloud-cli.js +42 -2
  315. package/packages/daemon/dist/cloud-cli.js.map +1 -1
  316. package/packages/daemon/dist/cloud-config.d.ts +1 -0
  317. package/packages/daemon/dist/cloud-config.d.ts.map +1 -1
  318. package/packages/daemon/dist/cloud-config.js +1 -1
  319. package/packages/daemon/dist/cloud-config.js.map +1 -1
  320. package/packages/daemon/dist/device-flow.d.ts +24 -0
  321. package/packages/daemon/dist/device-flow.d.ts.map +1 -0
  322. package/packages/daemon/dist/device-flow.js +128 -0
  323. package/packages/daemon/dist/device-flow.js.map +1 -0
  324. package/packages/daemon/dist/device-flow.test.d.ts +2 -0
  325. package/packages/daemon/dist/device-flow.test.d.ts.map +1 -0
  326. package/packages/daemon/dist/device-flow.test.js +172 -0
  327. package/packages/daemon/dist/device-flow.test.js.map +1 -0
  328. package/packages/daemon/dist/orchestrator-agent.d.ts +21 -0
  329. package/packages/daemon/dist/orchestrator-agent.d.ts.map +1 -0
  330. package/packages/daemon/dist/orchestrator-agent.js +113 -0
  331. package/packages/daemon/dist/orchestrator-agent.js.map +1 -0
  332. package/packages/daemon/dist/orchestrator-tools.d.ts +12 -0
  333. package/packages/daemon/dist/orchestrator-tools.d.ts.map +1 -0
  334. package/packages/daemon/dist/orchestrator-tools.js +137 -0
  335. package/packages/daemon/dist/orchestrator-tools.js.map +1 -0
  336. package/packages/daemon/dist/orchestrator.d.ts +4 -56
  337. package/packages/daemon/dist/orchestrator.d.ts.map +1 -1
  338. package/packages/daemon/dist/orchestrator.js +13 -303
  339. package/packages/daemon/dist/orchestrator.js.map +1 -1
  340. package/packages/daemon/dist/orchestrator.test.js +11 -1
  341. package/packages/daemon/dist/orchestrator.test.js.map +1 -1
  342. package/packages/daemon/package.json +5 -5
  343. package/packages/gsd-agent-core/dist/export-html/template.js +53 -4
  344. package/packages/gsd-agent-core/package.json +5 -5
  345. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  346. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +3 -2
  347. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  348. package/packages/gsd-agent-modes/package.json +7 -7
  349. package/packages/gsd-cloud/README.md +34 -0
  350. package/packages/gsd-cloud/bin/gsd-cloud.js +27 -0
  351. package/packages/gsd-cloud/package.json +38 -0
  352. package/packages/mcp-server/package.json +4 -4
  353. package/packages/native/package.json +1 -1
  354. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  355. package/packages/pi-agent-core/dist/agent-loop.js +14 -9
  356. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  357. package/packages/pi-agent-core/package.json +1 -1
  358. package/packages/pi-ai/dist/index.d.ts +1 -0
  359. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  360. package/packages/pi-ai/dist/index.js +1 -0
  361. package/packages/pi-ai/dist/index.js.map +1 -1
  362. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  363. package/packages/pi-ai/dist/providers/transform-messages.js +7 -3
  364. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  365. package/packages/pi-ai/dist/tool-result-content.d.ts +3 -0
  366. package/packages/pi-ai/dist/tool-result-content.d.ts.map +1 -0
  367. package/packages/pi-ai/dist/tool-result-content.js +62 -0
  368. package/packages/pi-ai/dist/tool-result-content.js.map +1 -0
  369. package/packages/pi-ai/dist/types.d.ts +8 -20
  370. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  371. package/packages/pi-ai/dist/types.js.map +1 -1
  372. package/packages/pi-ai/package.json +1 -1
  373. package/packages/pi-coding-agent/dist/core/package-manager.d.ts +9 -0
  374. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  375. package/packages/pi-coding-agent/dist/core/package-manager.js +74 -53
  376. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  377. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +6 -0
  378. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  379. package/packages/pi-coding-agent/dist/core/resource-loader.js +30 -2
  380. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  381. package/packages/pi-coding-agent/dist/core/skill-directories.d.ts +66 -0
  382. package/packages/pi-coding-agent/dist/core/skill-directories.d.ts.map +1 -0
  383. package/packages/pi-coding-agent/dist/core/skill-directories.js +138 -0
  384. package/packages/pi-coding-agent/dist/core/skill-directories.js.map +1 -0
  385. package/packages/pi-coding-agent/dist/core/skills.d.ts +4 -1
  386. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  387. package/packages/pi-coding-agent/dist/core/skills.js +4 -1
  388. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  389. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  390. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  391. package/packages/pi-coding-agent/dist/index.js +1 -0
  392. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  393. package/packages/pi-coding-agent/package.json +7 -7
  394. package/packages/pi-tui/package.json +2 -2
  395. package/packages/rpc-client/package.json +2 -2
  396. package/pkg/dist/core/export-html/template.js +53 -4
  397. package/pkg/package.json +1 -1
  398. package/src/resources/extensions/ask-user-questions.ts +1 -1
  399. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +146 -33
  400. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +44 -0
  401. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +93 -0
  402. package/src/resources/extensions/gsd/activity-log.ts +1 -1
  403. package/src/resources/extensions/gsd/auto/closeout.ts +114 -7
  404. package/src/resources/extensions/gsd/auto/orchestrator.ts +21 -14
  405. package/src/resources/extensions/gsd/auto/pre-dispatch.ts +6 -3
  406. package/src/resources/extensions/gsd/auto/unit-phase.ts +5 -9
  407. package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -4
  408. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +13 -7
  409. package/src/resources/extensions/gsd/auto-dispatch.ts +77 -16
  410. package/src/resources/extensions/gsd/auto-model-selection.ts +33 -1
  411. package/src/resources/extensions/gsd/auto-post-unit.ts +26 -5
  412. package/src/resources/extensions/gsd/auto-prompts.ts +73 -113
  413. package/src/resources/extensions/gsd/auto-recovery.ts +50 -6
  414. package/src/resources/extensions/gsd/auto-start.ts +62 -31
  415. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -2
  416. package/src/resources/extensions/gsd/auto-timers.ts +9 -2
  417. package/src/resources/extensions/gsd/auto-worktree-branch-lifecycle.ts +237 -0
  418. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +166 -0
  419. package/src/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.ts +37 -0
  420. package/src/resources/extensions/gsd/auto-worktree-creation.ts +171 -0
  421. package/src/resources/extensions/gsd/auto-worktree-entry.ts +154 -0
  422. package/src/resources/extensions/gsd/auto-worktree-merge-already-merged.ts +161 -0
  423. package/src/resources/extensions/gsd/auto-worktree-merge-branch-head.ts +83 -0
  424. package/src/resources/extensions/gsd/auto-worktree-merge-cleanup.ts +132 -0
  425. package/src/resources/extensions/gsd/auto-worktree-merge-code-changes.ts +71 -0
  426. package/src/resources/extensions/gsd/auto-worktree-merge-db-ready.ts +112 -0
  427. package/src/resources/extensions/gsd/auto-worktree-merge-integration-branch.ts +99 -0
  428. package/src/resources/extensions/gsd/auto-worktree-merge-message.ts +166 -0
  429. package/src/resources/extensions/gsd/auto-worktree-merge-pre-teardown.ts +93 -0
  430. package/src/resources/extensions/gsd/auto-worktree-merge-stash.ts +213 -0
  431. package/src/resources/extensions/gsd/auto-worktree-merge.ts +391 -0
  432. package/src/resources/extensions/gsd/auto-worktree-milestone-shelter.ts +159 -0
  433. package/src/resources/extensions/gsd/auto-worktree-path-resolution.ts +6 -0
  434. package/src/resources/extensions/gsd/auto-worktree-path-utils.ts +10 -0
  435. package/src/resources/extensions/gsd/auto-worktree-resource-version.ts +44 -0
  436. package/src/resources/extensions/gsd/auto-worktree-runtime-cleanup.ts +119 -0
  437. package/src/resources/extensions/gsd/auto-worktree-session-registry.ts +71 -0
  438. package/src/resources/extensions/gsd/auto-worktree-sync.ts +370 -0
  439. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +161 -0
  440. package/src/resources/extensions/gsd/auto-worktree.ts +69 -2429
  441. package/src/resources/extensions/gsd/auto.ts +126 -47
  442. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -1
  443. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +20 -2
  444. package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
  445. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +218 -27
  446. package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +77 -1
  447. package/src/resources/extensions/gsd/codebase-generator.ts +7 -1
  448. package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
  449. package/src/resources/extensions/gsd/commands-workflow-templates.ts +3 -3
  450. package/src/resources/extensions/gsd/compat/compat-marker.ts +47 -0
  451. package/src/resources/extensions/gsd/config-overlay.ts +7 -1
  452. package/src/resources/extensions/gsd/db/engine.ts +36 -0
  453. package/src/resources/extensions/gsd/db/queries.ts +9 -9
  454. package/src/resources/extensions/gsd/db/writers/cascades.ts +23 -1
  455. package/src/resources/extensions/gsd/db-adapter.ts +29 -3
  456. package/src/resources/extensions/gsd/docs/preferences-reference.md +3 -3
  457. package/src/resources/extensions/gsd/doctor-engine-checks.ts +109 -10
  458. package/src/resources/extensions/gsd/flat-phase-migration.ts +34 -3
  459. package/src/resources/extensions/gsd/forensics.ts +1 -1
  460. package/src/resources/extensions/gsd/git-conflict-resolve.ts +2 -2
  461. package/src/resources/extensions/gsd/git-service.ts +53 -0
  462. package/src/resources/extensions/gsd/gsd-db.ts +33 -11
  463. package/src/resources/extensions/gsd/guided-flow.ts +26 -18
  464. package/src/resources/extensions/gsd/journal.ts +1 -1
  465. package/src/resources/extensions/gsd/markdown-renderer.ts +52 -91
  466. package/src/resources/extensions/gsd/md-importer.ts +93 -22
  467. package/src/resources/extensions/gsd/metrics.ts +2 -2
  468. package/src/resources/extensions/gsd/migration-auto-check.ts +32 -3
  469. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +15 -0
  470. package/src/resources/extensions/gsd/milestone-settlement.ts +1 -1
  471. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  472. package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -1
  473. package/src/resources/extensions/gsd/paths.ts +108 -51
  474. package/src/resources/extensions/gsd/post-unit-hooks.ts +32 -0
  475. package/src/resources/extensions/gsd/preferences-models.ts +74 -20
  476. package/src/resources/extensions/gsd/preferences-skills.ts +10 -16
  477. package/src/resources/extensions/gsd/preferences-types.ts +54 -1
  478. package/src/resources/extensions/gsd/preferences-validation.ts +146 -9
  479. package/src/resources/extensions/gsd/preferences.ts +20 -0
  480. package/src/resources/extensions/gsd/prompts/system.md +6 -6
  481. package/src/resources/extensions/gsd/quick.ts +11 -3
  482. package/src/resources/extensions/gsd/reopen-reason.ts +109 -0
  483. package/src/resources/extensions/gsd/rule-registry.ts +111 -9
  484. package/src/resources/extensions/gsd/session-status-io.ts +34 -0
  485. package/src/resources/extensions/gsd/skill-discovery.ts +47 -23
  486. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +3 -1
  487. package/src/resources/extensions/gsd/state/derive/from-db.ts +201 -157
  488. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +1 -9
  489. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +2 -22
  490. package/src/resources/extensions/gsd/state-reconciliation/index.ts +14 -0
  491. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +169 -1
  492. package/src/resources/extensions/gsd/tests/auto-loop-no-copy-artifacts.test.ts +2 -1
  493. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +41 -2
  494. package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +48 -1
  495. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +57 -0
  496. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +1 -1
  497. package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +29 -1
  498. package/src/resources/extensions/gsd/tests/auto-timeout-recovery-supervisor-inflight-guard.test.ts +159 -0
  499. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +2 -1
  500. package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +1 -1
  501. package/src/resources/extensions/gsd/tests/auto-worktree-merge-already-merged.test.ts +177 -0
  502. package/src/resources/extensions/gsd/tests/auto-worktree-merge-branch-head.test.ts +118 -0
  503. package/src/resources/extensions/gsd/tests/auto-worktree-merge-cleanup.test.ts +115 -0
  504. package/src/resources/extensions/gsd/tests/auto-worktree-merge-code-changes.test.ts +76 -0
  505. package/src/resources/extensions/gsd/tests/auto-worktree-merge-db-ready.test.ts +140 -0
  506. package/src/resources/extensions/gsd/tests/auto-worktree-merge-integration-branch.test.ts +123 -0
  507. package/src/resources/extensions/gsd/tests/auto-worktree-merge-message.test.ts +114 -0
  508. package/src/resources/extensions/gsd/tests/auto-worktree-merge-pre-teardown.test.ts +84 -0
  509. package/src/resources/extensions/gsd/tests/auto-worktree-merge-stash.test.ts +70 -0
  510. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-shelter.test.ts +52 -0
  511. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +6 -6
  512. package/src/resources/extensions/gsd/tests/auto-worktree-resource-version.test.ts +59 -0
  513. package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +3 -1
  514. package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +26 -0
  515. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  516. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +3 -1
  517. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +85 -0
  518. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +45 -0
  519. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +1 -1
  520. package/src/resources/extensions/gsd/tests/db-adapter.test.ts +39 -0
  521. package/src/resources/extensions/gsd/tests/db-writable-probe.test.ts +66 -0
  522. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -0
  523. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +174 -0
  524. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +1 -1
  525. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +71 -1
  526. package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +46 -1
  527. package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +72 -32
  528. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +40 -0
  529. package/src/resources/extensions/gsd/tests/import-completion-lost-update.test.ts +196 -0
  530. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +4 -6
  531. package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +2 -1
  532. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +3 -3
  533. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +7 -8
  534. package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +2 -5
  535. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +76 -0
  536. package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +1 -1
  537. package/src/resources/extensions/gsd/tests/integration/merge-preserve-worktree-on-preteardown-error.test.ts +1 -1
  538. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +2 -1
  539. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +5 -7
  540. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +88 -1
  541. package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +2 -4
  542. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -15
  543. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +1 -1
  544. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +1 -1
  545. package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +1 -1
  546. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +91 -0
  547. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +2 -1
  548. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +439 -0
  549. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +24 -0
  550. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +1 -1
  551. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -3
  552. package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +1 -1
  553. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +0 -1
  554. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +269 -0
  555. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +8 -1
  556. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +1 -4
  557. package/src/resources/extensions/gsd/tests/preferences.test.ts +19 -0
  558. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +5 -0
  559. package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +54 -0
  560. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +49 -1
  561. package/src/resources/extensions/gsd/tests/reopen-reason.test.ts +117 -0
  562. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +52 -0
  563. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +95 -1
  564. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +20 -0
  565. package/src/resources/extensions/gsd/tests/sibling-model-fallbacks.test.ts +189 -0
  566. package/src/resources/extensions/gsd/tests/single-field-model-thinking.test.ts +156 -0
  567. package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +46 -0
  568. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +6 -1
  569. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -5
  570. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +32 -0
  571. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +2 -1
  572. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +2 -1
  573. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +1 -1
  574. package/src/resources/extensions/gsd/tests/supervisor-model-swap-inflight-guard.test.ts +181 -0
  575. package/src/resources/extensions/gsd/tests/supervisor-model-swap-thinking-clamp.test.ts +122 -0
  576. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +1 -1
  577. package/src/resources/extensions/gsd/tests/system-flat-phase-layout.test.ts +33 -0
  578. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +4 -4
  579. package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +2 -1
  580. package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +4 -4
  581. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +196 -0
  582. package/src/resources/extensions/gsd/tests/uat-dispatch.test.ts +211 -0
  583. package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +1 -1
  584. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +26 -1
  585. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +39 -0
  586. package/src/resources/extensions/gsd/tests/uok-kernel-path.test.ts +226 -2
  587. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +6 -0
  588. package/src/resources/extensions/gsd/tests/worker-resume-wait.test.ts +73 -0
  589. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +213 -2
  590. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -1
  591. package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +1 -1
  592. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +1 -3
  593. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +1 -1
  594. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +1 -1
  595. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +1 -1
  596. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +1 -1
  597. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +2 -1
  598. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +5 -2
  599. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +1 -1
  600. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +1 -1
  601. package/src/resources/extensions/gsd/tool-contract.ts +29 -0
  602. package/src/resources/extensions/gsd/tools/complete-milestone.ts +9 -5
  603. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +19 -8
  604. package/src/resources/extensions/gsd/tools/reopen-slice.ts +5 -0
  605. package/src/resources/extensions/gsd/tools/reopen-task.ts +28 -5
  606. package/src/resources/extensions/gsd/tools/validate-milestone.ts +13 -9
  607. package/src/resources/extensions/gsd/types.ts +23 -4
  608. package/src/resources/extensions/gsd/uat-dispatch.ts +176 -0
  609. package/src/resources/extensions/gsd/unit-registry.ts +16 -2
  610. package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +1 -1
  611. package/src/resources/extensions/gsd/uok/audit-toggle.ts +32 -2
  612. package/src/resources/extensions/gsd/uok/audit.ts +2 -0
  613. package/src/resources/extensions/gsd/uok/gate-runner.ts +26 -36
  614. package/src/resources/extensions/gsd/uok/gitops.ts +21 -18
  615. package/src/resources/extensions/gsd/uok/kernel.ts +169 -48
  616. package/src/resources/extensions/gsd/uok/model-policy.ts +20 -17
  617. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -1
  618. package/src/resources/extensions/gsd/workflow-event-ledger.ts +1 -1
  619. package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
  620. package/src/resources/extensions/gsd/workflow-projections.ts +9 -24
  621. package/src/resources/extensions/gsd/workspace-git-preflight.ts +2 -2
  622. package/src/resources/extensions/gsd/workspace.ts +5 -21
  623. package/src/resources/extensions/gsd/worktree-command.ts +1 -1
  624. package/src/resources/extensions/gsd/worktree-lifecycle.ts +19 -15
  625. package/src/resources/extensions/gsd/worktree-reentry.ts +2 -1
  626. package/src/resources/extensions/shared/gsd-browser-cli.ts +64 -7
  627. package/src/resources/extensions/shared/interview-ui.ts +58 -11
  628. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +32 -0
  629. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  630. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  631. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  632. /package/dist/web/standalone/.next/static/{bCg3aYrFN1DKZr2dqgE7L → XFuMvz26Zb_lrrR-8dvkd}/_buildManifest.js +0 -0
  633. /package/dist/web/standalone/.next/static/{bCg3aYrFN1DKZr2dqgE7L → XFuMvz26Zb_lrrR-8dvkd}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Orchestrator — LLM-powered agent for the #gsd-control Discord channel.\n *\n * Receives Discord messages, maintains conversation history, calls the\n * Anthropic messages API with 5 tool definitions (list_projects, start_session,\n * get_status, stop_session, get_session_detail), and sends the LLM's response\n * back to Discord.\n *\n * Uses the standard messages.create() tool-use loop (not betaZodTool helpers,\n * which don't exist in SDK v0.52). Zod schemas are used for input validation\n * at the tool execution layer.\n */\n\nimport { z } from 'zod';\nimport type Anthropic from '@anthropic-ai/sdk';\nimport type {\n MessageParam,\n ContentBlockParam,\n Tool,\n ToolResultBlockParam,\n ToolUseBlock,\n TextBlock,\n} from '@anthropic-ai/sdk/resources/messages/messages';\nimport type { SessionManager } from './session-manager.js';\nimport type { ChannelManager } from './channel-manager.js';\nimport type { ProjectInfo, ManagedSession } from './types.js';\nimport type { Logger } from './logger.js';\n\n// ---------------------------------------------------------------------------\n// API key resolution — requires ANTHROPIC_API_KEY env var\n// Anthropic OAuth removed per TOS compliance (see docs/user-docs/claude-code-auth-compliance.md)\n// ---------------------------------------------------------------------------\n\nfunction resolveAnthropicApiKey(): string {\n const apiKey = process.env.ANTHROPIC_API_KEY;\n if (!apiKey) {\n throw new Error(\n 'ANTHROPIC_API_KEY is required. Set it in your environment or run `gsd config`.',\n );\n }\n return apiKey;\n}\n\n// ---------------------------------------------------------------------------\n// Configuration\n// ---------------------------------------------------------------------------\n\nexport interface OrchestratorConfig {\n model: string;\n max_tokens: number;\n control_channel_id: string;\n}\n\nexport interface OrchestratorDeps {\n sessionManager: SessionManager;\n channelManager: ChannelManager;\n scanProjects: () => Promise<ProjectInfo[]>;\n config: OrchestratorConfig;\n logger: Logger;\n ownerId: string;\n}\n\n// ---------------------------------------------------------------------------\n// System Prompt\n// ---------------------------------------------------------------------------\n\nconst SYSTEM_PROMPT = `You are GSD Control — a concise, capable orchestrator for managing GSD (Git Ship Done) coding agent sessions via Discord.\n\nYou have tools to list projects, start sessions, get status, stop sessions, and inspect session details. Use them to fulfill the user's requests.\n\nResponse guidelines:\n- Be terse and direct. No filler, no performed enthusiasm.\n- When reporting status, use bullet points with project name, status, duration, and cost.\n- When starting a session, confirm with the project name and session ID.\n- When stopping a session, confirm which session was stopped.\n- If something fails, say what went wrong plainly.\n- Use Discord markdown formatting (bold, code blocks) for readability.\n- Never expose internal error stack traces to the user — summarize the issue.`;\n\n// ---------------------------------------------------------------------------\n// Tool Definitions (Anthropic API format)\n// ---------------------------------------------------------------------------\n\nconst TOOLS: Tool[] = [\n {\n name: 'list_projects',\n description: 'List all detected projects across configured scan roots. Returns project names, paths, and detected markers (git, node, gsd, etc.).',\n input_schema: {\n type: 'object' as const,\n properties: {},\n required: [],\n },\n },\n {\n name: 'start_session',\n description: 'Start a new GSD auto-mode session for a project. Provide the absolute project path. Optionally provide a command to run instead of the default \"/gsd auto\".',\n input_schema: {\n type: 'object' as const,\n properties: {\n projectPath: { type: 'string', description: 'Absolute path to the project directory' },\n command: { type: 'string', description: 'Optional command to send instead of \"/gsd auto\"' },\n },\n required: ['projectPath'],\n },\n },\n {\n name: 'get_status',\n description: 'Get the current status of all active GSD sessions. Shows project name, status, duration, and cost for each.',\n input_schema: {\n type: 'object' as const,\n properties: {},\n required: [],\n },\n },\n {\n name: 'stop_session',\n description: 'Stop a running GSD session. Provide a session ID or project name — fuzzy matching is used to find the session.',\n input_schema: {\n type: 'object' as const,\n properties: {\n identifier: { type: 'string', description: 'Session ID or project name to match' },\n },\n required: ['identifier'],\n },\n },\n {\n name: 'get_session_detail',\n description: 'Get detailed information about a specific session including cost breakdown, recent events, pending blockers, and error state.',\n input_schema: {\n type: 'object' as const,\n properties: {\n sessionId: { type: 'string', description: 'The session ID to inspect' },\n },\n required: ['sessionId'],\n },\n },\n];\n\n// ---------------------------------------------------------------------------\n// Zod schemas for tool input validation\n// ---------------------------------------------------------------------------\n\nconst StartSessionInput = z.object({\n projectPath: z.string(),\n command: z.string().optional(),\n});\n\nconst StopSessionInput = z.object({\n identifier: z.string(),\n});\n\nconst GetSessionDetailInput = z.object({\n sessionId: z.string(),\n});\n\n// ---------------------------------------------------------------------------\n// Conversation History Cap\n// ---------------------------------------------------------------------------\n\nconst MAX_HISTORY = 30;\n\n// ---------------------------------------------------------------------------\n// Orchestrator\n// ---------------------------------------------------------------------------\n\nexport class Orchestrator {\n private readonly deps: OrchestratorDeps;\n private client: Anthropic | null;\n private history: MessageParam[] = [];\n\n /**\n * @param deps - orchestrator dependencies (session manager, channel manager, etc.)\n * @param client - optional Anthropic client for testability; if omitted, created from env\n */\n constructor(deps: OrchestratorDeps, client?: Anthropic) {\n this.deps = deps;\n this.client = client ?? null;\n }\n\n /**\n * Lazily initialise the Anthropic client. Dynamic import handles K007 module resolution.\n * Requires ANTHROPIC_API_KEY environment variable.\n */\n private async getClient(): Promise<Anthropic> {\n if (this.client) return this.client;\n const apiKey = resolveAnthropicApiKey();\n const { default: AnthropicSDK } = await import('@anthropic-ai/sdk');\n this.client = new AnthropicSDK({ apiKey });\n return this.client;\n }\n\n /**\n * Handle an incoming Discord message. Entry point called by the bot's\n * message handler for every message in every channel.\n *\n * Guards: ignores bot messages, non-owner messages, and non-control-channel messages.\n */\n async handleMessage(message: DiscordMessageLike): Promise<void> {\n // Ignore bot messages\n if (message.author.bot) return;\n\n // Ignore non-control-channel messages\n if (message.channelId !== this.deps.config.control_channel_id) return;\n\n // Auth guard — only the owner can use the orchestrator\n if (message.author.id !== this.deps.ownerId) {\n this.deps.logger.debug('orchestrator auth rejected', { userId: message.author.id });\n return;\n }\n\n const content = message.content?.trim();\n if (!content) return;\n\n this.deps.logger.info('orchestrator message received', {\n userId: message.author.id,\n channelId: message.channelId,\n contentLength: content.length,\n });\n\n // Append user message to history\n this.history.push({ role: 'user', content });\n\n try {\n // Show typing indicator while processing\n await message.channel.sendTyping().catch(() => {});\n\n const responseText = await this.runAgentLoop();\n\n // Send response to Discord\n await message.channel.send(responseText);\n\n this.deps.logger.info('orchestrator response sent', {\n channelId: message.channelId,\n responseLength: responseText.length,\n });\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n\n // Invalidate cached client on auth errors so next call re-resolves OAuth token\n if (errorMsg.includes('authentication') || errorMsg.includes('apiKey') || errorMsg.includes('authToken') || errorMsg.includes('401')) {\n this.client = null;\n }\n\n this.deps.logger.error('orchestrator error', {\n error: errorMsg,\n userId: message.author.id,\n channelId: message.channelId,\n });\n\n // Send error feedback to Discord\n try {\n await message.channel.send('⚠️ Something went wrong processing your request.');\n } catch (sendErr) {\n this.deps.logger.warn('orchestrator error reply failed', {\n error: sendErr instanceof Error ? sendErr.message : String(sendErr),\n });\n }\n\n // Still append a synthetic assistant message so history stays paired\n this.history.push({ role: 'assistant', content: '[error — see logs]' });\n }\n\n this.trimHistory();\n }\n\n /**\n * Run the tool-use loop: call messages.create(), execute any tool calls,\n * feed results back, repeat until the model produces a final text response.\n */\n private async runAgentLoop(): Promise<string> {\n const client = await this.getClient();\n const { model, max_tokens } = this.deps.config;\n\n let loopMessages: MessageParam[] = [...this.history];\n const maxIterations = 10; // safety valve\n\n for (let i = 0; i < maxIterations; i++) {\n const response = await client.messages.create({\n model,\n max_tokens,\n system: SYSTEM_PROMPT,\n tools: TOOLS,\n messages: loopMessages,\n });\n\n // If the model stopped for end_turn (no tool calls), extract text and return\n if (response.stop_reason === 'end_turn' || response.stop_reason !== 'tool_use') {\n const textBlocks = response.content.filter(\n (b): b is TextBlock => b.type === 'text',\n );\n const finalText = textBlocks.map((b) => b.text).join('\\n') || '(No response)';\n\n // Append assistant message to conversation history\n this.history.push({ role: 'assistant', content: finalText });\n\n return finalText;\n }\n\n // Model wants to use tools — execute them all\n const toolUseBlocks = response.content.filter(\n (b): b is ToolUseBlock => b.type === 'tool_use',\n );\n\n // Build tool results\n const toolResults: ToolResultBlockParam[] = [];\n for (const toolUse of toolUseBlocks) {\n const result = await this.executeTool(toolUse.name, toolUse.input as Record<string, unknown>);\n toolResults.push({\n type: 'tool_result',\n tool_use_id: toolUse.id,\n content: result,\n });\n }\n\n // Append the assistant message (with tool_use blocks) and user tool_result message\n loopMessages = [\n ...loopMessages,\n { role: 'assistant', content: response.content as ContentBlockParam[] },\n { role: 'user', content: toolResults },\n ];\n }\n\n // If we hit max iterations, return a fallback\n return 'I hit the maximum number of tool iterations. Please try a simpler request.';\n }\n\n /**\n * Execute a single tool by name. Returns a string result for the LLM.\n * All errors are caught and returned as error strings (the LLM can reason about them).\n */\n private async executeTool(name: string, input: Record<string, unknown>): Promise<string> {\n try {\n switch (name) {\n case 'list_projects':\n return await this.toolListProjects();\n case 'start_session':\n return await this.toolStartSession(input);\n case 'get_status':\n return this.toolGetStatus();\n case 'get_session_detail':\n return this.toolGetSessionDetail(input);\n case 'stop_session':\n return await this.toolStopSession(input);\n default:\n return `Unknown tool: ${name}`;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n this.deps.logger.error('tool execution error', { tool: name, error: msg });\n return `Error: ${msg}`;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Tool implementations\n // ---------------------------------------------------------------------------\n\n private async toolListProjects(): Promise<string> {\n const projects = await this.deps.scanProjects();\n if (projects.length === 0) return 'No projects found.';\n return JSON.stringify(\n projects.map((p) => ({ name: p.name, path: p.path, markers: p.markers })),\n null,\n 2,\n );\n }\n\n private async toolStartSession(input: Record<string, unknown>): Promise<string> {\n const parsed = StartSessionInput.parse(input);\n const sessionId = await this.deps.sessionManager.startSession({\n projectDir: parsed.projectPath,\n command: parsed.command,\n });\n return `Session started: ${sessionId} for ${parsed.projectPath}`;\n }\n\n private toolGetStatus(): string {\n const sessions = this.deps.sessionManager.getAllSessions();\n if (sessions.length === 0) return 'No active sessions.';\n\n return sessions\n .map((s: ManagedSession) => {\n const durationMin = Math.floor((Date.now() - s.startTime) / 60_000);\n const cost = s.cost.totalCost.toFixed(4);\n return `• ${s.projectName} — ${s.status} (${durationMin}m, $${cost})`;\n })\n .join('\\n');\n }\n\n private async toolStopSession(input: Record<string, unknown>): Promise<string> {\n const parsed = StopSessionInput.parse(input);\n const { identifier } = parsed;\n\n // Try exact sessionId match first\n const byId = this.deps.sessionManager.getSession(identifier);\n if (byId) {\n await this.deps.sessionManager.cancelSession(identifier);\n return `Stopped session ${identifier} (${byId.projectName})`;\n }\n\n // Fuzzy match by project name\n const all = this.deps.sessionManager.getAllSessions();\n const match = all.find(\n (s: ManagedSession) =>\n s.projectName.toLowerCase().includes(identifier.toLowerCase()) ||\n s.projectDir.toLowerCase().includes(identifier.toLowerCase()),\n );\n if (match) {\n await this.deps.sessionManager.cancelSession(match.sessionId);\n return `Stopped session ${match.sessionId} (${match.projectName})`;\n }\n\n return `No session found matching \"${identifier}\"`;\n }\n\n private toolGetSessionDetail(input: Record<string, unknown>): string {\n const parsed = GetSessionDetailInput.parse(input);\n const result = this.deps.sessionManager.getResult(parsed.sessionId);\n return JSON.stringify(result, null, 2);\n }\n\n // ---------------------------------------------------------------------------\n // History management\n // ---------------------------------------------------------------------------\n\n /**\n * Trim conversation history to MAX_HISTORY entries.\n * Removes the oldest user+assistant pair from the front to keep pairs aligned.\n */\n private trimHistory(): void {\n while (this.history.length > MAX_HISTORY) {\n // Remove from front — two messages at a time to keep user/assistant pairs\n this.history.splice(0, 2);\n }\n }\n\n /**\n * Return a copy of the conversation history (for debugging / observability).\n */\n getHistory(): MessageParam[] {\n return [...this.history];\n }\n\n /**\n * Stop the orchestrator — clears history and nulls client reference.\n */\n stop(): void {\n this.history = [];\n this.client = null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Discord message type (minimal interface for testability)\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal Discord message interface — avoids importing discord.js directly,\n * making the orchestrator testable without full discord.js mocking.\n */\nexport interface DiscordMessageLike {\n author: { id: string; bot: boolean };\n channelId: string;\n content: string;\n channel: {\n send: (content: string) => Promise<unknown>;\n sendTyping: () => Promise<unknown>;\n };\n}\n"]}
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Orchestrator — Discord-facing controller for the #gsd-control channel.\n *\n * Receives Discord messages, filters them by channel/owner/bot guards, delegates\n * valid user content to OrchestratorAgent, and sends the response back to Discord.\n */\n\nimport type Anthropic from '@anthropic-ai/sdk';\nimport type { MessageParam } from '@anthropic-ai/sdk/resources/messages/messages';\nimport type { SessionManager } from './session-manager.js';\nimport type { ChannelManager } from './channel-manager.js';\nimport type { ProjectInfo } from './types.js';\nimport type { Logger } from './logger.js';\nimport { OrchestratorAgent } from './orchestrator-agent.js';\n\nexport interface OrchestratorConfig {\n model: string;\n max_tokens: number;\n control_channel_id: string;\n}\n\nexport interface OrchestratorDeps {\n sessionManager: SessionManager;\n channelManager: ChannelManager;\n scanProjects: () => Promise<ProjectInfo[]>;\n config: OrchestratorConfig;\n logger: Logger;\n ownerId: string;\n}\n\nexport class Orchestrator {\n private readonly deps: OrchestratorDeps;\n private readonly agent: OrchestratorAgent;\n\n constructor(deps: OrchestratorDeps, client?: Anthropic) {\n this.deps = deps;\n this.agent = new OrchestratorAgent(\n { model: deps.config.model, max_tokens: deps.config.max_tokens },\n {\n sessionManager: deps.sessionManager,\n scanProjects: deps.scanProjects,\n logger: deps.logger,\n },\n client,\n );\n }\n\n async handleMessage(message: DiscordMessageLike): Promise<void> {\n if (message.author.bot) return;\n if (message.channelId !== this.deps.config.control_channel_id) return;\n\n if (message.author.id !== this.deps.ownerId) {\n this.deps.logger.debug('orchestrator auth rejected', { userId: message.author.id });\n return;\n }\n\n const content = message.content?.trim();\n if (!content) return;\n\n this.deps.logger.info('orchestrator message received', {\n userId: message.author.id,\n channelId: message.channelId,\n contentLength: content.length,\n });\n\n try {\n await message.channel.sendTyping().catch(() => {});\n\n const responseText = await this.agent.run(content);\n await message.channel.send(responseText);\n\n this.deps.logger.info('orchestrator response sent', {\n channelId: message.channelId,\n responseLength: responseText.length,\n });\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n\n this.deps.logger.error('orchestrator error', {\n error: errorMsg,\n userId: message.author.id,\n channelId: message.channelId,\n });\n\n try {\n await message.channel.send('⚠️ Something went wrong processing your request.');\n } catch (sendErr) {\n this.deps.logger.warn('orchestrator error reply failed', {\n error: sendErr instanceof Error ? sendErr.message : String(sendErr),\n });\n }\n }\n }\n\n getHistory(): MessageParam[] {\n return this.agent.getHistory();\n }\n\n stop(): void {\n this.agent.stop();\n }\n}\n\nexport interface DiscordMessageLike {\n author: { id: string; bot: boolean };\n channelId: string;\n content: string;\n channel: {\n send: (content: string) => Promise<unknown>;\n sendTyping: () => Promise<unknown>;\n };\n}\n"]}
@@ -234,8 +234,18 @@ describe('Orchestrator', () => {
234
234
  await orchestrator.handleMessage(msg);
235
235
  assert.equal(msg.sentMessages.length, 1);
236
236
  assert.equal(msg.sentMessages[0], 'Here are your projects');
237
- // The tool was called (2 create calls: tool_use + end_turn)
238
237
  assert.equal(mockClient.createCallCount, 2);
238
+ const finalMessages = mockClient.lastCreateParams?.messages;
239
+ const toolResultMessage = finalMessages.at(-1);
240
+ assert.equal(toolResultMessage?.role, 'user');
241
+ const toolResults = toolResultMessage?.content;
242
+ assert.equal(toolResults.length, 1);
243
+ assert.match(toolResults[0].tool_use_id, /^toolu_/);
244
+ assert.equal(toolResults[0].type, 'tool_result');
245
+ assert.equal(toolResults[0].content, JSON.stringify([
246
+ { name: 'alpha', path: '/home/user/alpha', markers: ['git', 'node', 'gsd'] },
247
+ { name: 'bravo', path: '/home/user/bravo', markers: ['git', 'rust'] },
248
+ ], null, 2));
239
249
  });
240
250
  });
241
251
  // ---- start_session tool ----
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.test.js","sourceRoot":"","sources":["../src/orchestrator.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tests for Orchestrator — LLM agent for #gsd-control channel.\n *\n * Uses a MockAnthropicClient that simulates messages.create() responses,\n * allowing tool execution and conversation flow testing without real API calls.\n */\n\nimport { describe, it, afterEach } from 'node:test';\nimport assert from 'node:assert/strict';\nimport { mkdtempSync, rmSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { randomUUID } from 'node:crypto';\nimport { Orchestrator, type OrchestratorConfig, type OrchestratorDeps, type DiscordMessageLike } from './orchestrator.js';\nimport { Logger } from './logger.js';\nimport type { ManagedSession, ProjectInfo, SessionStatus, CostAccumulator } from './types.js';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction tmpDir(): string {\n return mkdtempSync(join(tmpdir(), `orch-test-${randomUUID().slice(0, 8)}-`));\n}\n\nconst cleanupDirs: string[] = [];\nconst activeLoggers: Logger[] = [];\n\nasync function cleanupAll(): Promise<void> {\n // Close all loggers first so write streams flush before dirs are removed\n for (const logger of activeLoggers) {\n try { await logger.close(); } catch { /* ignore */ }\n }\n activeLoggers.length = 0;\n\n while (cleanupDirs.length) {\n const d = cleanupDirs.pop()!;\n if (existsSync(d)) rmSync(d, { recursive: true, force: true });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Mock Anthropic Client\n// ---------------------------------------------------------------------------\n\ninterface MockCreateParams {\n model: string;\n max_tokens: number;\n system: string;\n tools: unknown[];\n messages: unknown[];\n}\n\ntype CreateHandler = (params: MockCreateParams) => {\n stop_reason: string;\n content: Array<{ type: string; text?: string; id?: string; name?: string; input?: unknown }>;\n};\n\nclass MockAnthropicClient {\n public createCallCount = 0;\n public lastCreateParams: MockCreateParams | null = null;\n private createHandler: CreateHandler;\n\n constructor(handler?: CreateHandler) {\n this.createHandler = handler ?? MockAnthropicClient.defaultHandler;\n }\n\n /** Default handler: returns a simple text response */\n static defaultHandler(): ReturnType<CreateHandler> {\n return {\n stop_reason: 'end_turn',\n content: [{ type: 'text', text: 'Mock LLM response' }],\n };\n }\n\n /** Handler that simulates a tool call then end_turn */\n static toolThenTextHandler(toolName: string, toolInput: unknown, finalText: string): CreateHandler {\n let callCount = 0;\n return () => {\n callCount++;\n if (callCount === 1) {\n return {\n stop_reason: 'tool_use',\n content: [\n {\n type: 'tool_use',\n id: `toolu_${randomUUID().slice(0, 8)}`,\n name: toolName,\n input: toolInput,\n },\n ],\n };\n }\n return {\n stop_reason: 'end_turn',\n content: [{ type: 'text', text: finalText }],\n };\n };\n }\n\n /** Handler that throws an error */\n static errorHandler(message: string): CreateHandler {\n return () => {\n throw new Error(message);\n };\n }\n\n messages = {\n create: async (params: MockCreateParams) => {\n this.createCallCount++;\n this.lastCreateParams = params;\n return this.createHandler(params);\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Mock SessionManager\n// ---------------------------------------------------------------------------\n\nfunction makeMockSession(overrides: Partial<ManagedSession> = {}): ManagedSession {\n return {\n sessionId: overrides.sessionId ?? 'sess-123',\n projectDir: overrides.projectDir ?? '/home/user/project',\n projectName: overrides.projectName ?? 'my-project',\n status: overrides.status ?? ('running' as SessionStatus),\n client: {} as ManagedSession['client'],\n events: [],\n pendingBlocker: null,\n cost: overrides.cost ?? { totalCost: 0.1234, tokens: { input: 1000, output: 500, cacheRead: 0, cacheWrite: 0 } },\n startTime: overrides.startTime ?? Date.now() - 300_000, // 5 min ago\n ...overrides,\n };\n}\n\nclass MockSessionManager {\n public sessions: ManagedSession[] = [];\n public startSessionCalls: Array<{ projectDir: string; command?: string }> = [];\n public cancelSessionCalls: string[] = [];\n public getResultCalls: string[] = [];\n\n async startSession(opts: { projectDir: string; command?: string }): Promise<string> {\n this.startSessionCalls.push(opts);\n return 'sess-new-123';\n }\n\n getSession(sessionId: string): ManagedSession | undefined {\n return this.sessions.find((s) => s.sessionId === sessionId);\n }\n\n getAllSessions(): ManagedSession[] {\n return this.sessions;\n }\n\n async cancelSession(sessionId: string): Promise<void> {\n this.cancelSessionCalls.push(sessionId);\n }\n\n getResult(sessionId: string): Record<string, unknown> {\n const session = this.sessions.find((s) => s.sessionId === sessionId);\n if (!session) throw new Error(`Session not found: ${sessionId}`);\n return {\n sessionId: session.sessionId,\n projectDir: session.projectDir,\n projectName: session.projectName,\n status: session.status,\n durationMs: 300_000,\n cost: session.cost,\n recentEvents: [],\n pendingBlocker: null,\n error: null,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Mock ChannelManager (unused by orchestrator directly, but required by deps)\n// ---------------------------------------------------------------------------\n\nclass MockChannelManager {}\n\n// ---------------------------------------------------------------------------\n// Mock Discord Message\n// ---------------------------------------------------------------------------\n\nfunction makeMessage(overrides: Partial<{\n authorId: string;\n bot: boolean;\n channelId: string;\n content: string;\n}>): DiscordMessageLike & { sentMessages: string[] } {\n const sentMessages: string[] = [];\n return {\n author: {\n id: overrides.authorId ?? 'owner-123',\n bot: overrides.bot ?? false,\n },\n channelId: overrides.channelId ?? 'control-channel-1',\n content: overrides.content ?? 'hello',\n channel: {\n send: async (content: string) => {\n sentMessages.push(content);\n },\n sendTyping: async () => {},\n },\n sentMessages,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Test Setup Factory\n// ---------------------------------------------------------------------------\n\nfunction makeOrchestrator(opts?: {\n client?: MockAnthropicClient;\n sessions?: ManagedSession[];\n projects?: ProjectInfo[];\n}) {\n const dir = tmpDir();\n cleanupDirs.push(dir);\n const logPath = join(dir, 'test.log');\n const logger = new Logger({ filePath: logPath, level: 'debug' });\n activeLoggers.push(logger);\n\n const sessionManager = new MockSessionManager();\n if (opts?.sessions) sessionManager.sessions = opts.sessions;\n\n const projects: ProjectInfo[] = opts?.projects ?? [\n { name: 'alpha', path: '/home/user/alpha', markers: ['git', 'node', 'gsd'], lastModified: Date.now() },\n { name: 'bravo', path: '/home/user/bravo', markers: ['git', 'rust'], lastModified: Date.now() },\n ];\n\n const config: OrchestratorConfig = {\n model: 'claude-sonnet-4-20250514',\n max_tokens: 4096,\n control_channel_id: 'control-channel-1',\n };\n\n const deps: OrchestratorDeps = {\n sessionManager: sessionManager as unknown as OrchestratorDeps['sessionManager'],\n channelManager: new MockChannelManager() as unknown as OrchestratorDeps['channelManager'],\n scanProjects: async () => projects,\n config,\n logger,\n ownerId: 'owner-123',\n };\n\n const mockClient = opts?.client ?? new MockAnthropicClient();\n const orchestrator = new Orchestrator(deps, mockClient as unknown as import('@anthropic-ai/sdk').default);\n\n return { orchestrator, mockClient, sessionManager, logger, logPath };\n}\n\n// ---------------------------------------------------------------------------\n// Tests\n// ---------------------------------------------------------------------------\n\ndescribe('Orchestrator', () => {\n // Clean up after each test so logger streams are flushed before dirs removed\n afterEach(async () => {\n await cleanupAll();\n });\n\n // ---- Tool definitions ----\n\n describe('tool definitions', () => {\n it('passes 5 tools to the Anthropic API', async () => {\n const { orchestrator, mockClient } = makeOrchestrator();\n const msg = makeMessage({ content: 'what can you do?' });\n await orchestrator.handleMessage(msg);\n\n assert.ok(mockClient.lastCreateParams);\n const tools = mockClient.lastCreateParams.tools as Array<{ name: string }>;\n assert.equal(tools.length, 5);\n\n const names = tools.map((t) => t.name).sort();\n assert.deepEqual(names, [\n 'get_session_detail',\n 'get_status',\n 'list_projects',\n 'start_session',\n 'stop_session',\n ]);\n });\n });\n\n // ---- list_projects tool ----\n\n describe('list_projects tool', () => {\n it('returns project list from scanProjects', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler('list_projects', {}, 'Here are your projects'),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient });\n const msg = makeMessage({ content: 'list my projects' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(msg.sentMessages.length, 1);\n assert.equal(msg.sentMessages[0], 'Here are your projects');\n // The tool was called (2 create calls: tool_use + end_turn)\n assert.equal(mockClient.createCallCount, 2);\n });\n });\n\n // ---- start_session tool ----\n\n describe('start_session tool', () => {\n it('calls sessionManager.startSession and returns confirmation', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler(\n 'start_session',\n { projectPath: '/home/user/alpha' },\n 'Started session for alpha',\n ),\n );\n const { orchestrator, sessionManager } = makeOrchestrator({ client: mockClient });\n const msg = makeMessage({ content: 'start alpha' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(sessionManager.startSessionCalls.length, 1);\n assert.equal(sessionManager.startSessionCalls[0]!.projectDir, '/home/user/alpha');\n assert.equal(msg.sentMessages[0], 'Started session for alpha');\n });\n });\n\n // ---- get_status tool ----\n\n describe('get_status tool', () => {\n it('returns formatted session status', async () => {\n const session = makeMockSession({ projectName: 'alpha', status: 'running' as SessionStatus });\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler('get_status', {}, 'Status: alpha is running'),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient, sessions: [session] });\n const msg = makeMessage({ content: 'status' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(msg.sentMessages[0], 'Status: alpha is running');\n });\n\n it('handles empty session list', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler('get_status', {}, 'No sessions running'),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient, sessions: [] });\n const msg = makeMessage({ content: 'status' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(msg.sentMessages[0], 'No sessions running');\n });\n });\n\n // ---- stop_session tool ----\n\n describe('stop_session tool', () => {\n it('stops session matched by sessionId', async () => {\n const session = makeMockSession({ sessionId: 'sess-abc', projectName: 'alpha' });\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler(\n 'stop_session',\n { identifier: 'sess-abc' },\n 'Stopped alpha',\n ),\n );\n const { orchestrator, sessionManager } = makeOrchestrator({ client: mockClient, sessions: [session] });\n const msg = makeMessage({ content: 'stop sess-abc' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(sessionManager.cancelSessionCalls.length, 1);\n assert.equal(sessionManager.cancelSessionCalls[0], 'sess-abc');\n });\n\n it('fuzzy matches by project name', async () => {\n const session = makeMockSession({ sessionId: 'sess-xyz', projectName: 'my-big-project' });\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler(\n 'stop_session',\n { identifier: 'big-project' },\n 'Stopped my-big-project',\n ),\n );\n const { orchestrator, sessionManager } = makeOrchestrator({ client: mockClient, sessions: [session] });\n const msg = makeMessage({ content: 'stop big project' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(sessionManager.cancelSessionCalls.length, 1);\n assert.equal(sessionManager.cancelSessionCalls[0], 'sess-xyz');\n });\n\n it('returns not-found for unmatched identifier', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler(\n 'stop_session',\n { identifier: 'nonexistent' },\n 'No session found',\n ),\n );\n const { orchestrator, sessionManager } = makeOrchestrator({ client: mockClient, sessions: [] });\n const msg = makeMessage({ content: 'stop nonexistent' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(sessionManager.cancelSessionCalls.length, 0);\n });\n });\n\n // ---- get_session_detail tool ----\n\n describe('get_session_detail tool', () => {\n it('returns formatted session detail', async () => {\n const session = makeMockSession({ sessionId: 'sess-detail' });\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler(\n 'get_session_detail',\n { sessionId: 'sess-detail' },\n 'Session details for my-project',\n ),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient, sessions: [session] });\n const msg = makeMessage({ content: 'detail sess-detail' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(msg.sentMessages[0], 'Session details for my-project');\n });\n });\n\n // ---- Message routing / auth guards ----\n\n describe('handleMessage routing', () => {\n it('ignores bot messages', async () => {\n const { orchestrator, mockClient } = makeOrchestrator();\n const msg = makeMessage({ bot: true, content: 'hello from bot' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(mockClient.createCallCount, 0);\n assert.equal(msg.sentMessages.length, 0);\n });\n\n it('ignores non-owner messages', async () => {\n const { orchestrator, mockClient } = makeOrchestrator();\n const msg = makeMessage({ authorId: 'stranger-456', content: 'hack the planet' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(mockClient.createCallCount, 0);\n assert.equal(msg.sentMessages.length, 0);\n });\n\n it('ignores messages from non-control channels', async () => {\n const { orchestrator, mockClient } = makeOrchestrator();\n const msg = makeMessage({ channelId: 'random-channel', content: 'hello' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(mockClient.createCallCount, 0);\n assert.equal(msg.sentMessages.length, 0);\n });\n\n it('ignores empty message content', async () => {\n const { orchestrator, mockClient } = makeOrchestrator();\n const msg = makeMessage({ content: ' ' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(mockClient.createCallCount, 0);\n });\n\n it('routes valid message through LLM and sends response', async () => {\n const { orchestrator, mockClient } = makeOrchestrator();\n const msg = makeMessage({ content: 'hello orchestrator' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(mockClient.createCallCount, 1);\n assert.equal(msg.sentMessages.length, 1);\n assert.equal(msg.sentMessages[0], 'Mock LLM response');\n });\n });\n\n // ---- Conversation history ----\n\n describe('conversation history', () => {\n it('accumulates user and assistant entries', async () => {\n const { orchestrator } = makeOrchestrator();\n\n await orchestrator.handleMessage(makeMessage({ content: 'first' }));\n await orchestrator.handleMessage(makeMessage({ content: 'second' }));\n\n const history = orchestrator.getHistory();\n assert.equal(history.length, 4); // 2 user + 2 assistant\n assert.equal(history[0]!.role, 'user');\n assert.equal(history[1]!.role, 'assistant');\n assert.equal(history[2]!.role, 'user');\n assert.equal(history[3]!.role, 'assistant');\n });\n\n it('trims to MAX_HISTORY (30) by removing oldest pairs', async () => {\n const { orchestrator } = makeOrchestrator();\n\n // Send 17 messages → 34 history entries (17 user + 17 assistant)\n // After trimming: should be ≤30\n for (let i = 0; i < 17; i++) {\n await orchestrator.handleMessage(makeMessage({ content: `msg-${i}` }));\n }\n\n const history = orchestrator.getHistory();\n assert.ok(history.length <= 30, `History length ${history.length} exceeds 30`);\n // Should have trimmed from the front — oldest entries gone\n // 34 entries → trim 2 at a time until ≤30 → 30 entries (trimmed 4)\n assert.equal(history.length, 30);\n });\n });\n\n // ---- Error handling ----\n\n describe('error handling', () => {\n it('sends error message to Discord when LLM API throws', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.errorHandler('API rate limit exceeded'),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient });\n const msg = makeMessage({ content: 'hello' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(msg.sentMessages.length, 1);\n assert.ok(msg.sentMessages[0]!.includes('Something went wrong'));\n });\n\n it('appends error placeholder to history on LLM failure', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.errorHandler('Network error'),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient });\n await orchestrator.handleMessage(makeMessage({ content: 'fail' }));\n\n const history = orchestrator.getHistory();\n assert.equal(history.length, 2); // user + error assistant\n assert.equal(history[1]!.role, 'assistant');\n assert.equal(history[1]!.content, '[error — see logs]');\n });\n });\n\n // ---- stop() ----\n\n describe('stop()', () => {\n it('clears conversation history and nulls client', async () => {\n const { orchestrator } = makeOrchestrator();\n\n await orchestrator.handleMessage(makeMessage({ content: 'hello' }));\n assert.ok(orchestrator.getHistory().length > 0);\n\n orchestrator.stop();\n assert.equal(orchestrator.getHistory().length, 0);\n });\n });\n\n // ---- Tool execution direct tests ----\n\n describe('tool execution (via agent loop)', () => {\n it('list_projects returns empty message when no projects', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler('list_projects', {}, 'No projects'),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient, projects: [] });\n const msg = makeMessage({ content: 'list' });\n await orchestrator.handleMessage(msg);\n\n // The second create call receives the tool result\n assert.equal(mockClient.createCallCount, 2);\n });\n\n it('start_session with optional command passes through', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler(\n 'start_session',\n { projectPath: '/p', command: '/gsd quick fix tests' },\n 'Started',\n ),\n );\n const { orchestrator, sessionManager } = makeOrchestrator({ client: mockClient });\n const msg = makeMessage({ content: 'start with custom command' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(sessionManager.startSessionCalls.length, 1);\n assert.equal(sessionManager.startSessionCalls[0]!.command, '/gsd quick fix tests');\n });\n });\n\n});\n"]}
1
+ {"version":3,"file":"orchestrator.test.js","sourceRoot":"","sources":["../src/orchestrator.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tests for Orchestrator — LLM agent for #gsd-control channel.\n *\n * Uses a MockAnthropicClient that simulates messages.create() responses,\n * allowing tool execution and conversation flow testing without real API calls.\n */\n\nimport { describe, it, afterEach } from 'node:test';\nimport assert from 'node:assert/strict';\nimport { mkdtempSync, rmSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { randomUUID } from 'node:crypto';\nimport { Orchestrator, type OrchestratorConfig, type OrchestratorDeps, type DiscordMessageLike } from './orchestrator.js';\nimport { Logger } from './logger.js';\nimport type { ManagedSession, ProjectInfo, SessionStatus, CostAccumulator } from './types.js';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction tmpDir(): string {\n return mkdtempSync(join(tmpdir(), `orch-test-${randomUUID().slice(0, 8)}-`));\n}\n\nconst cleanupDirs: string[] = [];\nconst activeLoggers: Logger[] = [];\n\nasync function cleanupAll(): Promise<void> {\n // Close all loggers first so write streams flush before dirs are removed\n for (const logger of activeLoggers) {\n try { await logger.close(); } catch { /* ignore */ }\n }\n activeLoggers.length = 0;\n\n while (cleanupDirs.length) {\n const d = cleanupDirs.pop()!;\n if (existsSync(d)) rmSync(d, { recursive: true, force: true });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Mock Anthropic Client\n// ---------------------------------------------------------------------------\n\ninterface MockCreateParams {\n model: string;\n max_tokens: number;\n system: string;\n tools: unknown[];\n messages: unknown[];\n}\n\ntype CreateHandler = (params: MockCreateParams) => {\n stop_reason: string;\n content: Array<{ type: string; text?: string; id?: string; name?: string; input?: unknown }>;\n};\n\nclass MockAnthropicClient {\n public createCallCount = 0;\n public lastCreateParams: MockCreateParams | null = null;\n private createHandler: CreateHandler;\n\n constructor(handler?: CreateHandler) {\n this.createHandler = handler ?? MockAnthropicClient.defaultHandler;\n }\n\n /** Default handler: returns a simple text response */\n static defaultHandler(): ReturnType<CreateHandler> {\n return {\n stop_reason: 'end_turn',\n content: [{ type: 'text', text: 'Mock LLM response' }],\n };\n }\n\n /** Handler that simulates a tool call then end_turn */\n static toolThenTextHandler(toolName: string, toolInput: unknown, finalText: string): CreateHandler {\n let callCount = 0;\n return () => {\n callCount++;\n if (callCount === 1) {\n return {\n stop_reason: 'tool_use',\n content: [\n {\n type: 'tool_use',\n id: `toolu_${randomUUID().slice(0, 8)}`,\n name: toolName,\n input: toolInput,\n },\n ],\n };\n }\n return {\n stop_reason: 'end_turn',\n content: [{ type: 'text', text: finalText }],\n };\n };\n }\n\n /** Handler that throws an error */\n static errorHandler(message: string): CreateHandler {\n return () => {\n throw new Error(message);\n };\n }\n\n messages = {\n create: async (params: MockCreateParams) => {\n this.createCallCount++;\n this.lastCreateParams = params;\n return this.createHandler(params);\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Mock SessionManager\n// ---------------------------------------------------------------------------\n\nfunction makeMockSession(overrides: Partial<ManagedSession> = {}): ManagedSession {\n return {\n sessionId: overrides.sessionId ?? 'sess-123',\n projectDir: overrides.projectDir ?? '/home/user/project',\n projectName: overrides.projectName ?? 'my-project',\n status: overrides.status ?? ('running' as SessionStatus),\n client: {} as ManagedSession['client'],\n events: [],\n pendingBlocker: null,\n cost: overrides.cost ?? { totalCost: 0.1234, tokens: { input: 1000, output: 500, cacheRead: 0, cacheWrite: 0 } },\n startTime: overrides.startTime ?? Date.now() - 300_000, // 5 min ago\n ...overrides,\n };\n}\n\nclass MockSessionManager {\n public sessions: ManagedSession[] = [];\n public startSessionCalls: Array<{ projectDir: string; command?: string }> = [];\n public cancelSessionCalls: string[] = [];\n public getResultCalls: string[] = [];\n\n async startSession(opts: { projectDir: string; command?: string }): Promise<string> {\n this.startSessionCalls.push(opts);\n return 'sess-new-123';\n }\n\n getSession(sessionId: string): ManagedSession | undefined {\n return this.sessions.find((s) => s.sessionId === sessionId);\n }\n\n getAllSessions(): ManagedSession[] {\n return this.sessions;\n }\n\n async cancelSession(sessionId: string): Promise<void> {\n this.cancelSessionCalls.push(sessionId);\n }\n\n getResult(sessionId: string): Record<string, unknown> {\n const session = this.sessions.find((s) => s.sessionId === sessionId);\n if (!session) throw new Error(`Session not found: ${sessionId}`);\n return {\n sessionId: session.sessionId,\n projectDir: session.projectDir,\n projectName: session.projectName,\n status: session.status,\n durationMs: 300_000,\n cost: session.cost,\n recentEvents: [],\n pendingBlocker: null,\n error: null,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Mock ChannelManager (unused by orchestrator directly, but required by deps)\n// ---------------------------------------------------------------------------\n\nclass MockChannelManager {}\n\n// ---------------------------------------------------------------------------\n// Mock Discord Message\n// ---------------------------------------------------------------------------\n\nfunction makeMessage(overrides: Partial<{\n authorId: string;\n bot: boolean;\n channelId: string;\n content: string;\n}>): DiscordMessageLike & { sentMessages: string[] } {\n const sentMessages: string[] = [];\n return {\n author: {\n id: overrides.authorId ?? 'owner-123',\n bot: overrides.bot ?? false,\n },\n channelId: overrides.channelId ?? 'control-channel-1',\n content: overrides.content ?? 'hello',\n channel: {\n send: async (content: string) => {\n sentMessages.push(content);\n },\n sendTyping: async () => {},\n },\n sentMessages,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Test Setup Factory\n// ---------------------------------------------------------------------------\n\nfunction makeOrchestrator(opts?: {\n client?: MockAnthropicClient;\n sessions?: ManagedSession[];\n projects?: ProjectInfo[];\n}) {\n const dir = tmpDir();\n cleanupDirs.push(dir);\n const logPath = join(dir, 'test.log');\n const logger = new Logger({ filePath: logPath, level: 'debug' });\n activeLoggers.push(logger);\n\n const sessionManager = new MockSessionManager();\n if (opts?.sessions) sessionManager.sessions = opts.sessions;\n\n const projects: ProjectInfo[] = opts?.projects ?? [\n { name: 'alpha', path: '/home/user/alpha', markers: ['git', 'node', 'gsd'], lastModified: Date.now() },\n { name: 'bravo', path: '/home/user/bravo', markers: ['git', 'rust'], lastModified: Date.now() },\n ];\n\n const config: OrchestratorConfig = {\n model: 'claude-sonnet-4-20250514',\n max_tokens: 4096,\n control_channel_id: 'control-channel-1',\n };\n\n const deps: OrchestratorDeps = {\n sessionManager: sessionManager as unknown as OrchestratorDeps['sessionManager'],\n channelManager: new MockChannelManager() as unknown as OrchestratorDeps['channelManager'],\n scanProjects: async () => projects,\n config,\n logger,\n ownerId: 'owner-123',\n };\n\n const mockClient = opts?.client ?? new MockAnthropicClient();\n const orchestrator = new Orchestrator(deps, mockClient as unknown as import('@anthropic-ai/sdk').default);\n\n return { orchestrator, mockClient, sessionManager, logger, logPath };\n}\n\n// ---------------------------------------------------------------------------\n// Tests\n// ---------------------------------------------------------------------------\n\ndescribe('Orchestrator', () => {\n // Clean up after each test so logger streams are flushed before dirs removed\n afterEach(async () => {\n await cleanupAll();\n });\n\n // ---- Tool definitions ----\n\n describe('tool definitions', () => {\n it('passes 5 tools to the Anthropic API', async () => {\n const { orchestrator, mockClient } = makeOrchestrator();\n const msg = makeMessage({ content: 'what can you do?' });\n await orchestrator.handleMessage(msg);\n\n assert.ok(mockClient.lastCreateParams);\n const tools = mockClient.lastCreateParams.tools as Array<{ name: string }>;\n assert.equal(tools.length, 5);\n\n const names = tools.map((t) => t.name).sort();\n assert.deepEqual(names, [\n 'get_session_detail',\n 'get_status',\n 'list_projects',\n 'start_session',\n 'stop_session',\n ]);\n });\n });\n\n // ---- list_projects tool ----\n\n describe('list_projects tool', () => {\n it('returns project list from scanProjects', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler('list_projects', {}, 'Here are your projects'),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient });\n const msg = makeMessage({ content: 'list my projects' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(msg.sentMessages.length, 1);\n assert.equal(msg.sentMessages[0], 'Here are your projects');\n assert.equal(mockClient.createCallCount, 2);\n\n const finalMessages = mockClient.lastCreateParams?.messages as Array<{ role: string; content: unknown }>;\n const toolResultMessage = finalMessages.at(-1);\n assert.equal(toolResultMessage?.role, 'user');\n\n const toolResults = toolResultMessage?.content as Array<{\n type: string;\n tool_use_id: string;\n content: string;\n }>;\n assert.equal(toolResults.length, 1);\n assert.match(toolResults[0]!.tool_use_id, /^toolu_/);\n assert.equal(toolResults[0]!.type, 'tool_result');\n assert.equal(\n toolResults[0]!.content,\n JSON.stringify(\n [\n { name: 'alpha', path: '/home/user/alpha', markers: ['git', 'node', 'gsd'] },\n { name: 'bravo', path: '/home/user/bravo', markers: ['git', 'rust'] },\n ],\n null,\n 2,\n ),\n );\n });\n });\n\n // ---- start_session tool ----\n\n describe('start_session tool', () => {\n it('calls sessionManager.startSession and returns confirmation', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler(\n 'start_session',\n { projectPath: '/home/user/alpha' },\n 'Started session for alpha',\n ),\n );\n const { orchestrator, sessionManager } = makeOrchestrator({ client: mockClient });\n const msg = makeMessage({ content: 'start alpha' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(sessionManager.startSessionCalls.length, 1);\n assert.equal(sessionManager.startSessionCalls[0]!.projectDir, '/home/user/alpha');\n assert.equal(msg.sentMessages[0], 'Started session for alpha');\n });\n });\n\n // ---- get_status tool ----\n\n describe('get_status tool', () => {\n it('returns formatted session status', async () => {\n const session = makeMockSession({ projectName: 'alpha', status: 'running' as SessionStatus });\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler('get_status', {}, 'Status: alpha is running'),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient, sessions: [session] });\n const msg = makeMessage({ content: 'status' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(msg.sentMessages[0], 'Status: alpha is running');\n });\n\n it('handles empty session list', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler('get_status', {}, 'No sessions running'),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient, sessions: [] });\n const msg = makeMessage({ content: 'status' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(msg.sentMessages[0], 'No sessions running');\n });\n });\n\n // ---- stop_session tool ----\n\n describe('stop_session tool', () => {\n it('stops session matched by sessionId', async () => {\n const session = makeMockSession({ sessionId: 'sess-abc', projectName: 'alpha' });\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler(\n 'stop_session',\n { identifier: 'sess-abc' },\n 'Stopped alpha',\n ),\n );\n const { orchestrator, sessionManager } = makeOrchestrator({ client: mockClient, sessions: [session] });\n const msg = makeMessage({ content: 'stop sess-abc' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(sessionManager.cancelSessionCalls.length, 1);\n assert.equal(sessionManager.cancelSessionCalls[0], 'sess-abc');\n });\n\n it('fuzzy matches by project name', async () => {\n const session = makeMockSession({ sessionId: 'sess-xyz', projectName: 'my-big-project' });\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler(\n 'stop_session',\n { identifier: 'big-project' },\n 'Stopped my-big-project',\n ),\n );\n const { orchestrator, sessionManager } = makeOrchestrator({ client: mockClient, sessions: [session] });\n const msg = makeMessage({ content: 'stop big project' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(sessionManager.cancelSessionCalls.length, 1);\n assert.equal(sessionManager.cancelSessionCalls[0], 'sess-xyz');\n });\n\n it('returns not-found for unmatched identifier', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler(\n 'stop_session',\n { identifier: 'nonexistent' },\n 'No session found',\n ),\n );\n const { orchestrator, sessionManager } = makeOrchestrator({ client: mockClient, sessions: [] });\n const msg = makeMessage({ content: 'stop nonexistent' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(sessionManager.cancelSessionCalls.length, 0);\n });\n });\n\n // ---- get_session_detail tool ----\n\n describe('get_session_detail tool', () => {\n it('returns formatted session detail', async () => {\n const session = makeMockSession({ sessionId: 'sess-detail' });\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler(\n 'get_session_detail',\n { sessionId: 'sess-detail' },\n 'Session details for my-project',\n ),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient, sessions: [session] });\n const msg = makeMessage({ content: 'detail sess-detail' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(msg.sentMessages[0], 'Session details for my-project');\n });\n });\n\n // ---- Message routing / auth guards ----\n\n describe('handleMessage routing', () => {\n it('ignores bot messages', async () => {\n const { orchestrator, mockClient } = makeOrchestrator();\n const msg = makeMessage({ bot: true, content: 'hello from bot' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(mockClient.createCallCount, 0);\n assert.equal(msg.sentMessages.length, 0);\n });\n\n it('ignores non-owner messages', async () => {\n const { orchestrator, mockClient } = makeOrchestrator();\n const msg = makeMessage({ authorId: 'stranger-456', content: 'hack the planet' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(mockClient.createCallCount, 0);\n assert.equal(msg.sentMessages.length, 0);\n });\n\n it('ignores messages from non-control channels', async () => {\n const { orchestrator, mockClient } = makeOrchestrator();\n const msg = makeMessage({ channelId: 'random-channel', content: 'hello' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(mockClient.createCallCount, 0);\n assert.equal(msg.sentMessages.length, 0);\n });\n\n it('ignores empty message content', async () => {\n const { orchestrator, mockClient } = makeOrchestrator();\n const msg = makeMessage({ content: ' ' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(mockClient.createCallCount, 0);\n });\n\n it('routes valid message through LLM and sends response', async () => {\n const { orchestrator, mockClient } = makeOrchestrator();\n const msg = makeMessage({ content: 'hello orchestrator' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(mockClient.createCallCount, 1);\n assert.equal(msg.sentMessages.length, 1);\n assert.equal(msg.sentMessages[0], 'Mock LLM response');\n });\n });\n\n // ---- Conversation history ----\n\n describe('conversation history', () => {\n it('accumulates user and assistant entries', async () => {\n const { orchestrator } = makeOrchestrator();\n\n await orchestrator.handleMessage(makeMessage({ content: 'first' }));\n await orchestrator.handleMessage(makeMessage({ content: 'second' }));\n\n const history = orchestrator.getHistory();\n assert.equal(history.length, 4); // 2 user + 2 assistant\n assert.equal(history[0]!.role, 'user');\n assert.equal(history[1]!.role, 'assistant');\n assert.equal(history[2]!.role, 'user');\n assert.equal(history[3]!.role, 'assistant');\n });\n\n it('trims to MAX_HISTORY (30) by removing oldest pairs', async () => {\n const { orchestrator } = makeOrchestrator();\n\n // Send 17 messages → 34 history entries (17 user + 17 assistant)\n // After trimming: should be ≤30\n for (let i = 0; i < 17; i++) {\n await orchestrator.handleMessage(makeMessage({ content: `msg-${i}` }));\n }\n\n const history = orchestrator.getHistory();\n assert.ok(history.length <= 30, `History length ${history.length} exceeds 30`);\n // Should have trimmed from the front — oldest entries gone\n // 34 entries → trim 2 at a time until ≤30 → 30 entries (trimmed 4)\n assert.equal(history.length, 30);\n });\n });\n\n // ---- Error handling ----\n\n describe('error handling', () => {\n it('sends error message to Discord when LLM API throws', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.errorHandler('API rate limit exceeded'),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient });\n const msg = makeMessage({ content: 'hello' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(msg.sentMessages.length, 1);\n assert.ok(msg.sentMessages[0]!.includes('Something went wrong'));\n });\n\n it('appends error placeholder to history on LLM failure', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.errorHandler('Network error'),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient });\n await orchestrator.handleMessage(makeMessage({ content: 'fail' }));\n\n const history = orchestrator.getHistory();\n assert.equal(history.length, 2); // user + error assistant\n assert.equal(history[1]!.role, 'assistant');\n assert.equal(history[1]!.content, '[error — see logs]');\n });\n });\n\n // ---- stop() ----\n\n describe('stop()', () => {\n it('clears conversation history and nulls client', async () => {\n const { orchestrator } = makeOrchestrator();\n\n await orchestrator.handleMessage(makeMessage({ content: 'hello' }));\n assert.ok(orchestrator.getHistory().length > 0);\n\n orchestrator.stop();\n assert.equal(orchestrator.getHistory().length, 0);\n });\n });\n\n // ---- Tool execution direct tests ----\n\n describe('tool execution (via agent loop)', () => {\n it('list_projects returns empty message when no projects', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler('list_projects', {}, 'No projects'),\n );\n const { orchestrator } = makeOrchestrator({ client: mockClient, projects: [] });\n const msg = makeMessage({ content: 'list' });\n await orchestrator.handleMessage(msg);\n\n // The second create call receives the tool result\n assert.equal(mockClient.createCallCount, 2);\n });\n\n it('start_session with optional command passes through', async () => {\n const mockClient = new MockAnthropicClient(\n MockAnthropicClient.toolThenTextHandler(\n 'start_session',\n { projectPath: '/p', command: '/gsd quick fix tests' },\n 'Started',\n ),\n );\n const { orchestrator, sessionManager } = makeOrchestrator({ client: mockClient });\n const msg = makeMessage({ content: 'start with custom command' });\n await orchestrator.handleMessage(msg);\n\n assert.equal(sessionManager.startSessionCalls.length, 1);\n assert.equal(sessionManager.startSessionCalls[0]!.command, '/gsd quick fix tests');\n });\n });\n\n});\n"]}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengsd/daemon",
3
- "version": "1.5.0",
3
+ "version": "1.6.0-dev.aa7f94e8",
4
4
  "description": "GSD daemon — background process for project monitoring and Discord integration",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -27,13 +27,13 @@
27
27
  },
28
28
  "scripts": {
29
29
  "build": "node ../../scripts/clean-package-dist.cjs && tsc",
30
- "test": "node --test dist/daemon.test.js dist/cloud-config.test.js dist/cloud-runtime.test.js dist/local-tool-executor.test.js dist/mcp-cli.test.js dist/message-batcher.test.js"
30
+ "test": "node --test dist/daemon.test.js dist/cloud-config.test.js dist/cloud-runtime.test.js dist/device-flow.test.js dist/local-tool-executor.test.js dist/mcp-cli.test.js dist/message-batcher.test.js"
31
31
  },
32
32
  "dependencies": {
33
33
  "@anthropic-ai/sdk": "^0.52.0",
34
- "@opengsd/contracts": "^1.5.0",
35
- "@opengsd/mcp-server": "^1.5.0",
36
- "@opengsd/rpc-client": "^1.5.0",
34
+ "@opengsd/contracts": "^1.6.0-dev.aa7f94e8",
35
+ "@opengsd/mcp-server": "^1.6.0-dev.aa7f94e8",
36
+ "@opengsd/rpc-client": "^1.6.0-dev.aa7f94e8",
37
37
  "discord.js": "^14.25.1",
38
38
  "ws": "^8.20.0",
39
39
  "yaml": "^2.8.0",
@@ -894,15 +894,64 @@
894
894
  const isError = result?.isError || false;
895
895
  const statusClass = result ? (isError ? 'error' : 'success') : 'pending';
896
896
 
897
+ // This template runs as a standalone browser script in exported HTML,
898
+ // so it cannot import normalizeToolResultContent from @gsd/pi-ai.
899
+ // Keep these fallback semantics aligned with that helper.
900
+ const stringifyResultContent = (content) => {
901
+ try {
902
+ const value = JSON.stringify(content);
903
+ if (typeof value === 'string') return value;
904
+ } catch {
905
+ // Fall through to String(content). JSON.stringify can throw for cycles.
906
+ }
907
+
908
+ try {
909
+ return String(content);
910
+ } catch {
911
+ return '[unstringifiable tool result content]';
912
+ }
913
+ };
914
+
915
+ const serializableCacheControl = (block) => {
916
+ if (!block || typeof block !== 'object' || !('cache_control' in block)) return {};
917
+ try {
918
+ JSON.stringify(block.cache_control);
919
+ return { cache_control: block.cache_control };
920
+ } catch {
921
+ return {};
922
+ }
923
+ };
924
+
925
+ const normalizeResultContentBlock = (block) => {
926
+ if (typeof block === 'string') return { type: 'text', text: block };
927
+ if (block && typeof block === 'object') {
928
+ const cacheControl = serializableCacheControl(block);
929
+ if (block.type === 'text' && typeof block.text === 'string') return { type: 'text', text: block.text, ...cacheControl };
930
+ if (block.type === 'image' && typeof block.data === 'string' && typeof block.mimeType === 'string') {
931
+ return { type: 'image', data: block.data, mimeType: block.mimeType, ...cacheControl };
932
+ }
933
+ }
934
+ return { type: 'text', text: stringifyResultContent(block) };
935
+ };
936
+
937
+ const getResultContent = () => {
938
+ if (!result) return [];
939
+ if (Array.isArray(result.content)) {
940
+ const blocks = result.content.map(normalizeResultContentBlock);
941
+ return blocks.length > 0 ? blocks : [{ type: 'text', text: '' }];
942
+ }
943
+ if (typeof result.content === 'string') return [{ type: 'text', text: result.content }];
944
+ if (result.content == null) return [{ type: 'text', text: '' }];
945
+ return [{ type: 'text', text: stringifyResultContent(result.content) }];
946
+ };
947
+
897
948
  const getResultText = () => {
898
- if (!result) return '';
899
- const textBlocks = result.content.filter(c => c.type === 'text');
949
+ const textBlocks = getResultContent().filter(c => c.type === 'text');
900
950
  return textBlocks.map(c => c.text).join('\n');
901
951
  };
902
952
 
903
953
  const getResultImages = () => {
904
- if (!result) return [];
905
- return result.content.filter(c => c.type === 'image');
954
+ return getResultContent().filter(c => c.type === 'image');
906
955
  };
907
956
 
908
957
  const renderResultImages = () => {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsd/agent-core",
3
- "version": "1.5.0",
3
+ "version": "1.6.0-dev.aa7f94e8",
4
4
  "description": "GSD session orchestration layer on top of @gsd/pi-coding-agent",
5
5
  "type": "module",
6
6
  "gsd": {
@@ -25,9 +25,9 @@
25
25
  "test": "node --import ../../src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/*.test.ts src/**/*.test.ts"
26
26
  },
27
27
  "dependencies": {
28
- "@gsd/native": "^1.5.0",
29
- "@gsd/pi-agent-core": "^1.5.0",
30
- "@gsd/pi-ai": "^1.5.0",
31
- "@gsd/pi-coding-agent": "^1.5.0"
28
+ "@gsd/native": "^1.6.0-dev.aa7f94e8",
29
+ "@gsd/pi-agent-core": "^1.6.0-dev.aa7f94e8",
30
+ "@gsd/pi-ai": "^1.6.0-dev.aa7f94e8",
31
+ "@gsd/pi-coding-agent": "^1.6.0-dev.aa7f94e8"
32
32
  }
33
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"chat-controller.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/controllers/chat-controller.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAOnG,OAAO,EACN,4BAA4B,EAC5B,sBAAsB,EAGtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGN,yBAAyB,EACzB,6BAA6B,EAC7B,6BAA6B,EAE7B,oBAAoB,EACpB,MAAM,0BAA0B,CAAC;AAYlC,OAAO,EACN,4BAA4B,EAC5B,sBAAsB,EACtB,yBAAyB,EACzB,6BAA6B,EAC7B,6BAA6B,EAC7B,oBAAoB,GACpB,CAAC;AAyBF,uFAAuF;AACvF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,wBAAwB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAc7F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,wBAAwB,GAAG,IAAI,CAO1E;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACvE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,4BAA4B,EAAE,MAAM,GAAG,CAAC;IACxC,gBAAgB,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACxD,qBAAqB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACpD,2BAA2B,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IACvD,sBAAsB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,4BAA4B,EAAE,MAAM,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,wBAAwB,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CAChD,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAua7C"}
1
+ {"version":3,"file":"chat-controller.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/controllers/chat-controller.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAOnG,OAAO,EACN,4BAA4B,EAC5B,sBAAsB,EAGtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGN,yBAAyB,EACzB,6BAA6B,EAC7B,6BAA6B,EAE7B,oBAAoB,EACpB,MAAM,0BAA0B,CAAC;AAYlC,OAAO,EACN,4BAA4B,EAC5B,sBAAsB,EACtB,yBAAyB,EACzB,6BAA6B,EAC7B,6BAA6B,EAC7B,oBAAoB,GACpB,CAAC;AAyBF,uFAAuF;AACvF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,wBAAwB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAc7F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,wBAAwB,GAAG,IAAI,CAO1E;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACvE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,4BAA4B,EAAE,MAAM,GAAG,CAAC;IACxC,gBAAgB,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACxD,qBAAqB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAC;IACpD,2BAA2B,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,CAAC;IACvD,sBAAsB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,4BAA4B,EAAE,MAAM,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,uBAAuB,EAAE,MAAM,IAAI,CAAC;IACpC,wBAAwB,EAAE;QAAE,KAAK,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC;CAChD,EAAE,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAua7C"}
@@ -1,5 +1,6 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Interactive TUI chat stream controller.
3
+ import { normalizeToolResultContent } from "@gsd/pi-ai";
3
4
  import { Loader, Spacer, Text } from "@gsd/pi-tui";
4
5
  import { theme } from "@gsd/pi-coding-agent/theme/theme.js";
5
6
  import { AssistantMessageComponent } from "../components/assistant-message.js";
@@ -143,7 +144,7 @@ export async function handleAgentEvent(host, event) {
143
144
  if (ext) {
144
145
  externalToolResult = {
145
146
  toolCallId: tc.id,
146
- content: ext.content ?? [{ type: "text", text: "" }],
147
+ content: normalizeToolResultContent(ext.content),
147
148
  // Preserve undefined when MCP omits structuredContent — an empty
148
149
  // object is truthy and makes ask_user_questions renderResult show
149
150
  // "Cancelled" despite a successful text payload (#cc-elicitation).
@@ -159,7 +160,7 @@ export async function handleAgentEvent(host, event) {
159
160
  if (block?.id && ext) {
160
161
  externalToolResult = {
161
162
  toolCallId: block.id,
162
- content: ext.content ?? [{ type: "text", text: "" }],
163
+ content: normalizeToolResultContent(ext.content),
163
164
  details: ext.details,
164
165
  isError: ext.isError ?? false,
165
166
  };