@jaimevalasek/aioson 1.7.2 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -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 +42 -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/cypher.md +252 -0
- package/template/.aioson/agents/dev.md +112 -628
- package/template/.aioson/agents/deyvin.md +33 -236
- 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 +5 -7
- 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 +168 -514
- package/template/.aioson/agents/setup.md +52 -278
- package/template/.aioson/agents/sheldon.md +122 -754
- package/template/.aioson/agents/site-forge.md +111 -1583
- package/template/.aioson/agents/squad.md +139 -2010
- package/template/.aioson/agents/tester.md +10 -0
- package/template/.aioson/agents/ux-ui.md +104 -812
- 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.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/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/web-research-cache.md +3 -0
- package/template/.aioson/tasks/squad-create.md +35 -8
- package/template/.aioson/tasks/squad-design.md +50 -2
- package/template/.aioson/tasks/squad-investigate.md +14 -1
- 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 +5 -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
|
@@ -3,11 +3,22 @@
|
|
|
3
3
|
const fs = require('node:fs/promises');
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
const { getAgentDefinition, resolveInstructionPath, buildAgentPrompt } = require('../agents');
|
|
6
|
-
const {
|
|
7
|
-
const { validateProjectContextFile } = require('../context');
|
|
6
|
+
const { normalizeInteractionLanguage } = require('../locales');
|
|
7
|
+
const { validateProjectContextFile, getInteractionLanguage } = require('../context');
|
|
8
8
|
const { exists, ensureDir } = require('../utils');
|
|
9
9
|
const { syncWorkflowRuntime } = require('../execution-gateway');
|
|
10
|
-
const { writeHandoff, buildWorkflowHandoff } = require('../session-handoff');
|
|
10
|
+
const { writeHandoff, buildWorkflowHandoff, buildWorkflowHandoffProtocol } = require('../session-handoff');
|
|
11
|
+
const { runTechnicalGate, formatGateError } = require('../workflow-gates');
|
|
12
|
+
const { buildTestBriefing } = require('../test-briefing');
|
|
13
|
+
const { validateHandoffContract, formatContractError, getBlockingRevisions } = require('../handoff-contract');
|
|
14
|
+
const { buildPathGuardBlock } = require('../path-guard');
|
|
15
|
+
const { logError, buildHealingPrompt } = require('../self-healing');
|
|
16
|
+
const { validateHandoffProtocol } = require('../handoff-validator');
|
|
17
|
+
const { readAutonomyProtocol, resolveEffectiveMode } = require('../autonomy-policy');
|
|
18
|
+
const { readAgentManifest, buildAgentCapabilitySummary } = require('../agent-manifests');
|
|
19
|
+
const { inspectStagedChanges } = require('../lib/git-commit-guard');
|
|
20
|
+
const { emitSecurityRuntimeEvent } = require('../lib/security/runtime-events');
|
|
21
|
+
const { runSecurityAudit } = require('./security-audit');
|
|
11
22
|
|
|
12
23
|
const STATE_RELATIVE_PATH = '.aioson/context/workflow.state.json';
|
|
13
24
|
const CONFIG_RELATIVE_PATH = '.aioson/context/workflow.config.json';
|
|
@@ -16,7 +27,7 @@ const EVENTS_RELATIVE_PATH = '.aioson/context/workflow.events.jsonl';
|
|
|
16
27
|
const DEFAULT_FEATURE_WORKFLOW_BY_CLASSIFICATION = {
|
|
17
28
|
MICRO: ['product', 'dev', 'qa'],
|
|
18
29
|
SMALL: ['product', 'analyst', 'dev', 'qa'],
|
|
19
|
-
MEDIUM: ['product', 'analyst', 'dev', 'qa']
|
|
30
|
+
MEDIUM: ['product', 'analyst', 'dev', 'pentester', 'qa']
|
|
20
31
|
};
|
|
21
32
|
|
|
22
33
|
function normalizeAgentName(input) {
|
|
@@ -63,7 +74,8 @@ function parseFeaturesMarkdown(markdown) {
|
|
|
63
74
|
started: parts[3],
|
|
64
75
|
completed: parts[4]
|
|
65
76
|
}))
|
|
66
|
-
.filter((row) => row.slug && row.slug !== 'slug')
|
|
77
|
+
.filter((row) => row.slug && row.slug !== 'slug')
|
|
78
|
+
.filter((row) => !/^-+$/ .test(row.slug));
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
async function readJsonIfExists(filePath) {
|
|
@@ -155,11 +167,11 @@ async function readWorkflowConfig(targetDir) {
|
|
|
155
167
|
|
|
156
168
|
async function resolveLocaleForTarget(targetDir, options) {
|
|
157
169
|
const fromOption = options.language || options.lang;
|
|
158
|
-
if (fromOption) return
|
|
170
|
+
if (fromOption) return normalizeInteractionLanguage(fromOption);
|
|
159
171
|
|
|
160
172
|
const context = await validateProjectContextFile(targetDir);
|
|
161
|
-
if (context.parsed && context.data
|
|
162
|
-
return
|
|
173
|
+
if (context.parsed && context.data) {
|
|
174
|
+
return getInteractionLanguage(context.data, 'en');
|
|
163
175
|
}
|
|
164
176
|
|
|
165
177
|
return 'en';
|
|
@@ -270,12 +282,134 @@ function findNextFromSequence(sequence, completed, skipped) {
|
|
|
270
282
|
return sequence.find((stage) => !done.has(normalizeAgentName(stage))) || null;
|
|
271
283
|
}
|
|
272
284
|
|
|
285
|
+
function reconcileWorkflowState(state) {
|
|
286
|
+
if (!state || typeof state !== 'object' || !Array.isArray(state.sequence)) {
|
|
287
|
+
return { state, changed: false };
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const sequence = state.sequence.map(normalizeAgentName);
|
|
291
|
+
const completed = Array.from(new Set((state.completed || []).map(normalizeAgentName).filter(Boolean)));
|
|
292
|
+
const skippedSet = new Set((state.skipped || []).map(normalizeAgentName).filter(Boolean));
|
|
293
|
+
const detour = state.detour && typeof state.detour === 'object'
|
|
294
|
+
? {
|
|
295
|
+
...state.detour,
|
|
296
|
+
agent: normalizeAgentName(state.detour.agent),
|
|
297
|
+
returnTo: normalizeAgentName(state.detour.returnTo)
|
|
298
|
+
}
|
|
299
|
+
: null;
|
|
300
|
+
let changed = false;
|
|
301
|
+
|
|
302
|
+
// If a later stage is already completed, any unresolved earlier stage was
|
|
303
|
+
// effectively bypassed outside the workflow and must not remain "active".
|
|
304
|
+
const furthestCompletedIndex = sequence.reduce((max, stage, index) => (
|
|
305
|
+
completed.includes(stage) ? Math.max(max, index) : max
|
|
306
|
+
), -1);
|
|
307
|
+
|
|
308
|
+
if (furthestCompletedIndex >= 0) {
|
|
309
|
+
for (let index = 0; index < furthestCompletedIndex; index += 1) {
|
|
310
|
+
const stage = sequence[index];
|
|
311
|
+
if (!completed.includes(stage) && !skippedSet.has(stage)) {
|
|
312
|
+
skippedSet.add(stage);
|
|
313
|
+
changed = true;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const skipped = sequence.filter((stage) => skippedSet.has(stage));
|
|
319
|
+
const resolved = new Set([...completed, ...skipped]);
|
|
320
|
+
let current = state.current ? normalizeAgentName(state.current) : null;
|
|
321
|
+
let next = state.next ? normalizeAgentName(state.next) : null;
|
|
322
|
+
const currentIsActiveDetour = Boolean(
|
|
323
|
+
detour &&
|
|
324
|
+
detour.active &&
|
|
325
|
+
current &&
|
|
326
|
+
current === detour.agent
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
if (current && ((!sequence.includes(current) && !currentIsActiveDetour) || resolved.has(current))) {
|
|
330
|
+
current = null;
|
|
331
|
+
changed = true;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (!detour || !detour.active) {
|
|
335
|
+
if (current) {
|
|
336
|
+
const currentIndex = sequence.indexOf(current);
|
|
337
|
+
const expectedQueuedNext = sequence.find(
|
|
338
|
+
(stage, index) => index > currentIndex && !resolved.has(stage)
|
|
339
|
+
) || null;
|
|
340
|
+
if (next && next !== current && next !== expectedQueuedNext) {
|
|
341
|
+
next = expectedQueuedNext || current;
|
|
342
|
+
changed = true;
|
|
343
|
+
} else if (!next) {
|
|
344
|
+
next = expectedQueuedNext || current;
|
|
345
|
+
changed = true;
|
|
346
|
+
}
|
|
347
|
+
} else {
|
|
348
|
+
const inferredNext = findNextFromSequence(sequence, completed, skipped);
|
|
349
|
+
if (next !== inferredNext) {
|
|
350
|
+
next = inferredNext;
|
|
351
|
+
changed = true;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (!changed) {
|
|
357
|
+
return { state, changed: false };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return {
|
|
361
|
+
changed: true,
|
|
362
|
+
state: buildStatePayload({
|
|
363
|
+
...state,
|
|
364
|
+
sequence,
|
|
365
|
+
completed,
|
|
366
|
+
skipped,
|
|
367
|
+
current,
|
|
368
|
+
next,
|
|
369
|
+
detour
|
|
370
|
+
})
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
273
374
|
function isInferableStage(stage) {
|
|
274
375
|
return ['setup', 'product', 'analyst', 'architect', 'ux-ui', 'orchestrator'].includes(
|
|
275
376
|
normalizeAgentName(stage)
|
|
276
377
|
);
|
|
277
378
|
}
|
|
278
379
|
|
|
380
|
+
function isSecurityGateBlocked(contractCheck, state, stageName) {
|
|
381
|
+
if (normalizeAgentName(stageName) !== 'qa' || state.mode !== 'feature' || !state.featureSlug) {
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
return contractCheck.missing.some((item) =>
|
|
385
|
+
item.includes('security:') ||
|
|
386
|
+
item.includes(`security-findings-${state.featureSlug}.json`)
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function buildQaSecurityAuditBriefing(result, targetDir) {
|
|
391
|
+
if (!result) return '';
|
|
392
|
+
|
|
393
|
+
if (result.ok === false && result.reason) {
|
|
394
|
+
return [
|
|
395
|
+
'## Secure by Default audit',
|
|
396
|
+
`- Auto-run failed before QA review: ${result.reason}.`,
|
|
397
|
+
'- Gate D will remain blocked until a valid `security-findings-{slug}.json` artifact exists.',
|
|
398
|
+
'- If CLI is unavailable in your client, use the fallback checklist and record the limitation explicitly in the QA report and `project-pulse.md`.'
|
|
399
|
+
].join('\n');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return [
|
|
403
|
+
'## Secure by Default audit',
|
|
404
|
+
`- Auto-ran \`security:audit\` for feature \`${result.slug}\` at QA activation.`,
|
|
405
|
+
`- Exit code: ${result.exitCode}. Findings: ${result.findingsCount}.`,
|
|
406
|
+
`- Summary: critical=${result.summary.critical}, high=${result.summary.high}, medium=${result.summary.medium}, low=${result.summary.low}, inconclusive=${result.summary.inconclusive}.`,
|
|
407
|
+
`- Artifact: \`${path.relative(targetDir, result.artifactPath)}\`.`,
|
|
408
|
+
'- If the audit or manual heuristics indicate auth, money, or ownership risk, invoke `@pentester` with `--mode=app_target --feature=<slug> --scope=<target>` before final Gate D sign-off.',
|
|
409
|
+
'- If CLI is unavailable in your client, use the fallback checklist and record the limitation explicitly in the QA report and `project-pulse.md`.'
|
|
410
|
+
].join('\n');
|
|
411
|
+
}
|
|
412
|
+
|
|
279
413
|
async function inferCompletedStages(targetDir, draftState) {
|
|
280
414
|
const completed = [];
|
|
281
415
|
for (const stage of draftState.sequence) {
|
|
@@ -291,7 +425,11 @@ async function loadOrCreateState(targetDir, options = {}) {
|
|
|
291
425
|
const statePath = path.join(targetDir, STATE_RELATIVE_PATH);
|
|
292
426
|
const existing = await readJsonIfExists(statePath);
|
|
293
427
|
if (existing && typeof existing === 'object' && Array.isArray(existing.sequence)) {
|
|
294
|
-
|
|
428
|
+
const reconciled = reconcileWorkflowState(existing);
|
|
429
|
+
if (reconciled.changed) {
|
|
430
|
+
await writeJson(statePath, reconciled.state);
|
|
431
|
+
}
|
|
432
|
+
return { statePath, state: reconciled.state, created: false };
|
|
295
433
|
}
|
|
296
434
|
|
|
297
435
|
const context = await validateProjectContextFile(targetDir);
|
|
@@ -371,6 +509,27 @@ async function finalizeCurrentStage(targetDir, config, state, stageName) {
|
|
|
371
509
|
throw new Error('No stage is active to complete.');
|
|
372
510
|
}
|
|
373
511
|
|
|
512
|
+
// ── Harness Done Gate ───────────────────────────────────────────────────
|
|
513
|
+
if (state.mode === 'feature' && state.featureSlug) {
|
|
514
|
+
const contractPath = path.join(targetDir, '.aioson', 'plans', state.featureSlug, 'harness-contract.json');
|
|
515
|
+
const progressPath = path.join(targetDir, '.aioson', 'plans', state.featureSlug, 'progress.json');
|
|
516
|
+
|
|
517
|
+
// Se contrato existe, verificamos o progresso
|
|
518
|
+
const fs = require('node:fs');
|
|
519
|
+
if (fs.existsSync(contractPath) && fs.existsSync(progressPath)) {
|
|
520
|
+
try {
|
|
521
|
+
const progress = JSON.parse(fs.readFileSync(progressPath, 'utf8'));
|
|
522
|
+
// Bloqueia se não estiver pronto para o gate E o estágio for crítico (dev/qa)
|
|
523
|
+
if (!progress.ready_for_done_gate && (normalizedStage === 'dev' || normalizedStage === 'qa')) {
|
|
524
|
+
throw new Error(`[Harness Block] A feature "${state.featureSlug}" não passou na validação contratual. Execute 'aioson harness:validate' e resolva os problemas antes de concluir o estágio @${normalizedStage}.`);
|
|
525
|
+
}
|
|
526
|
+
} catch (err) {
|
|
527
|
+
if (err.message.includes('[Harness Block]')) throw err;
|
|
528
|
+
// Se erro de parse, ignoramos para não quebrar o workflow por corrupção
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
374
533
|
if (state.detour && state.detour.active && normalizeAgentName(state.detour.agent) === normalizedStage) {
|
|
375
534
|
const validDetour = await validateStageArtifacts(targetDir, state, normalizedStage);
|
|
376
535
|
if (!validDetour) {
|
|
@@ -391,6 +550,56 @@ async function finalizeCurrentStage(targetDir, config, state, stageName) {
|
|
|
391
550
|
throw new Error(`Cannot complete ${normalizedStage}; expected artifacts are missing.`);
|
|
392
551
|
}
|
|
393
552
|
|
|
553
|
+
// ── Handoff Contract Gate ───────────────────────────────────────────────
|
|
554
|
+
const contractCheck = await validateHandoffContract(targetDir, state, normalizedStage);
|
|
555
|
+
if (!contractCheck.ok) {
|
|
556
|
+
if (isSecurityGateBlocked(contractCheck, state, normalizedStage)) {
|
|
557
|
+
await emitSecurityRuntimeEvent({
|
|
558
|
+
targetDir,
|
|
559
|
+
eventType: 'security_gate_blocked',
|
|
560
|
+
message: `Gate D blocked for ${state.featureSlug} at @qa`,
|
|
561
|
+
status: 'failed',
|
|
562
|
+
agentName: 'qa',
|
|
563
|
+
source: 'workflow',
|
|
564
|
+
workflowState: state,
|
|
565
|
+
workflowStage: 'qa',
|
|
566
|
+
payload: {
|
|
567
|
+
feature_slug: state.featureSlug,
|
|
568
|
+
classification: state.classification,
|
|
569
|
+
blockers: contractCheck.missing
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
const errMsg = formatContractError(contractCheck);
|
|
574
|
+
await logError(targetDir, normalizedStage, errMsg, 'contract');
|
|
575
|
+
throw new Error(errMsg);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// ── Revision Gate (Phase 2) ─────────────────────────────────────────────
|
|
579
|
+
const blockingRevisions = await getBlockingRevisions(targetDir, state.featureSlug);
|
|
580
|
+
if (blockingRevisions.length > 0) {
|
|
581
|
+
const ids = blockingRevisions.map((r) => r.id).join(', ');
|
|
582
|
+
const errMsg = [
|
|
583
|
+
`[Revision Gate BLOCKED]`,
|
|
584
|
+
`Feature: ${state.featureSlug}`,
|
|
585
|
+
``,
|
|
586
|
+
`Pending blocking revision(s): ${ids}`,
|
|
587
|
+
``,
|
|
588
|
+
`Resolve each revision before completing this stage:`,
|
|
589
|
+
...blockingRevisions.map((r) => ` aioson revision:resolve . --slug=${state.featureSlug} --rev-id=${r.id} --approve|--reject`)
|
|
590
|
+
].join('\n');
|
|
591
|
+
await logError(targetDir, normalizedStage, errMsg, 'revision');
|
|
592
|
+
throw new Error(errMsg);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// ── Technical Compilation/Test Gate ─────────────────────────────────────
|
|
596
|
+
const techGate = await runTechnicalGate(targetDir, normalizedStage);
|
|
597
|
+
if (!techGate.ok) {
|
|
598
|
+
const errMsg = formatGateError(techGate);
|
|
599
|
+
await logError(targetDir, normalizedStage, errMsg, 'technical');
|
|
600
|
+
throw new Error(errMsg);
|
|
601
|
+
}
|
|
602
|
+
|
|
394
603
|
const completed = Array.from(new Set([...(state.completed || []), normalizedStage]));
|
|
395
604
|
const next = findNextFromSequence(state.sequence, completed, state.skipped || []);
|
|
396
605
|
const nextState = buildStatePayload({
|
|
@@ -423,7 +632,7 @@ function applySkip(config, state, target) {
|
|
|
423
632
|
});
|
|
424
633
|
}
|
|
425
634
|
|
|
426
|
-
async function activateStage(targetDir, state, locale, tool, explicitAgent = null) {
|
|
635
|
+
async function activateStage(targetDir, state, locale, tool, explicitAgent = null, requestedMode = null) {
|
|
427
636
|
const stageName = normalizeAgentName(explicitAgent || state.current || state.next);
|
|
428
637
|
if (!stageName) {
|
|
429
638
|
return {
|
|
@@ -434,13 +643,109 @@ async function activateStage(targetDir, state, locale, tool, explicitAgent = nul
|
|
|
434
643
|
};
|
|
435
644
|
}
|
|
436
645
|
|
|
646
|
+
// ── Committer Safety Gate ───────────────────────────────────────────────
|
|
647
|
+
if (stageName === 'committer') {
|
|
648
|
+
const guard = await inspectStagedChanges(targetDir, { allowWarnings: false });
|
|
649
|
+
if (guard.summary.stagedCount === 0) {
|
|
650
|
+
throw new Error(
|
|
651
|
+
`[Committer Gate BLOCKED] Nenhum arquivo no stage para commit. ` +
|
|
652
|
+
`Execute primeiro: aioson commit:prepare . --agent-safe --staged-only --mode=headless`
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
if (!guard.ok) {
|
|
656
|
+
throw new Error(
|
|
657
|
+
`[Committer Gate BLOCKED] Arquivos proibidos detectados no stage ` +
|
|
658
|
+
`(node_modules, build artifacts, secrets, etc.). ` +
|
|
659
|
+
`Execute 'aioson git:guard .' para ver detalhes, corrija e rode 'aioson commit:prepare . --agent-safe --staged-only --mode=headless' antes de ativar @committer.`
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// ── Test Briefing Injection for qa/tester ───────────────────────────────
|
|
665
|
+
let testBriefing = '';
|
|
666
|
+
let securityAuditBriefing = '';
|
|
667
|
+
if (stageName === 'qa' || stageName === 'tester') {
|
|
668
|
+
try {
|
|
669
|
+
testBriefing = await buildTestBriefing(targetDir);
|
|
670
|
+
} catch {
|
|
671
|
+
// Non-fatal: if briefing generation fails, proceed without it
|
|
672
|
+
testBriefing = '';
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
if (
|
|
677
|
+
stageName === 'qa' &&
|
|
678
|
+
state.mode === 'feature' &&
|
|
679
|
+
state.classification === 'MEDIUM' &&
|
|
680
|
+
state.featureSlug
|
|
681
|
+
) {
|
|
682
|
+
try {
|
|
683
|
+
const auditResult = await runSecurityAudit({
|
|
684
|
+
args: [targetDir],
|
|
685
|
+
options: {
|
|
686
|
+
slug: state.featureSlug,
|
|
687
|
+
json: true,
|
|
688
|
+
runtimeAgentName: 'qa',
|
|
689
|
+
runtimeSource: 'workflow',
|
|
690
|
+
runtimeState: state,
|
|
691
|
+
runtimeWorkflowStage: 'qa'
|
|
692
|
+
},
|
|
693
|
+
logger: { log() {}, error() {}, warn() {} }
|
|
694
|
+
});
|
|
695
|
+
securityAuditBriefing = buildQaSecurityAuditBriefing(auditResult, targetDir);
|
|
696
|
+
} catch {
|
|
697
|
+
securityAuditBriefing = buildQaSecurityAuditBriefing({
|
|
698
|
+
ok: false,
|
|
699
|
+
reason: 'audit_runtime_failure'
|
|
700
|
+
}, targetDir);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// ── Path Guard Injection for implementation agents ────────────────────────
|
|
705
|
+
let pathGuardBlock = '';
|
|
706
|
+
if (['dev', 'architect', 'ux-ui', 'pentester', 'qa', 'tester', 'committer'].includes(stageName)) {
|
|
707
|
+
try {
|
|
708
|
+
pathGuardBlock = await buildPathGuardBlock(targetDir);
|
|
709
|
+
} catch {
|
|
710
|
+
pathGuardBlock = '';
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
437
714
|
const agent = getAgentDefinition(stageName);
|
|
438
715
|
if (!agent) {
|
|
439
716
|
throw new Error(`Unknown agent: ${stageName}`);
|
|
440
717
|
}
|
|
441
718
|
|
|
719
|
+
const autonomyProtocol = await readAutonomyProtocol(targetDir);
|
|
720
|
+
const agentManifest = await readAgentManifest(targetDir, agent.id);
|
|
721
|
+
const effectiveMode = resolveEffectiveMode({
|
|
722
|
+
protocol: autonomyProtocol,
|
|
723
|
+
tool,
|
|
724
|
+
agentId: agent.id,
|
|
725
|
+
manifest: agentManifest,
|
|
726
|
+
requestedMode
|
|
727
|
+
});
|
|
728
|
+
|
|
442
729
|
const instructionPath = await resolveExistingInstructionPath(targetDir, agent, locale);
|
|
443
|
-
|
|
730
|
+
let prompt = buildAgentPrompt(agent, tool, {
|
|
731
|
+
instructionPath,
|
|
732
|
+
targetDir,
|
|
733
|
+
interactionLanguage: locale,
|
|
734
|
+
autonomyMode: effectiveMode,
|
|
735
|
+
capabilitySummary: buildAgentCapabilitySummary(agentManifest, tool)
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
if (testBriefing) {
|
|
739
|
+
prompt += '\n\n' + testBriefing;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
if (securityAuditBriefing) {
|
|
743
|
+
prompt += '\n\n' + securityAuditBriefing;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
if (pathGuardBlock) {
|
|
747
|
+
prompt += '\n\n' + pathGuardBlock;
|
|
748
|
+
}
|
|
444
749
|
|
|
445
750
|
let nextState = state;
|
|
446
751
|
if (explicitAgent && stageName !== normalizeAgentName(state.next)) {
|
|
@@ -464,11 +769,23 @@ async function activateStage(targetDir, state, locale, tool, explicitAgent = nul
|
|
|
464
769
|
state: nextState,
|
|
465
770
|
agent: stageName,
|
|
466
771
|
instructionPath,
|
|
467
|
-
prompt
|
|
772
|
+
prompt,
|
|
773
|
+
effectiveMode
|
|
468
774
|
};
|
|
469
775
|
}
|
|
470
776
|
|
|
471
777
|
async function runWorkflowNext({ args, options, logger, t }) {
|
|
778
|
+
if (options.status || options.suggest) {
|
|
779
|
+
const { runWorkflowStatus } = require('./workflow-status');
|
|
780
|
+
return runWorkflowStatus({ args, options, logger, t });
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
const logErrorLine = typeof logger.error === 'function'
|
|
784
|
+
? logger.error.bind(logger)
|
|
785
|
+
: typeof logger.log === 'function'
|
|
786
|
+
? logger.log.bind(logger)
|
|
787
|
+
: () => {};
|
|
788
|
+
|
|
472
789
|
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
473
790
|
const tool = options.tool || 'codex';
|
|
474
791
|
const locale = await resolveLocaleForTarget(targetDir, options);
|
|
@@ -478,14 +795,119 @@ async function runWorkflowNext({ args, options, logger, t }) {
|
|
|
478
795
|
let completedStage = null;
|
|
479
796
|
|
|
480
797
|
if (options.complete || options['complete-current']) {
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
798
|
+
let finalized;
|
|
799
|
+
try {
|
|
800
|
+
finalized = await finalizeCurrentStage(
|
|
801
|
+
targetDir,
|
|
802
|
+
config,
|
|
803
|
+
state,
|
|
804
|
+
options.complete === true ? state.current || state.next : options.complete
|
|
805
|
+
);
|
|
806
|
+
} catch (err) {
|
|
807
|
+
// ── Auto-heal intercept ───────────────────────────────────────────────
|
|
808
|
+
const autoHeal = Boolean(options['auto-heal'] || options.autoHeal);
|
|
809
|
+
const isHealabled = autoHeal && (
|
|
810
|
+
err.message.includes('[Technical Gate BLOCKED]') ||
|
|
811
|
+
err.message.includes('[Handoff Contract BLOCKED]')
|
|
812
|
+
);
|
|
813
|
+
if (isHealabled) {
|
|
814
|
+
const failedStage = normalizeAgentName(options.complete === true ? state.current || state.next : options.complete);
|
|
815
|
+
await logError(targetDir, failedStage, err.message, 'technical');
|
|
816
|
+
const retryCount = await require('../self-healing').getRetryCount(targetDir, failedStage);
|
|
817
|
+
if (retryCount < require('../self-healing').MAX_RETRIES) {
|
|
818
|
+
await require('../self-healing').incrementRetryCount(targetDir, failedStage, err.message.substring(0, 200));
|
|
819
|
+
// Build healing activation
|
|
820
|
+
const baseActivation = await activateStage(targetDir, state, locale, tool, failedStage, options.mode || null);
|
|
821
|
+
const healingPrompt = buildHealingPrompt(
|
|
822
|
+
baseActivation.prompt || '',
|
|
823
|
+
failedStage,
|
|
824
|
+
{ error: err.message },
|
|
825
|
+
retryCount + 1
|
|
826
|
+
);
|
|
827
|
+
const healedState = {
|
|
828
|
+
...baseActivation.state,
|
|
829
|
+
current: failedStage,
|
|
830
|
+
detour: null
|
|
831
|
+
};
|
|
832
|
+
await persistState(targetDir, healedState);
|
|
833
|
+
const eventPayload = {
|
|
834
|
+
id: Date.now(),
|
|
835
|
+
kind: 'workflow',
|
|
836
|
+
createdAt: new Date().toISOString(),
|
|
837
|
+
eventType: 'heal',
|
|
838
|
+
message: `Auto-heal @${failedStage} — retry ${retryCount + 1}/3`,
|
|
839
|
+
mode: state.mode,
|
|
840
|
+
classification: state.classification,
|
|
841
|
+
featureSlug: state.featureSlug,
|
|
842
|
+
current: failedStage,
|
|
843
|
+
next: state.next,
|
|
844
|
+
completed: state.completed,
|
|
845
|
+
skipped: state.skipped,
|
|
846
|
+
sequence: state.sequence,
|
|
847
|
+
healing: true,
|
|
848
|
+
retryCount: retryCount + 1,
|
|
849
|
+
autonomyMode: baseActivation.effectiveMode || null
|
|
850
|
+
};
|
|
851
|
+
await appendWorkflowEvent(targetDir, eventPayload);
|
|
852
|
+
const runtime = await syncWorkflowRuntime(targetDir, {
|
|
853
|
+
state: healedState,
|
|
854
|
+
eventPayload,
|
|
855
|
+
activationAgent: failedStage,
|
|
856
|
+
completedStage: null
|
|
857
|
+
});
|
|
858
|
+
const healingHandoff = buildWorkflowHandoff(healedState, null, failedStage);
|
|
859
|
+
healingHandoff.protocol = buildWorkflowHandoffProtocol(healedState, null, failedStage, {
|
|
860
|
+
autonomyMode: baseActivation.effectiveMode || null,
|
|
861
|
+
handoffContractOk: true,
|
|
862
|
+
technicalGateOk: false,
|
|
863
|
+
artifactUris: []
|
|
864
|
+
});
|
|
865
|
+
const healingValidation = await validateHandoffProtocol(targetDir, healingHandoff.protocol);
|
|
866
|
+
if (!healingValidation.ok) {
|
|
867
|
+
logErrorLine('Handoff protocol warning:');
|
|
868
|
+
for (const err of healingValidation.errors) logErrorLine(` - ${err}`);
|
|
869
|
+
}
|
|
870
|
+
await writeHandoff(targetDir, healingHandoff);
|
|
871
|
+
logger.log(t('workflow_heal.title', { stage: `@${failedStage}`, count: retryCount + 1 }));
|
|
872
|
+
logger.log(healingPrompt);
|
|
873
|
+
return {
|
|
874
|
+
ok: true,
|
|
875
|
+
targetDir,
|
|
876
|
+
locale,
|
|
877
|
+
tool,
|
|
878
|
+
statePath: STATE_RELATIVE_PATH,
|
|
879
|
+
configPath: CONFIG_RELATIVE_PATH,
|
|
880
|
+
created: loaded.created,
|
|
881
|
+
mode: state.mode,
|
|
882
|
+
classification: state.classification,
|
|
883
|
+
current: healedState.current,
|
|
884
|
+
next: healedState.next,
|
|
885
|
+
detour: healedState.detour,
|
|
886
|
+
completed: healedState.completed,
|
|
887
|
+
skipped: healedState.skipped,
|
|
888
|
+
completedStage: null,
|
|
889
|
+
featureSlug: state.featureSlug,
|
|
890
|
+
runtime,
|
|
891
|
+
agent: failedStage,
|
|
892
|
+
instructionPath: baseActivation.instructionPath,
|
|
893
|
+
prompt: healingPrompt,
|
|
894
|
+
autoHealed: true,
|
|
895
|
+
effectiveMode: baseActivation.effectiveMode || null
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
throw err;
|
|
900
|
+
}
|
|
901
|
+
state = finalized.state;
|
|
902
|
+
completedStage = finalized.completedStage;
|
|
903
|
+
await require('../self-healing').incrementRetryCount(targetDir, completedStage, '');
|
|
904
|
+
const { getRetryCount } = require('../self-healing');
|
|
905
|
+
const retries = await getRetryCount(targetDir, completedStage);
|
|
906
|
+
if (retries > 0) {
|
|
907
|
+
// Reset retry count on successful completion after healing
|
|
908
|
+
const retriesPath = path.join(targetDir, '.aioson/context/pipeline-retries', `${completedStage}.json`);
|
|
909
|
+
try { await fs.unlink(retriesPath); } catch { /* ignore */ }
|
|
910
|
+
}
|
|
489
911
|
}
|
|
490
912
|
|
|
491
913
|
if (options.skip) {
|
|
@@ -493,7 +915,7 @@ async function runWorkflowNext({ args, options, logger, t }) {
|
|
|
493
915
|
}
|
|
494
916
|
|
|
495
917
|
const requestedAgent = options.agent ? normalizeAgentName(options.agent) : null;
|
|
496
|
-
const activation = await activateStage(targetDir, state, locale, tool, requestedAgent);
|
|
918
|
+
const activation = await activateStage(targetDir, state, locale, tool, requestedAgent, options.mode || null);
|
|
497
919
|
state = activation.state;
|
|
498
920
|
const statePath = await persistState(targetDir, state);
|
|
499
921
|
const eventPayload = {
|
|
@@ -518,7 +940,8 @@ async function runWorkflowNext({ args, options, logger, t }) {
|
|
|
518
940
|
requestedAgent: options.requestedAgent ? normalizeAgentName(options.requestedAgent) : null,
|
|
519
941
|
completed: state.completed,
|
|
520
942
|
skipped: state.skipped,
|
|
521
|
-
sequence: state.sequence
|
|
943
|
+
sequence: state.sequence,
|
|
944
|
+
autonomyMode: activation.effectiveMode || null
|
|
522
945
|
};
|
|
523
946
|
await appendWorkflowEvent(targetDir, eventPayload);
|
|
524
947
|
const runtime = await syncWorkflowRuntime(targetDir, {
|
|
@@ -531,6 +954,18 @@ async function runWorkflowNext({ args, options, logger, t }) {
|
|
|
531
954
|
// Generate session handoff when a stage completes or workflow finishes
|
|
532
955
|
if (completedStage || !activation.agent) {
|
|
533
956
|
const handoffData = buildWorkflowHandoff(state, completedStage, activation.agent);
|
|
957
|
+
handoffData.autonomyMode = activation.effectiveMode || null;
|
|
958
|
+
handoffData.protocol = buildWorkflowHandoffProtocol(state, completedStage, activation.agent, {
|
|
959
|
+
autonomyMode: activation.effectiveMode || null,
|
|
960
|
+
handoffContractOk: true,
|
|
961
|
+
technicalGateOk: true,
|
|
962
|
+
artifactUris: []
|
|
963
|
+
});
|
|
964
|
+
const handoffValidation = await validateHandoffProtocol(targetDir, handoffData.protocol);
|
|
965
|
+
if (!handoffValidation.ok) {
|
|
966
|
+
logErrorLine('Handoff protocol warning:');
|
|
967
|
+
for (const err of handoffValidation.errors) logErrorLine(` - ${err}`);
|
|
968
|
+
}
|
|
534
969
|
await writeHandoff(targetDir, handoffData);
|
|
535
970
|
}
|
|
536
971
|
|
|
@@ -553,6 +988,7 @@ async function runWorkflowNext({ args, options, logger, t }) {
|
|
|
553
988
|
featureSlug: state.featureSlug,
|
|
554
989
|
runtime,
|
|
555
990
|
agent: activation.agent,
|
|
991
|
+
effectiveMode: activation.effectiveMode || null,
|
|
556
992
|
instructionPath: activation.instructionPath,
|
|
557
993
|
prompt: activation.prompt
|
|
558
994
|
};
|
|
@@ -595,7 +1031,9 @@ module.exports = {
|
|
|
595
1031
|
readWorkflowConfig,
|
|
596
1032
|
detectWorkflowMode,
|
|
597
1033
|
loadOrCreateState,
|
|
1034
|
+
reconcileWorkflowState,
|
|
598
1035
|
finalizeCurrentStage,
|
|
599
1036
|
applySkip,
|
|
1037
|
+
activateStage,
|
|
600
1038
|
runWorkflowNext
|
|
601
1039
|
};
|