@gong-ym/ai-spec-auto 0.2.3

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 (640) hide show
  1. package/.agents/commands/README.md +33 -0
  2. package/.agents/commands/claude/spec-start-review.md +88 -0
  3. package/.agents/commands/codex/spec-continue.md +74 -0
  4. package/.agents/commands/codex/spec-orchestrate.md +35 -0
  5. package/.agents/commands/codex/spec-start-review.md +88 -0
  6. package/.agents/commands/codex/spec-start.md +67 -0
  7. package/.agents/commands/codex/spec-status.md +22 -0
  8. package/.agents/commands/codex/spec-stop.md +29 -0
  9. package/.agents/commands/codex/spec-update.md +40 -0
  10. package/.agents/commands/common/branch-review.md +117 -0
  11. package/.agents/commands/common/project-init.md +25 -0
  12. package/.agents/commands/common/spec-continue.md +74 -0
  13. package/.agents/commands/common/spec-orchestrate.md +35 -0
  14. package/.agents/commands/common/spec-start-review.md +82 -0
  15. package/.agents/commands/common/spec-start.md +67 -0
  16. package/.agents/commands/common/spec-status.md +22 -0
  17. package/.agents/commands/common/spec-stop.md +29 -0
  18. package/.agents/commands/common/spec-update.md +40 -0
  19. package/.agents/commands/cursor/opsx-apply.md +55 -0
  20. package/.agents/commands/cursor/opsx-archive.md +48 -0
  21. package/.agents/commands/cursor/opsx-explore.md +45 -0
  22. package/.agents/commands/cursor/opsx-propose.md +59 -0
  23. package/.agents/commands/cursor/spec-continue.md +63 -0
  24. package/.agents/commands/cursor/spec-orchestrate.md +53 -0
  25. package/.agents/commands/cursor/spec-start-review.md +78 -0
  26. package/.agents/commands/cursor/spec-start.md +59 -0
  27. package/.agents/commands/cursor/spec-status.md +30 -0
  28. package/.agents/commands/cursor/spec-stop.md +29 -0
  29. package/.agents/commands/cursor/spec-update.md +41 -0
  30. package/.agents/flows/FRONTMATTER.md +263 -0
  31. package/.agents/flows/RUN_OUTPUT.md +263 -0
  32. package/.agents/flows/common/README.md +29 -0
  33. package/.agents/flows/common/bugfix-to-verification.md +95 -0
  34. package/.agents/flows/common/change-to-architecture-review.md +89 -0
  35. package/.agents/flows/common/change-to-release.md +94 -0
  36. package/.agents/flows/common/prd-to-delivery.md +184 -0
  37. package/.agents/flows/common/requirement-to-observability.md +97 -0
  38. package/.agents/orchestration/README.md +22 -0
  39. package/.agents/orchestration/expert-dispatch-spec.md +155 -0
  40. package/.agents/orchestration/expert-executor-spec.md +84 -0
  41. package/.agents/orchestration/expert-runtime-action-spec.md +73 -0
  42. package/.agents/orchestration/runtime-state-handoff-spec.md +264 -0
  43. package/.agents/orchestration/task-anchor-spec.md +212 -0
  44. package/.agents/orchestration/task-orchestrator-adapter-payload.md +153 -0
  45. package/.agents/orchestration/task-orchestrator-bootstrap-payload.md +145 -0
  46. package/.agents/orchestration/task-orchestrator-output-extractor-spec.md +93 -0
  47. package/.agents/orchestration/task-orchestrator-run-plan-template.md +312 -0
  48. package/.agents/orchestration/task-orchestrator-runtime-hooks.md +214 -0
  49. package/.agents/registry/README.md +63 -0
  50. package/.agents/registry/flows.json +125 -0
  51. package/.agents/registry/profiles.json +101 -0
  52. package/.agents/registry/roles.json +1266 -0
  53. package/.agents/registry/rules.json +148 -0
  54. package/.agents/registry/scenario-packages.json +123 -0
  55. package/.agents/registry/skills.json +130 -0
  56. package/.agents/roles/INDEX.md +346 -0
  57. package/.agents/roles/common/README.md +76 -0
  58. package/.agents/roles/common/archive-change.md +80 -0
  59. package/.agents/roles/common/backend-implementer.md +92 -0
  60. package/.agents/roles/common/code-guardian.md +151 -0
  61. package/.agents/roles/common/frontend-implementer.md +146 -0
  62. package/.agents/roles/common/requirement-analyst.md +138 -0
  63. package/.agents/roles/common/task-orchestrator-routing.md +301 -0
  64. package/.agents/roles/common/task-orchestrator.md +224 -0
  65. package/.agents/roles/common/tooling-implementer.md +92 -0
  66. package/.agents/roles/domains/README.md +35 -0
  67. package/.agents/roles/domains/delivery/README.md +11 -0
  68. package/.agents/roles/domains/delivery/container-specialist.md +50 -0
  69. package/.agents/roles/domains/delivery/deployment-specialist.md +50 -0
  70. package/.agents/roles/domains/delivery/pipeline-specialist.md +50 -0
  71. package/.agents/roles/domains/demand-design/README.md +16 -0
  72. package/.agents/roles/domains/demand-design/api-contract-specialist.md +52 -0
  73. package/.agents/roles/domains/demand-design/design-collaborator.md +58 -0
  74. package/.agents/roles/domains/documentation/README.md +11 -0
  75. package/.agents/roles/domains/documentation/api-doc-specialist.md +50 -0
  76. package/.agents/roles/domains/documentation/component-doc-specialist.md +49 -0
  77. package/.agents/roles/domains/documentation/technical-writing-specialist.md +48 -0
  78. package/.agents/roles/domains/engineering/README.md +17 -0
  79. package/.agents/roles/domains/engineering/architecture-advisor.md +53 -0
  80. package/.agents/roles/domains/engineering/build-specialist.md +51 -0
  81. package/.agents/roles/domains/engineering/dependency-governor.md +52 -0
  82. package/.agents/roles/domains/governance/README.md +17 -0
  83. package/.agents/roles/domains/governance/api-governance-specialist.md +51 -0
  84. package/.agents/roles/domains/governance/lint-policy-specialist.md +49 -0
  85. package/.agents/roles/domains/governance/route-governance-specialist.md +52 -0
  86. package/.agents/roles/domains/observability/README.md +11 -0
  87. package/.agents/roles/domains/observability/error-tracker.md +50 -0
  88. package/.agents/roles/domains/observability/event-instrumentation-specialist.md +51 -0
  89. package/.agents/roles/domains/observability/rum-analyst.md +50 -0
  90. package/.agents/roles/domains/performance/README.md +11 -0
  91. package/.agents/roles/domains/performance/asset-optimizer.md +50 -0
  92. package/.agents/roles/domains/performance/performance-auditor.md +56 -0
  93. package/.agents/roles/domains/performance/vitals-analyst.md +50 -0
  94. package/.agents/roles/domains/security-a11y/README.md +11 -0
  95. package/.agents/roles/domains/security-a11y/a11y-auditor.md +50 -0
  96. package/.agents/roles/domains/security-a11y/aria-specialist.md +51 -0
  97. package/.agents/roles/domains/security-a11y/security-reviewer.md +49 -0
  98. package/.agents/roles/domains/testing/README.md +12 -0
  99. package/.agents/roles/domains/testing/coverage-analyst.md +50 -0
  100. package/.agents/roles/domains/testing/e2e-test-specialist.md +51 -0
  101. package/.agents/roles/domains/testing/unit-test-specialist.md +56 -0
  102. package/.agents/roles/domains/testing/verification-reviewer.md +67 -0
  103. package/.agents/rules/README.md +87 -0
  104. package/.agents/rules/common/02-/347/274/226/347/240/201/350/247/204/350/214/203.md +45 -0
  105. package/.agents/rules/common/08-/351/200/232/347/224/250/347/272/246/346/235/237.md +63 -0
  106. package/.agents/rules/common/10-/346/226/207/346/241/243/350/247/204/350/214/203.md +101 -0
  107. package/.agents/rules/common/12-Superpowers/346/211/247/350/241/214/350/247/204/350/214/203.md +46 -0
  108. package/.agents/rules/common/14-/345/256/241/350/256/241/346/261/207/346/212/245/350/247/204/350/214/203.md +107 -0
  109. package/.agents/rules/common/15-visual-gate-wait.md +90 -0
  110. package/.agents/rules/profiles/nestjs/01-/351/241/271/347/233/256/346/246/202/350/277/260.md +27 -0
  111. package/.agents/rules/profiles/nestjs/03-/351/241/271/347/233/256/347/273/223/346/236/204.md +20 -0
  112. package/.agents/rules/profiles/nestjs/04-/346/250/241/345/235/227/347/273/223/346/236/204/350/247/204/350/214/203.md +24 -0
  113. package/.agents/rules/profiles/nestjs/05-/346/216/245/345/217/243/344/270/216/345/245/221/347/272/246/350/247/204/350/214/203.md +24 -0
  114. package/.agents/rules/profiles/nestjs/06-/346/225/260/346/215/256/350/256/277/351/227/256/350/247/204/350/214/203.md +24 -0
  115. package/.agents/rules/profiles/nestjs/07-/351/205/215/347/275/256/344/270/216/350/277/220/350/241/214/346/227/266/350/247/204/350/214/203.md +20 -0
  116. package/.agents/rules/profiles/nestjs/09-/345/274/202/345/270/270/344/270/216/346/227/245/345/277/227/350/247/204/350/214/203.md +20 -0
  117. package/.agents/rules/profiles/nestjs/11-/346/265/213/350/257/225/350/247/204/350/214/203.md +24 -0
  118. package/.agents/rules/profiles/nestjs/13-/344/273/243/347/240/201/346/240/274/345/274/217/345/214/226/344/270/216/346/243/200/346/237/245.md +20 -0
  119. package/.agents/rules/profiles/node-tooling/01-/351/241/271/347/233/256/346/246/202/350/277/260.md +30 -0
  120. package/.agents/rules/profiles/node-tooling/03-/351/241/271/347/233/256/347/273/223/346/236/204.md +37 -0
  121. package/.agents/rules/profiles/node-tooling/04-CLI/344/270/216/346/250/241/345/235/227/350/247/204/350/214/203.md +42 -0
  122. package/.agents/rules/profiles/node-tooling/05-Contract/344/270/216Schema/350/247/204/350/214/203.md +42 -0
  123. package/.agents/rules/profiles/node-tooling/06-/350/277/220/350/241/214/346/227/266/346/226/207/344/273/266/350/247/204/350/214/203.md +30 -0
  124. package/.agents/rules/profiles/node-tooling/07-/346/227/245/345/277/227/344/270/216/351/224/231/350/257/257/345/244/204/347/220/206/350/247/204/350/214/203.md +60 -0
  125. package/.agents/rules/profiles/node-tooling/09-/350/204/232/346/234/254/344/270/216/345/205/245/345/217/243/350/247/204/350/214/203.md +45 -0
  126. package/.agents/rules/profiles/node-tooling/11-/346/265/213/350/257/225/350/247/204/350/214/203.md +41 -0
  127. package/.agents/rules/profiles/node-tooling/13-/344/273/243/347/240/201/346/240/274/345/274/217/345/214/226/344/270/216/346/243/200/346/237/245.md +55 -0
  128. package/.agents/rules/profiles/react/01-/351/241/271/347/233/256/346/246/202/350/277/260.md +29 -0
  129. package/.agents/rules/profiles/react/03-/351/241/271/347/233/256/347/273/223/346/236/204.md +104 -0
  130. package/.agents/rules/profiles/react/04-/347/273/204/344/273/266/350/247/204/350/214/203.md +46 -0
  131. package/.agents/rules/profiles/react/05-API/350/247/204/350/214/203.md +67 -0
  132. package/.agents/rules/profiles/react/06-/350/267/257/347/224/261/350/247/204/350/214/203.md +54 -0
  133. package/.agents/rules/profiles/react/07-/347/212/266/346/200/201/347/256/241/347/220/206.md +226 -0
  134. package/.agents/rules/profiles/react/09-/346/240/267/345/274/217/350/247/204/350/214/203.md +71 -0
  135. package/.agents/rules/profiles/react/11-/346/265/213/350/257/225/350/247/204/350/214/203.md +80 -0
  136. package/.agents/rules/profiles/react/13-/344/273/243/347/240/201/346/240/274/345/274/217/345/214/226/344/270/216/346/243/200/346/237/245.md +159 -0
  137. package/.agents/rules/profiles/springboot/01-/351/241/271/347/233/256/346/246/202/350/277/260.md +31 -0
  138. package/.agents/rules/profiles/springboot/03-/351/241/271/347/233/256/347/273/223/346/236/204.md +37 -0
  139. package/.agents/rules/profiles/springboot/04-/345/210/206/345/261/202/350/247/204/350/214/203.md +33 -0
  140. package/.agents/rules/profiles/springboot/05-/346/216/245/345/217/243/344/270/216/345/245/221/347/272/246/350/247/204/350/214/203.md +51 -0
  141. package/.agents/rules/profiles/springboot/06-/346/225/260/346/215/256/350/256/277/351/227/256/350/247/204/350/214/203.md +34 -0
  142. package/.agents/rules/profiles/springboot/07-/351/205/215/347/275/256/344/270/216/350/277/220/350/241/214/346/227/266/350/247/204/350/214/203.md +38 -0
  143. package/.agents/rules/profiles/springboot/09-/345/274/202/345/270/270/344/270/216/346/227/245/345/277/227/350/247/204/350/214/203.md +48 -0
  144. package/.agents/rules/profiles/springboot/11-/346/265/213/350/257/225/350/247/204/350/214/203.md +43 -0
  145. package/.agents/rules/profiles/springboot/13-/344/273/243/347/240/201/346/240/274/345/274/217/345/214/226/344/270/216/346/243/200/346/237/245.md +48 -0
  146. package/.agents/rules/profiles/vue/01-/351/241/271/347/233/256/346/246/202/350/277/260.md +47 -0
  147. package/.agents/rules/profiles/vue/03-/351/241/271/347/233/256/347/273/223/346/236/204.md +106 -0
  148. package/.agents/rules/profiles/vue/04-/347/273/204/344/273/266/350/247/204/350/214/203.md +61 -0
  149. package/.agents/rules/profiles/vue/05-API/350/247/204/350/214/203.md +67 -0
  150. package/.agents/rules/profiles/vue/06-/350/267/257/347/224/261/350/247/204/350/214/203.md +69 -0
  151. package/.agents/rules/profiles/vue/07-/347/212/266/346/200/201/347/256/241/347/220/206.md +93 -0
  152. package/.agents/rules/profiles/vue/09-/346/240/267/345/274/217/350/247/204/350/214/203.md +67 -0
  153. package/.agents/rules/profiles/vue/11-/346/265/213/350/257/225/350/247/204/350/214/203.md +80 -0
  154. package/.agents/rules/profiles/vue/13-/344/273/243/347/240/201/346/240/274/345/274/217/345/214/226/344/270/216/346/243/200/346/237/245.md +159 -0
  155. package/.agents/skills/README.md +171 -0
  156. package/.agents/skills/common/archive-change/SKILL.md +180 -0
  157. package/.agents/skills/common/branch-code-reviewer/SKILL.md +459 -0
  158. package/.agents/skills/common/branch-code-reviewer/references/business-risk-guide.md +293 -0
  159. package/.agents/skills/common/branch-code-reviewer/references/html-template-guide.md +121 -0
  160. package/.agents/skills/common/config-and-secret-scan/SKILL.md +99 -0
  161. package/.agents/skills/common/create-proposal/SKILL.md +192 -0
  162. package/.agents/skills/common/create-proposal/evals/evals.json +16 -0
  163. package/.agents/skills/common/create-proposal/evals/train_queries.json +18 -0
  164. package/.agents/skills/common/create-proposal/evals/validation_queries.json +18 -0
  165. package/.agents/skills/common/create-proposal/references/interaction-spec-template.md +42 -0
  166. package/.agents/skills/common/create-test/SKILL.md +292 -0
  167. package/.agents/skills/common/dependency-impact-graph/SKILL.md +80 -0
  168. package/.agents/skills/common/execute-task/SKILL.md +206 -0
  169. package/.agents/skills/common/execute-task/evals/evals.json +16 -0
  170. package/.agents/skills/common/execute-task/evals/train_queries.json +18 -0
  171. package/.agents/skills/common/execute-task/evals/validation_queries.json +18 -0
  172. package/.agents/skills/common/find-skills/SKILL.md +144 -0
  173. package/.agents/skills/common/install-ai-spec-auto/SKILL.md +260 -0
  174. package/.agents/skills/common/install-ai-spec-auto/evals/evals.json +17 -0
  175. package/.agents/skills/common/install-ai-spec-auto/evals/train_queries.json +18 -0
  176. package/.agents/skills/common/install-ai-spec-auto/evals/validation_queries.json +18 -0
  177. package/.agents/skills/common/project-init/SKILL.md +178 -0
  178. package/.agents/skills/common/project-init/evals/evals.json +16 -0
  179. package/.agents/skills/common/project-init/evals/train_queries.json +18 -0
  180. package/.agents/skills/common/project-init/evals/validation_queries.json +18 -0
  181. package/.agents/skills/common/project-init/references/custom-rule-generation.md +89 -0
  182. package/.agents/skills/common/project-init/references/deep-scan-rules.md +67 -0
  183. package/.agents/skills/common/project-init/references/output-contracts.md +71 -0
  184. package/.agents/skills/common/project-init/references/repo-fact-gathering.md +83 -0
  185. package/.agents/skills/common/project-init/references/scope-resolution.md +76 -0
  186. package/.agents/skills/common/project-init/scripts/inspect-project.js +112 -0
  187. package/.agents/skills/common/skill-creator/LICENSE.txt +202 -0
  188. package/.agents/skills/common/skill-creator/SKILL.md +370 -0
  189. package/.agents/skills/common/skill-creator/evals/evals.json +16 -0
  190. package/.agents/skills/common/skill-creator/evals/train_queries.json +18 -0
  191. package/.agents/skills/common/skill-creator/evals/validation_queries.json +18 -0
  192. package/.agents/skills/common/skill-creator/references/output-patterns.md +82 -0
  193. package/.agents/skills/common/skill-creator/references/workflows.md +28 -0
  194. package/.agents/skills/common/skill-creator/scripts/init_skill.py +209 -0
  195. package/.agents/skills/common/skill-creator/scripts/package_skill.py +110 -0
  196. package/.agents/skills/common/skill-creator/scripts/quick_validate.py +51 -0
  197. package/.agents/skills/common/skill-optimizer/SKILL.md +102 -0
  198. package/.agents/skills/common/skill-optimizer/evals/evals.json +16 -0
  199. package/.agents/skills/common/skill-optimizer/evals/train_queries.json +18 -0
  200. package/.agents/skills/common/skill-optimizer/evals/validation_queries.json +18 -0
  201. package/.agents/skills/common/skill-optimizer/references/design-patterns.md +26 -0
  202. package/.agents/skills/common/skill-optimizer/references/review-checklist.md +22 -0
  203. package/.agents/skills/common/using-superpowers/SKILL.md +151 -0
  204. package/.agents/skills/common/wait-for-gate-signal/SKILL.md +85 -0
  205. package/.agents/skills/domains/README.md +19 -0
  206. package/.agents/skills/domains/ui-ux-pro-max/SKILL.md +58 -0
  207. package/.agents/skills/domains/web/design-analysis/SKILL.md +89 -0
  208. package/.agents/skills/domains/web/design-analysis/rules/analysis-order.md +61 -0
  209. package/.agents/skills/domains/web/design-analysis/rules/analysis-priorities.md +136 -0
  210. package/.agents/skills/domains/web/design-analysis/rules/checklist-common-misses.md +107 -0
  211. package/.agents/skills/domains/web/design-analysis/rules/implementation-common-errors.md +204 -0
  212. package/.agents/skills/domains/web/design-analysis/rules/implementation-guidelines.md +211 -0
  213. package/.agents/skills/domains/web/design-analysis/rules/output-analysis-checklist.md +247 -0
  214. package/.agents/skills/domains/web/design-analysis/rules/tools-design-guidelines.md +108 -0
  215. package/.agents/skills/domains/web/design-analysis/rules/workflow-element-extraction.md +162 -0
  216. package/.agents/skills/domains/web/design-analysis/rules/workflow-layout-map.md +131 -0
  217. package/.agents/skills/domains/web/design-analysis/rules/workflow-output-checklist.md +70 -0
  218. package/.agents/skills/domains/web/design-analysis/rules/workflow-style-summary.md +91 -0
  219. package/.agents/skills/domains/web/route-permission-map/SKILL.md +103 -0
  220. package/.agents/skills/domains/web/ui-verification/SKILL.md +114 -0
  221. package/.agents/skills/domains/web/ui-verification/evals/evals.json +16 -0
  222. package/.agents/skills/domains/web/ui-verification/evals/train_queries.json +18 -0
  223. package/.agents/skills/domains/web/ui-verification/evals/validation_queries.json +18 -0
  224. package/.agents/skills/domains/web/ui-verification/rules/comparison-content-image.md +34 -0
  225. package/.agents/skills/domains/web/ui-verification/rules/comparison-content-text.md +30 -0
  226. package/.agents/skills/domains/web/ui-verification/rules/comparison-hierarchy.md +33 -0
  227. package/.agents/skills/domains/web/ui-verification/rules/comparison-layout.md +35 -0
  228. package/.agents/skills/domains/web/ui-verification/rules/errors-alignment.md +42 -0
  229. package/.agents/skills/domains/web/ui-verification/rules/errors-button-dimensions.md +28 -0
  230. package/.agents/skills/domains/web/ui-verification/rules/errors-button-position.md +25 -0
  231. package/.agents/skills/domains/web/ui-verification/rules/errors-css-priority.md +50 -0
  232. package/.agents/skills/domains/web/ui-verification/rules/errors-flex-column-width.md +46 -0
  233. package/.agents/skills/domains/web/ui-verification/rules/errors-flex-layout.md +46 -0
  234. package/.agents/skills/domains/web/ui-verification/rules/errors-grid-container-width.md +44 -0
  235. package/.agents/skills/domains/web/ui-verification/rules/errors-page-container-width.md +39 -0
  236. package/.agents/skills/domains/web/ui-verification/rules/tools-browser-navigation.md +53 -0
  237. package/.agents/skills/domains/web/ui-verification/rules/tools-design-guidelines.md +53 -0
  238. package/.agents/skills/domains/web/ui-verification/rules/workflow-checklist.md +27 -0
  239. package/.agents/skills/domains/web/ui-verification/rules/workflow-problem-list.md +56 -0
  240. package/.agents/skills/domains/web/ui-verification/rules/workflow-reflection.md +44 -0
  241. package/.agents/skills/domains/web/ui-verification/rules/writing-alignment.md +44 -0
  242. package/.agents/skills/domains/web/ui-verification/rules/writing-element-completeness.md +63 -0
  243. package/.agents/skills/domains/web/ui-verification/rules/writing-list-layout.md +75 -0
  244. package/.agents/skills/domains/web/ui-verification/rules/writing-page-container-width.md +37 -0
  245. package/.agents/skills/domains/web/web-design-guidelines/SKILL.md +40 -0
  246. package/.agents/skills/profiles/nestjs/README.md +4 -0
  247. package/.agents/skills/profiles/node-tooling/README.md +9 -0
  248. package/.agents/skills/profiles/react/create-api/SKILL.md +145 -0
  249. package/.agents/skills/profiles/react/create-component/SKILL.md +160 -0
  250. package/.agents/skills/profiles/react/create-route/SKILL.md +168 -0
  251. package/.agents/skills/profiles/react/create-store/SKILL.md +262 -0
  252. package/.agents/skills/profiles/react/theme-variables/SKILL.md +82 -0
  253. package/.agents/skills/profiles/react/vercel-composition-patterns/AGENTS.md +899 -0
  254. package/.agents/skills/profiles/react/vercel-composition-patterns/SKILL.md +81 -0
  255. package/.agents/skills/profiles/react/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
  256. package/.agents/skills/profiles/react/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
  257. package/.agents/skills/profiles/react/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
  258. package/.agents/skills/profiles/react/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
  259. package/.agents/skills/profiles/react/vercel-composition-patterns/rules/state-context-interface.md +191 -0
  260. package/.agents/skills/profiles/react/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
  261. package/.agents/skills/profiles/react/vercel-composition-patterns/rules/state-lift-state.md +125 -0
  262. package/.agents/skills/profiles/react/vercel-react-best-practices/AGENTS.md +2934 -0
  263. package/.agents/skills/profiles/react/vercel-react-best-practices/SKILL.md +136 -0
  264. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  265. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
  266. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
  267. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  268. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/async-defer-await.md +80 -0
  269. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/async-dependencies.md +51 -0
  270. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/async-parallel.md +28 -0
  271. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  272. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
  273. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  274. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  275. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  276. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  277. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  278. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
  279. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
  280. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  281. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
  282. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  283. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  284. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  285. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  286. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  287. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  288. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  289. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  290. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  291. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  292. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  293. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  294. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  295. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  296. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  297. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  298. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  299. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
  300. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  301. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  302. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  303. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  304. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  305. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  306. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  307. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  308. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
  309. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  310. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  311. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  312. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  313. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  314. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  315. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
  316. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  317. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/server-cache-react.md +76 -0
  318. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
  319. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
  320. package/.agents/skills/profiles/react/vercel-react-best-practices/rules/server-serialization.md +38 -0
  321. package/.agents/skills/profiles/springboot/README.md +10 -0
  322. package/.agents/skills/profiles/vue/create-api/SKILL.md +105 -0
  323. package/.agents/skills/profiles/vue/create-component/SKILL.md +76 -0
  324. package/.agents/skills/profiles/vue/create-route/SKILL.md +141 -0
  325. package/.agents/skills/profiles/vue/create-store/SKILL.md +97 -0
  326. package/.agents/skills/profiles/vue/create-view/SKILL.md +81 -0
  327. package/.agents/skills/profiles/vue/theme-variables/SKILL.md +73 -0
  328. package/.agents/skills/profiles/vue/vue-best-practices/SKILL.md +166 -0
  329. package/.agents/skills/profiles/vue/vue-best-practices/references/animation-class-based-technique.md +254 -0
  330. package/.agents/skills/profiles/vue/vue-best-practices/references/animation-state-driven-technique.md +291 -0
  331. package/.agents/skills/profiles/vue/vue-best-practices/references/component-async.md +97 -0
  332. package/.agents/skills/profiles/vue/vue-best-practices/references/component-data-flow.md +307 -0
  333. package/.agents/skills/profiles/vue/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
  334. package/.agents/skills/profiles/vue/vue-best-practices/references/component-keep-alive.md +137 -0
  335. package/.agents/skills/profiles/vue/vue-best-practices/references/component-slots.md +216 -0
  336. package/.agents/skills/profiles/vue/vue-best-practices/references/component-suspense.md +228 -0
  337. package/.agents/skills/profiles/vue/vue-best-practices/references/component-teleport.md +108 -0
  338. package/.agents/skills/profiles/vue/vue-best-practices/references/component-transition-group.md +128 -0
  339. package/.agents/skills/profiles/vue/vue-best-practices/references/component-transition.md +125 -0
  340. package/.agents/skills/profiles/vue/vue-best-practices/references/composables.md +290 -0
  341. package/.agents/skills/profiles/vue/vue-best-practices/references/directives.md +162 -0
  342. package/.agents/skills/profiles/vue/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
  343. package/.agents/skills/profiles/vue/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
  344. package/.agents/skills/profiles/vue/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
  345. package/.agents/skills/profiles/vue/vue-best-practices/references/plugins.md +166 -0
  346. package/.agents/skills/profiles/vue/vue-best-practices/references/reactivity.md +344 -0
  347. package/.agents/skills/profiles/vue/vue-best-practices/references/render-functions.md +201 -0
  348. package/.agents/skills/profiles/vue/vue-best-practices/references/sfc.md +310 -0
  349. package/.agents/skills/profiles/vue/vue-best-practices/references/state-management.md +135 -0
  350. package/.agents/skills/profiles/vue/vue-best-practices/references/updated-hook-performance.md +187 -0
  351. package/.agents/templates/common/README.md +23 -0
  352. package/.agents/templates/common/bugfix.md +22 -0
  353. package/.agents/templates/common/create-expert-package.md +458 -0
  354. package/.agents/templates/common/mock-page.md +28 -0
  355. package/.agents/templates/common/new-component.md +25 -0
  356. package/.agents/templates/common/new-page.md +31 -0
  357. package/.cursor/mcp.json +36 -0
  358. package/.qoder/README.md +114 -0
  359. package/.qoder/commands +1 -0
  360. package/.qoder/mcp.json +26 -0
  361. package/.qoder/rules +1 -0
  362. package/.qoder/skills +1 -0
  363. package/LICENSE +21 -0
  364. package/README.md +433 -0
  365. package/bin/archive-change.js +474 -0
  366. package/bin/check-command.js +62 -0
  367. package/bin/cli.js +295 -0
  368. package/bin/command-template-renderer.js +40 -0
  369. package/bin/context-command.js +102 -0
  370. package/bin/demo-runtime-smoke.js +760 -0
  371. package/bin/execution-semantics.js +821 -0
  372. package/bin/executor-command.js +93 -0
  373. package/bin/expert-dispatch.js +334 -0
  374. package/bin/expert-executor.js +1148 -0
  375. package/bin/guard-command.js +52 -0
  376. package/bin/hub-command.js +876 -0
  377. package/bin/ide-command.js +242 -0
  378. package/bin/init-command.js +193 -0
  379. package/bin/install-workflow.js +2983 -0
  380. package/bin/manifest-export.js +34 -0
  381. package/bin/profile-registry.js +90 -0
  382. package/bin/protocol-workflow.js +446 -0
  383. package/bin/repair-command.js +161 -0
  384. package/bin/repo-map.js +177 -0
  385. package/bin/report-command.js +236 -0
  386. package/bin/runtime-bootstrap.js +428 -0
  387. package/bin/runtime-embedded.js +101 -0
  388. package/bin/runtime-fallback.js +106 -0
  389. package/bin/runtime-launcher.js +116 -0
  390. package/bin/runtime-paths.js +177 -0
  391. package/bin/runtime-registry.js +289 -0
  392. package/bin/runtime-state.js +2541 -0
  393. package/bin/scan.js +96 -0
  394. package/bin/self-upgrade.js +206 -0
  395. package/bin/skill-spec-validator.js +457 -0
  396. package/bin/spec-command.js +366 -0
  397. package/bin/superpowers.js +384 -0
  398. package/bin/sync-command.js +59 -0
  399. package/bin/sync.js +1904 -0
  400. package/bin/task-orchestrator-adapter.js +341 -0
  401. package/bin/task-orchestrator-extractor.js +274 -0
  402. package/bin/task-orchestrator-runner.js +1208 -0
  403. package/bin/telemetry/README.md +66 -0
  404. package/bin/telemetry/aspect.js +153 -0
  405. package/bin/telemetry/collect.js +67 -0
  406. package/bin/telemetry/config.js +114 -0
  407. package/bin/telemetry/defaults.json +5 -0
  408. package/bin/telemetry/healthcheck.js +195 -0
  409. package/bin/telemetry/identity.js +53 -0
  410. package/bin/telemetry/index.js +25 -0
  411. package/bin/telemetry/reporter.js +83 -0
  412. package/bin/telemetry/safe.js +39 -0
  413. package/bin/validate-registry.js +740 -0
  414. package/bin/visual-bridge-config.js +117 -0
  415. package/bin/visual-bridge.js +287 -0
  416. package/bin/visual-command.js +432 -0
  417. package/bin/worktree-command.js +194 -0
  418. package/configs/common/.editorconfig +15 -0
  419. package/configs/common/.husky/commit-msg +4 -0
  420. package/configs/common/.husky/pre-commit +4 -0
  421. package/configs/common/.lintstagedrc +11 -0
  422. package/configs/common/.prettierignore +11 -0
  423. package/configs/common/.prettierrc.json +11 -0
  424. package/configs/common/.stylelintignore +14 -0
  425. package/configs/common/.stylelintrc.json +21 -0
  426. package/configs/common/commitlint.config.js +3 -0
  427. package/configs/profiles/nestjs/.gitkeep +1 -0
  428. package/configs/profiles/node-tooling/.gitkeep +1 -0
  429. package/configs/profiles/react/.eslintignore +6 -0
  430. package/configs/profiles/react/.eslintrc.js +16 -0
  431. package/configs/profiles/react/.stylelintrc.json +18 -0
  432. package/configs/profiles/springboot/.gitkeep +1 -0
  433. package/configs/profiles/vue/.eslintignore +7 -0
  434. package/configs/profiles/vue/.eslintrc.cjs +17 -0
  435. package/contracts/README.md +28 -0
  436. package/contracts/fixtures/asset-package.fixture.json +26 -0
  437. package/contracts/fixtures/asset-usage-feedback.fixture.json +14 -0
  438. package/contracts/fixtures/evidence-report.fixture.json +28 -0
  439. package/contracts/fixtures/manifest.fixture.json +20 -0
  440. package/contracts/fixtures/run-event.fixture.json +15 -0
  441. package/contracts/schemas/asset-package.schema.json +76 -0
  442. package/contracts/schemas/asset-usage-feedback.schema.json +57 -0
  443. package/contracts/schemas/evidence-report.schema.json +60 -0
  444. package/contracts/schemas/manifest.schema.json +63 -0
  445. package/contracts/schemas/run-event.schema.json +72 -0
  446. package/install.ps1 +35 -0
  447. package/install.sh +17 -0
  448. package/internal/ai-protocol-workflow.js +5600 -0
  449. package/internal/hub-client.js +98 -0
  450. package/internal/hub-sync-selection.js +69 -0
  451. package/internal/visual-hooks/README.md +481 -0
  452. package/internal/visual-hooks/config-loader.js +218 -0
  453. package/internal/visual-hooks/control-puller.js +206 -0
  454. package/internal/visual-hooks/gate-signal.js +150 -0
  455. package/internal/visual-hooks/inbox-consumer.js +469 -0
  456. package/internal/visual-hooks/index.js +197 -0
  457. package/internal/visual-hooks/push-client.js +189 -0
  458. package/internal/visual-hooks/receipt-pusher.js +176 -0
  459. package/internal/visual-hooks/runtime-state-pusher.js +128 -0
  460. package/openspec/changes/.gitkeep +0 -0
  461. package/openspec/changes/archive/.gitkeep +0 -0
  462. package/openspec/config.yaml.template +52 -0
  463. package/openspec/schemas/expert-delivery/schema.yaml +68 -0
  464. package/openspec/schemas/expert-delivery/templates/checklist.md +39 -0
  465. package/openspec/schemas/expert-delivery/templates/design.md +61 -0
  466. package/openspec/schemas/expert-delivery/templates/iterations.md +25 -0
  467. package/openspec/schemas/expert-delivery/templates/proposal.md +45 -0
  468. package/openspec/schemas/expert-delivery/templates/spec.md +29 -0
  469. package/openspec/schemas/expert-delivery/templates/tasks.md +24 -0
  470. package/openspec/specs/.gitkeep +0 -0
  471. package/package.json +73 -0
  472. package/scripts/acceptance-zero-intrusion.sh +168 -0
  473. package/scripts/hub-sync-assets.config.example.json +296 -0
  474. package/scripts/hub-sync-assets.js +2038 -0
  475. package/scripts/local-verify.sh +280 -0
  476. package/scripts/post-publish-auto-fix-check.js +404 -0
  477. package/scripts/post-publish-verify.sh +175 -0
  478. package/scripts/setup-cursor-manual-test.sh +107 -0
  479. package/scripts/setup-cursor-spec-archive-test.sh +111 -0
  480. package/scripts/setup-visual-integration.sh +225 -0
  481. package/scripts/test-integration.sh +176 -0
  482. package/scripts/update-test-project.sh +93 -0
  483. package/scripts/upload-four-web.sh +57 -0
  484. package/scripts/verify-install-ps1-bom.js +26 -0
  485. package/src/agent/agent-context.js +259 -0
  486. package/src/agent/agent-profile.js +185 -0
  487. package/src/agent/agent-templates.js +161 -0
  488. package/src/agent/agent-types.js +108 -0
  489. package/src/agent/collaboration-protocol.js +333 -0
  490. package/src/agent/conflict-handler.js +364 -0
  491. package/src/agent/file-permission.js +121 -0
  492. package/src/agent/index.js +38 -0
  493. package/src/agent/permission-audit.js +151 -0
  494. package/src/agent/review-repair-loop.js +270 -0
  495. package/src/agent/tool-permission.js +101 -0
  496. package/src/asset/asset-dependency.js +322 -0
  497. package/src/asset/asset-feedback.js +350 -0
  498. package/src/asset/asset-fork.js +300 -0
  499. package/src/asset/asset-install.js +278 -0
  500. package/src/asset/asset-installer.js +497 -0
  501. package/src/asset/asset-lifecycle.js +324 -0
  502. package/src/asset/asset-manager.js +245 -0
  503. package/src/asset/asset-package-manager.js +349 -0
  504. package/src/asset/asset-package.js +186 -0
  505. package/src/asset/asset-quality.js +262 -0
  506. package/src/asset/asset-registry.js +387 -0
  507. package/src/asset/asset-version.js +293 -0
  508. package/src/asset/index.js +86 -0
  509. package/src/cache/agent-profile-cache.js +59 -0
  510. package/src/cache/asset-cache.js +63 -0
  511. package/src/cache/global-cache.js +61 -0
  512. package/src/cache/manifest-cache.js +30 -0
  513. package/src/check/check-service.js +32 -0
  514. package/src/config/config-layer.js +343 -0
  515. package/src/config/config-loader.js +60 -0
  516. package/src/config/defaults.js +49 -0
  517. package/src/connectors/hub/asset-package.js +72 -0
  518. package/src/connectors/hub/asset-usage-feedback.js +46 -0
  519. package/src/connectors/hub/hub-connector.js +44 -0
  520. package/src/connectors/hub/index.js +21 -0
  521. package/src/connectors/visual/evidence-report.js +49 -0
  522. package/src/connectors/visual/index.js +15 -0
  523. package/src/connectors/visual/queue.js +41 -0
  524. package/src/connectors/visual/run-event.js +81 -0
  525. package/src/connectors/visual/visual-connector.js +77 -0
  526. package/src/context/context-budget.js +59 -0
  527. package/src/context/context-builder.js +285 -0
  528. package/src/context/context-loader.js +116 -0
  529. package/src/context/context-planner.js +158 -0
  530. package/src/context/types.js +96 -0
  531. package/src/contracts/index.js +63 -0
  532. package/src/executor/executor-registry.js +78 -0
  533. package/src/executor/executor-result-parser.js +44 -0
  534. package/src/executor/executor-runner.js +141 -0
  535. package/src/executor/executor-selector.js +139 -0
  536. package/src/executor/executor-timeout.js +36 -0
  537. package/src/executor/providers/base-provider-utils.js +189 -0
  538. package/src/executor/providers/claude-code-executor-provider.js +128 -0
  539. package/src/executor/providers/codex-executor-provider.js +126 -0
  540. package/src/executor/providers/cursor-executor-provider.js +99 -0
  541. package/src/executor/types.js +137 -0
  542. package/src/git/branch-manager.js +71 -0
  543. package/src/git/dirty-checker.js +43 -0
  544. package/src/git/dirty-strategy-handler.js +29 -0
  545. package/src/git/git-command.js +37 -0
  546. package/src/git/git-repository-detector.js +45 -0
  547. package/src/git/multi-repo-worktree-planner.js +88 -0
  548. package/src/git/policy.js +19 -0
  549. package/src/git/strategies/block-dirty-strategy.js +34 -0
  550. package/src/git/strategies/ignore-dirty-strategy.js +33 -0
  551. package/src/git/strategies/patch-snapshot-strategy.js +53 -0
  552. package/src/git/strategies/wip-commit-strategy.js +38 -0
  553. package/src/git/types.js +71 -0
  554. package/src/git/worktree-manager.js +85 -0
  555. package/src/governance/asset-review.js +351 -0
  556. package/src/governance/audit-log.js +368 -0
  557. package/src/governance/gray-release.js +312 -0
  558. package/src/governance/index.js +31 -0
  559. package/src/governance/policy-types.js +56 -0
  560. package/src/governance/rbac-types.js +171 -0
  561. package/src/governance/rbac.js +382 -0
  562. package/src/governance/rollback.js +360 -0
  563. package/src/governance/security-policy.js +354 -0
  564. package/src/hook/hook-config-writer.js +125 -0
  565. package/src/hub/hub-client.js +186 -0
  566. package/src/hub/hub-config.js +39 -0
  567. package/src/hub/project-facts.js +31 -0
  568. package/src/hub/runtime-feedback-reporter.js +55 -0
  569. package/src/ide/adapters/adapter-protocol.js +385 -0
  570. package/src/ide/adapters/claude-adapter.js +419 -0
  571. package/src/ide/adapters/codex-adapter.js +60 -0
  572. package/src/ide/adapters/cursor-adapter.js +484 -0
  573. package/src/ide/adapters/index.js +24 -0
  574. package/src/ide/anchors/markdown-anchor-writer.js +152 -0
  575. package/src/ide/ide-service.js +270 -0
  576. package/src/ide/ide-types.js +94 -0
  577. package/src/ide/links/link-mode-resolver.js +160 -0
  578. package/src/ide/registry/ide-registry-builder.js +165 -0
  579. package/src/incident/incident-writer.js +47 -0
  580. package/src/incident/types.js +22 -0
  581. package/src/init/ide-linker.js +126 -0
  582. package/src/init/ide-pointer-injector.js +75 -0
  583. package/src/init/init-applier.js +197 -0
  584. package/src/init/init-plan.js +294 -0
  585. package/src/init/init-service.js +65 -0
  586. package/src/init/manifest-installer.js +302 -0
  587. package/src/init/types.js +26 -0
  588. package/src/project/config-writer.js +83 -0
  589. package/src/project/context-index-writer.js +82 -0
  590. package/src/project/json-utils.js +72 -0
  591. package/src/project/local-state-writer.js +50 -0
  592. package/src/project/lock-file-writer.js +98 -0
  593. package/src/project/manifest-writer.js +126 -0
  594. package/src/project/policy-config-writer.js +91 -0
  595. package/src/project/project-config-writer.js +74 -0
  596. package/src/project/project-files.js +39 -0
  597. package/src/project/registry-index-writer.js +43 -0
  598. package/src/project/workspace-config-writer.js +63 -0
  599. package/src/run/index.js +11 -0
  600. package/src/run/run-id.js +32 -0
  601. package/src/run/run-service.js +269 -0
  602. package/src/run/run-store.js +80 -0
  603. package/src/scanner/aggregator/detection-aggregator.js +23 -0
  604. package/src/scanner/boundary/boundary-resolver.js +229 -0
  605. package/src/scanner/detectors/detector-registry.js +44 -0
  606. package/src/scanner/detectors/fastapi-detector.js +46 -0
  607. package/src/scanner/detectors/go-detector.js +46 -0
  608. package/src/scanner/detectors/nestjs-detector.js +57 -0
  609. package/src/scanner/detectors/nextjs-detector.js +52 -0
  610. package/src/scanner/detectors/react-vite-detector.js +52 -0
  611. package/src/scanner/detectors/react-webpack-detector.js +57 -0
  612. package/src/scanner/detectors/springboot-detector.js +46 -0
  613. package/src/scanner/detectors/springcloud-detector.js +46 -0
  614. package/src/scanner/detectors/springmvc-detector.js +46 -0
  615. package/src/scanner/detectors/vue-vite-detector.js +52 -0
  616. package/src/scanner/engine.js +72 -0
  617. package/src/scanner/facts/fact-extractor.js +211 -0
  618. package/src/scanner/types.js +30 -0
  619. package/src/security/asset-tamper-checker.js +188 -0
  620. package/src/security/checksum.js +40 -0
  621. package/src/spec/spec-writer.js +302 -0
  622. package/src/state-machine/circuit-breaker.js +112 -0
  623. package/src/state-machine/escape-hatch.js +49 -0
  624. package/src/state-machine/stage-runner.js +281 -0
  625. package/src/state-machine/state-machine.js +24 -0
  626. package/src/state-machine/transition-guard.js +36 -0
  627. package/src/state-machine/types.js +37 -0
  628. package/src/sync/sync-service.js +192 -0
  629. package/src/visual/agent-visual.js +142 -0
  630. package/src/visual/event-gateway.js +357 -0
  631. package/src/visual/event-mapper.js +128 -0
  632. package/src/visual/hook-dashboard.js +216 -0
  633. package/src/visual/index.js +27 -0
  634. package/src/visual/metrics.js +287 -0
  635. package/src/visual/privacy-filter.js +100 -0
  636. package/src/visual/risk-board.js +252 -0
  637. package/src/visual/timeline.js +245 -0
  638. package/src/visual/visual-client.js +94 -0
  639. package/src/visual/visual-config.js +40 -0
  640. package/src/visual/visual-reporter.js +88 -0
@@ -0,0 +1,2541 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const { spawnSync } = require('child_process');
5
+ const {
6
+ resolveRuntimePaths,
7
+ getExistingPath,
8
+ getCandidatePaths,
9
+ shouldPersistHistory,
10
+ shouldPersistCheckpoints,
11
+ } = require('./runtime-paths');
12
+ const { syncRepoMap } = require('./repo-map');
13
+
14
+ function printUsage() {
15
+ console.log(`Usage:
16
+ ai-spec-auto runtime-state init --run-plan <file> [options]
17
+ ai-spec-auto runtime-state bootstrap --payload <file> [options]
18
+ ai-spec-auto runtime-state bootstrap --stdin [options]
19
+ ai-spec-auto runtime-state handoff --to-role <role> [options]
20
+ ai-spec-auto runtime-state approve [options]
21
+ ai-spec-auto runtime-state pause [options]
22
+ ai-spec-auto runtime-state resume [options]
23
+ ai-spec-auto runtime-state restore --checkpoint <file> [options]
24
+ ai-spec-auto runtime-state gate-blocked [options]
25
+ ai-spec-auto runtime-state complete [options]
26
+ ai-spec-auto runtime-state fail [options]
27
+ ai-spec-auto runtime-state cancel [options]
28
+ ai-spec-auto runtime-state status [options]
29
+
30
+ Options:
31
+ --target <dir> Target project directory (default: .)
32
+ --run-plan <file> Path to run-plan JSON file
33
+ --task-anchor <file> Optional path to task-anchor JSON file
34
+ --payload <file> Path to task-orchestrator bootstrap payload JSON file
35
+ --stdin Read bootstrap payload JSON from stdin
36
+ --run-id <id> Override generated run id
37
+ --to-role <role> Target role for handoff update
38
+ --next-role <role> Next role after current handoff
39
+ --from-role <role> Explicit source role override
40
+ --gate <id> Expected approval gate id
41
+ --checkpoint <file> Restore source checkpoint JSON file
42
+ --pending-gate <id> Pending approval gate id
43
+ --clear-pending-gate Clear current pending gate
44
+ --blocked-by-role <id> Role that raised the current gate
45
+ --resume-to-role <id> Role to resume into after approval
46
+ --required-user-action <text>
47
+ Explicit user action required by the gate
48
+ --blocked-reason <text> Human-readable reason for the gate
49
+ --message <text> Event message override
50
+ --error <text> Failure detail appended to errors list
51
+ --event-type <type> Event type override (default: role-handoff)
52
+ --status <status> planned | running | paused | waiting-confirm | waiting-approval | blocked | success | failed | cancelled
53
+ --trigger-source <src> Trigger source (default: ide-skill)
54
+ --entry <entry> Entry role (default: task-orchestrator)
55
+ --raw-input <text> Raw user input override
56
+ --change-id <id> Change id override
57
+ --change-impact <kind> patch | scope-delta | re-scope | archive-fix | followup-patch
58
+ --reconcile-strategy <strategy>
59
+ in-place | rewind-to-requirement | rewind-to-frontend | rewind-to-guardian | suggest-new-change | followup-patch
60
+ --reopen-reason <text> Human-readable reopen / repair reason
61
+ --parent-change-id <id> Parent change id for follow-up patch runs
62
+ --artifacts-to-update <items>
63
+ Comma-separated artifact hints to update incrementally
64
+ --json Print JSON result
65
+ --pretty Print readable summary (default)
66
+ --help Show this help
67
+
68
+ Environment:
69
+ AI_SPEC_PERSIST_CHECKPOINTS=1
70
+ Persist .ai-spec/checkpoints/<run-id>/*.json for restore/debug
71
+ `);
72
+ }
73
+
74
+ function parseArgs(argv) {
75
+ const args = [...argv];
76
+ const command = args.shift();
77
+ const options = {
78
+ target: '.',
79
+ triggerSource: 'ide-skill',
80
+ entry: 'task-orchestrator',
81
+ pretty: true,
82
+ json: false,
83
+ };
84
+
85
+ while (args.length > 0) {
86
+ const arg = args.shift();
87
+ switch (arg) {
88
+ case '--target':
89
+ options.target = args.shift();
90
+ break;
91
+ case '--run-plan':
92
+ options.runPlan = args.shift();
93
+ break;
94
+ case '--task-anchor':
95
+ case '--anchor':
96
+ options.taskAnchor = args.shift();
97
+ break;
98
+ case '--payload':
99
+ options.payload = args.shift();
100
+ break;
101
+ case '--stdin':
102
+ options.stdin = true;
103
+ break;
104
+ case '--run-id':
105
+ options.runId = args.shift();
106
+ break;
107
+ case '--to-role':
108
+ options.toRole = args.shift();
109
+ break;
110
+ case '--next-role':
111
+ options.nextRole = args.shift();
112
+ break;
113
+ case '--from-role':
114
+ options.fromRole = args.shift();
115
+ break;
116
+ case '--gate':
117
+ options.gate = args.shift();
118
+ break;
119
+ case '--checkpoint':
120
+ options.checkpoint = args.shift();
121
+ break;
122
+ case '--pending-gate':
123
+ options.pendingGate = args.shift();
124
+ break;
125
+ case '--clear-pending-gate':
126
+ options.clearPendingGate = true;
127
+ break;
128
+ case '--blocked-by-role':
129
+ options.blockedByRole = args.shift();
130
+ break;
131
+ case '--resume-to-role':
132
+ options.resumeToRole = args.shift();
133
+ break;
134
+ case '--required-user-action':
135
+ options.requiredUserAction = args.shift();
136
+ break;
137
+ case '--blocked-reason':
138
+ options.blockedReason = args.shift();
139
+ break;
140
+ case '--message':
141
+ options.message = args.shift();
142
+ break;
143
+ case '--error':
144
+ options.error = args.shift();
145
+ break;
146
+ case '--event-type':
147
+ options.eventType = args.shift();
148
+ break;
149
+ case '--status':
150
+ options.status = args.shift();
151
+ break;
152
+ case '--trigger-source':
153
+ options.triggerSource = args.shift();
154
+ break;
155
+ case '--entry':
156
+ options.entry = args.shift();
157
+ break;
158
+ case '--raw-input':
159
+ options.rawInput = args.shift();
160
+ break;
161
+ case '--change-id':
162
+ options.changeId = args.shift();
163
+ break;
164
+ case '--change-impact':
165
+ options.changeImpact = args.shift();
166
+ break;
167
+ case '--reconcile-strategy':
168
+ options.reconcileStrategy = args.shift();
169
+ break;
170
+ case '--reopen-reason':
171
+ options.reopenReason = args.shift();
172
+ break;
173
+ case '--parent-change-id':
174
+ options.parentChangeId = args.shift();
175
+ break;
176
+ case '--artifacts-to-update':
177
+ options.artifactsToUpdate = String(args.shift() || '')
178
+ .split(',')
179
+ .map((item) => item.trim())
180
+ .filter(Boolean);
181
+ break;
182
+ case '--json':
183
+ options.json = true;
184
+ options.pretty = false;
185
+ break;
186
+ case '--pretty':
187
+ options.pretty = true;
188
+ options.json = false;
189
+ break;
190
+ case '--help':
191
+ case '-h':
192
+ options.help = true;
193
+ break;
194
+ default:
195
+ throw new Error(`Unknown argument: ${arg}`);
196
+ }
197
+ }
198
+
199
+ return { command, options };
200
+ }
201
+
202
+ const DEFAULT_RUN_MODE = 'auto';
203
+ const DEFAULT_REVIEW_POLICY = 'none';
204
+ const RUN_MODES = new Set(['auto', 'suggest', 'manual']);
205
+ const REVIEW_POLICIES = new Set(['none', 'main-flow-blocking']);
206
+
207
+ function normalizeRunMode(value) {
208
+ const normalized = String(value || '').trim().toLowerCase();
209
+ return RUN_MODES.has(normalized) ? normalized : DEFAULT_RUN_MODE;
210
+ }
211
+
212
+ function normalizeReviewPolicy(value) {
213
+ const normalized = String(value || '').trim().toLowerCase();
214
+ return REVIEW_POLICIES.has(normalized) ? normalized : DEFAULT_REVIEW_POLICY;
215
+ }
216
+
217
+ function buildEffectiveApprovalGates(flowId, gates, reviewPolicy) {
218
+ const normalizedPolicy = normalizeReviewPolicy(reviewPolicy);
219
+ const deduped = Array.isArray(gates)
220
+ ? [...new Set(gates.map((item) => String(item || '').trim()).filter(Boolean))]
221
+ : [];
222
+ if (flowId !== 'prd-to-delivery' || normalizedPolicy !== 'main-flow-blocking') {
223
+ return deduped;
224
+ }
225
+ const supportedMainFlowGates = new Set(['before-implementation', 'before-guardian', 'before-archive']);
226
+ const shouldInjectMainFlowGates = deduped.length === 0 || deduped.every((gate) => supportedMainFlowGates.has(gate));
227
+ if (!shouldInjectMainFlowGates) {
228
+ return deduped;
229
+ }
230
+
231
+ const ordered = [];
232
+ for (const gate of ['before-implementation', 'before-guardian', 'before-archive']) {
233
+ if (!ordered.includes(gate)) {
234
+ ordered.push(gate);
235
+ }
236
+ }
237
+ for (const gate of deduped) {
238
+ if (!ordered.includes(gate)) {
239
+ ordered.push(gate);
240
+ }
241
+ }
242
+ return ordered;
243
+ }
244
+
245
+ function readJsonFile(filePath, label) {
246
+ const raw = fs.readFileSync(filePath, 'utf8');
247
+ try {
248
+ return JSON.parse(raw);
249
+ } catch (error) {
250
+ throw new Error(`${label} is not valid JSON: ${filePath}`);
251
+ }
252
+ }
253
+
254
+ function readJsonFromStdin(label) {
255
+ const raw = fs.readFileSync(0, 'utf8');
256
+ if (!raw.trim()) {
257
+ throw new Error(`${label} stdin is empty`);
258
+ }
259
+ try {
260
+ return JSON.parse(raw);
261
+ } catch (error) {
262
+ throw new Error(`${label} stdin is not valid JSON`);
263
+ }
264
+ }
265
+
266
+ function assertRunPlan(runPlan, filePath) {
267
+ if (!runPlan || typeof runPlan !== 'object') {
268
+ throw new Error(`Invalid run-plan object: ${filePath}`);
269
+ }
270
+ if (runPlan.kind !== 'run-plan') {
271
+ throw new Error(`Expected kind "run-plan" but got "${runPlan.kind || 'undefined'}": ${filePath}`);
272
+ }
273
+ if (!runPlan.flow || !runPlan.flow.id) {
274
+ throw new Error(`run-plan is missing flow.id: ${filePath}`);
275
+ }
276
+ if (!runPlan.plan || !runPlan.plan.first_handoff) {
277
+ throw new Error(`run-plan is missing plan.first_handoff: ${filePath}`);
278
+ }
279
+ }
280
+
281
+ function pad2(value) {
282
+ return String(value).padStart(2, '0');
283
+ }
284
+
285
+ function createRunId(now = new Date()) {
286
+ const y = now.getFullYear();
287
+ const m = pad2(now.getMonth() + 1);
288
+ const d = pad2(now.getDate());
289
+ const hh = pad2(now.getHours());
290
+ const mm = pad2(now.getMinutes());
291
+ const ss = pad2(now.getSeconds());
292
+ const rand = Math.random().toString(36).slice(2, 6);
293
+ return `run_${y}${m}${d}_${hh}${mm}${ss}_${rand}`;
294
+ }
295
+
296
+ function slugifyValue(value) {
297
+ return String(value || '')
298
+ .toLowerCase()
299
+ .replace(/[^a-z0-9]+/g, '-')
300
+ .replace(/^-+|-+$/g, '')
301
+ .replace(/-{2,}/g, '-');
302
+ }
303
+
304
+ function deriveChangeId({ explicitChangeId, rawInput, taskType, runId }) {
305
+ const normalizedExplicit = slugifyValue(explicitChangeId);
306
+ if (normalizedExplicit) {
307
+ return normalizedExplicit;
308
+ }
309
+
310
+ const normalizedInput = slugifyValue(rawInput);
311
+ if (normalizedInput) {
312
+ return normalizedInput.slice(0, 64);
313
+ }
314
+
315
+ const normalizedTaskType = slugifyValue(taskType) || 'change';
316
+ const normalizedRunId = slugifyValue(runId) || 'run';
317
+ return `${normalizedTaskType}-${normalizedRunId}`.slice(0, 96);
318
+ }
319
+
320
+ const FLOW_APPROVAL_RESUME_ROLE_HINTS = {
321
+ 'prd-to-delivery': {
322
+ 'requirement-analyst': 'frontend-implementer',
323
+ 'frontend-implementer': 'code-guardian',
324
+ 'code-guardian': 'archive-change',
325
+ 'archive-change': 'archive-change',
326
+ },
327
+ };
328
+
329
+ function inferApprovalResumeRole(state, options = {}) {
330
+ if (options.toRole || options.nextRole) {
331
+ return options.toRole || options.nextRole;
332
+ }
333
+
334
+ const gateResumeRole = state.gate_context?.resume_to_role || null;
335
+ if (gateResumeRole) {
336
+ return gateResumeRole;
337
+ }
338
+
339
+ const anchorNextRole = state.anchor?.stage?.next_role || null;
340
+ if (anchorNextRole) {
341
+ return anchorNextRole;
342
+ }
343
+
344
+ const flowId = state.flow?.id || null;
345
+ const currentRole = state.current_role || null;
346
+ const hintedRole = flowId && currentRole
347
+ ? FLOW_APPROVAL_RESUME_ROLE_HINTS[flowId]?.[currentRole] || null
348
+ : null;
349
+ if (hintedRole) {
350
+ return hintedRole;
351
+ }
352
+
353
+ return state.current_role || state.anchor?.stage?.current_role || state.plan?.first_handoff || null;
354
+ }
355
+
356
+ const CHECKPOINT_EVENTS = new Set([
357
+ 'bootstrap',
358
+ 'handoff',
359
+ 'gate-blocked',
360
+ 'approve',
361
+ 'pause',
362
+ 'complete',
363
+ 'fail',
364
+ 'cancel',
365
+ ]);
366
+
367
+ function buildGateContext(state, options = {}, fallbackGate = null) {
368
+ const gateId = options.gateId || options.gate || options.pendingGate || fallbackGate || state?.pending_gate || null;
369
+ if (!gateId) {
370
+ return null;
371
+ }
372
+
373
+ return {
374
+ gate_id: gateId,
375
+ blocked_by_role: options.blockedByRole || options.fromRole || state?.current_role || null,
376
+ resume_to_role: options.resumeToRole || options.nextRole || options.toRole || inferApprovalResumeRole(state || {}, options) || null,
377
+ required_user_action: options.requiredUserAction || state?.gate_context?.required_user_action || null,
378
+ blocked_reason: options.blockedReason || state?.gate_context?.blocked_reason || null,
379
+ };
380
+ }
381
+
382
+ function buildIncrementalUpdateState(state, options = {}, defaults = {}) {
383
+ const previous = state?.incremental_update && typeof state.incremental_update === 'object'
384
+ ? state.incremental_update
385
+ : {};
386
+ const next = {
387
+ change_context: options.changeContext || defaults.changeContext || previous.change_context || null,
388
+ route_decision: options.routeDecision || defaults.routeDecision || previous.route_decision || null,
389
+ trace_mode: options.traceMode || defaults.traceMode || previous.trace_mode || null,
390
+ change_impact: options.changeImpact || defaults.changeImpact || previous.change_impact || null,
391
+ reconcile_strategy: options.reconcileStrategy || defaults.reconcileStrategy || previous.reconcile_strategy || null,
392
+ artifacts_to_update: Array.isArray(options.artifactsToUpdate)
393
+ ? options.artifactsToUpdate
394
+ : Array.isArray(defaults.artifactsToUpdate)
395
+ ? defaults.artifactsToUpdate
396
+ : Array.isArray(previous.artifacts_to_update)
397
+ ? previous.artifacts_to_update
398
+ : [],
399
+ reopen_reason: options.reopenReason || defaults.reopenReason || previous.reopen_reason || null,
400
+ parent_change_id: options.parentChangeId || defaults.parentChangeId || previous.parent_change_id || null,
401
+ target_role: options.toRole || options.nextRole || defaults.targetRole || previous.target_role || null,
402
+ handoff_gate: options.handoffGate || defaults.handoffGate || previous.handoff_gate || null,
403
+ updated_at: defaults.updatedAt || previous.updated_at || null,
404
+ };
405
+
406
+ if (
407
+ !next.change_context &&
408
+ !next.route_decision &&
409
+ !next.trace_mode &&
410
+ !next.change_impact &&
411
+ !next.reconcile_strategy &&
412
+ next.artifacts_to_update.length === 0 &&
413
+ !next.reopen_reason &&
414
+ !next.parent_change_id &&
415
+ !next.target_role &&
416
+ !next.handoff_gate
417
+ ) {
418
+ return null;
419
+ }
420
+
421
+ return next;
422
+ }
423
+
424
+ function buildDefaultAutoFixState() {
425
+ return {
426
+ attempts: 0,
427
+ max_attempts: 1,
428
+ active: false,
429
+ last_failed_steps: [],
430
+ };
431
+ }
432
+
433
+ function normalizeAutoFixStep(step) {
434
+ if (!step || typeof step !== 'object') {
435
+ return null;
436
+ }
437
+
438
+ return {
439
+ name: typeof step.name === 'string' && step.name.trim() ? step.name.trim() : 'unknown',
440
+ status: typeof step.status === 'string' && step.status.trim() ? step.status.trim() : null,
441
+ command: typeof step.command === 'string' && step.command.trim() ? step.command.trim() : null,
442
+ exit_code: typeof step.exit_code === 'number' ? step.exit_code : null,
443
+ reason: typeof step.reason === 'string' && step.reason.trim() ? step.reason.trim() : null,
444
+ error: typeof step.error === 'string' && step.error.trim() ? step.error.trim() : null,
445
+ stdout_excerpt: typeof step.stdout_excerpt === 'string' && step.stdout_excerpt.trim() ? step.stdout_excerpt.trim() : null,
446
+ stderr_excerpt: typeof step.stderr_excerpt === 'string' && step.stderr_excerpt.trim() ? step.stderr_excerpt.trim() : null,
447
+ };
448
+ }
449
+
450
+ function normalizeAutoFixState(value) {
451
+ const defaults = buildDefaultAutoFixState();
452
+ const merged = value && typeof value === 'object'
453
+ ? { ...defaults, ...value }
454
+ : defaults;
455
+ const maxAttempts = Number.isFinite(Number(merged.max_attempts))
456
+ ? Math.max(1, Number(merged.max_attempts))
457
+ : defaults.max_attempts;
458
+ const attempts = Number.isFinite(Number(merged.attempts))
459
+ ? Math.max(0, Math.min(Number(merged.attempts), maxAttempts))
460
+ : defaults.attempts;
461
+ const lastFailedSteps = Array.isArray(merged.last_failed_steps)
462
+ ? merged.last_failed_steps
463
+ .map((item) => normalizeAutoFixStep(item))
464
+ .filter(Boolean)
465
+ : [];
466
+
467
+ return {
468
+ attempts,
469
+ max_attempts: maxAttempts,
470
+ active: Boolean(merged.active),
471
+ last_failed_steps: lastFailedSteps,
472
+ };
473
+ }
474
+
475
+ function buildNextAutoFixState(state, options = {}, defaults = {}) {
476
+ const current = normalizeAutoFixState(state?.auto_fix);
477
+ if (options.autoFixData && typeof options.autoFixData === 'object') {
478
+ return normalizeAutoFixState({
479
+ ...current,
480
+ ...options.autoFixData,
481
+ });
482
+ }
483
+
484
+ if (defaults && typeof defaults === 'object' && Object.keys(defaults).length > 0) {
485
+ return normalizeAutoFixState({
486
+ ...current,
487
+ ...defaults,
488
+ });
489
+ }
490
+
491
+ return current;
492
+ }
493
+
494
+ function buildCheckpointMetadata(state, eventName, relPath, timestamp) {
495
+ return {
496
+ sequence: (Number(state?.checkpoint_count) || 0) + 1,
497
+ event: eventName,
498
+ at: timestamp,
499
+ file: relPath,
500
+ };
501
+ }
502
+
503
+ const MICRO_TASK_TYPES = new Set([
504
+ 'page-development',
505
+ 'component-development',
506
+ 'bugfix',
507
+ 'bug-fix',
508
+ 'problem-fix',
509
+ 'issue-fix',
510
+ 'style-update',
511
+ 'route-update',
512
+ ]);
513
+
514
+ const MICRO_INPUT_PATTERNS = [
515
+ /mock/i,
516
+ /mock数据/,
517
+ /示例数据/,
518
+ /静态/,
519
+ /单页/,
520
+ /单一页面/,
521
+ /简单页面/,
522
+ /简单组件/,
523
+ /列表页面/,
524
+ /登录页面/,
525
+ /注册页面/,
526
+ /商品列表页面/,
527
+ /原型/,
528
+ ];
529
+
530
+ const STANDARD_INPUT_PATTERNS = [
531
+ /重构/,
532
+ /权限/,
533
+ /支付/,
534
+ /认证/,
535
+ /oauth/i,
536
+ /短信/,
537
+ /多步骤/,
538
+ /多页面/,
539
+ /复杂/,
540
+ /真实接口/,
541
+ /核心模块/,
542
+ /状态联动/,
543
+ /合规/,
544
+ /安全/,
545
+ ];
546
+
547
+ const HIGH_RISK_INPUT_PATTERNS = [
548
+ /支付/,
549
+ /认证/,
550
+ /oauth/i,
551
+ /短信/,
552
+ /权限/,
553
+ /安全/,
554
+ /合规/,
555
+ /风控/,
556
+ /收款/,
557
+ /交易/,
558
+ ];
559
+
560
+ const DEFERRED_DETAIL_PATTERNS = [
561
+ /先不说/,
562
+ /先不提供/,
563
+ /暂不说/,
564
+ /暂不提供/,
565
+ /暂未确定/,
566
+ /未明确/,
567
+ /待定/,
568
+ /后续再说/,
569
+ /后面再说/,
570
+ ];
571
+
572
+ function inferRiskLevel({ explicitRiskLevel, rawInput, taskType, deliveryProfile }) {
573
+ const normalizedExplicit = String(explicitRiskLevel || '').trim().toLowerCase();
574
+ if (normalizedExplicit === 'low' || normalizedExplicit === 'medium' || normalizedExplicit === 'high') {
575
+ return normalizedExplicit;
576
+ }
577
+
578
+ let score = 0;
579
+ const input = String(rawInput || '');
580
+ const normalizedTaskType = String(taskType || '').trim().toLowerCase();
581
+
582
+ if (deliveryProfile === 'standard') {
583
+ score += 1;
584
+ }
585
+
586
+ if (normalizedTaskType.includes('payment') || normalizedTaskType.includes('auth') || normalizedTaskType.includes('security')) {
587
+ score += 2;
588
+ }
589
+
590
+ for (const pattern of HIGH_RISK_INPUT_PATTERNS) {
591
+ if (pattern.test(input)) {
592
+ score += 2;
593
+ break;
594
+ }
595
+ }
596
+
597
+ for (const pattern of DEFERRED_DETAIL_PATTERNS) {
598
+ if (pattern.test(input)) {
599
+ score += 2;
600
+ break;
601
+ }
602
+ }
603
+
604
+ if (score >= 4) {
605
+ return 'high';
606
+ }
607
+ if (score >= 2) {
608
+ return 'medium';
609
+ }
610
+ return 'low';
611
+ }
612
+
613
+ function inferDeliveryProfile({ explicitProfile, flowId, taskType, rawInput, riskLevel }) {
614
+ const normalizedExplicit = String(explicitProfile || '').trim().toLowerCase();
615
+ if (normalizedExplicit === 'micro' || normalizedExplicit === 'standard') {
616
+ return normalizedExplicit;
617
+ }
618
+
619
+ let score = 0;
620
+
621
+ if (MICRO_TASK_TYPES.has(String(taskType || '').trim().toLowerCase())) {
622
+ score += 1;
623
+ }
624
+
625
+ const input = String(rawInput || '');
626
+ for (const pattern of MICRO_INPUT_PATTERNS) {
627
+ if (pattern.test(input)) {
628
+ score += 2;
629
+ break;
630
+ }
631
+ }
632
+
633
+ for (const pattern of STANDARD_INPUT_PATTERNS) {
634
+ if (pattern.test(input)) {
635
+ score -= 2;
636
+ break;
637
+ }
638
+ }
639
+
640
+ const normalizedRisk = String(riskLevel || '').trim().toLowerCase();
641
+ if (normalizedRisk === 'low') {
642
+ score += 1;
643
+ } else if (normalizedRisk === 'high') {
644
+ score -= 2;
645
+ }
646
+
647
+ if (flowId && flowId !== 'prd-to-delivery') {
648
+ score -= 1;
649
+ }
650
+
651
+ return score >= 2 ? 'micro' : 'standard';
652
+ }
653
+
654
+ function inferArtifactProfile({ explicitProfile, deliveryProfile }) {
655
+ const normalizedExplicit = String(explicitProfile || '').trim().toLowerCase();
656
+ if (normalizedExplicit === 'compact' || normalizedExplicit === 'full') {
657
+ return normalizedExplicit;
658
+ }
659
+
660
+ return deliveryProfile === 'micro' ? 'compact' : 'full';
661
+ }
662
+
663
+ function inferComplexity({ explicitComplexity, deliveryProfile, riskLevel }) {
664
+ const normalizedExplicit = String(explicitComplexity || '').trim().toLowerCase();
665
+ if (normalizedExplicit === 'low' || normalizedExplicit === 'medium' || normalizedExplicit === 'high') {
666
+ return normalizedExplicit;
667
+ }
668
+
669
+ const normalizedRisk = String(riskLevel || '').trim().toLowerCase();
670
+ if (normalizedRisk === 'high') {
671
+ return 'high';
672
+ }
673
+ if (normalizedRisk === 'medium') {
674
+ return 'medium';
675
+ }
676
+
677
+ return deliveryProfile === 'micro' ? 'low' : 'medium';
678
+ }
679
+
680
+ function normalizeSpecsArtifactPath(relPath) {
681
+ const value = String(relPath || '').trim();
682
+ if (!value) {
683
+ return null;
684
+ }
685
+
686
+ const normalized = value.replace(/[\\/]+$/, '');
687
+ if (/[\\/]specs$/.test(normalized)) {
688
+ return normalized;
689
+ }
690
+
691
+ const match = normalized.match(/^(.*[\\/]specs)(?:[\\/].+)?$/);
692
+ return match ? match[1] : normalized;
693
+ }
694
+
695
+ function buildDefaultArtifacts(changeId, options = {}) {
696
+ const flowId = String(options.flowId || '').trim();
697
+ const runId = String(options.runId || '').trim();
698
+ const traceMode = String(options.traceMode || '').trim();
699
+
700
+ if ((flowId === 'bugfix-to-verification' || traceMode === 'direct-fix') && runId) {
701
+ const historyDir = `.ai-spec/history/${runId}`;
702
+ return {
703
+ proposal: null,
704
+ specs: null,
705
+ design: null,
706
+ tasks: null,
707
+ bugfix: `${historyDir}/bugfix.md`,
708
+ implementation_notes: `${historyDir}/implementation-notes.md`,
709
+ checklist: `${historyDir}/checklist.md`,
710
+ iterations: `${historyDir}/iterations.md`,
711
+ additional: [],
712
+ };
713
+ }
714
+
715
+ if (!changeId) {
716
+ return {
717
+ proposal: null,
718
+ specs: null,
719
+ design: null,
720
+ tasks: null,
721
+ bugfix: null,
722
+ implementation_notes: null,
723
+ checklist: null,
724
+ iterations: null,
725
+ additional: [],
726
+ };
727
+ }
728
+
729
+ const baseDir = `openspec/changes/${changeId}`;
730
+ return {
731
+ proposal: `${baseDir}/proposal.md`,
732
+ specs: `${baseDir}/specs`,
733
+ design: `${baseDir}/design.md`,
734
+ tasks: `${baseDir}/tasks.md`,
735
+ bugfix: null,
736
+ implementation_notes: null,
737
+ checklist: `${baseDir}/checklist.md`,
738
+ iterations: `${baseDir}/iterations.md`,
739
+ additional: [],
740
+ };
741
+ }
742
+
743
+ function mergeArtifacts(baseArtifacts, inferredArtifacts) {
744
+ const proposal = inferredArtifacts?.proposal || baseArtifacts?.proposal || null;
745
+ const specs = normalizeSpecsArtifactPath(inferredArtifacts?.specs || baseArtifacts?.specs || null);
746
+ const design = inferredArtifacts?.design || baseArtifacts?.design || null;
747
+ const tasks = inferredArtifacts?.tasks || baseArtifacts?.tasks || null;
748
+ const bugfix = inferredArtifacts?.bugfix || baseArtifacts?.bugfix || null;
749
+ const implementationNotes = inferredArtifacts?.implementation_notes || baseArtifacts?.implementation_notes || null;
750
+ const checklist = inferredArtifacts?.checklist || baseArtifacts?.checklist || null;
751
+ const iterations = inferredArtifacts?.iterations || baseArtifacts?.iterations || null;
752
+ const primaryArtifacts = new Set(
753
+ [proposal, specs, design, tasks, bugfix, implementationNotes, checklist, iterations]
754
+ .map((item) => (typeof item === 'string' ? item.trim().replace(/[\\/]+$/, '') : null))
755
+ .filter(Boolean),
756
+ );
757
+ const additional = [
758
+ ...(Array.isArray(baseArtifacts?.additional) ? baseArtifacts.additional : []),
759
+ ...(Array.isArray(inferredArtifacts?.additional) ? inferredArtifacts.additional : []),
760
+ ]
761
+ .map((item) => String(item || '').trim())
762
+ .filter(Boolean)
763
+ .map((item) => item.replace(/[\\/]+$/, ''))
764
+ .filter((item) => !primaryArtifacts.has(item));
765
+
766
+ const merged = {
767
+ proposal,
768
+ specs,
769
+ design,
770
+ tasks,
771
+ bugfix,
772
+ implementation_notes: implementationNotes,
773
+ checklist,
774
+ iterations,
775
+ additional: Array.from(new Set(additional.filter(Boolean))),
776
+ };
777
+
778
+ if (merged.additional.length === 0) {
779
+ delete merged.additional;
780
+ }
781
+
782
+ return merged;
783
+ }
784
+
785
+ function inferArtifacts(artifacts) {
786
+ const normalized = {
787
+ proposal: null,
788
+ specs: null,
789
+ design: null,
790
+ tasks: null,
791
+ bugfix: null,
792
+ implementation_notes: null,
793
+ checklist: null,
794
+ iterations: null,
795
+ additional: [],
796
+ };
797
+
798
+ if (!artifacts) {
799
+ return normalized;
800
+ }
801
+
802
+ if (artifacts && typeof artifacts === 'object' && !Array.isArray(artifacts)) {
803
+ const directKeys = ['proposal', 'specs', 'design', 'tasks', 'bugfix', 'implementation_notes', 'checklist', 'iterations'];
804
+ for (const key of directKeys) {
805
+ if (typeof artifacts[key] === 'string' && artifacts[key].trim()) {
806
+ normalized[key] = key === 'specs'
807
+ ? normalizeSpecsArtifactPath(artifacts[key])
808
+ : artifacts[key];
809
+ }
810
+ }
811
+
812
+ const additional = artifacts.additional;
813
+ if (typeof additional === 'string' && additional.trim()) {
814
+ normalized.additional.push(additional);
815
+ } else if (Array.isArray(additional)) {
816
+ normalized.additional.push(...additional.filter((item) => typeof item === 'string' && item.trim()));
817
+ }
818
+
819
+ if (normalized.additional.length === 0) {
820
+ delete normalized.additional;
821
+ }
822
+
823
+ return normalized;
824
+ }
825
+
826
+ if (!Array.isArray(artifacts)) {
827
+ return normalized;
828
+ }
829
+
830
+ for (const item of artifacts) {
831
+ if (typeof item !== 'string') {
832
+ continue;
833
+ }
834
+ if (item.endsWith('/proposal.md')) {
835
+ normalized.proposal = item;
836
+ continue;
837
+ }
838
+ if (/[\\/]specs(?:[\\/].+)?$/.test(item)) {
839
+ normalized.specs = normalizeSpecsArtifactPath(item);
840
+ continue;
841
+ }
842
+ if (item.endsWith('/design.md')) {
843
+ normalized.design = item;
844
+ continue;
845
+ }
846
+ if (item.endsWith('/tasks.md')) {
847
+ normalized.tasks = item;
848
+ continue;
849
+ }
850
+ if (item.endsWith('/bugfix.md')) {
851
+ normalized.bugfix = item;
852
+ continue;
853
+ }
854
+ if (item.endsWith('/implementation-notes.md')) {
855
+ normalized.implementation_notes = item;
856
+ continue;
857
+ }
858
+ if (item.endsWith('/checklist.md')) {
859
+ normalized.checklist = item;
860
+ continue;
861
+ }
862
+ if (item.endsWith('/iterations.md')) {
863
+ normalized.iterations = item;
864
+ continue;
865
+ }
866
+ normalized.additional.push(item);
867
+ }
868
+
869
+ if (normalized.additional.length === 0) {
870
+ delete normalized.additional;
871
+ }
872
+
873
+ return normalized;
874
+ }
875
+
876
+ function sanitizeAnchor(taskAnchor) {
877
+ if (!taskAnchor || typeof taskAnchor !== 'object') {
878
+ return null;
879
+ }
880
+ return {
881
+ kind: taskAnchor.kind || 'task-anchor',
882
+ task: taskAnchor.task || null,
883
+ stage: taskAnchor.stage || null,
884
+ constraints: taskAnchor.constraints || null,
885
+ artifacts: taskAnchor.artifacts || null,
886
+ expected_output: taskAnchor.expected_output || [],
887
+ };
888
+ }
889
+
890
+ function normalizeBootstrapPayload(payload, sourceLabel) {
891
+ if (!payload || typeof payload !== 'object') {
892
+ throw new Error(`Invalid bootstrap payload: ${sourceLabel}`);
893
+ }
894
+
895
+ if (payload.kind === 'run-plan') {
896
+ return {
897
+ runPlan: payload,
898
+ taskAnchor: null,
899
+ };
900
+ }
901
+
902
+ const runPlan = payload.run_plan || payload.runPlan || null;
903
+ const taskAnchor = payload.task_anchor || payload.taskAnchor || null;
904
+
905
+ if (!runPlan) {
906
+ throw new Error(`Bootstrap payload is missing run_plan: ${sourceLabel}`);
907
+ }
908
+
909
+ return { runPlan, taskAnchor };
910
+ }
911
+
912
+ function buildRunState({ runPlan, taskAnchor, options, now, source }) {
913
+ const runId = options.runId || runPlan.run_id || createRunId(now);
914
+ const createdAt = now.toISOString();
915
+ const runMode = normalizeRunMode(runPlan.mode);
916
+ const reviewPolicy = normalizeReviewPolicy(runPlan.review_policy || runPlan.plan?.review_policy || null);
917
+ const rawInput =
918
+ options.rawInput ||
919
+ runPlan.task?.raw_input ||
920
+ taskAnchor?.task?.raw_goal ||
921
+ null;
922
+ const changeId = deriveChangeId({
923
+ explicitChangeId: options.changeId || runPlan.task?.change_id || taskAnchor?.task?.change_id || null,
924
+ rawInput,
925
+ taskType: runPlan.task?.type || null,
926
+ runId,
927
+ });
928
+ const deliveryProfile = inferDeliveryProfile({
929
+ explicitProfile: runPlan.delivery_profile || runPlan.flow?.delivery_profile || runPlan.plan?.delivery_profile || null,
930
+ flowId: runPlan.flow?.id || null,
931
+ taskType: runPlan.task?.type || null,
932
+ rawInput,
933
+ riskLevel: runPlan.task?.risk_level || null,
934
+ });
935
+ const riskLevel = inferRiskLevel({
936
+ explicitRiskLevel: runPlan.task?.risk_level || null,
937
+ rawInput,
938
+ taskType: runPlan.task?.type || null,
939
+ deliveryProfile,
940
+ });
941
+ const artifactProfile = inferArtifactProfile({
942
+ explicitProfile: runPlan.artifact_profile || runPlan.plan?.artifact_profile || null,
943
+ deliveryProfile,
944
+ });
945
+ const complexity = inferComplexity({
946
+ explicitComplexity: runPlan.complexity || runPlan.task?.complexity || null,
947
+ deliveryProfile,
948
+ riskLevel,
949
+ });
950
+ const changeContext = options.changeContext || runPlan.task?.change_context || null;
951
+ const routeDecision = options.routeDecision || runPlan.task?.route_decision || null;
952
+ const traceMode = options.traceMode || runPlan.task?.trace_mode || null;
953
+ const artifacts = mergeArtifacts(buildDefaultArtifacts(changeId, {
954
+ flowId: runPlan.flow?.id || null,
955
+ runId,
956
+ traceMode,
957
+ }), inferArtifacts(runPlan.artifacts));
958
+ const currentRole = runPlan.plan?.first_handoff || null;
959
+ const approvalGates = buildEffectiveApprovalGates(
960
+ runPlan.flow?.id || null,
961
+ Array.isArray(runPlan.plan?.approval_gates) ? runPlan.plan.approval_gates : [],
962
+ reviewPolicy,
963
+ );
964
+ const normalizedRunPlanStatus = String(runPlan.status || '').trim().toLowerCase();
965
+ const initialStatus = options.status
966
+ || (runMode === 'suggest'
967
+ ? (normalizedRunPlanStatus && normalizedRunPlanStatus !== 'planned' ? runPlan.status : 'waiting-confirm')
968
+ : runPlan.status || 'planned');
969
+ const pendingGate =
970
+ options.pendingGate ||
971
+ runPlan.pending_gate ||
972
+ runPlan.plan?.pending_gate ||
973
+ null;
974
+ const sanitizedAnchor = sanitizeAnchor(taskAnchor);
975
+ const anchor = sanitizedAnchor
976
+ ? {
977
+ ...sanitizedAnchor,
978
+ task: {
979
+ ...(sanitizedAnchor.task || {}),
980
+ change_id: sanitizedAnchor.task?.change_id || changeId,
981
+ },
982
+ artifacts: mergeArtifacts(
983
+ buildDefaultArtifacts(changeId, {
984
+ flowId: runPlan.flow?.id || null,
985
+ runId,
986
+ traceMode,
987
+ }),
988
+ inferArtifacts(sanitizedAnchor.artifacts || artifacts),
989
+ ),
990
+ }
991
+ : null;
992
+ const initMessage = source?.bootstrapPayload
993
+ ? 'runtime-state initialized from task-orchestrator bootstrap payload'
994
+ : 'runtime-state initialized from run-plan';
995
+ const initialGateContext = runPlan.gate_context && typeof runPlan.gate_context === 'object'
996
+ ? {
997
+ gate_id: runPlan.gate_context.gate_id || null,
998
+ blocked_by_role: runPlan.gate_context.blocked_by_role || null,
999
+ resume_to_role: runPlan.gate_context.resume_to_role || currentRole,
1000
+ required_user_action: runPlan.gate_context.required_user_action || null,
1001
+ blocked_reason: runPlan.gate_context.blocked_reason || null,
1002
+ }
1003
+ : null;
1004
+ const suggestGateContext = runMode === 'suggest' && initialStatus === 'waiting-confirm' && !pendingGate
1005
+ ? {
1006
+ gate_id: 'start-review',
1007
+ blocked_by_role: 'task-orchestrator',
1008
+ resume_to_role: currentRole,
1009
+ required_user_action: '请先确认建议执行计划,再启动第一位专家。',
1010
+ blocked_reason: '当前以 suggest(建议)模式启动,首轮 run-plan 需要先经过人工确认。',
1011
+ }
1012
+ : null;
1013
+
1014
+ return {
1015
+ schema_version: 1,
1016
+ kind: 'run-state',
1017
+ run_id: runId,
1018
+ mode: runMode,
1019
+ review_policy: reviewPolicy,
1020
+ delivery_profile: deliveryProfile,
1021
+ artifact_profile: artifactProfile,
1022
+ complexity,
1023
+ status: initialStatus,
1024
+ trigger: {
1025
+ source: options.triggerSource,
1026
+ entry: options.entry,
1027
+ raw_input: rawInput,
1028
+ latest_user_input: rawInput,
1029
+ latest_input_at: rawInput ? createdAt : null,
1030
+ },
1031
+ task: {
1032
+ change_id: changeId,
1033
+ parent_change_id: options.parentChangeId || runPlan.task?.parent_change_id || taskAnchor?.task?.parent_change_id || null,
1034
+ input_kind: runPlan.task?.input_kind || taskAnchor?.task?.input_kind || 'unknown',
1035
+ risk_level: riskLevel,
1036
+ type: runPlan.task?.type || null,
1037
+ complexity,
1038
+ change_context: changeContext,
1039
+ route_decision: routeDecision,
1040
+ trace_mode: traceMode,
1041
+ change_impact: options.changeImpact || runPlan.task?.change_impact || null,
1042
+ },
1043
+ flow: {
1044
+ id: runPlan.flow?.id || null,
1045
+ name: runPlan.flow?.name || null,
1046
+ source: runPlan.flow?.source || null,
1047
+ delivery_profile: deliveryProfile,
1048
+ artifact_profile: artifactProfile,
1049
+ },
1050
+ plan: {
1051
+ required_roles: runPlan.plan?.required_roles || [],
1052
+ activated_optional_roles: runPlan.plan?.activated_optional_roles || [],
1053
+ skipped_optional_roles: runPlan.plan?.skipped_optional_roles || [],
1054
+ approval_gates: approvalGates,
1055
+ first_handoff: currentRole,
1056
+ delivery_profile: deliveryProfile,
1057
+ artifact_profile: artifactProfile,
1058
+ review_policy: reviewPolicy,
1059
+ },
1060
+ current_role: currentRole,
1061
+ pending_input_update: false,
1062
+ pending_gate: pendingGate,
1063
+ gate_context: pendingGate
1064
+ ? buildGateContext(null, options, pendingGate)
1065
+ : initialGateContext || suggestGateContext,
1066
+ incremental_update: buildIncrementalUpdateState(null, options, {
1067
+ changeContext,
1068
+ routeDecision,
1069
+ traceMode,
1070
+ changeImpact: options.changeImpact || runPlan.task?.change_impact || null,
1071
+ reconcileStrategy: options.reconcileStrategy || runPlan.task?.reconcile_strategy || null,
1072
+ artifactsToUpdate: options.artifactsToUpdate || runPlan.task?.artifacts_to_update || [],
1073
+ reopenReason: options.reopenReason || runPlan.task?.reopen_reason || null,
1074
+ parentChangeId: options.parentChangeId || runPlan.task?.parent_change_id || null,
1075
+ updatedAt: createdAt,
1076
+ }),
1077
+ artifacts,
1078
+ verification: null,
1079
+ auto_fix: buildDefaultAutoFixState(),
1080
+ last_checkpoint: null,
1081
+ checkpoint_count: 0,
1082
+ assumptions: Array.isArray(runPlan.assumptions) ? runPlan.assumptions : [],
1083
+ missing_inputs: runPlan.missing_inputs || [],
1084
+ warnings: runPlan.warnings || [],
1085
+ errors: runPlan.errors || [],
1086
+ input_updates: [],
1087
+ anchor,
1088
+ events: [
1089
+ {
1090
+ at: createdAt,
1091
+ type: 'run-created',
1092
+ status: options.status || runPlan.status || 'planned',
1093
+ message: initMessage,
1094
+ },
1095
+ ],
1096
+ timestamps: {
1097
+ created_at: createdAt,
1098
+ updated_at: createdAt,
1099
+ },
1100
+ };
1101
+ }
1102
+
1103
+ function listMissingOpenSpecArtifacts(targetDir, state, artifactKeys) {
1104
+ const artifactMap = mergeArtifacts(
1105
+ buildDefaultArtifacts(state.task?.change_id || state.anchor?.task?.change_id || null),
1106
+ inferArtifacts(state.artifacts || null),
1107
+ );
1108
+ const missing = [];
1109
+
1110
+ for (const key of artifactKeys) {
1111
+ const relPath = artifactMap[key];
1112
+ if (!relPath) {
1113
+ missing.push(`artifact:${key}`);
1114
+ continue;
1115
+ }
1116
+
1117
+ const absolutePath = path.join(targetDir, relPath);
1118
+ if (!fs.existsSync(absolutePath)) {
1119
+ missing.push(relPath);
1120
+ }
1121
+ }
1122
+
1123
+ return missing;
1124
+ }
1125
+
1126
+ function assertRequiredOpenSpecArtifacts(targetDir, state, action, toRole) {
1127
+ if (state.flow?.id !== 'prd-to-delivery') {
1128
+ return;
1129
+ }
1130
+
1131
+ if (!state.task?.change_id) {
1132
+ throw new Error(`Cannot ${action} prd-to-delivery run without task.change_id`);
1133
+ }
1134
+
1135
+ let requiredArtifacts = [];
1136
+ if (action === 'handoff' && toRole === 'frontend-implementer') {
1137
+ requiredArtifacts = ['proposal', 'specs', 'design', 'tasks'];
1138
+ } else if (action === 'complete') {
1139
+ requiredArtifacts = ['proposal', 'specs', 'design', 'tasks', 'checklist', 'iterations'];
1140
+ }
1141
+
1142
+ if (requiredArtifacts.length === 0) {
1143
+ return;
1144
+ }
1145
+
1146
+ const missingArtifacts = listMissingOpenSpecArtifacts(targetDir, state, requiredArtifacts);
1147
+ if (missingArtifacts.length > 0) {
1148
+ throw new Error(
1149
+ `Cannot ${action} prd-to-delivery run; missing required OpenSpec artifacts: ${missingArtifacts.join(', ')}`,
1150
+ );
1151
+ }
1152
+ }
1153
+
1154
+ function ensureDir(dirPath) {
1155
+ fs.mkdirSync(dirPath, { recursive: true });
1156
+ }
1157
+
1158
+ function writeJsonFile(filePath, value) {
1159
+ fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
1160
+ }
1161
+
1162
+ function readRunStateFile(filePath) {
1163
+ const state = readJsonFile(filePath, 'run-state');
1164
+ if (!state || typeof state !== 'object' || state.kind !== 'run-state') {
1165
+ throw new Error(`Invalid run-state object: ${filePath}`);
1166
+ }
1167
+ if (!state.run_id) {
1168
+ throw new Error(`run-state is missing run_id: ${filePath}`);
1169
+ }
1170
+ return state;
1171
+ }
1172
+
1173
+ function loadTaskAnchor(taskAnchorPath, taskAnchorData = null) {
1174
+ if (taskAnchorData) {
1175
+ return taskAnchorData;
1176
+ }
1177
+ return taskAnchorPath ? readJsonFile(taskAnchorPath, 'task-anchor') : null;
1178
+ }
1179
+
1180
+ function maybeAttachCheckpoint(targetDir, state, checkpointEvent) {
1181
+ if (!shouldPersistCheckpoints() || !checkpointEvent || !CHECKPOINT_EVENTS.has(checkpointEvent)) {
1182
+ return state;
1183
+ }
1184
+
1185
+ const runtimePaths = resolveRuntimePaths(targetDir);
1186
+ const checkpointDir = path.join(runtimePaths.checkpointsDir.path, state.run_id);
1187
+ ensureDir(checkpointDir);
1188
+
1189
+ const timestamp = state.timestamps?.updated_at || new Date().toISOString();
1190
+ const sequence = (Number(state.checkpoint_count) || 0) + 1;
1191
+ const checkpointFileName = `${String(sequence).padStart(3, '0')}-${checkpointEvent}.json`;
1192
+ const checkpointPath = path.join(checkpointDir, checkpointFileName);
1193
+ const checkpointRelPath = path.relative(targetDir, checkpointPath);
1194
+ const metadata = buildCheckpointMetadata(state, checkpointEvent, checkpointRelPath, timestamp);
1195
+ const nextState = {
1196
+ ...state,
1197
+ checkpoint_count: sequence,
1198
+ last_checkpoint: metadata,
1199
+ };
1200
+
1201
+ writeJsonFile(checkpointPath, {
1202
+ schema_version: 1,
1203
+ kind: 'runtime-checkpoint',
1204
+ run_id: state.run_id,
1205
+ sequence,
1206
+ event: checkpointEvent,
1207
+ created_at: timestamp,
1208
+ state: nextState,
1209
+ });
1210
+
1211
+ return nextState;
1212
+ }
1213
+
1214
+ function saveUpdatedRunState({
1215
+ targetDir,
1216
+ historyRunPath,
1217
+ currentRunPath,
1218
+ syncCurrent,
1219
+ forceSyncCurrent = false,
1220
+ state,
1221
+ checkpointEvent = null,
1222
+ }) {
1223
+ syncRepoMap(targetDir);
1224
+ const nextState = maybeAttachCheckpoint(targetDir, state, checkpointEvent);
1225
+
1226
+ if (historyRunPath) {
1227
+ writeJsonFile(historyRunPath, nextState);
1228
+ }
1229
+ if (syncCurrent || forceSyncCurrent) {
1230
+ writeJsonFile(currentRunPath, nextState);
1231
+ }
1232
+
1233
+ try {
1234
+ const bridgePath = path.join(__dirname, 'visual-bridge.js');
1235
+ if (fs.existsSync(bridgePath)) {
1236
+ const child = spawnSync(process.execPath, [bridgePath, 'push-current', '--target', targetDir, '--event-name', checkpointEvent || 'runtime-state-updated', '--json'], {
1237
+ encoding: 'utf8',
1238
+ stdio: ['ignore', 'pipe', 'pipe'],
1239
+ });
1240
+ if (child.status !== 0 && process.env.AI_SPEC_VISUAL_BRIDGE_DEBUG === '1') {
1241
+ console.warn(`visual bridge skipped: ${child.stderr || child.stdout || 'unknown error'}`);
1242
+ }
1243
+ }
1244
+ } catch (error) {
1245
+ if (process.env.AI_SPEC_VISUAL_BRIDGE_DEBUG === '1') {
1246
+ console.warn(`visual bridge error: ${error.message}`);
1247
+ }
1248
+ }
1249
+
1250
+ return nextState;
1251
+ }
1252
+
1253
+ function recordRunInputUpdate(options) {
1254
+ if (!options.userInput || !String(options.userInput).trim()) {
1255
+ throw new Error('Missing required argument: userInput');
1256
+ }
1257
+
1258
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
1259
+ const { currentRunPath, historyRunPath, state, syncCurrent } = resolveRunStatePaths(targetDir, options.runId);
1260
+
1261
+ if (['success', 'failed', 'cancelled'].includes(String(state.status || '').toLowerCase())) {
1262
+ throw new Error(`Cannot update terminal run: ${state.run_id}`);
1263
+ }
1264
+
1265
+ const now = new Date();
1266
+ const userInput = String(options.userInput).trim();
1267
+ const update = {
1268
+ at: now.toISOString(),
1269
+ text: userInput,
1270
+ source: options.source || 'protocol-update',
1271
+ change_context: options.changeContext || null,
1272
+ route_decision: options.routeDecision || null,
1273
+ trace_mode: options.traceMode || null,
1274
+ change_impact: options.changeImpact || null,
1275
+ reconcile_strategy: options.reconcileStrategy || null,
1276
+ artifacts_to_update: Array.isArray(options.artifactsToUpdate) ? options.artifactsToUpdate : [],
1277
+ reopen_reason: options.reopenReason || null,
1278
+ parent_change_id: options.parentChangeId || null,
1279
+ target_role: options.toRole || options.nextRole || null,
1280
+ handoff_gate: options.handoffGate || null,
1281
+ };
1282
+
1283
+ const nextInputUpdates = [...(Array.isArray(state.input_updates) ? state.input_updates : []), update].slice(-20);
1284
+ const event = buildStateEvent({
1285
+ state,
1286
+ options: {
1287
+ ...options,
1288
+ toRole: state.current_role || state.plan?.first_handoff || null,
1289
+ clearPendingGate: false,
1290
+ message: `user input updated: ${userInput}`,
1291
+ },
1292
+ now,
1293
+ defaults: {
1294
+ status: state.status || 'running',
1295
+ eventType: 'user-input-updated',
1296
+ message: `user input updated: ${userInput}`,
1297
+ pendingGate: state.pending_gate ?? null,
1298
+ },
1299
+ });
1300
+
1301
+ const updatedState = {
1302
+ ...state,
1303
+ pending_input_update: true,
1304
+ trigger: {
1305
+ ...(state.trigger || {}),
1306
+ latest_user_input: userInput,
1307
+ latest_input_at: now.toISOString(),
1308
+ latest_change_context: options.changeContext || null,
1309
+ latest_route_decision: options.routeDecision || null,
1310
+ latest_trace_mode: options.traceMode || null,
1311
+ latest_change_impact: options.changeImpact || null,
1312
+ latest_reconcile_strategy: options.reconcileStrategy || null,
1313
+ },
1314
+ incremental_update: buildIncrementalUpdateState(state, options, {
1315
+ updatedAt: now.toISOString(),
1316
+ }),
1317
+ input_updates: nextInputUpdates,
1318
+ events: [...(Array.isArray(state.events) ? state.events : []), event],
1319
+ timestamps: {
1320
+ ...(state.timestamps || {}),
1321
+ updated_at: now.toISOString(),
1322
+ },
1323
+ };
1324
+
1325
+ const persistedState = saveUpdatedRunState({
1326
+ targetDir,
1327
+ historyRunPath,
1328
+ currentRunPath,
1329
+ syncCurrent,
1330
+ state: updatedState,
1331
+ checkpointEvent: 'pause',
1332
+ });
1333
+
1334
+ return {
1335
+ status: 'success',
1336
+ target: targetDir,
1337
+ artifacts: {
1338
+ current_run: syncCurrent ? currentRunPath : null,
1339
+ run_history: historyRunPath,
1340
+ },
1341
+ state: persistedState,
1342
+ update,
1343
+ };
1344
+ }
1345
+
1346
+ function writeRunState({ targetDir, runPlan, taskAnchor, options, source }) {
1347
+ const now = new Date();
1348
+ const state = buildRunState({ runPlan, taskAnchor, options, now, source });
1349
+ const runtimePaths = resolveRuntimePaths(targetDir);
1350
+ const persistHistory = shouldPersistHistory();
1351
+ if (persistHistory) {
1352
+ ensureDir(runtimePaths.runsDir.path);
1353
+ }
1354
+ ensureDir(path.dirname(runtimePaths.currentRun.path));
1355
+
1356
+ const currentRunPath = runtimePaths.currentRun.path;
1357
+ const historyRunPath = persistHistory
1358
+ ? path.join(runtimePaths.runsDir.path, `${state.run_id}.json`)
1359
+ : null;
1360
+
1361
+ const persistedState = saveUpdatedRunState({
1362
+ targetDir,
1363
+ historyRunPath,
1364
+ currentRunPath,
1365
+ syncCurrent: true,
1366
+ forceSyncCurrent: true,
1367
+ state,
1368
+ checkpointEvent: 'bootstrap',
1369
+ });
1370
+
1371
+ return {
1372
+ status: 'success',
1373
+ target: targetDir,
1374
+ artifacts: {
1375
+ current_run: currentRunPath,
1376
+ run_history: historyRunPath,
1377
+ },
1378
+ state: persistedState,
1379
+ source: {
1380
+ run_plan: source.runPlan || null,
1381
+ task_anchor: source.taskAnchor || null,
1382
+ bootstrap_payload: source.bootstrapPayload || null,
1383
+ },
1384
+ };
1385
+ }
1386
+
1387
+ function resolveRunStatePaths(targetDir, runId) {
1388
+ const runtimePaths = resolveRuntimePaths(targetDir);
1389
+ const aiSpecDir = runtimePaths.aiSpecDir.path;
1390
+ const currentRunPath = runtimePaths.currentRun.path;
1391
+ let historyRunPath = null;
1392
+ let state = null;
1393
+ const currentState = fs.existsSync(currentRunPath)
1394
+ ? readRunStateFile(currentRunPath)
1395
+ : null;
1396
+
1397
+ if (runId) {
1398
+ if (currentState && currentState.run_id === runId) {
1399
+ state = currentState;
1400
+ }
1401
+ for (const candidateDir of getCandidatePaths(runtimePaths.runsDir)) {
1402
+ const candidatePath = path.join(candidateDir, `${runId}.json`);
1403
+ if (fs.existsSync(candidatePath)) {
1404
+ historyRunPath = candidatePath;
1405
+ if (!state) {
1406
+ state = readRunStateFile(historyRunPath);
1407
+ }
1408
+ break;
1409
+ }
1410
+ }
1411
+ if (!state) {
1412
+ throw new Error(`run-state history file not found for run_id: ${runId}`);
1413
+ }
1414
+ } else {
1415
+ if (!fs.existsSync(currentRunPath)) {
1416
+ throw new Error(`current run-state file not found: ${currentRunPath}`);
1417
+ }
1418
+ state = currentState;
1419
+ const candidateHistory = getExistingPath({
1420
+ path: path.join(runtimePaths.runsDir.path, `${state.run_id}.json`),
1421
+ legacyPaths: getCandidatePaths(runtimePaths.runsDir).map((dirPath) => path.join(dirPath, `${state.run_id}.json`)).slice(1),
1422
+ });
1423
+ historyRunPath = fs.existsSync(candidateHistory) ? candidateHistory : null;
1424
+ }
1425
+
1426
+ return {
1427
+ aiSpecDir,
1428
+ currentRunPath,
1429
+ historyRunPath,
1430
+ state,
1431
+ syncCurrent: Boolean(currentState && currentState.run_id === state.run_id),
1432
+ };
1433
+ }
1434
+
1435
+ function buildHandoffEvent({ state, options, now }) {
1436
+ const fromRole = options.fromRole || state.current_role || state.plan?.first_handoff || null;
1437
+ const toRole = options.toRole;
1438
+ const eventType = options.eventType || 'role-handoff';
1439
+ const message =
1440
+ options.message ||
1441
+ `handoff from ${fromRole || 'unknown'} to ${toRole}`;
1442
+
1443
+ return {
1444
+ at: now.toISOString(),
1445
+ type: eventType,
1446
+ status: options.status || state.status || 'running',
1447
+ from_role: fromRole,
1448
+ to_role: toRole,
1449
+ pending_gate:
1450
+ options.clearPendingGate ? null :
1451
+ (Object.prototype.hasOwnProperty.call(options, 'pendingGate') ? options.pendingGate || null : state.pending_gate || null),
1452
+ gate_context: options.clearPendingGate ? null : buildGateContext(state, options),
1453
+ message,
1454
+ };
1455
+ }
1456
+
1457
+ function buildStateEvent({ state, options, now, defaults = {} }) {
1458
+ const fromRole = options.fromRole || defaults.fromRole || state.current_role || state.plan?.first_handoff || null;
1459
+ const toRole = options.toRole || defaults.toRole || null;
1460
+ const pendingGate = options.clearPendingGate
1461
+ ? null
1462
+ : (Object.prototype.hasOwnProperty.call(options, 'pendingGate')
1463
+ ? options.pendingGate || null
1464
+ : defaults.pendingGate ?? state.pending_gate ?? null);
1465
+ const status = options.status || defaults.status || state.status || 'running';
1466
+ const eventType = options.eventType || defaults.eventType || 'state-updated';
1467
+ const message = options.message || defaults.message || eventType;
1468
+
1469
+ return {
1470
+ at: now.toISOString(),
1471
+ type: eventType,
1472
+ status,
1473
+ from_role: fromRole,
1474
+ to_role: toRole,
1475
+ pending_gate: pendingGate,
1476
+ gate_context: pendingGate ? buildGateContext(state, options, pendingGate) : null,
1477
+ message,
1478
+ };
1479
+ }
1480
+
1481
+ function shouldClearPendingGateForHandoff(state, options = {}) {
1482
+ if (Object.prototype.hasOwnProperty.call(options, 'clearPendingGate')) {
1483
+ return Boolean(options.clearPendingGate);
1484
+ }
1485
+
1486
+ if (Object.prototype.hasOwnProperty.call(options, 'pendingGate')) {
1487
+ return false;
1488
+ }
1489
+
1490
+ return Boolean(state?.pending_gate && state?.pending_input_update);
1491
+ }
1492
+
1493
+ function updateAnchorForRole(existingAnchor, taskAnchor, toRole, nextRole) {
1494
+ const sanitizedAnchor = taskAnchor ? sanitizeAnchor(taskAnchor) : existingAnchor || null;
1495
+ if (!sanitizedAnchor) {
1496
+ return null;
1497
+ }
1498
+ return {
1499
+ ...sanitizedAnchor,
1500
+ stage: {
1501
+ ...(sanitizedAnchor.stage || {}),
1502
+ current_role: toRole ?? sanitizedAnchor.stage?.current_role ?? null,
1503
+ next_role: nextRole ?? sanitizedAnchor.stage?.next_role ?? null,
1504
+ },
1505
+ };
1506
+ }
1507
+
1508
+ function handoffRunState(options) {
1509
+ if (!options.toRole) {
1510
+ throw new Error('Missing required argument: --to-role <role>');
1511
+ }
1512
+
1513
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
1514
+ const taskAnchorPath = options.taskAnchor
1515
+ ? path.resolve(process.cwd(), options.taskAnchor)
1516
+ : null;
1517
+ const { currentRunPath, historyRunPath, state, syncCurrent } = resolveRunStatePaths(targetDir, options.runId);
1518
+ assertRequiredOpenSpecArtifacts(targetDir, state, 'handoff', options.toRole);
1519
+ const taskAnchor = loadTaskAnchor(taskAnchorPath, options.taskAnchorData || null);
1520
+ const sanitizedAnchor = updateAnchorForRole(
1521
+ state.anchor || null,
1522
+ taskAnchor,
1523
+ options.toRole,
1524
+ options.nextRole,
1525
+ );
1526
+ const now = new Date();
1527
+ const clearPendingGate = shouldClearPendingGateForHandoff(state, options);
1528
+ const event = buildHandoffEvent({
1529
+ state,
1530
+ options: {
1531
+ ...options,
1532
+ clearPendingGate,
1533
+ },
1534
+ now,
1535
+ });
1536
+ const updatedState = {
1537
+ ...state,
1538
+ status: options.status || 'running',
1539
+ current_role: options.toRole,
1540
+ pending_input_update: false,
1541
+ pending_gate: clearPendingGate
1542
+ ? null
1543
+ : (Object.prototype.hasOwnProperty.call(options, 'pendingGate') ? options.pendingGate || null : state.pending_gate || null),
1544
+ gate_context: clearPendingGate
1545
+ ? null
1546
+ : buildGateContext(state, options),
1547
+ verification: options.verificationData || state.verification || null,
1548
+ auto_fix: buildNextAutoFixState(state, options),
1549
+ anchor: sanitizedAnchor,
1550
+ events: [...(Array.isArray(state.events) ? state.events : []), event],
1551
+ timestamps: {
1552
+ ...(state.timestamps || {}),
1553
+ updated_at: now.toISOString(),
1554
+ },
1555
+ };
1556
+
1557
+ const persistedState = saveUpdatedRunState({
1558
+ targetDir,
1559
+ historyRunPath,
1560
+ currentRunPath,
1561
+ syncCurrent,
1562
+ state: updatedState,
1563
+ checkpointEvent: 'handoff',
1564
+ });
1565
+
1566
+ return {
1567
+ status: 'success',
1568
+ target: targetDir,
1569
+ artifacts: {
1570
+ current_run: syncCurrent ? currentRunPath : null,
1571
+ run_history: historyRunPath,
1572
+ },
1573
+ state: persistedState,
1574
+ source: {
1575
+ task_anchor: taskAnchorPath,
1576
+ },
1577
+ handoff: {
1578
+ from_role: event.from_role || null,
1579
+ to_role: options.toRole,
1580
+ next_role: options.nextRole || null,
1581
+ },
1582
+ };
1583
+ }
1584
+
1585
+ function approveRunState(options) {
1586
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
1587
+ const taskAnchorPath = options.taskAnchor
1588
+ ? path.resolve(process.cwd(), options.taskAnchor)
1589
+ : null;
1590
+ const { currentRunPath, historyRunPath, state, syncCurrent } = resolveRunStatePaths(targetDir, options.runId);
1591
+ const activeGate = state.pending_gate || null;
1592
+ const requestedGate = options.gate || activeGate;
1593
+
1594
+ if (!activeGate) {
1595
+ throw new Error('No pending approval gate found');
1596
+ }
1597
+ if (options.gate && activeGate && options.gate !== activeGate) {
1598
+ throw new Error(`Pending gate mismatch: current is "${activeGate}", requested "${options.gate}"`);
1599
+ }
1600
+
1601
+ const toRole = inferApprovalResumeRole(state, options);
1602
+ const taskAnchor = loadTaskAnchor(taskAnchorPath, options.taskAnchorData || null);
1603
+ const anchor = updateAnchorForRole(state.anchor || null, taskAnchor, toRole, options.nextRole);
1604
+ const now = new Date();
1605
+ const event = buildStateEvent({
1606
+ state,
1607
+ options: { ...options, toRole, clearPendingGate: true },
1608
+ now,
1609
+ defaults: {
1610
+ status: 'running',
1611
+ eventType: 'gate-cleared',
1612
+ message: `approval cleared for ${requestedGate}`,
1613
+ pendingGate: null,
1614
+ },
1615
+ });
1616
+
1617
+ const updatedState = {
1618
+ ...state,
1619
+ status: options.status || 'running',
1620
+ current_role: toRole,
1621
+ pending_input_update: false,
1622
+ pending_gate: null,
1623
+ gate_context: null,
1624
+ incremental_update: buildIncrementalUpdateState(state, options, {
1625
+ updatedAt: now.toISOString(),
1626
+ }),
1627
+ auto_fix: buildNextAutoFixState(state, options),
1628
+ anchor,
1629
+ events: [...(Array.isArray(state.events) ? state.events : []), event],
1630
+ timestamps: {
1631
+ ...(state.timestamps || {}),
1632
+ updated_at: now.toISOString(),
1633
+ },
1634
+ };
1635
+
1636
+ const persistedState = saveUpdatedRunState({
1637
+ targetDir,
1638
+ historyRunPath,
1639
+ currentRunPath,
1640
+ syncCurrent,
1641
+ state: updatedState,
1642
+ checkpointEvent: 'approve',
1643
+ });
1644
+
1645
+ return {
1646
+ status: 'success',
1647
+ target: targetDir,
1648
+ artifacts: {
1649
+ current_run: syncCurrent ? currentRunPath : null,
1650
+ run_history: historyRunPath,
1651
+ },
1652
+ state: persistedState,
1653
+ source: {
1654
+ task_anchor: taskAnchorPath,
1655
+ gate: requestedGate,
1656
+ },
1657
+ handoff: {
1658
+ from_role: event.from_role || null,
1659
+ to_role: toRole,
1660
+ next_role: options.nextRole || null,
1661
+ },
1662
+ };
1663
+ }
1664
+
1665
+ function pauseRunState(options) {
1666
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
1667
+ const taskAnchorPath = options.taskAnchor
1668
+ ? path.resolve(process.cwd(), options.taskAnchor)
1669
+ : null;
1670
+ const { currentRunPath, historyRunPath, state, syncCurrent } = resolveRunStatePaths(targetDir, options.runId);
1671
+ if (['success', 'failed', 'cancelled'].includes(String(state.status || '').toLowerCase())) {
1672
+ throw new Error(`Cannot pause terminal run: ${state.run_id}`);
1673
+ }
1674
+
1675
+ const toRole = options.toRole || state.current_role || state.anchor?.stage?.current_role || state.plan?.first_handoff || null;
1676
+ const taskAnchor = loadTaskAnchor(taskAnchorPath, options.taskAnchorData || null);
1677
+ const anchor = updateAnchorForRole(state.anchor || null, taskAnchor, toRole, options.nextRole);
1678
+ const now = new Date();
1679
+ const event = buildStateEvent({
1680
+ state,
1681
+ options: { ...options, toRole, clearPendingGate: false },
1682
+ now,
1683
+ defaults: {
1684
+ status: 'paused',
1685
+ eventType: 'run-paused',
1686
+ message: options.message || 'run paused',
1687
+ pendingGate: state.pending_gate || null,
1688
+ },
1689
+ });
1690
+
1691
+ const updatedState = {
1692
+ ...state,
1693
+ status: options.status || 'paused',
1694
+ current_role: toRole,
1695
+ pending_input_update: false,
1696
+ pending_gate: options.clearPendingGate ? null : state.pending_gate || null,
1697
+ gate_context: options.clearPendingGate ? null : state.gate_context || null,
1698
+ incremental_update: buildIncrementalUpdateState(state, options, {
1699
+ updatedAt: now.toISOString(),
1700
+ }),
1701
+ auto_fix: buildNextAutoFixState(state, options),
1702
+ anchor,
1703
+ events: [...(Array.isArray(state.events) ? state.events : []), event],
1704
+ timestamps: {
1705
+ ...(state.timestamps || {}),
1706
+ updated_at: now.toISOString(),
1707
+ },
1708
+ };
1709
+
1710
+ const persistedState = saveUpdatedRunState({
1711
+ targetDir,
1712
+ historyRunPath,
1713
+ currentRunPath,
1714
+ syncCurrent,
1715
+ state: updatedState,
1716
+ });
1717
+
1718
+ return {
1719
+ status: 'success',
1720
+ target: targetDir,
1721
+ artifacts: {
1722
+ current_run: syncCurrent ? currentRunPath : null,
1723
+ run_history: historyRunPath,
1724
+ },
1725
+ state: persistedState,
1726
+ source: {
1727
+ task_anchor: taskAnchorPath,
1728
+ },
1729
+ };
1730
+ }
1731
+
1732
+ function resumeRunState(options) {
1733
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
1734
+ const taskAnchorPath = options.taskAnchor
1735
+ ? path.resolve(process.cwd(), options.taskAnchor)
1736
+ : null;
1737
+ const { currentRunPath, historyRunPath, state, syncCurrent } = resolveRunStatePaths(targetDir, options.runId);
1738
+ const toRole = state.pending_gate
1739
+ ? inferApprovalResumeRole(state, options)
1740
+ : (options.toRole || state.current_role || state.anchor?.stage?.current_role || state.plan?.first_handoff || null);
1741
+ const taskAnchor = loadTaskAnchor(taskAnchorPath, options.taskAnchorData || null);
1742
+ const anchor = updateAnchorForRole(state.anchor || null, taskAnchor, toRole, options.nextRole);
1743
+ const now = new Date();
1744
+ const event = buildStateEvent({
1745
+ state,
1746
+ options: { ...options, toRole, clearPendingGate: true },
1747
+ now,
1748
+ defaults: {
1749
+ status: 'running',
1750
+ eventType: 'run-resumed',
1751
+ message: `resumed run at ${toRole || 'unknown'}`,
1752
+ pendingGate: null,
1753
+ },
1754
+ });
1755
+
1756
+ const updatedState = {
1757
+ ...state,
1758
+ status: options.status || 'running',
1759
+ current_role: toRole,
1760
+ pending_input_update: false,
1761
+ pending_gate: options.clearPendingGate === false ? state.pending_gate || null : null,
1762
+ gate_context: options.clearPendingGate === false ? state.gate_context || null : null,
1763
+ incremental_update: buildIncrementalUpdateState(state, options, {
1764
+ updatedAt: now.toISOString(),
1765
+ }),
1766
+ auto_fix: buildNextAutoFixState(state, options),
1767
+ anchor,
1768
+ events: [...(Array.isArray(state.events) ? state.events : []), event],
1769
+ timestamps: {
1770
+ ...(state.timestamps || {}),
1771
+ updated_at: now.toISOString(),
1772
+ },
1773
+ };
1774
+
1775
+ const persistedState = saveUpdatedRunState({
1776
+ targetDir,
1777
+ historyRunPath,
1778
+ currentRunPath,
1779
+ syncCurrent,
1780
+ state: updatedState,
1781
+ });
1782
+
1783
+ return {
1784
+ status: 'success',
1785
+ target: targetDir,
1786
+ artifacts: {
1787
+ current_run: syncCurrent ? currentRunPath : null,
1788
+ run_history: historyRunPath,
1789
+ },
1790
+ state: persistedState,
1791
+ source: {
1792
+ task_anchor: taskAnchorPath,
1793
+ },
1794
+ };
1795
+ }
1796
+
1797
+ function restoreRunState(options) {
1798
+ if (!options.checkpoint) {
1799
+ throw new Error('Missing required argument: --checkpoint <file>');
1800
+ }
1801
+
1802
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
1803
+ const checkpointPath = path.resolve(process.cwd(), options.checkpoint);
1804
+ const checkpoint = readJsonFile(checkpointPath, 'runtime checkpoint');
1805
+
1806
+ if (checkpoint.kind !== 'runtime-checkpoint' || !checkpoint.state || checkpoint.state.kind !== 'run-state') {
1807
+ throw new Error(`Invalid runtime checkpoint: ${checkpointPath}`);
1808
+ }
1809
+
1810
+ const runId = options.runId || checkpoint.run_id || checkpoint.state.run_id || null;
1811
+ if (!runId) {
1812
+ throw new Error(`Checkpoint is missing run_id: ${checkpointPath}`);
1813
+ }
1814
+ if (checkpoint.run_id && checkpoint.run_id !== runId) {
1815
+ throw new Error(`Checkpoint run_id mismatch: expected ${runId}, got ${checkpoint.run_id}`);
1816
+ }
1817
+
1818
+ const { currentRunPath, historyRunPath } = resolveRunStatePaths(targetDir, runId);
1819
+ const currentRun = fs.existsSync(currentRunPath) ? readRunStateFile(currentRunPath) : null;
1820
+ if (currentRun && currentRun.run_id !== runId) {
1821
+ throw new Error(`Restore only supports the current active run; current run is ${currentRun.run_id}, requested ${runId}`);
1822
+ }
1823
+
1824
+ const now = new Date();
1825
+ const restoredState = {
1826
+ ...checkpoint.state,
1827
+ events: [
1828
+ ...(Array.isArray(checkpoint.state.events) ? checkpoint.state.events : []),
1829
+ {
1830
+ at: now.toISOString(),
1831
+ type: 'run-restored',
1832
+ status: checkpoint.state.status || 'running',
1833
+ from_role: checkpoint.state.current_role || null,
1834
+ to_role: checkpoint.state.current_role || null,
1835
+ pending_gate: checkpoint.state.pending_gate || null,
1836
+ message: `restored from checkpoint ${path.relative(targetDir, checkpointPath)}`,
1837
+ },
1838
+ ],
1839
+ timestamps: {
1840
+ ...(checkpoint.state.timestamps || {}),
1841
+ updated_at: now.toISOString(),
1842
+ },
1843
+ };
1844
+
1845
+ const persistedState = saveUpdatedRunState({
1846
+ targetDir,
1847
+ historyRunPath,
1848
+ currentRunPath,
1849
+ syncCurrent: true,
1850
+ forceSyncCurrent: true,
1851
+ state: restoredState,
1852
+ });
1853
+
1854
+ return {
1855
+ status: 'success',
1856
+ target: targetDir,
1857
+ artifacts: {
1858
+ current_run: currentRunPath,
1859
+ run_history: historyRunPath,
1860
+ checkpoint: checkpointPath,
1861
+ },
1862
+ state: persistedState,
1863
+ source: {
1864
+ checkpoint: checkpointPath,
1865
+ },
1866
+ };
1867
+ }
1868
+
1869
+ function statusRunState(options) {
1870
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
1871
+ const { currentRunPath, historyRunPath, state, syncCurrent } = resolveRunStatePaths(targetDir, options.runId);
1872
+ const events = Array.isArray(state.events) ? state.events : [];
1873
+ const lastEvent = events.length > 0 ? events[events.length - 1] : null;
1874
+
1875
+ return {
1876
+ status: 'success',
1877
+ target: targetDir,
1878
+ artifacts: {
1879
+ current_run: syncCurrent ? currentRunPath : null,
1880
+ run_history: historyRunPath,
1881
+ },
1882
+ summary: {
1883
+ run_id: state.run_id,
1884
+ mode: state.mode || null,
1885
+ delivery_profile: state.delivery_profile || null,
1886
+ artifact_profile: state.artifact_profile || null,
1887
+ complexity: state.complexity || state.task?.complexity || null,
1888
+ status: state.status || null,
1889
+ flow_id: state.flow?.id || null,
1890
+ current_role: state.current_role || null,
1891
+ pending_input_update: Boolean(state.pending_input_update),
1892
+ input_update_count: Array.isArray(state.input_updates) ? state.input_updates.length : 0,
1893
+ pending_gate: state.pending_gate || null,
1894
+ gate_context: state.gate_context || null,
1895
+ incremental_update: state.incremental_update || null,
1896
+ auto_fix: normalizeAutoFixState(state.auto_fix),
1897
+ checkpoint_count: Number(state.checkpoint_count) || 0,
1898
+ last_checkpoint: state.last_checkpoint || null,
1899
+ updated_at: state.timestamps?.updated_at || null,
1900
+ last_event: lastEvent,
1901
+ },
1902
+ state,
1903
+ };
1904
+ }
1905
+
1906
+ function gateBlockedRunState(options) {
1907
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
1908
+ const taskAnchorPath = options.taskAnchor
1909
+ ? path.resolve(process.cwd(), options.taskAnchor)
1910
+ : null;
1911
+ const { currentRunPath, historyRunPath, state, syncCurrent } = resolveRunStatePaths(targetDir, options.runId);
1912
+ const requestedGate = options.gate || options.pendingGate || state.pending_gate || null;
1913
+ const nextStatus = options.status || (requestedGate ? 'waiting-approval' : 'blocked');
1914
+ const taskAnchor = loadTaskAnchor(taskAnchorPath, options.taskAnchorData || null);
1915
+ const toRole = options.toRole || state.current_role || null;
1916
+ const anchor = updateAnchorForRole(state.anchor || null, taskAnchor, toRole, options.nextRole);
1917
+ const now = new Date();
1918
+ const event = buildStateEvent({
1919
+ state,
1920
+ options: { ...options, pendingGate: requestedGate, toRole },
1921
+ now,
1922
+ defaults: {
1923
+ status: nextStatus,
1924
+ eventType: 'gate-blocked',
1925
+ message: requestedGate
1926
+ ? `waiting for ${requestedGate} approval`
1927
+ : 'run blocked',
1928
+ pendingGate: requestedGate,
1929
+ },
1930
+ });
1931
+
1932
+ const updatedState = {
1933
+ ...state,
1934
+ status: nextStatus,
1935
+ current_role: toRole,
1936
+ pending_input_update: false,
1937
+ pending_gate: requestedGate,
1938
+ gate_context: buildGateContext(state, options, requestedGate),
1939
+ incremental_update: buildIncrementalUpdateState(state, options, {
1940
+ updatedAt: now.toISOString(),
1941
+ }),
1942
+ verification: options.verificationData || state.verification || null,
1943
+ auto_fix: buildNextAutoFixState(state, options),
1944
+ anchor,
1945
+ events: [...(Array.isArray(state.events) ? state.events : []), event],
1946
+ timestamps: {
1947
+ ...(state.timestamps || {}),
1948
+ updated_at: now.toISOString(),
1949
+ },
1950
+ };
1951
+
1952
+ const persistedState = saveUpdatedRunState({
1953
+ targetDir,
1954
+ historyRunPath,
1955
+ currentRunPath,
1956
+ syncCurrent,
1957
+ state: updatedState,
1958
+ checkpointEvent: 'gate-blocked',
1959
+ });
1960
+
1961
+ return {
1962
+ status: 'success',
1963
+ target: targetDir,
1964
+ artifacts: {
1965
+ current_run: syncCurrent ? currentRunPath : null,
1966
+ run_history: historyRunPath,
1967
+ },
1968
+ state: persistedState,
1969
+ source: {
1970
+ task_anchor: taskAnchorPath,
1971
+ gate: requestedGate,
1972
+ },
1973
+ };
1974
+ }
1975
+
1976
+ function completeRunState(options) {
1977
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
1978
+ const taskAnchorPath = options.taskAnchor
1979
+ ? path.resolve(process.cwd(), options.taskAnchor)
1980
+ : null;
1981
+ const { currentRunPath, historyRunPath, state, syncCurrent } = resolveRunStatePaths(targetDir, options.runId);
1982
+ if (options.skipArtifactCheck !== true) {
1983
+ assertRequiredOpenSpecArtifacts(targetDir, state, 'complete', options.toRole || state.current_role || null);
1984
+ }
1985
+ const toRole = options.toRole || state.current_role || null;
1986
+ const taskAnchor = loadTaskAnchor(taskAnchorPath, options.taskAnchorData || null);
1987
+ const anchor = updateAnchorForRole(state.anchor || null, taskAnchor, toRole, options.nextRole);
1988
+ const nextArtifacts = options.artifactsData
1989
+ ? mergeArtifacts(
1990
+ mergeArtifacts(buildDefaultArtifacts(state.task?.change_id || state.anchor?.task?.change_id || null), inferArtifacts(state.artifacts || null)),
1991
+ inferArtifacts(options.artifactsData),
1992
+ )
1993
+ : state.artifacts;
1994
+ const now = new Date();
1995
+ const event = buildStateEvent({
1996
+ state,
1997
+ options: { ...options, toRole, clearPendingGate: true },
1998
+ now,
1999
+ defaults: {
2000
+ status: 'success',
2001
+ eventType: 'run-completed',
2002
+ message: 'run completed',
2003
+ pendingGate: null,
2004
+ },
2005
+ });
2006
+
2007
+ const updatedState = {
2008
+ ...state,
2009
+ status: options.status || 'success',
2010
+ current_role: toRole,
2011
+ pending_input_update: false,
2012
+ pending_gate: null,
2013
+ gate_context: null,
2014
+ incremental_update: buildIncrementalUpdateState(state, options, {
2015
+ updatedAt: now.toISOString(),
2016
+ }),
2017
+ artifacts: nextArtifacts,
2018
+ auto_fix: buildNextAutoFixState(state, options, { active: false }),
2019
+ anchor,
2020
+ events: [...(Array.isArray(state.events) ? state.events : []), event],
2021
+ timestamps: {
2022
+ ...(state.timestamps || {}),
2023
+ updated_at: now.toISOString(),
2024
+ finished_at: now.toISOString(),
2025
+ },
2026
+ };
2027
+
2028
+ const persistedState = saveUpdatedRunState({
2029
+ targetDir,
2030
+ historyRunPath,
2031
+ currentRunPath,
2032
+ syncCurrent,
2033
+ state: updatedState,
2034
+ checkpointEvent: 'complete',
2035
+ });
2036
+
2037
+ return {
2038
+ status: 'success',
2039
+ target: targetDir,
2040
+ artifacts: {
2041
+ current_run: syncCurrent ? currentRunPath : null,
2042
+ run_history: historyRunPath,
2043
+ },
2044
+ state: persistedState,
2045
+ source: {
2046
+ task_anchor: taskAnchorPath,
2047
+ },
2048
+ };
2049
+ }
2050
+
2051
+ function failRunState(options) {
2052
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
2053
+ const taskAnchorPath = options.taskAnchor
2054
+ ? path.resolve(process.cwd(), options.taskAnchor)
2055
+ : null;
2056
+ const { currentRunPath, historyRunPath, state, syncCurrent } = resolveRunStatePaths(targetDir, options.runId);
2057
+ const toRole = options.toRole || state.current_role || null;
2058
+ const taskAnchor = loadTaskAnchor(taskAnchorPath, options.taskAnchorData || null);
2059
+ const anchor = updateAnchorForRole(state.anchor || null, taskAnchor, toRole, options.nextRole);
2060
+ const now = new Date();
2061
+ const errorMessage = options.error || options.message || 'run failed';
2062
+ const event = buildStateEvent({
2063
+ state,
2064
+ options: { ...options, toRole, clearPendingGate: true, message: errorMessage },
2065
+ now,
2066
+ defaults: {
2067
+ status: 'failed',
2068
+ eventType: 'run-failed',
2069
+ message: errorMessage,
2070
+ pendingGate: null,
2071
+ },
2072
+ });
2073
+
2074
+ const updatedErrors = [...(Array.isArray(state.errors) ? state.errors : [])];
2075
+ if (errorMessage) {
2076
+ updatedErrors.push(errorMessage);
2077
+ }
2078
+
2079
+ const updatedState = {
2080
+ ...state,
2081
+ status: options.status || 'failed',
2082
+ current_role: toRole,
2083
+ pending_input_update: false,
2084
+ pending_gate: null,
2085
+ gate_context: null,
2086
+ incremental_update: buildIncrementalUpdateState(state, options, {
2087
+ updatedAt: now.toISOString(),
2088
+ }),
2089
+ auto_fix: buildNextAutoFixState(state, options, { active: false }),
2090
+ anchor,
2091
+ errors: updatedErrors,
2092
+ events: [...(Array.isArray(state.events) ? state.events : []), event],
2093
+ timestamps: {
2094
+ ...(state.timestamps || {}),
2095
+ updated_at: now.toISOString(),
2096
+ finished_at: now.toISOString(),
2097
+ },
2098
+ };
2099
+
2100
+ const persistedState = saveUpdatedRunState({
2101
+ targetDir,
2102
+ historyRunPath,
2103
+ currentRunPath,
2104
+ syncCurrent,
2105
+ state: updatedState,
2106
+ checkpointEvent: 'fail',
2107
+ });
2108
+
2109
+ return {
2110
+ status: 'success',
2111
+ target: targetDir,
2112
+ artifacts: {
2113
+ current_run: syncCurrent ? currentRunPath : null,
2114
+ run_history: historyRunPath,
2115
+ },
2116
+ state: persistedState,
2117
+ source: {
2118
+ task_anchor: taskAnchorPath,
2119
+ error: options.error || null,
2120
+ },
2121
+ };
2122
+ }
2123
+
2124
+ function cancelRunState(options) {
2125
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
2126
+ const taskAnchorPath = options.taskAnchor
2127
+ ? path.resolve(process.cwd(), options.taskAnchor)
2128
+ : null;
2129
+ const { currentRunPath, historyRunPath, state, syncCurrent } = resolveRunStatePaths(targetDir, options.runId);
2130
+ const toRole = options.toRole || state.current_role || null;
2131
+ const taskAnchor = loadTaskAnchor(taskAnchorPath, options.taskAnchorData || null);
2132
+ const anchor = updateAnchorForRole(state.anchor || null, taskAnchor, toRole, options.nextRole);
2133
+ const now = new Date();
2134
+ const cancelMessage = options.message || 'run cancelled';
2135
+ const event = buildStateEvent({
2136
+ state,
2137
+ options: { ...options, toRole, clearPendingGate: true, message: cancelMessage },
2138
+ now,
2139
+ defaults: {
2140
+ status: 'cancelled',
2141
+ eventType: 'run-cancelled',
2142
+ message: cancelMessage,
2143
+ pendingGate: null,
2144
+ },
2145
+ });
2146
+
2147
+ const updatedState = {
2148
+ ...state,
2149
+ status: options.status || 'cancelled',
2150
+ current_role: toRole,
2151
+ pending_input_update: false,
2152
+ pending_gate: null,
2153
+ gate_context: null,
2154
+ incremental_update: buildIncrementalUpdateState(state, options, {
2155
+ updatedAt: now.toISOString(),
2156
+ }),
2157
+ auto_fix: buildNextAutoFixState(state, options, { active: false }),
2158
+ anchor,
2159
+ events: [...(Array.isArray(state.events) ? state.events : []), event],
2160
+ timestamps: {
2161
+ ...(state.timestamps || {}),
2162
+ updated_at: now.toISOString(),
2163
+ finished_at: now.toISOString(),
2164
+ },
2165
+ };
2166
+
2167
+ const persistedState = saveUpdatedRunState({
2168
+ targetDir,
2169
+ historyRunPath,
2170
+ currentRunPath,
2171
+ syncCurrent,
2172
+ state: updatedState,
2173
+ checkpointEvent: 'cancel',
2174
+ });
2175
+
2176
+ return {
2177
+ status: 'success',
2178
+ target: targetDir,
2179
+ artifacts: {
2180
+ current_run: syncCurrent ? currentRunPath : null,
2181
+ run_history: historyRunPath,
2182
+ },
2183
+ state: persistedState,
2184
+ source: {
2185
+ task_anchor: taskAnchorPath,
2186
+ },
2187
+ };
2188
+ }
2189
+
2190
+ function initRunState(options) {
2191
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
2192
+ const runPlanPath = path.resolve(process.cwd(), options.runPlan);
2193
+ const taskAnchorPath = options.taskAnchor
2194
+ ? path.resolve(process.cwd(), options.taskAnchor)
2195
+ : null;
2196
+
2197
+ const runPlan = readJsonFile(runPlanPath, 'run-plan');
2198
+ assertRunPlan(runPlan, runPlanPath);
2199
+
2200
+ const taskAnchor = taskAnchorPath
2201
+ ? readJsonFile(taskAnchorPath, 'task-anchor')
2202
+ : null;
2203
+
2204
+ return writeRunState({
2205
+ targetDir,
2206
+ runPlan,
2207
+ taskAnchor,
2208
+ options,
2209
+ source: {
2210
+ runPlan: runPlanPath,
2211
+ taskAnchor: taskAnchorPath,
2212
+ bootstrapPayload: null,
2213
+ },
2214
+ });
2215
+ }
2216
+
2217
+ function bootstrapRunState(options) {
2218
+ const targetDir = path.resolve(process.cwd(), options.target || '.');
2219
+ const inputCount = [
2220
+ Boolean(options.payload),
2221
+ Boolean(options.stdin),
2222
+ Boolean(options.payloadData),
2223
+ ].filter(Boolean).length;
2224
+ const hasInput = inputCount > 0;
2225
+
2226
+ if (!hasInput) {
2227
+ throw new Error('Missing bootstrap input: use --payload <file> or --stdin');
2228
+ }
2229
+ if (inputCount > 1) {
2230
+ throw new Error('Use only one bootstrap input: --payload <file>, --stdin, or payloadData');
2231
+ }
2232
+
2233
+ const payloadSource = options.payloadData
2234
+ ? 'memory-payload'
2235
+ : options.payload
2236
+ ? path.resolve(process.cwd(), options.payload)
2237
+ : 'stdin';
2238
+ const payload = options.payloadData
2239
+ ? options.payloadData
2240
+ : options.payload
2241
+ ? readJsonFile(payloadSource, 'bootstrap payload')
2242
+ : readJsonFromStdin('bootstrap payload');
2243
+
2244
+ const { runPlan, taskAnchor } = normalizeBootstrapPayload(payload, payloadSource);
2245
+ assertRunPlan(runPlan, payloadSource);
2246
+
2247
+ return writeRunState({
2248
+ targetDir,
2249
+ runPlan,
2250
+ taskAnchor,
2251
+ options,
2252
+ source: {
2253
+ runPlan: payloadSource,
2254
+ taskAnchor: payloadSource,
2255
+ bootstrapPayload: payloadSource,
2256
+ },
2257
+ });
2258
+ }
2259
+
2260
+ function printPretty(result, action = 'init') {
2261
+ if (action === 'handoff') {
2262
+ console.log('run-state updated');
2263
+ } else if (action === 'approve') {
2264
+ console.log('run-state approved');
2265
+ } else if (action === 'resume') {
2266
+ console.log('run-state resumed');
2267
+ } else if (action === 'pause') {
2268
+ console.log('run-state paused');
2269
+ } else if (action === 'restore') {
2270
+ console.log('run-state restored');
2271
+ } else if (action === 'gate-blocked') {
2272
+ console.log('run-state blocked');
2273
+ } else if (action === 'status') {
2274
+ console.log('run-state status');
2275
+ } else if (action === 'complete') {
2276
+ console.log('run-state completed');
2277
+ } else if (action === 'fail') {
2278
+ console.log('run-state failed');
2279
+ } else if (action === 'cancel') {
2280
+ console.log('run-state cancelled');
2281
+ } else {
2282
+ console.log('run-state initialized');
2283
+ }
2284
+ console.log(` target: ${result.target}`);
2285
+ console.log(` run_id: ${result.state.run_id}`);
2286
+ console.log(` current: ${result.artifacts.current_run}`);
2287
+ if (result.artifacts.run_history) {
2288
+ console.log(` history: ${result.artifacts.run_history}`);
2289
+ }
2290
+ console.log(` mode: ${result.state.mode || 'n/a'}`);
2291
+ console.log(` review_policy: ${result.state.review_policy || 'n/a'}`);
2292
+ console.log(` delivery_profile: ${result.state.delivery_profile || 'n/a'}`);
2293
+ console.log(` artifact_profile: ${result.state.artifact_profile || 'n/a'}`);
2294
+ console.log(` complexity: ${result.state.complexity || result.state.task?.complexity || 'n/a'}`);
2295
+ console.log(` checkpoints: ${Number(result.state.checkpoint_count) || 0}`);
2296
+ if (result.state.last_checkpoint?.file) {
2297
+ console.log(` last_checkpoint: ${result.state.last_checkpoint.file}`);
2298
+ }
2299
+ if (action === 'status') {
2300
+ console.log(` status: ${result.state.status || 'n/a'}`);
2301
+ console.log(` current_role: ${result.state.current_role || 'n/a'}`);
2302
+ console.log(` pending_gate: ${result.state.pending_gate || 'n/a'}`);
2303
+ if (result.state.gate_context?.required_user_action) {
2304
+ console.log(` required_user_action: ${result.state.gate_context.required_user_action}`);
2305
+ }
2306
+ } else if (action === 'handoff') {
2307
+ console.log(` current_role: ${result.state.current_role || 'n/a'}`);
2308
+ console.log(` from_role: ${result.handoff?.from_role || 'n/a'}`);
2309
+ console.log(` to_role: ${result.handoff?.to_role || 'n/a'}`);
2310
+ } else if (
2311
+ action === 'pause' ||
2312
+ action === 'approve' ||
2313
+ action === 'resume' ||
2314
+ action === 'restore' ||
2315
+ action === 'gate-blocked' ||
2316
+ action === 'complete' ||
2317
+ action === 'fail'
2318
+ ) {
2319
+ console.log(` status: ${result.state.status || 'n/a'}`);
2320
+ console.log(` current_role: ${result.state.current_role || 'n/a'}`);
2321
+ console.log(` pending_gate: ${result.state.pending_gate || 'n/a'}`);
2322
+ } else {
2323
+ console.log(` first_handoff: ${result.state.plan.first_handoff || 'n/a'}`);
2324
+ }
2325
+ if (result.source.bootstrap_payload) {
2326
+ console.log(` bootstrap_payload: ${result.source.bootstrap_payload}`);
2327
+ }
2328
+ }
2329
+
2330
+ function main(argv = process.argv.slice(2)) {
2331
+ const { command, options } = parseArgs(argv);
2332
+
2333
+ if (!command || options.help || command === '--help' || command === '-h' || command === 'help') {
2334
+ printUsage();
2335
+ return 0;
2336
+ }
2337
+
2338
+ if (command === 'init') {
2339
+ if (!options.runPlan) {
2340
+ throw new Error('Missing required argument: --run-plan <file>');
2341
+ }
2342
+
2343
+ const result = initRunState(options);
2344
+
2345
+ if (options.json) {
2346
+ console.log(JSON.stringify(result, null, 2));
2347
+ } else {
2348
+ printPretty(result, 'init');
2349
+ }
2350
+
2351
+ return 0;
2352
+ }
2353
+
2354
+ if (command === 'bootstrap') {
2355
+ const result = bootstrapRunState(options);
2356
+
2357
+ if (options.json) {
2358
+ console.log(JSON.stringify(result, null, 2));
2359
+ } else {
2360
+ printPretty(result, 'bootstrap');
2361
+ }
2362
+
2363
+ return 0;
2364
+ }
2365
+
2366
+ if (command === 'handoff') {
2367
+ const result = handoffRunState(options);
2368
+
2369
+ if (options.json) {
2370
+ console.log(JSON.stringify(result, null, 2));
2371
+ } else {
2372
+ printPretty(result, 'handoff');
2373
+ }
2374
+
2375
+ return 0;
2376
+ }
2377
+
2378
+ if (command === 'approve') {
2379
+ const result = approveRunState(options);
2380
+
2381
+ if (options.json) {
2382
+ console.log(JSON.stringify(result, null, 2));
2383
+ } else {
2384
+ printPretty(result, 'approve');
2385
+ }
2386
+
2387
+ return 0;
2388
+ }
2389
+
2390
+ if (command === 'pause') {
2391
+ const result = pauseRunState(options);
2392
+
2393
+ if (options.json) {
2394
+ console.log(JSON.stringify(result, null, 2));
2395
+ } else {
2396
+ printPretty(result, 'pause');
2397
+ }
2398
+
2399
+ return 0;
2400
+ }
2401
+
2402
+ if (command === 'resume') {
2403
+ const result = resumeRunState(options);
2404
+
2405
+ if (options.json) {
2406
+ console.log(JSON.stringify(result, null, 2));
2407
+ } else {
2408
+ printPretty(result, 'resume');
2409
+ }
2410
+
2411
+ return 0;
2412
+ }
2413
+
2414
+ if (command === 'restore') {
2415
+ const result = restoreRunState(options);
2416
+
2417
+ if (options.json) {
2418
+ console.log(JSON.stringify(result, null, 2));
2419
+ } else {
2420
+ printPretty(result, 'restore');
2421
+ }
2422
+
2423
+ return 0;
2424
+ }
2425
+
2426
+ if (command === 'gate-blocked') {
2427
+ const result = gateBlockedRunState(options);
2428
+
2429
+ if (options.json) {
2430
+ console.log(JSON.stringify(result, null, 2));
2431
+ } else {
2432
+ printPretty(result, 'gate-blocked');
2433
+ }
2434
+
2435
+ return 0;
2436
+ }
2437
+
2438
+ if (command === 'status') {
2439
+ const result = statusRunState(options);
2440
+
2441
+ if (options.json) {
2442
+ console.log(JSON.stringify(result, null, 2));
2443
+ } else {
2444
+ printPretty(result, 'status');
2445
+ }
2446
+
2447
+ return 0;
2448
+ }
2449
+
2450
+ if (command === 'complete') {
2451
+ const result = completeRunState(options);
2452
+
2453
+ if (options.json) {
2454
+ console.log(JSON.stringify(result, null, 2));
2455
+ } else {
2456
+ printPretty(result, 'complete');
2457
+ }
2458
+
2459
+ return 0;
2460
+ }
2461
+
2462
+ if (command === 'fail') {
2463
+ const result = failRunState(options);
2464
+
2465
+ if (options.json) {
2466
+ console.log(JSON.stringify(result, null, 2));
2467
+ } else {
2468
+ printPretty(result, 'fail');
2469
+ }
2470
+
2471
+ return 0;
2472
+ }
2473
+
2474
+ if (command === 'cancel') {
2475
+ const result = cancelRunState(options);
2476
+
2477
+ if (options.json) {
2478
+ console.log(JSON.stringify(result, null, 2));
2479
+ } else {
2480
+ printPretty(result, 'cancel');
2481
+ }
2482
+
2483
+ return 0;
2484
+ }
2485
+
2486
+ if (
2487
+ command !== 'init' &&
2488
+ command !== 'bootstrap' &&
2489
+ command !== 'handoff' &&
2490
+ command !== 'approve' &&
2491
+ command !== 'pause' &&
2492
+ command !== 'resume' &&
2493
+ command !== 'restore' &&
2494
+ command !== 'gate-blocked' &&
2495
+ command !== 'status' &&
2496
+ command !== 'complete' &&
2497
+ command !== 'fail' &&
2498
+ command !== 'cancel'
2499
+ ) {
2500
+ throw new Error(`Unsupported runtime-state command: ${command}`);
2501
+ }
2502
+ }
2503
+
2504
+ if (require.main === module) {
2505
+ try {
2506
+ const exitCode = main();
2507
+ process.exit(exitCode);
2508
+ } catch (error) {
2509
+ console.error(`runtime-state error: ${error.message}`);
2510
+ process.exit(1);
2511
+ }
2512
+ }
2513
+
2514
+ module.exports = {
2515
+ main,
2516
+ parseArgs,
2517
+ createRunId,
2518
+ normalizeSpecsArtifactPath,
2519
+ inferDeliveryProfile,
2520
+ inferArtifactProfile,
2521
+ inferComplexity,
2522
+ inferRiskLevel,
2523
+ inferArtifacts,
2524
+ buildRunState,
2525
+ recordRunInputUpdate,
2526
+ readRunStateFile,
2527
+ resolveRunStatePaths,
2528
+ initRunState,
2529
+ bootstrapRunState,
2530
+ normalizeBootstrapPayload,
2531
+ handoffRunState,
2532
+ approveRunState,
2533
+ pauseRunState,
2534
+ resumeRunState,
2535
+ restoreRunState,
2536
+ gateBlockedRunState,
2537
+ statusRunState,
2538
+ completeRunState,
2539
+ failRunState,
2540
+ cancelRunState,
2541
+ };