gsd-pi 2.41.0-dev.0acbce9 → 2.41.0-dev.5a170d0

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 (291) hide show
  1. package/README.md +1 -1
  2. package/dist/cli-web-branch.d.ts +6 -0
  3. package/dist/cli-web-branch.js +17 -0
  4. package/dist/onboarding.js +2 -1
  5. package/dist/resources/extensions/gsd/auto/loop.js +89 -1
  6. package/dist/resources/extensions/gsd/auto/phases.js +28 -10
  7. package/dist/resources/extensions/gsd/auto/session.js +6 -0
  8. package/dist/resources/extensions/gsd/auto-dashboard.js +8 -2
  9. package/dist/resources/extensions/gsd/auto-dispatch.js +19 -2
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -0
  11. package/dist/resources/extensions/gsd/auto-recovery.js +12 -4
  12. package/dist/resources/extensions/gsd/auto-start.js +8 -3
  13. package/dist/resources/extensions/gsd/auto-worktree.js +147 -13
  14. package/dist/resources/extensions/gsd/auto.js +64 -2
  15. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +199 -164
  16. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +62 -0
  17. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
  18. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +16 -0
  19. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +7 -2
  20. package/dist/resources/extensions/gsd/commands/catalog.js +40 -1
  21. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
  22. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  23. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +146 -0
  24. package/dist/resources/extensions/gsd/context-injector.js +74 -0
  25. package/dist/resources/extensions/gsd/context-store.js +4 -3
  26. package/dist/resources/extensions/gsd/custom-execution-policy.js +47 -0
  27. package/dist/resources/extensions/gsd/custom-verification.js +145 -0
  28. package/dist/resources/extensions/gsd/custom-workflow-engine.js +164 -0
  29. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -0
  30. package/dist/resources/extensions/gsd/db-writer.js +5 -2
  31. package/dist/resources/extensions/gsd/definition-loader.js +352 -0
  32. package/dist/resources/extensions/gsd/detection.js +1 -1
  33. package/dist/resources/extensions/gsd/dev-execution-policy.js +24 -0
  34. package/dist/resources/extensions/gsd/dev-workflow-engine.js +82 -0
  35. package/dist/resources/extensions/gsd/doctor.js +11 -1
  36. package/dist/resources/extensions/gsd/engine-resolver.js +40 -0
  37. package/dist/resources/extensions/gsd/engine-types.js +8 -0
  38. package/dist/resources/extensions/gsd/execution-policy.js +8 -0
  39. package/dist/resources/extensions/gsd/exit-command.js +12 -2
  40. package/dist/resources/extensions/gsd/export.js +9 -13
  41. package/dist/resources/extensions/gsd/extension-manifest.json +2 -2
  42. package/dist/resources/extensions/gsd/files.js +28 -11
  43. package/dist/resources/extensions/gsd/forensics.js +10 -3
  44. package/dist/resources/extensions/gsd/git-service.js +5 -1
  45. package/dist/resources/extensions/gsd/graph.js +225 -0
  46. package/dist/resources/extensions/gsd/gsd-db.js +25 -8
  47. package/dist/resources/extensions/gsd/guided-flow-queue.js +1 -1
  48. package/dist/resources/extensions/gsd/guided-flow.js +7 -3
  49. package/dist/resources/extensions/gsd/journal.js +85 -0
  50. package/dist/resources/extensions/gsd/md-importer.js +5 -0
  51. package/dist/resources/extensions/gsd/milestone-ids.js +1 -1
  52. package/dist/resources/extensions/gsd/native-git-bridge.js +2 -2
  53. package/dist/resources/extensions/gsd/post-unit-hooks.js +24 -412
  54. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  55. package/dist/resources/extensions/gsd/preferences.js +1 -0
  56. package/dist/resources/extensions/gsd/prompt-loader.js +34 -4
  57. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
  58. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
  59. package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
  60. package/dist/resources/extensions/gsd/prompts/queue.md +1 -1
  61. package/dist/resources/extensions/gsd/repo-identity.js +46 -2
  62. package/dist/resources/extensions/gsd/rule-registry.js +489 -0
  63. package/dist/resources/extensions/gsd/rule-types.js +6 -0
  64. package/dist/resources/extensions/gsd/run-manager.js +134 -0
  65. package/dist/resources/extensions/gsd/service-tier.js +138 -0
  66. package/dist/resources/extensions/gsd/structured-data-formatter.js +2 -1
  67. package/dist/resources/extensions/gsd/templates/decisions.md +2 -2
  68. package/dist/resources/extensions/gsd/workflow-engine.js +7 -0
  69. package/dist/resources/extensions/gsd/workflow-templates.js +13 -1
  70. package/dist/resources/extensions/gsd/worktree-manager.js +20 -6
  71. package/dist/resources/extensions/gsd/worktree-resolver.js +19 -2
  72. package/dist/resources/extensions/subagent/index.js +7 -3
  73. package/dist/resources/extensions/voice/index.js +4 -4
  74. package/dist/resources/skills/create-workflow/SKILL.md +103 -0
  75. package/dist/resources/skills/create-workflow/references/feature-patterns.md +128 -0
  76. package/dist/resources/skills/create-workflow/references/verification-policies.md +76 -0
  77. package/dist/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
  78. package/dist/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
  79. package/dist/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
  80. package/dist/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
  81. package/dist/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
  82. package/dist/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
  83. package/dist/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
  84. package/dist/web/standalone/.next/BUILD_ID +1 -1
  85. package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
  86. package/dist/web/standalone/.next/build-manifest.json +3 -3
  87. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  88. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  90. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/index.html +1 -1
  121. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
  128. package/dist/web/standalone/.next/server/chunks/229.js +3 -3
  129. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  132. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  133. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  134. package/dist/web/standalone/.next/static/chunks/4024.c195dc1fdd2adbea.js +9 -0
  135. package/dist/web/standalone/.next/static/chunks/{webpack-9afaaebf6042a1d7.js → webpack-fa307370fcf9fb2c.js} +1 -1
  136. package/dist/web-mode.d.ts +2 -0
  137. package/dist/web-mode.js +29 -7
  138. package/package.json +1 -1
  139. package/packages/native/src/__tests__/text.test.mjs +33 -0
  140. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +3 -1
  141. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
  142. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  143. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +10 -7
  144. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  145. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -0
  147. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  148. package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +4 -2
  149. package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +11 -7
  150. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +5 -0
  151. package/src/resources/extensions/gsd/auto/loop-deps.ts +5 -1
  152. package/src/resources/extensions/gsd/auto/loop.ts +101 -1
  153. package/src/resources/extensions/gsd/auto/phases.ts +30 -10
  154. package/src/resources/extensions/gsd/auto/session.ts +6 -0
  155. package/src/resources/extensions/gsd/auto/types.ts +4 -0
  156. package/src/resources/extensions/gsd/auto-dashboard.ts +9 -2
  157. package/src/resources/extensions/gsd/auto-dispatch.ts +25 -5
  158. package/src/resources/extensions/gsd/auto-post-unit.ts +8 -0
  159. package/src/resources/extensions/gsd/auto-recovery.ts +12 -4
  160. package/src/resources/extensions/gsd/auto-start.ts +8 -3
  161. package/src/resources/extensions/gsd/auto-worktree.ts +162 -18
  162. package/src/resources/extensions/gsd/auto.ts +71 -2
  163. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +209 -162
  164. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +62 -0
  165. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
  166. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +13 -0
  167. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +9 -2
  168. package/src/resources/extensions/gsd/commands/catalog.ts +40 -1
  169. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
  170. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  171. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +164 -0
  172. package/src/resources/extensions/gsd/context-injector.ts +100 -0
  173. package/src/resources/extensions/gsd/context-store.ts +4 -3
  174. package/src/resources/extensions/gsd/custom-execution-policy.ts +73 -0
  175. package/src/resources/extensions/gsd/custom-verification.ts +180 -0
  176. package/src/resources/extensions/gsd/custom-workflow-engine.ts +216 -0
  177. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -0
  178. package/src/resources/extensions/gsd/db-writer.ts +6 -2
  179. package/src/resources/extensions/gsd/definition-loader.ts +462 -0
  180. package/src/resources/extensions/gsd/detection.ts +1 -1
  181. package/src/resources/extensions/gsd/dev-execution-policy.ts +51 -0
  182. package/src/resources/extensions/gsd/dev-workflow-engine.ts +110 -0
  183. package/src/resources/extensions/gsd/doctor.ts +12 -1
  184. package/src/resources/extensions/gsd/engine-resolver.ts +57 -0
  185. package/src/resources/extensions/gsd/engine-types.ts +71 -0
  186. package/src/resources/extensions/gsd/execution-policy.ts +43 -0
  187. package/src/resources/extensions/gsd/exit-command.ts +14 -2
  188. package/src/resources/extensions/gsd/export.ts +8 -15
  189. package/src/resources/extensions/gsd/extension-manifest.json +2 -2
  190. package/src/resources/extensions/gsd/files.ts +29 -12
  191. package/src/resources/extensions/gsd/forensics.ts +9 -3
  192. package/src/resources/extensions/gsd/git-service.ts +5 -4
  193. package/src/resources/extensions/gsd/graph.ts +312 -0
  194. package/src/resources/extensions/gsd/gsd-db.ts +37 -8
  195. package/src/resources/extensions/gsd/guided-flow-queue.ts +1 -1
  196. package/src/resources/extensions/gsd/guided-flow.ts +7 -3
  197. package/src/resources/extensions/gsd/journal.ts +134 -0
  198. package/src/resources/extensions/gsd/md-importer.ts +6 -0
  199. package/src/resources/extensions/gsd/milestone-ids.ts +1 -1
  200. package/src/resources/extensions/gsd/native-git-bridge.ts +2 -2
  201. package/src/resources/extensions/gsd/post-unit-hooks.ts +24 -462
  202. package/src/resources/extensions/gsd/preferences-types.ts +3 -0
  203. package/src/resources/extensions/gsd/preferences.ts +1 -0
  204. package/src/resources/extensions/gsd/prompt-loader.ts +35 -4
  205. package/src/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
  206. package/src/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
  207. package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
  208. package/src/resources/extensions/gsd/prompts/queue.md +1 -1
  209. package/src/resources/extensions/gsd/repo-identity.ts +47 -2
  210. package/src/resources/extensions/gsd/rule-registry.ts +599 -0
  211. package/src/resources/extensions/gsd/rule-types.ts +68 -0
  212. package/src/resources/extensions/gsd/run-manager.ts +180 -0
  213. package/src/resources/extensions/gsd/service-tier.ts +171 -0
  214. package/src/resources/extensions/gsd/structured-data-formatter.ts +3 -1
  215. package/src/resources/extensions/gsd/templates/decisions.md +2 -2
  216. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +103 -120
  217. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +85 -0
  218. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +2 -2
  219. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +202 -0
  220. package/src/resources/extensions/gsd/tests/bundled-workflow-defs.test.ts +180 -0
  221. package/src/resources/extensions/gsd/tests/captures.test.ts +12 -1
  222. package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +283 -0
  223. package/src/resources/extensions/gsd/tests/context-injector.test.ts +313 -0
  224. package/src/resources/extensions/gsd/tests/context-store.test.ts +10 -5
  225. package/src/resources/extensions/gsd/tests/continue-here.test.ts +20 -20
  226. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +540 -0
  227. package/src/resources/extensions/gsd/tests/custom-verification.test.ts +382 -0
  228. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +339 -0
  229. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +87 -0
  230. package/src/resources/extensions/gsd/tests/db-writer.test.ts +10 -0
  231. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +778 -0
  232. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +318 -0
  233. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +15 -10
  234. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +5 -4
  235. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +167 -0
  236. package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +174 -0
  237. package/src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts +476 -0
  238. package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +271 -0
  239. package/src/resources/extensions/gsd/tests/exit-command.test.ts +55 -0
  240. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +599 -0
  241. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +8 -1
  242. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +7 -7
  243. package/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts +429 -0
  244. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +513 -0
  245. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +147 -0
  246. package/src/resources/extensions/gsd/tests/journal.test.ts +386 -0
  247. package/src/resources/extensions/gsd/tests/md-importer.test.ts +31 -1
  248. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  249. package/src/resources/extensions/gsd/tests/milestone-id-reservation.test.ts +1 -1
  250. package/src/resources/extensions/gsd/tests/parsers.test.ts +110 -0
  251. package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -25
  252. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +3 -1
  253. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +61 -1
  254. package/src/resources/extensions/gsd/tests/routing-history.test.ts +11 -22
  255. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +413 -0
  256. package/src/resources/extensions/gsd/tests/run-manager.test.ts +229 -0
  257. package/src/resources/extensions/gsd/tests/service-tier.test.ts +98 -0
  258. package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +2 -2
  259. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +102 -0
  260. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +4 -3
  261. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +45 -0
  262. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +117 -0
  263. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -1
  264. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +99 -0
  265. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -0
  266. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +4 -0
  267. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +178 -0
  268. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +195 -105
  269. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -3
  270. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +140 -0
  271. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +74 -0
  272. package/src/resources/extensions/gsd/types.ts +3 -0
  273. package/src/resources/extensions/gsd/workflow-engine.ts +38 -0
  274. package/src/resources/extensions/gsd/workflow-templates.ts +12 -1
  275. package/src/resources/extensions/gsd/worktree-manager.ts +21 -6
  276. package/src/resources/extensions/gsd/worktree-resolver.ts +30 -9
  277. package/src/resources/extensions/subagent/index.ts +7 -3
  278. package/src/resources/extensions/voice/index.ts +4 -4
  279. package/src/resources/skills/create-workflow/SKILL.md +103 -0
  280. package/src/resources/skills/create-workflow/references/feature-patterns.md +128 -0
  281. package/src/resources/skills/create-workflow/references/verification-policies.md +76 -0
  282. package/src/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
  283. package/src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
  284. package/src/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
  285. package/src/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
  286. package/src/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
  287. package/src/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
  288. package/src/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
  289. package/dist/web/standalone/.next/static/chunks/4024.279c423e4661ece1.js +0 -9
  290. /package/dist/web/standalone/.next/static/{SwbKZ7JPNFlEmU4f8pKEv → K7GYOOPvQWX6TKYEKhODM}/_buildManifest.js +0 -0
  291. /package/dist/web/standalone/.next/static/{SwbKZ7JPNFlEmU4f8pKEv → K7GYOOPvQWX6TKYEKhODM}/_ssgManifest.js +0 -0
@@ -9,7 +9,7 @@ import { createHash } from "node:crypto";
9
9
  import { execFileSync } from "node:child_process";
10
10
  import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
11
11
  import { homedir } from "node:os";
12
- import { basename, join, resolve } from "node:path";
12
+ import { basename, dirname, join, resolve } from "node:path";
13
13
  const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
14
14
  function isRepoMeta(value) {
15
15
  if (!value || typeof value !== "object")
@@ -81,6 +81,49 @@ export function readRepoMeta(externalPath) {
81
81
  return null;
82
82
  }
83
83
  }
84
+ // ─── Inherited-Repo Detection ───────────────────────────────────────────────
85
+ /**
86
+ * Check whether `basePath` is inheriting a parent directory's git repo
87
+ * rather than being the git root itself.
88
+ *
89
+ * Returns true when ALL of:
90
+ * 1. basePath is inside a git repo (git rev-parse succeeds)
91
+ * 2. The resolved git root is a proper ancestor of basePath
92
+ * 3. There is no `.gsd` directory at the git root (the parent project
93
+ * has not been initialised with GSD)
94
+ *
95
+ * When true, the caller should run `git init` at basePath so that
96
+ * `repoIdentity()` produces a hash unique to this directory, preventing
97
+ * cross-project state leaks (#1639).
98
+ *
99
+ * When the git root already has `.gsd`, the directory is a legitimate
100
+ * subdirectory of an existing GSD project — `cd src/ && /gsd` should
101
+ * still load the parent project's milestones.
102
+ */
103
+ export function isInheritedRepo(basePath) {
104
+ try {
105
+ const root = resolveGitRoot(basePath);
106
+ const normalizedBase = canonicalizeExistingPath(basePath);
107
+ const normalizedRoot = canonicalizeExistingPath(root);
108
+ if (normalizedBase === normalizedRoot)
109
+ return false; // basePath IS the root
110
+ // The git root is a proper ancestor. Check whether it already has .gsd
111
+ // (i.e. the parent project was initialised with GSD).
112
+ if (existsSync(join(root, ".gsd")))
113
+ return false;
114
+ // Also walk up from basePath to the git root checking for .gsd
115
+ let dir = normalizedBase;
116
+ while (dir !== normalizedRoot && dir !== dirname(dir)) {
117
+ if (existsSync(join(dir, ".gsd")))
118
+ return false;
119
+ dir = dirname(dir);
120
+ }
121
+ return true;
122
+ }
123
+ catch {
124
+ return false;
125
+ }
126
+ }
84
127
  // ─── Repo Identity ──────────────────────────────────────────────────────────
85
128
  /**
86
129
  * Get the git remote URL for "origin", or "" if no remote is configured.
@@ -105,7 +148,8 @@ function getRemoteUrl(basePath) {
105
148
  */
106
149
  function canonicalizeExistingPath(path) {
107
150
  try {
108
- return realpathSync(path);
151
+ // Use native realpath on Windows to resolve 8.3 short paths (e.g. RUNNER~1)
152
+ return process.platform === "win32" ? realpathSync.native(path) : realpathSync(path);
109
153
  }
110
154
  catch {
111
155
  return resolve(path);
@@ -0,0 +1,489 @@
1
+ // GSD Extension — Unified Rule Registry
2
+ //
3
+ // Holds all dispatch rules and hooks as a flat list of UnifiedRule objects.
4
+ // Provides evaluation methods for each phase (dispatch, post-unit, pre-dispatch)
5
+ // and encapsulates mutable hook state as instance fields.
6
+ //
7
+ // A module-level singleton accessor allows existing code to migrate incrementally.
8
+ import { resolvePostUnitHooks, resolvePreDispatchHooks } from "./preferences.js";
9
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ // ─── Artifact Path Resolution ──────────────────────────────────────────────
12
+ export function resolveHookArtifactPath(basePath, unitId, artifactName) {
13
+ const parts = unitId.split("/");
14
+ if (parts.length === 3) {
15
+ const [mid, sid, tid] = parts;
16
+ return join(basePath, ".gsd", "milestones", mid, "slices", sid, "tasks", `${tid}-${artifactName}`);
17
+ }
18
+ if (parts.length === 2) {
19
+ const [mid, sid] = parts;
20
+ return join(basePath, ".gsd", "milestones", mid, "slices", sid, artifactName);
21
+ }
22
+ return join(basePath, ".gsd", "milestones", parts[0], artifactName);
23
+ }
24
+ // ─── Dispatch Rule Conversion ──────────────────────────────────────────────
25
+ /**
26
+ * Convert an array of DispatchRule objects to UnifiedRule[] format.
27
+ * Preserves exact array order — dispatch is order-dependent (first-match-wins).
28
+ */
29
+ export function convertDispatchRules(rules) {
30
+ return rules.map((rule) => ({
31
+ name: rule.name,
32
+ when: "dispatch",
33
+ evaluation: "first-match",
34
+ where: rule.match,
35
+ then: (result) => result,
36
+ description: `Dispatch rule: ${rule.name}`,
37
+ }));
38
+ }
39
+ // ─── RuleRegistry ─────────────────────────────────────────────────────────
40
+ const HOOK_STATE_FILE = "hook-state.json";
41
+ export class RuleRegistry {
42
+ /** Static dispatch rules provided at construction time. */
43
+ dispatchRules;
44
+ // ── Mutable hook state (encapsulated, not module-level) ──────────────
45
+ activeHook = null;
46
+ hookQueue = [];
47
+ cycleCounts = new Map();
48
+ retryPending = false;
49
+ retryTrigger = null;
50
+ constructor(dispatchRules) {
51
+ this.dispatchRules = dispatchRules;
52
+ }
53
+ // ── Core query ───────────────────────────────────────────────────────
54
+ /**
55
+ * Returns all rules: static dispatch rules + dynamically loaded hook rules.
56
+ * Hook rules are loaded fresh from preferences on each call (not cached).
57
+ */
58
+ listRules() {
59
+ const rules = [...this.dispatchRules];
60
+ // Convert post-unit hooks to unified rules
61
+ const postHooks = resolvePostUnitHooks();
62
+ for (const hook of postHooks) {
63
+ rules.push({
64
+ name: hook.name,
65
+ when: "post-unit",
66
+ evaluation: "all-matching",
67
+ where: (unitType) => hook.after.includes(unitType),
68
+ then: () => hook,
69
+ description: `Post-unit hook: fires after ${hook.after.join(", ")}`,
70
+ lifecycle: {
71
+ artifact: hook.artifact,
72
+ retry_on: hook.retry_on,
73
+ max_cycles: hook.max_cycles,
74
+ },
75
+ });
76
+ }
77
+ // Convert pre-dispatch hooks to unified rules
78
+ const preHooks = resolvePreDispatchHooks();
79
+ for (const hook of preHooks) {
80
+ rules.push({
81
+ name: hook.name,
82
+ when: "pre-dispatch",
83
+ evaluation: "all-matching",
84
+ where: (unitType) => hook.before.includes(unitType),
85
+ then: () => hook,
86
+ description: `Pre-dispatch hook: fires before ${hook.before.join(", ")}`,
87
+ });
88
+ }
89
+ return rules;
90
+ }
91
+ // ── Dispatch evaluation (async, first-match-wins) ───────────────────
92
+ /**
93
+ * Iterate dispatch rules in order. First match wins.
94
+ * Returns stop action if no rule matches (unhandled phase).
95
+ */
96
+ async evaluateDispatch(ctx) {
97
+ for (const rule of this.dispatchRules) {
98
+ const result = await rule.where(ctx);
99
+ if (result) {
100
+ if (result.action !== "skip")
101
+ result.matchedRule = rule.name;
102
+ return result;
103
+ }
104
+ }
105
+ return {
106
+ action: "stop",
107
+ reason: `Unhandled phase "${ctx.state.phase}" — run /gsd doctor to diagnose.`,
108
+ level: "info",
109
+ matchedRule: "<no-match>",
110
+ };
111
+ }
112
+ // ── Post-unit hook evaluation (sync, all-matching with lifecycle) ────
113
+ /**
114
+ * Replicate exact semantics of checkPostUnitHooks from post-unit-hooks.ts:
115
+ * hook-on-hook prevention, idempotency, cycle limits, retry_on, dequeue.
116
+ */
117
+ evaluatePostUnit(completedUnitType, completedUnitId, basePath) {
118
+ // If we just completed a hook unit, handle its result
119
+ if (this.activeHook) {
120
+ return this._handleHookCompletion(basePath);
121
+ }
122
+ // Don't trigger hooks for other hook units (prevent hook-on-hook chains)
123
+ // Don't trigger hooks for triage units or quick-task units
124
+ if (completedUnitType.startsWith("hook/") ||
125
+ completedUnitType === "triage-captures" ||
126
+ completedUnitType === "quick-task") {
127
+ return null;
128
+ }
129
+ // Check if any hooks are configured for this unit type
130
+ const hooks = resolvePostUnitHooks().filter(h => h.after.includes(completedUnitType));
131
+ if (hooks.length === 0)
132
+ return null;
133
+ // Build hook queue for this trigger
134
+ this.hookQueue = hooks.map(config => ({
135
+ config,
136
+ triggerUnitType: completedUnitType,
137
+ triggerUnitId: completedUnitId,
138
+ }));
139
+ return this._dequeueNextHook(basePath);
140
+ }
141
+ _dequeueNextHook(basePath) {
142
+ while (this.hookQueue.length > 0) {
143
+ const entry = this.hookQueue.shift();
144
+ const { config, triggerUnitType, triggerUnitId } = entry;
145
+ // Check idempotency — if artifact already exists, skip
146
+ if (config.artifact) {
147
+ const artifactPath = resolveHookArtifactPath(basePath, triggerUnitId, config.artifact);
148
+ if (existsSync(artifactPath))
149
+ continue;
150
+ }
151
+ // Check cycle limit
152
+ const cycleKey = `${config.name}/${triggerUnitType}/${triggerUnitId}`;
153
+ const currentCycle = (this.cycleCounts.get(cycleKey) ?? 0) + 1;
154
+ const maxCycles = config.max_cycles ?? 1;
155
+ if (currentCycle > maxCycles)
156
+ continue;
157
+ this.cycleCounts.set(cycleKey, currentCycle);
158
+ this.activeHook = {
159
+ hookName: config.name,
160
+ triggerUnitType,
161
+ triggerUnitId,
162
+ cycle: currentCycle,
163
+ pendingRetry: false,
164
+ };
165
+ // Build prompt with variable substitution
166
+ const [mid, sid, tid] = triggerUnitId.split("/");
167
+ let prompt = config.prompt
168
+ .replace(/\{milestoneId\}/g, mid ?? "")
169
+ .replace(/\{sliceId\}/g, sid ?? "")
170
+ .replace(/\{taskId\}/g, tid ?? "");
171
+ // Inject browser safety instruction
172
+ prompt += "\n\n**Browser tool safety:** Do NOT use `browser_wait_for` with `condition: \"network_idle\"` — it hangs indefinitely when dev servers keep persistent connections (Vite HMR, WebSocket). Use `selector_visible`, `text_visible`, or `delay` instead.";
173
+ return {
174
+ hookName: config.name,
175
+ prompt,
176
+ model: config.model,
177
+ unitType: `hook/${config.name}`,
178
+ unitId: triggerUnitId,
179
+ };
180
+ }
181
+ // No more hooks — clear active state
182
+ this.activeHook = null;
183
+ return null;
184
+ }
185
+ _handleHookCompletion(basePath) {
186
+ const hook = this.activeHook;
187
+ const hooks = resolvePostUnitHooks();
188
+ const config = hooks.find(h => h.name === hook.hookName);
189
+ // Check if retry was requested via retry_on artifact
190
+ if (config?.retry_on) {
191
+ const retryArtifactPath = resolveHookArtifactPath(basePath, hook.triggerUnitId, config.retry_on);
192
+ if (existsSync(retryArtifactPath)) {
193
+ const cycleKey = `${config.name}/${hook.triggerUnitType}/${hook.triggerUnitId}`;
194
+ const currentCycle = this.cycleCounts.get(cycleKey) ?? 1;
195
+ const maxCycles = config.max_cycles ?? 1;
196
+ if (currentCycle < maxCycles) {
197
+ this.activeHook = null;
198
+ this.hookQueue = [];
199
+ this.retryPending = true;
200
+ this.retryTrigger = {
201
+ unitType: hook.triggerUnitType,
202
+ unitId: hook.triggerUnitId,
203
+ retryArtifact: config.retry_on,
204
+ };
205
+ return null;
206
+ }
207
+ }
208
+ }
209
+ // Hook completed normally — try next hook in queue
210
+ this.activeHook = null;
211
+ return this._dequeueNextHook(basePath);
212
+ }
213
+ // ── Pre-dispatch hook evaluation (sync, all-matching with compose) ──
214
+ /**
215
+ * Replicate exact semantics of runPreDispatchHooks from post-unit-hooks.ts:
216
+ * modify/skip/replace compose semantics.
217
+ */
218
+ evaluatePreDispatch(unitType, unitId, prompt, basePath) {
219
+ // Don't intercept hook units
220
+ if (unitType.startsWith("hook/")) {
221
+ return { action: "proceed", prompt, firedHooks: [] };
222
+ }
223
+ const hooks = resolvePreDispatchHooks().filter(h => h.before.includes(unitType));
224
+ if (hooks.length === 0) {
225
+ return { action: "proceed", prompt, firedHooks: [] };
226
+ }
227
+ const [mid, sid, tid] = unitId.split("/");
228
+ const substitute = (text) => text
229
+ .replace(/\{milestoneId\}/g, mid ?? "")
230
+ .replace(/\{sliceId\}/g, sid ?? "")
231
+ .replace(/\{taskId\}/g, tid ?? "");
232
+ const firedHooks = [];
233
+ let currentPrompt = prompt;
234
+ for (const hook of hooks) {
235
+ if (hook.action === "skip") {
236
+ if (hook.skip_if) {
237
+ const conditionPath = resolveHookArtifactPath(basePath, unitId, hook.skip_if);
238
+ if (!existsSync(conditionPath))
239
+ continue;
240
+ }
241
+ firedHooks.push(hook.name);
242
+ return { action: "skip", firedHooks };
243
+ }
244
+ if (hook.action === "replace") {
245
+ firedHooks.push(hook.name);
246
+ return {
247
+ action: "replace",
248
+ prompt: substitute(hook.prompt ?? ""),
249
+ unitType: hook.unit_type,
250
+ model: hook.model,
251
+ firedHooks,
252
+ };
253
+ }
254
+ if (hook.action === "modify") {
255
+ firedHooks.push(hook.name);
256
+ if (hook.prepend) {
257
+ currentPrompt = `${substitute(hook.prepend)}\n\n${currentPrompt}`;
258
+ }
259
+ if (hook.append) {
260
+ currentPrompt = `${currentPrompt}\n\n${substitute(hook.append)}`;
261
+ }
262
+ }
263
+ }
264
+ return {
265
+ action: "proceed",
266
+ prompt: currentPrompt,
267
+ model: hooks.find(h => h.action === "modify" && h.model)?.model,
268
+ firedHooks,
269
+ };
270
+ }
271
+ // ── State accessors ─────────────────────────────────────────────────
272
+ getActiveHook() {
273
+ return this.activeHook;
274
+ }
275
+ isRetryPending() {
276
+ return this.retryPending;
277
+ }
278
+ /**
279
+ * Returns the trigger unit info for a pending retry, or null.
280
+ * Clears the retry state after reading.
281
+ */
282
+ consumeRetryTrigger() {
283
+ if (!this.retryPending || !this.retryTrigger)
284
+ return null;
285
+ const trigger = { ...this.retryTrigger };
286
+ this.retryPending = false;
287
+ this.retryTrigger = null;
288
+ return trigger;
289
+ }
290
+ /** Clear all mutable state (activeHook, hookQueue, cycleCounts, retryPending, retryTrigger). */
291
+ resetState() {
292
+ this.activeHook = null;
293
+ this.hookQueue = [];
294
+ this.cycleCounts.clear();
295
+ this.retryPending = false;
296
+ this.retryTrigger = null;
297
+ }
298
+ // ── Persistence ─────────────────────────────────────────────────────
299
+ _hookStatePath(basePath) {
300
+ return join(basePath, ".gsd", HOOK_STATE_FILE);
301
+ }
302
+ /** Persist current hook cycle counts to disk. */
303
+ persistState(basePath) {
304
+ const state = {
305
+ cycleCounts: Object.fromEntries(this.cycleCounts),
306
+ savedAt: new Date().toISOString(),
307
+ };
308
+ try {
309
+ const dir = join(basePath, ".gsd");
310
+ if (!existsSync(dir))
311
+ mkdirSync(dir, { recursive: true });
312
+ writeFileSync(this._hookStatePath(basePath), JSON.stringify(state, null, 2), "utf-8");
313
+ }
314
+ catch {
315
+ // Non-fatal — state is recreatable from artifacts
316
+ }
317
+ }
318
+ /** Restore hook cycle counts from disk after a crash/restart. */
319
+ restoreState(basePath) {
320
+ try {
321
+ const filePath = this._hookStatePath(basePath);
322
+ if (!existsSync(filePath))
323
+ return;
324
+ const raw = readFileSync(filePath, "utf-8");
325
+ const state = JSON.parse(raw);
326
+ if (state.cycleCounts && typeof state.cycleCounts === "object") {
327
+ this.cycleCounts.clear();
328
+ for (const [key, value] of Object.entries(state.cycleCounts)) {
329
+ if (typeof value === "number") {
330
+ this.cycleCounts.set(key, value);
331
+ }
332
+ }
333
+ }
334
+ }
335
+ catch {
336
+ // Non-fatal — fresh state is fine
337
+ }
338
+ }
339
+ /** Clear persisted hook state file from disk. */
340
+ clearPersistedState(basePath) {
341
+ try {
342
+ const filePath = this._hookStatePath(basePath);
343
+ if (existsSync(filePath)) {
344
+ writeFileSync(filePath, JSON.stringify({ cycleCounts: {}, savedAt: new Date().toISOString() }, null, 2), "utf-8");
345
+ }
346
+ }
347
+ catch {
348
+ // Non-fatal
349
+ }
350
+ }
351
+ // ── Hook status reporting ───────────────────────────────────────────
352
+ /** Get status of all configured hooks for display. */
353
+ getHookStatus() {
354
+ const entries = [];
355
+ const postHooks = resolvePostUnitHooks();
356
+ for (const hook of postHooks) {
357
+ const activeCycles = {};
358
+ for (const [key, count] of this.cycleCounts) {
359
+ if (key.startsWith(`${hook.name}/`)) {
360
+ activeCycles[key] = count;
361
+ }
362
+ }
363
+ entries.push({
364
+ name: hook.name,
365
+ type: "post",
366
+ enabled: hook.enabled !== false,
367
+ targets: hook.after,
368
+ activeCycles,
369
+ });
370
+ }
371
+ const preHooks = resolvePreDispatchHooks();
372
+ for (const hook of preHooks) {
373
+ entries.push({
374
+ name: hook.name,
375
+ type: "pre",
376
+ enabled: hook.enabled !== false,
377
+ targets: hook.before,
378
+ activeCycles: {},
379
+ });
380
+ }
381
+ return entries;
382
+ }
383
+ /**
384
+ * Manually trigger a specific hook for a unit.
385
+ * Bypasses normal flow — forces hook to run even if artifact exists.
386
+ */
387
+ triggerHookManually(hookName, unitType, unitId, basePath) {
388
+ const hook = resolvePostUnitHooks().find(h => h.name === hookName);
389
+ if (!hook) {
390
+ console.error(`[triggerHookManually] Hook "${hookName}" not found in post_unit_hooks`);
391
+ return null;
392
+ }
393
+ if (!hook.prompt || typeof hook.prompt !== "string" || hook.prompt.trim().length === 0) {
394
+ console.error(`[triggerHookManually] Hook "${hookName}" has empty prompt`);
395
+ return null;
396
+ }
397
+ this.activeHook = {
398
+ hookName: hook.name,
399
+ triggerUnitType: unitType,
400
+ triggerUnitId: unitId,
401
+ cycle: 1,
402
+ pendingRetry: false,
403
+ };
404
+ this.hookQueue = [{
405
+ config: hook,
406
+ triggerUnitType: unitType,
407
+ triggerUnitId: unitId,
408
+ }];
409
+ const cycleKey = `${hook.name}/${unitType}/${unitId}`;
410
+ const currentCycle = (this.cycleCounts.get(cycleKey) ?? 0) + 1;
411
+ this.cycleCounts.set(cycleKey, currentCycle);
412
+ this.activeHook.cycle = currentCycle;
413
+ const [mid, sid, tid] = unitId.split("/");
414
+ const prompt = hook.prompt
415
+ .replace(/\{milestoneId\}/g, mid ?? "")
416
+ .replace(/\{sliceId\}/g, sid ?? "")
417
+ .replace(/\{taskId\}/g, tid ?? "");
418
+ return {
419
+ hookName: hook.name,
420
+ prompt,
421
+ model: hook.model,
422
+ unitType: `hook/${hook.name}`,
423
+ unitId,
424
+ };
425
+ }
426
+ /** Format hook status for terminal display. */
427
+ formatHookStatus() {
428
+ const entries = this.getHookStatus();
429
+ if (entries.length === 0) {
430
+ return "No hooks configured. Add post_unit_hooks or pre_dispatch_hooks to .gsd/preferences.md";
431
+ }
432
+ const lines = ["Configured Hooks:", ""];
433
+ const postHooks = entries.filter(e => e.type === "post");
434
+ const preHooks = entries.filter(e => e.type === "pre");
435
+ if (postHooks.length > 0) {
436
+ lines.push("Post-Unit Hooks (run after unit completes):");
437
+ for (const hook of postHooks) {
438
+ const status = hook.enabled ? "enabled" : "disabled";
439
+ const cycles = Object.keys(hook.activeCycles).length;
440
+ const cycleInfo = cycles > 0 ? ` (${cycles} active cycle${cycles === 1 ? "" : "s"})` : "";
441
+ lines.push(` ${hook.name} [${status}] → after: ${hook.targets.join(", ")}${cycleInfo}`);
442
+ }
443
+ lines.push("");
444
+ }
445
+ if (preHooks.length > 0) {
446
+ lines.push("Pre-Dispatch Hooks (run before unit dispatches):");
447
+ for (const hook of preHooks) {
448
+ const status = hook.enabled ? "enabled" : "disabled";
449
+ lines.push(` ${hook.name} [${status}] → before: ${hook.targets.join(", ")}`);
450
+ }
451
+ lines.push("");
452
+ }
453
+ return lines.join("\n");
454
+ }
455
+ }
456
+ // ─── Module-level Singleton ─────────────────────────────────────────────────
457
+ let _registry = null;
458
+ /** Get the singleton registry. Throws if not initialized. */
459
+ export function getRegistry() {
460
+ if (!_registry) {
461
+ throw new Error("RuleRegistry not initialized — call initRegistry() or setRegistry() first.");
462
+ }
463
+ return _registry;
464
+ }
465
+ /** Set the singleton registry instance. */
466
+ export function setRegistry(r) {
467
+ _registry = r;
468
+ }
469
+ /** Create and set the singleton registry with the given dispatch rules. */
470
+ export function initRegistry(dispatchRules) {
471
+ const registry = new RuleRegistry(dispatchRules);
472
+ setRegistry(registry);
473
+ return registry;
474
+ }
475
+ /**
476
+ * Get the singleton registry, lazily creating one with empty dispatch rules
477
+ * if not yet initialized. This ensures facade functions work even when
478
+ * the full registry hasn't been set up (e.g. during testing).
479
+ */
480
+ export function getOrCreateRegistry() {
481
+ if (!_registry) {
482
+ _registry = new RuleRegistry([]);
483
+ }
484
+ return _registry;
485
+ }
486
+ /** Reset the singleton (for testing). */
487
+ export function resetRegistry() {
488
+ _registry = null;
489
+ }
@@ -0,0 +1,6 @@
1
+ // GSD Extension — Unified Rule Type Definitions
2
+ //
3
+ // Every dispatch rule and hook is expressed as a `UnifiedRule` with a
4
+ // consistent when/where/then shape. This file defines the type system;
5
+ // the `RuleRegistry` class in rule-registry.ts holds instances at runtime.
6
+ export {};