@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/parser.js
CHANGED
|
@@ -19,7 +19,14 @@ function parseArgv(argv) {
|
|
|
19
19
|
// Boolean-only flags that never consume the next token
|
|
20
20
|
const boolOnly = new Set([
|
|
21
21
|
'all', 'force', 'dry-run', 'no-interactive', 'fix', 'json',
|
|
22
|
-
'help', 'version', 'no-launch', 'attach'
|
|
22
|
+
'help', 'version', 'no-launch', 'attach', 'tmux',
|
|
23
|
+
'allow-warnings', 'install-hook', 'uninstall-hook', 'remove-hook',
|
|
24
|
+
'agent-safe',
|
|
25
|
+
'status', 'suggest', 'apply',
|
|
26
|
+
// `--resume` alone means "resume last"; `--resume=<id>` carries a value
|
|
27
|
+
// and is handled by the `=` branch above. Without this entry, `--resume`
|
|
28
|
+
// followed by `--tool=claude` would swallow the next token as its value.
|
|
29
|
+
'resume'
|
|
23
30
|
]);
|
|
24
31
|
|
|
25
32
|
const next = tokens[i + 1];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* path-guard — canonical path resolution helpers for agent prompts.
|
|
5
|
+
*
|
|
6
|
+
* Prevents agents from misplacing files by injecting the project map
|
|
7
|
+
* into implementation agent prompts.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const path = require('node:path');
|
|
11
|
+
const { readFileSafe, fileExists } = require('./preflight-engine');
|
|
12
|
+
|
|
13
|
+
const PROJECT_MAP_PATH = '.aioson/context/project-map.md';
|
|
14
|
+
|
|
15
|
+
const FALLBACK_RULES = `
|
|
16
|
+
## Path Conventions (fallback)
|
|
17
|
+
|
|
18
|
+
- When the user says \`/docs/\`, they mean the project root \`docs/\` folder, not \`.aioson/docs/\`.
|
|
19
|
+
- When the user specifies a target directory, confirm the exact path before creating files.
|
|
20
|
+
- Never replace or remove existing content (log entries, list items, config entries) unless explicitly asked. Only append or modify the targeted item.
|
|
21
|
+
- Framework artifacts (specs, state, handoffs) belong in \`.aioson/context/\`.
|
|
22
|
+
`.trim();
|
|
23
|
+
|
|
24
|
+
async function loadProjectMap(targetDir) {
|
|
25
|
+
const mapPath = path.join(targetDir, PROJECT_MAP_PATH);
|
|
26
|
+
if (await fileExists(mapPath)) {
|
|
27
|
+
const content = await readFileSafe(mapPath);
|
|
28
|
+
if (content) return content.trim();
|
|
29
|
+
}
|
|
30
|
+
return FALLBACK_RULES;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function buildPathGuardBlock(targetDir) {
|
|
34
|
+
const map = await loadProjectMap(targetDir);
|
|
35
|
+
return [
|
|
36
|
+
'## Canonical Path Rules',
|
|
37
|
+
'> Resolve all file paths using the map below. Confirm ambiguous paths with the user before creating files.',
|
|
38
|
+
'',
|
|
39
|
+
map
|
|
40
|
+
].join('\n');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = {
|
|
44
|
+
buildPathGuardBlock,
|
|
45
|
+
loadProjectMap,
|
|
46
|
+
PROJECT_MAP_PATH
|
|
47
|
+
};
|
package/src/preflight-engine.js
CHANGED
|
@@ -145,6 +145,10 @@ function rulesDir(targetDir) {
|
|
|
145
145
|
return path.join(targetDir, '.aioson', 'rules');
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
function designDocsDir(targetDir) {
|
|
149
|
+
return path.join(targetDir, '.aioson', 'design-docs');
|
|
150
|
+
}
|
|
151
|
+
|
|
148
152
|
function artifactPath(targetDir, name, slug) {
|
|
149
153
|
const dir = contextDir(targetDir);
|
|
150
154
|
if (slug) return path.join(dir, `${name}-${slug}.md`);
|
|
@@ -161,6 +165,61 @@ async function loadProjectContext(targetDir) {
|
|
|
161
165
|
return { exists: true, data, content };
|
|
162
166
|
}
|
|
163
167
|
|
|
168
|
+
// ─── Sheldon manifest scanner ─────────────────────────────────────────────────
|
|
169
|
+
|
|
170
|
+
function parseManifestPhaseTable(content) {
|
|
171
|
+
if (!content) return [];
|
|
172
|
+
const phases = [];
|
|
173
|
+
const tableRe = /^\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|$/gm;
|
|
174
|
+
let match;
|
|
175
|
+
let headerPassed = false;
|
|
176
|
+
while ((match = tableRe.exec(content)) !== null) {
|
|
177
|
+
const cols = [match[1], match[2], match[3], match[4]].map((c) => c.trim());
|
|
178
|
+
if (!headerPassed) {
|
|
179
|
+
// Skip header row and separator row
|
|
180
|
+
if (cols[0].toLowerCase() === 'phase' || /^-+$/.test(cols[0])) {
|
|
181
|
+
headerPassed = cols[0].toLowerCase() === 'phase';
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (!headerPassed) continue;
|
|
186
|
+
if (/^-+$/.test(cols[0])) continue;
|
|
187
|
+
const phaseNum = parseInt(cols[0], 10);
|
|
188
|
+
if (!Number.isFinite(phaseNum)) continue;
|
|
189
|
+
phases.push({ phase: phaseNum, file: cols[1].replace(/`/g, ''), status: cols[2], purpose: cols[3] });
|
|
190
|
+
}
|
|
191
|
+
return phases;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async function scanActiveManifest(targetDir, slug) {
|
|
195
|
+
if (!slug) return { exists: false };
|
|
196
|
+
const manifestPath = path.join(targetDir, '.aioson', 'plans', slug, 'manifest.md');
|
|
197
|
+
const stat = await fileStat(manifestPath);
|
|
198
|
+
if (!stat) return { exists: false };
|
|
199
|
+
const content = await readFileSafe(manifestPath);
|
|
200
|
+
const fm = content ? parseFrontmatter(content) : {};
|
|
201
|
+
const status = fm.status || null;
|
|
202
|
+
const isDone = status === 'complete' || status === 'done';
|
|
203
|
+
|
|
204
|
+
// Parse phase table to find the first pending phase (AC-SDLC-27)
|
|
205
|
+
const phases = parseManifestPhaseTable(content);
|
|
206
|
+
const DONE_STATUSES = new Set(['done', 'complete', 'qa_approved', 'completed']);
|
|
207
|
+
const nextPendingPhase = phases.find((p) => !DONE_STATUSES.has(String(p.status).toLowerCase())) || null;
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
exists: true,
|
|
211
|
+
path: `.aioson/plans/${slug}/manifest.md`,
|
|
212
|
+
status,
|
|
213
|
+
is_active: !isDone,
|
|
214
|
+
phases,
|
|
215
|
+
next_pending_phase: nextPendingPhase ? {
|
|
216
|
+
phase: nextPendingPhase.phase,
|
|
217
|
+
file: nextPendingPhase.file,
|
|
218
|
+
status: nextPendingPhase.status
|
|
219
|
+
} : null
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
164
223
|
// ─── Artifact scanner ─────────────────────────────────────────────────────────
|
|
165
224
|
|
|
166
225
|
async function scanArtifacts(targetDir, slug) {
|
|
@@ -305,6 +364,31 @@ async function detectClassification(targetDir, slug) {
|
|
|
305
364
|
|
|
306
365
|
// ─── Rules discovery ──────────────────────────────────────────────────────────
|
|
307
366
|
|
|
367
|
+
function parseAgentList(value) {
|
|
368
|
+
if (value === undefined || value === null) return null;
|
|
369
|
+
const raw = String(value).trim();
|
|
370
|
+
if (!raw) return [];
|
|
371
|
+
if (raw === '[]') return [];
|
|
372
|
+
if (raw.startsWith('[') && raw.endsWith(']')) {
|
|
373
|
+
return raw
|
|
374
|
+
.slice(1, -1)
|
|
375
|
+
.split(',')
|
|
376
|
+
.map((item) => item.trim().replace(/^["']|["']$/g, ''))
|
|
377
|
+
.filter(Boolean);
|
|
378
|
+
}
|
|
379
|
+
return raw
|
|
380
|
+
.split(',')
|
|
381
|
+
.map((item) => item.trim().replace(/^["']|["']$/g, ''))
|
|
382
|
+
.filter(Boolean);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function appliesToAgent(frontmatter, agent) {
|
|
386
|
+
const agents = parseAgentList(frontmatter.agents);
|
|
387
|
+
if (agents === null) return true;
|
|
388
|
+
if (agents.length === 0) return true;
|
|
389
|
+
return agents.includes('all') || agents.includes(agent);
|
|
390
|
+
}
|
|
391
|
+
|
|
308
392
|
async function discoverRules(targetDir, agent) {
|
|
309
393
|
const dir = rulesDir(targetDir);
|
|
310
394
|
const rules = [];
|
|
@@ -318,76 +402,197 @@ async function discoverRules(targetDir, agent) {
|
|
|
318
402
|
|
|
319
403
|
for (const entry of entries) {
|
|
320
404
|
if (!entry.endsWith('.md')) continue;
|
|
405
|
+
if (entry.toLowerCase() === 'readme.md') continue;
|
|
321
406
|
const content = await readFileSafe(path.join(dir, entry));
|
|
322
407
|
if (!content) continue;
|
|
323
408
|
|
|
324
409
|
// Check applicability: universal rules or agent-specific
|
|
325
410
|
const fm = parseFrontmatter(content);
|
|
326
|
-
|
|
327
|
-
if (applies) rules.push(entry);
|
|
411
|
+
if (appliesToAgent(fm, agent)) rules.push(entry);
|
|
328
412
|
}
|
|
329
413
|
|
|
330
|
-
return rules;
|
|
414
|
+
return rules.sort();
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
async function discoverDesignDocs(targetDir, agent) {
|
|
418
|
+
const dir = designDocsDir(targetDir);
|
|
419
|
+
const docs = [];
|
|
420
|
+
|
|
421
|
+
let entries;
|
|
422
|
+
try {
|
|
423
|
+
entries = await fs.readdir(dir);
|
|
424
|
+
} catch {
|
|
425
|
+
return docs;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
for (const entry of entries) {
|
|
429
|
+
if (!entry.endsWith('.md')) continue;
|
|
430
|
+
if (entry.toLowerCase() === 'readme.md') continue;
|
|
431
|
+
const content = await readFileSafe(path.join(dir, entry));
|
|
432
|
+
if (!content) continue;
|
|
433
|
+
|
|
434
|
+
const fm = parseFrontmatter(content);
|
|
435
|
+
if (!appliesToAgent(fm, agent)) continue;
|
|
436
|
+
docs.push(path.join('.aioson', 'design-docs', entry).split(path.sep).join('/'));
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return docs.sort();
|
|
331
440
|
}
|
|
332
441
|
|
|
333
442
|
// ─── Context package builder ──────────────────────────────────────────────────
|
|
334
443
|
|
|
335
|
-
function buildContextPackage(agent, slug, classification, artifacts, devState) {
|
|
444
|
+
function buildContextPackage(agent, slug, classification, artifacts, devState, manifest) {
|
|
336
445
|
const pkg = [];
|
|
337
446
|
|
|
338
447
|
if (artifacts.project_context.exists) pkg.push(artifacts.project_context.path);
|
|
339
448
|
|
|
340
449
|
if (slug) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
if (artifacts.
|
|
450
|
+
const downstreamAgents = ['pm', 'orchestrator', 'dev', 'deyvin', 'qa'];
|
|
451
|
+
const shouldCarryFullFeatureContext = downstreamAgents.includes(agent);
|
|
452
|
+
|
|
453
|
+
if (shouldCarryFullFeatureContext && artifacts.prd.exists) pkg.push(artifacts.prd.path);
|
|
454
|
+
if (shouldCarryFullFeatureContext && artifacts.sheldon_enrichment.exists) pkg.push(artifacts.sheldon_enrichment.path);
|
|
455
|
+
if ((shouldCarryFullFeatureContext || ['analyst', 'architect'].includes(agent)) && artifacts.requirements.exists) {
|
|
345
456
|
pkg.push(artifacts.requirements.path);
|
|
346
457
|
}
|
|
458
|
+
|
|
459
|
+
if (artifacts.spec.exists) pkg.push(artifacts.spec.path);
|
|
460
|
+
|
|
461
|
+
if (shouldCarryFullFeatureContext && artifacts.architecture.exists) pkg.push(artifacts.architecture.path);
|
|
462
|
+
if (shouldCarryFullFeatureContext && artifacts.conformance.exists) pkg.push(artifacts.conformance.path);
|
|
463
|
+
|
|
464
|
+
// Manifest precedence (AC-SDLC-24, AC-SDLC-25):
|
|
465
|
+
// If active Sheldon manifest exists and is not done, it is the primary execution artifact.
|
|
466
|
+
// implementation-plan is supporting context only.
|
|
467
|
+
if (manifest && manifest.exists && manifest.is_active && (agent === 'dev' || agent === 'deyvin')) {
|
|
468
|
+
pkg.push(manifest.path + ' [PRIMARY — active Sheldon manifest]');
|
|
469
|
+
if (manifest.next_pending_phase && manifest.next_pending_phase.file) {
|
|
470
|
+
pkg.push(path.join(path.dirname(manifest.path), manifest.next_pending_phase.file).split(path.sep).join('/') + ' [current phase]');
|
|
471
|
+
}
|
|
472
|
+
if (artifacts.implementation_plan.exists) {
|
|
473
|
+
pkg.push(artifacts.implementation_plan.path + ' [supporting context only]');
|
|
474
|
+
}
|
|
475
|
+
} else if (artifacts.implementation_plan.exists) {
|
|
476
|
+
pkg.push(artifacts.implementation_plan.path);
|
|
477
|
+
}
|
|
347
478
|
}
|
|
348
479
|
|
|
349
480
|
// Agent-specific additions
|
|
350
|
-
if (agent === 'dev' && artifacts.dev_state.exists) pkg.push('dev-state.md (check for
|
|
351
|
-
if (agent === 'qa' && artifacts.spec.exists) pkg.push(artifacts.spec.path);
|
|
481
|
+
if (agent === 'dev' && artifacts.dev_state.exists) pkg.push('dev-state.md (check for stale state before using)');
|
|
352
482
|
if (agent === 'architect' && artifacts.architecture.exists) pkg.push(artifacts.architecture.path);
|
|
353
483
|
|
|
354
484
|
return [...new Set(pkg)];
|
|
355
485
|
}
|
|
356
486
|
|
|
487
|
+
// ─── Stale dev-state detection ───────────────────────────────────────────────
|
|
488
|
+
|
|
489
|
+
function detectStaleDevState(devState, slug) {
|
|
490
|
+
if (!devState.exists) return null;
|
|
491
|
+
if (devState.status === 'done') {
|
|
492
|
+
return `dev-state.md is marked done (feature: ${devState.active_feature || 'unknown'}) — it belongs to a completed session and should not be used as active context`;
|
|
493
|
+
}
|
|
494
|
+
if (slug && devState.active_feature && devState.active_feature !== slug) {
|
|
495
|
+
return `dev-state.md belongs to feature "${devState.active_feature}", not "${slug}" — load the correct dev-state or ignore this one`;
|
|
496
|
+
}
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
|
|
357
500
|
// ─── Readiness evaluator ─────────────────────────────────────────────────────
|
|
358
501
|
|
|
359
|
-
function evaluateReadiness(artifacts, phaseGates, classification, agent) {
|
|
502
|
+
function evaluateReadiness(artifacts, phaseGates, classification, agent, devState, slug) {
|
|
360
503
|
const blockers = [];
|
|
504
|
+
const warnings = [];
|
|
361
505
|
|
|
362
506
|
if (!artifacts.project_context.exists) blockers.push('project.context.md missing');
|
|
363
507
|
|
|
364
|
-
if (agent === '
|
|
508
|
+
if (agent === 'sheldon') {
|
|
509
|
+
if (!artifacts.prd.exists) {
|
|
510
|
+
blockers.push('prd file missing — @product must produce prd-{slug}.md first');
|
|
511
|
+
}
|
|
512
|
+
if (!artifacts.sheldon_enrichment.exists) {
|
|
513
|
+
warnings.push('sheldon-enrichment file not found — this will be a first-session enrichment');
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (agent === 'analyst') {
|
|
518
|
+
if (!artifacts.prd.exists) blockers.push('prd file missing — @product must produce prd-{slug}.md first');
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (agent === 'architect') {
|
|
522
|
+
if (!artifacts.requirements.exists) {
|
|
523
|
+
blockers.push('requirements file missing — @analyst must produce requirements-{slug}.md first (Gate A)');
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (agent === 'pm') {
|
|
528
|
+
if (!artifacts.architecture.exists) {
|
|
529
|
+
blockers.push('architecture.md missing — @architect must complete design first (Gate B)');
|
|
530
|
+
}
|
|
531
|
+
if (!artifacts.requirements.exists) {
|
|
532
|
+
warnings.push('requirements file missing — @pm should review it before writing the implementation plan');
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (agent === 'orchestrator') {
|
|
537
|
+
if (!artifacts.requirements.exists) {
|
|
538
|
+
blockers.push('requirements file missing — Gate A not satisfied');
|
|
539
|
+
}
|
|
540
|
+
if (!artifacts.spec.exists) {
|
|
541
|
+
blockers.push('spec file missing — Gate C not satisfied');
|
|
542
|
+
}
|
|
543
|
+
const implementationPlan = artifacts.implementation_plan || { exists: false, frontmatter: {} };
|
|
544
|
+
if (classification === 'MEDIUM' && !implementationPlan.exists) {
|
|
545
|
+
blockers.push('implementation-plan-{slug}.md missing — @pm must produce it before orchestration');
|
|
546
|
+
} else if (classification === 'MEDIUM' && implementationPlan.frontmatter.status !== 'approved') {
|
|
547
|
+
blockers.push(`implementation plan is not approved: ${implementationPlan.frontmatter.status || 'missing status'} — @pm must approve it`);
|
|
548
|
+
}
|
|
549
|
+
if (phaseGates.plan !== 'approved') {
|
|
550
|
+
blockers.push(`Gate C (plan) not approved: ${phaseGates.plan || 'pending'} — @pm must produce and approve implementation-plan-{slug}.md`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (agent === 'dev' || agent === 'deyvin') {
|
|
365
555
|
if (!artifacts.spec.exists) blockers.push('spec file missing');
|
|
366
|
-
if (
|
|
367
|
-
|
|
556
|
+
if (classification === 'MEDIUM') {
|
|
557
|
+
const implementationPlan = artifacts.implementation_plan || { exists: false, frontmatter: {} };
|
|
558
|
+
if (!implementationPlan.exists) {
|
|
559
|
+
blockers.push('implementation-plan-{slug}.md missing — @pm must produce it before implementation');
|
|
560
|
+
} else if (implementationPlan.frontmatter.status !== 'approved') {
|
|
561
|
+
blockers.push(`implementation plan is not approved: ${implementationPlan.frontmatter.status || 'missing status'}`);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (classification && classification !== 'MICRO') {
|
|
565
|
+
if (phaseGates.plan !== 'approved') {
|
|
566
|
+
blockers.push(`Gate C (plan) not approved: ${phaseGates.plan || 'pending'} — run "aioson gate:check . --feature=${slug || '<slug>'} --gate=C"`);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
// Dev-state stale check
|
|
570
|
+
if (devState) {
|
|
571
|
+
const staleWarning = detectStaleDevState(devState, slug);
|
|
572
|
+
if (staleWarning) warnings.push(`dev-state stale: ${staleWarning}`);
|
|
368
573
|
}
|
|
369
574
|
}
|
|
370
575
|
|
|
371
576
|
if (agent === 'qa') {
|
|
372
577
|
if (!artifacts.spec.exists) blockers.push('spec file missing');
|
|
578
|
+
if (classification === 'MEDIUM') {
|
|
579
|
+
const implementationPlan = artifacts.implementation_plan || { exists: false, frontmatter: {} };
|
|
580
|
+
if (!implementationPlan.exists) {
|
|
581
|
+
blockers.push('implementation-plan-{slug}.md missing');
|
|
582
|
+
} else if (implementationPlan.frontmatter.status !== 'approved') {
|
|
583
|
+
blockers.push(`implementation plan is not approved: ${implementationPlan.frontmatter.status || 'missing status'}`);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
373
586
|
if (classification && classification !== 'MICRO') {
|
|
374
|
-
if (phaseGates.plan
|
|
587
|
+
if (phaseGates.plan !== 'approved') {
|
|
375
588
|
blockers.push(`Gate C (plan) not approved: ${phaseGates.plan || 'pending'}`);
|
|
376
589
|
}
|
|
377
590
|
}
|
|
378
591
|
}
|
|
379
592
|
|
|
380
|
-
if (
|
|
381
|
-
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (agent === 'architect') {
|
|
385
|
-
if (!artifacts.requirements.exists) blockers.push('requirements file missing');
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
return blockers.length === 0
|
|
389
|
-
? { status: 'READY', blockers: [] }
|
|
390
|
-
: { status: 'BLOCKED', blockers };
|
|
593
|
+
if (blockers.length > 0) return { status: 'BLOCKED', blockers, warnings };
|
|
594
|
+
if (warnings.length > 0) return { status: 'READY_WITH_WARNINGS', blockers: [], warnings };
|
|
595
|
+
return { status: 'READY', blockers: [], warnings: [] };
|
|
391
596
|
}
|
|
392
597
|
|
|
393
598
|
// ─── Spec version extractor ───────────────────────────────────────────────────
|
|
@@ -425,17 +630,23 @@ module.exports = {
|
|
|
425
630
|
detectTestRunner,
|
|
426
631
|
contextDir,
|
|
427
632
|
rulesDir,
|
|
633
|
+
designDocsDir,
|
|
428
634
|
artifactPath,
|
|
429
635
|
loadProjectContext,
|
|
430
636
|
scanArtifacts,
|
|
637
|
+
scanActiveManifest,
|
|
431
638
|
parseGatesFromSpec,
|
|
432
639
|
readPhaseGates,
|
|
433
640
|
readDevState,
|
|
434
641
|
readProjectPulse,
|
|
435
642
|
detectClassification,
|
|
643
|
+
parseAgentList,
|
|
644
|
+
appliesToAgent,
|
|
436
645
|
discoverRules,
|
|
646
|
+
discoverDesignDocs,
|
|
437
647
|
buildContextPackage,
|
|
438
648
|
evaluateReadiness,
|
|
649
|
+
detectStaleDevState,
|
|
439
650
|
extractSpecVersion,
|
|
440
651
|
extractLastCheckpoint,
|
|
441
652
|
GATE_NAMES,
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* self-healing — auto-retry state and prompt building for failed agent stages.
|
|
5
|
+
*
|
|
6
|
+
* Keeps retry counters and error logs so `workflow:heal` can re-run a stage
|
|
7
|
+
* with corrective context without human re-prompting.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const path = require('node:path');
|
|
11
|
+
const fs = require('node:fs/promises');
|
|
12
|
+
const { ensureDir } = require('./utils');
|
|
13
|
+
|
|
14
|
+
const MAX_RETRIES = 3;
|
|
15
|
+
const RETRIES_DIR = '.aioson/context/pipeline-retries';
|
|
16
|
+
const ERRORS_PATH = '.aioson/context/workflow.errors.jsonl';
|
|
17
|
+
|
|
18
|
+
async function readJsonlLast(filePath, predicate) {
|
|
19
|
+
try {
|
|
20
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
21
|
+
const lines = content.trim().split('\n').filter(Boolean);
|
|
22
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
23
|
+
const obj = JSON.parse(lines[i]);
|
|
24
|
+
if (!predicate || predicate(obj)) return obj;
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
// ignore read/parse errors
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function getRetryCount(targetDir, stage) {
|
|
33
|
+
const retriesPath = path.join(targetDir, RETRIES_DIR, `${stage}.json`);
|
|
34
|
+
try {
|
|
35
|
+
const raw = await fs.readFile(retriesPath, 'utf8');
|
|
36
|
+
const data = JSON.parse(raw);
|
|
37
|
+
return Number(data.count || 0);
|
|
38
|
+
} catch {
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function incrementRetryCount(targetDir, stage, errorSummary) {
|
|
44
|
+
const retriesPath = path.join(targetDir, RETRIES_DIR, `${stage}.json`);
|
|
45
|
+
await ensureDir(path.dirname(retriesPath));
|
|
46
|
+
const count = await getRetryCount(targetDir, stage);
|
|
47
|
+
const payload = {
|
|
48
|
+
stage,
|
|
49
|
+
count: count + 1,
|
|
50
|
+
lastError: errorSummary || '',
|
|
51
|
+
updatedAt: new Date().toISOString()
|
|
52
|
+
};
|
|
53
|
+
await fs.writeFile(retriesPath, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
|
|
54
|
+
return payload.count;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function logError(targetDir, stage, errorMessage, gateType) {
|
|
58
|
+
const errorsPath = path.join(targetDir, ERRORS_PATH);
|
|
59
|
+
await ensureDir(path.dirname(errorsPath));
|
|
60
|
+
const entry = {
|
|
61
|
+
ts: new Date().toISOString(),
|
|
62
|
+
stage,
|
|
63
|
+
gateType: gateType || 'technical',
|
|
64
|
+
error: errorMessage || ''
|
|
65
|
+
};
|
|
66
|
+
await fs.appendFile(errorsPath, `${JSON.stringify(entry)}\n`, 'utf8');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function getLastError(targetDir, stage) {
|
|
70
|
+
const errorsPath = path.join(targetDir, ERRORS_PATH);
|
|
71
|
+
return readJsonlLast(errorsPath, (obj) => obj.stage === stage);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function canRetry(targetDir, stage) {
|
|
75
|
+
return getRetryCount(targetDir, stage).then((c) => c < MAX_RETRIES);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function buildHealingPrompt(basePrompt, stage, lastError, retryCount) {
|
|
79
|
+
const remaining = MAX_RETRIES - retryCount;
|
|
80
|
+
const healingBlock = [
|
|
81
|
+
'',
|
|
82
|
+
'## 🩹 Self-Healing Context (auto-injected by AIOSON motor)',
|
|
83
|
+
'',
|
|
84
|
+
`> This is retry attempt **${retryCount}** of **${MAX_RETRIES}** for stage @${stage}.`,
|
|
85
|
+
`> **${remaining}** attempt(s) remain before escalation to the user.`,
|
|
86
|
+
'',
|
|
87
|
+
'### Error that caused the previous failure',
|
|
88
|
+
'```',
|
|
89
|
+
lastError.error || 'Unknown error',
|
|
90
|
+
'```',
|
|
91
|
+
'',
|
|
92
|
+
'### Your task now',
|
|
93
|
+
`1. Read the error above carefully.`,
|
|
94
|
+
`2. Identify the root cause in the codebase (files, types, mocks, paths, etc.).`,
|
|
95
|
+
`3. Apply the minimal fix needed to resolve the error.`,
|
|
96
|
+
`4. Re-run the verification command (e.g., \`tsc --noEmit\`, \`cargo check\`, tests) to confirm the fix.`,
|
|
97
|
+
`5. Only then finish the stage.`,
|
|
98
|
+
'',
|
|
99
|
+
'> Do NOT change unrelated code. Focus only on the error shown above.',
|
|
100
|
+
''
|
|
101
|
+
].join('\n');
|
|
102
|
+
|
|
103
|
+
return basePrompt + healingBlock;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function buildHealingActivation(targetDir, state, stage, locale, tool, activateStageFn) {
|
|
107
|
+
const retryCount = await getRetryCount(targetDir, stage);
|
|
108
|
+
const lastError = await getLastError(targetDir, stage);
|
|
109
|
+
|
|
110
|
+
if (!lastError) {
|
|
111
|
+
throw new Error(`No recorded error found for stage @${stage}. Run the stage normally first.`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const baseActivation = await activateStageFn(targetDir, state, locale, tool, stage);
|
|
115
|
+
const healingPrompt = buildHealingPrompt(
|
|
116
|
+
baseActivation.prompt || '',
|
|
117
|
+
stage,
|
|
118
|
+
lastError,
|
|
119
|
+
retryCount + 1
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
...baseActivation,
|
|
124
|
+
prompt: healingPrompt,
|
|
125
|
+
healing: true,
|
|
126
|
+
retryCount: retryCount + 1,
|
|
127
|
+
maxRetries: MAX_RETRIES
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = {
|
|
132
|
+
MAX_RETRIES,
|
|
133
|
+
RETRIES_DIR,
|
|
134
|
+
ERRORS_PATH,
|
|
135
|
+
getRetryCount,
|
|
136
|
+
incrementRetryCount,
|
|
137
|
+
logError,
|
|
138
|
+
getLastError,
|
|
139
|
+
canRetry,
|
|
140
|
+
buildHealingPrompt,
|
|
141
|
+
buildHealingActivation
|
|
142
|
+
};
|