@opengsd/gsd-pi 1.4.0 → 1.5.0-dev.553dc518

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 (606) hide show
  1. package/README.md +11 -11
  2. package/dist/onboarding.js +11 -0
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/GSD-WORKFLOW.md +20 -25
  5. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +118 -53
  6. package/dist/resources/extensions/cursor-cli/index.js +16 -0
  7. package/dist/resources/extensions/cursor-cli/models.js +63 -0
  8. package/dist/resources/extensions/cursor-cli/package.json +11 -0
  9. package/dist/resources/extensions/cursor-cli/readiness.js +128 -0
  10. package/dist/resources/extensions/cursor-cli/stream-adapter.js +353 -0
  11. package/dist/resources/extensions/gsd/activity-log.js +4 -1
  12. package/dist/resources/extensions/gsd/artifact-verification.js +25 -9
  13. package/dist/resources/extensions/gsd/auto/closeout.js +137 -42
  14. package/dist/resources/extensions/gsd/auto/finalize.js +9 -0
  15. package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -3
  16. package/dist/resources/extensions/gsd/auto/pre-dispatch.js +6 -3
  17. package/dist/resources/extensions/gsd/auto/run-unit.js +5 -2
  18. package/dist/resources/extensions/gsd/auto/schedule-wakeup.js +3 -0
  19. package/dist/resources/extensions/gsd/auto/unit-phase.js +5 -9
  20. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +4 -5
  21. package/dist/resources/extensions/gsd/auto-dispatch.js +15 -5
  22. package/dist/resources/extensions/gsd/auto-model-selection.js +36 -18
  23. package/dist/resources/extensions/gsd/auto-prompts.js +76 -2
  24. package/dist/resources/extensions/gsd/auto-start.js +7 -5
  25. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +4 -0
  26. package/dist/resources/extensions/gsd/auto-worktree-branch-lifecycle.js +189 -0
  27. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +133 -0
  28. package/dist/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.js +35 -0
  29. package/dist/resources/extensions/gsd/auto-worktree-creation.js +130 -0
  30. package/dist/resources/extensions/gsd/auto-worktree-entry.js +118 -0
  31. package/dist/resources/extensions/gsd/auto-worktree-merge-already-merged.js +98 -0
  32. package/dist/resources/extensions/gsd/auto-worktree-merge-branch-head.js +52 -0
  33. package/dist/resources/extensions/gsd/auto-worktree-merge-cleanup.js +87 -0
  34. package/dist/resources/extensions/gsd/auto-worktree-merge-code-changes.js +46 -0
  35. package/dist/resources/extensions/gsd/auto-worktree-merge-db-ready.js +68 -0
  36. package/dist/resources/extensions/gsd/auto-worktree-merge-integration-branch.js +51 -0
  37. package/dist/resources/extensions/gsd/auto-worktree-merge-message.js +106 -0
  38. package/dist/resources/extensions/gsd/auto-worktree-merge-pre-teardown.js +64 -0
  39. package/dist/resources/extensions/gsd/auto-worktree-merge-stash.js +168 -0
  40. package/dist/resources/extensions/gsd/auto-worktree-merge.js +302 -0
  41. package/dist/resources/extensions/gsd/auto-worktree-milestone-shelter.js +119 -0
  42. package/dist/resources/extensions/gsd/auto-worktree-path-resolution.js +5 -0
  43. package/dist/resources/extensions/gsd/auto-worktree-path-utils.js +5 -0
  44. package/dist/resources/extensions/gsd/auto-worktree-resource-version.js +41 -0
  45. package/dist/resources/extensions/gsd/auto-worktree-runtime-cleanup.js +99 -0
  46. package/dist/resources/extensions/gsd/auto-worktree-session-registry.js +57 -0
  47. package/dist/resources/extensions/gsd/auto-worktree-sync.js +249 -0
  48. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +120 -0
  49. package/dist/resources/extensions/gsd/auto-worktree.js +20 -2046
  50. package/dist/resources/extensions/gsd/auto.js +31 -5
  51. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -0
  52. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -1
  53. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +133 -6
  54. package/dist/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.js +58 -9
  55. package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
  56. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +127 -22
  57. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +14 -1
  58. package/dist/resources/extensions/gsd/codebase-generator.js +157 -19
  59. package/dist/resources/extensions/gsd/commands/handlers/core.js +40 -4
  60. package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
  61. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +153 -1
  62. package/dist/resources/extensions/gsd/commands-workflow-templates.js +3 -3
  63. package/dist/resources/extensions/gsd/commands-worktree.js +11 -2
  64. package/dist/resources/extensions/gsd/db/queries.js +48 -9
  65. package/dist/resources/extensions/gsd/discussion-handoff.js +8 -3
  66. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -2
  67. package/dist/resources/extensions/gsd/doctor-engine-checks.js +292 -18
  68. package/dist/resources/extensions/gsd/doctor-providers.js +38 -10
  69. package/dist/resources/extensions/gsd/doctor.js +93 -3
  70. package/dist/resources/extensions/gsd/exec-sandbox.js +6 -2
  71. package/dist/resources/extensions/gsd/flat-phase-migration.js +88 -26
  72. package/dist/resources/extensions/gsd/forensics.js +1 -1
  73. package/dist/resources/extensions/gsd/git-conflict-resolve.js +2 -2
  74. package/dist/resources/extensions/gsd/git-service.js +59 -18
  75. package/dist/resources/extensions/gsd/gsd-db.js +63 -0
  76. package/dist/resources/extensions/gsd/guidance.js +1 -0
  77. package/dist/resources/extensions/gsd/guided-flow.js +46 -12
  78. package/dist/resources/extensions/gsd/key-manager.js +1 -0
  79. package/dist/resources/extensions/gsd/markdown-renderer.js +40 -11
  80. package/dist/resources/extensions/gsd/migrate-external.js +24 -7
  81. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +14 -3
  82. package/dist/resources/extensions/gsd/milestone-settlement.js +1 -1
  83. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  84. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -1
  85. package/dist/resources/extensions/gsd/preferences-diagnostics.js +24 -1
  86. package/dist/resources/extensions/gsd/preferences-models.js +6 -4
  87. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  88. package/dist/resources/extensions/gsd/preferences-validation.js +107 -2
  89. package/dist/resources/extensions/gsd/preferences.js +29 -2
  90. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -2
  91. package/dist/resources/extensions/gsd/prompts/system.md +6 -6
  92. package/dist/resources/extensions/gsd/quick.js +12 -3
  93. package/dist/resources/extensions/gsd/redact-secrets.js +37 -0
  94. package/dist/resources/extensions/gsd/repo-identity.js +16 -0
  95. package/dist/resources/extensions/gsd/repository-registry.js +6 -1
  96. package/dist/resources/extensions/gsd/root-write-leak-guard.js +4 -2
  97. package/dist/resources/extensions/gsd/safe-fs.js +23 -2
  98. package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
  99. package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -0
  100. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +2 -1
  101. package/dist/resources/extensions/gsd/state/derive/from-db.js +88 -153
  102. package/dist/resources/extensions/gsd/tool-contract.js +14 -0
  103. package/dist/resources/extensions/gsd/tools/plan-task.js +76 -8
  104. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +40 -0
  105. package/dist/resources/extensions/gsd/unit-context-manifest.js +5 -4
  106. package/dist/resources/extensions/gsd/unit-registry.js +37 -2
  107. package/dist/resources/extensions/gsd/unit-runtime.js +21 -0
  108. package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +1 -1
  109. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -1
  110. package/dist/resources/extensions/gsd/workspace-git-preflight.js +2 -2
  111. package/dist/resources/extensions/gsd/workspace.js +26 -8
  112. package/dist/resources/extensions/gsd/worktree-command.js +1 -1
  113. package/dist/resources/extensions/gsd/worktree-lifecycle.js +81 -14
  114. package/dist/resources/extensions/gsd/worktree-manager.js +97 -4
  115. package/dist/resources/extensions/gsd/worktree-reentry.js +2 -1
  116. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  117. package/dist/web/standalone/.next/BUILD_ID +1 -1
  118. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  119. package/dist/web/standalone/.next/build-manifest.json +3 -3
  120. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  121. package/dist/web/standalone/.next/required-server-files.json +3 -3
  122. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  123. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  125. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  133. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  135. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  136. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  137. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  139. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  149. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  161. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  183. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  193. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  199. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  202. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  203. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  204. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  205. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  206. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  207. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  209. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  210. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  211. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  212. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  213. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  214. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  215. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  216. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  217. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  218. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  219. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  220. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  221. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  222. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  223. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  224. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  225. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  226. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  227. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  228. package/dist/web/standalone/.next/server/app/index.html +1 -1
  229. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  230. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  231. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  232. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  233. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  234. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  235. package/dist/web/standalone/.next/server/app/page.js +2 -2
  236. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  237. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  238. package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
  239. package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
  240. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  241. package/dist/web/standalone/.next/server/middleware.js +3 -3
  242. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  243. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  244. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  245. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
  246. package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
  247. package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
  248. package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
  249. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
  250. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  251. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  252. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  253. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  254. package/dist/web/standalone/server.js +1 -1
  255. package/dist/wizard.d.ts +8 -0
  256. package/dist/wizard.js +8 -1
  257. package/integrations/hermes/CONTEXT.md +47 -0
  258. package/integrations/hermes/README.md +21 -0
  259. package/integrations/hermes/__init__.py +31 -0
  260. package/integrations/hermes/docs/issue-1162-grilling.md +197 -0
  261. package/integrations/hermes/docs/setup.md +4 -0
  262. package/integrations/hermes/open_gsd_hermes/commands.py +141 -0
  263. package/integrations/hermes/open_gsd_hermes/config.py +2 -0
  264. package/integrations/hermes/open_gsd_hermes/gsd_client.py +591 -39
  265. package/integrations/hermes/open_gsd_hermes/notifications.py +10 -1
  266. package/integrations/hermes/plugin.yaml +4 -0
  267. package/integrations/hermes/tests/test_config.py +6 -0
  268. package/integrations/hermes/tests/test_directory_loader.py +37 -0
  269. package/integrations/hermes/tests/test_gsd_client_cache.py +3 -0
  270. package/integrations/hermes/tests/test_gsd_client_execute.py +35 -0
  271. package/integrations/hermes/tests/test_gsd_client_process_cwd.py +22 -0
  272. package/integrations/hermes/tests/test_gsd_client_timeout.py +98 -0
  273. package/integrations/hermes/tests/test_milestone_client.py +447 -0
  274. package/integrations/hermes/tests/test_new_milestone_command.py +313 -0
  275. package/integrations/hermes/tests/test_supervisor_fsm.py +40 -0
  276. package/package.json +8 -8
  277. package/packages/cloud-mcp-gateway/dist/auth-store.d.ts +1 -0
  278. package/packages/cloud-mcp-gateway/dist/auth-store.d.ts.map +1 -1
  279. package/packages/cloud-mcp-gateway/dist/auth-store.js +21 -1
  280. package/packages/cloud-mcp-gateway/dist/auth-store.js.map +1 -1
  281. package/packages/cloud-mcp-gateway/dist/auth-store.test.js +34 -0
  282. package/packages/cloud-mcp-gateway/dist/auth-store.test.js.map +1 -1
  283. package/packages/cloud-mcp-gateway/package.json +2 -2
  284. package/packages/contracts/package.json +1 -1
  285. package/packages/daemon/dist/cloud-runtime.d.ts +2 -0
  286. package/packages/daemon/dist/cloud-runtime.d.ts.map +1 -1
  287. package/packages/daemon/dist/cloud-runtime.js +25 -1
  288. package/packages/daemon/dist/cloud-runtime.js.map +1 -1
  289. package/packages/daemon/dist/cloud-runtime.test.js +51 -0
  290. package/packages/daemon/dist/cloud-runtime.test.js.map +1 -1
  291. package/packages/daemon/dist/message-batcher.d.ts +7 -0
  292. package/packages/daemon/dist/message-batcher.d.ts.map +1 -1
  293. package/packages/daemon/dist/message-batcher.js +13 -0
  294. package/packages/daemon/dist/message-batcher.js.map +1 -1
  295. package/packages/daemon/dist/message-batcher.test.js +48 -0
  296. package/packages/daemon/dist/message-batcher.test.js.map +1 -1
  297. package/packages/daemon/dist/session-manager.js +1 -1
  298. package/packages/daemon/dist/session-manager.js.map +1 -1
  299. package/packages/daemon/package.json +5 -5
  300. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts +13 -1
  301. package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
  302. package/packages/gsd-agent-core/dist/compaction/compaction.js +15 -1
  303. package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
  304. package/packages/gsd-agent-core/dist/export-html/template.js +53 -4
  305. package/packages/gsd-agent-core/dist/session/agent-session-navigation.d.ts.map +1 -1
  306. package/packages/gsd-agent-core/dist/session/agent-session-navigation.js +4 -1
  307. package/packages/gsd-agent-core/dist/session/agent-session-navigation.js.map +1 -1
  308. package/packages/gsd-agent-core/package.json +5 -5
  309. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  310. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +3 -2
  311. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  312. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -1
  313. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +1 -0
  314. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -1
  315. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js +1 -1
  316. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js.map +1 -1
  317. package/packages/gsd-agent-modes/package.json +7 -7
  318. package/packages/mcp-server/dist/server.d.ts +18 -5
  319. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  320. package/packages/mcp-server/dist/server.js +46 -5
  321. package/packages/mcp-server/dist/server.js.map +1 -1
  322. package/packages/mcp-server/dist/session-manager.js +1 -1
  323. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  324. package/packages/mcp-server/package.json +4 -4
  325. package/packages/native/package.json +1 -1
  326. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  327. package/packages/pi-agent-core/dist/agent-loop.js +14 -9
  328. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  329. package/packages/pi-agent-core/package.json +1 -1
  330. package/packages/pi-ai/dist/env-api-keys.d.ts.map +1 -1
  331. package/packages/pi-ai/dist/env-api-keys.js +3 -0
  332. package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
  333. package/packages/pi-ai/dist/index.d.ts +1 -0
  334. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  335. package/packages/pi-ai/dist/index.js +1 -0
  336. package/packages/pi-ai/dist/index.js.map +1 -1
  337. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  338. package/packages/pi-ai/dist/providers/transform-messages.js +7 -3
  339. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  340. package/packages/pi-ai/dist/tool-result-content.d.ts +3 -0
  341. package/packages/pi-ai/dist/tool-result-content.d.ts.map +1 -0
  342. package/packages/pi-ai/dist/tool-result-content.js +62 -0
  343. package/packages/pi-ai/dist/tool-result-content.js.map +1 -0
  344. package/packages/pi-ai/dist/types.d.ts +10 -22
  345. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  346. package/packages/pi-ai/dist/types.js.map +1 -1
  347. package/packages/pi-ai/package.json +1 -1
  348. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  349. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
  350. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  351. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +1 -0
  352. package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -1
  353. package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -1
  354. package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  355. package/packages/pi-coding-agent/dist/core/session-manager.js +3 -0
  356. package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  357. package/packages/pi-coding-agent/package.json +7 -7
  358. package/packages/pi-tui/package.json +2 -2
  359. package/packages/rpc-client/dist/rpc-client.js +1 -1
  360. package/packages/rpc-client/dist/rpc-client.js.map +1 -1
  361. package/packages/rpc-client/package.json +2 -2
  362. package/pkg/dist/core/export-html/template.js +53 -4
  363. package/pkg/package.json +1 -1
  364. package/scripts/link-workspace-packages.cjs +14 -4
  365. package/src/resources/GSD-WORKFLOW.md +20 -25
  366. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +130 -51
  367. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +371 -39
  368. package/src/resources/extensions/cursor-cli/index.ts +18 -0
  369. package/src/resources/extensions/cursor-cli/models.ts +65 -0
  370. package/src/resources/extensions/cursor-cli/package.json +11 -0
  371. package/src/resources/extensions/cursor-cli/readiness.ts +143 -0
  372. package/src/resources/extensions/cursor-cli/stream-adapter.ts +440 -0
  373. package/src/resources/extensions/cursor-cli/tests/index.test.ts +54 -0
  374. package/src/resources/extensions/cursor-cli/tests/readiness.test.ts +29 -0
  375. package/src/resources/extensions/cursor-cli/tests/stream-adapter.test.ts +166 -0
  376. package/src/resources/extensions/gsd/activity-log.ts +4 -1
  377. package/src/resources/extensions/gsd/artifact-verification.ts +25 -9
  378. package/src/resources/extensions/gsd/auto/closeout.ts +163 -58
  379. package/src/resources/extensions/gsd/auto/finalize.ts +8 -0
  380. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
  381. package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -3
  382. package/src/resources/extensions/gsd/auto/pre-dispatch.ts +6 -3
  383. package/src/resources/extensions/gsd/auto/run-unit.ts +5 -2
  384. package/src/resources/extensions/gsd/auto/schedule-wakeup.ts +8 -0
  385. package/src/resources/extensions/gsd/auto/unit-phase.ts +5 -9
  386. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +4 -5
  387. package/src/resources/extensions/gsd/auto-dispatch.ts +17 -5
  388. package/src/resources/extensions/gsd/auto-model-selection.ts +49 -18
  389. package/src/resources/extensions/gsd/auto-prompts.ts +73 -2
  390. package/src/resources/extensions/gsd/auto-start.ts +8 -5
  391. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +4 -0
  392. package/src/resources/extensions/gsd/auto-worktree-branch-lifecycle.ts +237 -0
  393. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +166 -0
  394. package/src/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.ts +37 -0
  395. package/src/resources/extensions/gsd/auto-worktree-creation.ts +171 -0
  396. package/src/resources/extensions/gsd/auto-worktree-entry.ts +154 -0
  397. package/src/resources/extensions/gsd/auto-worktree-merge-already-merged.ts +161 -0
  398. package/src/resources/extensions/gsd/auto-worktree-merge-branch-head.ts +83 -0
  399. package/src/resources/extensions/gsd/auto-worktree-merge-cleanup.ts +132 -0
  400. package/src/resources/extensions/gsd/auto-worktree-merge-code-changes.ts +71 -0
  401. package/src/resources/extensions/gsd/auto-worktree-merge-db-ready.ts +112 -0
  402. package/src/resources/extensions/gsd/auto-worktree-merge-integration-branch.ts +99 -0
  403. package/src/resources/extensions/gsd/auto-worktree-merge-message.ts +166 -0
  404. package/src/resources/extensions/gsd/auto-worktree-merge-pre-teardown.ts +93 -0
  405. package/src/resources/extensions/gsd/auto-worktree-merge-stash.ts +213 -0
  406. package/src/resources/extensions/gsd/auto-worktree-merge.ts +391 -0
  407. package/src/resources/extensions/gsd/auto-worktree-milestone-shelter.ts +159 -0
  408. package/src/resources/extensions/gsd/auto-worktree-path-resolution.ts +6 -0
  409. package/src/resources/extensions/gsd/auto-worktree-path-utils.ts +10 -0
  410. package/src/resources/extensions/gsd/auto-worktree-resource-version.ts +44 -0
  411. package/src/resources/extensions/gsd/auto-worktree-runtime-cleanup.ts +119 -0
  412. package/src/resources/extensions/gsd/auto-worktree-session-registry.ts +71 -0
  413. package/src/resources/extensions/gsd/auto-worktree-sync.ts +370 -0
  414. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +161 -0
  415. package/src/resources/extensions/gsd/auto-worktree.ts +69 -2390
  416. package/src/resources/extensions/gsd/auto.ts +32 -19
  417. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -0
  418. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -1
  419. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +147 -6
  420. package/src/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.ts +80 -12
  421. package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
  422. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +163 -22
  423. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +23 -1
  424. package/src/resources/extensions/gsd/codebase-generator.ts +179 -18
  425. package/src/resources/extensions/gsd/commands/handlers/core.ts +39 -3
  426. package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
  427. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +135 -1
  428. package/src/resources/extensions/gsd/commands-workflow-templates.ts +3 -3
  429. package/src/resources/extensions/gsd/commands-worktree.ts +13 -2
  430. package/src/resources/extensions/gsd/db/queries.ts +49 -9
  431. package/src/resources/extensions/gsd/discussion-handoff.ts +10 -2
  432. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -2
  433. package/src/resources/extensions/gsd/doctor-engine-checks.ts +372 -22
  434. package/src/resources/extensions/gsd/doctor-providers.ts +39 -10
  435. package/src/resources/extensions/gsd/doctor-types.ts +5 -1
  436. package/src/resources/extensions/gsd/doctor.ts +95 -3
  437. package/src/resources/extensions/gsd/exec-sandbox.ts +6 -2
  438. package/src/resources/extensions/gsd/flat-phase-migration.ts +112 -25
  439. package/src/resources/extensions/gsd/forensics.ts +1 -1
  440. package/src/resources/extensions/gsd/git-conflict-resolve.ts +2 -2
  441. package/src/resources/extensions/gsd/git-service.ts +67 -17
  442. package/src/resources/extensions/gsd/gsd-db.ts +85 -0
  443. package/src/resources/extensions/gsd/guidance.ts +2 -0
  444. package/src/resources/extensions/gsd/guided-flow.ts +52 -13
  445. package/src/resources/extensions/gsd/key-manager.ts +1 -0
  446. package/src/resources/extensions/gsd/markdown-renderer.ts +40 -10
  447. package/src/resources/extensions/gsd/migrate-external.ts +23 -6
  448. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +19 -4
  449. package/src/resources/extensions/gsd/milestone-settlement.ts +1 -1
  450. package/src/resources/extensions/gsd/model-router.ts +4 -5
  451. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  452. package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -1
  453. package/src/resources/extensions/gsd/preferences-diagnostics.ts +24 -0
  454. package/src/resources/extensions/gsd/preferences-models.ts +6 -3
  455. package/src/resources/extensions/gsd/preferences-types.ts +30 -0
  456. package/src/resources/extensions/gsd/preferences-validation.ts +97 -2
  457. package/src/resources/extensions/gsd/preferences.ts +38 -4
  458. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -2
  459. package/src/resources/extensions/gsd/prompts/system.md +6 -6
  460. package/src/resources/extensions/gsd/quick.ts +11 -3
  461. package/src/resources/extensions/gsd/redact-secrets.ts +40 -0
  462. package/src/resources/extensions/gsd/repo-identity.ts +17 -0
  463. package/src/resources/extensions/gsd/repository-registry.ts +7 -1
  464. package/src/resources/extensions/gsd/root-write-leak-guard.ts +3 -2
  465. package/src/resources/extensions/gsd/safe-fs.ts +22 -2
  466. package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
  467. package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -0
  468. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +3 -1
  469. package/src/resources/extensions/gsd/state/derive/from-db.ts +201 -157
  470. package/src/resources/extensions/gsd/tests/auto-loop-no-copy-artifacts.test.ts +2 -1
  471. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +131 -5
  472. package/src/resources/extensions/gsd/tests/auto-migrating-recovery.test.ts +18 -0
  473. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +178 -0
  474. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +43 -1
  475. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +54 -0
  476. package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +41 -0
  477. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +41 -0
  478. package/src/resources/extensions/gsd/tests/auto-session-scope.test.ts +4 -4
  479. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +3 -0
  480. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +1 -1
  481. package/src/resources/extensions/gsd/tests/auto-timeout-recovery-harness-abort.test.ts +55 -0
  482. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +10 -1
  483. package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +1 -1
  484. package/src/resources/extensions/gsd/tests/auto-worktree-merge-already-merged.test.ts +177 -0
  485. package/src/resources/extensions/gsd/tests/auto-worktree-merge-branch-head.test.ts +118 -0
  486. package/src/resources/extensions/gsd/tests/auto-worktree-merge-cleanup.test.ts +115 -0
  487. package/src/resources/extensions/gsd/tests/auto-worktree-merge-code-changes.test.ts +76 -0
  488. package/src/resources/extensions/gsd/tests/auto-worktree-merge-db-ready.test.ts +140 -0
  489. package/src/resources/extensions/gsd/tests/auto-worktree-merge-integration-branch.test.ts +123 -0
  490. package/src/resources/extensions/gsd/tests/auto-worktree-merge-message.test.ts +114 -0
  491. package/src/resources/extensions/gsd/tests/auto-worktree-merge-pre-teardown.test.ts +84 -0
  492. package/src/resources/extensions/gsd/tests/auto-worktree-merge-stash.test.ts +70 -0
  493. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-shelter.test.ts +52 -0
  494. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +6 -6
  495. package/src/resources/extensions/gsd/tests/auto-worktree-resource-version.test.ts +59 -0
  496. package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +3 -1
  497. package/src/resources/extensions/gsd/tests/batch-task-query.test.ts +85 -0
  498. package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +29 -0
  499. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +365 -0
  500. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +62 -1
  501. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +1 -1
  502. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -0
  503. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +138 -1
  504. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +571 -5
  505. package/src/resources/extensions/gsd/tests/doctor-workspace.test.ts +207 -0
  506. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +1 -1
  507. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +82 -2
  508. package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +25 -1
  509. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +87 -19
  510. package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +89 -0
  511. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +40 -0
  512. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +9 -0
  513. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +4 -6
  514. package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +2 -1
  515. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +3 -3
  516. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +7 -8
  517. package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +2 -5
  518. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +76 -0
  519. package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +1 -1
  520. package/src/resources/extensions/gsd/tests/integration/merge-preserve-worktree-on-preteardown-error.test.ts +1 -1
  521. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +2 -1
  522. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +5 -7
  523. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
  524. package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +2 -4
  525. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +122 -0
  526. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +1 -1
  527. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +4 -4
  528. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +1 -1
  529. package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +1 -1
  530. package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +116 -0
  531. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +592 -23
  532. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +25 -1
  533. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +1 -1
  534. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -3
  535. package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +1 -1
  536. package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +2 -2
  537. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +50 -6
  538. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +17 -0
  539. package/src/resources/extensions/gsd/tests/plan-task.test.ts +264 -1
  540. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +1 -4
  541. package/src/resources/extensions/gsd/tests/preferences.test.ts +150 -0
  542. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +147 -0
  543. package/src/resources/extensions/gsd/tests/recovery-verify-logs.test.ts +4 -4
  544. package/src/resources/extensions/gsd/tests/redact-secrets.test.ts +56 -0
  545. package/src/resources/extensions/gsd/tests/register-hooks-flat-phase-migration.test.ts +73 -0
  546. package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +275 -0
  547. package/src/resources/extensions/gsd/tests/repository-registry.test.ts +41 -2
  548. package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +55 -0
  549. package/src/resources/extensions/gsd/tests/root-write-leak-guard.test.ts +31 -9
  550. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +20 -0
  551. package/src/resources/extensions/gsd/tests/schedule-wakeup-tool.test.ts +167 -0
  552. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -5
  553. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -0
  554. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +2 -1
  555. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +2 -1
  556. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -1
  557. package/src/resources/extensions/gsd/tests/status-per-repo.test.ts +94 -0
  558. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +1 -1
  559. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +1 -1
  560. package/src/resources/extensions/gsd/tests/system-flat-phase-layout.test.ts +33 -0
  561. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +4 -4
  562. package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +2 -1
  563. package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +4 -4
  564. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +35 -0
  565. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +166 -0
  566. package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +1 -1
  567. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +66 -18
  568. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +81 -0
  569. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +30 -0
  570. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +52 -0
  571. package/src/resources/extensions/gsd/tests/validator-scope-parity.test.ts +53 -1
  572. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +208 -1
  573. package/src/resources/extensions/gsd/tests/workspace.test.ts +18 -4
  574. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -1
  575. package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +1 -1
  576. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +1 -3
  577. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +1 -1
  578. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +1 -1
  579. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +4 -4
  580. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +2 -2
  581. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +1 -1
  582. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +1 -1
  583. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +2 -1
  584. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +36 -3
  585. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +1 -1
  586. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +1 -1
  587. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +32 -0
  588. package/src/resources/extensions/gsd/tool-contract.ts +29 -0
  589. package/src/resources/extensions/gsd/tools/plan-task.ts +107 -9
  590. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +58 -0
  591. package/src/resources/extensions/gsd/unit-context-manifest.ts +11 -5
  592. package/src/resources/extensions/gsd/unit-registry.ts +48 -2
  593. package/src/resources/extensions/gsd/unit-runtime.ts +42 -0
  594. package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +1 -1
  595. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -1
  596. package/src/resources/extensions/gsd/workspace-git-preflight.ts +2 -2
  597. package/src/resources/extensions/gsd/workspace.ts +42 -8
  598. package/src/resources/extensions/gsd/worktree-command.ts +1 -1
  599. package/src/resources/extensions/gsd/worktree-lifecycle.ts +154 -26
  600. package/src/resources/extensions/gsd/worktree-manager.ts +143 -5
  601. package/src/resources/extensions/gsd/worktree-reentry.ts +2 -1
  602. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
  603. package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
  604. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
  605. /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → ZpFDazP-38PXBPiI_LdZf}/_buildManifest.js +0 -0
  606. /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → ZpFDazP-38PXBPiI_LdZf}/_ssgManifest.js +0 -0
@@ -21,27 +21,117 @@
21
21
  * signature, so the identical-args streak never trips, while allowing
22
22
  * tool-heavy turns that are making file-mutation progress. Whichever guard
23
23
  * trips first blocks.
24
+ *
25
+ * Thresholds, exempt tools, and enable flags are user-tunable (#1198) via the
26
+ * `tool_call_loop_guard` key in `.gsd/PREFERENCES.md` and `GSD_TOOL_LOOP_*`
27
+ * environment variables, applied through {@link configureToolCallLoopGuard}.
28
+ * Defaults preserve the original hardcoded behavior.
24
29
  */
25
30
  import { createHash } from "node:crypto";
26
31
  import { INHERENTLY_REPEATABLE_TOOL_SET } from "./core-session-tools.js";
27
- const MAX_CONSECUTIVE_IDENTICAL_CALLS = 4;
32
+ import { hasBrowserContractPrefix } from "../../shared/browser-contract.js";
33
+ import { canonicalToolName } from "../engine-hook-contract.js";
34
+ /** Built-in defaults. Preserved when preferences/env do not override them. */
35
+ const DEFAULT_MAX_CONSECUTIVE_IDENTICAL_CALLS = 4;
36
+ const DEFAULT_PER_TOOL_DEFAULT_CAP = 6;
37
+ const DEFAULT_PER_TOOL_REPEATABLE_CAP = 15;
38
+ const DEFAULT_PER_TOOL_CAP_EXEMPT_TOOLS = ["find", "glob", "grep", "ls", "read", "search_and_read"];
28
39
  /** Interactive/user-facing tools where even 1 duplicate is confusing. */
29
40
  const STRICT_LOOP_TOOLS = new Set(["ask_user_questions"]);
30
41
  const MAX_CONSECUTIVE_STRICT = 1;
42
+ const STATE_MUTATING_TOOL_SET = new Set(["edit", "write", "multi_edit", "notebook_edit"]);
43
+ function defaultGuardConfig() {
44
+ return {
45
+ guardEnabled: true,
46
+ identicalEnabled: true,
47
+ maxConsecutiveIdentical: DEFAULT_MAX_CONSECUTIVE_IDENTICAL_CALLS,
48
+ repeatedEnabled: true,
49
+ perToolDefaultCap: DEFAULT_PER_TOOL_DEFAULT_CAP,
50
+ perToolRepeatableCap: DEFAULT_PER_TOOL_REPEATABLE_CAP,
51
+ perToolExempt: new Set(DEFAULT_PER_TOOL_CAP_EXEMPT_TOOLS),
52
+ };
53
+ }
54
+ let config = defaultGuardConfig();
55
+ /** Parse a positive-integer env var, returning undefined when unset/invalid. */
56
+ function envPositiveInt(name) {
57
+ const raw = process.env[name];
58
+ if (raw === undefined || raw.trim() === "")
59
+ return undefined;
60
+ const n = Number(raw);
61
+ return Number.isFinite(n) && n >= 1 ? Math.floor(n) : undefined;
62
+ }
63
+ /** Parse a boolean env var (`true`/`1` vs `false`/`0`), undefined when unset. */
64
+ function envBool(name) {
65
+ const raw = process.env[name];
66
+ if (raw === undefined || raw.trim() === "")
67
+ return undefined;
68
+ const v = raw.trim().toLowerCase();
69
+ if (v === "true" || v === "1" || v === "yes" || v === "on")
70
+ return true;
71
+ if (v === "false" || v === "0" || v === "no" || v === "off")
72
+ return false;
73
+ return undefined;
74
+ }
75
+ /** Parse a comma-separated tool-name list env var. */
76
+ function envToolList(name) {
77
+ const raw = process.env[name];
78
+ if (!raw)
79
+ return [];
80
+ return raw.split(",").map((s) => s.trim()).filter(Boolean);
81
+ }
31
82
  /**
32
- * Per-turn cap on calls to the SAME tool name, regardless of args (#783).
83
+ * Resolve preferences + environment overrides into the active configuration.
84
+ * Environment variables win over preferences; preferences win over built-in
85
+ * defaults. User-supplied exempt tools are additive to the built-in exempt
86
+ * set so defaults are always preserved.
33
87
  *
34
- * General-purpose execution tools are routinely called many times per turn
35
- * (touching multiple files, running several commands), so they get a higher
36
- * ceiling. Everything else — workflow one-shot tools (e.g. gsd_complete_milestone)
37
- * and any non-allowlisted tool — gets the default cap. The default is generous
38
- * enough to absorb legitimate retries but catches the reported improvisation
39
- * loop (~51 calls) well before a cost spike.
88
+ * Applied to both interactive sessions and `/gsd auto` (called from the
89
+ * session_start / session_switch hooks).
40
90
  */
41
- const PER_TOOL_DEFAULT_CAP = 6;
42
- const PER_TOOL_REPEATABLE_CAP = 15;
43
- const PER_TOOL_CAP_EXEMPT_TOOLS = new Set(["find", "glob", "grep", "ls", "read", "search_and_read"]);
44
- const STATE_MUTATING_TOOL_SET = new Set(["edit", "write", "multi_edit", "notebook_edit"]);
91
+ export function configureToolCallLoopGuard(prefs) {
92
+ const next = defaultGuardConfig();
93
+ if (prefs) {
94
+ if (typeof prefs.enabled === "boolean")
95
+ next.guardEnabled = prefs.enabled;
96
+ if (prefs.identical_args) {
97
+ if (typeof prefs.identical_args.enabled === "boolean")
98
+ next.identicalEnabled = prefs.identical_args.enabled;
99
+ if (typeof prefs.identical_args.max_consecutive_calls === "number" && prefs.identical_args.max_consecutive_calls >= 1) {
100
+ next.maxConsecutiveIdentical = Math.floor(prefs.identical_args.max_consecutive_calls);
101
+ }
102
+ }
103
+ if (prefs.repeated_tool) {
104
+ if (typeof prefs.repeated_tool.enabled === "boolean")
105
+ next.repeatedEnabled = prefs.repeated_tool.enabled;
106
+ if (typeof prefs.repeated_tool.default_cap === "number" && prefs.repeated_tool.default_cap >= 1) {
107
+ next.perToolDefaultCap = Math.floor(prefs.repeated_tool.default_cap);
108
+ }
109
+ if (typeof prefs.repeated_tool.repeatable_cap === "number" && prefs.repeated_tool.repeatable_cap >= 1) {
110
+ next.perToolRepeatableCap = Math.floor(prefs.repeated_tool.repeatable_cap);
111
+ }
112
+ for (const tool of prefs.repeated_tool.exempt_tools ?? []) {
113
+ if (typeof tool === "string" && tool.trim())
114
+ next.perToolExempt.add(tool.trim());
115
+ }
116
+ }
117
+ }
118
+ // Environment overrides (win over preferences).
119
+ const envEnabled = envBool("GSD_TOOL_LOOP_GUARD_ENABLED");
120
+ if (envEnabled !== undefined)
121
+ next.guardEnabled = envEnabled;
122
+ const envIdenticalMax = envPositiveInt("GSD_TOOL_LOOP_IDENTICAL_MAX");
123
+ if (envIdenticalMax !== undefined)
124
+ next.maxConsecutiveIdentical = envIdenticalMax;
125
+ const envDefaultCap = envPositiveInt("GSD_TOOL_LOOP_REPEATED_DEFAULT_CAP");
126
+ if (envDefaultCap !== undefined)
127
+ next.perToolDefaultCap = envDefaultCap;
128
+ const envRepeatableCap = envPositiveInt("GSD_TOOL_LOOP_REPEATED_REPEATABLE_CAP");
129
+ if (envRepeatableCap !== undefined)
130
+ next.perToolRepeatableCap = envRepeatableCap;
131
+ for (const tool of envToolList("GSD_TOOL_LOOP_EXEMPT_TOOLS"))
132
+ next.perToolExempt.add(tool);
133
+ config = next;
134
+ }
45
135
  let consecutiveCount = 0;
46
136
  let lastSignature = "";
47
137
  let lastToolName = "";
@@ -70,14 +160,17 @@ function hashToolCall(toolName, args) {
70
160
  * Returns `{ block: true, reason }` when the loop threshold is exceeded.
71
161
  *
72
162
  * Two independent guards run; whichever trips first blocks:
73
- * 1. Identical-signature streak (MAX_CONSECUTIVE_IDENTICAL_CALLS, strict for
163
+ * 1. Identical-signature streak (config.maxConsecutiveIdentical, strict for
74
164
  * ask_user_questions).
75
- * 2. Per-tool-name cap (PER_TOOL_DEFAULT_CAP / PER_TOOL_REPEATABLE_CAP),
165
+ * 2. Per-tool-name cap (config.perToolDefaultCap / config.perToolRepeatableCap),
76
166
  * independent of args, reset after file-mutation progress — catches
77
167
  * improvisation loops (#783).
168
+ *
169
+ * Both guards, their thresholds, and the per-tool exempt set are user-tunable
170
+ * via {@link configureToolCallLoopGuard} (#1198).
78
171
  */
79
172
  export function checkToolCallLoop(toolName, args) {
80
- if (!enabled)
173
+ if (!enabled || !config.guardEnabled)
81
174
  return { block: false, count: 0 };
82
175
  const sig = hashToolCall(toolName, args);
83
176
  if (sig === lastSignature) {
@@ -91,12 +184,14 @@ export function checkToolCallLoop(toolName, args) {
91
184
  // ── Guard 1: identical-signature streak ──
92
185
  const threshold = STRICT_LOOP_TOOLS.has(toolName)
93
186
  ? MAX_CONSECUTIVE_STRICT
94
- : MAX_CONSECUTIVE_IDENTICAL_CALLS;
95
- if (consecutiveCount > threshold) {
187
+ : config.maxConsecutiveIdentical;
188
+ if (config.identicalEnabled && consecutiveCount > threshold) {
96
189
  return {
97
190
  block: true,
98
191
  reason: `Tool loop detected (identical args): ${toolName} called ${consecutiveCount} times ` +
99
- `with identical arguments. Blocking to prevent infinite loop. ` +
192
+ `with identical arguments (max ${threshold}). Blocking to prevent infinite loop. ` +
193
+ `Raise tool_call_loop_guard.identical_args.max_consecutive_calls in .gsd/PREFERENCES.md ` +
194
+ `(or GSD_TOOL_LOOP_IDENTICAL_MAX) if this is expected. ` +
100
195
  `Do not retry this tool or call other tools this turn — stop and respond to the user in text.`,
101
196
  count: consecutiveCount,
102
197
  };
@@ -111,19 +206,29 @@ export function checkToolCallLoop(toolName, args) {
111
206
  perToolCounts.set(toolName, perToolCount);
112
207
  perToolLastMutationEpoch.set(toolName, mutationEpoch);
113
208
  // Read-only navigation tools are normal context gathering; Guard 1 still
114
- // catches true reread loops with identical arguments.
115
- if (PER_TOOL_CAP_EXEMPT_TOOLS.has(toolName)) {
209
+ // catches true reread loops with identical arguments. Browser Automation
210
+ // Contract tools (browser_*) are the same shape: a browser-backed UAT makes
211
+ // many distinct-arg calls (read a message, count edits, inspect a card, …),
212
+ // so the arg-independent per-tool cap misfires on legitimate verification;
213
+ // Guard 1's identical-signature streak still catches a genuinely stuck
214
+ // browser loop.
215
+ if (!config.repeatedEnabled ||
216
+ config.perToolExempt.has(toolName) ||
217
+ hasBrowserContractPrefix(canonicalToolName(toolName))) {
116
218
  return { block: false, count: consecutiveCount };
117
219
  }
118
220
  const perToolCap = INHERENTLY_REPEATABLE_TOOL_SET.has(toolName)
119
- ? PER_TOOL_REPEATABLE_CAP
120
- : PER_TOOL_DEFAULT_CAP;
221
+ ? config.perToolRepeatableCap
222
+ : config.perToolDefaultCap;
121
223
  if (perToolCount > perToolCap) {
122
224
  return {
123
225
  block: true,
124
226
  reason: `Tool loop detected (repeated tool): ${toolName} called ${perToolCount} times ` +
125
227
  `this turn (cap ${perToolCap}). Blocking to prevent infinite loop. ` +
126
228
  `The tool may be unavailable or failing repeatedly. ` +
229
+ `Raise tool_call_loop_guard.repeated_tool.default_cap/repeatable_cap or add "${toolName}" ` +
230
+ `to tool_call_loop_guard.repeated_tool.exempt_tools in .gsd/PREFERENCES.md ` +
231
+ `(or GSD_TOOL_LOOP_REPEATED_* / GSD_TOOL_LOOP_EXEMPT_TOOLS) if this is expected. ` +
127
232
  `Do not retry this tool or pivot to other tools this turn — stop and respond to the user in text.`,
128
233
  count: perToolCount,
129
234
  };
@@ -947,7 +947,7 @@ function allowedPlanningDispatchAgentsList() {
947
947
  return [...ALLOWED_PLANNING_DISPATCH_AGENTS].join(", ");
948
948
  }
949
949
  function allowsControlledSubagentDispatch(policy) {
950
- return ((policy.mode === "planning-dispatch" || policy.mode === "verification") &&
950
+ return ((policy.mode === "planning-dispatch" || policy.mode === "verification" || policy.mode === "workflow-only") &&
951
951
  Array.isArray(policy.allowedSubagents));
952
952
  }
953
953
  function warnMissingControlledDispatchAgentClasses(unitType, mode, toolName) {
@@ -975,6 +975,7 @@ function warnMissingControlledDispatchAgentClasses(unitType, mode, toolName) {
975
975
  const PLANNING_SAFE_TOOLS = new Set([
976
976
  "read", "grep", "find", "ls", "glob",
977
977
  "ask_user_questions",
978
+ "memory_query",
978
979
  "search-the-web", "resolve_library", "get_library_docs", "fetch_page",
979
980
  "search_and_read",
980
981
  ]);
@@ -1031,6 +1032,9 @@ function planningBlock(unitType, mode, what) {
1031
1032
  * → allows Bash for project verification commands, keeps
1032
1033
  * writes restricted to .gsd/, and permits subagent dispatch
1033
1034
  * only when the manifest declares allowedSubagents.
1035
+ * - "workflow-only"
1036
+ * → allows reads, GSD workflow tools, and declared read-only
1037
+ * subagents; blocks generic Bash and direct file writes.
1034
1038
  *
1035
1039
  * `pathOrCommand` is the file path for write/edit-shaped tools and the
1036
1040
  * shell command for bash. Other tools ignore this argument.
@@ -1101,6 +1105,15 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
1101
1105
  }
1102
1106
  return planningBlock(unitType, policy.mode, "subagent dispatch is not permitted in planning units");
1103
1107
  }
1108
+ if (policy.mode === "workflow-only") {
1109
+ if (tool === "bash") {
1110
+ return planningBlock(unitType, policy.mode, `bash is not permitted; use the unit's dedicated GSD workflow tools for durable validation output`);
1111
+ }
1112
+ if (PLANNING_WRITE_TOOLS.has(tool)) {
1113
+ return planningBlock(unitType, policy.mode, `cannot ${tool} "${pathOrCommand}" — direct artifact writes are disabled; call the required GSD workflow tool instead`);
1114
+ }
1115
+ return planningBlock(unitType, policy.mode, `tool "${tool}" is not on the workflow-only allowlist`);
1116
+ }
1104
1117
  if (tool === "bash") {
1105
1118
  if (policy.mode === "verification") {
1106
1119
  if (BASH_VERIFICATION_RE.test(pathOrCommand) || BASH_READ_ONLY_RE.test(pathOrCommand))
@@ -9,9 +9,11 @@
9
9
  */
10
10
  import { createHash } from "node:crypto";
11
11
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
12
- import { join, dirname, extname } from "node:path";
12
+ import { join, dirname, extname, relative, sep } from "node:path";
13
13
  import { execSync } from "node:child_process";
14
14
  import { gsdRoot } from "./paths.js";
15
+ import { createRepositoryRegistryFromPreferences, } from "./repository-registry.js";
16
+ import { loadEffectiveGSDPreferences } from "./preferences.js";
15
17
  // ─── Defaults ────────────────────────────────────────────────────────────────
16
18
  const DEFAULT_EXCLUDES = [
17
19
  // ── AI / tooling meta ──
@@ -144,6 +146,84 @@ function enumerateFiles(basePath, excludes, maxFiles) {
144
146
  const truncated = filtered.length > maxFiles;
145
147
  return { files: truncated ? filtered.slice(0, maxFiles) : filtered, truncated };
146
148
  }
149
+ /**
150
+ * Build a workspace-aware registry for parent mode, or null when the project is
151
+ * single-repo (no declared child repositories). Returns null so the caller falls
152
+ * back to the legacy single-root enumeration and produces byte-identical output.
153
+ */
154
+ function loadWorkspaceRegistry(basePath) {
155
+ const preferences = loadEffectiveGSDPreferences(basePath)?.preferences;
156
+ const workspace = preferences?.workspace;
157
+ const mode = workspace?.mode ?? "project";
158
+ // Parent mode is only meaningful with at least one declared child repo; the
159
+ // implicit "project" repo is always present, so require a declared non-project id.
160
+ const hasDeclaredChildRepo = workspace?.repositories
161
+ ? Object.keys(workspace.repositories).some((id) => id !== "project")
162
+ : false;
163
+ if (mode !== "parent" || !hasDeclaredChildRepo) {
164
+ return null;
165
+ }
166
+ return createRepositoryRegistryFromPreferences(basePath, preferences);
167
+ }
168
+ /** Stable key fragment for workspace-aware enumeration inputs (mode + declared repos). */
169
+ function workspaceEnumerationSignature(basePath) {
170
+ const registry = loadWorkspaceRegistry(basePath);
171
+ if (!registry)
172
+ return "single-root";
173
+ return JSON.stringify({
174
+ mode: registry.mode,
175
+ repositories: registry.repositories
176
+ .map((repo) => ({ id: repo.id, root: repo.root }))
177
+ .sort((a, b) => a.id.localeCompare(b.id)),
178
+ });
179
+ }
180
+ /**
181
+ * Enumerate tracked files across every declared repository in a parent workspace.
182
+ * Child-repo paths are rewritten to be workspace-relative (e.g. `frontend/src/x`)
183
+ * and tagged with their declaring repo id so the map can render repo-labelled
184
+ * sections. The maxFiles cap is applied across the union of all repositories.
185
+ */
186
+ function enumerateWorkspaceFiles(registry, excludes, maxFiles) {
187
+ const perRepo = [];
188
+ const seen = new Set();
189
+ let totalEligible = 0;
190
+ for (const repo of registry.repositories) {
191
+ const rawFiles = lsFiles(repo.root);
192
+ const repoPrefix = relative(registry.projectRoot, repo.root).split(sep).join("/");
193
+ const repoEntries = [];
194
+ for (const file of rawFiles) {
195
+ // Rewrite before exclusion so workspace-relative patterns (e.g. frontend/…) apply.
196
+ const workspacePath = repoPrefix ? `${repoPrefix}/${file}` : file;
197
+ if (shouldExclude(workspacePath, excludes))
198
+ continue;
199
+ if (seen.has(workspacePath))
200
+ continue;
201
+ seen.add(workspacePath);
202
+ totalEligible++;
203
+ repoEntries.push({ workspacePath, repoId: repo.id });
204
+ }
205
+ perRepo.push(repoEntries);
206
+ }
207
+ const files = [];
208
+ const repos = [];
209
+ const indices = new Array(perRepo.length).fill(0);
210
+ while (files.length < maxFiles) {
211
+ let progressed = false;
212
+ for (let i = 0; i < perRepo.length; i++) {
213
+ if (indices[i] < perRepo[i].length) {
214
+ const entry = perRepo[i][indices[i]++];
215
+ files.push(entry.workspacePath);
216
+ repos.push(entry.repoId);
217
+ progressed = true;
218
+ if (files.length >= maxFiles)
219
+ break;
220
+ }
221
+ }
222
+ if (!progressed)
223
+ break;
224
+ }
225
+ return { files, repos, truncated: totalEligible > files.length };
226
+ }
147
227
  function resolveGeneratorOptions(options) {
148
228
  const excludes = [...DEFAULT_EXCLUDES, ...(options?.excludePatterns ?? [])];
149
229
  const maxFiles = options?.maxFiles ?? DEFAULT_MAX_FILES;
@@ -159,38 +239,69 @@ function resolveGeneratorOptions(options) {
159
239
  }),
160
240
  };
161
241
  }
162
- function computeCodebaseFingerprint(files, resolved, truncated) {
242
+ function computeCodebaseFingerprint(files, resolved, truncated, repos) {
163
243
  return createHash("sha1")
164
244
  .update(JSON.stringify({
165
245
  files,
246
+ ...(repos ? { repos } : {}),
166
247
  truncated,
167
248
  optionSignature: resolved.optionSignature,
168
249
  }))
169
250
  .digest("hex");
170
251
  }
171
252
  // ─── Grouping ────────────────────────────────────────────────────────────────
172
- function groupByDirectory(files, descriptions, collapseThreshold) {
253
+ function groupByDirectory(files, descriptions, collapseThreshold, repos) {
173
254
  const dirMap = new Map();
174
- for (const file of files) {
255
+ for (let i = 0; i < files.length; i++) {
256
+ const file = files[i];
175
257
  const dir = dirname(file);
176
- const dirKey = dir === "." ? "" : dir;
177
- if (!dirMap.has(dirKey)) {
178
- dirMap.set(dirKey, []);
258
+ const dirPath = dir === "." ? "" : dir;
259
+ const repoId = repos?.[i];
260
+ const groupKey = repoId !== undefined ? `${repoId}\0${dirPath}` : dirPath;
261
+ if (!dirMap.has(groupKey)) {
262
+ dirMap.set(groupKey, []);
179
263
  }
180
- dirMap.get(dirKey).push({
264
+ dirMap.get(groupKey).push({
181
265
  path: file,
182
266
  description: descriptions.get(file) ?? "",
267
+ repo: repoId,
183
268
  });
184
269
  }
185
270
  const groups = [];
186
- const sortedDirs = [...dirMap.keys()].sort();
187
- for (const dir of sortedDirs) {
188
- const dirFiles = dirMap.get(dir);
271
+ const repoOrder = new Map();
272
+ if (repos) {
273
+ for (let i = 0; i < repos.length; i++) {
274
+ if (!repoOrder.has(repos[i])) {
275
+ repoOrder.set(repos[i], repoOrder.size);
276
+ }
277
+ }
278
+ }
279
+ const sortedDirs = [...dirMap.keys()].sort((a, b) => {
280
+ // Single-repo (project) mode must stay byte-identical to the pre-workspace
281
+ // output, which ordered directories with a bare `.sort()` (UTF-16 code-unit
282
+ // order, so uppercase sorts before lowercase). localeCompare would diverge
283
+ // for mixed-case names (e.g. "Zoo" before "apple" flips), so preserve
284
+ // code-unit ordering here; only the repo-partitioning key is added on top.
285
+ if (!repos)
286
+ return a < b ? -1 : a > b ? 1 : 0;
287
+ const repoA = dirMap.get(a)[0]?.repo ?? "";
288
+ const repoB = dirMap.get(b)[0]?.repo ?? "";
289
+ const orderA = repoOrder.get(repoA) ?? 0;
290
+ const orderB = repoOrder.get(repoB) ?? 0;
291
+ if (orderA !== orderB)
292
+ return orderA - orderB;
293
+ return a.localeCompare(b);
294
+ });
295
+ for (const groupKey of sortedDirs) {
296
+ const dirFiles = dirMap.get(groupKey);
189
297
  dirFiles.sort((a, b) => a.path.localeCompare(b.path));
298
+ const dirPath = repos ? groupKey.slice(groupKey.indexOf("\0") + 1) : groupKey;
190
299
  groups.push({
191
- path: dir,
300
+ path: dirPath,
192
301
  files: dirFiles,
193
302
  collapsed: dirFiles.length > collapseThreshold,
303
+ // Each group is scoped to one repo in workspace-aware mode.
304
+ repo: dirFiles[0]?.repo,
194
305
  });
195
306
  }
196
307
  return groups;
@@ -207,7 +318,18 @@ function renderCodebaseMap(groups, totalFiles, truncated, metadata) {
207
318
  lines.push(`Note: Truncated to first ${totalFiles} files. Run with higher --max-files to include all.`);
208
319
  }
209
320
  lines.push("");
321
+ let emittedRepo;
210
322
  for (const group of groups) {
323
+ // In a workspace-aware map, partition directories under their declaring
324
+ // repository. `## [repo-id]` headings are used (not `###`) so they never
325
+ // collide with the per-directory `### <dir>/` headings or the
326
+ // `parseCodebaseMap` list-item regexes. Groups are sorted by declaring
327
+ // repo (enumeration order) then directory path so each repo is contiguous.
328
+ if (group.repo && group.repo !== emittedRepo) {
329
+ emittedRepo = group.repo;
330
+ lines.push(`## [${group.repo}]`);
331
+ lines.push("");
332
+ }
211
333
  const heading = group.path || "(root)";
212
334
  lines.push(`### ${heading}/`);
213
335
  if (group.collapsed) {
@@ -250,13 +372,15 @@ function renderCodebaseMap(groups, totalFiles, truncated, metadata) {
250
372
  function buildCodebaseMap(basePath, resolved, existingDescriptions, enumerated) {
251
373
  const listed = enumerated ?? enumerateFiles(basePath, resolved.excludes, resolved.maxFiles);
252
374
  const descriptions = existingDescriptions ?? new Map();
253
- const groups = groupByDirectory(listed.files, descriptions, resolved.collapseThreshold);
375
+ const groups = groupByDirectory(listed.files, descriptions, resolved.collapseThreshold, listed.repos);
254
376
  const generatedAt = new Date().toISOString().split(".")[0] + "Z";
377
+ const repoIds = listed.repos ? Array.from(new Set(listed.repos)) : undefined;
255
378
  const metadata = {
256
379
  generatedAt,
257
- fingerprint: computeCodebaseFingerprint(listed.files, resolved, listed.truncated),
380
+ fingerprint: computeCodebaseFingerprint(listed.files, resolved, listed.truncated, listed.repos),
258
381
  fileCount: listed.files.length,
259
382
  truncated: listed.truncated,
383
+ ...(repoIds ? { repositories: repoIds } : {}),
260
384
  };
261
385
  const content = renderCodebaseMap(groups, listed.files.length, listed.truncated, metadata);
262
386
  return {
@@ -273,9 +397,21 @@ function buildCodebaseMap(basePath, resolved, existingDescriptions, enumerated)
273
397
  * Generate a fresh CODEBASE.md from scratch.
274
398
  * Preserves existing descriptions if `existingDescriptions` is provided.
275
399
  */
400
+ /**
401
+ * Resolve workspace-aware enumeration for parent mode, or undefined to fall
402
+ * back to the legacy single-root enumeration. Centralized so all three public
403
+ * entry points (generate/update/ensure) share one discovery path.
404
+ */
405
+ function resolveWorkspaceEnumeration(basePath, resolved) {
406
+ const registry = loadWorkspaceRegistry(basePath);
407
+ if (!registry)
408
+ return undefined;
409
+ return enumerateWorkspaceFiles(registry, resolved.excludes, resolved.maxFiles);
410
+ }
276
411
  export function generateCodebaseMap(basePath, options, existingDescriptions) {
277
412
  const resolved = resolveGeneratorOptions(options);
278
- return buildCodebaseMap(basePath, resolved, existingDescriptions);
413
+ const enumerated = resolveWorkspaceEnumeration(basePath, resolved);
414
+ return buildCodebaseMap(basePath, resolved, existingDescriptions, enumerated);
279
415
  }
280
416
  /**
281
417
  * Incremental update: re-scan files, preserve existing descriptions,
@@ -293,7 +429,8 @@ export function updateCodebaseMap(basePath, options) {
293
429
  const existingFiles = new Set(existingDescriptions.keys());
294
430
  // Generate new map preserving descriptions — reuse the returned file list
295
431
  // to avoid a second enumeration (prevents race between content and stats).
296
- const result = buildCodebaseMap(basePath, resolved, existingDescriptions);
432
+ const enumerated = resolveWorkspaceEnumeration(basePath, resolved);
433
+ const result = buildCodebaseMap(basePath, resolved, existingDescriptions, enumerated);
297
434
  const currentSet = new Set(result.files);
298
435
  // Count changes
299
436
  let added = 0;
@@ -326,7 +463,7 @@ function clearFreshnessCache(basePath) {
326
463
  }
327
464
  export function ensureCodebaseMapFresh(basePath, options, ensureOptions) {
328
465
  const resolved = resolveGeneratorOptions(options);
329
- const cacheKey = `${basePath}::${resolved.optionSignature}`;
466
+ const cacheKey = `${basePath}::${resolved.optionSignature}::${workspaceEnumerationSignature(basePath)}`;
330
467
  const ttlMs = ensureOptions?.ttlMs ?? DEFAULT_REFRESH_TTL_MS;
331
468
  const force = ensureOptions?.force === true;
332
469
  const now = Date.now();
@@ -338,8 +475,9 @@ export function ensureCodebaseMapFresh(basePath, options, ensureOptions) {
338
475
  }
339
476
  }
340
477
  const existing = readCodebaseMap(basePath);
341
- const listed = enumerateFiles(basePath, resolved.excludes, resolved.maxFiles);
342
- const fingerprint = computeCodebaseFingerprint(listed.files, resolved, listed.truncated);
478
+ const listed = resolveWorkspaceEnumeration(basePath, resolved)
479
+ ?? enumerateFiles(basePath, resolved.excludes, resolved.maxFiles);
480
+ const fingerprint = computeCodebaseFingerprint(listed.files, resolved, listed.truncated, listed.repos);
343
481
  const cacheAndReturn = (result) => {
344
482
  freshnessCache.set(cacheKey, { checkedAt: now, result });
345
483
  return result;
@@ -1,6 +1,8 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { computeProgressScore, formatProgressLine } from "../../progress-score.js";
3
- import { getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, modelIdsForProfileResolution, resolveProfileAnchorProvider, resolveDisabledModelProvidersFromPreferences } from "../../preferences.js";
3
+ import { isRepositoryDirty } from "../../git-service.js";
4
+ import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, modelIdsForProfileResolution, resolveProfileAnchorProvider, resolveDisabledModelProvidersFromPreferences } from "../../preferences.js";
5
+ import { createRepositoryRegistryFromPreferences } from "../../repository-registry.js";
4
6
  import { ensurePreferencesFile, handlePrefs, handlePrefsMode, handlePrefsWizard, handleLanguage } from "../../commands-prefs-wizard.js";
5
7
  import { runEnvironmentChecks } from "../../doctor-environment.js";
6
8
  import { deriveState } from "../../state.js";
@@ -206,7 +208,7 @@ export async function handleStatus(ctx) {
206
208
  },
207
209
  });
208
210
  if (result === undefined) {
209
- ctx.ui.notify(formatTextStatus(state), "info");
211
+ ctx.ui.notify(formatTextStatus(state, basePath), "info");
210
212
  }
211
213
  }
212
214
  export async function fireStatusViaCommand(ctx) {
@@ -539,7 +541,8 @@ export async function handleCoreCommand(trimmed, ctx, pi) {
539
541
  }
540
542
  return false;
541
543
  }
542
- export function formatTextStatus(state) {
544
+ export function formatTextStatus(state, basePath) {
545
+ const root = basePath ?? projectRoot();
543
546
  const lines = ["GSD Status\n"];
544
547
  lines.push(formatProgressLine(computeProgressScore()));
545
548
  lines.push("");
@@ -582,7 +585,7 @@ export function formatTextStatus(state) {
582
585
  lines.push(` ${icon} ${milestone.id}: ${milestone.title} (${milestone.status})`);
583
586
  }
584
587
  }
585
- const envResults = runEnvironmentChecks(projectRoot());
588
+ const envResults = runEnvironmentChecks(root);
586
589
  const envIssues = envResults.filter((result) => result.status !== "ok");
587
590
  if (envIssues.length > 0) {
588
591
  lines.push("");
@@ -591,5 +594,38 @@ export function formatTextStatus(state) {
591
594
  lines.push(` ${issue.status === "error" ? "✗" : "⚠"} ${issue.message}`);
592
595
  }
593
596
  }
597
+ // Parent-workspace per-repository git health (#818). No-op for single-repo
598
+ // projects; surfaces which declared child repos have uncommitted changes.
599
+ const repoBlock = buildWorkspaceRepoStatusBlock(root);
600
+ if (repoBlock) {
601
+ lines.push("");
602
+ lines.push("Repositories:");
603
+ lines.push(repoBlock);
604
+ }
594
605
  return lines.join("\n");
595
606
  }
607
+ /**
608
+ * Build a per-repository dirty/clean summary for parent-workspace status.
609
+ * Returns "" for single-repo (project-mode) projects so the status output is
610
+ * unchanged; otherwise one line per declared child repository.
611
+ */
612
+ function buildWorkspaceRepoStatusBlock(basePath) {
613
+ let registry;
614
+ try {
615
+ registry = createRepositoryRegistryFromPreferences(basePath, loadEffectiveGSDPreferences(basePath)?.preferences);
616
+ }
617
+ catch {
618
+ return "";
619
+ }
620
+ if (registry.mode !== "parent")
621
+ return "";
622
+ const childRepos = registry.repositories.filter((repo) => repo.id !== "project");
623
+ if (childRepos.length === 0)
624
+ return "";
625
+ return childRepos
626
+ .map((repo) => {
627
+ const dirty = isRepositoryDirty(repo.root);
628
+ return ` ${dirty ? "✗" : "✓"} ${repo.id}${repo.role ? ` — ${repo.role}` : ""}${dirty ? " (uncommitted changes)" : " (clean)"}`;
629
+ })
630
+ .join("\n");
631
+ }
@@ -16,7 +16,7 @@ import { appendCapture, hasPendingCaptures, loadPendingCaptures } from "./captur
16
16
  import { appendOverride, appendKnowledge } from "./files.js";
17
17
  import { formatDoctorIssuesForPrompt, formatDoctorReport, formatDoctorReportJson, runGSDDoctor, selectDoctorScope, filterDoctorIssues, } from "./doctor.js";
18
18
  import { isAutoActive, checkRemoteAutoSession } from "./auto.js";
19
- import { getAutoWorktreePath } from "./auto-worktree.js";
19
+ import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
20
20
  import { currentDirectoryRoot, projectRoot } from "./commands/context.js";
21
21
  import { loadPrompt } from "./prompt-loader.js";
22
22
  import { buildClaudeRuntimeFloorAdvisory } from "../../shared/claude-runtime-floor.js";