@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
@@ -5,9 +5,11 @@ const path = require('node:path');
5
5
  const { exists, ensureDir } = require('./utils');
6
6
 
7
7
  const HANDOFF_RELATIVE_PATH = '.aioson/context/last-handoff.json';
8
+ const HANDOFF_PROTOCOL_RELATIVE_PATH = '.aioson/context/handoff-protocol.json';
8
9
 
9
10
  async function writeHandoff(targetDir, payload) {
10
11
  const handoffPath = path.join(targetDir, HANDOFF_RELATIVE_PATH);
12
+ const protocolPath = path.join(targetDir, HANDOFF_PROTOCOL_RELATIVE_PATH);
11
13
  await ensureDir(path.dirname(handoffPath));
12
14
  const handoff = {
13
15
  version: 1,
@@ -24,7 +26,16 @@ async function writeHandoff(targetDir, payload) {
24
26
  feature_slug: payload.featureSlug || null
25
27
  };
26
28
  await fs.writeFile(handoffPath, `${JSON.stringify(handoff, null, 2)}\n`, 'utf8');
27
- return { handoffPath: HANDOFF_RELATIVE_PATH, handoff };
29
+
30
+ const protocol = payload.protocol || buildBasicHandoffProtocol(payload);
31
+ await fs.writeFile(protocolPath, `${JSON.stringify(protocol, null, 2)}\n`, 'utf8');
32
+
33
+ return {
34
+ handoffPath: HANDOFF_RELATIVE_PATH,
35
+ protocolPath: HANDOFF_PROTOCOL_RELATIVE_PATH,
36
+ handoff,
37
+ protocol
38
+ };
28
39
  }
29
40
 
30
41
  async function readHandoff(targetDir) {
@@ -38,6 +49,17 @@ async function readHandoff(targetDir) {
38
49
  }
39
50
  }
40
51
 
52
+ async function readHandoffProtocol(targetDir) {
53
+ const protocolPath = path.join(targetDir, HANDOFF_PROTOCOL_RELATIVE_PATH);
54
+ if (!(await exists(protocolPath))) return null;
55
+ try {
56
+ const content = await fs.readFile(protocolPath, 'utf8');
57
+ return JSON.parse(content);
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+
41
63
  function buildWorkflowHandoff(state, completedStage, nextAgent) {
42
64
  const agentLabel = completedStage ? `@${completedStage}` : null;
43
65
  const nextLabel = nextAgent ? `@${nextAgent}` : null;
@@ -58,6 +80,91 @@ function buildWorkflowHandoff(state, completedStage, nextAgent) {
58
80
  };
59
81
  }
60
82
 
83
+ function mapStageToCapability(stageName) {
84
+ const normalized = String(stageName || '').replace(/^@/, '').trim().toLowerCase();
85
+ if (!normalized) return null;
86
+
87
+ const map = {
88
+ setup: 'initialize_project_context',
89
+ product: 'define_product_scope',
90
+ analyst: 'analyze_requirements',
91
+ architect: 'design_architecture',
92
+ 'ux-ui': 'design_ui_spec',
93
+ pm: 'plan_delivery',
94
+ orchestrator: 'coordinate_parallel_work',
95
+ dev: 'implement_feature',
96
+ pentester: 'adversarial_review',
97
+ qa: 'verify_feature',
98
+ committer: 'prepare_commit'
99
+ };
100
+
101
+ return map[normalized] || null;
102
+ }
103
+
104
+ function buildWorkflowHandoffProtocol(state, completedStage, nextAgent, options = {}) {
105
+ const fromAgentId = completedStage || null;
106
+ const toAgentId = nextAgent || null;
107
+ const fromCapability = mapStageToCapability(fromAgentId);
108
+ const toCapability = mapStageToCapability(toAgentId);
109
+
110
+ return {
111
+ version: '1.0',
112
+ protocol_id: `hnd-${fromAgentId || 'init'}-${toAgentId || 'end'}-${Date.now()}`,
113
+ created_at: new Date().toISOString(),
114
+ workflow_mode: state.mode || null,
115
+ classification: state.classification || null,
116
+ feature_slug: state.featureSlug || null,
117
+ from: {
118
+ agent_id: fromAgentId,
119
+ capability_transferred: fromCapability
120
+ },
121
+ to: {
122
+ agent_id: toAgentId,
123
+ capability_required: toCapability
124
+ },
125
+ capabilities_transferred: fromCapability ? [fromCapability] : [],
126
+ artifact_uris: Array.isArray(options.artifactUris) ? options.artifactUris : [],
127
+ gate_status: options.gateStatus && typeof options.gateStatus === 'object' ? options.gateStatus : {},
128
+ autonomy_mode: options.autonomyMode || null,
129
+ validation: {
130
+ handoff_contract_ok: options.handoffContractOk !== false,
131
+ technical_gate_ok: options.technicalGateOk !== false,
132
+ validated_at: new Date().toISOString()
133
+ }
134
+ };
135
+ }
136
+
137
+ function buildBasicHandoffProtocol(payload) {
138
+ const fromAgentId = payload.lastStage ? String(payload.lastStage).replace(/^@/, '') : null;
139
+ const toAgentId = payload.nextAgent ? String(payload.nextAgent).replace(/^@/, '') : null;
140
+ const fromCapability = mapStageToCapability(fromAgentId);
141
+ return {
142
+ version: '1.0',
143
+ protocol_id: `hnd-${fromAgentId || 'init'}-${toAgentId || 'end'}-${Date.now()}`,
144
+ created_at: new Date().toISOString(),
145
+ workflow_mode: payload.workflowMode || null,
146
+ classification: payload.classification || null,
147
+ feature_slug: payload.featureSlug || null,
148
+ from: {
149
+ agent_id: fromAgentId,
150
+ capability_transferred: fromCapability
151
+ },
152
+ to: {
153
+ agent_id: toAgentId,
154
+ capability_required: mapStageToCapability(toAgentId)
155
+ },
156
+ capabilities_transferred: fromCapability ? [fromCapability] : [],
157
+ artifact_uris: Array.isArray(payload.contextFilesUpdated) ? payload.contextFilesUpdated : [],
158
+ gate_status: {},
159
+ autonomy_mode: payload.autonomyMode || null,
160
+ validation: {
161
+ handoff_contract_ok: true,
162
+ technical_gate_ok: true,
163
+ validated_at: new Date().toISOString()
164
+ }
165
+ };
166
+ }
167
+
61
168
  function buildRuntimeLogHandoff(agentName, message, summary) {
62
169
  return {
63
170
  lastAgent: agentName ? `@${agentName.replace(/^@/, '')}` : null,
@@ -70,8 +177,11 @@ function buildRuntimeLogHandoff(agentName, message, summary) {
70
177
 
71
178
  module.exports = {
72
179
  HANDOFF_RELATIVE_PATH,
180
+ HANDOFF_PROTOCOL_RELATIVE_PATH,
73
181
  writeHandoff,
74
182
  readHandoff,
183
+ readHandoffProtocol,
75
184
  buildWorkflowHandoff,
185
+ buildWorkflowHandoffProtocol,
76
186
  buildRuntimeLogHandoff
77
187
  };
@@ -10,7 +10,7 @@
10
10
  * Integrates with state-manager.js for STATE.md generation.
11
11
  *
12
12
  * Usage:
13
- * node squad-scaffold.js --slug=<slug> --name="Name" --mode=content|code|hybrid
13
+ * node squad-scaffold.js --slug=<slug> --name="Name" --mode=content|software|research|mixed
14
14
  */
15
15
 
16
16
  const fs = require('node:fs/promises');
@@ -19,27 +19,94 @@ const stateManager = require('./state-manager');
19
19
 
20
20
  const SQUADS_DIR = path.join('.aioson', 'squads');
21
21
 
22
- // ─── Templates ───────────���─────────────────────────��─────────────────────────
22
+ // ─── Templates ───────────────────────────────────────────────────────────────
23
+
24
+ function normalizeMode(mode) {
25
+ const raw = String(mode || '').trim().toLowerCase();
26
+ if (raw === 'code') return 'software';
27
+ if (raw === 'hybrid') return 'mixed';
28
+ if (raw === 'content' || raw === 'software' || raw === 'research' || raw === 'mixed') {
29
+ return raw;
30
+ }
31
+ return null;
32
+ }
23
33
 
24
34
  function agentsSkeleton(name, mode) {
25
35
  const executorTypes = {
26
36
  content: ['writer', 'editor', 'researcher'],
27
- code: ['developer', 'reviewer', 'tester'],
28
- hybrid: ['researcher', 'developer', 'writer']
37
+ software: ['developer', 'reviewer', 'tester'],
38
+ research: ['researcher', 'analyst', 'reviewer'],
39
+ mixed: ['researcher', 'developer', 'writer']
29
40
  };
30
41
 
31
- const types = executorTypes[mode] || executorTypes.hybrid;
32
- const slots = types.map((t) => `### ${t}\n- **Role:** (define)\n- **Tools:** (define)\n- **Checklist:** (define)`);
42
+ const types = executorTypes[mode] || executorTypes.mixed;
43
+ const slots = [
44
+ '## Mission',
45
+ '(define the squad mission here)',
46
+ '',
47
+ '## Does',
48
+ '- (define the main responsibilities)',
49
+ '',
50
+ '## Does not',
51
+ '- (define explicit out-of-scope boundaries)',
52
+ '',
53
+ '## Permanent executors',
54
+ '- @orquestrador — coordinates work, routes requests, and synthesizes outputs',
55
+ ...types.map((t) => `- @${t} — (define role)`),
56
+ '',
57
+ '## Squad skills',
58
+ '- (declare reusable skills when they exist)',
59
+ '',
60
+ '## Squad MCPs',
61
+ '- (declare MCPs when they exist)',
62
+ '',
63
+ '## Subagent policy',
64
+ '- (define when temporary subagents are allowed)',
65
+ '',
66
+ '## Outputs and review',
67
+ '- (define output locations and review policy)'
68
+ ];
33
69
 
34
- return `# ${name} — Agent Roster\n\n${slots.join('\n\n')}\n`;
70
+ return `# Squad ${name}\n\n${slots.join('\n')}\n`;
35
71
  }
36
72
 
37
73
  function manifestSkeleton(slug, name, mode) {
74
+ const rootDir = `${SQUADS_DIR}/${slug}`;
38
75
  return JSON.stringify({
76
+ schemaVersion: '1.0.0',
77
+ packageVersion: '1.0.0',
39
78
  slug,
40
79
  name,
41
80
  mode,
42
- created_at: new Date().toISOString(),
81
+ mission: `Define the mission for ${name}.`,
82
+ goal: `Define the goal for ${name}.`,
83
+ visibility: 'private',
84
+ locale_scope: 'universal',
85
+ storagePolicy: {
86
+ primary: 'file',
87
+ artifacts: `output/${slug}/`,
88
+ exports: {
89
+ html: true,
90
+ markdown: true,
91
+ json: true
92
+ }
93
+ },
94
+ package: {
95
+ rootDir,
96
+ agentsDir: `${rootDir}/agents`,
97
+ workersDir: `${rootDir}/workers`,
98
+ workflowsDir: `${rootDir}/workflows`,
99
+ checklistsDir: `${rootDir}/checklists`,
100
+ skillsDir: `${rootDir}/skills`,
101
+ templatesDir: `${rootDir}/templates`,
102
+ docsDir: `${rootDir}/docs`
103
+ },
104
+ rules: {
105
+ outputsDir: `output/${slug}`,
106
+ logsDir: `aioson-logs/${slug}`,
107
+ mediaDir: `media/${slug}`,
108
+ reviewPolicy: []
109
+ },
43
110
  budget: {
44
111
  max_tokens_per_session: null,
45
112
  max_tokens_per_task: null,
@@ -54,12 +121,66 @@ function manifestSkeleton(slug, name, mode) {
54
121
  anti_loop: {
55
122
  threshold: 8,
56
123
  action: 'feedback'
57
- }
124
+ },
125
+ skills: [],
126
+ mcps: [],
127
+ subagents: [],
128
+ contentBlueprints: [],
129
+ executors: [
130
+ {
131
+ slug: 'orquestrador',
132
+ title: 'Orquestrador',
133
+ type: 'agent',
134
+ role: 'Coordinate the squad execution and synthesize specialist outputs.',
135
+ file: `${rootDir}/agents/orquestrador.md`,
136
+ usesLLM: true,
137
+ deterministic: false,
138
+ modelTier: 'balanced',
139
+ skills: [],
140
+ genomes: []
141
+ }
142
+ ],
143
+ checklists: [
144
+ {
145
+ slug: 'quality',
146
+ title: 'Quality Checklist',
147
+ file: `${rootDir}/checklists/quality.md`
148
+ }
149
+ ],
150
+ workflows: [
151
+ {
152
+ slug: 'default',
153
+ title: 'Default Workflow',
154
+ file: `${rootDir}/workflows/default.md`,
155
+ phases: []
156
+ }
157
+ ],
158
+ genomes: [],
159
+ created_at: new Date().toISOString()
58
160
  }, null, 2);
59
161
  }
60
162
 
61
- function squadMdSkeleton(name, mode) {
62
- return `# ${name}\n\n## Overview\n(describe the squad's purpose)\n\n## Mode\n${mode}\n\n## Executors\nSee agents/agents.md\n\n## Workflows\n(define execution workflows)\n\n## Quality Gates\nSee checklists/quality.md\n`;
163
+ function squadMdSkeleton(slug, name, mode) {
164
+ return `# ${name}
165
+
166
+ Mode: ${mode}
167
+ Goal: (define the squad goal)
168
+ Agents: .aioson/squads/${slug}/agents
169
+ Manifest: .aioson/squads/${slug}/squad.manifest.json
170
+ Output: output/${slug}
171
+ Logs: aioson-logs/${slug}
172
+ Media: media/${slug}
173
+ LatestSession: output/${slug}/latest.html
174
+
175
+ ## Skills
176
+ - (declare squad-level skills here)
177
+
178
+ ## MCPs
179
+ - (declare MCPs here)
180
+
181
+ ## SubagentPolicy
182
+ - (define temporary subagent rules)
183
+ `;
63
184
  }
64
185
 
65
186
  function designDocSkeleton(name) {
@@ -78,6 +199,47 @@ function learningsIndexSkeleton(name) {
78
199
  return `# ${name} — Learnings Index\n\nsession_count: 0\n\n## Extracted Learnings\n*(populated automatically by learning-extractor after sessions)*\n\n## Manual Observations\n*(add observations here)*\n`;
79
200
  }
80
201
 
202
+ function orchestratorSkeleton(name, slug) {
203
+ return `# Agent @orquestrador
204
+
205
+ > ⚡ **ACTIVATED** — Execute immediately as @orquestrador.
206
+
207
+ ## Mission
208
+ Coordinate the ${name} squad, route requests to the right executor, and synthesize the final output.
209
+
210
+ ## Quick context
211
+ Squad: ${name} | Slug: ${slug}
212
+
213
+ ## Focus
214
+ - Route work to the right specialist
215
+ - Protect scope and output quality
216
+ - Keep workflows, reviews, and hand-offs coherent
217
+
218
+ ## Hard constraints
219
+ - Respect the squad manifest and package contract
220
+ - Do not absorb specialist work silently when routing is required
221
+ - Keep user-facing interaction aligned with the squad locale policy
222
+
223
+ ## Output contract
224
+ - Primary synthesis: .aioson/squads/${slug}/docs/design-doc.md
225
+ - Session deliverables: output/${slug}/
226
+ `;
227
+ }
228
+
229
+ function workflowSkeleton(name) {
230
+ return `# Workflow: default
231
+
232
+ ## Goal
233
+ Default execution flow for ${name}.
234
+
235
+ ## Phases
236
+ 1. Intake
237
+ 2. Execution
238
+ 3. Review
239
+ 4. Final synthesis
240
+ `;
241
+ }
242
+
81
243
  // ─── Public API ──────────────────────────────────────────────────────────────
82
244
 
83
245
  /**
@@ -88,12 +250,13 @@ function learningsIndexSkeleton(name) {
88
250
  * @returns {Promise<object>} — { ok, slug, files, directories }
89
251
  */
90
252
  async function scaffoldSquad(projectDir, options = {}) {
91
- const { slug, name, mode = 'hybrid' } = options;
253
+ const { slug, name } = options;
254
+ const mode = normalizeMode(options.mode || 'mixed');
92
255
 
93
256
  if (!slug) return { ok: false, error: 'slug is required' };
94
257
  if (!name) return { ok: false, error: 'name is required' };
95
- if (!['content', 'code', 'hybrid'].includes(mode)) {
96
- return { ok: false, error: `Invalid mode "${mode}" — use content|code|hybrid` };
258
+ if (!mode) {
259
+ return { ok: false, error: `Invalid mode "${options.mode}" — use content|software|research|mixed` };
97
260
  }
98
261
 
99
262
  const squadDir = path.join(projectDir, SQUADS_DIR, slug);
@@ -125,18 +288,19 @@ async function scaffoldSquad(projectDir, options = {}) {
125
288
 
126
289
  // Squad directory files
127
290
  await writeFile(path.join(base, 'agents', 'agents.md'), agentsSkeleton(name, mode));
291
+ await writeFile(path.join(base, 'agents', 'orquestrador.md'), orchestratorSkeleton(name, slug));
128
292
  await writeFile(path.join(base, 'squad.manifest.json'), manifestSkeleton(slug, name, mode));
129
- await writeFile(path.join(base, 'squad.md'), squadMdSkeleton(name, mode));
293
+ await writeFile(path.join(base, 'squad.md'), squadMdSkeleton(slug, name, mode));
130
294
  await writeFile(path.join(base, 'docs', 'design-doc.md'), designDocSkeleton(name));
131
295
  await writeFile(path.join(base, 'docs', 'readiness.md'), readinessSkeleton(name));
132
296
  await writeFile(path.join(base, 'checklists', 'quality.md'), qualitySkeleton(name));
133
297
  await writeFile(path.join(base, 'learnings', 'index.md'), learningsIndexSkeleton(name));
298
+ await writeFile(path.join(base, 'workflows', 'default.md'), workflowSkeleton(name));
134
299
 
135
300
  // Empty directories
136
- await ensureDir(path.join(base, 'workflows'));
137
- await ensureDir(path.join(base, 'scripts'));
138
- await ensureDir(path.join(base, 'script-plans'));
139
- await ensureDir(path.join(base, 'bus'));
301
+ await ensureDir(path.join(base, 'workers'));
302
+ await ensureDir(path.join(base, 'skills'));
303
+ await ensureDir(path.join(base, 'templates'));
140
304
 
141
305
  // Output directories
142
306
  await ensureDir(path.join('output', slug));
@@ -0,0 +1,226 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * test-briefing — auto-generate test context for @qa and @tester agents.
5
+ *
6
+ * Reduces friction from:
7
+ * - wrong UI text assertions (mock strings, button labels)
8
+ * - mock ordering bugs
9
+ * - incorrect test patterns
10
+ *
11
+ * Scans the project for:
12
+ * - existing test helpers / mock factories
13
+ * - recent test files to use as templates
14
+ * - UI text strings from components referenced in the spec
15
+ */
16
+
17
+ const path = require('node:path');
18
+ const fs = require('node:fs/promises');
19
+ const { readFileSafe, fileExists } = require('./preflight-engine');
20
+
21
+ const MAX_MOCK_FILES = 5;
22
+ const MAX_COMPONENT_FILES = 8;
23
+ const MAX_TEST_FILES = 4;
24
+
25
+ async function findFiles(targetDir, patterns, maxDepth = 4) {
26
+ const found = [];
27
+ async function walk(dir, depth) {
28
+ if (depth > maxDepth || found.length >= patterns.max) return;
29
+ let entries;
30
+ try {
31
+ entries = await fs.readdir(dir, { withFileTypes: true });
32
+ } catch {
33
+ return;
34
+ }
35
+ for (const entry of entries) {
36
+ if (entry.name.startsWith('.')) continue;
37
+ const full = path.join(dir, entry.name);
38
+ if (entry.isDirectory()) {
39
+ if (entry.name === 'node_modules' || entry.name === 'dist' || entry.name === 'build' || entry.name === '.aioson') continue;
40
+ await walk(full, depth + 1);
41
+ } else if (patterns.test(entry.name)) {
42
+ found.push(full);
43
+ if (found.length >= patterns.max) return;
44
+ }
45
+ }
46
+ }
47
+ await walk(targetDir, 0);
48
+ return found;
49
+ }
50
+
51
+ async function findMockHelpers(targetDir) {
52
+ // Look for common mock/helper patterns
53
+ const candidates = [
54
+ path.join(targetDir, 'tests', 'helpers', 'mocks.ts'),
55
+ path.join(targetDir, 'tests', 'helpers', 'mocks.js'),
56
+ path.join(targetDir, 'test', 'helpers', 'mocks.ts'),
57
+ path.join(targetDir, 'test', 'helpers', 'mocks.js'),
58
+ path.join(targetDir, 'src', '__mocks__', 'index.ts'),
59
+ path.join(targetDir, 'src', '__mocks__', 'index.js'),
60
+ path.join(targetDir, '__mocks__', 'index.ts'),
61
+ path.join(targetDir, '__mocks__', 'index.js'),
62
+ ];
63
+ const found = [];
64
+ for (const p of candidates) {
65
+ if (await fileExists(p)) found.push(p);
66
+ }
67
+ return found;
68
+ }
69
+
70
+ async function findRecentTestFiles(targetDir) {
71
+ const files = await findFiles(targetDir, {
72
+ test: (name) => /\.(test|spec)\.(js|jsx|ts|tsx)$/.test(name),
73
+ max: 20
74
+ });
75
+ // Sort by mtime descending, keep top N
76
+ const withStat = [];
77
+ for (const f of files) {
78
+ try {
79
+ const stat = await fs.stat(f);
80
+ withStat.push({ path: f, mtime: stat.mtime });
81
+ } catch { /* ignore */ }
82
+ }
83
+ withStat.sort((a, b) => b.mtime - a.mtime);
84
+ return withStat.slice(0, MAX_TEST_FILES).map((x) => x.path);
85
+ }
86
+
87
+ async function findComponentFiles(targetDir) {
88
+ // Heuristic: look in src/ for .tsx/.jsx files that are not tests
89
+ const files = await findFiles(path.join(targetDir, 'src'), {
90
+ test: (name) => /\.(tsx|jsx)$/.test(name) && !/(test|spec)\./.test(name),
91
+ max: 30
92
+ });
93
+ // Prefer files modified recently (likely part of the current feature)
94
+ const withStat = [];
95
+ for (const f of files) {
96
+ try {
97
+ const stat = await fs.stat(f);
98
+ withStat.push({ path: f, mtime: stat.mtime });
99
+ } catch { /* ignore */ }
100
+ }
101
+ withStat.sort((a, b) => b.mtime - a.mtime);
102
+ return withStat.slice(0, MAX_COMPONENT_FILES).map((x) => x.path);
103
+ }
104
+
105
+ function extractUiStrings(content) {
106
+ // Extract text inside JSX/TSX that looks user-facing
107
+ // Pattern 1: string literals inside tags > "text" or {'text'}
108
+ const strings = [];
109
+ const tagTextRe = />([^<>{}]{2,80})</g;
110
+ let m;
111
+ while ((m = tagTextRe.exec(content)) !== null) {
112
+ const text = m[1].trim();
113
+ if (text && !text.startsWith('{') && !text.endsWith('}')) {
114
+ strings.push(text);
115
+ }
116
+ }
117
+ // Pattern 2: placeholder="..." label="..." title="..." aria-label="..."
118
+ const attrRe = /(?:placeholder|label|title|aria-label|aria-labelledby|alt|helperText|errorText)\s*=\s*["']([^"']{1,80})["']/g;
119
+ while ((m = attrRe.exec(content)) !== null) {
120
+ strings.push(m[1].trim());
121
+ }
122
+ // Deduplicate and limit
123
+ return [...new Set(strings)].slice(0, 40);
124
+ }
125
+
126
+ function extractMockPatterns(content) {
127
+ const patterns = [];
128
+ // Look for vi.mock / vi.fn / jest.mock / jest.fn patterns
129
+ const mockRe = /^(?:\s*)(vi|jest)\.(mock|fn)\s*\(/gm;
130
+ let m;
131
+ while ((m = mockRe.exec(content)) !== null) {
132
+ const lineStart = content.lastIndexOf('\n', m.index) + 1;
133
+ const lineEnd = content.indexOf('\n', m.index);
134
+ const line = content.slice(lineStart, lineEnd === -1 ? undefined : lineEnd).trim();
135
+ patterns.push(line);
136
+ }
137
+ return patterns.slice(0, 20);
138
+ }
139
+
140
+ async function buildTestBriefing(targetDir) {
141
+ const lines = [];
142
+ lines.push('## Auto-generated Test Context (motor do AIOSON)');
143
+ lines.push('');
144
+
145
+ // 1. Mock helpers
146
+ const mockHelpers = await findMockHelpers(targetDir);
147
+ if (mockHelpers.length > 0) {
148
+ lines.push('### Shared mock helpers found');
149
+ for (const p of mockHelpers) {
150
+ const rel = path.relative(targetDir, p);
151
+ lines.push(`- ${rel}`);
152
+ }
153
+ lines.push('> Use these helpers instead of writing ad-hoc mocks. This prevents ordering bugs.');
154
+ lines.push('');
155
+ }
156
+
157
+ // 2. Recent test templates
158
+ const recentTests = await findRecentTestFiles(targetDir);
159
+ if (recentTests.length > 0) {
160
+ lines.push('### Recent test files (use as templates for patterns)');
161
+ for (const p of recentTests) {
162
+ const rel = path.relative(targetDir, p);
163
+ lines.push(`- ${rel}`);
164
+ }
165
+ lines.push('> Reference these files for mock ordering, assertion style, and helpers before writing new tests.');
166
+ lines.push('');
167
+ }
168
+
169
+ // 3. Mock patterns from recent tests
170
+ if (recentTests.length > 0) {
171
+ const mockPatterns = [];
172
+ for (const p of recentTests.slice(0, 2)) {
173
+ const content = await readFileSafe(p);
174
+ if (content) {
175
+ mockPatterns.push(...extractMockPatterns(content));
176
+ }
177
+ }
178
+ if (mockPatterns.length > 0) {
179
+ lines.push('### Common mock patterns in this project');
180
+ for (const pat of [...new Set(mockPatterns)].slice(0, 10)) {
181
+ lines.push(`- \`${pat}\``);
182
+ }
183
+ lines.push('');
184
+ }
185
+ }
186
+
187
+ // 4. UI text strings from recent components
188
+ const components = await findComponentFiles(targetDir);
189
+ if (components.length > 0) {
190
+ const allStrings = [];
191
+ for (const p of components) {
192
+ const content = await readFileSafe(p);
193
+ if (content) {
194
+ const strings = extractUiStrings(content);
195
+ if (strings.length > 0) {
196
+ allStrings.push({ file: path.relative(targetDir, p), strings });
197
+ }
198
+ }
199
+ }
200
+ if (allStrings.length > 0) {
201
+ lines.push('### UI text strings from recent components');
202
+ lines.push('> Verify exact strings before using them in assertions. Prefer `getByRole` over `getByText` when possible.');
203
+ for (const item of allStrings.slice(0, MAX_COMPONENT_FILES)) {
204
+ lines.push(`\n**${item.file}:**`);
205
+ for (const s of item.strings.slice(0, 12)) {
206
+ lines.push(`- "${s}"`);
207
+ }
208
+ }
209
+ lines.push('');
210
+ }
211
+ }
212
+
213
+ // 5. Testing conventions reminder
214
+ lines.push('### Testing conventions');
215
+ lines.push('- Verify exact UI text strings against component source before using them in assertions.');
216
+ lines.push('- Use `getByRole` over `getByText` when possible.');
217
+ lines.push('- If using `vi.mock`, ensure deterministic ordering (mock factories > mock implementations).');
218
+ lines.push('- Reference existing test files as templates for assertion style and helper usage.');
219
+ lines.push('');
220
+
221
+ return lines.join('\n');
222
+ }
223
+
224
+ module.exports = {
225
+ buildTestBriefing
226
+ };
package/src/updater.js CHANGED
@@ -23,7 +23,7 @@ async function updateInstallation(targetDir, options = {}) {
23
23
  mode: 'update',
24
24
  backupOnOverwrite: true,
25
25
  frameworkDetection: options.frameworkDetection || null,
26
- installProfile: null,
26
+ installProfile: savedProfile,
27
27
  selectiveUpdate: !options.all
28
28
  });
29
29
 
package/src/utils.js CHANGED
@@ -33,6 +33,9 @@ function nowStamp() {
33
33
 
34
34
  function toRelativeSafe(baseDir, absolutePath) {
35
35
  const rel = path.relative(baseDir, absolutePath);
36
+ if (rel.startsWith('..')) {
37
+ throw new Error(`Path traversal detected: "${absolutePath}" escapes base "${baseDir}"`);
38
+ }
36
39
  return rel.split(path.sep).join('/');
37
40
  }
38
41