@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
@@ -0,0 +1,376 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+ const { spawnSync } = require('node:child_process');
6
+
7
+ const {
8
+ PATTERNS,
9
+ FORBIDDEN_FILES,
10
+ isAllowedByMarkers,
11
+ isAllowedByPath
12
+ } = require('../lib/security/secrets-regex');
13
+ const {
14
+ EXIT_CODES,
15
+ resolveExitCode
16
+ } = require('../lib/security/exit-codes');
17
+ const {
18
+ writeFindings,
19
+ buildFindingId
20
+ } = require('../lib/security/findings-writer');
21
+ const { emitSecurityRuntimeEvent } = require('../lib/security/runtime-events');
22
+
23
+ const VERSION = '1.0.0';
24
+ const GENERATOR = `aioson security:scan@${VERSION}`;
25
+ const VALID_STAGES = new Set(['analyst', 'dev', 'qa', 'all']);
26
+
27
+ const SCAN_EXTENSIONS = new Set([
28
+ '.js', '.mjs', '.cjs', '.ts', '.tsx', '.jsx',
29
+ '.json', '.yaml', '.yml', '.md', '.txt',
30
+ '.env', '.sh', '.py', '.rb', '.php', '.go', '.rs'
31
+ ]);
32
+
33
+ const SKIP_DIRS = new Set([
34
+ 'node_modules', '.git', '.aioson', 'dist', 'build', 'coverage',
35
+ '.next', '.cache', 'tmp', '.turbo', '.vercel', 'researchs'
36
+ ]);
37
+
38
+ const MAX_FILE_BYTES = 512 * 1024; // 512 KB per file
39
+
40
+ function defaultRuntimeAgentName(stage) {
41
+ if (stage === 'analyst') return 'analyst';
42
+ if (stage === 'qa') return 'qa';
43
+ return 'dev';
44
+ }
45
+
46
+ async function* walk(dir, baseDir) {
47
+ let entries;
48
+ try {
49
+ entries = await fs.readdir(dir, { withFileTypes: true });
50
+ } catch (err) {
51
+ if (err && err.code === 'ENOENT') return;
52
+ throw err;
53
+ }
54
+ for (const entry of entries) {
55
+ const full = path.join(dir, entry.name);
56
+ if (entry.isDirectory()) {
57
+ if (SKIP_DIRS.has(entry.name)) continue;
58
+ yield* walk(full, baseDir);
59
+ } else if (entry.isFile()) {
60
+ const ext = path.extname(entry.name).toLowerCase();
61
+ const base = entry.name;
62
+ const isForbiddenName = FORBIDDEN_FILES.includes(base);
63
+ if (!isForbiddenName && ext && !SCAN_EXTENSIONS.has(ext)) continue;
64
+ yield { fullPath: full, relPath: path.relative(baseDir, full).split(path.sep).join('/'), name: base };
65
+ }
66
+ }
67
+ }
68
+
69
+ function regexFindingsForLine({ line, lineNumber, relPath }) {
70
+ if (isAllowedByMarkers(line)) return [];
71
+ if (isAllowedByPath(relPath)) return [];
72
+ const out = [];
73
+ for (const def of PATTERNS) {
74
+ def.pattern.lastIndex = 0;
75
+ let m;
76
+ while ((m = def.pattern.exec(line)) !== null) {
77
+ out.push({
78
+ source: 'security-scan',
79
+ control_id: def.control,
80
+ severity: def.severity,
81
+ scope: `${relPath}:${lineNumber}`,
82
+ affected_artifacts: [relPath],
83
+ preconditions: [`File ${relPath} is staged or committed`],
84
+ reproduction_steps: [`grep -nE on ${relPath}: pattern ${def.id}`],
85
+ evidence: [`Pattern "${def.name}" matched at ${relPath}:${lineNumber}`],
86
+ impact: `Possible exposed credential (${def.name}).`,
87
+ suggested_fix: 'Move to environment variable or vault. Rotate the credential. Add to .gitignore.',
88
+ recommended_owner: 'dev'
89
+ });
90
+ }
91
+ }
92
+ return out;
93
+ }
94
+
95
+ async function scanFileContent({ fullPath, relPath }) {
96
+ let stat;
97
+ try {
98
+ stat = await fs.stat(fullPath);
99
+ } catch {
100
+ return [];
101
+ }
102
+ if (stat.size > MAX_FILE_BYTES) return [];
103
+ let content;
104
+ try {
105
+ content = await fs.readFile(fullPath, 'utf8');
106
+ } catch {
107
+ return [];
108
+ }
109
+ const lines = content.split(/\r?\n/);
110
+ const findings = [];
111
+ for (let i = 0; i < lines.length; i += 1) {
112
+ const lineFindings = regexFindingsForLine({
113
+ line: lines[i],
114
+ lineNumber: i + 1,
115
+ relPath
116
+ });
117
+ findings.push(...lineFindings);
118
+ }
119
+ return findings;
120
+ }
121
+
122
+ function forbiddenFileFinding({ relPath, name }) {
123
+ if (isAllowedByPath(relPath)) return null;
124
+ return {
125
+ source: 'security-scan',
126
+ control_id: 'SEC-SBD-05',
127
+ severity: 'high',
128
+ scope: relPath,
129
+ affected_artifacts: [relPath],
130
+ preconditions: [`File ${name} is present in the workspace`],
131
+ reproduction_steps: [`Inspect ${relPath}`],
132
+ evidence: [`File ${relPath} is one of the forbidden filenames (${name}).`],
133
+ impact: 'Sensitive file may be committed; secrets at risk of leakage.',
134
+ suggested_fix: `Move ${name} out of the working tree, add to .gitignore, and rotate any contained secrets.`,
135
+ recommended_owner: 'dev'
136
+ };
137
+ }
138
+
139
+ function npmAuditFinding(stdout, exitCode) {
140
+ let parsed;
141
+ try {
142
+ parsed = JSON.parse(stdout);
143
+ } catch {
144
+ return null;
145
+ }
146
+ const meta = parsed && parsed.metadata;
147
+ const vulns = meta && meta.vulnerabilities;
148
+ if (!vulns) return null;
149
+ const high = (vulns.high || 0) + (vulns.critical || 0);
150
+ const moderate = vulns.moderate || 0;
151
+ if (high === 0 && moderate === 0) return null;
152
+ const severity = high > 0 ? 'high' : 'medium';
153
+ return {
154
+ source: 'security-scan',
155
+ control_id: 'SEC-SBD-05',
156
+ severity,
157
+ scope: 'package-lock.json:npm-audit',
158
+ affected_artifacts: ['package-lock.json'],
159
+ preconditions: ['package-lock.json exists'],
160
+ reproduction_steps: ['npm audit --json --omit=dev'],
161
+ evidence: [`npm audit reported ${high} high/critical, ${moderate} moderate (exit ${exitCode}).`],
162
+ impact: 'Known vulnerable dependency in production tree.',
163
+ suggested_fix: 'Run `npm audit fix` or upgrade affected packages.',
164
+ recommended_owner: 'dev'
165
+ };
166
+ }
167
+
168
+ function npmAuditInconclusive(stderr) {
169
+ return {
170
+ source: 'security-scan',
171
+ control_id: 'SEC-SBD-05',
172
+ severity: 'inconclusive',
173
+ status: 'needs_validation',
174
+ scope: 'package-lock.json:npm-audit-network',
175
+ affected_artifacts: ['package-lock.json'],
176
+ preconditions: ['npm audit was attempted'],
177
+ reproduction_steps: ['npm audit --json --omit=dev'],
178
+ evidence: [`npm audit failed (likely network): ${(stderr || '').slice(0, 200)}`],
179
+ impact: 'Cannot determine dependency vulnerability state at this time.',
180
+ suggested_fix: 'Re-run when network is available.',
181
+ recommended_owner: 'dev',
182
+ recommended_gate_status: 'review'
183
+ };
184
+ }
185
+
186
+ function runNpmAudit(targetDir) {
187
+ const result = spawnSync('npm', ['audit', '--json', '--omit=dev'], {
188
+ cwd: targetDir,
189
+ encoding: 'utf8',
190
+ timeout: 60_000,
191
+ shell: process.platform === 'win32'
192
+ });
193
+ if (result.error) {
194
+ const networkLike = /ENOTFOUND|ETIMEDOUT|network/i.test(String(result.error.message || ''));
195
+ return { ok: false, network: networkLike, stderr: String(result.error.message || ''), exitCode: -1 };
196
+ }
197
+ const stderr = result.stderr || '';
198
+ const networkLike = /ENOTFOUND|ETIMEDOUT|network/i.test(stderr);
199
+ return {
200
+ ok: true,
201
+ network: networkLike,
202
+ stdout: result.stdout || '',
203
+ stderr,
204
+ exitCode: result.status === null ? -1 : result.status
205
+ };
206
+ }
207
+
208
+ async function gatherFindings({ targetDir, stage }) {
209
+ const findings = [];
210
+ let inconclusive = false;
211
+
212
+ for await (const file of walk(targetDir, targetDir)) {
213
+ if (FORBIDDEN_FILES.includes(file.name)) {
214
+ const f = forbiddenFileFinding({ relPath: file.relPath, name: file.name });
215
+ if (f) findings.push(f);
216
+ }
217
+ const fileFindings = await scanFileContent(file);
218
+ findings.push(...fileFindings);
219
+ }
220
+
221
+ if (stage === 'dev' || stage === 'qa' || stage === 'all') {
222
+ const lockPath = path.join(targetDir, 'package-lock.json');
223
+ let hasLock = false;
224
+ try {
225
+ await fs.access(lockPath);
226
+ hasLock = true;
227
+ } catch {
228
+ hasLock = false;
229
+ }
230
+ if (hasLock) {
231
+ const audit = runNpmAudit(targetDir);
232
+ if (!audit.ok || audit.network || audit.exitCode === -1) {
233
+ findings.push(npmAuditInconclusive(audit.stderr));
234
+ inconclusive = true;
235
+ } else {
236
+ const f = npmAuditFinding(audit.stdout, audit.exitCode);
237
+ if (f) findings.push(f);
238
+ }
239
+ }
240
+ }
241
+
242
+ return { findings, inconclusive };
243
+ }
244
+
245
+ async function runSecurityScan({ args, options = {}, logger }) {
246
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
247
+ const stage = String(options.stage || 'all').toLowerCase();
248
+ const slug = options.feature || options.slug || null;
249
+ const classification = String(options.classification || 'MEDIUM').toUpperCase();
250
+ const strict = Boolean(options.strict);
251
+ const format = String(options.format || 'json').toLowerCase();
252
+
253
+ if (!VALID_STAGES.has(stage)) {
254
+ const out = { ok: false, exitCode: EXIT_CODES.BAD_INPUT, reason: 'invalid_stage', stage };
255
+ process.exitCode = out.exitCode;
256
+ logger.error(`security:scan: invalid --stage=${stage}. Valid: ${[...VALID_STAGES].join(', ')}`);
257
+ return out;
258
+ }
259
+
260
+ let stat;
261
+ try {
262
+ stat = await fs.stat(targetDir);
263
+ } catch {
264
+ const out = { ok: false, exitCode: EXIT_CODES.BAD_INPUT, reason: 'project_not_found', targetDir };
265
+ process.exitCode = out.exitCode;
266
+ logger.error(`security:scan: project path not found: ${targetDir}`);
267
+ return out;
268
+ }
269
+ if (!stat.isDirectory()) {
270
+ const out = { ok: false, exitCode: EXIT_CODES.BAD_INPUT, reason: 'project_not_directory', targetDir };
271
+ process.exitCode = out.exitCode;
272
+ logger.error(`security:scan: project path is not a directory: ${targetDir}`);
273
+ return out;
274
+ }
275
+
276
+ const generatedAt = options.now || new Date().toISOString();
277
+ const { findings, inconclusive } = await gatherFindings({ targetDir, stage });
278
+
279
+ const writeResult = await writeFindings({
280
+ targetDir,
281
+ slug,
282
+ source: 'security-scan',
283
+ generator: GENERATOR,
284
+ generatedAt,
285
+ scopeMode: slug ? 'feature' : 'project',
286
+ findings
287
+ });
288
+
289
+ if (!writeResult.ok && writeResult.reason === 'contract_violation_too_many_findings') {
290
+ process.exitCode = EXIT_CODES.CONTRACT_VIOLATION;
291
+ logger.error(`security:scan: too many findings (${writeResult.count} > ${writeResult.max}). Split scope.`);
292
+ await emitSecurityRuntimeEvent({
293
+ targetDir,
294
+ eventType: 'security_scan_completed',
295
+ message: `security:scan completed with contract violation for ${slug || 'project'} (stage=${stage}, exit=${EXIT_CODES.CONTRACT_VIOLATION})`,
296
+ status: 'completed',
297
+ agentName: options.runtimeAgentName || defaultRuntimeAgentName(stage),
298
+ source: options.runtimeSource || 'direct',
299
+ workflowState: options.runtimeState || null,
300
+ workflowStage: options.runtimeWorkflowStage || stage,
301
+ payload: {
302
+ command: 'security:scan',
303
+ slug: slug || 'project',
304
+ classification,
305
+ stage,
306
+ exitCode: EXIT_CODES.CONTRACT_VIOLATION,
307
+ findingsCount: writeResult.count,
308
+ artifactPath: writeResult.artifactPath || null,
309
+ reason: 'too_many_findings',
310
+ strict
311
+ }
312
+ });
313
+ return {
314
+ ok: false,
315
+ exitCode: EXIT_CODES.CONTRACT_VIOLATION,
316
+ reason: 'too_many_findings',
317
+ ...writeResult
318
+ };
319
+ }
320
+
321
+ const exitCode = resolveExitCode({
322
+ classification,
323
+ findings: writeResult.payload.findings,
324
+ hasInconclusive: inconclusive,
325
+ strict
326
+ });
327
+ process.exitCode = exitCode;
328
+
329
+ const summary = writeResult.payload.summary;
330
+ const result = {
331
+ ok: exitCode === EXIT_CODES.PASS,
332
+ exitCode,
333
+ artifactPath: writeResult.artifactPath,
334
+ summary,
335
+ findingsCount: writeResult.payload.findings.length,
336
+ classification,
337
+ stage,
338
+ strict,
339
+ slug: slug || null
340
+ };
341
+
342
+ await emitSecurityRuntimeEvent({
343
+ targetDir,
344
+ eventType: 'security_scan_completed',
345
+ message: `security:scan completed for ${slug || 'project'} (stage=${stage}, exit=${exitCode})`,
346
+ status: 'completed',
347
+ agentName: options.runtimeAgentName || defaultRuntimeAgentName(stage),
348
+ source: options.runtimeSource || 'direct',
349
+ workflowState: options.runtimeState || null,
350
+ workflowStage: options.runtimeWorkflowStage || stage,
351
+ payload: {
352
+ command: 'security:scan',
353
+ slug: slug || 'project',
354
+ classification,
355
+ stage,
356
+ exitCode,
357
+ findingsCount: result.findingsCount,
358
+ artifactPath: writeResult.artifactPath,
359
+ summary,
360
+ strict
361
+ }
362
+ });
363
+
364
+ if (format === 'json' || options.json) {
365
+ return result;
366
+ }
367
+ const summaryLine = `security:scan: ${summary.critical} critical, ${summary.high} high, ${summary.medium} medium, ${summary.low} low, ${summary.inconclusive} inconclusive (exit ${exitCode}).`;
368
+ logger.log(summaryLine);
369
+ for (const f of writeResult.payload.findings) {
370
+ if (f.status !== 'open' && f.status !== 'needs_validation') continue;
371
+ logger.log(` [${f.severity}] ${f.control_id} ${f.scope}`);
372
+ }
373
+ return result;
374
+ }
375
+
376
+ module.exports = { runSecurityScan, GENERATOR, VERSION };
@@ -20,10 +20,12 @@
20
20
  const path = require('node:path');
21
21
  const { execSync, execFileSync } = require('node:child_process');
22
22
  const { randomUUID } = require('node:crypto');
23
- const fs = require('node:fs/promises');
23
+ const fs = require('node:fs');
24
+ const fsp = require('node:fs/promises');
24
25
 
25
26
  const bus = require('../squad/intra-bus');
26
27
  const stateManager = require('../squad/state-manager');
28
+ const { createCircuitBreaker } = require('../harness/circuit-breaker');
27
29
 
28
30
  // ─── Agent execution ─────────────────────────────────────────────────────────
29
31
 
@@ -131,13 +133,37 @@ async function runSelfLoop({ args, options = {}, logger }) {
131
133
  const targetDir = path.resolve(process.cwd(), args[0] || '.');
132
134
  const agent = String(options.agent || options.a || 'dev').trim();
133
135
  const task = String(options.task || options.t || '').trim();
134
- const maxIterations = Math.min(Math.max(Number(options['max-iterations'] || 3), 1), 5);
135
136
  const spec = options.spec ? String(options.spec).trim() : null;
136
137
  const artifact = options.artifact ? String(options.artifact).trim() : null;
137
138
  const criteria = options['verification-criteria'] || options.criteria || '';
138
139
  const squad = options.squad ? String(options.squad).trim() : null;
139
140
  const timeoutMs = (Number(options.timeout) || 300) * 1000;
140
141
 
142
+ // Harness Integration — Discover contract
143
+ let cb = null;
144
+ let contractPath = options.contract;
145
+
146
+ // Auto-discover contract if not provided but feature slug is known
147
+ if (!contractPath && spec) {
148
+ const slug = path.basename(spec, '.md').replace(/^spec-/, '');
149
+ const autoPath = path.join(targetDir, '.aioson', 'plans', slug, 'harness-contract.json');
150
+ if (fs.existsSync(autoPath)) contractPath = autoPath;
151
+ }
152
+
153
+ if (contractPath && fs.existsSync(contractPath)) {
154
+ const progressPath = path.join(path.dirname(contractPath), 'progress.json');
155
+ cb = createCircuitBreaker(contractPath, progressPath);
156
+ await cb.load();
157
+ logger.log(`[Harness] Contract loaded: ${path.relative(targetDir, contractPath)}`);
158
+ }
159
+
160
+ // Set max iterations: Contract policy takes precedence over flag
161
+ let maxIterations = Math.min(Math.max(Number(options['max-iterations'] || 3), 1), 5);
162
+ if (cb && cb.contract && cb.contract.governor && cb.contract.governor.max_steps > 0) {
163
+ maxIterations = cb.contract.governor.max_steps;
164
+ logger.log(`[Harness] Max iterations set by contract: ${maxIterations}`);
165
+ }
166
+
141
167
  if (!task) {
142
168
  logger.error('Error: --task is required');
143
169
  return { ok: false, error: 'missing_task' };
@@ -153,6 +179,17 @@ async function runSelfLoop({ args, options = {}, logger }) {
153
179
  logger.log('');
154
180
 
155
181
  for (let iteration = 1; iteration <= maxIterations; iteration++) {
182
+ // Harness Check
183
+ if (cb) {
184
+ const { allowed, reason } = cb.check();
185
+ if (!allowed) {
186
+ logger.log(`── Harness Block ──────────────────────────────────────────`);
187
+ logger.log(` ✗ Execution paused: ${reason}`);
188
+ logger.log(` Intervenção humana necessária antes de retomar.`);
189
+ return { ok: false, iterations: iteration - 1, verdict: 'BLOCKED', reason };
190
+ }
191
+ }
192
+
156
193
  logger.log(`── Iteration ${iteration}/${maxIterations} ──────────────────────────`);
157
194
 
158
195
  // Step 1: Execute agent
@@ -198,6 +235,8 @@ async function runSelfLoop({ args, options = {}, logger }) {
198
235
  if (verifyResult.ok) {
199
236
  logger.log(` ✓ PASS${iteration > 1 ? ` (after ${iteration} iteration${iteration > 1 ? 's' : ''})` : ''}`);
200
237
 
238
+ if (cb) await cb.recordSuccess();
239
+
201
240
  // Record success in state
202
241
  if (squad) {
203
242
  await stateManager.updateState(targetDir, squad, {
@@ -218,6 +257,11 @@ async function runSelfLoop({ args, options = {}, logger }) {
218
257
  logger.log(` - ${issue.message}`);
219
258
  }
220
259
 
260
+ if (cb) {
261
+ const firstIssue = verifyResult.issues[0]?.message || verifyResult.verdict;
262
+ await cb.recordError(firstIssue);
263
+ }
264
+
221
265
  feedbackHistory.push({
222
266
  iteration,
223
267
  verdict: verifyResult.verdict,
@@ -3,6 +3,7 @@
3
3
  const path = require('node:path');
4
4
  const readline = require('node:readline/promises');
5
5
  const { detectFramework, isMonorepoDetection } = require('../detector');
6
+ const { normalizeLanguageTag } = require('../context');
6
7
 
7
8
  /**
8
9
  * Infer conversation language from the OS locale environment variables.
@@ -13,14 +14,7 @@ function detectSystemLanguage() {
13
14
  const raw = process.env.LANGUAGE || process.env.LANG || process.env.LC_ALL || '';
14
15
  const base = raw.split(':')[0].split('.')[0].trim();
15
16
  if (!base || base === 'C' || base === 'POSIX') return 'en';
16
- const normalized = base.replace('_', '-');
17
- const supported = ['en', 'pt-BR', 'es', 'fr'];
18
- if (supported.includes(normalized)) return normalized;
19
- const lang = normalized.split('-')[0].toLowerCase();
20
- if (lang === 'pt') return 'pt-BR';
21
- if (lang === 'es') return 'es';
22
- if (lang === 'fr') return 'fr';
23
- return 'en';
17
+ return normalizeLanguageTag(base, 'en');
24
18
  }
25
19
  const { getCliVersionSync } = require('../version');
26
20
  const {
@@ -226,7 +220,10 @@ function applyExplicitOverrides(data, options, detectedInstalled) {
226
220
  output.frameworkInstalled = normalizeBoolean(options['framework-installed'], detectedInstalled);
227
221
  }
228
222
  const langValue = options.language ?? options.lang;
229
- if (langValue !== undefined) output.conversationLanguage = String(langValue);
223
+ if (langValue !== undefined) {
224
+ output.conversationLanguage = String(langValue);
225
+ output.interactionLanguage = String(langValue);
226
+ }
230
227
  if (hasOption(options, 'design-skill')) output.designSkill = String(options['design-skill']);
231
228
  if (hasOption(options, 'test-runner')) output.testRunner = String(options['test-runner']);
232
229
  if (hasOption(options, 'web3-enabled')) {
@@ -489,6 +486,7 @@ async function runSetupContext({ args, options, logger, t }) {
489
486
  framework: detectedFramework,
490
487
  frameworkInstalled: detectedInstalled,
491
488
  conversationLanguage: detectSystemLanguage(),
489
+ interactionLanguage: detectSystemLanguage(),
492
490
  designSkill: '',
493
491
  testRunner: '',
494
492
  web3Enabled: inferredWeb3Enabled,
@@ -557,6 +555,7 @@ async function runSetupContext({ args, options, logger, t }) {
557
555
 
558
556
  data.profile = normalizeProfile(await ask(rl, t('setup_context.q_profile'), data.profile), data.profile);
559
557
  data.conversationLanguage = await ask(rl, t('setup_context.q_language'), data.conversationLanguage);
558
+ data.interactionLanguage = data.conversationLanguage;
560
559
 
561
560
  let profileData = null;
562
561
  if (data.profile === 'developer') {
@@ -612,6 +611,8 @@ async function runSetupContext({ args, options, logger, t }) {
612
611
  }
613
612
 
614
613
  data = applyExplicitOverrides(data, options, detectedInstalled);
614
+ if (!data.interactionLanguage) data.interactionLanguage = data.conversationLanguage || 'en';
615
+ if (!data.conversationLanguage) data.conversationLanguage = data.interactionLanguage;
615
616
 
616
617
  const classificationResult = calculateClassification({
617
618
  userTypesCount,
@@ -641,7 +642,7 @@ async function runSetupContext({ args, options, logger, t }) {
641
642
  const squadApiSection = await renderSquadApiSection(targetDir);
642
643
  const fullContent = squadApiSection ? content + '\n' + squadApiSection + '\n' : content;
643
644
  const filePath = await writeProjectContext(targetDir, fullContent);
644
- const localeApplyResult = await applyAgentLocale(targetDir, data.conversationLanguage, {
645
+ const localeApplyResult = await applyAgentLocale(targetDir, data.interactionLanguage, {
645
646
  dryRun: false
646
647
  });
647
648