gsd-pi 2.41.0 → 2.42.0-dev.1df898f

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 (494) hide show
  1. package/README.md +92 -29
  2. package/dist/cli-web-branch.d.ts +6 -0
  3. package/dist/cli-web-branch.js +17 -0
  4. package/dist/cli.js +18 -3
  5. package/dist/loader.js +3 -1
  6. package/dist/onboarding.js +2 -1
  7. package/dist/resource-loader.js +39 -6
  8. package/dist/resources/extensions/async-jobs/async-bash-tool.js +52 -4
  9. package/dist/resources/extensions/async-jobs/await-tool.js +5 -0
  10. package/dist/resources/extensions/async-jobs/index.js +2 -0
  11. package/dist/resources/extensions/gsd/auto/loop.js +89 -1
  12. package/dist/resources/extensions/gsd/auto/phases.js +29 -13
  13. package/dist/resources/extensions/gsd/auto/session.js +6 -0
  14. package/dist/resources/extensions/gsd/auto-dashboard.js +8 -2
  15. package/dist/resources/extensions/gsd/auto-dispatch.js +19 -2
  16. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -0
  17. package/dist/resources/extensions/gsd/auto-prompts.js +3 -16
  18. package/dist/resources/extensions/gsd/auto-recovery.js +12 -4
  19. package/dist/resources/extensions/gsd/auto-start.js +16 -14
  20. package/dist/resources/extensions/gsd/auto-worktree.js +147 -13
  21. package/dist/resources/extensions/gsd/auto.js +64 -2
  22. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +199 -164
  23. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +62 -0
  24. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +25 -3
  26. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +7 -2
  27. package/dist/resources/extensions/gsd/commands/catalog.js +40 -1
  28. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
  29. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  30. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +146 -0
  31. package/dist/resources/extensions/gsd/context-injector.js +74 -0
  32. package/dist/resources/extensions/gsd/context-store.js +4 -3
  33. package/dist/resources/extensions/gsd/custom-execution-policy.js +47 -0
  34. package/dist/resources/extensions/gsd/custom-verification.js +145 -0
  35. package/dist/resources/extensions/gsd/custom-workflow-engine.js +164 -0
  36. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -0
  37. package/dist/resources/extensions/gsd/db-writer.js +5 -2
  38. package/dist/resources/extensions/gsd/definition-loader.js +352 -0
  39. package/dist/resources/extensions/gsd/detection.js +20 -1
  40. package/dist/resources/extensions/gsd/dev-execution-policy.js +24 -0
  41. package/dist/resources/extensions/gsd/dev-workflow-engine.js +82 -0
  42. package/dist/resources/extensions/gsd/doctor-checks.js +31 -1
  43. package/dist/resources/extensions/gsd/doctor-providers.js +10 -0
  44. package/dist/resources/extensions/gsd/doctor.js +11 -1
  45. package/dist/resources/extensions/gsd/engine-resolver.js +40 -0
  46. package/dist/resources/extensions/gsd/engine-types.js +8 -0
  47. package/dist/resources/extensions/gsd/execution-policy.js +8 -0
  48. package/dist/resources/extensions/gsd/exit-command.js +12 -2
  49. package/dist/resources/extensions/gsd/export.js +9 -13
  50. package/dist/resources/extensions/gsd/extension-manifest.json +2 -2
  51. package/dist/resources/extensions/gsd/files.js +28 -11
  52. package/dist/resources/extensions/gsd/forensics.js +94 -3
  53. package/dist/resources/extensions/gsd/git-constants.js +1 -0
  54. package/dist/resources/extensions/gsd/git-service.js +6 -2
  55. package/dist/resources/extensions/gsd/graph.js +225 -0
  56. package/dist/resources/extensions/gsd/gsd-db.js +25 -8
  57. package/dist/resources/extensions/gsd/guided-flow-queue.js +1 -1
  58. package/dist/resources/extensions/gsd/guided-flow.js +7 -3
  59. package/dist/resources/extensions/gsd/journal.js +85 -0
  60. package/dist/resources/extensions/gsd/md-importer.js +5 -0
  61. package/dist/resources/extensions/gsd/milestone-ids.js +1 -1
  62. package/dist/resources/extensions/gsd/native-git-bridge.js +3 -2
  63. package/dist/resources/extensions/gsd/post-unit-hooks.js +24 -412
  64. package/dist/resources/extensions/gsd/preferences-types.js +2 -0
  65. package/dist/resources/extensions/gsd/preferences.js +60 -8
  66. package/dist/resources/extensions/gsd/prompt-loader.js +34 -4
  67. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
  68. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
  69. package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
  70. package/dist/resources/extensions/gsd/prompts/forensics.md +12 -5
  71. package/dist/resources/extensions/gsd/prompts/queue.md +1 -1
  72. package/dist/resources/extensions/gsd/repo-identity.js +92 -7
  73. package/dist/resources/extensions/gsd/rule-registry.js +489 -0
  74. package/dist/resources/extensions/gsd/rule-types.js +6 -0
  75. package/dist/resources/extensions/gsd/run-manager.js +134 -0
  76. package/dist/resources/extensions/gsd/service-tier.js +147 -0
  77. package/dist/resources/extensions/gsd/session-lock.js +2 -2
  78. package/dist/resources/extensions/gsd/structured-data-formatter.js +2 -1
  79. package/dist/resources/extensions/gsd/templates/decisions.md +2 -2
  80. package/dist/resources/extensions/gsd/workflow-engine.js +7 -0
  81. package/dist/resources/extensions/gsd/workflow-templates.js +13 -1
  82. package/dist/resources/extensions/gsd/worktree-manager.js +20 -6
  83. package/dist/resources/extensions/gsd/worktree-resolver.js +21 -4
  84. package/dist/resources/extensions/gsd/worktree.js +2 -2
  85. package/dist/resources/extensions/mcp-client/index.js +2 -1
  86. package/dist/resources/extensions/search-the-web/tool-search.js +3 -3
  87. package/dist/resources/extensions/subagent/index.js +7 -3
  88. package/dist/resources/extensions/voice/index.js +4 -4
  89. package/dist/resources/skills/create-workflow/SKILL.md +103 -0
  90. package/dist/resources/skills/create-workflow/references/feature-patterns.md +128 -0
  91. package/dist/resources/skills/create-workflow/references/verification-policies.md +76 -0
  92. package/dist/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
  93. package/dist/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
  94. package/dist/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
  95. package/dist/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
  96. package/dist/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
  97. package/dist/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
  98. package/dist/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
  99. package/dist/web/standalone/.next/BUILD_ID +1 -1
  100. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  101. package/dist/web/standalone/.next/build-manifest.json +4 -4
  102. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  103. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  104. package/dist/web/standalone/.next/required-server-files.json +3 -3
  105. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  106. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  108. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  116. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  122. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  132. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  170. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  176. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  190. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  192. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  194. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  199. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  200. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  202. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  203. package/dist/web/standalone/.next/server/app/index.html +1 -1
  204. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  205. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  206. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  207. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  208. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  209. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  210. package/dist/web/standalone/.next/server/app/page.js +2 -2
  211. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  212. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  213. package/dist/web/standalone/.next/server/chunks/229.js +3 -3
  214. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  215. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  216. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  217. package/dist/web/standalone/.next/server/middleware.js +2 -2
  218. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  219. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  220. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  221. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  222. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  223. package/dist/web/standalone/.next/static/chunks/4024.c195dc1fdd2adbea.js +9 -0
  224. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
  225. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
  226. package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
  227. package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
  228. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  229. package/dist/web/standalone/.next/static/chunks/{webpack-9afaaebf6042a1d7.js → webpack-fa307370fcf9fb2c.js} +1 -1
  230. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  231. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  232. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  233. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  234. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  235. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  236. package/dist/web/standalone/server.js +1 -1
  237. package/dist/web-mode.d.ts +4 -0
  238. package/dist/web-mode.js +69 -11
  239. package/package.json +1 -1
  240. package/packages/native/src/__tests__/text.test.mjs +33 -0
  241. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  242. package/packages/pi-agent-core/dist/agent.js +2 -0
  243. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  244. package/packages/pi-agent-core/dist/types.d.ts +6 -0
  245. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  246. package/packages/pi-agent-core/dist/types.js.map +1 -1
  247. package/packages/pi-agent-core/src/agent.test.ts +53 -0
  248. package/packages/pi-agent-core/src/agent.ts +3 -0
  249. package/packages/pi-agent-core/src/types.ts +6 -0
  250. package/packages/pi-agent-core/tsconfig.json +1 -1
  251. package/packages/pi-ai/dist/models.d.ts +5 -3
  252. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  253. package/packages/pi-ai/dist/models.generated.d.ts +801 -1468
  254. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  255. package/packages/pi-ai/dist/models.generated.js +1135 -1588
  256. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  257. package/packages/pi-ai/dist/models.js.map +1 -1
  258. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  259. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +60 -2
  260. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  261. package/packages/pi-ai/scripts/generate-models.ts +1543 -0
  262. package/packages/pi-ai/src/models.generated.ts +1140 -1593
  263. package/packages/pi-ai/src/models.ts +7 -4
  264. package/packages/pi-ai/src/utils/oauth/github-copilot.ts +74 -2
  265. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/core/agent-session.js +8 -1
  267. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +7 -0
  269. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  270. package/packages/pi-coding-agent/dist/core/auth-storage.js +29 -2
  271. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  272. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +60 -0
  273. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  274. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +3 -1
  275. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
  276. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  277. package/packages/pi-coding-agent/dist/core/extensions/loader.js +18 -0
  278. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  279. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  280. package/packages/pi-coding-agent/dist/core/lsp/client.js +23 -0
  281. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  282. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -0
  284. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/package-manager.d.ts +6 -0
  286. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/package-manager.js +63 -11
  288. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +9 -0
  290. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  291. package/packages/pi-coding-agent/dist/core/resource-loader.js +20 -6
  292. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  293. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  294. package/packages/pi-coding-agent/dist/core/system-prompt.js +6 -5
  295. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  296. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  297. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.js +3 -0
  298. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.js.map +1 -1
  299. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  300. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +9 -6
  301. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  302. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  303. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +10 -7
  304. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  305. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  306. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +34 -10
  307. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  308. package/packages/pi-coding-agent/package.json +1 -1
  309. package/packages/pi-coding-agent/src/core/agent-session.ts +7 -1
  310. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +68 -0
  311. package/packages/pi-coding-agent/src/core/auth-storage.ts +30 -2
  312. package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +4 -2
  313. package/packages/pi-coding-agent/src/core/extensions/loader.ts +18 -0
  314. package/packages/pi-coding-agent/src/core/lsp/client.ts +29 -0
  315. package/packages/pi-coding-agent/src/core/model-registry.ts +3 -0
  316. package/packages/pi-coding-agent/src/core/package-manager.ts +99 -58
  317. package/packages/pi-coding-agent/src/core/resource-loader.ts +24 -6
  318. package/packages/pi-coding-agent/src/core/system-prompt.ts +6 -5
  319. package/packages/pi-coding-agent/src/modes/interactive/components/extension-editor.ts +3 -0
  320. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +10 -6
  321. package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +11 -7
  322. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +36 -11
  323. package/pkg/package.json +1 -1
  324. package/src/resources/extensions/async-jobs/async-bash-timeout.test.ts +122 -0
  325. package/src/resources/extensions/async-jobs/async-bash-tool.ts +40 -4
  326. package/src/resources/extensions/async-jobs/await-tool.test.ts +47 -0
  327. package/src/resources/extensions/async-jobs/await-tool.ts +5 -0
  328. package/src/resources/extensions/async-jobs/index.ts +1 -0
  329. package/src/resources/extensions/async-jobs/job-manager.ts +2 -0
  330. package/src/resources/extensions/gsd/auto/loop-deps.ts +5 -2
  331. package/src/resources/extensions/gsd/auto/loop.ts +101 -1
  332. package/src/resources/extensions/gsd/auto/phases.ts +31 -13
  333. package/src/resources/extensions/gsd/auto/session.ts +6 -0
  334. package/src/resources/extensions/gsd/auto/types.ts +4 -0
  335. package/src/resources/extensions/gsd/auto-dashboard.ts +9 -2
  336. package/src/resources/extensions/gsd/auto-dispatch.ts +25 -5
  337. package/src/resources/extensions/gsd/auto-post-unit.ts +8 -0
  338. package/src/resources/extensions/gsd/auto-prompts.ts +2 -18
  339. package/src/resources/extensions/gsd/auto-recovery.ts +12 -4
  340. package/src/resources/extensions/gsd/auto-start.ts +15 -13
  341. package/src/resources/extensions/gsd/auto-worktree.ts +162 -18
  342. package/src/resources/extensions/gsd/auto.ts +71 -2
  343. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +209 -162
  344. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +62 -0
  345. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
  346. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +25 -4
  347. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +9 -2
  348. package/src/resources/extensions/gsd/commands/catalog.ts +40 -1
  349. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
  350. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  351. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +164 -0
  352. package/src/resources/extensions/gsd/context-injector.ts +100 -0
  353. package/src/resources/extensions/gsd/context-store.ts +4 -3
  354. package/src/resources/extensions/gsd/custom-execution-policy.ts +73 -0
  355. package/src/resources/extensions/gsd/custom-verification.ts +180 -0
  356. package/src/resources/extensions/gsd/custom-workflow-engine.ts +216 -0
  357. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -0
  358. package/src/resources/extensions/gsd/db-writer.ts +6 -2
  359. package/src/resources/extensions/gsd/definition-loader.ts +462 -0
  360. package/src/resources/extensions/gsd/detection.ts +20 -1
  361. package/src/resources/extensions/gsd/dev-execution-policy.ts +51 -0
  362. package/src/resources/extensions/gsd/dev-workflow-engine.ts +110 -0
  363. package/src/resources/extensions/gsd/doctor-checks.ts +32 -1
  364. package/src/resources/extensions/gsd/doctor-providers.ts +13 -0
  365. package/src/resources/extensions/gsd/doctor-types.ts +1 -0
  366. package/src/resources/extensions/gsd/doctor.ts +12 -1
  367. package/src/resources/extensions/gsd/engine-resolver.ts +57 -0
  368. package/src/resources/extensions/gsd/engine-types.ts +71 -0
  369. package/src/resources/extensions/gsd/execution-policy.ts +43 -0
  370. package/src/resources/extensions/gsd/exit-command.ts +14 -2
  371. package/src/resources/extensions/gsd/export.ts +8 -15
  372. package/src/resources/extensions/gsd/extension-manifest.json +2 -2
  373. package/src/resources/extensions/gsd/files.ts +29 -12
  374. package/src/resources/extensions/gsd/forensics.ts +101 -3
  375. package/src/resources/extensions/gsd/git-constants.ts +1 -0
  376. package/src/resources/extensions/gsd/git-service.ts +5 -5
  377. package/src/resources/extensions/gsd/gitignore.ts +1 -1
  378. package/src/resources/extensions/gsd/graph.ts +312 -0
  379. package/src/resources/extensions/gsd/gsd-db.ts +37 -8
  380. package/src/resources/extensions/gsd/guided-flow-queue.ts +1 -1
  381. package/src/resources/extensions/gsd/guided-flow.ts +7 -3
  382. package/src/resources/extensions/gsd/journal.ts +134 -0
  383. package/src/resources/extensions/gsd/md-importer.ts +6 -0
  384. package/src/resources/extensions/gsd/milestone-ids.ts +1 -1
  385. package/src/resources/extensions/gsd/native-git-bridge.ts +3 -2
  386. package/src/resources/extensions/gsd/post-unit-hooks.ts +24 -462
  387. package/src/resources/extensions/gsd/preferences-types.ts +6 -0
  388. package/src/resources/extensions/gsd/preferences.ts +63 -6
  389. package/src/resources/extensions/gsd/prompt-loader.ts +35 -4
  390. package/src/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
  391. package/src/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
  392. package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
  393. package/src/resources/extensions/gsd/prompts/forensics.md +12 -5
  394. package/src/resources/extensions/gsd/prompts/queue.md +1 -1
  395. package/src/resources/extensions/gsd/repo-identity.ts +95 -7
  396. package/src/resources/extensions/gsd/rule-registry.ts +599 -0
  397. package/src/resources/extensions/gsd/rule-types.ts +68 -0
  398. package/src/resources/extensions/gsd/run-manager.ts +180 -0
  399. package/src/resources/extensions/gsd/service-tier.ts +184 -0
  400. package/src/resources/extensions/gsd/session-lock.ts +2 -2
  401. package/src/resources/extensions/gsd/structured-data-formatter.ts +3 -1
  402. package/src/resources/extensions/gsd/templates/decisions.md +2 -2
  403. package/src/resources/extensions/gsd/tests/activity-log.test.ts +31 -69
  404. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +103 -120
  405. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +85 -0
  406. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +2 -2
  407. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +202 -0
  408. package/src/resources/extensions/gsd/tests/bundled-workflow-defs.test.ts +180 -0
  409. package/src/resources/extensions/gsd/tests/captures.test.ts +12 -1
  410. package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +283 -0
  411. package/src/resources/extensions/gsd/tests/context-injector.test.ts +313 -0
  412. package/src/resources/extensions/gsd/tests/context-store.test.ts +10 -5
  413. package/src/resources/extensions/gsd/tests/continue-here.test.ts +20 -20
  414. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +540 -0
  415. package/src/resources/extensions/gsd/tests/custom-verification.test.ts +382 -0
  416. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +339 -0
  417. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +87 -0
  418. package/src/resources/extensions/gsd/tests/db-writer.test.ts +10 -0
  419. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +778 -0
  420. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +318 -0
  421. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +15 -10
  422. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +5 -4
  423. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +167 -0
  424. package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +174 -0
  425. package/src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts +476 -0
  426. package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +271 -0
  427. package/src/resources/extensions/gsd/tests/exit-command.test.ts +55 -0
  428. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +48 -0
  429. package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +43 -0
  430. package/src/resources/extensions/gsd/tests/git-locale.test.ts +133 -0
  431. package/src/resources/extensions/gsd/tests/git-service.test.ts +44 -0
  432. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +599 -0
  433. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +8 -1
  434. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +7 -7
  435. package/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts +429 -0
  436. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +513 -0
  437. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +147 -0
  438. package/src/resources/extensions/gsd/tests/journal.test.ts +341 -0
  439. package/src/resources/extensions/gsd/tests/manifest-status.test.ts +73 -82
  440. package/src/resources/extensions/gsd/tests/md-importer.test.ts +31 -1
  441. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  442. package/src/resources/extensions/gsd/tests/milestone-id-reservation.test.ts +1 -1
  443. package/src/resources/extensions/gsd/tests/parsers.test.ts +110 -0
  444. package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -25
  445. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +3 -1
  446. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +61 -1
  447. package/src/resources/extensions/gsd/tests/routing-history.test.ts +11 -22
  448. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +413 -0
  449. package/src/resources/extensions/gsd/tests/run-manager.test.ts +229 -0
  450. package/src/resources/extensions/gsd/tests/service-tier.test.ts +127 -0
  451. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +56 -3
  452. package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +2 -2
  453. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +102 -0
  454. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +4 -3
  455. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +151 -0
  456. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +45 -0
  457. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +117 -0
  458. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -1
  459. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +156 -263
  460. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +99 -0
  461. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -0
  462. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +4 -0
  463. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +135 -0
  464. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +203 -106
  465. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +79 -5
  466. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +140 -0
  467. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +74 -0
  468. package/src/resources/extensions/gsd/types.ts +3 -0
  469. package/src/resources/extensions/gsd/workflow-engine.ts +38 -0
  470. package/src/resources/extensions/gsd/workflow-templates.ts +12 -1
  471. package/src/resources/extensions/gsd/worktree-manager.ts +21 -6
  472. package/src/resources/extensions/gsd/worktree-resolver.ts +32 -12
  473. package/src/resources/extensions/gsd/worktree.ts +2 -2
  474. package/src/resources/extensions/mcp-client/index.ts +5 -1
  475. package/src/resources/extensions/search-the-web/tool-search.ts +3 -3
  476. package/src/resources/extensions/subagent/index.ts +7 -3
  477. package/src/resources/extensions/voice/index.ts +4 -4
  478. package/src/resources/skills/create-workflow/SKILL.md +103 -0
  479. package/src/resources/skills/create-workflow/references/feature-patterns.md +128 -0
  480. package/src/resources/skills/create-workflow/references/verification-policies.md +76 -0
  481. package/src/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
  482. package/src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
  483. package/src/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
  484. package/src/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
  485. package/src/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
  486. package/src/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
  487. package/src/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
  488. package/dist/web/standalone/.next/static/chunks/4024.279c423e4661ece1.js +0 -9
  489. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
  490. package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
  491. package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
  492. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
  493. /package/dist/web/standalone/.next/static/{Ute3pMouVczQyT15qrBBO → qw8qDHXOTLUXBq1vEknSz}/_buildManifest.js +0 -0
  494. /package/dist/web/standalone/.next/static/{Ute3pMouVczQyT15qrBBO → qw8qDHXOTLUXBq1vEknSz}/_ssgManifest.js +0 -0
@@ -0,0 +1,99 @@
1
+ /**
2
+ * windows-path-normalization.test.ts — Verify Windows backslash paths are
3
+ * normalised to forward slashes before embedding in bash command strings.
4
+ *
5
+ * Regression test for #1436: on Windows, `cd C:\Users\user\project` in bash
6
+ * strips backslashes (escape characters), producing `C:Usersuserproject`.
7
+ */
8
+
9
+ import { createTestContext } from "./test-helpers.ts";
10
+
11
+ const { assertEq, assertTrue, report } = createTestContext();
12
+
13
+ // ─── shellEscape + path normalization ──────────────────────────────────────
14
+
15
+ // Replicate the shellEscape helper from cmux/index.ts
16
+ function shellEscape(value: string): string {
17
+ return `'${value.replace(/'/g, `'\\''`)}'`;
18
+ }
19
+
20
+ // The bashPath pattern used in subagent/index.ts
21
+ function bashPath(p: string): string {
22
+ return shellEscape(p.replaceAll("\\", "/"));
23
+ }
24
+
25
+ console.log("\n=== Windows backslash path normalization (#1436) ===");
26
+
27
+ // Backslash paths are converted to forward slashes
28
+ assertEq(
29
+ bashPath("C:\\Users\\user\\project"),
30
+ "'C:/Users/user/project'",
31
+ "backslash path normalised to forward slashes in shell-escaped string",
32
+ );
33
+
34
+ // Unix paths pass through unchanged
35
+ assertEq(
36
+ bashPath("/home/user/project"),
37
+ "'/home/user/project'",
38
+ "Unix path unchanged",
39
+ );
40
+
41
+ // Mixed separators are normalised
42
+ assertEq(
43
+ bashPath("C:\\Users/user\\project/src"),
44
+ "'C:/Users/user/project/src'",
45
+ "mixed separators normalised",
46
+ );
47
+
48
+ // Paths with single quotes are still properly escaped
49
+ assertEq(
50
+ bashPath("C:\\Users\\o'brien\\project"),
51
+ "'C:/Users/o'\\''brien/project'",
52
+ "single quote in path is escaped after normalisation",
53
+ );
54
+
55
+ // UNC paths
56
+ assertEq(
57
+ bashPath("\\\\server\\share\\dir"),
58
+ "'//server/share/dir'",
59
+ "UNC path normalised",
60
+ );
61
+
62
+ // Empty string
63
+ assertEq(
64
+ bashPath(""),
65
+ "''",
66
+ "empty string handled",
67
+ );
68
+
69
+ // ─── cd command construction ───────────────────────────────────────────────
70
+
71
+ console.log("\n=== cd command construction with normalised paths ===");
72
+
73
+ const windowsCwd = "C:\\Users\\user\\project\\.gsd\\worktrees\\M001";
74
+ const cdCommand = `cd ${bashPath(windowsCwd)}`;
75
+ assertEq(
76
+ cdCommand,
77
+ "cd 'C:/Users/user/project/.gsd/worktrees/M001'",
78
+ "cd command uses forward slashes for Windows worktree path",
79
+ );
80
+
81
+ // Verify the mangled form from #1436 is NOT produced
82
+ assertTrue(
83
+ !cdCommand.includes("C:Users"),
84
+ "mangled path C:Usersuserproject must not appear",
85
+ );
86
+
87
+ // ─── Worktree teardown orphan detection ────────────────────────────────────
88
+
89
+ console.log("\n=== teardown orphan warning path formatting ===");
90
+
91
+ const windowsWtDir = "C:\\Users\\user\\project\\.gsd\\worktrees\\M001";
92
+ const helpCommand = `rm -rf "${windowsWtDir.replaceAll("\\", "/")}"`;
93
+ assertEq(
94
+ helpCommand,
95
+ 'rm -rf "C:/Users/user/project/.gsd/worktrees/M001"',
96
+ "orphan cleanup help command uses forward slashes",
97
+ );
98
+
99
+ report();
@@ -138,6 +138,7 @@ async function main(): Promise<void> {
138
138
  choice: "reconcile on merge",
139
139
  rationale: "test coverage",
140
140
  revisable: "no",
141
+ made_by: 'agent',
141
142
  superseded_by: null,
142
143
  });
143
144
  closeDatabase();
@@ -47,6 +47,7 @@ function seedMainDb(dbPath: string): void {
47
47
  choice: 'node:sqlite',
48
48
  rationale: 'Built-in',
49
49
  revisable: 'yes',
50
+ made_by: 'agent',
50
51
  superseded_by: null,
51
52
  });
52
53
  insertRequirement({
@@ -182,6 +183,7 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
182
183
  choice: 'WAL',
183
184
  rationale: 'Performance',
184
185
  revisable: 'yes',
186
+ made_by: 'agent',
185
187
  superseded_by: null,
186
188
  });
187
189
  closeDatabase();
@@ -357,6 +359,7 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
357
359
  choice: 'yes',
358
360
  rationale: 'Robustness',
359
361
  revisable: 'no',
362
+ made_by: 'agent',
360
363
  superseded_by: null,
361
364
  });
362
365
  closeDatabase();
@@ -395,6 +398,7 @@ console.log('\n=== worktree-db: reconcileWorktreeDb ===');
395
398
  choice: 'works',
396
399
  rationale: 'Verify DETACH cleanup',
397
400
  revisable: 'no',
401
+ made_by: 'agent',
398
402
  superseded_by: null,
399
403
  });
400
404
 
@@ -0,0 +1,135 @@
1
+ /**
2
+ * worktree-health-dispatch.test.ts — Regression tests for the worktree health
3
+ * check in auto/phases.ts (#1833, #1843).
4
+ *
5
+ * Verifies that the pre-dispatch health check recognises non-JS project types
6
+ * (Rust, Go, Python, etc.) via the shared PROJECT_FILES list from detection.ts,
7
+ * rather than hard-coding package.json / src/ only.
8
+ */
9
+
10
+ import { describe, test, beforeEach, afterEach } from "node:test";
11
+ import assert from "node:assert/strict";
12
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ import { tmpdir } from "node:os";
15
+ import { execSync } from "node:child_process";
16
+
17
+ import { PROJECT_FILES } from "../detection.js";
18
+
19
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
20
+
21
+ /** Create a minimal git repo and return its path. */
22
+ function createGitRepo(): string {
23
+ const dir = mkdtempSync(join(tmpdir(), "wt-dispatch-test-"));
24
+ // All execSync calls use hardcoded strings only — no user input, no injection risk.
25
+ execSync("git init", { cwd: dir, stdio: "ignore" });
26
+ execSync("git config user.email test@test.com", { cwd: dir, stdio: "ignore" });
27
+ execSync("git config user.name Test", { cwd: dir, stdio: "ignore" });
28
+ writeFileSync(join(dir, "README.md"), "# test\n");
29
+ execSync("git add . && git commit -m init", { cwd: dir, stdio: "ignore" });
30
+ return dir;
31
+ }
32
+
33
+ /**
34
+ * Simulate the health check logic from auto/phases.ts.
35
+ *
36
+ * Returns true when the directory would PASS the health check (dispatch
37
+ * proceeds), false when it would FAIL (dispatch blocked).
38
+ *
39
+ * This mirrors the fixed logic: .git must exist, AND at least one
40
+ * PROJECT_FILES entry or a src/ directory must exist.
41
+ */
42
+ function wouldPassHealthCheck(basePath: string, existsSyncFn: (p: string) => boolean): boolean {
43
+ const hasGit = existsSyncFn(join(basePath, ".git"));
44
+ if (!hasGit) return false;
45
+
46
+ for (const file of PROJECT_FILES) {
47
+ if (existsSyncFn(join(basePath, file))) return true;
48
+ }
49
+ if (existsSyncFn(join(basePath, "src"))) return true;
50
+
51
+ return false;
52
+ }
53
+
54
+ import { existsSync } from "node:fs";
55
+
56
+ // ─── Tests ───────────────────────────────────────────────────────────────────
57
+
58
+ test("PROJECT_FILES is exported and contains expected multi-ecosystem entries", () => {
59
+ assert.ok(Array.isArray(PROJECT_FILES), "PROJECT_FILES is an array");
60
+ assert.ok(PROJECT_FILES.length >= 17, `expected >= 17 entries, got ${PROJECT_FILES.length}`);
61
+ // Spot-check key ecosystems
62
+ assert.ok(PROJECT_FILES.includes("Cargo.toml"), "includes Rust marker");
63
+ assert.ok(PROJECT_FILES.includes("go.mod"), "includes Go marker");
64
+ assert.ok(PROJECT_FILES.includes("pyproject.toml"), "includes Python marker");
65
+ assert.ok(PROJECT_FILES.includes("package.json"), "includes JS marker");
66
+ assert.ok(PROJECT_FILES.includes("pom.xml"), "includes Java marker");
67
+ assert.ok(PROJECT_FILES.includes("Package.swift"), "includes Swift marker");
68
+ });
69
+
70
+ describe("health check with git repo", () => {
71
+ let dir: string;
72
+ beforeEach(() => { dir = createGitRepo(); });
73
+ afterEach(() => { rmSync(dir, { recursive: true, force: true }); });
74
+
75
+ test("health check passes for Rust project (Cargo.toml, no package.json)", () => {
76
+ writeFileSync(join(dir, "Cargo.toml"), "[package]\nname = \"test\"\n");
77
+ mkdirSync(join(dir, "crates"), { recursive: true });
78
+ assert.ok(wouldPassHealthCheck(dir, existsSync), "Rust project should pass health check");
79
+ });
80
+
81
+ test("health check passes for Go project (go.mod, no package.json)", () => {
82
+ writeFileSync(join(dir, "go.mod"), "module example.com/test\n\ngo 1.21\n");
83
+ assert.ok(wouldPassHealthCheck(dir, existsSync), "Go project should pass health check");
84
+ });
85
+
86
+ test("health check passes for Python project (pyproject.toml, no package.json)", () => {
87
+ writeFileSync(join(dir, "pyproject.toml"), "[project]\nname = \"test\"\n");
88
+ assert.ok(wouldPassHealthCheck(dir, existsSync), "Python project should pass health check");
89
+ });
90
+
91
+ test("health check passes for Java project (pom.xml, no package.json)", () => {
92
+ writeFileSync(join(dir, "pom.xml"), "<project></project>\n");
93
+ assert.ok(wouldPassHealthCheck(dir, existsSync), "Java project should pass health check");
94
+ });
95
+
96
+ test("health check passes for Swift project (Package.swift, no package.json)", () => {
97
+ writeFileSync(join(dir, "Package.swift"), "// swift-tools-version:5.7\n");
98
+ assert.ok(wouldPassHealthCheck(dir, existsSync), "Swift project should pass health check");
99
+ });
100
+
101
+ test("health check passes for C/C++ project (CMakeLists.txt, no package.json)", () => {
102
+ writeFileSync(join(dir, "CMakeLists.txt"), "cmake_minimum_required(VERSION 3.20)\n");
103
+ assert.ok(wouldPassHealthCheck(dir, existsSync), "C/C++ project should pass health check");
104
+ });
105
+
106
+ test("health check passes for Elixir project (mix.exs, no package.json)", () => {
107
+ writeFileSync(join(dir, "mix.exs"), "defmodule Test.MixProject do\nend\n");
108
+ assert.ok(wouldPassHealthCheck(dir, existsSync), "Elixir project should pass health check");
109
+ });
110
+
111
+ test("health check passes for JS project (package.json, backward compat)", () => {
112
+ writeFileSync(join(dir, "package.json"), '{"name":"test"}\n');
113
+ assert.ok(wouldPassHealthCheck(dir, existsSync), "JS project should pass health check");
114
+ });
115
+
116
+ test("health check passes for src/-only project (backward compat)", () => {
117
+ mkdirSync(join(dir, "src"), { recursive: true });
118
+ assert.ok(wouldPassHealthCheck(dir, existsSync), "src/-only project should pass health check");
119
+ });
120
+
121
+ test("health check fails for empty git repo with no project files", () => {
122
+ assert.ok(!wouldPassHealthCheck(dir, existsSync), "empty git repo should fail health check");
123
+ });
124
+ });
125
+
126
+ describe("health check without git repo", () => {
127
+ let dir: string;
128
+ beforeEach(() => { dir = mkdtempSync(join(tmpdir(), "wt-dispatch-test-nogit-")); });
129
+ afterEach(() => { rmSync(dir, { recursive: true, force: true }); });
130
+
131
+ test("health check fails for directory with no .git", () => {
132
+ writeFileSync(join(dir, "Cargo.toml"), "[package]\nname = \"test\"\n");
133
+ assert.ok(!wouldPassHealthCheck(dir, existsSync), "no-git directory should fail health check");
134
+ });
135
+ });
@@ -1,4 +1,6 @@
1
- import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync, readFileSync } from "node:fs";
1
+ import { describe, test, beforeEach, afterEach } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync } from "node:fs";
2
4
  import { join } from "node:path";
3
5
  import { tmpdir } from "node:os";
4
6
  import { execSync } from "node:child_process";
@@ -13,82 +15,42 @@ import {
13
15
  worktreeBranchName,
14
16
  worktreePath,
15
17
  } from "../worktree-manager.ts";
16
- import { createTestContext } from './test-helpers.ts';
17
18
 
18
- const { assertEq, assertTrue, report } = createTestContext();
19
19
  function run(command: string, cwd: string): string {
20
20
  return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
21
21
  }
22
22
 
23
- // Set up a test repo
24
- const base = mkdtempSync(join(tmpdir(), "gsd-worktree-mgr-test-"));
25
- run("git init -b main", base);
26
- run('git config user.name "Pi Test"', base);
27
- run('git config user.email "pi@example.com"', base);
28
-
29
- // Create initial project structure
30
- mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
31
- writeFileSync(join(base, "README.md"), "# Test Project\n", "utf-8");
32
- writeFileSync(
33
- join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"),
34
- "# M001: Demo\n\n## Slices\n- [ ] **S01: First** `risk:low` `depends:[]`\n > After this: it works\n",
35
- "utf-8",
36
- );
37
- run("git add .", base);
38
- run('git commit -m "chore: init"', base);
39
-
40
- async function main(): Promise<void> {
41
- console.log("\n=== worktreeBranchName ===");
42
- assertEq(worktreeBranchName("feature-x"), "worktree/feature-x", "branch name format");
43
-
44
- console.log("\n=== createWorktree ===");
45
- const info = createWorktree(base, "feature-x");
46
- assertTrue(info.name === "feature-x", "name matches");
47
- assertTrue(info.branch === "worktree/feature-x", "branch matches");
48
- assertTrue(info.exists, "worktree exists");
49
- assertTrue(existsSync(info.path), "worktree path exists on disk");
50
- assertTrue(existsSync(join(info.path, "README.md")), "README.md copied to worktree");
51
- assertTrue(existsSync(join(info.path, ".gsd", "milestones", "M001", "M001-ROADMAP.md")), ".gsd files copied");
52
-
53
- // Branch was created
54
- const branches = run("git branch", base);
55
- assertTrue(branches.includes("worktree/feature-x"), "branch was created");
56
-
57
- console.log("\n=== createWorktree — duplicate ===");
58
- let duplicateError = "";
59
- try {
60
- createWorktree(base, "feature-x");
61
- } catch (e) {
62
- duplicateError = (e as Error).message;
63
- }
64
- assertTrue(duplicateError.includes("already exists"), "duplicate creation fails");
65
-
66
- console.log("\n=== createWorktree — invalid name ===");
67
- let invalidError = "";
68
- try {
69
- createWorktree(base, "bad name!");
70
- } catch (e) {
71
- invalidError = (e as Error).message;
72
- }
73
- assertTrue(invalidError.includes("Invalid worktree name"), "invalid name rejected");
74
-
75
- console.log("\n=== listWorktrees ===");
76
- const list = listWorktrees(base);
77
- assertEq(list.length, 1, "one worktree listed");
78
- assertEq(list[0]!.name, "feature-x", "correct name");
79
- assertEq(list[0]!.branch, "worktree/feature-x", "correct branch");
80
- assertTrue(list[0]!.exists, "exists flag is true");
81
-
82
- console.log("\n=== make changes in worktree ===");
83
- const wtPath = worktreePath(base, "feature-x");
84
- // Add a new GSD artifact in the worktree
23
+ function makeBaseRepo(): string {
24
+ const base = mkdtempSync(join(tmpdir(), "gsd-wt-test-"));
25
+ run("git init -b main", base);
26
+ run('git config user.name "Test User"', base);
27
+ run('git config user.email "test@example.com"', base);
28
+ mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
29
+ writeFileSync(join(base, "README.md"), "# Test Project\n", "utf-8");
30
+ writeFileSync(
31
+ join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"),
32
+ "# M001: Demo\n\n## Slices\n- [ ] **S01: First** `risk:low` `depends:[]`\n > After this: it works\n",
33
+ "utf-8",
34
+ );
35
+ run("git add .", base);
36
+ run('git commit -m "chore: init"', base);
37
+ return base;
38
+ }
39
+
40
+ function makeRepoWithWorktree(worktreeName: string): { base: string; wtPath: string } {
41
+ const base = makeBaseRepo();
42
+ createWorktree(base, worktreeName);
43
+ return { base, wtPath: worktreePath(base, worktreeName) };
44
+ }
45
+
46
+ function makeRepoWithChanges(worktreeName: string): { base: string; wtPath: string } {
47
+ const { base, wtPath } = makeRepoWithWorktree(worktreeName);
85
48
  mkdirSync(join(wtPath, ".gsd", "milestones", "M002"), { recursive: true });
86
49
  writeFileSync(
87
50
  join(wtPath, ".gsd", "milestones", "M002", "M002-ROADMAP.md"),
88
51
  "# M002: New Feature\n\n## Slices\n- [ ] **S01: Setup** `risk:low` `depends:[]`\n > After this: new feature ready\n",
89
52
  "utf-8",
90
53
  );
91
- // Modify an existing artifact
92
54
  writeFileSync(
93
55
  join(wtPath, ".gsd", "milestones", "M001", "M001-ROADMAP.md"),
94
56
  "# M001: Demo (updated)\n\n## Slices\n- [x] **S01: First** `risk:low` `depends:[]`\n > Done\n",
@@ -96,46 +58,181 @@ async function main(): Promise<void> {
96
58
  );
97
59
  run("git add .", wtPath);
98
60
  run('git commit -m "feat: add M002 and update M001"', wtPath);
99
-
100
- console.log("\n=== diffWorktreeGSD ===");
101
- const diff = diffWorktreeGSD(base, "feature-x");
102
- assertTrue(diff.added.length > 0, "has added files");
103
- assertTrue(diff.added.some(f => f.includes("M002")), "M002 roadmap is in added");
104
- assertTrue(diff.modified.length > 0, "has modified files");
105
- assertTrue(diff.modified.some(f => f.includes("M001")), "M001 roadmap is in modified");
106
- assertEq(diff.removed.length, 0, "no removed files");
107
-
108
- console.log("\n=== getWorktreeGSDDiff ===");
109
- const fullDiff = getWorktreeGSDDiff(base, "feature-x");
110
- assertTrue(fullDiff.includes("M002"), "full diff mentions M002");
111
- assertTrue(fullDiff.includes("updated"), "full diff mentions update");
112
-
113
- console.log("\n=== getWorktreeLog ===");
114
- const log = getWorktreeLog(base, "feature-x");
115
- assertTrue(log.includes("add M002"), "log shows commit message");
116
-
117
- console.log("\n=== removeWorktree ===");
118
- removeWorktree(base, "feature-x", { deleteBranch: true });
119
- assertTrue(!existsSync(wtPath), "worktree directory removed");
120
- const branchesAfter = run("git branch", base);
121
- assertTrue(!branchesAfter.includes("worktree/feature-x"), "branch deleted");
122
-
123
- console.log("\n=== listWorktrees after removal ===");
124
- const listAfter = listWorktrees(base);
125
- assertEq(listAfter.length, 0, "no worktrees after removal");
126
-
127
- console.log("\n=== removeWorktree — already gone ===");
128
- // Should not throw
129
- removeWorktree(base, "feature-x", { deleteBranch: true });
130
- assertTrue(true, "removeWorktree on missing worktree does not throw");
131
-
132
- // Cleanup
133
- rmSync(base, { recursive: true, force: true });
134
-
135
- report();
61
+ return { base, wtPath };
136
62
  }
137
63
 
138
- main().catch((error) => {
139
- console.error(error);
140
- process.exit(1);
64
+ // ─── worktreeBranchName ───────────────────────────────────────────────────────
65
+
66
+ test("worktreeBranchName formats branch name", () => {
67
+ assert.strictEqual(
68
+ worktreeBranchName("feature-x"),
69
+ "worktree/feature-x",
70
+ "should prefix with worktree/",
71
+ );
72
+ });
73
+
74
+ // ─── createWorktree ───────────────────────────────────────────────────────────
75
+
76
+ describe("createWorktree", () => {
77
+ let base: string;
78
+ beforeEach(() => { base = makeBaseRepo(); });
79
+ afterEach(() => { rmSync(base, { recursive: true, force: true }); });
80
+
81
+ test("creates worktree with correct metadata", () => {
82
+ const info = createWorktree(base, "feature-x");
83
+ assert.strictEqual(info.name, "feature-x", "name should match");
84
+ assert.strictEqual(info.branch, "worktree/feature-x", "branch should be prefixed");
85
+ assert.ok(info.exists, "exists flag should be true");
86
+ assert.ok(existsSync(info.path), "worktree path should exist on disk");
87
+ assert.ok(existsSync(join(info.path, "README.md")), "README.md should be in worktree");
88
+ assert.ok(
89
+ existsSync(join(info.path, ".gsd", "milestones", "M001", "M001-ROADMAP.md")),
90
+ ".gsd files should be in worktree",
91
+ );
92
+ const branches = run("git branch", base);
93
+ assert.ok(branches.includes("worktree/feature-x"), "branch should be created in base repo");
94
+ });
95
+
96
+ test("rejects invalid name", () => {
97
+ assert.throws(
98
+ () => createWorktree(base, "bad name!"),
99
+ (err: Error) => {
100
+ assert.ok(
101
+ err.message.includes("Invalid worktree name"),
102
+ `expected "Invalid worktree name" in error, got: ${err.message}`,
103
+ );
104
+ return true;
105
+ },
106
+ "should throw on invalid worktree name",
107
+ );
108
+ });
109
+ });
110
+
111
+ describe("createWorktree — duplicate rejection", () => {
112
+ let base: string;
113
+ beforeEach(() => {
114
+ const repo = makeRepoWithWorktree("feature-x");
115
+ base = repo.base;
116
+ });
117
+ afterEach(() => { rmSync(base, { recursive: true, force: true }); });
118
+
119
+ test("rejects duplicate name", () => {
120
+ assert.throws(
121
+ () => createWorktree(base, "feature-x"),
122
+ (err: Error) => {
123
+ assert.ok(
124
+ err.message.includes("already exists"),
125
+ `expected "already exists" in error, got: ${err.message}`,
126
+ );
127
+ return true;
128
+ },
129
+ "should throw on duplicate worktree name",
130
+ );
131
+ });
132
+ });
133
+
134
+ // ─── listWorktrees ────────────────────────────────────────────────────────────
135
+
136
+ describe("listWorktrees", () => {
137
+ let base: string;
138
+ beforeEach(() => {
139
+ const repo = makeRepoWithWorktree("feature-x");
140
+ base = repo.base;
141
+ });
142
+ afterEach(() => { rmSync(base, { recursive: true, force: true }); });
143
+
144
+ test("returns active worktrees", () => {
145
+ const list = listWorktrees(base);
146
+ assert.strictEqual(list.length, 1, "should list exactly one worktree");
147
+ assert.strictEqual(list[0]!.name, "feature-x", "name should match");
148
+ assert.strictEqual(list[0]!.branch, "worktree/feature-x", "branch should match");
149
+ assert.ok(list[0]!.exists, "exists flag should be true");
150
+ });
151
+
152
+ test("returns empty after removal", () => {
153
+ removeWorktree(base, "feature-x");
154
+ const list = listWorktrees(base);
155
+ assert.strictEqual(list.length, 0, "should have no worktrees after removal");
156
+ });
157
+ });
158
+
159
+ // ─── diffWorktreeGSD ─────────────────────────────────────────────────────────
160
+
161
+ describe("diffWorktreeGSD and getWorktreeGSDDiff", () => {
162
+ let base: string;
163
+ beforeEach(() => {
164
+ const repo = makeRepoWithChanges("feature-x");
165
+ base = repo.base;
166
+ });
167
+ afterEach(() => { rmSync(base, { recursive: true, force: true }); });
168
+
169
+ test("detects added and modified GSD files", () => {
170
+ const diff = diffWorktreeGSD(base, "feature-x");
171
+ assert.ok(diff.added.length > 0, "should have added files");
172
+ assert.ok(
173
+ diff.added.some((f) => f.includes("M002")),
174
+ "M002 roadmap should be in added files",
175
+ );
176
+ assert.ok(diff.modified.length > 0, "should have modified files");
177
+ assert.ok(
178
+ diff.modified.some((f) => f.includes("M001")),
179
+ "M001 roadmap should be in modified files",
180
+ );
181
+ assert.strictEqual(diff.removed.length, 0, "should have no removed files");
182
+ });
183
+
184
+ test("returns patch content", () => {
185
+ const fullDiff = getWorktreeGSDDiff(base, "feature-x");
186
+ assert.ok(fullDiff.includes("M002"), "diff should mention M002");
187
+ assert.ok(fullDiff.includes("updated"), "diff should mention the update");
188
+ });
189
+ });
190
+
191
+ // ─── getWorktreeLog ───────────────────────────────────────────────────────────
192
+
193
+ describe("getWorktreeLog", () => {
194
+ let base: string;
195
+ beforeEach(() => {
196
+ const repo = makeRepoWithChanges("feature-x");
197
+ base = repo.base;
198
+ });
199
+ afterEach(() => { rmSync(base, { recursive: true, force: true }); });
200
+
201
+ test("shows commits", () => {
202
+ const log = getWorktreeLog(base, "feature-x");
203
+ assert.ok(log.includes("add M002"), "log should include the commit message");
204
+ });
205
+ });
206
+
207
+ // ─── removeWorktree ───────────────────────────────────────────────────────────
208
+
209
+ describe("removeWorktree", () => {
210
+ let base: string;
211
+ let wtPath: string;
212
+ beforeEach(() => {
213
+ const repo = makeRepoWithWorktree("feature-x");
214
+ base = repo.base;
215
+ wtPath = repo.wtPath;
216
+ });
217
+ afterEach(() => { rmSync(base, { recursive: true, force: true }); });
218
+
219
+ test("removes directory and branch", () => {
220
+ removeWorktree(base, "feature-x", { deleteBranch: true });
221
+ assert.ok(!existsSync(wtPath), "worktree directory should be gone");
222
+ const branches = run("git branch", base);
223
+ assert.ok(!branches.includes("worktree/feature-x"), "branch should be deleted");
224
+ });
225
+ });
226
+
227
+ describe("removeWorktree — missing worktree", () => {
228
+ let base: string;
229
+ beforeEach(() => { base = makeBaseRepo(); });
230
+ afterEach(() => { rmSync(base, { recursive: true, force: true }); });
231
+
232
+ test("on missing worktree does not throw", () => {
233
+ assert.doesNotThrow(
234
+ () => removeWorktree(base, "nonexistent"),
235
+ "should not throw when worktree does not exist",
236
+ );
237
+ });
141
238
  });