@jaimevalasek/aioson 1.7.2 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (362) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +153 -10
  3. package/docs/en/cli-reference.md +56 -1
  4. package/docs/en/i18n.md +18 -18
  5. package/docs/en/schemas/index.json +10 -0
  6. package/docs/en/schemas/parallel-assign.schema.json +9 -0
  7. package/docs/en/schemas/parallel-doctor.schema.json +36 -0
  8. package/docs/en/schemas/parallel-guard.schema.json +63 -0
  9. package/docs/en/schemas/parallel-merge.schema.json +84 -0
  10. package/docs/en/schemas/parallel-status.schema.json +91 -1
  11. package/docs/integrations/apps-publish-marketplace.md +94 -0
  12. package/docs/pt/README.md +9 -0
  13. package/docs/pt/agentes.md +324 -3
  14. package/docs/pt/clientes-ai.md +7 -3
  15. package/docs/pt/comandos-cli.md +160 -13
  16. package/docs/pt/compress-agents.md +304 -0
  17. package/docs/pt/design-docs-governance.md +59 -0
  18. package/docs/pt/feature-archive.md +191 -0
  19. package/docs/pt/genome-3.0-spec.md +115 -4
  20. package/docs/pt/genome-distribution.md +232 -0
  21. package/docs/pt/inicio-rapido.md +1 -0
  22. package/docs/pt/motor-hardening.md +492 -0
  23. package/docs/pt/runner-system.md +113 -0
  24. package/package.json +2 -1
  25. package/src/agent-manifests.js +66 -0
  26. package/src/agents.js +27 -7
  27. package/src/autonomy-policy.js +139 -0
  28. package/src/brain-query.js +161 -0
  29. package/src/cli.js +1377 -1099
  30. package/src/commands/agents.js +102 -7
  31. package/src/commands/artifact-validate.js +33 -4
  32. package/src/commands/auth.js +272 -0
  33. package/src/commands/brain-query.js +44 -0
  34. package/src/commands/briefing.js +344 -0
  35. package/src/commands/commit-prepare.js +547 -0
  36. package/src/commands/compress-agents.js +416 -0
  37. package/src/commands/context-health.js +4 -2
  38. package/src/commands/context-trim.js +17 -11
  39. package/src/commands/design-hybrid-options.js +3 -3
  40. package/src/commands/devlog-process.js +6 -4
  41. package/src/commands/dossier.js +423 -0
  42. package/src/commands/feature-archive.js +513 -0
  43. package/src/commands/feature-close.js +123 -18
  44. package/src/commands/gate-approve.js +198 -0
  45. package/src/commands/gate-check.js +24 -5
  46. package/src/commands/genome-doctor.js +166 -9
  47. package/src/commands/git-guard.js +170 -0
  48. package/src/commands/harness.js +121 -0
  49. package/src/commands/implementation-plan.js +47 -20
  50. package/src/commands/init.js +6 -2
  51. package/src/commands/install.js +6 -2
  52. package/src/commands/live.js +497 -56
  53. package/src/commands/locale-apply.js +9 -6
  54. package/src/commands/locale-diff.js +11 -112
  55. package/src/commands/mcp-doctor.js +2 -1
  56. package/src/commands/mcp-init.js +4 -10
  57. package/src/commands/memory.js +234 -0
  58. package/src/commands/parallel-assign.js +107 -27
  59. package/src/commands/parallel-doctor.js +416 -3
  60. package/src/commands/parallel-guard.js +241 -0
  61. package/src/commands/parallel-init.js +66 -4
  62. package/src/commands/parallel-merge.js +299 -0
  63. package/src/commands/parallel-status.js +147 -3
  64. package/src/commands/preflight.js +63 -4
  65. package/src/commands/qa-init.js +10 -5
  66. package/src/commands/revision.js +235 -0
  67. package/src/commands/scaffold-complete.js +188 -0
  68. package/src/commands/security-audit.js +275 -0
  69. package/src/commands/security-scan.js +376 -0
  70. package/src/commands/self-implement-loop.js +46 -2
  71. package/src/commands/setup-context.js +11 -10
  72. package/src/commands/squad-agent-create.js +51 -9
  73. package/src/commands/squad-investigate.js +53 -0
  74. package/src/commands/squad-plan.js +33 -1
  75. package/src/commands/squad-scaffold.js +4 -3
  76. package/src/commands/squad-score.js +71 -14
  77. package/src/commands/squad-status.js +22 -1
  78. package/src/commands/squad-validate.js +93 -2
  79. package/src/commands/store-genome.js +304 -0
  80. package/src/commands/store-skill.js +247 -0
  81. package/src/commands/store-squad.js +431 -0
  82. package/src/commands/store-system.js +392 -0
  83. package/src/commands/tool-capabilities.js +63 -0
  84. package/src/commands/update.js +3 -3
  85. package/src/commands/verify-gate.js +40 -0
  86. package/src/commands/workflow-execute.js +644 -155
  87. package/src/commands/workflow-harden.js +231 -0
  88. package/src/commands/workflow-heal.js +136 -0
  89. package/src/commands/workflow-next.js +460 -22
  90. package/src/commands/workflow-status.js +328 -138
  91. package/src/commands/workspace.js +144 -0
  92. package/src/constants.js +42 -75
  93. package/src/context-memory.js +133 -4
  94. package/src/context-writer.js +2 -1
  95. package/src/context.js +32 -2
  96. package/src/doctor.js +46 -6
  97. package/src/dossier/codemap-store.js +267 -0
  98. package/src/dossier/dossier-bootstrap.js +222 -0
  99. package/src/dossier/dossier-compact.js +159 -0
  100. package/src/dossier/lock.js +128 -0
  101. package/src/dossier/revision-store.js +313 -0
  102. package/src/dossier/schema.js +155 -0
  103. package/src/dossier/store.js +400 -0
  104. package/src/execution-gateway.js +3 -0
  105. package/src/friction-scanner.js +202 -0
  106. package/src/genome-schema.js +24 -1
  107. package/src/genomes.js +33 -0
  108. package/src/handoff-contract.js +363 -0
  109. package/src/handoff-validator.js +45 -0
  110. package/src/harness/circuit-breaker.js +135 -0
  111. package/src/i18n/messages/en.js +317 -22
  112. package/src/i18n/messages/es.js +259 -18
  113. package/src/i18n/messages/fr.js +260 -18
  114. package/src/i18n/messages/pt-BR.js +313 -22
  115. package/src/install-profile.js +0 -16
  116. package/src/installer.js +70 -6
  117. package/src/lib/git-commit-guard.js +691 -0
  118. package/src/lib/security/artifact-reader.js +167 -0
  119. package/src/lib/security/exit-codes.js +51 -0
  120. package/src/lib/security/findings-writer.js +176 -0
  121. package/src/lib/security/runtime-events.js +77 -0
  122. package/src/lib/security/secrets-regex.js +115 -0
  123. package/src/lib/store/security-scan.js +173 -0
  124. package/src/lib/terminal-checkbox.js +130 -0
  125. package/src/lib/tmux-launcher.js +163 -0
  126. package/src/lib/tool-capabilities.js +102 -0
  127. package/src/locales.js +12 -8
  128. package/src/parallel-workspace.js +756 -0
  129. package/src/parser.js +8 -1
  130. package/src/path-guard.js +47 -0
  131. package/src/preflight-engine.js +237 -26
  132. package/src/self-healing.js +142 -0
  133. package/src/session-handoff.js +111 -1
  134. package/src/squad/squad-scaffold.js +183 -19
  135. package/src/test-briefing.js +226 -0
  136. package/src/updater.js +1 -1
  137. package/src/utils.js +3 -0
  138. package/src/workflow-gates.js +185 -0
  139. package/template/.aioson/agents/analyst.md +76 -130
  140. package/template/.aioson/agents/architect.md +53 -86
  141. package/template/.aioson/agents/committer.md +161 -0
  142. package/template/.aioson/agents/cypher.md +252 -0
  143. package/template/.aioson/agents/dev.md +112 -628
  144. package/template/.aioson/agents/deyvin.md +33 -236
  145. package/template/.aioson/agents/discover.md +235 -0
  146. package/template/.aioson/agents/discovery-design-doc.md +17 -252
  147. package/template/.aioson/agents/genome.md +76 -26
  148. package/template/.aioson/agents/manifests/analyst.manifest.json +26 -0
  149. package/template/.aioson/agents/manifests/architect.manifest.json +23 -0
  150. package/template/.aioson/agents/manifests/committer.manifest.json +23 -0
  151. package/template/.aioson/agents/manifests/dev.manifest.json +37 -0
  152. package/template/.aioson/agents/manifests/orchestrator.manifest.json +30 -0
  153. package/template/.aioson/agents/manifests/pentester.manifest.json +39 -0
  154. package/template/.aioson/agents/manifests/pm.manifest.json +26 -0
  155. package/template/.aioson/agents/manifests/product.manifest.json +23 -0
  156. package/template/.aioson/agents/manifests/qa.manifest.json +25 -0
  157. package/template/.aioson/agents/manifests/setup.manifest.json +20 -0
  158. package/template/.aioson/agents/manifests/ux-ui.manifest.json +24 -0
  159. package/template/.aioson/agents/neo.md +5 -7
  160. package/template/.aioson/agents/orache.md +2 -6
  161. package/template/.aioson/agents/orchestrator.md +81 -182
  162. package/template/.aioson/agents/pentester.md +235 -0
  163. package/template/.aioson/agents/pm.md +40 -104
  164. package/template/.aioson/agents/product.md +99 -344
  165. package/template/.aioson/agents/profiler-enricher.md +57 -6
  166. package/template/.aioson/agents/profiler-forge.md +17 -7
  167. package/template/.aioson/agents/profiler-researcher.md +29 -6
  168. package/template/.aioson/agents/qa.md +168 -514
  169. package/template/.aioson/agents/setup.md +52 -278
  170. package/template/.aioson/agents/sheldon.md +122 -754
  171. package/template/.aioson/agents/site-forge.md +111 -1583
  172. package/template/.aioson/agents/squad.md +139 -2010
  173. package/template/.aioson/agents/tester.md +10 -0
  174. package/template/.aioson/agents/ux-ui.md +104 -812
  175. package/template/.aioson/agents/validator.md +69 -0
  176. package/template/.aioson/brains/scripts/query.js +5 -1
  177. package/template/.aioson/config/autonomy-protocol.json +43 -0
  178. package/template/.aioson/config.md +43 -15
  179. package/template/.aioson/constitution.md +36 -33
  180. package/template/.aioson/context/design-doc.md +136 -0
  181. package/template/.aioson/context/project-map.md +57 -0
  182. package/template/.aioson/design-docs/code-reuse.md +48 -0
  183. package/template/.aioson/design-docs/componentization.md +47 -0
  184. package/template/.aioson/design-docs/file-size.md +52 -0
  185. package/template/.aioson/design-docs/folder-structure.md +51 -0
  186. package/template/.aioson/design-docs/naming.md +54 -0
  187. package/template/.aioson/docs/LAYERS.md +12 -2
  188. package/template/.aioson/docs/dev/execution-discipline.md +106 -0
  189. package/template/.aioson/docs/dev/stack-conventions.md +83 -0
  190. package/template/.aioson/docs/deyvin/continuity-recovery.md +57 -0
  191. package/template/.aioson/docs/deyvin/debugging-escalation.md +30 -0
  192. package/template/.aioson/docs/deyvin/pair-execution.md +44 -0
  193. package/template/.aioson/docs/deyvin/runtime-handoffs.md +36 -0
  194. package/template/.aioson/docs/product/conversation-playbook.md +116 -0
  195. package/template/.aioson/docs/product/prd-contract.md +107 -0
  196. package/template/.aioson/docs/product/quality-lens.md +57 -0
  197. package/template/.aioson/docs/product/research-loop.md +65 -0
  198. package/template/.aioson/docs/sheldon/enrichment-paths.md +134 -0
  199. package/template/.aioson/docs/sheldon/quality-lens.md +57 -0
  200. package/template/.aioson/docs/sheldon/research-loop.md +56 -0
  201. package/template/.aioson/docs/sheldon/web-intelligence.md +75 -0
  202. package/template/.aioson/docs/site-forge-build.md +195 -0
  203. package/template/.aioson/docs/site-forge-extraction.md +135 -0
  204. package/template/.aioson/docs/site-forge-qa.md +155 -0
  205. package/template/.aioson/docs/site-forge-recon.md +434 -0
  206. package/template/.aioson/docs/site-forge-transform.md +249 -0
  207. package/template/.aioson/docs/squad/content-output.md +91 -0
  208. package/template/.aioson/docs/squad/creation-flow.md +135 -0
  209. package/template/.aioson/docs/squad/domain-classification.md +117 -0
  210. package/template/.aioson/docs/squad/genome-bindings.md +47 -0
  211. package/template/.aioson/docs/squad/package-contract.md +234 -0
  212. package/template/.aioson/docs/squad/quality-lens.md +56 -0
  213. package/template/.aioson/docs/squad/research-loop.md +59 -0
  214. package/template/.aioson/docs/squad/session-operations.md +117 -0
  215. package/template/.aioson/docs/squad/workflow-quality.md +165 -0
  216. package/template/.aioson/docs/ux-ui/accessibility-audit.md +55 -0
  217. package/template/.aioson/docs/ux-ui/audit-mode.md +86 -0
  218. package/template/.aioson/docs/ux-ui/component-map.md +35 -0
  219. package/template/.aioson/docs/ux-ui/design-execution.md +111 -0
  220. package/template/.aioson/docs/ux-ui/design-gate.md +27 -0
  221. package/template/.aioson/docs/ux-ui/research-mode.md +39 -0
  222. package/template/.aioson/docs/ux-ui/site-delivery.md +156 -0
  223. package/template/.aioson/docs/ux-ui/token-contract.md +57 -0
  224. package/template/.aioson/genomes/copywriting.meta.json +48 -0
  225. package/template/.aioson/git-guard.json +11 -0
  226. package/template/.aioson/mcp/servers.md +0 -1
  227. package/template/.aioson/rules/agent-language-policy.md +93 -0
  228. package/template/.aioson/rules/aioson-context-boundary.md +63 -0
  229. package/template/.aioson/rules/canonical-path-contract.md +47 -0
  230. package/template/.aioson/rules/data-format-convention.md +24 -86
  231. package/template/.aioson/rules/disk-first-artifacts.md +44 -0
  232. package/template/.aioson/rules/output-brevity.md +44 -0
  233. package/template/.aioson/rules/prd-section-ownership.md +49 -0
  234. package/template/.aioson/rules/security-baseline.md +139 -0
  235. package/template/.aioson/rules/spec-level-ownership.md +61 -0
  236. package/template/.aioson/rules/squad-driver-pattern.md +81 -0
  237. package/template/.aioson/schemas/squad-blueprint.schema.json +24 -0
  238. package/template/.aioson/schemas/squad-manifest.schema.json +44 -0
  239. package/template/.aioson/skills/process/aioson-spec-driven/references/pm.md +30 -0
  240. package/template/.aioson/skills/process/secure-tdd/SKILL.md +97 -0
  241. package/template/.aioson/skills/process/secure-tdd/references/nextjs.md +81 -0
  242. package/template/.aioson/skills/process/secure-tdd/references/node-express.md +91 -0
  243. package/template/.aioson/skills/process/secure-tdd/references/planned-stacks.md +33 -0
  244. package/template/.aioson/skills/static/harness-validate/SKILL.md +46 -0
  245. package/template/.aioson/skills/static/web-research-cache.md +3 -0
  246. package/template/.aioson/tasks/squad-create.md +35 -8
  247. package/template/.aioson/tasks/squad-design.md +50 -2
  248. package/template/.aioson/tasks/squad-investigate.md +14 -1
  249. package/template/.claude/commands/aioson/agent/committer.md +5 -0
  250. package/template/.claude/commands/aioson/agent/copywriter.md +5 -0
  251. package/template/.claude/commands/aioson/agent/cypher.md +5 -0
  252. package/template/.claude/commands/aioson/agent/pair.md +5 -0
  253. package/template/.claude/commands/aioson/agent/validator.md +5 -0
  254. package/template/.gemini/commands/aios-analyst.toml +6 -3
  255. package/template/.gemini/commands/aios-architect.toml +7 -6
  256. package/template/.gemini/commands/aios-committer.toml +7 -0
  257. package/template/.gemini/commands/aios-copywriter.toml +7 -0
  258. package/template/.gemini/commands/aios-cypher.toml +7 -0
  259. package/template/.gemini/commands/aios-dev.toml +8 -7
  260. package/template/.gemini/commands/aios-deyvin.toml +6 -5
  261. package/template/.gemini/commands/aios-discovery-design-doc.toml +6 -3
  262. package/template/.gemini/commands/aios-genome.toml +7 -0
  263. package/template/.gemini/commands/aios-neo.toml +5 -3
  264. package/template/.gemini/commands/aios-orache.toml +7 -0
  265. package/template/.gemini/commands/aios-orchestrator.toml +8 -7
  266. package/template/.gemini/commands/aios-pair.toml +6 -5
  267. package/template/.gemini/commands/aios-pm.toml +8 -7
  268. package/template/.gemini/commands/aios-product.toml +5 -3
  269. package/template/.gemini/commands/aios-qa.toml +6 -5
  270. package/template/.gemini/commands/aios-setup.toml +5 -2
  271. package/template/.gemini/commands/aios-sheldon.toml +7 -0
  272. package/template/.gemini/commands/aios-site-forge.toml +7 -0
  273. package/template/.gemini/commands/aios-squad.toml +7 -0
  274. package/template/.gemini/commands/aios-tester.toml +6 -5
  275. package/template/.gemini/commands/aios-ux-ui.toml +8 -7
  276. package/template/.gemini/commands/aios-validator.toml +7 -0
  277. package/template/AGENTS.md +12 -1
  278. package/template/CLAUDE.md +5 -1
  279. package/template/.aioson/locales/en/agents/analyst.md +0 -244
  280. package/template/.aioson/locales/en/agents/architect.md +0 -245
  281. package/template/.aioson/locales/en/agents/dev.md +0 -397
  282. package/template/.aioson/locales/en/agents/deyvin.md +0 -137
  283. package/template/.aioson/locales/en/agents/discovery-design-doc.md +0 -27
  284. package/template/.aioson/locales/en/agents/genome.md +0 -212
  285. package/template/.aioson/locales/en/agents/neo.md +0 -8
  286. package/template/.aioson/locales/en/agents/orache.md +0 -6
  287. package/template/.aioson/locales/en/agents/orchestrator.md +0 -189
  288. package/template/.aioson/locales/en/agents/pair.md +0 -5
  289. package/template/.aioson/locales/en/agents/pm.md +0 -84
  290. package/template/.aioson/locales/en/agents/product.md +0 -378
  291. package/template/.aioson/locales/en/agents/profiler-enricher.md +0 -5
  292. package/template/.aioson/locales/en/agents/profiler-forge.md +0 -5
  293. package/template/.aioson/locales/en/agents/profiler-researcher.md +0 -5
  294. package/template/.aioson/locales/en/agents/qa.md +0 -270
  295. package/template/.aioson/locales/en/agents/setup.md +0 -421
  296. package/template/.aioson/locales/en/agents/sheldon.md +0 -455
  297. package/template/.aioson/locales/en/agents/squad.md +0 -449
  298. package/template/.aioson/locales/en/agents/tester.md +0 -6
  299. package/template/.aioson/locales/en/agents/ux-ui.md +0 -668
  300. package/template/.aioson/locales/es/agents/analyst.md +0 -225
  301. package/template/.aioson/locales/es/agents/architect.md +0 -245
  302. package/template/.aioson/locales/es/agents/dev.md +0 -370
  303. package/template/.aioson/locales/es/agents/deyvin.md +0 -99
  304. package/template/.aioson/locales/es/agents/discovery-design-doc.md +0 -21
  305. package/template/.aioson/locales/es/agents/genome.md +0 -104
  306. package/template/.aioson/locales/es/agents/neo.md +0 -50
  307. package/template/.aioson/locales/es/agents/orache.md +0 -105
  308. package/template/.aioson/locales/es/agents/orchestrator.md +0 -194
  309. package/template/.aioson/locales/es/agents/pair.md +0 -7
  310. package/template/.aioson/locales/es/agents/pm.md +0 -90
  311. package/template/.aioson/locales/es/agents/product.md +0 -372
  312. package/template/.aioson/locales/es/agents/profiler-enricher.md +0 -7
  313. package/template/.aioson/locales/es/agents/profiler-forge.md +0 -7
  314. package/template/.aioson/locales/es/agents/profiler-researcher.md +0 -7
  315. package/template/.aioson/locales/es/agents/qa.md +0 -198
  316. package/template/.aioson/locales/es/agents/setup.md +0 -405
  317. package/template/.aioson/locales/es/agents/sheldon.md +0 -309
  318. package/template/.aioson/locales/es/agents/squad.md +0 -532
  319. package/template/.aioson/locales/es/agents/tester.md +0 -9
  320. package/template/.aioson/locales/es/agents/ux-ui.md +0 -212
  321. package/template/.aioson/locales/fr/agents/analyst.md +0 -225
  322. package/template/.aioson/locales/fr/agents/architect.md +0 -245
  323. package/template/.aioson/locales/fr/agents/dev.md +0 -370
  324. package/template/.aioson/locales/fr/agents/deyvin.md +0 -99
  325. package/template/.aioson/locales/fr/agents/discovery-design-doc.md +0 -21
  326. package/template/.aioson/locales/fr/agents/genome.md +0 -104
  327. package/template/.aioson/locales/fr/agents/neo.md +0 -50
  328. package/template/.aioson/locales/fr/agents/orache.md +0 -106
  329. package/template/.aioson/locales/fr/agents/orchestrator.md +0 -194
  330. package/template/.aioson/locales/fr/agents/pair.md +0 -7
  331. package/template/.aioson/locales/fr/agents/pm.md +0 -90
  332. package/template/.aioson/locales/fr/agents/product.md +0 -372
  333. package/template/.aioson/locales/fr/agents/profiler-enricher.md +0 -7
  334. package/template/.aioson/locales/fr/agents/profiler-forge.md +0 -7
  335. package/template/.aioson/locales/fr/agents/profiler-researcher.md +0 -7
  336. package/template/.aioson/locales/fr/agents/qa.md +0 -198
  337. package/template/.aioson/locales/fr/agents/setup.md +0 -405
  338. package/template/.aioson/locales/fr/agents/sheldon.md +0 -309
  339. package/template/.aioson/locales/fr/agents/squad.md +0 -532
  340. package/template/.aioson/locales/fr/agents/tester.md +0 -9
  341. package/template/.aioson/locales/fr/agents/ux-ui.md +0 -212
  342. package/template/.aioson/locales/pt-BR/agents/analyst.md +0 -319
  343. package/template/.aioson/locales/pt-BR/agents/architect.md +0 -284
  344. package/template/.aioson/locales/pt-BR/agents/dev.md +0 -483
  345. package/template/.aioson/locales/pt-BR/agents/deyvin.md +0 -184
  346. package/template/.aioson/locales/pt-BR/agents/discovery-design-doc.md +0 -198
  347. package/template/.aioson/locales/pt-BR/agents/genome.md +0 -297
  348. package/template/.aioson/locales/pt-BR/agents/neo.md +0 -208
  349. package/template/.aioson/locales/pt-BR/agents/orache.md +0 -137
  350. package/template/.aioson/locales/pt-BR/agents/orchestrator.md +0 -324
  351. package/template/.aioson/locales/pt-BR/agents/pair.md +0 -5
  352. package/template/.aioson/locales/pt-BR/agents/pm.md +0 -182
  353. package/template/.aioson/locales/pt-BR/agents/product.md +0 -466
  354. package/template/.aioson/locales/pt-BR/agents/profiler-enricher.md +0 -5
  355. package/template/.aioson/locales/pt-BR/agents/profiler-forge.md +0 -5
  356. package/template/.aioson/locales/pt-BR/agents/profiler-researcher.md +0 -5
  357. package/template/.aioson/locales/pt-BR/agents/qa.md +0 -300
  358. package/template/.aioson/locales/pt-BR/agents/setup.md +0 -533
  359. package/template/.aioson/locales/pt-BR/agents/sheldon.md +0 -323
  360. package/template/.aioson/locales/pt-BR/agents/squad.md +0 -1330
  361. package/template/.aioson/locales/pt-BR/agents/tester.md +0 -449
  362. package/template/.aioson/locales/pt-BR/agents/ux-ui.md +0 -669
@@ -4,8 +4,21 @@ const fs = require('node:fs/promises');
4
4
  const path = require('node:path');
5
5
  const { exists } = require('../utils');
6
6
  const { recordRuntimeOperation } = require('../execution-gateway');
7
+ const {
8
+ WORKSPACE_MANIFEST_RELATIVE_PATH,
9
+ OWNERSHIP_MAP_RELATIVE_PATH,
10
+ MERGE_PLAN_RELATIVE_PATH,
11
+ buildLaneOwnershipEntries,
12
+ collectOwnershipConflicts,
13
+ collectWritePathConflicts,
14
+ extractStatusDependencyItems,
15
+ extractStatusMergeRank,
16
+ extractStatusWritePathItems,
17
+ buildMachineSyncReport,
18
+ collectDependencyIssues
19
+ } = require('../parallel-workspace');
7
20
 
8
- const KNOWN_STATUSES = ['pending', 'in_progress', 'completed', 'blocked'];
21
+ const KNOWN_STATUSES = ['pending', 'in_progress', 'completed', 'merged', 'blocked'];
9
22
 
10
23
  function parseLaneIndex(fileName) {
11
24
  const match = String(fileName || '').match(/^agent-(\d+)\.status\.md$/);
@@ -103,6 +116,7 @@ function createStatusCounts() {
103
116
  pending: 0,
104
117
  in_progress: 0,
105
118
  completed: 0,
119
+ merged: 0,
106
120
  blocked: 0,
107
121
  other: 0
108
122
  };
@@ -115,6 +129,7 @@ function formatStatusLabel(status, t) {
115
129
  if (normalized === 'pending') return t('parallel_status.status_pending');
116
130
  if (normalized === 'in_progress') return t('parallel_status.status_in_progress');
117
131
  if (normalized === 'completed') return t('parallel_status.status_completed');
132
+ if (normalized === 'merged') return t('parallel_status.status_merged');
118
133
  if (normalized === 'blocked') return t('parallel_status.status_blocked');
119
134
  return t('parallel_status.status_other');
120
135
  }
@@ -130,6 +145,9 @@ async function parseLaneFile(parallelDir, index) {
130
145
  const scopeItems = sanitizeScopeItems(extractSectionBullets(content, 'Scope'));
131
146
  const blockerItems = sanitizeBlockerItems(extractSectionBullets(content, 'Blockers'));
132
147
  const deliverables = parseDeliverables(content);
148
+ const dependencyItems = extractStatusDependencyItems(content);
149
+ const mergeRank = extractStatusMergeRank(content, index);
150
+ const writePathItems = extractStatusWritePathItems(content);
133
151
 
134
152
  return {
135
153
  lane: index,
@@ -139,10 +157,15 @@ async function parseLaneFile(parallelDir, index) {
139
157
  priority,
140
158
  updatedAt,
141
159
  scopeCount: scopeItems.length,
160
+ dependencyCount: dependencyItems.length,
142
161
  blockerCount: blockerItems.length,
143
162
  deliverables,
144
163
  scopeItems,
145
- blockerItems
164
+ blockerItems,
165
+ dependencyItems,
166
+ mergeRank,
167
+ writePathItems,
168
+ writePathCount: writePathItems.length
146
169
  };
147
170
  }
148
171
 
@@ -189,6 +212,57 @@ async function runParallelStatus({ args, options = {}, logger, t }) {
189
212
  const sharedDecisionEntries = sharedExists
190
213
  ? countDecisionRows(await fs.readFile(sharedPath, 'utf8'))
191
214
  : 0;
215
+ const manifestPath = path.join(targetDir, WORKSPACE_MANIFEST_RELATIVE_PATH);
216
+ const ownershipPath = path.join(targetDir, OWNERSHIP_MAP_RELATIVE_PATH);
217
+ const mergePlanPath = path.join(targetDir, MERGE_PLAN_RELATIVE_PATH);
218
+ const manifestExists = await exists(manifestPath);
219
+ const ownershipExists = await exists(ownershipPath);
220
+ const mergePlanExists = await exists(mergePlanPath);
221
+
222
+ let workspaceManifest = null;
223
+ let ownershipMap = null;
224
+ let mergePlan = null;
225
+ try {
226
+ workspaceManifest = manifestExists ? JSON.parse(await fs.readFile(manifestPath, 'utf8')) : null;
227
+ } catch {
228
+ workspaceManifest = null;
229
+ }
230
+ try {
231
+ ownershipMap = ownershipExists ? JSON.parse(await fs.readFile(ownershipPath, 'utf8')) : null;
232
+ } catch {
233
+ ownershipMap = null;
234
+ }
235
+ try {
236
+ mergePlan = mergePlanExists ? JSON.parse(await fs.readFile(mergePlanPath, 'utf8')) : null;
237
+ } catch {
238
+ mergePlan = null;
239
+ }
240
+
241
+ const ownershipConflicts = collectOwnershipConflicts(ownershipMap);
242
+ const laneEntries = buildLaneOwnershipEntries(
243
+ lanes.map((lane) => ({
244
+ lane: lane.lane,
245
+ items: lane.scopeItems,
246
+ owner: lane.owner,
247
+ dependsOn: lane.dependencyItems,
248
+ writePaths: lane.writePathItems,
249
+ mergeRank: lane.mergeRank
250
+ }))
251
+ );
252
+ const sync = buildMachineSyncReport({
253
+ laneEntries,
254
+ workspaceManifest,
255
+ ownershipMap,
256
+ mergePlan
257
+ });
258
+ const dependencies = collectDependencyIssues({
259
+ lanes,
260
+ mergeOrder: mergePlan && Array.isArray(mergePlan.order) ? mergePlan.order : []
261
+ });
262
+ const writePaths = collectWritePathConflicts(lanes);
263
+ const assignedPathLaneCount = lanes.filter((lane) => lane.writePathCount > 0).length;
264
+ const uncoveredAssignedLaneCount = lanes.filter((lane) => lane.scopeCount > 0 && lane.writePathCount === 0).length;
265
+ const totalWritePathCount = lanes.reduce((sum, lane) => sum + lane.writePathCount, 0);
192
266
 
193
267
  const output = {
194
268
  ok: true,
@@ -206,6 +280,35 @@ async function runParallelStatus({ args, options = {}, logger, t }) {
206
280
  exists: sharedExists,
207
281
  entries: sharedDecisionEntries
208
282
  },
283
+ machineFiles: {
284
+ workspaceManifest: manifestExists,
285
+ ownershipMap: ownershipExists,
286
+ mergePlan: mergePlanExists
287
+ },
288
+ ownership: {
289
+ assignedScopeCount: ownershipMap && Array.isArray(ownershipMap.lanes)
290
+ ? ownershipMap.lanes.reduce((sum, lane) => sum + (Array.isArray(lane.scope_keys) ? lane.scope_keys.length : 0), 0)
291
+ : 0,
292
+ conflictCount: ownershipConflicts.length,
293
+ conflicts: ownershipConflicts
294
+ },
295
+ writeScope: {
296
+ laneCount: assignedPathLaneCount,
297
+ totalPathCount: totalWritePathCount,
298
+ uncoveredAssignedLaneCount,
299
+ invalidPatternCount: writePaths.invalidCount,
300
+ invalidPatterns: writePaths.invalid,
301
+ conflictCount: writePaths.conflictCount,
302
+ conflicts: writePaths.conflicts
303
+ },
304
+ dependencies,
305
+ merge: {
306
+ strategy: mergePlan && mergePlan.strategy ? mergePlan.strategy : null,
307
+ order: mergePlan && Array.isArray(mergePlan.order) ? mergePlan.order : [],
308
+ laneCount: mergePlan && Array.isArray(mergePlan.lanes) ? mergePlan.lanes.length : 0,
309
+ orderViolationCount: dependencies.orderViolationCount
310
+ },
311
+ sync,
209
312
  lanes: lanes.map((lane) => ({
210
313
  lane: lane.lane,
211
314
  file: lane.file,
@@ -214,6 +317,11 @@ async function runParallelStatus({ args, options = {}, logger, t }) {
214
317
  priority: lane.priority,
215
318
  updatedAt: lane.updatedAt,
216
319
  scopeCount: lane.scopeCount,
320
+ dependencyCount: lane.dependencyCount,
321
+ dependencies: lane.dependencyItems,
322
+ mergeRank: lane.mergeRank,
323
+ writePathCount: lane.writePathCount,
324
+ writePaths: lane.writePathItems,
217
325
  blockerCount: lane.blockerCount,
218
326
  deliverables: lane.deliverables
219
327
  }))
@@ -237,7 +345,13 @@ async function runParallelStatus({ args, options = {}, logger, t }) {
237
345
  scopeCount,
238
346
  blockerCount,
239
347
  deliverables: output.deliverables,
240
- sharedDecisions: output.sharedDecisions
348
+ sharedDecisions: output.sharedDecisions,
349
+ machineFiles: output.machineFiles,
350
+ ownership: output.ownership,
351
+ writeScope: output.writeScope,
352
+ dependencies: output.dependencies,
353
+ merge: output.merge,
354
+ sync: output.sync
241
355
  }
242
356
  });
243
357
 
@@ -269,6 +383,36 @@ async function runParallelStatus({ args, options = {}, logger, t }) {
269
383
  count: sharedDecisionEntries
270
384
  })
271
385
  );
386
+ logger.log(
387
+ t('parallel_status.ownership_conflicts', {
388
+ count: output.ownership.conflictCount
389
+ })
390
+ );
391
+ logger.log(
392
+ t('parallel_status.write_scope_summary', {
393
+ lanes: output.writeScope.laneCount,
394
+ paths: output.writeScope.totalPathCount,
395
+ uncovered: output.writeScope.uncoveredAssignedLaneCount,
396
+ conflicts: output.writeScope.conflictCount,
397
+ invalid: output.writeScope.invalidPatternCount
398
+ })
399
+ );
400
+ logger.log(
401
+ t('parallel_status.dependencies_summary', {
402
+ declared: output.dependencies.declaredCount,
403
+ invalid: output.dependencies.invalidCount,
404
+ blocked: output.dependencies.blockedCount,
405
+ orderViolations: output.dependencies.orderViolationCount
406
+ })
407
+ );
408
+ logger.log(
409
+ t('parallel_status.sync_summary', {
410
+ count: output.sync.staleFiles.length
411
+ })
412
+ );
413
+ for (const file of output.sync.staleFiles) {
414
+ logger.log(t('parallel_status.sync_stale_line', { file }));
415
+ }
272
416
  for (const lane of output.lanes) {
273
417
  logger.log(
274
418
  t('parallel_status.lane_line', {
@@ -16,6 +16,7 @@ const path = require('node:path');
16
16
  const {
17
17
  loadProjectContext,
18
18
  scanArtifacts,
19
+ scanActiveManifest,
19
20
  readPhaseGates,
20
21
  readDevState,
21
22
  readProjectPulse,
@@ -23,8 +24,10 @@ const {
23
24
  detectFramework,
24
25
  detectTestRunner,
25
26
  discoverRules,
27
+ discoverDesignDocs,
26
28
  buildContextPackage,
27
29
  evaluateReadiness,
30
+ detectStaleDevState,
28
31
  extractSpecVersion,
29
32
  extractLastCheckpoint,
30
33
  GATE_NAMES
@@ -47,6 +50,7 @@ async function runPreflight({ args, options = {}, logger }) {
47
50
  // --- Gather all data ---
48
51
  const ctx = await loadProjectContext(targetDir);
49
52
  const artifacts = await scanArtifacts(targetDir, slug);
53
+ const manifest = await scanActiveManifest(targetDir, slug);
50
54
  const phaseGates = await readPhaseGates(targetDir, slug);
51
55
  const devState = await readDevState(targetDir);
52
56
  const pulse = await readProjectPulse(targetDir);
@@ -56,8 +60,17 @@ async function runPreflight({ args, options = {}, logger }) {
56
60
  const testRunnerInfo = await detectTestRunner(targetDir);
57
61
  const testRunner = testRunnerInfo ? testRunnerInfo.name : (ctx.data.test_runner || null);
58
62
  const rules = agent ? await discoverRules(targetDir, agent) : [];
59
- const contextPackage = buildContextPackage(agent || 'dev', slug, classification, artifacts, devState);
60
- const readiness = evaluateReadiness(artifacts, phaseGates, classification, agent);
63
+ const designDocs = agent ? await discoverDesignDocs(targetDir, agent) : [];
64
+ const contextPackage = buildContextPackage(agent || 'dev', slug, classification, artifacts, devState, manifest);
65
+ const readiness = evaluateReadiness(artifacts, phaseGates, classification, agent, devState, slug);
66
+
67
+ // Determine active execution artifact (AC-SDLC-24)
68
+ const activeExecutionArtifact = manifest && manifest.exists && manifest.is_active
69
+ ? manifest.path
70
+ : (artifacts.implementation_plan.exists ? artifacts.implementation_plan.path : null);
71
+
72
+ // Stale dev-state detection (AC-SDLC-12)
73
+ const staleDevStateWarning = devState.exists ? detectStaleDevState(devState, slug) : null;
61
74
 
62
75
  // Determine mode
63
76
  const mode = slug
@@ -105,10 +118,25 @@ async function runPreflight({ args, options = {}, logger }) {
105
118
  plan: phaseGates.plan || 'pending',
106
119
  execution: phaseGates.execution || 'pending'
107
120
  },
121
+ active_execution_artifact: activeExecutionArtifact,
122
+ manifest: manifest ? {
123
+ exists: manifest.exists,
124
+ path: manifest.path || null,
125
+ status: manifest.status || null,
126
+ is_active: manifest.is_active || false,
127
+ next_pending_phase: manifest.next_pending_phase || null
128
+ } : { exists: false },
108
129
  context_package: contextPackage,
109
130
  rules,
131
+ design_governance: designDocs,
132
+ context_layers: {
133
+ rules,
134
+ design_governance: designDocs
135
+ },
110
136
  readiness: readiness.status,
111
137
  readiness_blockers: readiness.blockers,
138
+ readiness_warnings: readiness.warnings || [],
139
+ stale_dev_state: staleDevStateWarning || null,
112
140
  pulse: {
113
141
  last_agent: pulse.last_agent || null,
114
142
  last_gate: pulse.last_gate || null,
@@ -165,13 +193,31 @@ async function runPreflight({ args, options = {}, logger }) {
165
193
  logger.log(` ${gateIcon(status)} Gate ${letter} (${name}): ${status}`);
166
194
  }
167
195
 
168
- if (devState.exists && devState.next_step) {
196
+ if (manifest && manifest.exists) {
197
+ logger.log('');
198
+ logger.log('Active execution artifact:');
199
+ const manifestIcon = manifest.is_active ? ' ✓' : ' ○';
200
+ logger.log(`${manifestIcon} ${manifest.path} (status: ${manifest.status || 'unknown'})${manifest.is_active ? ' [PRIMARY]' : ' [complete — not active]'}`);
201
+ if (manifest.is_active && manifest.next_pending_phase) {
202
+ const p = manifest.next_pending_phase;
203
+ logger.log(` → Next pending phase: Phase ${p.phase} — ${p.file} (status: ${p.status})`);
204
+ }
205
+ if (!manifest.is_active && artifacts.implementation_plan.exists) {
206
+ logger.log(` ✓ ${artifacts.implementation_plan.path || `implementation-plan-${slug}.md`} [primary — manifest complete]`);
207
+ }
208
+ }
209
+
210
+ if (devState.exists) {
169
211
  logger.log('');
170
212
  logger.log('Dev state:');
171
213
  if (devState.active_feature) logger.log(` active_feature: ${devState.active_feature}`);
172
214
  if (devState.active_phase) logger.log(` active_phase: ${devState.active_phase}`);
173
- logger.log(` next_step: "${devState.next_step}"`);
215
+ if (devState.next_step) logger.log(` next_step: "${devState.next_step}"`);
174
216
  if (devState.last_spec_version) logger.log(` last_spec_version: ${devState.last_spec_version}`);
217
+ if (devState.status) logger.log(` status: ${devState.status}`);
218
+ if (staleDevStateWarning) {
219
+ logger.log(` ⚠ STALE: ${staleDevStateWarning}`);
220
+ }
175
221
  }
176
222
 
177
223
  if (contextPackage.length > 0) {
@@ -185,6 +231,12 @@ async function runPreflight({ args, options = {}, logger }) {
185
231
  logger.log(`Rules loaded: ${rules.join(', ')}`);
186
232
  }
187
233
 
234
+ if (designDocs.length > 0) {
235
+ logger.log('');
236
+ logger.log('Design governance (load if implementation or structural planning touches code):');
237
+ designDocs.forEach((p, i) => logger.log(` ${i + 1}. ${p}`));
238
+ }
239
+
188
240
  if (pulse.last_agent) {
189
241
  logger.log('');
190
242
  logger.log('Project pulse:');
@@ -196,9 +248,16 @@ async function runPreflight({ args, options = {}, logger }) {
196
248
  logger.log('');
197
249
  if (readiness.status === 'READY') {
198
250
  logger.log(`Readiness: READY — proceed`);
251
+ } else if (readiness.status === 'READY_WITH_WARNINGS') {
252
+ logger.log(`Readiness: READY_WITH_WARNINGS — can proceed but review warnings`);
253
+ for (const w of readiness.warnings || []) logger.log(` ⚠ ${w}`);
199
254
  } else {
200
255
  logger.log(`Readiness: BLOCKED`);
201
256
  for (const b of readiness.blockers) logger.log(` ✗ ${b}`);
257
+ if ((readiness.warnings || []).length > 0) {
258
+ logger.log(' Warnings:');
259
+ for (const w of readiness.warnings) logger.log(` ⚠ ${w}`);
260
+ }
202
261
  }
203
262
  logger.log('');
204
263
 
@@ -3,7 +3,7 @@
3
3
  const path = require('node:path');
4
4
  const fs = require('node:fs/promises');
5
5
  const { readTextIfExists, ensureDir, exists } = require('../utils');
6
- const { validateProjectContextFile } = require('../context');
6
+ const { validateProjectContextFile, getInteractionLanguage } = require('../context');
7
7
 
8
8
  const DEFAULT_PERSONAS = ['naive', 'hacker', 'power', 'mobile'];
9
9
 
@@ -28,9 +28,14 @@ const DEFAULT_PERFORMANCE_THRESHOLDS = {
28
28
 
29
29
  function extractFrontmatterValue(markdown, key) {
30
30
  if (!markdown) return '';
31
- const regex = new RegExp(`^-\\s*${key}:\\s*(.*)$`, 'im');
32
- const match = String(markdown).match(regex);
33
- return match ? String(match[1] || '').trim() : '';
31
+ // Try list-style first: "- key: value"
32
+ const listRegex = new RegExp(`^-\\s*${key}:\\s*(.*)$`, 'im');
33
+ const listMatch = String(markdown).match(listRegex);
34
+ if (listMatch) return String(listMatch[1] || '').trim();
35
+ // Fallback to pure YAML: "key: value"
36
+ const yamlRegex = new RegExp(`^${key}:\\s*(.*)$`, 'im');
37
+ const yamlMatch = String(markdown).match(yamlRegex);
38
+ return yamlMatch ? String(yamlMatch[1] || '').trim().replace(/^['"]|['"]$/g, '') : '';
34
39
  }
35
40
 
36
41
  function extractYamlValue(markdown, key) {
@@ -90,7 +95,7 @@ async function runQaInit({ args, options = {}, logger, t }) {
90
95
  }
91
96
 
92
97
  const projectName = String(contextData.project_name || path.basename(targetDir) || 'Project');
93
- const language = String(contextData.conversation_language || 'en');
98
+ const language = getInteractionLanguage(contextData, 'en');
94
99
 
95
100
  // Parse prd.md for AC items
96
101
  const acItems = parseAcItems(prdContent);
@@ -0,0 +1,235 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson revision:open / revision:list / revision:resolve — Phase 2
5
+ *
6
+ * Usage:
7
+ * aioson revision:open . --slug=feature-x --requested-by=analyst --target=product
8
+ * --target-artifact=.aioson/context/prd-feature-x.md --reason="..." --severity=blocking
9
+ * aioson revision:list . --slug=feature-x [--status=pending]
10
+ * aioson revision:resolve . --rev-id=rev-001 --slug=feature-x --approve|--reject [--force-revision]
11
+ */
12
+
13
+ const path = require('node:path');
14
+
15
+ const revStore = require('../dossier/revision-store');
16
+ const { isValidSlug } = require('../dossier/schema');
17
+
18
+ function resolveContextDir(targetDir) {
19
+ return path.join(path.resolve(process.cwd(), targetDir || '.'), '.aioson', 'context');
20
+ }
21
+
22
+ function pickSlug(options) {
23
+ const raw = options.slug || options.feature;
24
+ return raw ? String(raw) : null;
25
+ }
26
+
27
+ async function runRevisionOpen({ args = [], options = {}, logger } = {}) {
28
+ const targetDir = args[0] || '.';
29
+ const slug = pickSlug(options);
30
+ const jsonOut = Boolean(options.json);
31
+ const log = (msg) => { if (logger && !jsonOut) logger.log(msg); };
32
+
33
+ if (!slug) {
34
+ if (jsonOut) return { ok: false, reason: 'missing_slug' };
35
+ log('--slug=<feature-slug> is required.');
36
+ return { ok: false };
37
+ }
38
+ if (!isValidSlug(slug)) {
39
+ if (jsonOut) return { ok: false, reason: 'invalid_slug', slug };
40
+ log(`Invalid slug "${slug}".`);
41
+ return { ok: false };
42
+ }
43
+
44
+ const requestedBy = options['requested-by'] || options.requestedBy;
45
+ const target = options.target;
46
+ const targetArtifact = options['target-artifact'] || options.targetArtifact;
47
+ const reason = options.reason;
48
+ const severity = options.severity || 'advisory';
49
+ const evidenceCodeRefs = options['evidence-code-refs']
50
+ ? String(options['evidence-code-refs']).split(',').map((s) => s.trim()).filter(Boolean)
51
+ : [];
52
+
53
+ if (!requestedBy) {
54
+ if (jsonOut) return { ok: false, reason: 'missing_requested_by' };
55
+ log('--requested-by=<agent> is required.');
56
+ return { ok: false };
57
+ }
58
+ if (!target) {
59
+ if (jsonOut) return { ok: false, reason: 'missing_target' };
60
+ log('--target=<agent> is required.');
61
+ return { ok: false };
62
+ }
63
+ if (!targetArtifact) {
64
+ if (jsonOut) return { ok: false, reason: 'missing_target_artifact' };
65
+ log('--target-artifact=<path> is required.');
66
+ return { ok: false };
67
+ }
68
+ if (!reason) {
69
+ if (jsonOut) return { ok: false, reason: 'missing_reason' };
70
+ log('--reason="..." is required.');
71
+ return { ok: false };
72
+ }
73
+
74
+ const ctxDir = resolveContextDir(targetDir);
75
+
76
+ try {
77
+ const revision = await revStore.open({
78
+ slug,
79
+ contextDir: ctxDir,
80
+ requestedBy,
81
+ target,
82
+ targetArtifact,
83
+ reason,
84
+ severity,
85
+ evidenceCodeRefs
86
+ });
87
+
88
+ if (jsonOut) return { ok: true, slug, revision };
89
+ log(`Revision opened: ${revision.id}`);
90
+ log(` slug: ${slug}`);
91
+ log(` requested_by: ${revision.requested_by} → target: ${revision.target}`);
92
+ log(` severity: ${revision.severity} status: ${revision.status}`);
93
+ if (revision.severity === 'blocking') {
94
+ log(` ⚠ Handoff will be blocked until resolved.`);
95
+ log(` Resolve with: aioson revision:resolve . --slug=${slug} --rev-id=${revision.id} --approve|--reject`);
96
+ }
97
+ return { ok: true, slug, revision };
98
+ } catch (err) {
99
+ if (err && err.code === 'EREVAGENT') {
100
+ if (jsonOut) return { ok: false, reason: 'invalid_agent', message: err.message };
101
+ log(err.message);
102
+ return { ok: false };
103
+ }
104
+ if (err && err.code === 'EREVSCHEMA') {
105
+ if (jsonOut) return { ok: false, reason: 'schema_error', message: err.message };
106
+ log(err.message);
107
+ return { ok: false };
108
+ }
109
+ throw err;
110
+ }
111
+ }
112
+
113
+ async function runRevisionList({ args = [], options = {}, logger } = {}) {
114
+ const targetDir = args[0] || '.';
115
+ const slug = pickSlug(options);
116
+ const jsonOut = Boolean(options.json);
117
+ const log = (msg) => { if (logger && !jsonOut) logger.log(msg); };
118
+
119
+ if (!slug) {
120
+ if (jsonOut) return { ok: false, reason: 'missing_slug' };
121
+ log('--slug=<feature-slug> is required.');
122
+ return { ok: false };
123
+ }
124
+ if (!isValidSlug(slug)) {
125
+ if (jsonOut) return { ok: false, reason: 'invalid_slug', slug };
126
+ log(`Invalid slug "${slug}".`);
127
+ return { ok: false };
128
+ }
129
+
130
+ const filterStatus = options.status ? String(options.status) : null;
131
+ const ctxDir = resolveContextDir(targetDir);
132
+
133
+ const revisions = await revStore.list({ slug, contextDir: ctxDir, status: filterStatus });
134
+
135
+ if (jsonOut) return { ok: true, slug, revisions, count: revisions.length };
136
+
137
+ if (revisions.length === 0) {
138
+ log(`No revisions found for "${slug}"${filterStatus ? ` with status=${filterStatus}` : ''}.`);
139
+ return { ok: true, slug, revisions: [], count: 0 };
140
+ }
141
+
142
+ log(`Revisions for "${slug}"${filterStatus ? ` (status=${filterStatus})` : ''}:`);
143
+ for (const r of revisions) {
144
+ const flag = r.severity === 'blocking' ? '⚠' : '·';
145
+ log(` ${flag} ${r.id} ${r.status.padEnd(10)} ${r.requested_by} → ${r.target} [${r.severity}]`);
146
+ log(` ${r.reason.slice(0, 80)}${r.reason.length > 80 ? '...' : ''}`);
147
+ }
148
+ return { ok: true, slug, revisions, count: revisions.length };
149
+ }
150
+
151
+ async function runRevisionResolve({ args = [], options = {}, logger } = {}) {
152
+ const targetDir = args[0] || '.';
153
+ const slug = pickSlug(options);
154
+ const revId = options['rev-id'] || options.revId;
155
+ const jsonOut = Boolean(options.json);
156
+ const forceRevision = Boolean(options['force-revision'] || options.forceRevision);
157
+ const log = (msg) => { if (logger && !jsonOut) logger.log(msg); };
158
+
159
+ if (!slug) {
160
+ if (jsonOut) return { ok: false, reason: 'missing_slug' };
161
+ log('--slug=<feature-slug> is required.');
162
+ return { ok: false };
163
+ }
164
+ if (!isValidSlug(slug)) {
165
+ if (jsonOut) return { ok: false, reason: 'invalid_slug', slug };
166
+ log(`Invalid slug "${slug}".`);
167
+ return { ok: false };
168
+ }
169
+ if (!revId) {
170
+ if (jsonOut) return { ok: false, reason: 'missing_rev_id' };
171
+ log('--rev-id=<rev-NNN> is required.');
172
+ return { ok: false };
173
+ }
174
+
175
+ const hasApprove = Boolean(options.approve);
176
+ const hasReject = Boolean(options.reject);
177
+ if (!hasApprove && !hasReject) {
178
+ if (jsonOut) return { ok: false, reason: 'missing_action' };
179
+ log('Either --approve or --reject is required.');
180
+ return { ok: false };
181
+ }
182
+ if (hasApprove && hasReject) {
183
+ if (jsonOut) return { ok: false, reason: 'conflicting_action' };
184
+ log('Cannot use --approve and --reject together.');
185
+ return { ok: false };
186
+ }
187
+
188
+ const action = hasApprove ? 'approve' : 'reject';
189
+ const ctxDir = resolveContextDir(targetDir);
190
+
191
+ try {
192
+ const { revision, gateIncremented } = await revStore.resolve({
193
+ slug,
194
+ contextDir: ctxDir,
195
+ revId,
196
+ action,
197
+ forceRevision
198
+ });
199
+
200
+ if (jsonOut) return { ok: true, slug, revision, gateIncremented };
201
+
202
+ if (action === 'reject') {
203
+ log(`Revision ${revId} rejected.`);
204
+ log(` Blocking revisions (if any) removed — handoff may now proceed.`);
205
+ } else {
206
+ log(`Revision ${revId} approved.`);
207
+ if (gateIncremented) {
208
+ log(` Gate '${gateIncremented.gate}' revision round: ${gateIncremented.rounds}/${revStore.MAX_REVISION_ROUNDS}`);
209
+ }
210
+ log(` Re-run @${revision.target} with revision context:`);
211
+ log(` aioson agent:prompt ${revision.target} . --revision-context=${revId}`);
212
+ }
213
+ return { ok: true, slug, revision, gateIncremented };
214
+ } catch (err) {
215
+ if (err && err.code === 'EREVNOTFOUND') {
216
+ if (jsonOut) return { ok: false, reason: 'not_found', revId };
217
+ log(err.message);
218
+ return { ok: false };
219
+ }
220
+ if (err && err.code === 'EREVNOTPENDING') {
221
+ if (jsonOut) return { ok: false, reason: 'not_pending', revId, status: err.status };
222
+ log(err.message);
223
+ return { ok: false };
224
+ }
225
+ if (err && err.code === 'EREVLOOP') {
226
+ if (jsonOut) return { ok: false, reason: 'anti_loop', gate: err.gate, rounds: err.rounds, max: revStore.MAX_REVISION_ROUNDS };
227
+ log(`Anti-loop: gate '${err.gate}' reached max revision rounds (${err.rounds}/${revStore.MAX_REVISION_ROUNDS}).`);
228
+ log(` Use --force-revision to override.`);
229
+ return { ok: false };
230
+ }
231
+ throw err;
232
+ }
233
+ }
234
+
235
+ module.exports = { runRevisionOpen, runRevisionList, runRevisionResolve };