@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,400 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const fs = require('node:fs/promises');
5
+ const path = require('node:path');
6
+
7
+ const {
8
+ SCHEMA_VERSION,
9
+ REQUIRED_SECTIONS,
10
+ isValidSlug,
11
+ assertFrontmatter,
12
+ validateFrontmatter
13
+ } = require('./schema');
14
+
15
+ const FEATURES_SUBDIR = 'features';
16
+ const DOSSIER_FILENAME = 'dossier.md';
17
+ const DEFAULT_AUTHOR = 'dossier-init';
18
+
19
+ function featureDir(contextDir, slug) {
20
+ return path.join(contextDir, FEATURES_SUBDIR, slug);
21
+ }
22
+
23
+ function dossierPath(contextDir, slug) {
24
+ return path.join(featureDir(contextDir, slug), DOSSIER_FILENAME);
25
+ }
26
+
27
+ function prdPath(contextDir, slug) {
28
+ return path.join(contextDir, `prd-${slug}.md`);
29
+ }
30
+
31
+ async function fileExists(p) {
32
+ try {
33
+ await fs.access(p);
34
+ return true;
35
+ } catch {
36
+ return false;
37
+ }
38
+ }
39
+
40
+ function parseFrontmatter(markdown) {
41
+ const text = String(markdown || '');
42
+ if (!text.startsWith('---\n') && !text.startsWith('---\r\n')) {
43
+ return { ok: false, data: null, body: text, reason: 'missing_frontmatter' };
44
+ }
45
+ const lines = text.split(/\r?\n/);
46
+ let closingIndex = -1;
47
+ for (let i = 1; i < lines.length; i += 1) {
48
+ if (lines[i].trim() === '---') {
49
+ closingIndex = i;
50
+ break;
51
+ }
52
+ }
53
+ if (closingIndex === -1) {
54
+ return { ok: false, data: null, body: text, reason: 'unclosed_frontmatter' };
55
+ }
56
+ const data = {};
57
+ for (let i = 1; i < closingIndex; i += 1) {
58
+ const line = lines[i].trim();
59
+ if (!line || line.startsWith('#')) continue;
60
+ const match = line.match(/^([a-zA-Z0-9_]+)\s*:\s*(.*)$/);
61
+ if (!match) {
62
+ return { ok: false, data: null, body: text, reason: 'invalid_frontmatter_line', line };
63
+ }
64
+ let val = match[2].trim();
65
+ if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
66
+ val = val.slice(1, -1);
67
+ }
68
+ data[match[1]] = val;
69
+ }
70
+ const body = lines.slice(closingIndex + 1).join('\n');
71
+ return { ok: true, data, body };
72
+ }
73
+
74
+ function parseSections(markdown) {
75
+ const text = String(markdown || '');
76
+ const parsed = parseFrontmatter(text);
77
+ const body = parsed.ok ? parsed.body : text;
78
+ const sections = Object.create(null);
79
+
80
+ const lines = body.split(/\r?\n/);
81
+ let current = null;
82
+ let buf = [];
83
+
84
+ const flush = () => {
85
+ if (current !== null) {
86
+ sections[current] = buf.join('\n').replace(/\s+$/, '');
87
+ }
88
+ };
89
+
90
+ for (const line of lines) {
91
+ const m = line.match(/^##\s+(.+?)\s*$/);
92
+ if (m) {
93
+ flush();
94
+ current = m[1].trim();
95
+ buf = [];
96
+ } else if (current !== null) {
97
+ buf.push(line);
98
+ }
99
+ }
100
+ flush();
101
+
102
+ return sections;
103
+ }
104
+
105
+ function extractPrdSection(prdMarkdown, headingNames) {
106
+ if (!prdMarkdown) return null;
107
+ const sections = parseSections(prdMarkdown);
108
+ for (const name of headingNames) {
109
+ if (sections[name]) {
110
+ const trimmed = sections[name].trim();
111
+ if (trimmed) return trimmed;
112
+ }
113
+ }
114
+ return null;
115
+ }
116
+
117
+ function buildDossierMarkdown({
118
+ slug,
119
+ classification,
120
+ createdAt,
121
+ author,
122
+ why,
123
+ what
124
+ }) {
125
+ const fm = [
126
+ '---',
127
+ `feature_slug: ${slug}`,
128
+ `schema_version: "${SCHEMA_VERSION}"`,
129
+ `created_by: ${author}`,
130
+ `created_at: ${createdAt}`,
131
+ 'status: active',
132
+ `classification: ${classification}`,
133
+ `last_updated_by: ${author}`,
134
+ `last_updated_at: ${createdAt}`,
135
+ '---',
136
+ ''
137
+ ].join('\n');
138
+
139
+ const body = [
140
+ '## Why',
141
+ '',
142
+ why || '_(preencher manualmente — PRD não encontrado ou sem seção de Vision/Problem)_',
143
+ '',
144
+ '## What',
145
+ '',
146
+ what || '_(preencher manualmente — PRD não encontrado ou sem seção de Escopo)_',
147
+ '',
148
+ '## Code Map',
149
+ '',
150
+ '```yaml',
151
+ 'files: []',
152
+ 'modules: []',
153
+ 'patterns: []',
154
+ '```',
155
+ '',
156
+ '## Rules & Design-Docs aplicáveis',
157
+ '',
158
+ '_(vazio — populado a partir da Phase 2)_',
159
+ '',
160
+ '## Agent Trail',
161
+ '',
162
+ '_(vazio — populado a partir da Phase 2)_',
163
+ '',
164
+ '## Revision Requests',
165
+ '',
166
+ '_(vazio — populado a partir da Phase 2)_',
167
+ ''
168
+ ].join('\n');
169
+
170
+ return fm + body;
171
+ }
172
+
173
+ async function init({
174
+ slug,
175
+ contextDir,
176
+ classification = 'MEDIUM',
177
+ author = DEFAULT_AUTHOR,
178
+ now = () => new Date(),
179
+ prdContent,
180
+ whyText,
181
+ whatText
182
+ } = {}) {
183
+ if (!isValidSlug(slug)) {
184
+ const err = new Error(`invalid slug (must be kebab-case): ${JSON.stringify(slug)}`);
185
+ err.code = 'EDOSSIERSLUG';
186
+ throw err;
187
+ }
188
+ if (typeof contextDir !== 'string' || !contextDir) {
189
+ throw new TypeError('init: contextDir must be a non-empty string');
190
+ }
191
+
192
+ const dir = featureDir(contextDir, slug);
193
+ const filePath = dossierPath(contextDir, slug);
194
+
195
+ let prd = prdContent;
196
+ if (prd === undefined) {
197
+ const candidate = prdPath(contextDir, slug);
198
+ if (await fileExists(candidate)) {
199
+ prd = await fs.readFile(candidate, 'utf8');
200
+ }
201
+ }
202
+
203
+ const why = whyText !== undefined ? whyText : extractPrdSection(prd, ['Problem', 'Why', 'Vision']);
204
+ const what = whatText !== undefined ? whatText : extractPrdSection(prd, ['Escopo do MVP', 'Scope', 'What']);
205
+
206
+ const createdAt = now().toISOString();
207
+ const markdown = buildDossierMarkdown({
208
+ slug,
209
+ classification,
210
+ createdAt,
211
+ author,
212
+ why,
213
+ what
214
+ });
215
+
216
+ // Validate before writing — fail fast if our own builder produces invalid output.
217
+ const fmValidation = validateFrontmatter({
218
+ feature_slug: slug,
219
+ schema_version: SCHEMA_VERSION,
220
+ created_by: author,
221
+ created_at: createdAt,
222
+ status: 'active',
223
+ classification,
224
+ last_updated_by: author,
225
+ last_updated_at: createdAt
226
+ });
227
+ if (!fmValidation.valid) {
228
+ const err = new Error(`refusing to write invalid dossier: ${fmValidation.errors.join('; ')}`);
229
+ err.code = 'EDOSSIERSCHEMA';
230
+ err.errors = fmValidation.errors;
231
+ throw err;
232
+ }
233
+
234
+ await fs.mkdir(dir, { recursive: true });
235
+ let fh;
236
+ try {
237
+ fh = await fs.open(filePath, 'wx');
238
+ } catch (err) {
239
+ if (err && err.code === 'EEXIST') {
240
+ const e = new Error(`dossier already exists at ${filePath}`);
241
+ e.code = 'EDOSSIEREXISTS';
242
+ e.path = filePath;
243
+ throw e;
244
+ }
245
+ throw err;
246
+ }
247
+ try {
248
+ await fh.writeFile(markdown);
249
+ } finally {
250
+ await fh.close();
251
+ }
252
+
253
+ return { path: filePath, dir, frontmatter: fmValidation, sections: parseSections(markdown) };
254
+ }
255
+
256
+ async function read({ slug, contextDir } = {}) {
257
+ if (!isValidSlug(slug)) {
258
+ const err = new Error(`invalid slug (must be kebab-case): ${JSON.stringify(slug)}`);
259
+ err.code = 'EDOSSIERSLUG';
260
+ throw err;
261
+ }
262
+ const filePath = dossierPath(contextDir, slug);
263
+ let raw;
264
+ try {
265
+ raw = await fs.readFile(filePath, 'utf8');
266
+ } catch (err) {
267
+ if (err && err.code === 'ENOENT') {
268
+ const e = new Error(`dossier not found for slug "${slug}" at ${filePath}`);
269
+ e.code = 'EDOSSIERMISSING';
270
+ e.path = filePath;
271
+ throw e;
272
+ }
273
+ throw err;
274
+ }
275
+
276
+ const fmParse = parseFrontmatter(raw);
277
+ if (!fmParse.ok) {
278
+ const err = new Error(`malformed dossier frontmatter at ${filePath}: ${fmParse.reason}`);
279
+ err.code = 'EDOSSIERPARSE';
280
+ err.path = filePath;
281
+ throw err;
282
+ }
283
+
284
+ // Schema validation — fail loud, never silent.
285
+ assertFrontmatter(fmParse.data);
286
+
287
+ return {
288
+ path: filePath,
289
+ raw,
290
+ frontmatter: fmParse.data,
291
+ sections: parseSections(raw)
292
+ };
293
+ }
294
+
295
+ async function show({ slug, contextDir } = {}) {
296
+ const { raw, frontmatter, sections, path: p } = await read({ slug, contextDir });
297
+
298
+ // Check for corrupted dossier-history.md (if present)
299
+ let historyWarn = null;
300
+ const hp = path.join(path.dirname(p), 'dossier-history.md');
301
+ try {
302
+ const histRaw = await fs.readFile(hp, 'utf8');
303
+ if (typeof histRaw !== 'string') historyWarn = 'history_corrupted';
304
+ } catch (err) {
305
+ if (err && err.code !== 'ENOENT') historyWarn = 'history_corrupted';
306
+ // ENOENT = absent, not corrupted — silently ignore
307
+ }
308
+
309
+ const header = [
310
+ `# Dossier — ${frontmatter.feature_slug} (${frontmatter.classification})`,
311
+ `status=${frontmatter.status} schema=${frontmatter.schema_version} updated=${frontmatter.last_updated_at}`,
312
+ `path: ${p}`,
313
+ ''
314
+ ].join('\n');
315
+ return { header, raw, frontmatter, sections, path: p, warn: historyWarn };
316
+ }
317
+
318
+ // Append-only write to a named ## section in dossier.md.
319
+ // Uses SHA-256 of (section + content) for dedup — repeated calls with same args are no-ops.
320
+ async function addFinding({ slug, contextDir, agent, section, content, now = () => new Date() } = {}) {
321
+ if (!isValidSlug(slug)) {
322
+ const err = new Error(`invalid slug: ${JSON.stringify(slug)}`);
323
+ err.code = 'EDOSSIERSLUG';
324
+ throw err;
325
+ }
326
+ const filePath = dossierPath(contextDir, slug);
327
+ let raw;
328
+ try {
329
+ raw = await fs.readFile(filePath, 'utf8');
330
+ } catch (err) {
331
+ if (err && err.code === 'ENOENT') {
332
+ const e = new Error(`dossier not found for slug "${slug}" at ${filePath}`);
333
+ e.code = 'EDOSSIERMISSING';
334
+ e.path = filePath;
335
+ throw e;
336
+ }
337
+ throw err;
338
+ }
339
+
340
+ const hash = crypto.createHash('sha256').update(`${section}\0${content}`).digest('hex');
341
+ const hashMarker = `<!-- sha256:${hash} -->`;
342
+
343
+ // Idempotency: if hash already present, no-op silently
344
+ if (raw.includes(hashMarker)) {
345
+ return { added: false, hash };
346
+ }
347
+
348
+ const timestamp = now().toISOString();
349
+ const entry = [
350
+ hashMarker,
351
+ `**${timestamp}** | @${agent} | _${section}_`,
352
+ '',
353
+ content.trim(),
354
+ ''
355
+ ].join('\n');
356
+
357
+ // Append inside ## Agent Trail (or after it if not found)
358
+ const lines = raw.split('\n');
359
+ let trailEnd = lines.length;
360
+ let inTrail = false;
361
+
362
+ for (let i = 0; i < lines.length; i++) {
363
+ if (lines[i].trimEnd() === '## Agent Trail') {
364
+ inTrail = true;
365
+ } else if (inTrail && /^## /.test(lines[i])) {
366
+ trailEnd = i;
367
+ break;
368
+ }
369
+ }
370
+
371
+ // Insert before the next section (or at end of file)
372
+ const before = lines.slice(0, trailEnd);
373
+ const after = lines.slice(trailEnd);
374
+
375
+ // Trim trailing blank lines from before to avoid double blanks
376
+ while (before.length > 0 && before[before.length - 1].trim() === '') before.pop();
377
+ before.push('', entry.trimEnd());
378
+
379
+ const rebuilt = [...before, '', ...after].join('\n');
380
+ await fs.writeFile(filePath, rebuilt, 'utf8');
381
+
382
+ return { added: true, hash };
383
+ }
384
+
385
+ module.exports = {
386
+ FEATURES_SUBDIR,
387
+ DOSSIER_FILENAME,
388
+ DEFAULT_AUTHOR,
389
+ REQUIRED_SECTIONS,
390
+ featureDir,
391
+ dossierPath,
392
+ prdPath,
393
+ parseFrontmatter,
394
+ parseSections,
395
+ buildDossierMarkdown,
396
+ addFinding,
397
+ init,
398
+ read,
399
+ show
400
+ };
@@ -220,6 +220,9 @@ async function syncWorkflowRuntime(targetDir, input) {
220
220
  try {
221
221
  const state = input.state || {};
222
222
  const eventPayload = input.eventPayload || {};
223
+ if (!eventPayload.autonomy_mode && eventPayload.autonomyMode) {
224
+ eventPayload.autonomy_mode = eventPayload.autonomyMode;
225
+ }
223
226
  const activationAgent = normalizeText(input.activationAgent);
224
227
  const completedStage = normalizeText(input.completedStage);
225
228
  const sessionKey = makeWorkflowSessionKey(state);
@@ -0,0 +1,202 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * friction-scanner — analyzes workflow error logs to detect recurring friction patterns.
5
+ *
6
+ * Reads .aioson/context/workflow.errors.jsonl and produces structured
7
+ * recommendations for codebase hardening.
8
+ */
9
+
10
+ const path = require('node:path');
11
+ const fs = require('node:fs/promises');
12
+ const { readFileSafe, fileExists } = require('./preflight-engine');
13
+
14
+ const ERRORS_PATH = '.aioson/context/workflow.errors.jsonl';
15
+
16
+ const PATTERNS = [
17
+ {
18
+ id: 'typescript_compile',
19
+ name: 'TypeScript compilation errors',
20
+ test: (err) => /tsc|typescript|type mismatch|cannot find module|unused import/i.test(err)
21
+ },
22
+ {
23
+ id: 'rust_compile',
24
+ name: 'Rust compilation errors',
25
+ test: (err) => /cargo check|rustc|sqlx|actix|tokio/i.test(err)
26
+ },
27
+ {
28
+ id: 'jsx_structure',
29
+ name: 'JSX / React structure errors',
30
+ test: (err) => /jsx|react|component|element type is invalid|nested|display-property/i.test(err)
31
+ },
32
+ {
33
+ id: 'test_mock_order',
34
+ name: 'Mock ordering / test helper issues',
35
+ test: (err) => /vi\.mock|vi\.fn|jest\.mock|mock ordering|hoisted|getByText/i.test(err)
36
+ },
37
+ {
38
+ id: 'ui_text_mismatch',
39
+ name: 'UI text mismatch in tests',
40
+ test: (err) => /confirmar|vincular|button label|tab name|ui text|assertion/i.test(err)
41
+ },
42
+ {
43
+ id: 'git_staging',
44
+ name: 'Git staging accidents',
45
+ test: (err) => /node_modules|build artifact|dev\.db|\.next|unwanted files staged/i.test(err)
46
+ },
47
+ {
48
+ id: 'path_misunderstanding',
49
+ name: 'Path / directory misinterpretation',
50
+ test: (err) => /wrong directory|path misunderstanding|bootstrap|\.aioson\/docs/i.test(err)
51
+ },
52
+ {
53
+ id: 'handoff_contract',
54
+ name: 'Handoff contract violations',
55
+ test: (err) => /handoff contract|missing artifact|gate .* not approved/i.test(err)
56
+ }
57
+ ];
58
+
59
+ async function loadErrors(targetDir) {
60
+ const errorsPath = path.join(targetDir, ERRORS_PATH);
61
+ if (!(await fileExists(errorsPath))) return [];
62
+ const content = await readFileSafe(errorsPath);
63
+ if (!content) return [];
64
+ const lines = content.trim().split('\n').filter(Boolean);
65
+ const entries = [];
66
+ for (const line of lines) {
67
+ try {
68
+ entries.push(JSON.parse(line));
69
+ } catch {
70
+ // ignore malformed lines
71
+ }
72
+ }
73
+ return entries;
74
+ }
75
+
76
+ function classifyError(entry) {
77
+ const text = `${entry.error || ''} ${entry.gateType || ''}`;
78
+ for (const pattern of PATTERNS) {
79
+ if (pattern.test(text)) {
80
+ return pattern.id;
81
+ }
82
+ }
83
+ return 'unknown';
84
+ }
85
+
86
+ async function scanFriction(targetDir) {
87
+ const entries = await loadErrors(targetDir);
88
+ const counts = {};
89
+ const byPattern = {};
90
+ const recent = entries.slice(-20);
91
+
92
+ for (const entry of entries) {
93
+ const pid = classifyError(entry);
94
+ counts[pid] = (counts[pid] || 0) + 1;
95
+ if (!byPattern[pid]) byPattern[pid] = [];
96
+ byPattern[pid].push(entry);
97
+ }
98
+
99
+ const sorted = Object.entries(counts)
100
+ .sort((a, b) => b[1] - a[1])
101
+ .map(([pid, count]) => {
102
+ const pattern = PATTERNS.find((p) => p.id === pid);
103
+ return {
104
+ id: pid,
105
+ name: pattern ? pattern.name : pid,
106
+ count,
107
+ examples: (byPattern[pid] || []).slice(-3).map((e) => e.error?.substring(0, 200) || '')
108
+ };
109
+ });
110
+
111
+ return {
112
+ total: entries.length,
113
+ recentCount: recent.length,
114
+ patterns: sorted
115
+ };
116
+ }
117
+
118
+ function buildRecommendations(analysis) {
119
+ const recs = [];
120
+ for (const p of analysis.patterns) {
121
+ switch (p.id) {
122
+ case 'typescript_compile':
123
+ recs.push({
124
+ pattern: p.name,
125
+ action: 'Enable strict type-checking hooks or add "tsc --noEmit" to pre-commit checks.',
126
+ autoFixable: false,
127
+ priority: p.count >= 3 ? 'high' : 'medium'
128
+ });
129
+ break;
130
+ case 'rust_compile':
131
+ recs.push({
132
+ pattern: p.name,
133
+ action: 'Add "cargo check" as a mandatory step in the dev agent prompt or CI pipeline.',
134
+ autoFixable: false,
135
+ priority: p.count >= 3 ? 'high' : 'medium'
136
+ });
137
+ break;
138
+ case 'jsx_structure':
139
+ recs.push({
140
+ pattern: p.name,
141
+ action: 'Add an ESLint plugin for JSX nesting rules (e.g., eslint-plugin-react).',
142
+ autoFixable: false,
143
+ priority: 'medium'
144
+ });
145
+ break;
146
+ case 'test_mock_order':
147
+ recs.push({
148
+ pattern: p.name,
149
+ action: 'Create a shared mock factory in tests/helpers/mocks.ts and update test conventions.',
150
+ autoFixable: true,
151
+ priority: p.count >= 2 ? 'high' : 'medium'
152
+ });
153
+ break;
154
+ case 'ui_text_mismatch':
155
+ recs.push({
156
+ pattern: p.name,
157
+ action: 'Enforce the test-briefing injection (already active) and add a rule to prefer getByRole.',
158
+ autoFixable: false,
159
+ priority: 'medium'
160
+ });
161
+ break;
162
+ case 'git_staging':
163
+ recs.push({
164
+ pattern: p.name,
165
+ action: 'Ensure .gitignore covers node_modules, dist, .next, *.db and install the pre-commit hook.',
166
+ autoFixable: true,
167
+ priority: 'high'
168
+ });
169
+ break;
170
+ case 'path_misunderstanding':
171
+ recs.push({
172
+ pattern: p.name,
173
+ action: 'Verify project-map.md exists and is loaded by implementation agents (already active).',
174
+ autoFixable: false,
175
+ priority: 'medium'
176
+ });
177
+ break;
178
+ case 'handoff_contract':
179
+ recs.push({
180
+ pattern: p.name,
181
+ action: 'Review agent prompts to ensure they set the correct gates and produce required artifacts.',
182
+ autoFixable: false,
183
+ priority: 'high'
184
+ });
185
+ break;
186
+ default:
187
+ recs.push({
188
+ pattern: p.name,
189
+ action: 'Investigate root cause manually and add a preventive rule.',
190
+ autoFixable: false,
191
+ priority: 'low'
192
+ });
193
+ }
194
+ }
195
+ return recs;
196
+ }
197
+
198
+ module.exports = {
199
+ scanFriction,
200
+ buildRecommendations,
201
+ PATTERNS
202
+ };
@@ -6,6 +6,7 @@ const {
6
6
  GENOME_FORMATS,
7
7
  GENOME_CONFIDENCE_LEVELS,
8
8
  GENOME_TYPES,
9
+ GENOME_RELATION_TYPES,
9
10
  countGenomeSections,
10
11
  normalizeGenome,
11
12
  normalizeGenomeMeta
@@ -79,6 +80,18 @@ function validatePersonaV3Requirements(normalized, sections, errors) {
79
80
  errors.push(`sections.${key} must contain at least one entry for genome-v3 persona profiles`);
80
81
  }
81
82
  }
83
+
84
+ // track 4.0 — optional, validate only if present
85
+ if (normalized.hexacoH && !GENOME_CONFIDENCE_LEVELS.includes(normalized.hexacoH)) {
86
+ errors.push(`hexaco_h must be one of: ${GENOME_CONFIDENCE_LEVELS.join(', ')}`);
87
+ }
88
+ if (Array.isArray(normalized.relations)) {
89
+ for (const rel of normalized.relations) {
90
+ if (rel.type && !GENOME_RELATION_TYPES.includes(rel.type)) {
91
+ errors.push(`relations[].type must be one of: ${GENOME_RELATION_TYPES.join(', ')}`);
92
+ }
93
+ }
94
+ }
82
95
  }
83
96
 
84
97
  function validateGenomeObject(input) {
@@ -155,6 +168,7 @@ function validateGenomeMeta(input) {
155
168
  cognitiveProfile: Array(meta.counts.cognitiveProfile).fill('x'),
156
169
  communicationStyle: Array(meta.counts.communicationStyle).fill('x'),
157
170
  biases: Array(meta.counts.biases).fill('x'),
171
+ traitInteractions: Array(meta.counts.traitInteractions || 0).fill('x'),
158
172
  conflictResolution: Array(meta.counts.conflictResolution).fill('x'),
159
173
  evidence: Array(meta.counts.evidence).fill('x'),
160
174
  applicationNotes: Array(meta.counts.applicationNotes).fill('x')
@@ -168,6 +182,14 @@ function validateGenomeMeta(input) {
168
182
  }
169
183
  if (!meta.createdAt) errors.push('createdAt is required');
170
184
  if (!meta.updatedAt) errors.push('updatedAt is required');
185
+ if (hasOwn(input, 'dependencies') && input.dependencies !== null && typeof input.dependencies === 'object') {
186
+ if ('skills' in input.dependencies && !Array.isArray(input.dependencies.skills)) {
187
+ errors.push('dependencies.skills must be an array of strings');
188
+ }
189
+ if ('genomes' in input.dependencies && !Array.isArray(input.dependencies.genomes)) {
190
+ errors.push('dependencies.genomes must be an array of strings');
191
+ }
192
+ }
171
193
  validatePersonaV3Requirements(
172
194
  {
173
195
  version: meta.version,
@@ -183,7 +205,8 @@ function validateGenomeMeta(input) {
183
205
  {
184
206
  cognitiveProfile: Array(meta.counts.cognitiveProfile).fill('x'),
185
207
  communicationStyle: Array(meta.counts.communicationStyle).fill('x'),
186
- biases: Array(meta.counts.biases).fill('x')
208
+ biases: Array(meta.counts.biases).fill('x'),
209
+ traitInteractions: Array(meta.counts.traitInteractions || 0).fill('x')
187
210
  },
188
211
  errors
189
212
  );