@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
@@ -22,9 +22,13 @@ import { bannerLines, name as styledName, warn } from './cli-style.js';
22
22
  import { createJiti } from '@mariozechner/jiti';
23
23
  import { fileURLToPath } from 'node:url';
24
24
  import { generateWorktreeName } from './worktree-name-gen.js';
25
- import { existsSync } from 'node:fs';
26
25
  import { resolveBundledGsdExtensionModule } from './bundled-resource-path.js';
27
26
  import { getJitiWorkspaceAliases } from './jiti-workspace-aliases.js';
27
+ import { formatMultipleWorktreesPrompt, formatStatus } from './worktree-cli-format.js';
28
+ import { planWorktreeFlag } from './worktree-cli-plan.js';
29
+ import { createAndEnterWorktree } from './worktree-cli-create.js';
30
+ import { enterWorktreeSession } from './worktree-cli-session.js';
31
+ import { getWorktreeStatus as calculateWorktreeStatus, findWorktreesWithChanges, } from './worktree-cli-status.js';
28
32
  const jiti = createJiti(fileURLToPath(import.meta.url), {
29
33
  interopDefault: true,
30
34
  debug: false,
@@ -83,58 +87,18 @@ async function loadMergeModules() {
83
87
  }
84
88
  // ─── Status Helpers ─────────────────────────────────────────────────────────
85
89
  function getWorktreeStatus(ext, basePath, name, wtPath, branch) {
86
- const diff = ext.diffWorktreeAll(basePath, name, branch);
87
- const numstat = ext.diffWorktreeNumstat(basePath, name, branch);
88
- const filesChanged = diff.added.length + diff.modified.length + diff.removed.length;
89
- let linesAdded = 0;
90
- let linesRemoved = 0;
91
- for (const s of numstat) {
92
- linesAdded += s.added;
93
- linesRemoved += s.removed;
94
- }
95
- let uncommitted = false;
96
- try {
97
- uncommitted = existsSync(wtPath) && ext.nativeHasChanges(wtPath);
98
- }
99
- catch (error) {
100
- logDebugFailure('native worktree dirty check', error);
101
- }
102
- let commits = 0;
103
- try {
104
- const mainBranch = ext.nativeDetectMainBranch(basePath);
105
- commits = ext.nativeCommitCountBetween(basePath, mainBranch, branch);
106
- }
107
- catch (error) {
108
- logDebugFailure('native commit count', error);
109
- }
90
+ return calculateWorktreeStatus(worktreeStatusDependencies(ext), basePath, name, wtPath, branch);
91
+ }
92
+ function worktreeStatusDependencies(ext) {
110
93
  return {
111
- name,
112
- path: wtPath,
113
- branch,
114
- exists: existsSync(wtPath),
115
- filesChanged,
116
- linesAdded,
117
- linesRemoved,
118
- uncommitted,
119
- commits,
94
+ diffWorktreeAll: ext.diffWorktreeAll,
95
+ diffWorktreeNumstat: ext.diffWorktreeNumstat,
96
+ nativeHasChanges: ext.nativeHasChanges,
97
+ nativeDetectMainBranch: ext.nativeDetectMainBranch,
98
+ nativeCommitCountBetween: ext.nativeCommitCountBetween,
99
+ onDebugFailure: logDebugFailure,
120
100
  };
121
101
  }
122
- // ─── Formatters ─────────────────────────────────────────────────────────────
123
- function formatStatus(s) {
124
- const lines = [];
125
- const badge = s.uncommitted
126
- ? chalk.yellow(' (uncommitted)')
127
- : s.filesChanged > 0
128
- ? chalk.cyan(' (unmerged)')
129
- : chalk.green(' (clean)');
130
- lines.push(` ${chalk.bold.cyan(s.name)}${badge}`);
131
- lines.push(` ${chalk.dim('branch')} ${chalk.magenta(s.branch)}`);
132
- lines.push(` ${chalk.dim('path')} ${chalk.dim(s.path)}`);
133
- if (s.filesChanged > 0) {
134
- lines.push(` ${chalk.dim('diff')} ${s.filesChanged} files, ${chalk.green(`+${s.linesAdded}`)} ${chalk.red(`-${s.linesRemoved}`)}, ${s.commits} commit${s.commits === 1 ? '' : 's'}`);
135
- }
136
- return lines.join('\n');
137
- }
138
102
  // ─── Subcommand: list ───────────────────────────────────────────────────────
139
103
  async function handleList(basePath) {
140
104
  const ext = await loadExtensionModules();
@@ -272,16 +236,7 @@ async function handleStatusBanner(basePath) {
272
236
  const worktrees = ext.listWorktrees(basePath);
273
237
  if (worktrees.length === 0)
274
238
  return;
275
- const withChanges = worktrees.filter(wt => {
276
- try {
277
- const diff = ext.diffWorktreeAll(basePath, wt.name, wt.branch);
278
- return diff.added.length + diff.modified.length + diff.removed.length > 0;
279
- }
280
- catch (error) {
281
- logDebugFailure(`status scan for ${wt.name}`, error);
282
- return false;
283
- }
284
- });
239
+ const withChanges = findWorktreesWithChanges(worktreeStatusDependencies(ext), basePath, worktrees, 'status scan');
285
240
  if (withChanges.length === 0)
286
241
  return;
287
242
  const names = withChanges.map(w => styledName(w.name)).join(', ');
@@ -291,74 +246,25 @@ async function handleStatusBanner(basePath) {
291
246
  async function handleWorktreeFlag(worktreeFlag) {
292
247
  const ext = await loadExtensionModules();
293
248
  const basePath = ext.resolveWorktreeProjectRoot(process.cwd());
294
- // gsd -w (no name) — resume most recent worktree with changes, or create new
295
- if (worktreeFlag === true) {
296
- const existing = ext.listWorktrees(basePath);
297
- const withChanges = existing.filter(wt => {
298
- try {
299
- const diff = ext.diffWorktreeAll(basePath, wt.name, wt.branch);
300
- return diff.added.length + diff.modified.length + diff.removed.length > 0;
301
- }
302
- catch (error) {
303
- logDebugFailure(`worktree -w scan for ${wt.name}`, error);
304
- return false;
305
- }
306
- });
307
- if (withChanges.length === 1) {
308
- // Single active worktree — resume it
309
- const wt = withChanges[0];
310
- process.chdir(wt.path);
311
- process.env.GSD_CLI_WORKTREE = wt.name;
312
- process.env.GSD_CLI_WORKTREE_BASE = basePath;
313
- process.stderr.write(chalk.green(`✓ Resumed worktree ${chalk.bold(wt.name)}\n`));
314
- process.stderr.write(chalk.dim(` path ${wt.path}\n`));
315
- process.stderr.write(chalk.dim(` branch ${wt.branch}\n\n`));
316
- return;
317
- }
318
- if (withChanges.length > 1) {
319
- // Multiple active worktrees — show them and ask user to pick
320
- process.stderr.write(chalk.yellow(`${withChanges.length} worktrees have unmerged changes:\n\n`));
321
- for (const wt of withChanges) {
322
- const status = getWorktreeStatus(ext, basePath, wt.name, wt.path, wt.branch);
323
- process.stderr.write(formatStatus(status) + '\n\n');
324
- }
325
- process.stderr.write(chalk.dim('Specify which one: gsd -w <name>\n'));
326
- process.exit(0);
327
- }
328
- // No active worktrees — create a new one
329
- const name = generateWorktreeName();
330
- await createAndEnter(ext, basePath, name);
331
- return;
332
- }
333
- // gsd -w <name> — create or resume named worktree
334
- const name = worktreeFlag;
335
249
  const existing = ext.listWorktrees(basePath);
336
- const found = existing.find(wt => wt.name === name);
337
- if (found) {
338
- process.chdir(found.path);
339
- process.env.GSD_CLI_WORKTREE = name;
340
- process.env.GSD_CLI_WORKTREE_BASE = basePath;
341
- process.stderr.write(chalk.green(`✓ Resumed worktree ${chalk.bold(name)}\n`));
342
- process.stderr.write(chalk.dim(` path ${found.path}\n`));
343
- process.stderr.write(chalk.dim(` branch ${found.branch}\n\n`));
250
+ const withChanges = worktreeFlag === true
251
+ ? findWorktreesWithChanges(worktreeStatusDependencies(ext), basePath, existing, 'worktree -w scan')
252
+ : [];
253
+ const plan = planWorktreeFlag(worktreeFlag, existing, withChanges, generateWorktreeName);
254
+ if (plan.action === 'resume') {
255
+ enterWorktreeSession(plan.worktree, basePath, 'Resumed');
256
+ return;
344
257
  }
345
- else {
346
- await createAndEnter(ext, basePath, name);
258
+ if (plan.action === 'show-multiple') {
259
+ const statuses = plan.worktrees.map((wt) => getWorktreeStatus(ext, basePath, wt.name, wt.path, wt.branch));
260
+ process.stderr.write(formatMultipleWorktreesPrompt(statuses));
261
+ process.exit(0);
347
262
  }
263
+ await createAndEnter(ext, basePath, plan.name);
348
264
  }
349
265
  async function createAndEnter(ext, basePath, name) {
350
266
  try {
351
- const info = ext.createWorktree(basePath, name);
352
- const hookError = ext.runWorktreePostCreateHook(basePath, info.path);
353
- if (hookError) {
354
- process.stderr.write(chalk.yellow(`[gsd] ${hookError}\n`));
355
- }
356
- process.chdir(info.path);
357
- process.env.GSD_CLI_WORKTREE = name;
358
- process.env.GSD_CLI_WORKTREE_BASE = basePath;
359
- process.stderr.write(chalk.green(`✓ Created worktree ${chalk.bold(name)}\n`));
360
- process.stderr.write(chalk.dim(` path ${info.path}\n`));
361
- process.stderr.write(chalk.dim(` branch ${info.branch}\n\n`));
267
+ createAndEnterWorktree(ext, basePath, name);
362
268
  }
363
269
  catch (err) {
364
270
  const msg = err instanceof Error ? err.message : String(err);
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import json
6
6
  import os
7
+ import shutil
7
8
  import subprocess
8
9
  import threading
9
10
  import time
@@ -62,7 +63,12 @@ class GsdMcpClient:
62
63
 
63
64
  def _env(self) -> dict[str, str]:
64
65
  env = os.environ.copy()
65
- env["GSD_CLI_PATH"] = self._config.cli_path
66
+ # Resolve cli_path to an absolute path so the MCP server's
67
+ # resolveCLIPath() does not resolve a bare command name (e.g. "gsd")
68
+ # against the project directory, producing a non-existent
69
+ # project-relative path that hangs gsd_execute until timeout.
70
+ resolved = shutil.which(self._config.cli_path) or self._config.cli_path
71
+ env["GSD_CLI_PATH"] = resolved
66
72
  return env
67
73
 
68
74
  def ensure_version(self) -> None:
@@ -134,9 +140,11 @@ class GsdMcpClient:
134
140
  def _send(self, payload: dict[str, Any], *, project_dir: str | None = None) -> None:
135
141
  proc = self._ensure_process(project_dir)
136
142
  assert proc.stdin is not None
137
- body = json.dumps(payload).encode("utf-8")
138
- header = f"Content-Length: {len(body)}\r\n\r\n".encode("ascii")
139
- proc.stdin.write(header + body)
143
+ # gsd-mcp-server uses the @modelcontextprotocol/sdk stdio transport,
144
+ # which is newline-delimited JSON (NDJSON), not the Content-Length
145
+ # framing from the LSP-style MCP spec. Emit one JSON object per line.
146
+ data = json.dumps(payload, ensure_ascii=False).encode("utf-8") + b"\n"
147
+ proc.stdin.write(data)
140
148
  proc.stdin.flush()
141
149
 
142
150
  def _read_stdout_chunk(self, deadline: float) -> None:
@@ -179,42 +187,23 @@ class GsdMcpClient:
179
187
  f"{self._config.mcp_read_timeout_seconds:g}s"
180
188
  )
181
189
 
182
- def _read_header(self, deadline: float) -> bytes:
190
+ def _read_line(self, deadline: float) -> bytes:
183
191
  while True:
184
- crlf_idx = self._stdout_buffer.find(b"\r\n\r\n")
185
- lf_idx = self._stdout_buffer.find(b"\n\n")
186
- candidates = [
187
- (idx, sep_len)
188
- for idx, sep_len in ((crlf_idx, 4), (lf_idx, 2))
189
- if idx >= 0
190
- ]
191
- if candidates:
192
- idx, sep_len = min(candidates)
193
- header = self._stdout_buffer[:idx]
194
- self._stdout_buffer = self._stdout_buffer[idx + sep_len :]
195
- return header
192
+ idx = self._stdout_buffer.find(b"\n")
193
+ if idx >= 0:
194
+ raw = self._stdout_buffer[:idx]
195
+ self._stdout_buffer = self._stdout_buffer[idx + 1 :]
196
+ return raw.rstrip(b"\r")
196
197
  self._read_stdout_chunk(deadline)
197
198
 
198
- def _read_exact(self, length: int, deadline: float) -> bytes:
199
- while len(self._stdout_buffer) < length:
200
- self._read_stdout_chunk(deadline)
201
- body = self._stdout_buffer[:length]
202
- self._stdout_buffer = self._stdout_buffer[length:]
203
- return body
204
-
205
199
  def _read_message(self) -> dict[str, Any]:
206
200
  deadline = time.monotonic() + self._config.mcp_read_timeout_seconds
207
- header = self._read_header(deadline)
208
- headers: dict[str, str] = {}
209
- for raw_line in header.splitlines():
210
- decoded = raw_line.decode("utf-8").strip()
211
- if not decoded:
212
- continue
213
- key, _, val = decoded.partition(":")
214
- headers[key.strip().lower()] = val.strip()
215
- length = int(headers.get("content-length", "0"))
216
- body = self._read_exact(length, deadline)
217
- return json.loads(body.decode("utf-8"))
201
+ # gsd-mcp-server emits newline-delimited JSON (NDJSON); each line is a
202
+ # complete JSON-RPC message. Skip blank keep-alive lines.
203
+ while True:
204
+ line = self._read_line(deadline)
205
+ if line.strip():
206
+ return json.loads(line.decode("utf-8"))
218
207
 
219
208
  def _initialize(self) -> None:
220
209
  self._request_id += 1
@@ -226,7 +215,7 @@ class GsdMcpClient:
226
215
  "params": {
227
216
  "protocolVersion": "2024-11-05",
228
217
  "capabilities": {},
229
- "clientInfo": {"name": "open-gsd-hermes", "version": "1.2.0"},
218
+ "clientInfo": {"name": "open-gsd-hermes", "version": "1.6.0"},
230
219
  },
231
220
  }
232
221
  )
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "open-gsd-hermes"
7
- version = "1.2.0"
7
+ version = "1.6.0"
8
8
  description = "Hermes Agent plugin — GSD structured delivery engine integration"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -31,7 +31,7 @@ def test_read_message_times_out_waiting_for_headers() -> None:
31
31
  proc.kill()
32
32
 
33
33
 
34
- def test_read_message_times_out_waiting_for_body() -> None:
34
+ def test_read_message_times_out_waiting_for_newline() -> None:
35
35
  client = GsdMcpClient(GsdConfig(mcp_read_timeout_seconds=0.05))
36
36
  proc = subprocess.Popen(
37
37
  [
@@ -39,7 +39,7 @@ def test_read_message_times_out_waiting_for_body() -> None:
39
39
  "-c",
40
40
  (
41
41
  "import sys, time; "
42
- "sys.stdout.buffer.write(b'Content-Length: 2\\r\\n\\r\\n{'); "
42
+ "sys.stdout.buffer.write(b'{\"jsonrpc\":\"2.0\"'); "
43
43
  "sys.stdout.flush(); "
44
44
  "time.sleep(10)"
45
45
  ),
@@ -59,7 +59,7 @@ def test_read_message_times_out_waiting_for_body() -> None:
59
59
  proc.kill()
60
60
 
61
61
 
62
- def test_read_message_fails_without_respawning_when_stdout_closes_mid_body(
62
+ def test_read_message_fails_without_respawning_when_stdout_closes_mid_line(
63
63
  tmp_path,
64
64
  ) -> None:
65
65
  client = GsdMcpClient(GsdConfig(mcp_read_timeout_seconds=1))
@@ -69,7 +69,7 @@ def test_read_message_fails_without_respawning_when_stdout_closes_mid_body(
69
69
  "-c",
70
70
  (
71
71
  "import sys; "
72
- "sys.stdout.buffer.write(b'Content-Length: 20\\r\\n\\r\\n{'); "
72
+ "sys.stdout.buffer.write(b'{\"jsonrpc\":\"2.0\"'); "
73
73
  "sys.stdout.flush()"
74
74
  ),
75
75
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengsd/gsd-pi",
3
- "version": "1.5.0",
3
+ "version": "1.6.0-dev.aa7f94e8",
4
4
  "description": "GSD Pi local-first coding agent",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -210,11 +210,11 @@
210
210
  },
211
211
  "optionalDependencies": {
212
212
  "@mariozechner/clipboard": "0.3.6",
213
- "@opengsd/engine-darwin-arm64": "1.5.0",
214
- "@opengsd/engine-darwin-x64": "1.5.0",
215
- "@opengsd/engine-linux-arm64-gnu": "1.5.0",
216
- "@opengsd/engine-linux-x64-gnu": "1.5.0",
217
- "@opengsd/engine-win32-x64-msvc": "1.5.0",
213
+ "@opengsd/engine-darwin-arm64": "1.6.0",
214
+ "@opengsd/engine-darwin-x64": "1.6.0",
215
+ "@opengsd/engine-linux-arm64-gnu": "1.6.0",
216
+ "@opengsd/engine-linux-x64-gnu": "1.6.0",
217
+ "@opengsd/engine-win32-x64-msvc": "1.6.0",
218
218
  "fsevents": "~2.3.3",
219
219
  "koffi": "^2.9.0"
220
220
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengsd/cloud-mcp-gateway",
3
- "version": "1.5.0",
3
+ "version": "1.6.0-dev.aa7f94e8",
4
4
  "description": "Cloud MCP gateway for brokering remote MCP clients to local GSD runtimes",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,7 +29,7 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@modelcontextprotocol/sdk": "^1.27.1",
32
- "@opengsd/mcp-server": "^1.5.0",
32
+ "@opengsd/mcp-server": "^1.6.0-dev.aa7f94e8",
33
33
  "ws": "^8.20.0",
34
34
  "zod": "^4.0.0"
35
35
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengsd/contracts",
3
- "version": "1.5.0",
3
+ "version": "1.6.0-dev.aa7f94e8",
4
4
  "description": "Shared public contracts for GSD workspace boundaries",
5
5
  "license": "MIT",
6
6
  "gsd": {
@@ -1,4 +1,4 @@
1
- export declare const CLOUD_COMMAND_USAGE = "Commands:\n status [--config <path>]\n pair --gateway <url> --code <code> [--runtime-name <name>] [--config <path>]\n connect [--config <path>] [--verbose]\n disconnect [--config <path>]\n";
1
+ export declare const CLOUD_COMMAND_USAGE = "Commands:\n login --gateway <url> [--runtime-name <name>] [--config <path>]\n status [--config <path>]\n pair --gateway <url> --code <code> [--runtime-name <name>] [--config <path>]\n connect [--config <path>] [--verbose]\n disconnect [--config <path>]\n";
2
2
  export declare function handleCloudRuntimeCommand(argv: string[], opts: {
3
3
  binaryName: string;
4
4
  nestedCommandName?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-cli.d.ts","sourceRoot":"","sources":["../src/cloud-cli.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,mBAAmB,qMAK/B,CAAC;AAEF,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,IAAI,CAAC,CA0EhB;AAED,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,CAe9F"}
1
+ {"version":3,"file":"cloud-cli.d.ts","sourceRoot":"","sources":["../src/cloud-cli.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,mBAAmB,wQAM/B,CAAC;AAEF,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,IAAI,CAAC,CAuGhB;AAED,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,MAAM,CAyB9F"}
@@ -3,7 +3,9 @@ import { resolveConfigPath, loadConfig } from "./config.js";
3
3
  import { Logger } from "./logger.js";
4
4
  import { Daemon } from "./daemon.js";
5
5
  import { clearCloudConfig, exchangePairingCode, redactedCloudStatus, saveCloudConfig } from "./cloud-config.js";
6
+ import { runDeviceFlow } from "./device-flow.js";
6
7
  export const CLOUD_COMMAND_USAGE = `Commands:
8
+ login --gateway <url> [--runtime-name <name>] [--config <path>]
7
9
  status [--config <path>]
8
10
  pair --gateway <url> --code <code> [--runtime-name <name>] [--config <path>]
9
11
  connect [--config <path>] [--verbose]
@@ -41,6 +43,34 @@ export async function handleCloudRuntimeCommand(argv, opts) {
41
43
  process.stdout.write(`${opts.binaryName}: cloud runtime disconnected locally.\n`);
42
44
  return;
43
45
  }
46
+ if (command === "login") {
47
+ if (!values.gateway) {
48
+ throw new Error("login requires --gateway");
49
+ }
50
+ const runtimeName = values["runtime-name"];
51
+ const { deviceToken, runtimeId, gatewayUrl } = await runDeviceFlow({
52
+ gatewayUrl: values.gateway,
53
+ configPath,
54
+ runtimeName,
55
+ binaryName: opts.binaryName,
56
+ });
57
+ const config = saveCloudConfig(configPath, {
58
+ gateway_url: gatewayUrl,
59
+ device_token: deviceToken,
60
+ runtime_id: runtimeId,
61
+ ...(runtimeName ? { runtime_name: runtimeName } : {}),
62
+ enabled: true,
63
+ });
64
+ process.stdout.write(`${opts.binaryName}: cloud runtime ${runtimeId} paired — connecting...\n`);
65
+ const logger = new Logger({
66
+ filePath: config.log.file,
67
+ level: config.log.level,
68
+ verbose: values.verbose,
69
+ });
70
+ const daemon = new Daemon(config, logger);
71
+ await daemon.start();
72
+ return;
73
+ }
44
74
  if (command === "pair") {
45
75
  if (!values.gateway || !values.code) {
46
76
  throw new Error("pair requires --gateway and --code");
@@ -79,15 +109,25 @@ export async function handleCloudRuntimeCommand(argv, opts) {
79
109
  }
80
110
  export function formatCloudRuntimeUsage(binaryName, nestedCommandName) {
81
111
  const prefix = nestedCommandName ? `${binaryName} ${nestedCommandName}` : binaryName;
82
- return `Usage: ${prefix} status [--config <path>]
112
+ return `Usage: ${prefix} login --gateway <url> [--runtime-name <name>] [--config <path>]
113
+ ${prefix} status [--config <path>]
83
114
  ${prefix} pair --gateway <url> --code <code> [--runtime-name <name>] [--config <path>]
84
115
  ${prefix} connect [--config <path>] [--verbose]
85
116
  ${prefix} disconnect [--config <path>]
86
117
 
118
+ Commands:
119
+ login (Recommended) Browser-based pairing — opens approval URL in terminal,
120
+ polls for authorization, then auto-connects the daemon. Use this instead
121
+ of pair + connect for interactive environments.
122
+ status Show current cloud runtime configuration and connection status.
123
+ pair Exchange a pairing code for a device token (headless/CI environments).
124
+ connect Start the daemon using a previously paired device token.
125
+ disconnect Remove cloud runtime configuration from the local config file.
126
+
87
127
  Options:
88
128
  --config <path> Path to YAML config file (default: ~/.gsd/daemon.yaml)
89
129
  --gateway <url> Cloud MCP Gateway URL
90
- --code <code> Pairing code from the Cloud MCP Gateway
130
+ --code <code> Pairing code from the Cloud MCP Gateway (pair only)
91
131
  --runtime-name <name> Friendly name for this Local GSD Runtime
92
132
  --verbose Print log entries to stderr in addition to the log file
93
133
  --help Show this help message and exit
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-cli.js","sourceRoot":"","sources":["../src/cloud-cli.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseArgs } from \"node:util\";\nimport { resolveConfigPath, loadConfig } from \"./config.js\";\nimport { Logger } from \"./logger.js\";\nimport { Daemon } from \"./daemon.js\";\nimport { clearCloudConfig, exchangePairingCode, redactedCloudStatus, saveCloudConfig } from \"./cloud-config.js\";\n\nexport const CLOUD_COMMAND_USAGE = `Commands:\n status [--config <path>]\n pair --gateway <url> --code <code> [--runtime-name <name>] [--config <path>]\n connect [--config <path>] [--verbose]\n disconnect [--config <path>]\n`;\n\nexport async function handleCloudRuntimeCommand(argv: string[], opts: {\n binaryName: string;\n nestedCommandName?: string;\n}): Promise<void> {\n if (argv[0] === \"--help\" || argv[0] === \"-h\") {\n process.stdout.write(formatCloudRuntimeUsage(opts.binaryName, opts.nestedCommandName));\n process.exit(0);\n }\n\n const command = argv[0];\n const { values } = parseArgs({\n args: argv.slice(1),\n options: {\n config: { type: \"string\", short: \"c\" },\n gateway: { type: \"string\" },\n code: { type: \"string\" },\n \"runtime-name\": { type: \"string\" },\n verbose: { type: \"boolean\", short: \"v\", default: false },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n strict: true,\n });\n\n if (values.help || !command) {\n process.stdout.write(formatCloudRuntimeUsage(opts.binaryName, opts.nestedCommandName));\n process.exit(0);\n }\n\n const configPath = resolveConfigPath(values.config);\n if (command === \"status\") {\n process.stdout.write(`${JSON.stringify(redactedCloudStatus(loadConfig(configPath)), null, 2)}\\n`);\n return;\n }\n\n if (command === \"disconnect\") {\n clearCloudConfig(configPath);\n process.stdout.write(`${opts.binaryName}: cloud runtime disconnected locally.\\n`);\n return;\n }\n\n if (command === \"pair\") {\n if (!values.gateway || !values.code) {\n throw new Error(\"pair requires --gateway and --code\");\n }\n const runtimeName = values[\"runtime-name\"];\n const result = await exchangePairingCode({\n gatewayUrl: values.gateway,\n code: values.code,\n runtimeName,\n });\n saveCloudConfig(configPath, {\n gateway_url: values.gateway,\n device_token: result.deviceToken,\n runtime_id: result.runtimeId,\n ...(runtimeName ? { runtime_name: runtimeName } : {}),\n enabled: true,\n });\n process.stdout.write(`${opts.binaryName}: paired cloud runtime ${result.runtimeId}.\\n`);\n return;\n }\n\n if (command === \"connect\") {\n const config = loadConfig(configPath);\n if (!config.cloud?.device_token || !config.cloud.runtime_id) {\n throw new Error(\"cloud runtime is not paired; run `pair` first\");\n }\n const logger = new Logger({\n filePath: config.log.file,\n level: config.log.level,\n verbose: values.verbose,\n });\n const daemon = new Daemon(config, logger);\n await daemon.start();\n return;\n }\n\n throw new Error(`Unknown cloud runtime command: ${command}`);\n}\n\nexport function formatCloudRuntimeUsage(binaryName: string, nestedCommandName?: string): string {\n const prefix = nestedCommandName ? `${binaryName} ${nestedCommandName}` : binaryName;\n return `Usage: ${prefix} status [--config <path>]\n ${prefix} pair --gateway <url> --code <code> [--runtime-name <name>] [--config <path>]\n ${prefix} connect [--config <path>] [--verbose]\n ${prefix} disconnect [--config <path>]\n\nOptions:\n --config <path> Path to YAML config file (default: ~/.gsd/daemon.yaml)\n --gateway <url> Cloud MCP Gateway URL\n --code <code> Pairing code from the Cloud MCP Gateway\n --runtime-name <name> Friendly name for this Local GSD Runtime\n --verbose Print log entries to stderr in addition to the log file\n --help Show this help message and exit\n`;\n}\n"]}
1
+ {"version":3,"file":"cloud-cli.js","sourceRoot":"","sources":["../src/cloud-cli.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseArgs } from \"node:util\";\nimport { resolveConfigPath, loadConfig } from \"./config.js\";\nimport { Logger } from \"./logger.js\";\nimport { Daemon } from \"./daemon.js\";\nimport { clearCloudConfig, exchangePairingCode, redactedCloudStatus, saveCloudConfig } from \"./cloud-config.js\";\nimport { runDeviceFlow } from \"./device-flow.js\";\n\nexport const CLOUD_COMMAND_USAGE = `Commands:\n login --gateway <url> [--runtime-name <name>] [--config <path>]\n status [--config <path>]\n pair --gateway <url> --code <code> [--runtime-name <name>] [--config <path>]\n connect [--config <path>] [--verbose]\n disconnect [--config <path>]\n`;\n\nexport async function handleCloudRuntimeCommand(argv: string[], opts: {\n binaryName: string;\n nestedCommandName?: string;\n}): Promise<void> {\n if (argv[0] === \"--help\" || argv[0] === \"-h\") {\n process.stdout.write(formatCloudRuntimeUsage(opts.binaryName, opts.nestedCommandName));\n process.exit(0);\n }\n\n const command = argv[0];\n const { values } = parseArgs({\n args: argv.slice(1),\n options: {\n config: { type: \"string\", short: \"c\" },\n gateway: { type: \"string\" },\n code: { type: \"string\" },\n \"runtime-name\": { type: \"string\" },\n verbose: { type: \"boolean\", short: \"v\", default: false },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n strict: true,\n });\n\n if (values.help || !command) {\n process.stdout.write(formatCloudRuntimeUsage(opts.binaryName, opts.nestedCommandName));\n process.exit(0);\n }\n\n const configPath = resolveConfigPath(values.config);\n if (command === \"status\") {\n process.stdout.write(`${JSON.stringify(redactedCloudStatus(loadConfig(configPath)), null, 2)}\\n`);\n return;\n }\n\n if (command === \"disconnect\") {\n clearCloudConfig(configPath);\n process.stdout.write(`${opts.binaryName}: cloud runtime disconnected locally.\\n`);\n return;\n }\n\n if (command === \"login\") {\n if (!values.gateway) {\n throw new Error(\"login requires --gateway\");\n }\n const runtimeName = values[\"runtime-name\"];\n const { deviceToken, runtimeId, gatewayUrl } = await runDeviceFlow({\n gatewayUrl: values.gateway,\n configPath,\n runtimeName,\n binaryName: opts.binaryName,\n });\n const config = saveCloudConfig(configPath, {\n gateway_url: gatewayUrl,\n device_token: deviceToken,\n runtime_id: runtimeId,\n ...(runtimeName ? { runtime_name: runtimeName } : {}),\n enabled: true,\n });\n process.stdout.write(`${opts.binaryName}: cloud runtime ${runtimeId} paired — connecting...\\n`);\n const logger = new Logger({\n filePath: config.log.file,\n level: config.log.level,\n verbose: values.verbose,\n });\n const daemon = new Daemon(config, logger);\n await daemon.start();\n return;\n }\n\n if (command === \"pair\") {\n if (!values.gateway || !values.code) {\n throw new Error(\"pair requires --gateway and --code\");\n }\n const runtimeName = values[\"runtime-name\"];\n const result = await exchangePairingCode({\n gatewayUrl: values.gateway,\n code: values.code,\n runtimeName,\n });\n saveCloudConfig(configPath, {\n gateway_url: values.gateway,\n device_token: result.deviceToken,\n runtime_id: result.runtimeId,\n ...(runtimeName ? { runtime_name: runtimeName } : {}),\n enabled: true,\n });\n process.stdout.write(`${opts.binaryName}: paired cloud runtime ${result.runtimeId}.\\n`);\n return;\n }\n\n if (command === \"connect\") {\n const config = loadConfig(configPath);\n if (!config.cloud?.device_token || !config.cloud.runtime_id) {\n throw new Error(\"cloud runtime is not paired; run `pair` first\");\n }\n const logger = new Logger({\n filePath: config.log.file,\n level: config.log.level,\n verbose: values.verbose,\n });\n const daemon = new Daemon(config, logger);\n await daemon.start();\n return;\n }\n\n throw new Error(`Unknown cloud runtime command: ${command}`);\n}\n\nexport function formatCloudRuntimeUsage(binaryName: string, nestedCommandName?: string): string {\n const prefix = nestedCommandName ? `${binaryName} ${nestedCommandName}` : binaryName;\n return `Usage: ${prefix} login --gateway <url> [--runtime-name <name>] [--config <path>]\n ${prefix} status [--config <path>]\n ${prefix} pair --gateway <url> --code <code> [--runtime-name <name>] [--config <path>]\n ${prefix} connect [--config <path>] [--verbose]\n ${prefix} disconnect [--config <path>]\n\nCommands:\n login (Recommended) Browser-based pairing — opens approval URL in terminal,\n polls for authorization, then auto-connects the daemon. Use this instead\n of pair + connect for interactive environments.\n status Show current cloud runtime configuration and connection status.\n pair Exchange a pairing code for a device token (headless/CI environments).\n connect Start the daemon using a previously paired device token.\n disconnect Remove cloud runtime configuration from the local config file.\n\nOptions:\n --config <path> Path to YAML config file (default: ~/.gsd/daemon.yaml)\n --gateway <url> Cloud MCP Gateway URL\n --code <code> Pairing code from the Cloud MCP Gateway (pair only)\n --runtime-name <name> Friendly name for this Local GSD Runtime\n --verbose Print log entries to stderr in addition to the log file\n --help Show this help message and exit\n`;\n}\n"]}
@@ -15,4 +15,5 @@ export declare function clearCloudConfig(configPath: string): DaemonConfig;
15
15
  export declare function redactedCloudStatus(config: DaemonConfig): Record<string, unknown>;
16
16
  export declare function validateGatewayNetworkTarget(url: URL): void;
17
17
  export declare function createGatewayLookup(url: URL): LookupFunction;
18
+ export declare function postJsonToValidatedGateway(url: URL, payload: Record<string, unknown>): Promise<Record<string, unknown>>;
18
19
  //# sourceMappingURL=cloud-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-config.d.ts","sourceRoot":"","sources":["../src/cloud-config.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAK/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAUjC;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CA2BvD;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,GAAG,YAAY,CAgB/G;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAWjE;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWjF;AAeD,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAK3D;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc,CAc5D"}
1
+ {"version":3,"file":"cloud-config.d.ts","sourceRoot":"","sources":["../src/cloud-config.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAK/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAUjC;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CA2BvD;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,GAAG,YAAY,CAgB/G;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAWjE;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWjF;AAeD,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAK3D;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc,CAc5D;AA+BD,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAmCvH"}
@@ -161,7 +161,7 @@ function writeConfigFile(configPath, contents) {
161
161
  writeFileSync(configPath, contents, { encoding: "utf-8", mode: 0o600 });
162
162
  chmodSync(configPath, 0o600);
163
163
  }
164
- function postJsonToValidatedGateway(url, payload) {
164
+ export function postJsonToValidatedGateway(url, payload) {
165
165
  validateGatewayNetworkTarget(url);
166
166
  const body = JSON.stringify(payload);
167
167
  const requestImpl = url.protocol === "https:" ? httpsRequest : httpRequest;
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-config.js","sourceRoot":"","sources":["../src/cloud-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { chmodSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { lookup } from \"node:dns\";\nimport type { LookupOneOptions } from \"node:dns\";\nimport { request as httpRequest } from \"node:http\";\nimport { request as httpsRequest } from \"node:https\";\nimport { isIP } from \"node:net\";\nimport type { LookupFunction } from \"node:net\";\nimport { dirname } from \"node:path\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport { loadConfig } from \"./config.js\";\nimport { protectCloudDeviceToken } from \"./cloud-token.js\";\nimport type { DaemonConfig } from \"./types.js\";\n\nexport interface PairingExchangeResult {\n runtimeId: string;\n deviceToken: string;\n}\n\nexport async function exchangePairingCode(params: {\n gatewayUrl: string;\n code: string;\n runtimeName?: string;\n}): Promise<PairingExchangeResult> {\n const pairingUrl = new URL(\"/pairing/exchange\", parseCloudGatewayUrl(params.gatewayUrl));\n const body = await postJsonToValidatedGateway(pairingUrl, {\n code: params.code,\n runtimeName: params.runtimeName,\n });\n if (typeof body.runtimeId !== \"string\" || typeof body.deviceToken !== \"string\") {\n throw new Error(\"Pairing response did not include runtimeId and deviceToken\");\n }\n return { runtimeId: body.runtimeId, deviceToken: body.deviceToken };\n}\n\nexport function parseCloudGatewayUrl(value: string): URL {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new Error(\"Cloud gateway URL must be an absolute HTTP(S) URL\");\n }\n\n if (url.protocol !== \"https:\" && url.protocol !== \"http:\") {\n throw new Error(\"Cloud gateway URL must use http or https\");\n }\n if (url.username || url.password) {\n throw new Error(\"Cloud gateway URL must not include credentials\");\n }\n if (url.hash) {\n throw new Error(\"Cloud gateway URL must not include a fragment\");\n }\n if (url.protocol === \"http:\" && !isLoopbackHost(url.hostname)) {\n throw new Error(\"Plain HTTP cloud gateway URLs are only allowed for localhost\");\n }\n if (url.protocol === \"https:\" && isPrivateIpHost(url.hostname)) {\n throw new Error(\"Cloud gateway URL must not target private or loopback IP addresses\");\n }\n\n url.pathname = url.pathname.replace(/\\/+$/, \"\");\n url.search = \"\";\n return url;\n}\n\nexport function saveCloudConfig(configPath: string, nextCloud: NonNullable<DaemonConfig[\"cloud\"]>): DaemonConfig {\n let raw: Record<string, unknown> = {};\n try {\n raw = parseYaml(readFileSync(configPath, \"utf-8\")) as Record<string, unknown> ?? {};\n } catch {\n raw = {};\n }\n const { device_token: deviceToken, ...cloud } = nextCloud;\n raw.cloud = {\n ...cloud,\n gateway_url: parseCloudGatewayUrl(nextCloud.gateway_url).toString(),\n ...(deviceToken ? { device_token_encrypted: protectCloudDeviceToken(deviceToken) } : {}),\n };\n mkdirSync(dirname(configPath), { recursive: true });\n writeConfigFile(configPath, stringifyYaml(raw));\n return loadConfig(configPath);\n}\n\nexport function clearCloudConfig(configPath: string): DaemonConfig {\n let raw: Record<string, unknown> = {};\n try {\n raw = parseYaml(readFileSync(configPath, \"utf-8\")) as Record<string, unknown> ?? {};\n } catch {\n raw = {};\n }\n delete raw.cloud;\n mkdirSync(dirname(configPath), { recursive: true });\n writeConfigFile(configPath, stringifyYaml(raw));\n return loadConfig(configPath);\n}\n\nexport function redactedCloudStatus(config: DaemonConfig): Record<string, unknown> {\n const cloud = config.cloud;\n if (!cloud) return { configured: false };\n return {\n configured: true,\n enabled: cloud.enabled ?? true,\n gateway_url: cloud.gateway_url,\n runtime_id: cloud.runtime_id ?? null,\n runtime_name: cloud.runtime_name ?? null,\n [\"device_\" + \"token\"]: cloud.device_token ? \"[redacted]\" : null,\n };\n}\n\nfunction isLoopbackHost(hostname: string): boolean {\n const host = hostname.toLowerCase();\n return host === \"localhost\" || host === \"127.0.0.1\" || host === \"::1\" || host === \"[::1]\";\n}\n\nfunction isPrivateIpHost(hostname: string): boolean {\n const host = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n if (host === \"localhost\") return true;\n if (isIP(host) === 4) return isPrivateIpv4(host);\n if (isIP(host) === 6) return isPrivateIpv6(host);\n return false;\n}\n\nexport function validateGatewayNetworkTarget(url: URL): void {\n if (url.protocol === \"http:\" && isLoopbackHost(url.hostname)) return;\n if (isPrivateIpHost(url.hostname)) {\n throw new Error(\"Cloud gateway URL must not target private or loopback IP addresses\");\n }\n}\n\nexport function createGatewayLookup(url: URL): LookupFunction {\n const allowLoopback = url.protocol === \"http:\" && isLoopbackHost(url.hostname);\n return (hostname, options, callback) => {\n const lookupOptions: LookupOneOptions = typeof options === \"number\"\n ? { family: options, all: false }\n : { ...options, all: false };\n lookup(hostname, lookupOptions, (err, address, family) => {\n if (err) return callback(err, address, family);\n if (!address || (!allowLoopback && isPrivateIpHost(address))) {\n return callback(new Error(\"Cloud gateway URL resolved to a private or loopback address\"), address, family);\n }\n callback(null, address, family);\n });\n };\n}\n\nfunction isPrivateIpv4(host: string): boolean {\n const octets = host.split(\".\").map((part) => Number(part));\n if (octets.length !== 4 || octets.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) return true;\n const [a, b] = octets;\n if (a === 10 || a === 127 || a === 0) return true;\n if (a === 169 && b === 254) return true;\n if (a === 172 && b >= 16 && b <= 31) return true;\n if (a === 192 && b === 168) return true;\n if (a === 100 && b >= 64 && b <= 127) return true;\n if (a === 192 && b === 0) return true;\n if (a === 198 && (b === 18 || b === 19)) return true;\n if (a >= 224) return true;\n return false;\n}\n\nfunction isPrivateIpv6(host: string): boolean {\n return host === \"::\"\n || host === \"::1\"\n || host.startsWith(\"fc\")\n || host.startsWith(\"fd\")\n || host.startsWith(\"fe80:\")\n || host.startsWith(\"2001:db8:\");\n}\n\nfunction writeConfigFile(configPath: string, contents: string): void {\n writeFileSync(configPath, contents, { encoding: \"utf-8\", mode: 0o600 });\n chmodSync(configPath, 0o600);\n}\n\nfunction postJsonToValidatedGateway(url: URL, payload: Record<string, unknown>): Promise<Record<string, unknown>> {\n validateGatewayNetworkTarget(url);\n const body = JSON.stringify(payload);\n const requestImpl = url.protocol === \"https:\" ? httpsRequest : httpRequest;\n\n return new Promise((resolve, reject) => {\n const req = requestImpl({\n protocol: url.protocol,\n hostname: url.hostname,\n port: url.port,\n path: `${url.pathname}${url.search}`,\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"content-length\": Buffer.byteLength(body),\n },\n lookup: createGatewayLookup(url),\n }, (res) => {\n const statusCode = res.statusCode ?? 0;\n const chunks: Buffer[] = [];\n res.on(\"data\", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));\n res.on(\"end\", () => {\n const responseText = Buffer.concat(chunks).toString(\"utf-8\");\n const parsed = parseJsonObject(responseText);\n if (statusCode < 200 || statusCode >= 300) {\n reject(new Error(typeof parsed.error === \"string\" ? parsed.error : `Pairing failed with HTTP ${statusCode}`));\n return;\n }\n resolve(parsed);\n });\n });\n\n req.on(\"error\", reject);\n req.end(body);\n });\n}\n\nfunction parseJsonObject(value: string): Record<string, unknown> {\n try {\n const parsed = JSON.parse(value) as unknown;\n return parsed && typeof parsed === \"object\" && !Array.isArray(parsed)\n ? parsed as Record<string, unknown>\n : {};\n } catch {\n return {};\n }\n}\n"]}
1
+ {"version":3,"file":"cloud-config.js","sourceRoot":"","sources":["../src/cloud-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { chmodSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { lookup } from \"node:dns\";\nimport type { LookupOneOptions } from \"node:dns\";\nimport { request as httpRequest } from \"node:http\";\nimport { request as httpsRequest } from \"node:https\";\nimport { isIP } from \"node:net\";\nimport type { LookupFunction } from \"node:net\";\nimport { dirname } from \"node:path\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport { loadConfig } from \"./config.js\";\nimport { protectCloudDeviceToken } from \"./cloud-token.js\";\nimport type { DaemonConfig } from \"./types.js\";\n\nexport interface PairingExchangeResult {\n runtimeId: string;\n deviceToken: string;\n}\n\nexport async function exchangePairingCode(params: {\n gatewayUrl: string;\n code: string;\n runtimeName?: string;\n}): Promise<PairingExchangeResult> {\n const pairingUrl = new URL(\"/pairing/exchange\", parseCloudGatewayUrl(params.gatewayUrl));\n const body = await postJsonToValidatedGateway(pairingUrl, {\n code: params.code,\n runtimeName: params.runtimeName,\n });\n if (typeof body.runtimeId !== \"string\" || typeof body.deviceToken !== \"string\") {\n throw new Error(\"Pairing response did not include runtimeId and deviceToken\");\n }\n return { runtimeId: body.runtimeId, deviceToken: body.deviceToken };\n}\n\nexport function parseCloudGatewayUrl(value: string): URL {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new Error(\"Cloud gateway URL must be an absolute HTTP(S) URL\");\n }\n\n if (url.protocol !== \"https:\" && url.protocol !== \"http:\") {\n throw new Error(\"Cloud gateway URL must use http or https\");\n }\n if (url.username || url.password) {\n throw new Error(\"Cloud gateway URL must not include credentials\");\n }\n if (url.hash) {\n throw new Error(\"Cloud gateway URL must not include a fragment\");\n }\n if (url.protocol === \"http:\" && !isLoopbackHost(url.hostname)) {\n throw new Error(\"Plain HTTP cloud gateway URLs are only allowed for localhost\");\n }\n if (url.protocol === \"https:\" && isPrivateIpHost(url.hostname)) {\n throw new Error(\"Cloud gateway URL must not target private or loopback IP addresses\");\n }\n\n url.pathname = url.pathname.replace(/\\/+$/, \"\");\n url.search = \"\";\n return url;\n}\n\nexport function saveCloudConfig(configPath: string, nextCloud: NonNullable<DaemonConfig[\"cloud\"]>): DaemonConfig {\n let raw: Record<string, unknown> = {};\n try {\n raw = parseYaml(readFileSync(configPath, \"utf-8\")) as Record<string, unknown> ?? {};\n } catch {\n raw = {};\n }\n const { device_token: deviceToken, ...cloud } = nextCloud;\n raw.cloud = {\n ...cloud,\n gateway_url: parseCloudGatewayUrl(nextCloud.gateway_url).toString(),\n ...(deviceToken ? { device_token_encrypted: protectCloudDeviceToken(deviceToken) } : {}),\n };\n mkdirSync(dirname(configPath), { recursive: true });\n writeConfigFile(configPath, stringifyYaml(raw));\n return loadConfig(configPath);\n}\n\nexport function clearCloudConfig(configPath: string): DaemonConfig {\n let raw: Record<string, unknown> = {};\n try {\n raw = parseYaml(readFileSync(configPath, \"utf-8\")) as Record<string, unknown> ?? {};\n } catch {\n raw = {};\n }\n delete raw.cloud;\n mkdirSync(dirname(configPath), { recursive: true });\n writeConfigFile(configPath, stringifyYaml(raw));\n return loadConfig(configPath);\n}\n\nexport function redactedCloudStatus(config: DaemonConfig): Record<string, unknown> {\n const cloud = config.cloud;\n if (!cloud) return { configured: false };\n return {\n configured: true,\n enabled: cloud.enabled ?? true,\n gateway_url: cloud.gateway_url,\n runtime_id: cloud.runtime_id ?? null,\n runtime_name: cloud.runtime_name ?? null,\n [\"device_\" + \"token\"]: cloud.device_token ? \"[redacted]\" : null,\n };\n}\n\nfunction isLoopbackHost(hostname: string): boolean {\n const host = hostname.toLowerCase();\n return host === \"localhost\" || host === \"127.0.0.1\" || host === \"::1\" || host === \"[::1]\";\n}\n\nfunction isPrivateIpHost(hostname: string): boolean {\n const host = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n if (host === \"localhost\") return true;\n if (isIP(host) === 4) return isPrivateIpv4(host);\n if (isIP(host) === 6) return isPrivateIpv6(host);\n return false;\n}\n\nexport function validateGatewayNetworkTarget(url: URL): void {\n if (url.protocol === \"http:\" && isLoopbackHost(url.hostname)) return;\n if (isPrivateIpHost(url.hostname)) {\n throw new Error(\"Cloud gateway URL must not target private or loopback IP addresses\");\n }\n}\n\nexport function createGatewayLookup(url: URL): LookupFunction {\n const allowLoopback = url.protocol === \"http:\" && isLoopbackHost(url.hostname);\n return (hostname, options, callback) => {\n const lookupOptions: LookupOneOptions = typeof options === \"number\"\n ? { family: options, all: false }\n : { ...options, all: false };\n lookup(hostname, lookupOptions, (err, address, family) => {\n if (err) return callback(err, address, family);\n if (!address || (!allowLoopback && isPrivateIpHost(address))) {\n return callback(new Error(\"Cloud gateway URL resolved to a private or loopback address\"), address, family);\n }\n callback(null, address, family);\n });\n };\n}\n\nfunction isPrivateIpv4(host: string): boolean {\n const octets = host.split(\".\").map((part) => Number(part));\n if (octets.length !== 4 || octets.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) return true;\n const [a, b] = octets;\n if (a === 10 || a === 127 || a === 0) return true;\n if (a === 169 && b === 254) return true;\n if (a === 172 && b >= 16 && b <= 31) return true;\n if (a === 192 && b === 168) return true;\n if (a === 100 && b >= 64 && b <= 127) return true;\n if (a === 192 && b === 0) return true;\n if (a === 198 && (b === 18 || b === 19)) return true;\n if (a >= 224) return true;\n return false;\n}\n\nfunction isPrivateIpv6(host: string): boolean {\n return host === \"::\"\n || host === \"::1\"\n || host.startsWith(\"fc\")\n || host.startsWith(\"fd\")\n || host.startsWith(\"fe80:\")\n || host.startsWith(\"2001:db8:\");\n}\n\nfunction writeConfigFile(configPath: string, contents: string): void {\n writeFileSync(configPath, contents, { encoding: \"utf-8\", mode: 0o600 });\n chmodSync(configPath, 0o600);\n}\n\nexport function postJsonToValidatedGateway(url: URL, payload: Record<string, unknown>): Promise<Record<string, unknown>> {\n validateGatewayNetworkTarget(url);\n const body = JSON.stringify(payload);\n const requestImpl = url.protocol === \"https:\" ? httpsRequest : httpRequest;\n\n return new Promise((resolve, reject) => {\n const req = requestImpl({\n protocol: url.protocol,\n hostname: url.hostname,\n port: url.port,\n path: `${url.pathname}${url.search}`,\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"content-length\": Buffer.byteLength(body),\n },\n lookup: createGatewayLookup(url),\n }, (res) => {\n const statusCode = res.statusCode ?? 0;\n const chunks: Buffer[] = [];\n res.on(\"data\", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));\n res.on(\"end\", () => {\n const responseText = Buffer.concat(chunks).toString(\"utf-8\");\n const parsed = parseJsonObject(responseText);\n if (statusCode < 200 || statusCode >= 300) {\n reject(new Error(typeof parsed.error === \"string\" ? parsed.error : `Pairing failed with HTTP ${statusCode}`));\n return;\n }\n resolve(parsed);\n });\n });\n\n req.on(\"error\", reject);\n req.end(body);\n });\n}\n\nfunction parseJsonObject(value: string): Record<string, unknown> {\n try {\n const parsed = JSON.parse(value) as unknown;\n return parsed && typeof parsed === \"object\" && !Array.isArray(parsed)\n ? parsed as Record<string, unknown>\n : {};\n } catch {\n return {};\n }\n}\n"]}