@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
package/src/genomes.js CHANGED
@@ -22,6 +22,7 @@ const GENOME_V3_SECTION_KEYS = [
22
22
  'cognitiveProfile',
23
23
  'communicationStyle',
24
24
  'biases',
25
+ 'traitInteractions',
25
26
  'conflictResolution'
26
27
  ];
27
28
  const GENOME_SECTION_KEYS = [...GENOME_CANONICAL_SECTION_KEYS, ...GENOME_V3_SECTION_KEYS];
@@ -102,6 +103,21 @@ function normalizeStringArray(value) {
102
103
  .filter(Boolean);
103
104
  }
104
105
 
106
+ const GENOME_RELATION_TYPES = ['complementa', 'contradiz', 'depende-de', 'sobrepos'];
107
+
108
+ function normalizeRelations(value) {
109
+ if (!Array.isArray(value)) return [];
110
+ return value
111
+ .map((entry) => {
112
+ if (!entry || typeof entry !== 'object') return null;
113
+ const genome = normalizeText(entry.genome || entry.slug);
114
+ const type = normalizeText(entry.type);
115
+ if (!genome) return null;
116
+ return { genome, type };
117
+ })
118
+ .filter(Boolean);
119
+ }
120
+
105
121
  function normalizeGenomeVersion(value, fallback = 2) {
106
122
  const parsed = Number.parseInt(String(value || ''), 10);
107
123
  if (!Number.isFinite(parsed)) return fallback;
@@ -193,6 +209,9 @@ function createEmptyGenome() {
193
209
  enneagram: '',
194
210
  bigFive: '',
195
211
  mbti: '',
212
+ hexacoH: '',
213
+ anchorPrompt: '',
214
+ relations: [],
196
215
  confidence: '',
197
216
  profilerReport: '',
198
217
  hybridMode: '',
@@ -210,6 +229,7 @@ function createEmptyGenome() {
210
229
  cognitiveProfile: [],
211
230
  communicationStyle: [],
212
231
  biases: [],
232
+ traitInteractions: [],
213
233
  conflictResolution: [],
214
234
  evidence: [],
215
235
  applicationNotes: []
@@ -289,6 +309,9 @@ function normalizeGenome(input = {}) {
289
309
  enneagram: normalizeText(merged.enneagram),
290
310
  bigFive: normalizeText(merged.bigFive || merged.big_five),
291
311
  mbti: normalizeText(merged.mbti),
312
+ hexacoH: normalizeOptionalEnum(merged.hexacoH || merged.hexaco_h, GENOME_CONFIDENCE_LEVELS),
313
+ anchorPrompt: normalizeText(merged.anchorPrompt || merged.anchor_prompt),
314
+ relations: normalizeRelations(merged.relations),
292
315
  confidence: normalizeOptionalEnum(merged.confidence, GENOME_CONFIDENCE_LEVELS),
293
316
  profilerReport: normalizeText(merged.profilerReport || merged.profiler_report),
294
317
  hybridMode: normalizeOptionalEnum(
@@ -315,6 +338,7 @@ function countGenomeSections(input = {}) {
315
338
  cognitiveProfile: genome.sections.cognitiveProfile.length,
316
339
  communicationStyle: genome.sections.communicationStyle.length,
317
340
  biases: genome.sections.biases.length,
341
+ traitInteractions: genome.sections.traitInteractions.length,
318
342
  conflictResolution: genome.sections.conflictResolution.length,
319
343
  evidence: genome.sections.evidence.length,
320
344
  applicationNotes: genome.sections.applicationNotes.length
@@ -334,6 +358,7 @@ function normalizeCounts(value = {}) {
334
358
  cognitiveProfile: normalizeInteger(value.cognitiveProfile, 0),
335
359
  communicationStyle: normalizeInteger(value.communicationStyle, 0),
336
360
  biases: normalizeInteger(value.biases, 0),
361
+ traitInteractions: normalizeInteger(value.traitInteractions, 0),
337
362
  conflictResolution: normalizeInteger(value.conflictResolution, 0),
338
363
  evidence: normalizeInteger(value.evidence, 0),
339
364
  applicationNotes: normalizeInteger(value.applicationNotes, 0)
@@ -390,6 +415,9 @@ function normalizeGenomeMeta(input = {}) {
390
415
  enneagram: normalizeText(input.enneagram || (genome && genome.enneagram)),
391
416
  bigFive: normalizeText(input.bigFive || input.big_five || (genome && genome.bigFive)),
392
417
  mbti: normalizeText(input.mbti || (genome && genome.mbti)),
418
+ hexacoH: normalizeOptionalEnum(input.hexacoH || input.hexaco_h || (genome && genome.hexacoH), GENOME_CONFIDENCE_LEVELS),
419
+ anchorPrompt: normalizeText(input.anchorPrompt || input.anchor_prompt || (genome && genome.anchorPrompt)),
420
+ relations: normalizeRelations(input.relations || (genome && genome.relations)),
393
421
  confidence: normalizeOptionalEnum(input.confidence || (genome && genome.confidence), GENOME_CONFIDENCE_LEVELS),
394
422
  profilerReport: normalizeText(input.profilerReport || input.profiler_report || (genome && genome.profilerReport)),
395
423
  hybridMode: normalizeOptionalEnum(
@@ -416,6 +444,10 @@ function normalizeGenomeMeta(input = {}) {
416
444
  squads: normalizeStringArray(input.bindings && input.bindings.squads),
417
445
  agents: normalizeStringArray(input.bindings && input.bindings.agents)
418
446
  },
447
+ dependencies: {
448
+ skills: normalizeStringArray(input.dependencies && input.dependencies.skills),
449
+ genomes: normalizeStringArray(input.dependencies && input.dependencies.genomes)
450
+ },
419
451
  createdAt,
420
452
  updatedAt
421
453
  };
@@ -455,6 +487,7 @@ module.exports = {
455
487
  GENOME_FORMATS,
456
488
  GENOME_CONFIDENCE_LEVELS,
457
489
  GENOME_HYBRID_MODES,
490
+ GENOME_RELATION_TYPES,
458
491
  GENOME_SECTION_KEYS,
459
492
  GENOME_CANONICAL_SECTION_KEYS,
460
493
  GENOME_V3_SECTION_KEYS,
@@ -0,0 +1,363 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * handoff-contract — machine-verified agent output contracts.
5
+ *
6
+ * Each agent role declares what it must produce before the workflow
7
+ * allows handoff to the next stage. This catches incomplete agent
8
+ * sessions early instead of discovering missing artifacts later.
9
+ */
10
+
11
+ const path = require('node:path');
12
+ const { readFileSafe, fileExists } = require('./preflight-engine');
13
+
14
+ // Contract definitions per agent stage
15
+ const CONTRACTS = {
16
+ setup: {
17
+ artifacts: ['.aioson/context/project.context.md'],
18
+ gates: [],
19
+ contextUpdates: []
20
+ },
21
+ product: {
22
+ artifacts: (targetDir, state) => {
23
+ if (state.mode === 'feature' && state.featureSlug) {
24
+ return [`.aioson/context/prd-${state.featureSlug}.md`];
25
+ }
26
+ return ['.aioson/context/prd.md'];
27
+ },
28
+ gates: [],
29
+ contextUpdates: ['.aioson/context/project-pulse.md']
30
+ },
31
+ analyst: {
32
+ artifacts: (targetDir, state) => {
33
+ if (state.mode === 'feature' && state.featureSlug) {
34
+ return [
35
+ `.aioson/context/requirements-${state.featureSlug}.md`,
36
+ `.aioson/context/spec-${state.featureSlug}.md`
37
+ ];
38
+ }
39
+ return ['.aioson/context/discovery.md'];
40
+ },
41
+ gates: ['A'], // Gate A must be approved
42
+ contextUpdates: ['.aioson/context/project-pulse.md']
43
+ },
44
+ architect: {
45
+ artifacts: ['.aioson/context/architecture.md'],
46
+ gates: ['B'],
47
+ contextUpdates: ['.aioson/context/project-pulse.md']
48
+ },
49
+ 'ux-ui': {
50
+ artifacts: ['.aioson/context/ui-spec.md'],
51
+ gates: ['B'],
52
+ contextUpdates: ['.aioson/context/project-pulse.md']
53
+ },
54
+ pm: {
55
+ artifacts: (targetDir, state) => {
56
+ // @pm owns implementation-plan only for MEDIUM features (AC-SDLC-16)
57
+ if (state.mode === 'feature' && state.featureSlug && state.classification === 'MEDIUM') {
58
+ return [`.aioson/context/implementation-plan-${state.featureSlug}.md`];
59
+ }
60
+ return [];
61
+ },
62
+ gates: [],
63
+ contextUpdates: ['.aioson/context/project-pulse.md']
64
+ },
65
+ orchestrator: {
66
+ artifacts: ['.aioson/context/parallel'],
67
+ gates: [],
68
+ contextUpdates: ['.aioson/context/project-pulse.md']
69
+ },
70
+ dev: {
71
+ artifacts: [],
72
+ gates: ['C'],
73
+ contextUpdates: ['.aioson/context/project-pulse.md', '.aioson/context/dev-state.md']
74
+ },
75
+ tester: {
76
+ artifacts: [],
77
+ gates: [],
78
+ contextUpdates: ['.aioson/context/project-pulse.md']
79
+ },
80
+ pentester: {
81
+ artifacts: (targetDir, state) => {
82
+ if (state.mode === 'feature' && state.featureSlug) {
83
+ return [`.aioson/context/security-findings-${state.featureSlug}.json`];
84
+ }
85
+ return [];
86
+ },
87
+ gates: [],
88
+ contextUpdates: ['.aioson/context/project-pulse.md']
89
+ },
90
+ qa: {
91
+ artifacts: [],
92
+ gates: ['D'],
93
+ contextUpdates: ['.aioson/context/project-pulse.md']
94
+ },
95
+ committer: {
96
+ artifacts: [],
97
+ gates: [],
98
+ contextUpdates: []
99
+ }
100
+ };
101
+
102
+ async function readSecurityFindings(findingsPath) {
103
+ try {
104
+ const content = await readFileSafe(findingsPath);
105
+ if (!content) return { ok: false, reason: 'empty_file' };
106
+ const data = JSON.parse(content);
107
+ return {
108
+ ok: true,
109
+ reviewContract: data.review_contract && typeof data.review_contract === 'object'
110
+ ? data.review_contract
111
+ : null,
112
+ findings: Array.isArray(data.findings) ? data.findings : []
113
+ };
114
+ } catch {
115
+ return { ok: false, reason: 'invalid_json' };
116
+ }
117
+ }
118
+
119
+ function isNonEmptyString(value) {
120
+ return typeof value === 'string' && value.trim().length > 0;
121
+ }
122
+
123
+ function validateReviewContract(reviewContract) {
124
+ const missing = [];
125
+
126
+ if (!reviewContract || typeof reviewContract !== 'object') {
127
+ return ['review_contract'];
128
+ }
129
+
130
+ for (const field of ['scope_mode', 'evidence_policy', 'findings_artifact_path']) {
131
+ if (!isNonEmptyString(reviewContract[field])) {
132
+ missing.push(field);
133
+ }
134
+ }
135
+
136
+ if (
137
+ reviewContract.target_mode === 'app_target' &&
138
+ !isNonEmptyString(reviewContract.target_scope)
139
+ ) {
140
+ missing.push('target_scope');
141
+ }
142
+
143
+ return missing;
144
+ }
145
+
146
+ function getFindingIdentifier(finding) {
147
+ if (isNonEmptyString(finding?.id)) return finding.id.trim();
148
+ if (isNonEmptyString(finding?.finding_id)) return finding.finding_id.trim();
149
+ return 'unknown-finding';
150
+ }
151
+
152
+ async function resolveArtifacts(contract, targetDir, state) {
153
+ const raw = typeof contract.artifacts === 'function'
154
+ ? contract.artifacts(targetDir, state)
155
+ : contract.artifacts;
156
+ return raw.map((p) => path.join(targetDir, p));
157
+ }
158
+
159
+ function parseFrontmatterValue(markdown, key) {
160
+ const fmMatch = String(markdown || '').match(/^---\r?\n([\s\S]*?)\r?\n---/);
161
+ if (!fmMatch) return null;
162
+ for (const line of fmMatch[1].split(/\r?\n/)) {
163
+ const idx = line.indexOf(':');
164
+ if (idx === -1) continue;
165
+ const currentKey = line.slice(0, idx).trim();
166
+ if (currentKey !== key) continue;
167
+ return line.slice(idx + 1).trim().replace(/^["']|["']$/g, '');
168
+ }
169
+ return null;
170
+ }
171
+
172
+ async function resolveClassification(targetDir, state) {
173
+ const explicit = isNonEmptyString(state?.classification) ? state.classification.trim().toUpperCase() : null;
174
+ if (explicit) return explicit;
175
+ const contextPath = path.join(targetDir, '.aioson', 'context', 'project.context.md');
176
+ const content = await readFileSafe(contextPath);
177
+ const inferred = parseFrontmatterValue(content, 'classification');
178
+ return isNonEmptyString(inferred) ? inferred.trim().toUpperCase() : null;
179
+ }
180
+
181
+ async function checkGateApproval(targetDir, gateLetter, slug) {
182
+ const specPath = slug
183
+ ? path.join(targetDir, '.aioson', 'context', `spec-${slug}.md`)
184
+ : path.join(targetDir, '.aioson', 'context', 'spec.md');
185
+ const content = await readFileSafe(specPath);
186
+ if (!content) {
187
+ if (!slug) return { ok: true, reason: 'project_mode_without_spec' };
188
+ return { ok: false, reason: 'spec_missing' };
189
+ }
190
+
191
+ const gateNames = { A: 'requirements', B: 'design', C: 'plan', D: 'execution' };
192
+ const gateName = gateNames[gateLetter];
193
+
194
+ // Parse frontmatter
195
+ const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
196
+ if (!fmMatch) return { ok: false, reason: 'no_frontmatter' };
197
+
198
+ const fm = {};
199
+ for (const line of fmMatch[1].split(/\r?\n/)) {
200
+ const idx = line.indexOf(':');
201
+ if (idx === -1) continue;
202
+ const key = line.slice(0, idx).trim();
203
+ const val = line.slice(idx + 1).trim().replace(/^["']|["']$/g, '');
204
+ if (key) fm[key] = val;
205
+ }
206
+
207
+ // Check explicit gate field
208
+ const gateVal = fm[`gate_${gateName}`] || fm[`gate${gateLetter}`] || fm[`gate_${gateLetter}`];
209
+ if (gateVal && gateVal.toLowerCase() === 'approved') {
210
+ return { ok: true };
211
+ }
212
+
213
+ // Check phase_gates JSON
214
+ if (fm.phase_gates) {
215
+ try {
216
+ const parsed = JSON.parse(fm.phase_gates.replace(/'/g, '"'));
217
+ if (parsed[gateName] === 'approved') return { ok: true };
218
+ } catch {
219
+ // ignore
220
+ }
221
+ }
222
+
223
+ // Check content for gate approval lines
224
+ const gateLineRe = new RegExp(`gate\\s+${gateLetter}[^:]*:\\s*approved`, 'i');
225
+ if (gateLineRe.test(content)) {
226
+ return { ok: true };
227
+ }
228
+
229
+ // Gate D: also accept QA sign-off section with PASS verdict
230
+ if (gateLetter === 'D') {
231
+ if (content.includes('## QA Sign-off')) {
232
+ const passMatch = content.match(/\*\*Verdict:\*\*\s*(PASS)/i);
233
+ if (passMatch) {
234
+ return { ok: true };
235
+ }
236
+ }
237
+ }
238
+
239
+ return { ok: false, reason: `gate_${gateName}_not_approved` };
240
+ }
241
+
242
+ async function validateHandoffContract(targetDir, state, stageName) {
243
+ const contract = CONTRACTS[stageName];
244
+ if (!contract) {
245
+ // Unknown stage — allow pass-through
246
+ return { ok: true, stage: stageName, missing: [] };
247
+ }
248
+
249
+ const missing = [];
250
+ const classification = await resolveClassification(targetDir, state);
251
+
252
+ // 1. Artifacts
253
+ const artifactPaths = await resolveArtifacts(contract, targetDir, state);
254
+ for (const p of artifactPaths) {
255
+ if (!(await fileExists(p))) {
256
+ missing.push(`missing artifact: ${path.relative(targetDir, p)}`);
257
+ }
258
+ }
259
+
260
+ // 2. Gates
261
+ for (const gateLetter of contract.gates) {
262
+ const gateCheck = await checkGateApproval(targetDir, gateLetter, state.featureSlug);
263
+ if (!gateCheck.ok) {
264
+ missing.push(`gate ${gateLetter} not approved (${gateCheck.reason})`);
265
+ }
266
+ }
267
+
268
+ // 3. Context updates (soft check — just warn if completely missing)
269
+ for (const p of contract.contextUpdates) {
270
+ const abs = path.join(targetDir, p);
271
+ if (!(await fileExists(abs))) {
272
+ missing.push(`missing context file: ${p} (recommended)`);
273
+ }
274
+ }
275
+
276
+ // 4. Security findings check — qa stage only
277
+ // Blocks on open high/critical findings with recommended_gate_status=block.
278
+ if (stageName === 'qa' && state.featureSlug) {
279
+ const findingsPath = path.join(
280
+ targetDir,
281
+ `.aioson/context/security-findings-${state.featureSlug}.json`
282
+ );
283
+ const requiresFindingsArtifact = state.mode === 'feature' && classification === 'MEDIUM';
284
+ if (!(await fileExists(findingsPath))) {
285
+ if (requiresFindingsArtifact) {
286
+ missing.push(`missing artifact: ${path.relative(targetDir, findingsPath)} (required for MEDIUM Gate D security audit)`);
287
+ }
288
+ } else {
289
+ const envelope = await readSecurityFindings(findingsPath);
290
+ if (!envelope || envelope.ok === false) {
291
+ missing.push(
292
+ `security: invalid findings artifact in ${path.relative(targetDir, findingsPath)} (${envelope?.reason || 'invalid_json'})`
293
+ );
294
+ } else {
295
+ const reviewContractMissing = validateReviewContract(envelope.reviewContract);
296
+ if (reviewContractMissing.length > 0) {
297
+ missing.push(
298
+ `security: invalid review_contract in ${path.relative(targetDir, findingsPath)} (missing: ${reviewContractMissing.join(', ')})`
299
+ );
300
+ } else {
301
+ const blockers = envelope.findings.filter(
302
+ (f) =>
303
+ (f.status === 'open' || f.status === 'needs_validation') &&
304
+ f.recommended_gate_status === 'block' &&
305
+ (f.severity === 'high' || f.severity === 'critical')
306
+ );
307
+ if (blockers.length > 0) {
308
+ missing.push(
309
+ `security: ${blockers.length} unresolved high/critical finding(s) blocking gate: ${blockers.map((f) => getFindingIdentifier(f)).join(', ')}`
310
+ );
311
+ }
312
+ }
313
+ }
314
+ }
315
+ }
316
+
317
+ // Only hard-block on artifacts and gates; context updates are warnings unless
318
+ // we are in strict mode. For now, treat everything as blocking to harden handoffs.
319
+ const hardBlockers = missing.filter((m) => !m.includes('(recommended)'));
320
+
321
+ return {
322
+ ok: hardBlockers.length === 0,
323
+ stage: stageName,
324
+ missing: hardBlockers,
325
+ warnings: missing.filter((m) => m.includes('(recommended)'))
326
+ };
327
+ }
328
+
329
+ function formatContractError(result) {
330
+ const lines = [
331
+ `[Handoff Contract BLOCKED]`,
332
+ `Stage: @${result.stage}`,
333
+ '',
334
+ 'Missing deliverables:',
335
+ ...result.missing.map((m) => ` - ${m}`)
336
+ ];
337
+ if (result.warnings.length > 0) {
338
+ lines.push('', 'Warnings:');
339
+ lines.push(...result.warnings.map((w) => ` - ${w}`));
340
+ }
341
+ lines.push('', 'Complete these items before finishing the stage.');
342
+ return lines.join('\n');
343
+ }
344
+
345
+ // Returns pending blocking revisions for the active feature (or [] for legacy features).
346
+ // Safe to call when dossier feature dir does not exist — returns [] silently.
347
+ async function getBlockingRevisions(targetDir, featureSlug) {
348
+ if (!featureSlug) return [];
349
+ try {
350
+ const { getBlockingRevisions: getBlockers } = require('./dossier/revision-store');
351
+ const ctxDir = path.join(targetDir, '.aioson', 'context');
352
+ return await getBlockers({ slug: featureSlug, contextDir: ctxDir });
353
+ } catch {
354
+ return [];
355
+ }
356
+ }
357
+
358
+ module.exports = {
359
+ validateHandoffContract,
360
+ formatContractError,
361
+ getBlockingRevisions,
362
+ CONTRACTS
363
+ };
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+
3
+ const { readAgentManifest, canAgentPerform } = require('./agent-manifests');
4
+
5
+ async function validateHandoffProtocol(targetDir, protocol) {
6
+ const errors = [];
7
+ if (!protocol || typeof protocol !== 'object') {
8
+ return { ok: false, errors: ['Missing handoff protocol payload'] };
9
+ }
10
+
11
+ const toAgentId = protocol.to && protocol.to.agent_id ? String(protocol.to.agent_id).trim() : '';
12
+ const requiredCapability = protocol.to && protocol.to.capability_required
13
+ ? String(protocol.to.capability_required).trim()
14
+ : '';
15
+
16
+ if (protocol.to && typeof protocol.to === 'object' && !toAgentId) {
17
+ errors.push('Missing to.agent_id in handoff protocol');
18
+ }
19
+
20
+ if (toAgentId) {
21
+ const toManifest = await readAgentManifest(targetDir, toAgentId);
22
+ if (!toManifest) {
23
+ errors.push(`Agent ${toAgentId} has no capability manifest`);
24
+ } else if (requiredCapability && !canAgentPerform(toManifest, requiredCapability)) {
25
+ errors.push(`Agent ${toAgentId} does not declare capability ${requiredCapability}`);
26
+ }
27
+ }
28
+
29
+ const validation = protocol.validation && typeof protocol.validation === 'object'
30
+ ? protocol.validation
31
+ : {};
32
+
33
+ if (validation.handoff_contract_ok === false) {
34
+ errors.push('Handoff contract validation failed');
35
+ }
36
+
37
+ return {
38
+ ok: errors.length === 0,
39
+ errors
40
+ };
41
+ }
42
+
43
+ module.exports = {
44
+ validateHandoffProtocol
45
+ };
@@ -0,0 +1,135 @@
1
+ const fs = require('fs');
2
+
3
+ /**
4
+ * Circuit Breaker para o AIOSON — Módulo Puro
5
+ * Estados: CLOSED | OPEN | HALF_OPEN
6
+ * Persistência: progress.json
7
+ */
8
+ class CircuitBreaker {
9
+ constructor(contractPath, progressPath) {
10
+ this.contractPath = contractPath;
11
+ this.progressPath = progressPath;
12
+ this.contract = null;
13
+ this.progress = null;
14
+ }
15
+
16
+ /**
17
+ * Carrega os arquivos de contrato e progresso do disco.
18
+ * Se o progresso estiver corrompido, tenta recuperar ou cria novo.
19
+ */
20
+ async load() {
21
+ try {
22
+ this.contract = JSON.parse(fs.readFileSync(this.contractPath, 'utf8'));
23
+ } catch (err) {
24
+ throw new Error(`[CircuitBreaker] Falha ao carregar contrato: ${err.message}`);
25
+ }
26
+
27
+ try {
28
+ if (fs.existsSync(this.progressPath)) {
29
+ this.progress = JSON.parse(fs.readFileSync(this.progressPath, 'utf8'));
30
+ } else {
31
+ this.progress = this._createInitialProgress();
32
+ }
33
+ } catch (err) {
34
+ // Recuperação em caso de JSON corrompido
35
+ console.warn(`[CircuitBreaker] Progress corrompido, recriando...`);
36
+ this.progress = this._createInitialProgress();
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Verifica se uma nova iteração é permitida.
42
+ * Retorna { allowed: boolean, reason: string|null }
43
+ */
44
+ check() {
45
+ if (!this.progress || !this.contract) return { allowed: true, reason: null };
46
+
47
+ const { circuit_state, iterations, consecutive_errors } = this.progress;
48
+ const { max_steps, error_streak_limit } = this.contract.governor;
49
+
50
+ if (circuit_state === 'OPEN') {
51
+ return { allowed: false, reason: 'circuit_open' };
52
+ }
53
+
54
+ if (max_steps > 0 && iterations >= max_steps) {
55
+ return { allowed: false, reason: 'max_steps_reached' };
56
+ }
57
+
58
+ if (error_streak_limit > 0 && consecutive_errors >= error_streak_limit) {
59
+ return { allowed: false, reason: 'error_streak_limit_reached' };
60
+ }
61
+
62
+ return { allowed: true, reason: null };
63
+ }
64
+
65
+ /**
66
+ * Registra um sucesso no loop.
67
+ * Reseta erros consecutivos e pode fechar o circuit se estiver HALF_OPEN.
68
+ */
69
+ async recordSuccess() {
70
+ this.progress.consecutive_errors = 0;
71
+ this.progress.iterations += 1;
72
+ this.progress.last_updated = new Date().toISOString();
73
+ this.progress.ready_for_done_gate = true;
74
+
75
+ if (this.progress.circuit_state === 'HALF_OPEN') {
76
+ this.progress.circuit_state = 'CLOSED';
77
+ this.progress.status = 'in_progress';
78
+ }
79
+
80
+ await this._save();
81
+ }
82
+
83
+ /**
84
+ * Registra um erro no loop.
85
+ * Incrementa erros consecutivos e abre o circuit se atingir limites.
86
+ */
87
+ async recordError(reason) {
88
+ this.progress.consecutive_errors += 1;
89
+ this.progress.last_error = reason;
90
+ this.progress.last_updated = new Date().toISOString();
91
+ this.progress.ready_for_done_gate = false;
92
+
93
+ const { error_streak_limit, max_steps } = this.contract.governor;
94
+
95
+ if (error_streak_limit > 0 && this.progress.consecutive_errors >= error_streak_limit) {
96
+ this.progress.circuit_state = 'OPEN';
97
+ this.progress.status = 'circuit_open';
98
+ this.progress.last_error = `error_streak_limit_reached: ${reason}`;
99
+ } else if (max_steps > 0 && this.progress.iterations >= max_steps) {
100
+ this.progress.circuit_state = 'OPEN';
101
+ this.progress.status = 'circuit_open';
102
+ this.progress.last_error = `max_steps_reached: ${reason}`;
103
+ }
104
+
105
+ await this._save();
106
+ }
107
+
108
+ _createInitialProgress() {
109
+ return {
110
+ feature: this.contract ? this.contract.feature : 'unknown',
111
+ phase: 1,
112
+ status: 'in_progress',
113
+ completed_steps: [],
114
+ last_error: null,
115
+ session_count: 1,
116
+ last_updated: new Date().toISOString(),
117
+ circuit_state: 'CLOSED',
118
+ iterations: 0,
119
+ consecutive_errors: 0,
120
+ ready_for_done_gate: false
121
+ };
122
+ }
123
+
124
+ async _save() {
125
+ fs.writeFileSync(this.progressPath, JSON.stringify(this.progress, null, 2), 'utf8');
126
+ }
127
+
128
+ getState() {
129
+ return this.progress ? this.progress.circuit_state : 'CLOSED';
130
+ }
131
+ }
132
+
133
+ module.exports = {
134
+ createCircuitBreaker: (contractPath, progressPath) => new CircuitBreaker(contractPath, progressPath)
135
+ };