@opengsd/gsd-pi 1.8.1 → 1.9.0

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 (339) hide show
  1. package/README.md +10 -8
  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/flat-phase-migration.js +156 -21
  34. package/dist/resources/extensions/gsd/gsd-db.js +187 -45
  35. package/dist/resources/extensions/gsd/guided-flow.js +29 -10
  36. package/dist/resources/extensions/gsd/markdown-renderer.js +16 -2
  37. package/dist/resources/extensions/gsd/md-importer.js +102 -14
  38. package/dist/resources/extensions/gsd/migrate/command.js +19 -162
  39. package/dist/resources/extensions/gsd/migrate/execution.js +98 -0
  40. package/dist/resources/extensions/gsd/migrate/plan.js +49 -0
  41. package/dist/resources/extensions/gsd/migrate/planning-writer.js +12 -17
  42. package/dist/resources/extensions/gsd/migrate/presentation.js +64 -0
  43. package/dist/resources/extensions/gsd/parallel-eligibility.js +5 -4
  44. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +28 -43
  45. package/dist/resources/extensions/gsd/paths.js +4 -1
  46. package/dist/resources/extensions/gsd/phase-anchor.js +7 -2
  47. package/dist/resources/extensions/gsd/post-execution-checks.js +4 -4
  48. package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  49. package/dist/resources/extensions/gsd/safety/evidence-collector.js +26 -1
  50. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +30 -5
  51. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +27 -13
  52. package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +13 -3
  53. package/dist/resources/extensions/gsd/stop-notice.js +15 -1
  54. package/dist/resources/extensions/gsd/sync-lock.js +13 -7
  55. package/dist/resources/extensions/gsd/tools/complete-task.js +82 -1
  56. package/dist/resources/extensions/gsd/tools/plan-task.js +13 -15
  57. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +18 -15
  58. package/dist/resources/extensions/gsd/tools/replan-task.js +128 -0
  59. package/dist/resources/extensions/gsd/tools/rework-brief.js +74 -0
  60. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +81 -0
  61. package/dist/resources/extensions/gsd/unit-registry.js +4 -0
  62. package/dist/resources/extensions/gsd/uok/plan-v2.js +19 -3
  63. package/dist/resources/extensions/gsd/worktree-state-projection.js +6 -0
  64. package/dist/resources/extensions/mac-tools/index.js +31 -9
  65. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  66. package/dist/web/standalone/.next/BUILD_ID +1 -1
  67. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  68. package/dist/web/standalone/.next/build-manifest.json +2 -2
  69. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  70. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  71. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  80. package/dist/web/standalone/.next/server/app/_not-found.rsc +2 -2
  81. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  82. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  87. package/dist/web/standalone/.next/server/app/index.html +1 -1
  88. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  89. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  91. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  93. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  94. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  96. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  97. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  99. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  100. package/dist/web/standalone/.next/static/css/3b1ceb7abfb9a230.css +1 -0
  101. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  102. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  103. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  104. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  105. package/dist/web/standalone/package.json +0 -1
  106. package/dist/web-mode.js +31 -3
  107. package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
  108. package/integrations/hermes/pyproject.toml +1 -1
  109. package/package.json +12 -10
  110. package/packages/cloud-mcp-gateway/package.json +2 -2
  111. package/packages/contracts/dist/workflow.d.ts +14 -0
  112. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  113. package/packages/contracts/dist/workflow.js +16 -0
  114. package/packages/contracts/dist/workflow.js.map +1 -1
  115. package/packages/contracts/package.json +1 -1
  116. package/packages/daemon/dist/cloud-config.d.ts +1 -1
  117. package/packages/daemon/dist/cloud-config.d.ts.map +1 -1
  118. package/packages/daemon/dist/cloud-config.js +5 -1
  119. package/packages/daemon/dist/cloud-config.js.map +1 -1
  120. package/packages/daemon/dist/cloud-config.test.js +51 -1
  121. package/packages/daemon/dist/cloud-config.test.js.map +1 -1
  122. package/packages/daemon/dist/local-tool-executor.d.ts.map +1 -1
  123. package/packages/daemon/dist/local-tool-executor.js +2 -0
  124. package/packages/daemon/dist/local-tool-executor.js.map +1 -1
  125. package/packages/daemon/package.json +6 -6
  126. package/packages/gsd-agent-core/package.json +5 -5
  127. package/packages/gsd-agent-modes/package.json +7 -7
  128. package/packages/gsd-cloud/dist/cli.d.ts +5 -0
  129. package/packages/gsd-cloud/dist/cli.d.ts.map +1 -0
  130. package/packages/gsd-cloud/dist/cli.js +160 -0
  131. package/packages/gsd-cloud/dist/cli.js.map +1 -0
  132. package/packages/gsd-cloud/dist/cloud-config.d.ts +19 -0
  133. package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -0
  134. package/packages/gsd-cloud/dist/cloud-config.js +231 -0
  135. package/packages/gsd-cloud/dist/cloud-config.js.map +1 -0
  136. package/packages/gsd-cloud/dist/cloud-config.test.d.ts +2 -0
  137. package/packages/gsd-cloud/dist/cloud-config.test.d.ts.map +1 -0
  138. package/packages/gsd-cloud/dist/cloud-config.test.js +118 -0
  139. package/packages/gsd-cloud/dist/cloud-config.test.js.map +1 -0
  140. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts +2 -0
  141. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts.map +1 -0
  142. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js +37 -0
  143. package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js.map +1 -0
  144. package/packages/gsd-cloud/dist/cloud-runtime.d.ts +35 -0
  145. package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -0
  146. package/packages/gsd-cloud/dist/cloud-runtime.js +258 -0
  147. package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -0
  148. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts +2 -0
  149. package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts.map +1 -0
  150. package/packages/gsd-cloud/dist/cloud-runtime.test.js +88 -0
  151. package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -0
  152. package/packages/gsd-cloud/dist/cloud-token.d.ts +3 -0
  153. package/packages/gsd-cloud/dist/cloud-token.d.ts.map +1 -0
  154. package/packages/gsd-cloud/dist/cloud-token.js +37 -0
  155. package/packages/gsd-cloud/dist/cloud-token.js.map +1 -0
  156. package/packages/gsd-cloud/dist/config.d.ts +17 -0
  157. package/packages/gsd-cloud/dist/config.d.ts.map +1 -0
  158. package/packages/gsd-cloud/dist/config.js +146 -0
  159. package/packages/gsd-cloud/dist/config.js.map +1 -0
  160. package/packages/gsd-cloud/dist/device-flow.d.ts +24 -0
  161. package/packages/gsd-cloud/dist/device-flow.d.ts.map +1 -0
  162. package/packages/gsd-cloud/dist/device-flow.js +128 -0
  163. package/packages/gsd-cloud/dist/device-flow.js.map +1 -0
  164. package/packages/gsd-cloud/dist/device-flow.test.d.ts +2 -0
  165. package/packages/gsd-cloud/dist/device-flow.test.d.ts.map +1 -0
  166. package/packages/gsd-cloud/dist/device-flow.test.js +155 -0
  167. package/packages/gsd-cloud/dist/device-flow.test.js.map +1 -0
  168. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts +6 -0
  169. package/packages/gsd-cloud/dist/executors/claude-executor.d.ts.map +1 -0
  170. package/packages/gsd-cloud/dist/executors/claude-executor.js +15 -0
  171. package/packages/gsd-cloud/dist/executors/claude-executor.js.map +1 -0
  172. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts +6 -0
  173. package/packages/gsd-cloud/dist/executors/codex-executor.d.ts.map +1 -0
  174. package/packages/gsd-cloud/dist/executors/codex-executor.js +15 -0
  175. package/packages/gsd-cloud/dist/executors/codex-executor.js.map +1 -0
  176. package/packages/gsd-cloud/dist/executors/executor.d.ts +28 -0
  177. package/packages/gsd-cloud/dist/executors/executor.d.ts.map +1 -0
  178. package/packages/gsd-cloud/dist/executors/executor.js +11 -0
  179. package/packages/gsd-cloud/dist/executors/executor.js.map +1 -0
  180. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts +34 -0
  181. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts.map +1 -0
  182. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js +179 -0
  183. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js.map +1 -0
  184. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts +2 -0
  185. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts.map +1 -0
  186. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js +44 -0
  187. package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js.map +1 -0
  188. package/packages/gsd-cloud/dist/executors/index.d.ts +17 -0
  189. package/packages/gsd-cloud/dist/executors/index.d.ts.map +1 -0
  190. package/packages/gsd-cloud/dist/executors/index.js +29 -0
  191. package/packages/gsd-cloud/dist/executors/index.js.map +1 -0
  192. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts +36 -0
  193. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts.map +1 -0
  194. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js +176 -0
  195. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js.map +1 -0
  196. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts +2 -0
  197. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts.map +1 -0
  198. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js +34 -0
  199. package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js.map +1 -0
  200. package/packages/gsd-cloud/dist/index.d.ts +7 -0
  201. package/packages/gsd-cloud/dist/index.d.ts.map +1 -0
  202. package/packages/gsd-cloud/dist/index.js +8 -0
  203. package/packages/gsd-cloud/dist/index.js.map +1 -0
  204. package/packages/gsd-cloud/dist/inject-gateway.d.ts +16 -0
  205. package/packages/gsd-cloud/dist/inject-gateway.d.ts.map +1 -0
  206. package/packages/gsd-cloud/dist/inject-gateway.js +29 -0
  207. package/packages/gsd-cloud/dist/inject-gateway.js.map +1 -0
  208. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts +2 -0
  209. package/packages/gsd-cloud/dist/inject-gateway.test.d.ts.map +1 -0
  210. package/packages/gsd-cloud/dist/inject-gateway.test.js +41 -0
  211. package/packages/gsd-cloud/dist/inject-gateway.test.js.map +1 -0
  212. package/packages/gsd-cloud/dist/logger.d.ts +25 -0
  213. package/packages/gsd-cloud/dist/logger.d.ts.map +1 -0
  214. package/packages/gsd-cloud/dist/logger.js +72 -0
  215. package/packages/gsd-cloud/dist/logger.js.map +1 -0
  216. package/packages/gsd-cloud/dist/types.d.ts +51 -0
  217. package/packages/gsd-cloud/dist/types.d.ts.map +1 -0
  218. package/packages/gsd-cloud/dist/types.js +9 -0
  219. package/packages/gsd-cloud/dist/types.js.map +1 -0
  220. package/packages/gsd-cloud/package.json +3 -3
  221. package/packages/mcp-server/README.md +8 -0
  222. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  223. package/packages/mcp-server/dist/workflow-tools.js +64 -2
  224. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  225. package/packages/mcp-server/package.json +4 -4
  226. package/packages/native/package.json +1 -1
  227. package/packages/pi-agent-core/package.json +1 -1
  228. package/packages/pi-ai/dist/models.generated.d.ts +60 -0
  229. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  230. package/packages/pi-ai/dist/models.generated.js +54 -0
  231. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  232. package/packages/pi-ai/dist/providers/amazon-bedrock.js +1 -0
  233. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  234. package/packages/pi-ai/dist/providers/anthropic.js +19 -0
  235. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  236. package/packages/pi-ai/package.json +1 -1
  237. package/packages/pi-coding-agent/package.json +7 -7
  238. package/packages/pi-tui/package.json +2 -2
  239. package/packages/rpc-client/package.json +2 -2
  240. package/pkg/package.json +1 -1
  241. package/src/resources/GSD-WORKFLOW.md +16 -47
  242. package/src/resources/extensions/browser-tools/capture.ts +2 -86
  243. package/src/resources/extensions/browser-tools/screenshot-constraints.ts +94 -0
  244. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +18 -1
  245. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -0
  246. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +30 -2
  247. package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
  248. package/src/resources/extensions/gsd/auto-dispatch.ts +86 -19
  249. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -0
  250. package/src/resources/extensions/gsd/auto-prompts.ts +38 -1
  251. package/src/resources/extensions/gsd/auto.ts +5 -1
  252. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +91 -4
  253. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +80 -24
  254. package/src/resources/extensions/gsd/command-feedback.ts +19 -12
  255. package/src/resources/extensions/gsd/compat/compat-marker.ts +21 -4
  256. package/src/resources/extensions/gsd/db/command-queue.ts +7 -1
  257. package/src/resources/extensions/gsd/db/engine.ts +53 -17
  258. package/src/resources/extensions/gsd/db/writers/cascades.ts +5 -1
  259. package/src/resources/extensions/gsd/db/writers/status.ts +25 -8
  260. package/src/resources/extensions/gsd/db-base-schema.ts +30 -0
  261. package/src/resources/extensions/gsd/db-migration-steps.ts +32 -0
  262. package/src/resources/extensions/gsd/db-schema-metadata.ts +4 -1
  263. package/src/resources/extensions/gsd/docs/preferences-reference.md +4 -4
  264. package/src/resources/extensions/gsd/flat-phase-migration.ts +160 -19
  265. package/src/resources/extensions/gsd/gsd-db.ts +255 -52
  266. package/src/resources/extensions/gsd/guided-flow.ts +39 -10
  267. package/src/resources/extensions/gsd/markdown-renderer.ts +23 -7
  268. package/src/resources/extensions/gsd/md-importer.ts +109 -11
  269. package/src/resources/extensions/gsd/migrate/command.ts +21 -227
  270. package/src/resources/extensions/gsd/migrate/execution.ts +136 -0
  271. package/src/resources/extensions/gsd/migrate/plan.ts +101 -0
  272. package/src/resources/extensions/gsd/migrate/planning-writer.ts +12 -20
  273. package/src/resources/extensions/gsd/migrate/presentation.ts +83 -0
  274. package/src/resources/extensions/gsd/parallel-eligibility.ts +5 -4
  275. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +37 -40
  276. package/src/resources/extensions/gsd/paths.ts +4 -1
  277. package/src/resources/extensions/gsd/phase-anchor.ts +8 -2
  278. package/src/resources/extensions/gsd/post-execution-checks.ts +4 -4
  279. package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
  280. package/src/resources/extensions/gsd/safety/evidence-collector.ts +28 -1
  281. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +31 -5
  282. package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +30 -13
  283. package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +16 -3
  284. package/src/resources/extensions/gsd/state-reconciliation/types.ts +2 -2
  285. package/src/resources/extensions/gsd/stop-notice.ts +18 -1
  286. package/src/resources/extensions/gsd/sync-lock.ts +14 -6
  287. package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +96 -1
  288. package/src/resources/extensions/gsd/tests/command-feedback.test.ts +12 -0
  289. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +104 -0
  290. package/src/resources/extensions/gsd/tests/complete-task.test.ts +286 -0
  291. package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +186 -0
  292. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +29 -0
  293. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +123 -0
  294. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +50 -0
  295. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +49 -0
  296. package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +81 -0
  297. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +22 -0
  298. package/src/resources/extensions/gsd/tests/external-edit-scoped-import.test.ts +262 -0
  299. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +202 -0
  300. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +29 -0
  301. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +25 -0
  302. package/src/resources/extensions/gsd/tests/import-slice-milestone-completion-preserve.test.ts +116 -0
  303. package/src/resources/extensions/gsd/tests/migrate-plan.test.ts +68 -0
  304. package/src/resources/extensions/gsd/tests/migrate-presentation.test.ts +98 -0
  305. package/src/resources/extensions/gsd/tests/migrate-safety-audit.test.ts +1 -1
  306. package/src/resources/extensions/gsd/tests/milestone-leases.test.ts +55 -0
  307. package/src/resources/extensions/gsd/tests/parallel-eligibility-file-overlap.test.ts +146 -0
  308. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +59 -0
  309. package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +32 -4
  310. package/src/resources/extensions/gsd/tests/plan-task.test.ts +26 -23
  311. package/src/resources/extensions/gsd/tests/planning-writer.test.ts +29 -0
  312. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +22 -0
  313. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +50 -0
  314. package/src/resources/extensions/gsd/tests/replan-task-handler.test.ts +103 -0
  315. package/src/resources/extensions/gsd/tests/rework-brief.test.ts +197 -0
  316. package/src/resources/extensions/gsd/tests/skip-slice-cascades-tasks.test.ts +21 -0
  317. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +17 -0
  318. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +19 -0
  319. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +34 -0
  320. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +93 -1
  321. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -0
  322. package/src/resources/extensions/gsd/tests/workflow-migration-gates.test.ts +139 -0
  323. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +36 -0
  324. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +52 -0
  325. package/src/resources/extensions/gsd/tools/complete-task.ts +120 -0
  326. package/src/resources/extensions/gsd/tools/plan-task.ts +14 -16
  327. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +18 -17
  328. package/src/resources/extensions/gsd/tools/replan-task.ts +160 -0
  329. package/src/resources/extensions/gsd/tools/rework-brief.ts +91 -0
  330. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +92 -0
  331. package/src/resources/extensions/gsd/types.ts +11 -0
  332. package/src/resources/extensions/gsd/unit-registry.ts +4 -0
  333. package/src/resources/extensions/gsd/uok/plan-v2.ts +20 -3
  334. package/src/resources/extensions/gsd/worktree-state-projection.ts +12 -0
  335. package/src/resources/extensions/mac-tools/index.ts +52 -9
  336. package/src/resources/extensions/mac-tools/tests/mac-screenshot-payload.test.cjs +70 -0
  337. package/dist/web/standalone/.next/static/css/18c2fdf261bfc1b7.css +0 -1
  338. /package/dist/web/standalone/.next/static/{UaXRrOYxBpG9QBINKhZkg → BE5XoklToI6lZjRzpXih8}/_buildManifest.js +0 -0
  339. /package/dist/web/standalone/.next/static/{UaXRrOYxBpG9QBINKhZkg → BE5XoklToI6lZjRzpXih8}/_ssgManifest.js +0 -0
@@ -3,7 +3,8 @@
3
3
  // Parallel to external-markdown-edit.ts. Detects sha drift between the compat
4
4
  // marker's planning.projections/passthrough and current .planning/ files.
5
5
  //
6
- // Modeled files (projections): re-imported via parsePlanningDirectory → DB.
6
+ // Modeled files (projections): re-imported via parsePlanningDirectory → DB,
7
+ // with markdown status authority scoped to their marker entity milestone ids.
7
8
  // Passthrough files (un-modeled docs): sha refreshed, content untouched.
8
9
 
9
10
  import { existsSync, readFileSync } from "node:fs";
@@ -148,13 +149,25 @@ async function repairExternalPlanningEdit(
148
149
  const { parsePlanningDirectory } = await import("../../migrate/parser.js");
149
150
  const { transformToGSD } = await import("../../migrate/transformer.js");
150
151
  const { writeGSDDirectory } = await import("../../migrate/writer.js");
151
- const { migrateHierarchyToDb } = await import("../../md-importer.js");
152
+ const { migrateHierarchyToDb, milestoneIdsFromEntities } = await import("../../md-importer.js");
152
153
  const { invalidateStateCache } = await import("../../state.js");
153
154
 
154
155
  const parsed = await parsePlanningDirectory(join(ctx.basePath, ".planning"));
155
156
  const gsdProject = transformToGSD(parsed);
156
157
  await writeGSDDirectory(gsdProject, ctx.basePath);
157
- migrateHierarchyToDb(ctx.basePath);
158
+ // #027: scope status authority to the milestone(s) this drifted .planning/
159
+ // file projects (first `/`-segment of its DB entity ids), so a stale
160
+ // checkbox in an unrelated projection can't revert a reopened slice/milestone
161
+ // in the DB. Unseeded files carry no entities → empty set → preserve DB
162
+ // status everywhere (fail toward the DB, log the breadcrumb).
163
+ const statusAuthoritativeMilestones = milestoneIdsFromEntities(record.entities);
164
+ if (statusAuthoritativeMilestones.size === 0) {
165
+ logWarning(
166
+ "reconcile",
167
+ `external-planning-edit: no milestone scope resolved for ${record.projectionPath}; preserving DB status for all milestones`,
168
+ );
169
+ }
170
+ migrateHierarchyToDb(ctx.basePath, { statusAuthoritativeMilestones });
158
171
  invalidateStateCache();
159
172
  } catch (err) {
160
173
  logWarning(
@@ -49,14 +49,14 @@ export type DriftRecord =
49
49
  projectionPath: string; // relative to basePath, e.g. "m1/plan.md"
50
50
  expectedSha: string; // sha recorded in .compat.json
51
51
  actualSha: string; // freshly computed from disk
52
- entities: string[]; // DB entity ids to re-import
52
+ entities: string[]; // DB entity ids used to scope status authority
53
53
  }
54
54
  | {
55
55
  kind: "external-planning-edit";
56
56
  projectionPath: string; // relative to .planning/, e.g. "phases/01-foo/01-01-PLAN.md"
57
57
  expectedSha: string;
58
58
  actualSha: string;
59
- entities: string[];
59
+ entities: string[]; // DB entity ids used to scope status authority
60
60
  passthrough: boolean; // true = content-only, no re-import, just refresh sha
61
61
  };
62
62
 
@@ -66,10 +66,27 @@ export function isNonBlockingPauseNotice(message: string): boolean {
66
66
  return message.includes("idempotent advance: unit already active");
67
67
  }
68
68
 
69
+ /**
70
+ * A picker / next-action menu that could not render in a non-interactive
71
+ * (headless / RPC) session. Both wordings originate from the menu-unavailable
72
+ * helpers (`notifyCommandMenuUnavailable` and `notifyPickerCommandNeedsInteractiveMenu`
73
+ * in next-action-ui.ts / command-feedback.ts). Headless `auto`/`next` cannot
74
+ * answer such a menu, so the run has dead-ended and needs operator intervention.
75
+ * Classify it as blocked so the headless host exits 10 instead of idling
76
+ * forever waiting for a completion signal that never comes. (#1294)
77
+ */
78
+ export function isInteractiveMenuUnavailableNotice(message: string): boolean {
79
+ return (
80
+ message.includes("menu could not be shown in this session") ||
81
+ message.includes("did not start:")
82
+ );
83
+ }
84
+
69
85
  export function isBlockedNoticeMessage(message: string): boolean {
70
86
  return (
71
87
  message.includes("blocked:") ||
72
88
  (isPauseNotice(message) && !isNonBlockingPauseNotice(message)) ||
73
- isManualResolutionNotice(message)
89
+ isManualResolutionNotice(message) ||
90
+ isInteractiveMenuUnavailableNotice(message)
74
91
  );
75
92
  }
@@ -9,8 +9,10 @@ import { dirname, join } from "node:path";
9
9
  const STALE_THRESHOLD_MS = 60_000; // 60 seconds
10
10
  const DEFAULT_TIMEOUT_MS = 0; // fail fast; sync waits block the JS event loop
11
11
 
12
- function lockFilePath(basePath: string): string {
13
- return join(basePath, ".gsd", "sync.lock");
12
+ const DEFAULT_LOCK_NAME = "sync.lock";
13
+
14
+ function lockFilePath(basePath: string, lockName: string = DEFAULT_LOCK_NAME): string {
15
+ return join(basePath, ".gsd", lockName);
14
16
  }
15
17
 
16
18
  /** True if the given PID is alive in the current process namespace. */
@@ -74,8 +76,9 @@ function tryCreateLockFile(lp: string, payload: string): boolean {
74
76
  export function acquireSyncLock(
75
77
  basePath: string,
76
78
  _timeoutMs: number = DEFAULT_TIMEOUT_MS,
79
+ lockName: string = DEFAULT_LOCK_NAME,
77
80
  ): { acquired: boolean } {
78
- const lp = lockFilePath(basePath);
81
+ const lp = lockFilePath(basePath, lockName);
79
82
  const lockData = JSON.stringify(
80
83
  { pid: process.pid, acquired_at: new Date().toISOString() },
81
84
  null,
@@ -89,7 +92,12 @@ export function acquireSyncLock(
89
92
  return { acquired: true };
90
93
  }
91
94
  } catch {
92
- /* unexpected fall through to retry */
95
+ // tryCreateLockFile only throws for non-EEXIST errors — a persistently
96
+ // uncreatable lock path (dangling-symlink parent, ENOTDIR, read-only FS).
97
+ // Retrying would spin the loop forever with no progress condition,
98
+ // blocking the JS event loop. Fail open like a contended lock so callers
99
+ // proceed (racy but functional) instead of hanging.
100
+ return { acquired: false };
93
101
  }
94
102
 
95
103
  // File exists. Decide whether to steal (stale + owner dead) or skip.
@@ -131,8 +139,8 @@ export function acquireSyncLock(
131
139
  /**
132
140
  * Release the advisory sync lock. No-op if lock file does not exist.
133
141
  */
134
- export function releaseSyncLock(basePath: string): void {
135
- const lp = lockFilePath(basePath);
142
+ export function releaseSyncLock(basePath: string, lockName: string = DEFAULT_LOCK_NAME): void {
143
+ const lp = lockFilePath(basePath, lockName);
136
144
  try {
137
145
  if (existsSync(lp)) {
138
146
  unlinkSync(lp);
@@ -3,8 +3,14 @@
3
3
 
4
4
  import test from "node:test";
5
5
  import assert from "node:assert/strict";
6
+ import { writeFileSync } from "node:fs";
7
+ import { join } from "node:path";
6
8
 
7
- import { shouldDeferCloseoutGitAction } from "../auto-post-unit.ts";
9
+ import { postUnitPreVerification, shouldDeferCloseoutGitAction, type PostUnitContext } from "../auto-post-unit.ts";
10
+ import { AutoSession } from "../auto/session.ts";
11
+ import { closeDatabase, insertMilestone, insertSlice, insertTask, insertVerificationEvidence, openDatabase } from "../gsd-db.ts";
12
+ import { recordToolCall, recordToolResult, resetEvidence } from "../safety/evidence-collector.ts";
13
+ import { cleanup, git, makeTempRepo } from "./test-utils.ts";
8
14
 
9
15
  test("execute-task defers closeout git action until verification passes", () => {
10
16
  assert.equal(shouldDeferCloseoutGitAction("execute-task"), true);
@@ -14,3 +20,92 @@ test("non execute-task units keep pre-verification closeout git action", () => {
14
20
  assert.equal(shouldDeferCloseoutGitAction("plan-slice"), false);
15
21
  assert.equal(shouldDeferCloseoutGitAction("complete-slice"), false);
16
22
  });
23
+
24
+ test("blocking evidence-xref commits deferred execute-task work before pausing", async () => {
25
+ const base = makeTempRepo("gsd-evidence-xref-commit-before-pause-");
26
+
27
+ try {
28
+ writeFileSync(join(base, ".gitignore"), ".gsd/\n");
29
+ git(base, "add", ".gitignore");
30
+ git(base, "commit", "-m", "chore: ignore gsd runtime");
31
+
32
+ openDatabase(":memory:");
33
+ insertMilestone({ id: "M001", title: "Milestone", status: "active" });
34
+ insertSlice({ id: "S01", milestoneId: "M001", title: "Slice", status: "active" });
35
+ insertTask({
36
+ id: "T01",
37
+ sliceId: "S01",
38
+ milestoneId: "M001",
39
+ title: "Add app entrypoint",
40
+ status: "complete",
41
+ oneLiner: "Added app entrypoint",
42
+ keyFiles: ["app.js"],
43
+ planning: {
44
+ description: "Create app entrypoint",
45
+ estimate: "small",
46
+ files: ["app.js"],
47
+ verify: "npm test",
48
+ inputs: [],
49
+ expectedOutput: ["app.js"],
50
+ observabilityImpact: "none",
51
+ },
52
+ });
53
+ insertVerificationEvidence({
54
+ taskId: "T01",
55
+ sliceId: "S01",
56
+ milestoneId: "M001",
57
+ command: "npm test",
58
+ exitCode: 0,
59
+ verdict: "passed",
60
+ durationMs: 10,
61
+ });
62
+
63
+ writeFileSync(join(base, "app.js"), "console.log('ready');\n");
64
+ resetEvidence();
65
+ recordToolCall("call-1", "bash", { command: "npm test" });
66
+ recordToolResult("call-1", "bash", "Command exited with code 1\nfailed\n", true);
67
+
68
+ const s = new AutoSession();
69
+ s.active = true;
70
+ s.basePath = base;
71
+ s.currentUnit = { type: "execute-task", id: "M001/S01/T01", startedAt: Date.now() };
72
+
73
+ let pauseCalled = false;
74
+ const notifications: string[] = [];
75
+ const pctx: PostUnitContext = {
76
+ s,
77
+ ctx: {
78
+ ui: { notify: (message: string) => notifications.push(message) },
79
+ } as unknown as PostUnitContext["ctx"],
80
+ pi: {} as PostUnitContext["pi"],
81
+ buildSnapshotOpts: () => ({}),
82
+ lockBase: () => base,
83
+ stopAuto: async () => {},
84
+ pauseAuto: async () => {
85
+ pauseCalled = true;
86
+ assert.equal(git(base, "status", "--short"), "", "task work must be committed before pauseAuto runs");
87
+ },
88
+ updateProgressWidget: () => {},
89
+ };
90
+
91
+ const result = await postUnitPreVerification(pctx, {
92
+ skipSettleDelay: true,
93
+ skipWorktreeSync: true,
94
+ });
95
+
96
+ assert.equal(result, "dispatched");
97
+ assert.equal(pauseCalled, true);
98
+ assert.ok(
99
+ notifications.some((message) => message.includes("claimed passing verification")),
100
+ `expected evidence-xref notification, got: ${notifications.join("\n")}`,
101
+ );
102
+
103
+ const commitMessage = git(base, "log", "-1", "--pretty=%B");
104
+ assert.match(commitMessage, /^feat: Added app entrypoint/m);
105
+ assert.match(commitMessage, /GSD-Task: S01\/T01/);
106
+ } finally {
107
+ resetEvidence();
108
+ closeDatabase();
109
+ cleanup(base);
110
+ }
111
+ });
@@ -11,6 +11,7 @@ import {
11
11
  notifySmartEntryNeedsInteractiveMenu,
12
12
  requiresInteractiveMenu,
13
13
  } from "../command-feedback.js";
14
+ import { isBlockedNoticeMessage, isInteractiveMenuUnavailableNotice } from "../stop-notice.js";
14
15
  import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
15
16
 
16
17
  function makeCtx(overrides: {
@@ -87,6 +88,17 @@ describe("notifyQueueHubNeedsInteractiveMenu", () => {
87
88
  assert.match(notes[0]!.message, /\/gsd queue/);
88
89
  assert.match(notes[0]!.message, /reorder/i);
89
90
  });
91
+
92
+ // /gsd queue continues headless with the add-work flow after this notice, so
93
+ // it must NOT be classified as a blocked dead-end (would exit 10 early). (#1294)
94
+ it("emits a notice the headless host does not treat as a dead-end", () => {
95
+ const ctx = makeCtx({ hasUI: false });
96
+ notifyQueueHubNeedsInteractiveMenu(ctx, "this session has no interactive menu");
97
+ const notes = (ctx as typeof ctx & { _notifications: Array<{ message: string }> })._notifications;
98
+ const message = notes[0]!.message.toLowerCase();
99
+ assert.equal(isInteractiveMenuUnavailableNotice(message), false);
100
+ assert.equal(isBlockedNoticeMessage(message), false);
101
+ });
90
102
  });
91
103
 
92
104
  describe("notifyInitNeedsInteractiveMenu", () => {
@@ -16,6 +16,9 @@ import {
16
16
  EMPTY_MARKER,
17
17
  compatMarkerPath,
18
18
  } from "../compat/compat-marker.ts";
19
+ import { externalMarkdownEditHandler } from "../state-reconciliation/drift/external-markdown-edit.ts";
20
+ import type { DriftContext } from "../state-reconciliation/types.ts";
21
+ import type { GSDState } from "../types.ts";
19
22
 
20
23
  const tmpDirs: string[] = [];
21
24
 
@@ -188,3 +191,104 @@ test("pruneOrphanedProjectionEntries returns 0 and writes nothing when marker is
188
191
  const files = readdirSync(join(base, ".gsd"));
189
192
  assert.ok(!files.includes(".compat.json"), "must not create a marker where none existed");
190
193
  });
194
+
195
+ // --- Path-traversal containment (plan 029) ---------------------------------
196
+ //
197
+ // The marker is repo-controlled content whose projection-map keys are joined
198
+ // with basePath and readFileSync'd by the drift detectors. A key that escapes
199
+ // .gsd/ must invalidate the whole marker so readCompatMarker fails safe to the
200
+ // empty marker (detectors see no entries → nothing outside the repo is read).
201
+
202
+ for (const badKey of ["../outside.md", "/etc/hosts", "C:/x.md", "..\\x.md"]) {
203
+ test(`readCompatMarker rejects a projection key that escapes the root: ${JSON.stringify(badKey)}`, () => {
204
+ const base = makeTmpBase();
205
+ // Write the hostile marker directly (writeCompatMarker does not validate).
206
+ writeCompatMarker(base, {
207
+ schema: 2,
208
+ lastWriter: "gsd-pi",
209
+ lastProjectedAt: "2026-07-07T00:00:00.000Z",
210
+ projections: { [badKey]: { sha: "deadbeefdeadbeef", entities: ["m1"] } },
211
+ piVersion: "1.8.1",
212
+ });
213
+
214
+ const marker = readCompatMarker(base);
215
+ assert.equal(
216
+ Object.keys(marker.projections).length,
217
+ 0,
218
+ "a marker with an escaping key must fall back to the empty marker",
219
+ );
220
+ });
221
+ }
222
+
223
+ test("readCompatMarker preserves legitimate nested projection keys", () => {
224
+ const base = makeTmpBase();
225
+ const roadmap = "milestones/M001/M001-ROADMAP.md";
226
+ const context = "phases/01-foo/01-CONTEXT.md";
227
+ writeCompatMarker(base, {
228
+ schema: 2,
229
+ lastWriter: "gsd-pi",
230
+ lastProjectedAt: "2026-07-07T00:00:00.000Z",
231
+ projections: {
232
+ [roadmap]: { sha: "aaaaaaaaaaaaaaaa", entities: ["M001"] },
233
+ [context]: { sha: "bbbbbbbbbbbbbbbb", entities: ["P01"] },
234
+ },
235
+ planning: { active: false, layout: null, projections: {}, passthrough: {} },
236
+ piVersion: "1.8.1",
237
+ });
238
+
239
+ const marker = readCompatMarker(base);
240
+ assert.ok(marker.projections[roadmap], "roadmap key must round-trip");
241
+ assert.ok(marker.projections[context], "nested phase key must round-trip");
242
+ assert.equal(Object.keys(marker.projections).length, 2);
243
+ });
244
+
245
+ test("an escaping key in planning.passthrough also invalidates the whole marker", () => {
246
+ const base = makeTmpBase();
247
+ writeCompatMarker(base, {
248
+ schema: 2,
249
+ lastWriter: "gsd-pi",
250
+ lastProjectedAt: "2026-07-07T00:00:00.000Z",
251
+ projections: {},
252
+ planning: {
253
+ active: true,
254
+ layout: "flat-phases",
255
+ projections: {},
256
+ passthrough: { "../../secret.md": { sha: "cccccccccccccccc", entities: [] } },
257
+ },
258
+ piVersion: "1.8.1",
259
+ });
260
+
261
+ const marker = readCompatMarker(base);
262
+ assert.equal(Object.keys(marker.projections).length, 0);
263
+ assert.equal(marker.planning!.active, false, "planning falls back to inactive default");
264
+ });
265
+
266
+ test("hostile marker makes the drift detector read nothing outside the project", async () => {
267
+ const base = makeTmpBase();
268
+ // Sentinel lives OUTSIDE the project dir; a `../` traversal from .gsd/ would
269
+ // reach it if the key were trusted.
270
+ const sentinelDir = mkdtempSync(join(tmpdir(), `gsd-sentinel-${randomUUID()}`));
271
+ tmpDirs.push(sentinelDir);
272
+ const sentinelName = "known_hosts";
273
+ writeFileSync(join(sentinelDir, sentinelName), "SECRET\n", "utf-8");
274
+ const escapeKey = `../../${sentinelName}`; // e.g. ../../known_hosts
275
+
276
+ writeCompatMarker(base, {
277
+ schema: 2,
278
+ lastWriter: "gsd-pi",
279
+ lastProjectedAt: "2026-07-07T00:00:00.000Z",
280
+ projections: { [escapeKey]: { sha: "0000000000000000", entities: ["m1"] } },
281
+ piVersion: "1.8.1",
282
+ });
283
+
284
+ const stubState = { phase: "idle" } as unknown as GSDState;
285
+ const ctx: DriftContext = { basePath: base, state: stubState };
286
+
287
+ // Must not throw and must not emit a record referencing the sentinel.
288
+ const drift = await externalMarkdownEditHandler.detect(stubState, ctx);
289
+ assert.equal(drift.length, 0, "no drift record from a rejected hostile marker");
290
+ assert.ok(
291
+ !drift.some((d) => d.projectionPath.includes(sentinelName)),
292
+ "detector must not reference the out-of-project sentinel",
293
+ );
294
+ });