@jaimevalasek/aioson 1.7.0 → 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.
- package/CHANGELOG.md +60 -0
- package/README.md +153 -10
- package/docs/en/cli-reference.md +56 -1
- package/docs/en/i18n.md +18 -18
- package/docs/en/schemas/index.json +10 -0
- package/docs/en/schemas/parallel-assign.schema.json +9 -0
- package/docs/en/schemas/parallel-doctor.schema.json +36 -0
- package/docs/en/schemas/parallel-guard.schema.json +63 -0
- package/docs/en/schemas/parallel-merge.schema.json +84 -0
- package/docs/en/schemas/parallel-status.schema.json +91 -1
- package/docs/integrations/apps-publish-marketplace.md +94 -0
- package/docs/pt/README.md +9 -0
- package/docs/pt/agentes.md +324 -3
- package/docs/pt/clientes-ai.md +7 -3
- package/docs/pt/comandos-cli.md +160 -13
- package/docs/pt/compress-agents.md +304 -0
- package/docs/pt/design-docs-governance.md +59 -0
- package/docs/pt/feature-archive.md +191 -0
- package/docs/pt/genome-3.0-spec.md +115 -4
- package/docs/pt/genome-distribution.md +232 -0
- package/docs/pt/inicio-rapido.md +1 -0
- package/docs/pt/motor-hardening.md +492 -0
- package/docs/pt/runner-system.md +113 -0
- package/package.json +2 -1
- package/src/agent-manifests.js +66 -0
- package/src/agents.js +27 -7
- package/src/autonomy-policy.js +139 -0
- package/src/brain-query.js +161 -0
- package/src/cli.js +1377 -1099
- package/src/commands/agents.js +102 -7
- package/src/commands/artifact-validate.js +33 -4
- package/src/commands/auth.js +272 -0
- package/src/commands/brain-query.js +44 -0
- package/src/commands/briefing.js +344 -0
- package/src/commands/commit-prepare.js +547 -0
- package/src/commands/compress-agents.js +416 -0
- package/src/commands/context-health.js +4 -2
- package/src/commands/context-trim.js +17 -11
- package/src/commands/design-hybrid-options.js +3 -3
- package/src/commands/devlog-process.js +6 -4
- package/src/commands/dossier.js +423 -0
- package/src/commands/feature-archive.js +513 -0
- package/src/commands/feature-close.js +123 -18
- package/src/commands/gate-approve.js +198 -0
- package/src/commands/gate-check.js +24 -5
- package/src/commands/genome-doctor.js +166 -9
- package/src/commands/git-guard.js +170 -0
- package/src/commands/harness.js +121 -0
- package/src/commands/implementation-plan.js +47 -20
- package/src/commands/init.js +6 -2
- package/src/commands/install.js +6 -2
- package/src/commands/live.js +497 -56
- package/src/commands/locale-apply.js +9 -6
- package/src/commands/locale-diff.js +11 -112
- package/src/commands/mcp-doctor.js +2 -1
- package/src/commands/mcp-init.js +4 -10
- package/src/commands/memory.js +234 -0
- package/src/commands/parallel-assign.js +107 -27
- package/src/commands/parallel-doctor.js +416 -3
- package/src/commands/parallel-guard.js +241 -0
- package/src/commands/parallel-init.js +66 -4
- package/src/commands/parallel-merge.js +299 -0
- package/src/commands/parallel-status.js +147 -3
- package/src/commands/preflight.js +63 -4
- package/src/commands/qa-init.js +10 -5
- package/src/commands/revision.js +235 -0
- package/src/commands/scaffold-complete.js +188 -0
- package/src/commands/security-audit.js +275 -0
- package/src/commands/security-scan.js +376 -0
- package/src/commands/self-implement-loop.js +46 -2
- package/src/commands/setup-context.js +11 -10
- package/src/commands/squad-agent-create.js +51 -9
- package/src/commands/squad-investigate.js +53 -0
- package/src/commands/squad-plan.js +33 -1
- package/src/commands/squad-scaffold.js +4 -3
- package/src/commands/squad-score.js +71 -14
- package/src/commands/squad-status.js +22 -1
- package/src/commands/squad-validate.js +93 -2
- package/src/commands/store-genome.js +304 -0
- package/src/commands/store-skill.js +247 -0
- package/src/commands/store-squad.js +431 -0
- package/src/commands/store-system.js +392 -0
- package/src/commands/tool-capabilities.js +63 -0
- package/src/commands/update.js +3 -3
- package/src/commands/verify-gate.js +40 -0
- package/src/commands/workflow-execute.js +644 -155
- package/src/commands/workflow-harden.js +231 -0
- package/src/commands/workflow-heal.js +136 -0
- package/src/commands/workflow-next.js +460 -22
- package/src/commands/workflow-status.js +328 -138
- package/src/commands/workspace.js +144 -0
- package/src/constants.js +55 -75
- package/src/context-memory.js +133 -4
- package/src/context-writer.js +2 -1
- package/src/context.js +32 -2
- package/src/doctor.js +46 -6
- package/src/dossier/codemap-store.js +267 -0
- package/src/dossier/dossier-bootstrap.js +222 -0
- package/src/dossier/dossier-compact.js +159 -0
- package/src/dossier/lock.js +128 -0
- package/src/dossier/revision-store.js +313 -0
- package/src/dossier/schema.js +155 -0
- package/src/dossier/store.js +400 -0
- package/src/execution-gateway.js +3 -0
- package/src/friction-scanner.js +202 -0
- package/src/genome-schema.js +24 -1
- package/src/genomes.js +33 -0
- package/src/handoff-contract.js +363 -0
- package/src/handoff-validator.js +45 -0
- package/src/harness/circuit-breaker.js +135 -0
- package/src/i18n/messages/en.js +317 -22
- package/src/i18n/messages/es.js +259 -18
- package/src/i18n/messages/fr.js +260 -18
- package/src/i18n/messages/pt-BR.js +313 -22
- package/src/install-profile.js +0 -16
- package/src/installer.js +70 -6
- package/src/lib/git-commit-guard.js +691 -0
- package/src/lib/security/artifact-reader.js +167 -0
- package/src/lib/security/exit-codes.js +51 -0
- package/src/lib/security/findings-writer.js +176 -0
- package/src/lib/security/runtime-events.js +77 -0
- package/src/lib/security/secrets-regex.js +115 -0
- package/src/lib/store/security-scan.js +173 -0
- package/src/lib/terminal-checkbox.js +130 -0
- package/src/lib/tmux-launcher.js +163 -0
- package/src/lib/tool-capabilities.js +102 -0
- package/src/locales.js +12 -8
- package/src/parallel-workspace.js +756 -0
- package/src/parser.js +8 -1
- package/src/path-guard.js +47 -0
- package/src/preflight-engine.js +237 -26
- package/src/self-healing.js +142 -0
- package/src/session-handoff.js +111 -1
- package/src/squad/squad-scaffold.js +183 -19
- package/src/test-briefing.js +226 -0
- package/src/updater.js +1 -1
- package/src/utils.js +3 -0
- package/src/workflow-gates.js +185 -0
- package/template/.aioson/agents/analyst.md +76 -130
- package/template/.aioson/agents/architect.md +53 -86
- package/template/.aioson/agents/committer.md +161 -0
- package/template/.aioson/agents/copywriter.md +463 -0
- package/template/.aioson/agents/cypher.md +252 -0
- package/template/.aioson/agents/dev.md +112 -600
- package/template/.aioson/agents/deyvin.md +33 -235
- package/template/.aioson/agents/discover.md +235 -0
- package/template/.aioson/agents/discovery-design-doc.md +17 -252
- package/template/.aioson/agents/genome.md +76 -26
- package/template/.aioson/agents/manifests/analyst.manifest.json +26 -0
- package/template/.aioson/agents/manifests/architect.manifest.json +23 -0
- package/template/.aioson/agents/manifests/committer.manifest.json +23 -0
- package/template/.aioson/agents/manifests/dev.manifest.json +37 -0
- package/template/.aioson/agents/manifests/orchestrator.manifest.json +30 -0
- package/template/.aioson/agents/manifests/pentester.manifest.json +39 -0
- package/template/.aioson/agents/manifests/pm.manifest.json +26 -0
- package/template/.aioson/agents/manifests/product.manifest.json +23 -0
- package/template/.aioson/agents/manifests/qa.manifest.json +25 -0
- package/template/.aioson/agents/manifests/setup.manifest.json +20 -0
- package/template/.aioson/agents/manifests/ux-ui.manifest.json +24 -0
- package/template/.aioson/agents/neo.md +10 -8
- package/template/.aioson/agents/orache.md +2 -6
- package/template/.aioson/agents/orchestrator.md +81 -182
- package/template/.aioson/agents/pentester.md +235 -0
- package/template/.aioson/agents/pm.md +40 -104
- package/template/.aioson/agents/product.md +99 -344
- package/template/.aioson/agents/profiler-enricher.md +57 -6
- package/template/.aioson/agents/profiler-forge.md +17 -7
- package/template/.aioson/agents/profiler-researcher.md +29 -6
- package/template/.aioson/agents/qa.md +165 -410
- package/template/.aioson/agents/setup.md +52 -262
- package/template/.aioson/agents/sheldon.md +122 -754
- package/template/.aioson/agents/site-forge.md +111 -1583
- package/template/.aioson/agents/squad.md +139 -1820
- package/template/.aioson/agents/tester.md +10 -0
- package/template/.aioson/agents/ux-ui.md +103 -645
- package/template/.aioson/agents/validator.md +69 -0
- package/template/.aioson/brains/scripts/query.js +5 -1
- package/template/.aioson/config/autonomy-protocol.json +43 -0
- package/template/.aioson/config.md +43 -15
- package/template/.aioson/constitution.md +36 -33
- package/template/.aioson/context/design-doc.md +136 -0
- package/template/.aioson/context/project-map.md +57 -0
- package/template/.aioson/design-docs/code-reuse.md +48 -0
- package/template/.aioson/design-docs/componentization.md +47 -0
- package/template/.aioson/design-docs/file-size.md +52 -0
- package/template/.aioson/design-docs/folder-structure.md +51 -0
- package/template/.aioson/design-docs/naming.md +54 -0
- package/template/.aioson/docs/LAYERS.md +12 -2
- package/template/.aioson/docs/dev/execution-discipline.md +106 -0
- package/template/.aioson/docs/dev/stack-conventions.md +83 -0
- package/template/.aioson/docs/deyvin/continuity-recovery.md +57 -0
- package/template/.aioson/docs/deyvin/debugging-escalation.md +30 -0
- package/template/.aioson/docs/deyvin/pair-execution.md +44 -0
- package/template/.aioson/docs/deyvin/runtime-handoffs.md +36 -0
- package/template/.aioson/docs/product/conversation-playbook.md +116 -0
- package/template/.aioson/docs/product/prd-contract.md +107 -0
- package/template/.aioson/docs/product/quality-lens.md +57 -0
- package/template/.aioson/docs/product/research-loop.md +65 -0
- package/template/.aioson/docs/sheldon/enrichment-paths.md +134 -0
- package/template/.aioson/docs/sheldon/quality-lens.md +57 -0
- package/template/.aioson/docs/sheldon/research-loop.md +56 -0
- package/template/.aioson/docs/sheldon/web-intelligence.md +75 -0
- package/template/.aioson/docs/site-forge-build.md +195 -0
- package/template/.aioson/docs/site-forge-extraction.md +135 -0
- package/template/.aioson/docs/site-forge-qa.md +155 -0
- package/template/.aioson/docs/site-forge-recon.md +434 -0
- package/template/.aioson/docs/site-forge-transform.md +249 -0
- package/template/.aioson/docs/squad/content-output.md +91 -0
- package/template/.aioson/docs/squad/creation-flow.md +135 -0
- package/template/.aioson/docs/squad/domain-classification.md +117 -0
- package/template/.aioson/docs/squad/genome-bindings.md +47 -0
- package/template/.aioson/docs/squad/package-contract.md +234 -0
- package/template/.aioson/docs/squad/quality-lens.md +56 -0
- package/template/.aioson/docs/squad/research-loop.md +59 -0
- package/template/.aioson/docs/squad/session-operations.md +117 -0
- package/template/.aioson/docs/squad/workflow-quality.md +165 -0
- package/template/.aioson/docs/ux-ui/accessibility-audit.md +55 -0
- package/template/.aioson/docs/ux-ui/audit-mode.md +86 -0
- package/template/.aioson/docs/ux-ui/component-map.md +35 -0
- package/template/.aioson/docs/ux-ui/design-execution.md +111 -0
- package/template/.aioson/docs/ux-ui/design-gate.md +27 -0
- package/template/.aioson/docs/ux-ui/research-mode.md +39 -0
- package/template/.aioson/docs/ux-ui/site-delivery.md +156 -0
- package/template/.aioson/docs/ux-ui/token-contract.md +57 -0
- package/template/.aioson/genomes/copywriting.md +204 -0
- package/template/.aioson/genomes/copywriting.meta.json +48 -0
- package/template/.aioson/git-guard.json +11 -0
- package/template/.aioson/mcp/servers.md +0 -1
- package/template/.aioson/rules/agent-language-policy.md +93 -0
- package/template/.aioson/rules/aioson-context-boundary.md +63 -0
- package/template/.aioson/rules/canonical-path-contract.md +47 -0
- package/template/.aioson/rules/data-format-convention.md +24 -86
- package/template/.aioson/rules/disk-first-artifacts.md +44 -0
- package/template/.aioson/rules/output-brevity.md +44 -0
- package/template/.aioson/rules/prd-section-ownership.md +49 -0
- package/template/.aioson/rules/security-baseline.md +139 -0
- package/template/.aioson/rules/spec-level-ownership.md +61 -0
- package/template/.aioson/rules/squad-driver-pattern.md +81 -0
- package/template/.aioson/schemas/squad-blueprint.schema.json +24 -0
- package/template/.aioson/schemas/squad-manifest.schema.json +44 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/motion.md +2 -0
- package/template/.aioson/skills/marketing/references/anti-patterns.md +254 -0
- package/template/.aioson/skills/marketing/references/fascinations.md +192 -0
- package/template/.aioson/skills/marketing/references/five-acts.md +248 -0
- package/template/.aioson/skills/marketing/references/market-intelligence.md +198 -0
- package/template/.aioson/skills/marketing/references/offer-structure.md +203 -0
- package/template/.aioson/skills/marketing/references/one-belief.md +149 -0
- package/template/.aioson/skills/marketing/references/patterns.md +218 -0
- package/template/.aioson/skills/marketing/references/pms-research.md +193 -0
- package/template/.aioson/skills/marketing/vsl-craft.md +385 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/pm.md +30 -0
- package/template/.aioson/skills/process/secure-tdd/SKILL.md +97 -0
- package/template/.aioson/skills/process/secure-tdd/references/nextjs.md +81 -0
- package/template/.aioson/skills/process/secure-tdd/references/node-express.md +91 -0
- package/template/.aioson/skills/process/secure-tdd/references/planned-stacks.md +33 -0
- package/template/.aioson/skills/static/harness-validate/SKILL.md +46 -0
- package/template/.aioson/skills/static/landing-page-deploy.md +192 -0
- package/template/.aioson/skills/static/landing-page-forge.md +730 -0
- package/template/.aioson/skills/static/ui-ux-modern.md +1 -0
- package/template/.aioson/skills/static/web-research-cache.md +3 -0
- package/template/.aioson/tasks/squad-create.md +56 -7
- package/template/.aioson/tasks/squad-design.md +80 -2
- package/template/.aioson/tasks/squad-investigate.md +14 -1
- package/template/.aioson/templates/squads/digital-marketing-agency/template.json +96 -0
- package/template/.claude/commands/aioson/agent/committer.md +5 -0
- package/template/.claude/commands/aioson/agent/copywriter.md +5 -0
- package/template/.claude/commands/aioson/agent/cypher.md +5 -0
- package/template/.claude/commands/aioson/agent/pair.md +5 -0
- package/template/.claude/commands/aioson/agent/validator.md +5 -0
- package/template/.gemini/commands/aios-analyst.toml +6 -3
- package/template/.gemini/commands/aios-architect.toml +7 -6
- package/template/.gemini/commands/aios-committer.toml +7 -0
- package/template/.gemini/commands/aios-copywriter.toml +7 -0
- package/template/.gemini/commands/aios-cypher.toml +7 -0
- package/template/.gemini/commands/aios-dev.toml +8 -7
- package/template/.gemini/commands/aios-deyvin.toml +6 -5
- package/template/.gemini/commands/aios-discovery-design-doc.toml +6 -3
- package/template/.gemini/commands/aios-genome.toml +7 -0
- package/template/.gemini/commands/aios-neo.toml +5 -3
- package/template/.gemini/commands/aios-orache.toml +7 -0
- package/template/.gemini/commands/aios-orchestrator.toml +8 -7
- package/template/.gemini/commands/aios-pair.toml +6 -5
- package/template/.gemini/commands/aios-pm.toml +8 -7
- package/template/.gemini/commands/aios-product.toml +5 -3
- package/template/.gemini/commands/aios-qa.toml +6 -5
- package/template/.gemini/commands/aios-setup.toml +5 -2
- package/template/.gemini/commands/aios-sheldon.toml +7 -0
- package/template/.gemini/commands/aios-site-forge.toml +7 -0
- package/template/.gemini/commands/aios-squad.toml +7 -0
- package/template/.gemini/commands/aios-tester.toml +6 -5
- package/template/.gemini/commands/aios-ux-ui.toml +8 -7
- package/template/.gemini/commands/aios-validator.toml +7 -0
- package/template/AGENTS.md +12 -1
- package/template/CLAUDE.md +6 -1
- package/template/.aioson/locales/en/agents/analyst.md +0 -244
- package/template/.aioson/locales/en/agents/architect.md +0 -245
- package/template/.aioson/locales/en/agents/dev.md +0 -397
- package/template/.aioson/locales/en/agents/deyvin.md +0 -137
- package/template/.aioson/locales/en/agents/discovery-design-doc.md +0 -27
- package/template/.aioson/locales/en/agents/genome.md +0 -212
- package/template/.aioson/locales/en/agents/neo.md +0 -8
- package/template/.aioson/locales/en/agents/orache.md +0 -6
- package/template/.aioson/locales/en/agents/orchestrator.md +0 -189
- package/template/.aioson/locales/en/agents/pair.md +0 -5
- package/template/.aioson/locales/en/agents/pm.md +0 -84
- package/template/.aioson/locales/en/agents/product.md +0 -378
- package/template/.aioson/locales/en/agents/profiler-enricher.md +0 -5
- package/template/.aioson/locales/en/agents/profiler-forge.md +0 -5
- package/template/.aioson/locales/en/agents/profiler-researcher.md +0 -5
- package/template/.aioson/locales/en/agents/qa.md +0 -270
- package/template/.aioson/locales/en/agents/setup.md +0 -421
- package/template/.aioson/locales/en/agents/sheldon.md +0 -455
- package/template/.aioson/locales/en/agents/squad.md +0 -449
- package/template/.aioson/locales/en/agents/tester.md +0 -6
- package/template/.aioson/locales/en/agents/ux-ui.md +0 -668
- package/template/.aioson/locales/es/agents/analyst.md +0 -225
- package/template/.aioson/locales/es/agents/architect.md +0 -245
- package/template/.aioson/locales/es/agents/dev.md +0 -370
- package/template/.aioson/locales/es/agents/deyvin.md +0 -99
- package/template/.aioson/locales/es/agents/discovery-design-doc.md +0 -21
- package/template/.aioson/locales/es/agents/genome.md +0 -104
- package/template/.aioson/locales/es/agents/neo.md +0 -50
- package/template/.aioson/locales/es/agents/orache.md +0 -105
- package/template/.aioson/locales/es/agents/orchestrator.md +0 -194
- package/template/.aioson/locales/es/agents/pair.md +0 -7
- package/template/.aioson/locales/es/agents/pm.md +0 -90
- package/template/.aioson/locales/es/agents/product.md +0 -372
- package/template/.aioson/locales/es/agents/profiler-enricher.md +0 -7
- package/template/.aioson/locales/es/agents/profiler-forge.md +0 -7
- package/template/.aioson/locales/es/agents/profiler-researcher.md +0 -7
- package/template/.aioson/locales/es/agents/qa.md +0 -198
- package/template/.aioson/locales/es/agents/setup.md +0 -405
- package/template/.aioson/locales/es/agents/sheldon.md +0 -309
- package/template/.aioson/locales/es/agents/squad.md +0 -532
- package/template/.aioson/locales/es/agents/tester.md +0 -9
- package/template/.aioson/locales/es/agents/ux-ui.md +0 -212
- package/template/.aioson/locales/fr/agents/analyst.md +0 -225
- package/template/.aioson/locales/fr/agents/architect.md +0 -245
- package/template/.aioson/locales/fr/agents/dev.md +0 -370
- package/template/.aioson/locales/fr/agents/deyvin.md +0 -99
- package/template/.aioson/locales/fr/agents/discovery-design-doc.md +0 -21
- package/template/.aioson/locales/fr/agents/genome.md +0 -104
- package/template/.aioson/locales/fr/agents/neo.md +0 -50
- package/template/.aioson/locales/fr/agents/orache.md +0 -106
- package/template/.aioson/locales/fr/agents/orchestrator.md +0 -194
- package/template/.aioson/locales/fr/agents/pair.md +0 -7
- package/template/.aioson/locales/fr/agents/pm.md +0 -90
- package/template/.aioson/locales/fr/agents/product.md +0 -372
- package/template/.aioson/locales/fr/agents/profiler-enricher.md +0 -7
- package/template/.aioson/locales/fr/agents/profiler-forge.md +0 -7
- package/template/.aioson/locales/fr/agents/profiler-researcher.md +0 -7
- package/template/.aioson/locales/fr/agents/qa.md +0 -198
- package/template/.aioson/locales/fr/agents/setup.md +0 -405
- package/template/.aioson/locales/fr/agents/sheldon.md +0 -309
- package/template/.aioson/locales/fr/agents/squad.md +0 -532
- package/template/.aioson/locales/fr/agents/tester.md +0 -9
- package/template/.aioson/locales/fr/agents/ux-ui.md +0 -212
- package/template/.aioson/locales/pt-BR/agents/analyst.md +0 -319
- package/template/.aioson/locales/pt-BR/agents/architect.md +0 -284
- package/template/.aioson/locales/pt-BR/agents/dev.md +0 -483
- package/template/.aioson/locales/pt-BR/agents/deyvin.md +0 -184
- package/template/.aioson/locales/pt-BR/agents/discovery-design-doc.md +0 -198
- package/template/.aioson/locales/pt-BR/agents/genome.md +0 -297
- package/template/.aioson/locales/pt-BR/agents/neo.md +0 -208
- package/template/.aioson/locales/pt-BR/agents/orache.md +0 -137
- package/template/.aioson/locales/pt-BR/agents/orchestrator.md +0 -324
- package/template/.aioson/locales/pt-BR/agents/pair.md +0 -5
- package/template/.aioson/locales/pt-BR/agents/pm.md +0 -182
- package/template/.aioson/locales/pt-BR/agents/product.md +0 -466
- package/template/.aioson/locales/pt-BR/agents/profiler-enricher.md +0 -5
- package/template/.aioson/locales/pt-BR/agents/profiler-forge.md +0 -5
- package/template/.aioson/locales/pt-BR/agents/profiler-researcher.md +0 -5
- package/template/.aioson/locales/pt-BR/agents/qa.md +0 -300
- package/template/.aioson/locales/pt-BR/agents/setup.md +0 -533
- package/template/.aioson/locales/pt-BR/agents/sheldon.md +0 -323
- package/template/.aioson/locales/pt-BR/agents/squad.md +0 -1330
- package/template/.aioson/locales/pt-BR/agents/tester.md +0 -449
- package/template/.aioson/locales/pt-BR/agents/ux-ui.md +0 -669
- package/template/.aioson/skills/design-system/components/SKILL.md:Zone.Identifier +0 -0
- package/template/.aioson/skills/design-system/dashboards/SKILL.md:Zone.Identifier +0 -0
- package/template/.aioson/skills/design-system/foundations/SKILL.md:Zone.Identifier +0 -0
- package/template/.aioson/skills/design-system/motion/SKILL.md:Zone.Identifier +0 -0
- package/template/.aioson/skills/design-system/patterns/SKILL.md:Zone.Identifier +0 -0
package/src/session-handoff.js
CHANGED
|
@@ -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
|
-
|
|
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|
|
|
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
|
-
|
|
28
|
-
|
|
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.
|
|
32
|
-
const slots =
|
|
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}
|
|
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
|
-
|
|
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}
|
|
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
|
|
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 (!
|
|
96
|
-
return { ok: false, error: `Invalid mode "${mode}" — use content|
|
|
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, '
|
|
137
|
-
await ensureDir(path.join(base, '
|
|
138
|
-
await ensureDir(path.join(base, '
|
|
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:
|
|
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
|
|