@opengsd/gsd-pi 1.8.0 → 1.8.1-dev.897b3c90

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 (463) hide show
  1. package/README.md +8 -3
  2. package/dist/cli.js +5 -1
  3. package/dist/headless-events.d.ts +2 -1
  4. package/dist/headless-events.js +11 -3
  5. package/dist/headless-milestone-readiness.d.ts +29 -0
  6. package/dist/headless-milestone-readiness.js +161 -0
  7. package/dist/headless.js +25 -2
  8. package/dist/print-mode-exit.d.ts +12 -0
  9. package/dist/print-mode-exit.js +14 -0
  10. package/dist/resources/.managed-resources-content-hash +1 -1
  11. package/dist/resources/GSD-WORKFLOW.md +16 -47
  12. package/dist/resources/extensions/browser-tools/capture.js +2 -77
  13. package/dist/resources/extensions/browser-tools/screenshot-constraints.js +83 -0
  14. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +17 -2
  15. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +30 -2
  16. package/dist/resources/extensions/gsd/auto-artifact-paths.js +2 -2
  17. package/dist/resources/extensions/gsd/auto-dispatch.js +74 -19
  18. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -0
  19. package/dist/resources/extensions/gsd/auto-prompts.js +35 -1
  20. package/dist/resources/extensions/gsd/auto.js +5 -1
  21. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +78 -4
  22. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +84 -26
  23. package/dist/resources/extensions/gsd/command-feedback.js +16 -12
  24. package/dist/resources/extensions/gsd/compat/compat-marker.js +19 -2
  25. package/dist/resources/extensions/gsd/db/command-queue.js +7 -2
  26. package/dist/resources/extensions/gsd/db/engine.js +51 -16
  27. package/dist/resources/extensions/gsd/db/writers/cascades.js +5 -1
  28. package/dist/resources/extensions/gsd/db/writers/status.js +13 -3
  29. package/dist/resources/extensions/gsd/db-base-schema.js +28 -0
  30. package/dist/resources/extensions/gsd/db-migration-steps.js +30 -0
  31. package/dist/resources/extensions/gsd/db-schema-metadata.js +4 -1
  32. package/dist/resources/extensions/gsd/docs/preferences-reference.md +4 -4
  33. package/dist/resources/extensions/gsd/doctor-history.js +65 -0
  34. package/dist/resources/extensions/gsd/doctor-state-checks.js +509 -0
  35. package/dist/resources/extensions/gsd/doctor-workspace-checks.js +91 -0
  36. package/dist/resources/extensions/gsd/doctor.js +14 -653
  37. package/dist/resources/extensions/gsd/flat-phase-migration.js +156 -21
  38. package/dist/resources/extensions/gsd/gsd-db.js +187 -45
  39. package/dist/resources/extensions/gsd/guided-flow.js +29 -10
  40. package/dist/resources/extensions/gsd/markdown-renderer.js +16 -2
  41. package/dist/resources/extensions/gsd/md-importer.js +109 -16
  42. package/dist/resources/extensions/gsd/migrate/command.js +19 -162
  43. package/dist/resources/extensions/gsd/migrate/execution.js +98 -0
  44. package/dist/resources/extensions/gsd/migrate/plan.js +49 -0
  45. package/dist/resources/extensions/gsd/migrate/planning-writer.js +20 -19
  46. package/dist/resources/extensions/gsd/migrate/presentation.js +64 -0
  47. package/dist/resources/extensions/gsd/migration-auto-check.js +4 -0
  48. package/dist/resources/extensions/gsd/parallel-eligibility.js +5 -4
  49. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +28 -43
  50. package/dist/resources/extensions/gsd/paths.js +4 -1
  51. package/dist/resources/extensions/gsd/phase-anchor.js +7 -2
  52. package/dist/resources/extensions/gsd/post-execution-checks.js +4 -4
  53. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  54. package/dist/resources/extensions/gsd/safety/evidence-collector.js +26 -1
  55. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +30 -5
  56. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +27 -13
  57. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +13 -3
  58. package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +54 -14
  59. package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +48 -5
  60. package/dist/resources/extensions/gsd/stop-notice.js +15 -1
  61. package/dist/resources/extensions/gsd/sync-lock.js +13 -7
  62. package/dist/resources/extensions/gsd/tools/complete-task.js +82 -1
  63. package/dist/resources/extensions/gsd/tools/plan-task.js +13 -15
  64. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +18 -15
  65. package/dist/resources/extensions/gsd/tools/replan-task.js +128 -0
  66. package/dist/resources/extensions/gsd/tools/rework-brief.js +74 -0
  67. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +81 -0
  68. package/dist/resources/extensions/gsd/unit-registry.js +4 -0
  69. package/dist/resources/extensions/gsd/uok/plan-v2.js +19 -3
  70. package/dist/resources/extensions/gsd/worktree-state-projection.js +6 -0
  71. package/dist/resources/extensions/mac-tools/index.js +31 -9
  72. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  73. package/dist/web/standalone/.next/BUILD_ID +1 -1
  74. package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
  75. package/dist/web/standalone/.next/build-manifest.json +3 -3
  76. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  77. package/dist/web/standalone/.next/required-server-files.json +3 -3
  78. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  79. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  89. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  98. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  105. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  117. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  139. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  149. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  155. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  171. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  175. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/index.html +1 -1
  185. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  186. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  187. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  188. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  189. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  190. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  191. package/dist/web/standalone/.next/server/app/page.js +2 -2
  192. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
  194. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  195. package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
  196. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  197. package/dist/web/standalone/.next/server/middleware.js +3 -3
  198. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  199. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  200. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  201. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
  202. package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
  203. package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
  204. package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
  205. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
  206. package/dist/web/standalone/.next/static/css/3b1ceb7abfb9a230.css +1 -0
  207. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  208. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  209. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  210. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  211. package/dist/web/standalone/package.json +0 -1
  212. package/dist/web/standalone/server.js +1 -1
  213. package/dist/web-mode.js +31 -3
  214. package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
  215. package/integrations/hermes/pyproject.toml +1 -1
  216. package/package.json +12 -10
  217. package/packages/cloud-mcp-gateway/package.json +2 -2
  218. package/packages/contracts/dist/workflow.d.ts +14 -0
  219. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  220. package/packages/contracts/dist/workflow.js +16 -0
  221. package/packages/contracts/dist/workflow.js.map +1 -1
  222. package/packages/contracts/package.json +1 -1
  223. package/packages/daemon/dist/cloud-config.d.ts +1 -1
  224. package/packages/daemon/dist/cloud-config.d.ts.map +1 -1
  225. package/packages/daemon/dist/cloud-config.js +5 -1
  226. package/packages/daemon/dist/cloud-config.js.map +1 -1
  227. package/packages/daemon/dist/cloud-config.test.js +51 -1
  228. package/packages/daemon/dist/cloud-config.test.js.map +1 -1
  229. package/packages/daemon/dist/local-tool-executor.d.ts.map +1 -1
  230. package/packages/daemon/dist/local-tool-executor.js +2 -0
  231. package/packages/daemon/dist/local-tool-executor.js.map +1 -1
  232. package/packages/daemon/package.json +6 -6
  233. package/packages/gsd-agent-core/package.json +5 -5
  234. package/packages/gsd-agent-modes/package.json +7 -7
  235. package/packages/gsd-cloud/dist/cli.d.ts +5 -0
  236. package/packages/gsd-cloud/dist/cli.d.ts.map +1 -0
  237. package/packages/gsd-cloud/dist/cli.js +160 -0
  238. package/packages/gsd-cloud/dist/cli.js.map +1 -0
  239. package/packages/gsd-cloud/dist/cloud-config.d.ts +19 -0
  240. package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -0
  241. package/packages/gsd-cloud/dist/cloud-config.js +231 -0
  242. package/packages/gsd-cloud/dist/cloud-config.js.map +1 -0
  243. package/packages/gsd-cloud/dist/cloud-config.test.d.ts +2 -0
  244. package/packages/gsd-cloud/dist/cloud-config.test.d.ts.map +1 -0
  245. package/packages/gsd-cloud/dist/cloud-config.test.js +118 -0
  246. package/packages/gsd-cloud/dist/cloud-config.test.js.map +1 -0
  247. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts +2 -0
  248. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts.map +1 -0
  249. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js +37 -0
  250. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js.map +1 -0
  251. package/packages/gsd-cloud/dist/cloud-runtime.d.ts +35 -0
  252. package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -0
  253. package/packages/gsd-cloud/dist/cloud-runtime.js +258 -0
  254. package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -0
  255. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts +2 -0
  256. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts.map +1 -0
  257. package/packages/gsd-cloud/dist/cloud-runtime.test.js +88 -0
  258. package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -0
  259. package/packages/gsd-cloud/dist/cloud-token.d.ts +3 -0
  260. package/packages/gsd-cloud/dist/cloud-token.d.ts.map +1 -0
  261. package/packages/gsd-cloud/dist/cloud-token.js +37 -0
  262. package/packages/gsd-cloud/dist/cloud-token.js.map +1 -0
  263. package/packages/gsd-cloud/dist/config.d.ts +17 -0
  264. package/packages/gsd-cloud/dist/config.d.ts.map +1 -0
  265. package/packages/gsd-cloud/dist/config.js +146 -0
  266. package/packages/gsd-cloud/dist/config.js.map +1 -0
  267. package/packages/gsd-cloud/dist/device-flow.d.ts +24 -0
  268. package/packages/gsd-cloud/dist/device-flow.d.ts.map +1 -0
  269. package/packages/gsd-cloud/dist/device-flow.js +128 -0
  270. package/packages/gsd-cloud/dist/device-flow.js.map +1 -0
  271. package/packages/gsd-cloud/dist/device-flow.test.d.ts +2 -0
  272. package/packages/gsd-cloud/dist/device-flow.test.d.ts.map +1 -0
  273. package/packages/gsd-cloud/dist/device-flow.test.js +155 -0
  274. package/packages/gsd-cloud/dist/device-flow.test.js.map +1 -0
  275. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts +6 -0
  276. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts.map +1 -0
  277. package/packages/gsd-cloud/dist/executors/claude-executor.js +15 -0
  278. package/packages/gsd-cloud/dist/executors/claude-executor.js.map +1 -0
  279. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts +6 -0
  280. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts.map +1 -0
  281. package/packages/gsd-cloud/dist/executors/codex-executor.js +15 -0
  282. package/packages/gsd-cloud/dist/executors/codex-executor.js.map +1 -0
  283. package/packages/gsd-cloud/dist/executors/executor.d.ts +28 -0
  284. package/packages/gsd-cloud/dist/executors/executor.d.ts.map +1 -0
  285. package/packages/gsd-cloud/dist/executors/executor.js +11 -0
  286. package/packages/gsd-cloud/dist/executors/executor.js.map +1 -0
  287. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts +34 -0
  288. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts.map +1 -0
  289. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js +179 -0
  290. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js.map +1 -0
  291. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts +2 -0
  292. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts.map +1 -0
  293. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js +44 -0
  294. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js.map +1 -0
  295. package/packages/gsd-cloud/dist/executors/index.d.ts +17 -0
  296. package/packages/gsd-cloud/dist/executors/index.d.ts.map +1 -0
  297. package/packages/gsd-cloud/dist/executors/index.js +29 -0
  298. package/packages/gsd-cloud/dist/executors/index.js.map +1 -0
  299. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts +36 -0
  300. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts.map +1 -0
  301. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js +176 -0
  302. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js.map +1 -0
  303. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts +2 -0
  304. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts.map +1 -0
  305. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js +34 -0
  306. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js.map +1 -0
  307. package/packages/gsd-cloud/dist/index.d.ts +7 -0
  308. package/packages/gsd-cloud/dist/index.d.ts.map +1 -0
  309. package/packages/gsd-cloud/dist/index.js +8 -0
  310. package/packages/gsd-cloud/dist/index.js.map +1 -0
  311. package/packages/gsd-cloud/dist/inject-gateway.d.ts +16 -0
  312. package/packages/gsd-cloud/dist/inject-gateway.d.ts.map +1 -0
  313. package/packages/gsd-cloud/dist/inject-gateway.js +29 -0
  314. package/packages/gsd-cloud/dist/inject-gateway.js.map +1 -0
  315. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts +2 -0
  316. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts.map +1 -0
  317. package/packages/gsd-cloud/dist/inject-gateway.test.js +41 -0
  318. package/packages/gsd-cloud/dist/inject-gateway.test.js.map +1 -0
  319. package/packages/gsd-cloud/dist/logger.d.ts +25 -0
  320. package/packages/gsd-cloud/dist/logger.d.ts.map +1 -0
  321. package/packages/gsd-cloud/dist/logger.js +72 -0
  322. package/packages/gsd-cloud/dist/logger.js.map +1 -0
  323. package/packages/gsd-cloud/dist/types.d.ts +51 -0
  324. package/packages/gsd-cloud/dist/types.d.ts.map +1 -0
  325. package/packages/gsd-cloud/dist/types.js +9 -0
  326. package/packages/gsd-cloud/dist/types.js.map +1 -0
  327. package/packages/gsd-cloud/package.json +3 -3
  328. package/packages/mcp-server/README.md +8 -0
  329. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  330. package/packages/mcp-server/dist/workflow-tools.js +64 -2
  331. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  332. package/packages/mcp-server/package.json +4 -4
  333. package/packages/native/package.json +1 -1
  334. package/packages/pi-agent-core/package.json +1 -1
  335. package/packages/pi-ai/dist/models.generated.d.ts +60 -0
  336. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  337. package/packages/pi-ai/dist/models.generated.js +54 -0
  338. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  339. package/packages/pi-ai/dist/providers/amazon-bedrock.js +1 -0
  340. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  341. package/packages/pi-ai/dist/providers/anthropic.js +19 -0
  342. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  343. package/packages/pi-ai/package.json +1 -1
  344. package/packages/pi-coding-agent/package.json +7 -7
  345. package/packages/pi-tui/package.json +2 -2
  346. package/packages/rpc-client/package.json +2 -2
  347. package/pkg/package.json +1 -1
  348. package/src/resources/GSD-WORKFLOW.md +16 -47
  349. package/src/resources/extensions/browser-tools/capture.ts +2 -86
  350. package/src/resources/extensions/browser-tools/screenshot-constraints.ts +94 -0
  351. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +18 -1
  352. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -0
  353. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +30 -2
  354. package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
  355. package/src/resources/extensions/gsd/auto-dispatch.ts +86 -19
  356. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -0
  357. package/src/resources/extensions/gsd/auto-prompts.ts +38 -1
  358. package/src/resources/extensions/gsd/auto.ts +5 -1
  359. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +91 -4
  360. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +80 -24
  361. package/src/resources/extensions/gsd/command-feedback.ts +19 -12
  362. package/src/resources/extensions/gsd/compat/compat-marker.ts +21 -4
  363. package/src/resources/extensions/gsd/db/command-queue.ts +7 -1
  364. package/src/resources/extensions/gsd/db/engine.ts +53 -17
  365. package/src/resources/extensions/gsd/db/writers/cascades.ts +5 -1
  366. package/src/resources/extensions/gsd/db/writers/status.ts +25 -8
  367. package/src/resources/extensions/gsd/db-base-schema.ts +30 -0
  368. package/src/resources/extensions/gsd/db-migration-steps.ts +32 -0
  369. package/src/resources/extensions/gsd/db-schema-metadata.ts +4 -1
  370. package/src/resources/extensions/gsd/docs/preferences-reference.md +4 -4
  371. package/src/resources/extensions/gsd/doctor-history.ts +81 -0
  372. package/src/resources/extensions/gsd/doctor-state-checks.ts +527 -0
  373. package/src/resources/extensions/gsd/doctor-workspace-checks.ts +97 -0
  374. package/src/resources/extensions/gsd/doctor.ts +14 -673
  375. package/src/resources/extensions/gsd/flat-phase-migration.ts +160 -19
  376. package/src/resources/extensions/gsd/gsd-db.ts +255 -52
  377. package/src/resources/extensions/gsd/guided-flow.ts +39 -10
  378. package/src/resources/extensions/gsd/markdown-renderer.ts +23 -7
  379. package/src/resources/extensions/gsd/md-importer.ts +116 -13
  380. package/src/resources/extensions/gsd/migrate/command.ts +21 -227
  381. package/src/resources/extensions/gsd/migrate/execution.ts +136 -0
  382. package/src/resources/extensions/gsd/migrate/plan.ts +101 -0
  383. package/src/resources/extensions/gsd/migrate/planning-writer.ts +21 -23
  384. package/src/resources/extensions/gsd/migrate/presentation.ts +83 -0
  385. package/src/resources/extensions/gsd/migration-auto-check.ts +3 -0
  386. package/src/resources/extensions/gsd/parallel-eligibility.ts +5 -4
  387. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +37 -40
  388. package/src/resources/extensions/gsd/paths.ts +4 -1
  389. package/src/resources/extensions/gsd/phase-anchor.ts +8 -2
  390. package/src/resources/extensions/gsd/post-execution-checks.ts +4 -4
  391. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  392. package/src/resources/extensions/gsd/safety/evidence-collector.ts +28 -1
  393. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +31 -5
  394. package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +30 -13
  395. package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +16 -3
  396. package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +67 -20
  397. package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +47 -5
  398. package/src/resources/extensions/gsd/state-reconciliation/types.ts +2 -2
  399. package/src/resources/extensions/gsd/stop-notice.ts +18 -1
  400. package/src/resources/extensions/gsd/sync-lock.ts +14 -6
  401. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +96 -1
  402. package/src/resources/extensions/gsd/tests/command-feedback.test.ts +12 -0
  403. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +104 -0
  404. package/src/resources/extensions/gsd/tests/complete-task.test.ts +286 -0
  405. package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +76 -1
  406. package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +186 -0
  407. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +29 -0
  408. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +123 -0
  409. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +50 -0
  410. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +49 -0
  411. package/src/resources/extensions/gsd/tests/doctor-history-public-api.test.ts +25 -0
  412. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +81 -0
  413. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +22 -0
  414. package/src/resources/extensions/gsd/tests/external-edit-scoped-import.test.ts +262 -0
  415. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +202 -0
  416. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +29 -0
  417. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +25 -0
  418. package/src/resources/extensions/gsd/tests/import-slice-milestone-completion-preserve.test.ts +116 -0
  419. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +53 -0
  420. package/src/resources/extensions/gsd/tests/migrate-plan.test.ts +68 -0
  421. package/src/resources/extensions/gsd/tests/migrate-presentation.test.ts +98 -0
  422. package/src/resources/extensions/gsd/tests/migrate-safety-audit.test.ts +1 -1
  423. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +53 -0
  424. package/src/resources/extensions/gsd/tests/milestone-leases.test.ts +55 -0
  425. package/src/resources/extensions/gsd/tests/parallel-eligibility-file-overlap.test.ts +146 -0
  426. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +59 -0
  427. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +4 -0
  428. package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +32 -4
  429. package/src/resources/extensions/gsd/tests/plan-task.test.ts +26 -23
  430. package/src/resources/extensions/gsd/tests/planning-writer.test.ts +47 -1
  431. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +22 -0
  432. package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +18 -3
  433. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +50 -0
  434. package/src/resources/extensions/gsd/tests/replan-task-handler.test.ts +103 -0
  435. package/src/resources/extensions/gsd/tests/rework-brief.test.ts +197 -0
  436. package/src/resources/extensions/gsd/tests/skip-slice-cascades-tasks.test.ts +21 -0
  437. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +177 -25
  438. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +17 -0
  439. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +19 -0
  440. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +34 -0
  441. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +93 -1
  442. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -0
  443. package/src/resources/extensions/gsd/tests/workflow-migration-gates.test.ts +139 -0
  444. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +36 -0
  445. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +52 -0
  446. package/src/resources/extensions/gsd/tools/complete-task.ts +120 -0
  447. package/src/resources/extensions/gsd/tools/plan-task.ts +14 -16
  448. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +18 -17
  449. package/src/resources/extensions/gsd/tools/replan-task.ts +160 -0
  450. package/src/resources/extensions/gsd/tools/rework-brief.ts +91 -0
  451. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +92 -0
  452. package/src/resources/extensions/gsd/types.ts +11 -0
  453. package/src/resources/extensions/gsd/unit-registry.ts +4 -0
  454. package/src/resources/extensions/gsd/uok/plan-v2.ts +20 -3
  455. package/src/resources/extensions/gsd/worktree-state-projection.ts +12 -0
  456. package/src/resources/extensions/mac-tools/index.ts +52 -9
  457. package/src/resources/extensions/mac-tools/tests/mac-screenshot-payload.test.cjs +70 -0
  458. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  459. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  460. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  461. package/dist/web/standalone/.next/static/css/18c2fdf261bfc1b7.css +0 -1
  462. /package/dist/web/standalone/.next/static/{seHIUVbR1mm7LfG83nWJO → TezjdjSHBVRRr54XjAvte}/_buildManifest.js +0 -0
  463. /package/dist/web/standalone/.next/static/{seHIUVbR1mm7LfG83nWJO → TezjdjSHBVRRr54XjAvte}/_ssgManifest.js +0 -0
@@ -0,0 +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,CAkC5D;AAiCD,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,GAAE,MAAmC,GAC7C,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAsClC"}
@@ -0,0 +1,231 @@
1
+ import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { lookup } from "node:dns";
3
+ import { request as httpRequest } from "node:http";
4
+ import { request as httpsRequest } from "node:https";
5
+ import { isIP } from "node:net";
6
+ import { dirname } from "node:path";
7
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
8
+ import { loadConfig } from "./config.js";
9
+ import { protectCloudDeviceToken } from "./cloud-token.js";
10
+ export async function exchangePairingCode(params) {
11
+ const pairingUrl = new URL("/pairing/exchange", parseCloudGatewayUrl(params.gatewayUrl));
12
+ const body = await postJsonToValidatedGateway(pairingUrl, {
13
+ code: params.code,
14
+ runtimeName: params.runtimeName,
15
+ });
16
+ if (typeof body.runtimeId !== "string" || typeof body.deviceToken !== "string") {
17
+ throw new Error("Pairing response did not include runtimeId and deviceToken");
18
+ }
19
+ return { runtimeId: body.runtimeId, deviceToken: body.deviceToken };
20
+ }
21
+ export function parseCloudGatewayUrl(value) {
22
+ let url;
23
+ try {
24
+ url = new URL(value);
25
+ }
26
+ catch {
27
+ throw new Error("Cloud gateway URL must be an absolute HTTP(S) URL");
28
+ }
29
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
30
+ throw new Error("Cloud gateway URL must use http or https");
31
+ }
32
+ if (url.username || url.password) {
33
+ throw new Error("Cloud gateway URL must not include credentials");
34
+ }
35
+ if (url.hash) {
36
+ throw new Error("Cloud gateway URL must not include a fragment");
37
+ }
38
+ if (url.protocol === "http:" && !isLoopbackHost(url.hostname)) {
39
+ throw new Error("Plain HTTP cloud gateway URLs are only allowed for localhost");
40
+ }
41
+ if (url.protocol === "https:" && isPrivateIpHost(url.hostname)) {
42
+ throw new Error("Cloud gateway URL must not target private or loopback IP addresses");
43
+ }
44
+ url.pathname = url.pathname.replace(/\/+$/, "");
45
+ url.search = "";
46
+ return url;
47
+ }
48
+ export function saveCloudConfig(configPath, nextCloud) {
49
+ let raw = {};
50
+ try {
51
+ raw = parseYaml(readFileSync(configPath, "utf-8")) ?? {};
52
+ }
53
+ catch {
54
+ raw = {};
55
+ }
56
+ const { device_token: deviceToken, ...cloud } = nextCloud;
57
+ raw.cloud = {
58
+ ...cloud,
59
+ gateway_url: parseCloudGatewayUrl(nextCloud.gateway_url).toString(),
60
+ ...(deviceToken ? { device_token_encrypted: protectCloudDeviceToken(deviceToken) } : {}),
61
+ };
62
+ mkdirSync(dirname(configPath), { recursive: true });
63
+ writeConfigFile(configPath, stringifyYaml(raw));
64
+ return loadConfig(configPath);
65
+ }
66
+ export function clearCloudConfig(configPath) {
67
+ let raw = {};
68
+ try {
69
+ raw = parseYaml(readFileSync(configPath, "utf-8")) ?? {};
70
+ }
71
+ catch {
72
+ raw = {};
73
+ }
74
+ delete raw.cloud;
75
+ mkdirSync(dirname(configPath), { recursive: true });
76
+ writeConfigFile(configPath, stringifyYaml(raw));
77
+ return loadConfig(configPath);
78
+ }
79
+ export function redactedCloudStatus(config) {
80
+ const cloud = config.cloud;
81
+ if (!cloud)
82
+ return { configured: false };
83
+ return {
84
+ configured: true,
85
+ enabled: cloud.enabled ?? true,
86
+ gateway_url: cloud.gateway_url,
87
+ runtime_id: cloud.runtime_id ?? null,
88
+ runtime_name: cloud.runtime_name ?? null,
89
+ ["device_" + "token"]: cloud.device_token ? "[redacted]" : null,
90
+ };
91
+ }
92
+ function isLoopbackHost(hostname) {
93
+ const host = hostname.toLowerCase();
94
+ return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
95
+ }
96
+ function isPrivateIpHost(hostname) {
97
+ const host = hostname.toLowerCase().replace(/^\[|\]$/g, "");
98
+ if (host === "localhost")
99
+ return true;
100
+ if (isIP(host) === 4)
101
+ return isPrivateIpv4(host);
102
+ if (isIP(host) === 6)
103
+ return isPrivateIpv6(host);
104
+ return false;
105
+ }
106
+ export function validateGatewayNetworkTarget(url) {
107
+ if (url.protocol === "http:" && isLoopbackHost(url.hostname))
108
+ return;
109
+ if (isPrivateIpHost(url.hostname)) {
110
+ throw new Error("Cloud gateway URL must not target private or loopback IP addresses");
111
+ }
112
+ }
113
+ export function createGatewayLookup(url) {
114
+ const allowLoopback = url.protocol === "http:" && isLoopbackHost(url.hostname);
115
+ const rejected = (address) => !address || (!allowLoopback && isPrivateIpHost(address));
116
+ // Node's socket connect (autoSelectFamily / Happy Eyeballs, default-on since
117
+ // Node 20) calls a custom lookup with `all: true` and expects an ARRAY
118
+ // callback. Forcing `all: false` + a scalar callback made every real gateway
119
+ // request throw "Invalid IP address: undefined". Honor both forms; the SSRF
120
+ // guard is applied to every resolved address (reject the whole lookup if any
121
+ // is private/loopback — an attacker-controlled resolver must not slip one in).
122
+ return ((hostname, options, callback) => {
123
+ const wantsAll = typeof options === "object" && options !== null && options.all === true;
124
+ const base = typeof options === "number" ? { family: options } : { ...options };
125
+ if (wantsAll) {
126
+ lookup(hostname, { ...base, all: true }, (err, addresses) => {
127
+ if (err)
128
+ return callback(err);
129
+ const list = addresses;
130
+ if (!list.length || list.some((entry) => rejected(entry.address))) {
131
+ return callback(new Error("Cloud gateway URL resolved to a private or loopback address"));
132
+ }
133
+ callback(null, list);
134
+ });
135
+ return;
136
+ }
137
+ lookup(hostname, { ...base, all: false }, (err, address, family) => {
138
+ if (err)
139
+ return callback(err, address, family);
140
+ if (rejected(address)) {
141
+ return callback(new Error("Cloud gateway URL resolved to a private or loopback address"), address, family);
142
+ }
143
+ callback(null, address, family);
144
+ });
145
+ });
146
+ }
147
+ function isPrivateIpv4(host) {
148
+ const octets = host.split(".").map((part) => Number(part));
149
+ if (octets.length !== 4 || octets.some((part) => !Number.isInteger(part) || part < 0 || part > 255))
150
+ return true;
151
+ const [a, b] = octets;
152
+ if (a === 10 || a === 127 || a === 0)
153
+ return true;
154
+ if (a === 169 && b === 254)
155
+ return true;
156
+ if (a === 172 && b >= 16 && b <= 31)
157
+ return true;
158
+ if (a === 192 && b === 168)
159
+ return true;
160
+ if (a === 100 && b >= 64 && b <= 127)
161
+ return true;
162
+ if (a === 192 && b === 0)
163
+ return true;
164
+ if (a === 198 && (b === 18 || b === 19))
165
+ return true;
166
+ if (a >= 224)
167
+ return true;
168
+ return false;
169
+ }
170
+ function isPrivateIpv6(host) {
171
+ return host === "::"
172
+ || host === "::1"
173
+ || host.startsWith("fc")
174
+ || host.startsWith("fd")
175
+ || host.startsWith("fe80:")
176
+ || host.startsWith("2001:db8:");
177
+ }
178
+ function writeConfigFile(configPath, contents) {
179
+ writeFileSync(configPath, contents, { encoding: "utf-8", mode: 0o600 });
180
+ chmodSync(configPath, 0o600);
181
+ }
182
+ const GATEWAY_REQUEST_TIMEOUT_MS = 30_000;
183
+ export function postJsonToValidatedGateway(url, payload, timeoutMs = GATEWAY_REQUEST_TIMEOUT_MS) {
184
+ validateGatewayNetworkTarget(url);
185
+ const body = JSON.stringify(payload);
186
+ const requestImpl = url.protocol === "https:" ? httpsRequest : httpRequest;
187
+ return new Promise((resolve, reject) => {
188
+ const req = requestImpl({
189
+ protocol: url.protocol,
190
+ hostname: url.hostname,
191
+ port: url.port,
192
+ path: `${url.pathname}${url.search}`,
193
+ method: "POST",
194
+ headers: {
195
+ "content-type": "application/json",
196
+ "content-length": Buffer.byteLength(body),
197
+ },
198
+ lookup: createGatewayLookup(url),
199
+ }, (res) => {
200
+ const statusCode = res.statusCode ?? 0;
201
+ const chunks = [];
202
+ res.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
203
+ res.on("end", () => {
204
+ const responseText = Buffer.concat(chunks).toString("utf-8");
205
+ const parsed = parseJsonObject(responseText);
206
+ if (statusCode < 200 || statusCode >= 300) {
207
+ reject(new Error(typeof parsed.error === "string" ? parsed.error : `Pairing failed with HTTP ${statusCode}`));
208
+ return;
209
+ }
210
+ resolve(parsed);
211
+ });
212
+ });
213
+ req.setTimeout(timeoutMs, () => {
214
+ req.destroy(new Error(`Gateway request timed out after ${timeoutMs}ms`));
215
+ });
216
+ req.on("error", reject);
217
+ req.end(body);
218
+ });
219
+ }
220
+ function parseJsonObject(value) {
221
+ try {
222
+ const parsed = JSON.parse(value);
223
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
224
+ ? parsed
225
+ : {};
226
+ }
227
+ catch {
228
+ return {};
229
+ }
230
+ }
231
+ //# sourceMappingURL=cloud-config.js.map
@@ -0,0 +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 { LookupOptions } 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 const rejected = (address: string): boolean =>\n !address || (!allowLoopback && isPrivateIpHost(address));\n // Node's socket connect (autoSelectFamily / Happy Eyeballs, default-on since\n // Node 20) calls a custom lookup with `all: true` and expects an ARRAY\n // callback. Forcing `all: false` + a scalar callback made every real gateway\n // request throw \"Invalid IP address: undefined\". Honor both forms; the SSRF\n // guard is applied to every resolved address (reject the whole lookup if any\n // is private/loopback — an attacker-controlled resolver must not slip one in).\n return ((hostname: string, options: unknown, callback: (...args: unknown[]) => void) => {\n const wantsAll =\n typeof options === \"object\" && options !== null && (options as LookupOptions).all === true;\n const base: LookupOptions =\n typeof options === \"number\" ? { family: options } : { ...(options as LookupOptions) };\n if (wantsAll) {\n lookup(hostname, { ...base, all: true }, (err, addresses) => {\n if (err) return callback(err);\n const list = addresses as Array<{ address: string; family: number }>;\n if (!list.length || list.some((entry) => rejected(entry.address))) {\n return callback(new Error(\"Cloud gateway URL resolved to a private or loopback address\"));\n }\n callback(null, list);\n });\n return;\n }\n lookup(hostname, { ...base, all: false }, (err, address, family) => {\n if (err) return callback(err, address, family);\n if (rejected(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 }) as unknown as LookupFunction;\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\nconst GATEWAY_REQUEST_TIMEOUT_MS = 30_000;\n\nexport function postJsonToValidatedGateway(\n url: URL,\n payload: Record<string, unknown>,\n timeoutMs: number = GATEWAY_REQUEST_TIMEOUT_MS,\n): 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.setTimeout(timeoutMs, () => {\n req.destroy(new Error(`Gateway request timed out after ${timeoutMs}ms`));\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"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cloud-config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-config.test.d.ts","sourceRoot":"","sources":["../src/cloud-config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,118 @@
1
+ // Project/App: Open GSD
2
+ // File Purpose: Tests for the cloud gateway config module. Two independent suites:
3
+ // 1. SSRF-guard matrix for parseCloudGatewayUrl / validateGatewayNetworkTarget —
4
+ // loosening any branch (plain-HTTP carve-out, private/loopback IP rejection,
5
+ // protocol/credential/fragment checks) turns a case red.
6
+ // 2. postJsonToValidatedGateway's request timeout — a hung gateway must reject
7
+ // rather than hang the pairing/device flow.
8
+ import { test } from "node:test";
9
+ import assert from "node:assert/strict";
10
+ import { createServer } from "node:http";
11
+ import { parseCloudGatewayUrl, validateGatewayNetworkTarget, postJsonToValidatedGateway, } from "./cloud-config.js";
12
+ // Each rejected case pairs an untrusted input with the substring the guard must
13
+ // report — so a message change is deliberate, not accidental.
14
+ const REJECTED = [
15
+ // Plain HTTP is only allowed for loopback hosts.
16
+ { input: "http://evil.example", message: /only allowed for localhost/ },
17
+ // RFC1918 private ranges over HTTPS.
18
+ { input: "https://10.0.0.1", message: /private or loopback/ },
19
+ { input: "https://192.168.1.1", message: /private or loopback/ },
20
+ { input: "https://172.16.0.1", message: /private or loopback/ },
21
+ // Link-local / cloud metadata endpoint.
22
+ { input: "https://169.254.169.254", message: /private or loopback/ },
23
+ // Loopback over HTTPS (IPv4 and IPv6 forms) and the localhost hostname.
24
+ { input: "https://127.0.0.1", message: /private or loopback/ },
25
+ { input: "https://[::1]", message: /private or loopback/ },
26
+ { input: "https://localhost", message: /private or loopback/ },
27
+ // Non-HTTP protocol.
28
+ { input: "ftp://gateway.example", message: /must use http or https/ },
29
+ // Embedded credentials / fragments are rejected outright.
30
+ { input: "https://user:pass@gateway.example", message: /must not include credentials/ },
31
+ { input: "https://gateway.example/#frag", message: /must not include a fragment/ },
32
+ // Unparseable / non-absolute inputs.
33
+ { input: "", message: /absolute HTTP\(S\) URL/ },
34
+ { input: "not a url", message: /absolute HTTP\(S\) URL/ },
35
+ ];
36
+ for (const { input, message } of REJECTED) {
37
+ test(`parseCloudGatewayUrl rejects ${JSON.stringify(input)}`, () => {
38
+ assert.throws(() => parseCloudGatewayUrl(input), message);
39
+ });
40
+ }
41
+ // Accepted: a public HTTPS host and the documented local-dev plain-HTTP loopback carve-out.
42
+ const ACCEPTED = [
43
+ { input: "https://cloud-gateway.opengsd.net", hostname: "cloud-gateway.opengsd.net", protocol: "https:" },
44
+ { input: "http://localhost:8787", hostname: "localhost", protocol: "http:" },
45
+ { input: "http://127.0.0.1:8787", hostname: "127.0.0.1", protocol: "http:" },
46
+ ];
47
+ for (const { input, hostname, protocol } of ACCEPTED) {
48
+ test(`parseCloudGatewayUrl accepts ${JSON.stringify(input)}`, () => {
49
+ const url = parseCloudGatewayUrl(input);
50
+ assert.equal(url.hostname, hostname);
51
+ assert.equal(url.protocol, protocol);
52
+ // Round-trips to a usable absolute URL for the same host.
53
+ assert.equal(new URL(url.toString()).hostname, hostname);
54
+ });
55
+ }
56
+ // validateGatewayNetworkTarget is the request-time defense-in-depth guard applied to
57
+ // already-constructed URLs (device code/token endpoints). Cover its branches directly.
58
+ test("validateGatewayNetworkTarget rejects private/loopback targets", () => {
59
+ assert.throws(() => validateGatewayNetworkTarget(new URL("https://169.254.169.254")), /private or loopback/);
60
+ assert.throws(() => validateGatewayNetworkTarget(new URL("https://10.0.0.1")), /private or loopback/);
61
+ assert.throws(() => validateGatewayNetworkTarget(new URL("https://[::1]")), /private or loopback/);
62
+ });
63
+ test("validateGatewayNetworkTarget allows a public HTTPS host and http loopback", () => {
64
+ assert.doesNotThrow(() => validateGatewayNetworkTarget(new URL("https://cloud-gateway.opengsd.net")));
65
+ assert.doesNotThrow(() => validateGatewayNetworkTarget(new URL("http://localhost:8787")));
66
+ assert.doesNotThrow(() => validateGatewayNetworkTarget(new URL("http://127.0.0.1:8787")));
67
+ });
68
+ // Start a loopback server, returning its base URL; skips the test under sandbox EPERM.
69
+ async function listenLoopback(t, handler) {
70
+ const server = createServer(handler);
71
+ try {
72
+ await new Promise((resolve, reject) => {
73
+ server.once("error", reject);
74
+ server.listen(0, "127.0.0.1", resolve);
75
+ });
76
+ }
77
+ catch (err) {
78
+ if (err.code === "EPERM") {
79
+ t.skip("loopback listen is blocked in this sandbox");
80
+ return null;
81
+ }
82
+ throw err;
83
+ }
84
+ const address = server.address();
85
+ assert.ok(address && typeof address === "object");
86
+ return {
87
+ baseUrl: `http://127.0.0.1:${address.port}`,
88
+ close: () => new Promise((resolve, reject) => server.close((err) => err ? reject(err) : resolve())),
89
+ };
90
+ }
91
+ test("postJsonToValidatedGateway rejects when the gateway never responds", async (t) => {
92
+ // Handler that accepts the request but never sends a response — the hung-server case.
93
+ const server = await listenLoopback(t, () => { });
94
+ if (!server)
95
+ return;
96
+ try {
97
+ await assert.rejects(postJsonToValidatedGateway(new URL(`${server.baseUrl}/x`), {}, 200), /timed out after 200ms/);
98
+ }
99
+ finally {
100
+ await server.close();
101
+ }
102
+ });
103
+ test("postJsonToValidatedGateway resolves a fast healthy response before the timeout", async (t) => {
104
+ const server = await listenLoopback(t, (_req, res) => {
105
+ res.writeHead(200, { "content-type": "application/json" });
106
+ res.end("{}");
107
+ });
108
+ if (!server)
109
+ return;
110
+ try {
111
+ const body = await postJsonToValidatedGateway(new URL(`${server.baseUrl}/x`), {}, 200);
112
+ assert.deepEqual(body, {});
113
+ }
114
+ finally {
115
+ await server.close();
116
+ }
117
+ });
118
+ //# sourceMappingURL=cloud-config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-config.test.js","sourceRoot":"","sources":["../src/cloud-config.test.ts"],"names":[],"mappings":"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","sourcesContent":["// Project/App: Open GSD\n// File Purpose: Tests for the cloud gateway config module. Two independent suites:\n// 1. SSRF-guard matrix for parseCloudGatewayUrl / validateGatewayNetworkTarget —\n// loosening any branch (plain-HTTP carve-out, private/loopback IP rejection,\n// protocol/credential/fragment checks) turns a case red.\n// 2. postJsonToValidatedGateway's request timeout — a hung gateway must reject\n// rather than hang the pairing/device flow.\nimport { test } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { createServer, type RequestListener } from \"node:http\";\nimport {\n parseCloudGatewayUrl,\n validateGatewayNetworkTarget,\n postJsonToValidatedGateway,\n} from \"./cloud-config.js\";\n\n// Each rejected case pairs an untrusted input with the substring the guard must\n// report — so a message change is deliberate, not accidental.\nconst REJECTED: Array<{ input: string; message: RegExp }> = [\n // Plain HTTP is only allowed for loopback hosts.\n { input: \"http://evil.example\", message: /only allowed for localhost/ },\n // RFC1918 private ranges over HTTPS.\n { input: \"https://10.0.0.1\", message: /private or loopback/ },\n { input: \"https://192.168.1.1\", message: /private or loopback/ },\n { input: \"https://172.16.0.1\", message: /private or loopback/ },\n // Link-local / cloud metadata endpoint.\n { input: \"https://169.254.169.254\", message: /private or loopback/ },\n // Loopback over HTTPS (IPv4 and IPv6 forms) and the localhost hostname.\n { input: \"https://127.0.0.1\", message: /private or loopback/ },\n { input: \"https://[::1]\", message: /private or loopback/ },\n { input: \"https://localhost\", message: /private or loopback/ },\n // Non-HTTP protocol.\n { input: \"ftp://gateway.example\", message: /must use http or https/ },\n // Embedded credentials / fragments are rejected outright.\n { input: \"https://user:pass@gateway.example\", message: /must not include credentials/ },\n { input: \"https://gateway.example/#frag\", message: /must not include a fragment/ },\n // Unparseable / non-absolute inputs.\n { input: \"\", message: /absolute HTTP\\(S\\) URL/ },\n { input: \"not a url\", message: /absolute HTTP\\(S\\) URL/ },\n];\n\nfor (const { input, message } of REJECTED) {\n test(`parseCloudGatewayUrl rejects ${JSON.stringify(input)}`, () => {\n assert.throws(() => parseCloudGatewayUrl(input), message);\n });\n}\n\n// Accepted: a public HTTPS host and the documented local-dev plain-HTTP loopback carve-out.\nconst ACCEPTED: Array<{ input: string; hostname: string; protocol: string }> = [\n { input: \"https://cloud-gateway.opengsd.net\", hostname: \"cloud-gateway.opengsd.net\", protocol: \"https:\" },\n { input: \"http://localhost:8787\", hostname: \"localhost\", protocol: \"http:\" },\n { input: \"http://127.0.0.1:8787\", hostname: \"127.0.0.1\", protocol: \"http:\" },\n];\n\nfor (const { input, hostname, protocol } of ACCEPTED) {\n test(`parseCloudGatewayUrl accepts ${JSON.stringify(input)}`, () => {\n const url = parseCloudGatewayUrl(input);\n assert.equal(url.hostname, hostname);\n assert.equal(url.protocol, protocol);\n // Round-trips to a usable absolute URL for the same host.\n assert.equal(new URL(url.toString()).hostname, hostname);\n });\n}\n\n// validateGatewayNetworkTarget is the request-time defense-in-depth guard applied to\n// already-constructed URLs (device code/token endpoints). Cover its branches directly.\ntest(\"validateGatewayNetworkTarget rejects private/loopback targets\", () => {\n assert.throws(() => validateGatewayNetworkTarget(new URL(\"https://169.254.169.254\")), /private or loopback/);\n assert.throws(() => validateGatewayNetworkTarget(new URL(\"https://10.0.0.1\")), /private or loopback/);\n assert.throws(() => validateGatewayNetworkTarget(new URL(\"https://[::1]\")), /private or loopback/);\n});\n\ntest(\"validateGatewayNetworkTarget allows a public HTTPS host and http loopback\", () => {\n assert.doesNotThrow(() => validateGatewayNetworkTarget(new URL(\"https://cloud-gateway.opengsd.net\")));\n assert.doesNotThrow(() => validateGatewayNetworkTarget(new URL(\"http://localhost:8787\")));\n assert.doesNotThrow(() => validateGatewayNetworkTarget(new URL(\"http://127.0.0.1:8787\")));\n});\n\n// Start a loopback server, returning its base URL; skips the test under sandbox EPERM.\nasync function listenLoopback(\n t: { skip: (msg: string) => void },\n handler: RequestListener,\n): Promise<{ baseUrl: string; close: () => Promise<void> } | null> {\n const server = createServer(handler);\n try {\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(0, \"127.0.0.1\", resolve);\n });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"EPERM\") {\n t.skip(\"loopback listen is blocked in this sandbox\");\n return null;\n }\n throw err;\n }\n const address = server.address();\n assert.ok(address && typeof address === \"object\");\n return {\n baseUrl: `http://127.0.0.1:${address.port}`,\n close: () => new Promise<void>((resolve, reject) => server.close((err) => err ? reject(err) : resolve())),\n };\n}\n\ntest(\"postJsonToValidatedGateway rejects when the gateway never responds\", async (t) => {\n // Handler that accepts the request but never sends a response — the hung-server case.\n const server = await listenLoopback(t, () => { /* never call res.end */ });\n if (!server) return;\n try {\n await assert.rejects(\n postJsonToValidatedGateway(new URL(`${server.baseUrl}/x`), {}, 200),\n /timed out after 200ms/,\n );\n } finally {\n await server.close();\n }\n});\n\ntest(\"postJsonToValidatedGateway resolves a fast healthy response before the timeout\", async (t) => {\n const server = await listenLoopback(t, (_req, res) => {\n res.writeHead(200, { \"content-type\": \"application/json\" });\n res.end(\"{}\");\n });\n if (!server) return;\n try {\n const body = await postJsonToValidatedGateway(new URL(`${server.baseUrl}/x`), {}, 200);\n assert.deepEqual(body, {});\n } finally {\n await server.close();\n }\n});\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cloud-gateway-lookup.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-gateway-lookup.test.d.ts","sourceRoot":"","sources":["../src/cloud-gateway-lookup.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ // Project/App: Open GSD
2
+ // File Purpose: Regression tests for createGatewayLookup — the custom DNS lookup
3
+ // must honor Node's `all: true` (autoSelectFamily/Happy Eyeballs) array form and
4
+ // still enforce the SSRF guard on every resolved address.
5
+ import { test } from "node:test";
6
+ import assert from "node:assert/strict";
7
+ import { createGatewayLookup } from "./cloud-config.js";
8
+ // Invoke the lookup and capture (err, result) from its Node-style callback.
9
+ function run(url, options) {
10
+ const lookup = createGatewayLookup(new URL(url));
11
+ return new Promise((resolve) => {
12
+ lookup("localhost", options, (...args) => resolve({ err: args[0] ?? null, result: args[1] }));
13
+ });
14
+ }
15
+ test("all:true resolves to an ARRAY for a http loopback URL (regression: was scalar → 'Invalid IP address')", async () => {
16
+ const { err, result } = await run("http://localhost", { all: true, family: 0 });
17
+ assert.equal(err, null, "loopback allowed for http URL");
18
+ assert.ok(Array.isArray(result), "all:true must call back with an array");
19
+ assert.ok(result.length > 0, "expected at least one address");
20
+ for (const entry of result) {
21
+ assert.equal(typeof entry.address, "string");
22
+ assert.ok(entry.family === 4 || entry.family === 6);
23
+ }
24
+ });
25
+ test("all:true REJECTS when a resolved address is private/loopback (SSRF guard, https URL)", async () => {
26
+ const { err } = await run("https://localhost", { all: true, family: 0 });
27
+ assert.ok(err instanceof Error, "expected rejection");
28
+ assert.match(err.message, /private or loopback/);
29
+ });
30
+ test("scalar (all:false) path still guards: https loopback rejected, http loopback allowed", async () => {
31
+ const rejected = await run("https://localhost", { all: false, family: 0 });
32
+ assert.ok(rejected.err instanceof Error, "https loopback rejected in scalar path");
33
+ const allowed = await run("http://localhost", { all: false, family: 0 });
34
+ assert.equal(allowed.err, null, "http loopback allowed in scalar path");
35
+ assert.equal(typeof allowed.result, "string", "scalar path returns a single address");
36
+ });
37
+ //# sourceMappingURL=cloud-gateway-lookup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-gateway-lookup.test.js","sourceRoot":"","sources":["../src/cloud-gateway-lookup.test.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,iFAAiF;AACjF,iFAAiF;AACjF,0DAA0D;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,4EAA4E;AAC5E,SAAS,GAAG,CAAC,GAAW,EAAE,OAAgB;IACxC,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACjD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC5B,MAAoF,CACnF,WAAW,EACX,OAAO,EACP,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAG,IAAI,CAAC,CAAC,CAAkB,IAAI,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAC7F,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,IAAI,CAAC,uGAAuG,EAAE,KAAK,IAAI,EAAE;IACvH,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,kBAAkB,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAChF,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,+BAA+B,CAAC,CAAC;IACzD,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,uCAAuC,CAAC,CAAC;IAC1E,MAAM,CAAC,EAAE,CAAE,MAAoB,CAAC,MAAM,GAAG,CAAC,EAAE,+BAA+B,CAAC,CAAC;IAC7E,KAAK,MAAM,KAAK,IAAI,MAAoD,EAAE,CAAC;QACzE,MAAM,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC7C,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;IACtD,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sFAAsF,EAAE,KAAK,IAAI,EAAE;IACtG,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,GAAG,CAAC,mBAAmB,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IACzE,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY,KAAK,EAAE,oBAAoB,CAAC,CAAC;IACtD,MAAM,CAAC,KAAK,CAAC,GAAI,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sFAAsF,EAAE,KAAK,IAAI,EAAE;IACtG,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,mBAAmB,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3E,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,YAAY,KAAK,EAAE,wCAAwC,CAAC,CAAC;IACnF,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,kBAAkB,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IACzE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,sCAAsC,CAAC,CAAC;IACxE,MAAM,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,sCAAsC,CAAC,CAAC;AACxF,CAAC,CAAC,CAAC","sourcesContent":["// Project/App: Open GSD\n// File Purpose: Regression tests for createGatewayLookup — the custom DNS lookup\n// must honor Node's `all: true` (autoSelectFamily/Happy Eyeballs) array form and\n// still enforce the SSRF guard on every resolved address.\nimport { test } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { createGatewayLookup } from \"./cloud-config.js\";\n\n// Invoke the lookup and capture (err, result) from its Node-style callback.\nfunction run(url: string, options: unknown): Promise<{ err: Error | null; result: unknown }> {\n const lookup = createGatewayLookup(new URL(url));\n return new Promise((resolve) => {\n (lookup as unknown as (h: string, o: unknown, cb: (...a: unknown[]) => void) => void)(\n \"localhost\",\n options,\n (...args: unknown[]) => resolve({ err: (args[0] as Error | null) ?? null, result: args[1] }),\n );\n });\n}\n\ntest(\"all:true resolves to an ARRAY for a http loopback URL (regression: was scalar → 'Invalid IP address')\", async () => {\n const { err, result } = await run(\"http://localhost\", { all: true, family: 0 });\n assert.equal(err, null, \"loopback allowed for http URL\");\n assert.ok(Array.isArray(result), \"all:true must call back with an array\");\n assert.ok((result as unknown[]).length > 0, \"expected at least one address\");\n for (const entry of result as Array<{ address: string; family: number }>) {\n assert.equal(typeof entry.address, \"string\");\n assert.ok(entry.family === 4 || entry.family === 6);\n }\n});\n\ntest(\"all:true REJECTS when a resolved address is private/loopback (SSRF guard, https URL)\", async () => {\n const { err } = await run(\"https://localhost\", { all: true, family: 0 });\n assert.ok(err instanceof Error, \"expected rejection\");\n assert.match(err!.message, /private or loopback/);\n});\n\ntest(\"scalar (all:false) path still guards: https loopback rejected, http loopback allowed\", async () => {\n const rejected = await run(\"https://localhost\", { all: false, family: 0 });\n assert.ok(rejected.err instanceof Error, \"https loopback rejected in scalar path\");\n const allowed = await run(\"http://localhost\", { all: false, family: 0 });\n assert.equal(allowed.err, null, \"http loopback allowed in scalar path\");\n assert.equal(typeof allowed.result, \"string\", \"scalar path returns a single address\");\n});\n"]}
@@ -0,0 +1,35 @@
1
+ import type { Logger } from "./logger.js";
2
+ import type { DaemonConfig } from "./types.js";
3
+ import type { Executor } from "./executors/executor.js";
4
+ export declare class CloudRuntime {
5
+ private readonly cloud;
6
+ private readonly executor;
7
+ private readonly logger;
8
+ private static readonly MAX_OUTBOX;
9
+ private static readonly RECONNECT_DELAY_MS;
10
+ private static readonly MAX_INITIAL_CONNECT_ATTEMPTS;
11
+ private static readonly INITIAL_CONNECT_HANDSHAKE_TIMEOUT_MS;
12
+ private socket;
13
+ private heartbeat;
14
+ private reconnect;
15
+ private readonly inFlight;
16
+ private outbox;
17
+ private stopped;
18
+ private firstConnectDeferred;
19
+ private initialConnectAttempts;
20
+ constructor(cloud: NonNullable<DaemonConfig["cloud"]>, executor: Executor, logger: Logger);
21
+ start(): Promise<void>;
22
+ stop(): void;
23
+ private connect;
24
+ private handleSocketOpen;
25
+ private handleSocketMessage;
26
+ private handleSocketClose;
27
+ private handleSocketError;
28
+ private advertiseProjects;
29
+ private handleMessage;
30
+ private cancelInFlight;
31
+ private resolveFirstConnect;
32
+ private rejectFirstConnect;
33
+ private send;
34
+ }
35
+ //# sourceMappingURL=cloud-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-runtime.d.ts","sourceRoot":"","sources":["../src/cloud-runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAWxD,qBAAa,YAAY;IAoBrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IArBzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAO;IACzC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAMnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,4BAA4B,CAAK;IACzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oCAAoC,CAAU;IACtE,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,oBAAoB,CAAyC;IACrE,OAAO,CAAC,sBAAsB,CAAK;gBAGhB,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,EACzC,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM;IAGjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtB,IAAI,IAAI,IAAI;IAcZ,OAAO,CAAC,OAAO;IAkDf,OAAO,CAAC,gBAAgB;YAmBV,mBAAmB;IAKjC,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,iBAAiB;YAKX,iBAAiB;YAUjB,aAAa;YA6Bb,cAAc;IAqB5B,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,IAAI;CAcb"}