@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
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// scaffold:complete — Emite o evento `scaffold_complete` no `aios.sqlite` ativo
|
|
4
|
+
// para sinalizar a um runner externo (ex.: AIOSON Play) que o scaffolding foi
|
|
5
|
+
// concluído e o app está pronto para ser promovido (rename de drafts/{uuid}/
|
|
6
|
+
// para apps/{slug}/, gravação do manifest.json, etc.).
|
|
7
|
+
//
|
|
8
|
+
// Schema do evento:
|
|
9
|
+
// event_type: 'scaffold_complete'
|
|
10
|
+
// payload: { slug, manifest, scaffold_path }
|
|
11
|
+
//
|
|
12
|
+
// Uso típico (executado pelo agente após criar o app):
|
|
13
|
+
// aioson scaffold:complete --slug=<slug>
|
|
14
|
+
// aioson scaffold:complete --slug=<slug> --manifest=./manifest.json
|
|
15
|
+
// aioson scaffold:complete --slug=<slug> --manifest=./notecards/manifest.json --scaffold-path=./notecards
|
|
16
|
+
|
|
17
|
+
const fs = require('node:fs/promises');
|
|
18
|
+
const path = require('node:path');
|
|
19
|
+
const {
|
|
20
|
+
resolveRuntimePaths,
|
|
21
|
+
openRuntimeDb,
|
|
22
|
+
appendRunEvent
|
|
23
|
+
} = require('../runtime-store');
|
|
24
|
+
|
|
25
|
+
function resolveTargetDir(args) {
|
|
26
|
+
return path.resolve(process.cwd(), args[0] || '.');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function requireOption(options, key, t) {
|
|
30
|
+
const value = options[key];
|
|
31
|
+
if (value === undefined || value === null || String(value).trim() === '') {
|
|
32
|
+
throw new Error(
|
|
33
|
+
(t && t('runtime.option_required', { option: `--${key}` })) ||
|
|
34
|
+
`Required option missing: --${key}`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return String(value).trim();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
|
|
41
|
+
|
|
42
|
+
function validateSlug(slug) {
|
|
43
|
+
if (!SLUG_RE.test(slug)) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`Invalid slug "${slug}". Use lowercase letters, digits, and hyphens (must start and end with letter/digit).`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function validateManifest(manifest, slug) {
|
|
51
|
+
const required = ['name', 'description', 'version'];
|
|
52
|
+
const missing = required.filter((k) => !manifest[k] || String(manifest[k]).trim() === '');
|
|
53
|
+
if (missing.length > 0) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Manifest is missing required fields: ${missing.join(', ')}. Required: ${required.join(', ')}.`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
if (manifest.slug && manifest.slug !== slug) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Slug mismatch: --slug=${slug} but manifest.slug=${manifest.slug}.`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function readManifest(manifestPath) {
|
|
66
|
+
const raw = await fs.readFile(manifestPath, 'utf-8');
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(raw);
|
|
69
|
+
} catch (err) {
|
|
70
|
+
throw new Error(`Invalid JSON in ${manifestPath}: ${err.message}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function findActiveRun(db, { sessionKey, agent }) {
|
|
75
|
+
// Prioridade: --session > --agent > running mais recente.
|
|
76
|
+
if (sessionKey) {
|
|
77
|
+
const row = db
|
|
78
|
+
.prepare(
|
|
79
|
+
`SELECT run_key, agent_name, session_key, status, started_at
|
|
80
|
+
FROM agent_runs
|
|
81
|
+
WHERE session_key = ?
|
|
82
|
+
ORDER BY started_at DESC
|
|
83
|
+
LIMIT 1`
|
|
84
|
+
)
|
|
85
|
+
.get(sessionKey);
|
|
86
|
+
if (!row) {
|
|
87
|
+
throw new Error(`No agent_run found for session_key=${sessionKey}.`);
|
|
88
|
+
}
|
|
89
|
+
return row;
|
|
90
|
+
}
|
|
91
|
+
if (agent) {
|
|
92
|
+
const row = db
|
|
93
|
+
.prepare(
|
|
94
|
+
`SELECT run_key, agent_name, session_key, status, started_at
|
|
95
|
+
FROM agent_runs
|
|
96
|
+
WHERE agent_name = ? AND status IN ('running', 'starting', 'handoff')
|
|
97
|
+
ORDER BY started_at DESC
|
|
98
|
+
LIMIT 1`
|
|
99
|
+
)
|
|
100
|
+
.get(agent);
|
|
101
|
+
if (!row) {
|
|
102
|
+
throw new Error(`No active agent_run found for agent=${agent}.`);
|
|
103
|
+
}
|
|
104
|
+
return row;
|
|
105
|
+
}
|
|
106
|
+
const row = db
|
|
107
|
+
.prepare(
|
|
108
|
+
`SELECT run_key, agent_name, session_key, status, started_at
|
|
109
|
+
FROM agent_runs
|
|
110
|
+
WHERE status IN ('running', 'starting', 'handoff')
|
|
111
|
+
ORDER BY started_at DESC
|
|
112
|
+
LIMIT 1`
|
|
113
|
+
)
|
|
114
|
+
.get();
|
|
115
|
+
if (!row) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
'No active agent_run found. Use `aioson live:start ...` first, or pass --session/--agent.'
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
return row;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function runScaffoldComplete({ args, options = {}, logger, t }) {
|
|
124
|
+
const targetDir = resolveTargetDir(args);
|
|
125
|
+
const slug = requireOption(options, 'slug', t);
|
|
126
|
+
validateSlug(slug);
|
|
127
|
+
|
|
128
|
+
const manifestRel = String(options.manifest || './manifest.json').trim();
|
|
129
|
+
const manifestPath = path.resolve(targetDir, manifestRel);
|
|
130
|
+
const scaffoldPathRel = String(options['scaffold-path'] || options.scaffoldPath || '.').trim();
|
|
131
|
+
const scaffoldPath = path.resolve(targetDir, scaffoldPathRel);
|
|
132
|
+
|
|
133
|
+
const manifest = await readManifest(manifestPath);
|
|
134
|
+
validateManifest(manifest, slug);
|
|
135
|
+
if (!manifest.slug) {
|
|
136
|
+
manifest.slug = slug;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const handle = await openRuntimeDb(targetDir, { mustExist: true });
|
|
140
|
+
if (!handle) {
|
|
141
|
+
const { dbPath } = resolveRuntimePaths(targetDir);
|
|
142
|
+
throw new Error(`Runtime DB not found at ${dbPath}. Use \`aioson live:start ...\` first.`);
|
|
143
|
+
}
|
|
144
|
+
const { db, dbPath } = handle;
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
const sessionKey = options.session ? String(options.session).trim() : null;
|
|
148
|
+
const agent = options.agent ? String(options.agent).trim() : null;
|
|
149
|
+
const run = findActiveRun(db, { sessionKey, agent });
|
|
150
|
+
|
|
151
|
+
const payload = {
|
|
152
|
+
slug,
|
|
153
|
+
manifest,
|
|
154
|
+
scaffold_path: scaffoldPath
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
appendRunEvent(db, {
|
|
158
|
+
runKey: run.run_key,
|
|
159
|
+
eventType: 'scaffold_complete',
|
|
160
|
+
message: `Scaffold complete: ${slug}`,
|
|
161
|
+
payload,
|
|
162
|
+
phase: 'scaffold',
|
|
163
|
+
status: 'completed'
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (!options.json && logger) {
|
|
167
|
+
logger.log(
|
|
168
|
+
`Scaffold complete event emitted: slug=${slug} | run=${run.run_key} | session=${run.session_key} | db=${dbPath}`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
ok: true,
|
|
174
|
+
targetDir,
|
|
175
|
+
dbPath,
|
|
176
|
+
slug,
|
|
177
|
+
runKey: run.run_key,
|
|
178
|
+
sessionKey: run.session_key,
|
|
179
|
+
agent: run.agent_name,
|
|
180
|
+
manifestPath,
|
|
181
|
+
scaffoldPath
|
|
182
|
+
};
|
|
183
|
+
} finally {
|
|
184
|
+
db.close();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
module.exports = { runScaffoldComplete };
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const fs = require('node:fs/promises');
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
readSlugArtifacts,
|
|
8
|
+
extractClassification,
|
|
9
|
+
extractAttackSurfaceFlags
|
|
10
|
+
} = require('../lib/security/artifact-reader');
|
|
11
|
+
const { EXIT_CODES, resolveExitCode } = require('../lib/security/exit-codes');
|
|
12
|
+
const { writeFindings } = require('../lib/security/findings-writer');
|
|
13
|
+
const { emitSecurityRuntimeEvent } = require('../lib/security/runtime-events');
|
|
14
|
+
|
|
15
|
+
const VERSION = '1.0.0';
|
|
16
|
+
const GENERATOR = `aioson security:audit@${VERSION}`;
|
|
17
|
+
|
|
18
|
+
const REQUIRED_ARTIFACT_KEYS = ['prd', 'requirements', 'spec'];
|
|
19
|
+
|
|
20
|
+
const SURFACE_TO_CONTROLS = Object.freeze({
|
|
21
|
+
auth: ['SEC-SBD-08', 'SEC-SBD-03'],
|
|
22
|
+
ownership: ['SEC-SBD-03'],
|
|
23
|
+
money: ['SEC-SBD-04'],
|
|
24
|
+
uploads: ['SEC-SBD-02'],
|
|
25
|
+
external_urls: ['SEC-SBD-06'],
|
|
26
|
+
secrets: ['SEC-SBD-05'],
|
|
27
|
+
storage: ['SEC-SBD-07']
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
function missingArtifactFinding(key, filePath) {
|
|
31
|
+
return {
|
|
32
|
+
source: 'security-audit',
|
|
33
|
+
control_id: 'SEC-SBD-00',
|
|
34
|
+
severity: 'inconclusive',
|
|
35
|
+
status: 'needs_validation',
|
|
36
|
+
scope: `${key}:${filePath}`,
|
|
37
|
+
affected_artifacts: [filePath],
|
|
38
|
+
preconditions: [`Artifact ${key} expected at ${filePath}`],
|
|
39
|
+
reproduction_steps: [`stat ${filePath}`],
|
|
40
|
+
evidence: [`Artifact ${key} not found at ${filePath}`],
|
|
41
|
+
impact: `Cannot audit feature without ${key} artifact.`,
|
|
42
|
+
suggested_fix: `Generate ${key} via the appropriate agent before running audit.`,
|
|
43
|
+
recommended_owner: 'analyst',
|
|
44
|
+
recommended_gate_status: 'review'
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function attackSurfaceMissingFinding(slug, filePath) {
|
|
49
|
+
return {
|
|
50
|
+
source: 'security-audit',
|
|
51
|
+
control_id: 'SEC-SBD-03',
|
|
52
|
+
severity: 'medium',
|
|
53
|
+
scope: `${slug}:attack-surface-map`,
|
|
54
|
+
affected_artifacts: [filePath],
|
|
55
|
+
preconditions: ['requirements artifact present'],
|
|
56
|
+
reproduction_steps: ['Search requirements for "Attack Surface Map" section'],
|
|
57
|
+
evidence: ['No Attack Surface Map section found in requirements.'],
|
|
58
|
+
impact: 'Without an Attack Surface Map, ownership/IDOR coverage cannot be verified.',
|
|
59
|
+
suggested_fix: 'Add an Attack Surface Map section to requirements (analyst).',
|
|
60
|
+
recommended_owner: 'analyst',
|
|
61
|
+
recommended_gate_status: 'review'
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function controlEvidenceFinding({ slug, controlId, surface, specPath }) {
|
|
66
|
+
return {
|
|
67
|
+
source: 'security-audit',
|
|
68
|
+
control_id: controlId,
|
|
69
|
+
severity: 'high',
|
|
70
|
+
scope: `${slug}:${surface}:${controlId}`,
|
|
71
|
+
affected_artifacts: [specPath],
|
|
72
|
+
preconditions: [`Surface "${surface}" present in requirements`],
|
|
73
|
+
reproduction_steps: [`Search spec-${slug}.md for ${controlId} evidence or N/A rationale`],
|
|
74
|
+
evidence: [`Surface "${surface}" present but no ${controlId} evidence or N/A rationale found in spec.`],
|
|
75
|
+
impact: `Control ${controlId} is required for surface "${surface}" but its evidence is missing.`,
|
|
76
|
+
suggested_fix: `Add evidence (or explicit N/A rationale) for ${controlId} in spec-${slug}.md.`,
|
|
77
|
+
recommended_owner: 'dev',
|
|
78
|
+
recommended_gate_status: 'block'
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function specMentionsControl(specContent, controlId) {
|
|
83
|
+
if (!specContent) return false;
|
|
84
|
+
const re = new RegExp(`\\b${controlId.replace(/-/g, '[-]')}\\b`);
|
|
85
|
+
return re.test(specContent);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function specDeclaresNoSensitiveSurface(specContent) {
|
|
89
|
+
if (!specContent) return false;
|
|
90
|
+
return /\bno sensitive attack surface\b/i.test(specContent);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function buildAuditFindings({ slug, bundle }) {
|
|
94
|
+
const findings = [];
|
|
95
|
+
const { artifacts } = bundle;
|
|
96
|
+
|
|
97
|
+
for (const key of REQUIRED_ARTIFACT_KEYS) {
|
|
98
|
+
const a = artifacts[key];
|
|
99
|
+
if (!a || !a.present) {
|
|
100
|
+
findings.push(missingArtifactFinding(key, a ? a.path : `${key}-${slug}.md`));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const requirements = artifacts.requirements && artifacts.requirements.content;
|
|
105
|
+
const spec = artifacts.spec && artifacts.spec.content;
|
|
106
|
+
const specPath = artifacts.spec ? artifacts.spec.path : `spec-${slug}.md`;
|
|
107
|
+
|
|
108
|
+
const { hasMap, surfaces } = extractAttackSurfaceFlags(requirements);
|
|
109
|
+
|
|
110
|
+
const classification = extractClassification(requirements) || extractClassification(spec) || 'MICRO';
|
|
111
|
+
const hasNoSensitiveSurface = specDeclaresNoSensitiveSurface(spec);
|
|
112
|
+
|
|
113
|
+
if (classification === 'MEDIUM' && requirements && !hasMap) {
|
|
114
|
+
findings.push(attackSurfaceMissingFinding(slug, artifacts.requirements.path));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (classification === 'MEDIUM' && !hasNoSensitiveSurface) {
|
|
118
|
+
for (const surface of surfaces) {
|
|
119
|
+
const controls = SURFACE_TO_CONTROLS[surface] || [];
|
|
120
|
+
for (const controlId of controls) {
|
|
121
|
+
if (!specMentionsControl(spec, controlId)) {
|
|
122
|
+
findings.push(controlEvidenceFinding({ slug, controlId, surface, specPath }));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return { findings, classification };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function runSecurityAudit({ args, options = {}, logger }) {
|
|
132
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
133
|
+
const slug = options.slug || options.feature || null;
|
|
134
|
+
const strict = Boolean(options.strict);
|
|
135
|
+
const format = String(options.format || 'json').toLowerCase();
|
|
136
|
+
|
|
137
|
+
if (!slug) {
|
|
138
|
+
const out = { ok: false, exitCode: EXIT_CODES.BAD_INPUT, reason: 'missing_slug' };
|
|
139
|
+
process.exitCode = out.exitCode;
|
|
140
|
+
logger.error('security:audit: --slug=<slug> is required.');
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
let stat;
|
|
145
|
+
try {
|
|
146
|
+
stat = await fs.stat(targetDir);
|
|
147
|
+
} catch {
|
|
148
|
+
const out = { ok: false, exitCode: EXIT_CODES.BAD_INPUT, reason: 'project_not_found', targetDir };
|
|
149
|
+
process.exitCode = out.exitCode;
|
|
150
|
+
logger.error(`security:audit: project path not found: ${targetDir}`);
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
if (!stat.isDirectory()) {
|
|
154
|
+
const out = { ok: false, exitCode: EXIT_CODES.BAD_INPUT, reason: 'project_not_directory', targetDir };
|
|
155
|
+
process.exitCode = out.exitCode;
|
|
156
|
+
logger.error(`security:audit: project path is not a directory: ${targetDir}`);
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const bundle = await readSlugArtifacts(targetDir, slug);
|
|
161
|
+
const requiredAllMissing = REQUIRED_ARTIFACT_KEYS.every((k) => !bundle.artifacts[k] || !bundle.artifacts[k].present);
|
|
162
|
+
if (requiredAllMissing) {
|
|
163
|
+
const out = {
|
|
164
|
+
ok: false,
|
|
165
|
+
exitCode: EXIT_CODES.BAD_INPUT,
|
|
166
|
+
reason: 'slug_artifacts_missing',
|
|
167
|
+
slug,
|
|
168
|
+
baseDir: bundle.baseDir
|
|
169
|
+
};
|
|
170
|
+
process.exitCode = out.exitCode;
|
|
171
|
+
logger.error(`security:audit: no artifacts found for slug "${slug}" under ${bundle.baseDir}.`);
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const { findings, classification } = buildAuditFindings({ slug, bundle });
|
|
176
|
+
const generatedAt = options.now || new Date().toISOString();
|
|
177
|
+
|
|
178
|
+
const writeResult = await writeFindings({
|
|
179
|
+
targetDir,
|
|
180
|
+
slug,
|
|
181
|
+
source: 'security-audit',
|
|
182
|
+
generator: GENERATOR,
|
|
183
|
+
generatedAt,
|
|
184
|
+
scopeMode: 'feature',
|
|
185
|
+
findings
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (!writeResult.ok && writeResult.reason === 'contract_violation_too_many_findings') {
|
|
189
|
+
process.exitCode = EXIT_CODES.CONTRACT_VIOLATION;
|
|
190
|
+
logger.error(`security:audit: too many findings (${writeResult.count} > ${writeResult.max}).`);
|
|
191
|
+
await emitSecurityRuntimeEvent({
|
|
192
|
+
targetDir,
|
|
193
|
+
eventType: 'security_audit_completed',
|
|
194
|
+
message: `security:audit completed with contract violation for ${slug} (exit=${EXIT_CODES.CONTRACT_VIOLATION})`,
|
|
195
|
+
status: 'completed',
|
|
196
|
+
agentName: options.runtimeAgentName || 'qa',
|
|
197
|
+
source: options.runtimeSource || 'direct',
|
|
198
|
+
workflowState: options.runtimeState || null,
|
|
199
|
+
workflowStage: options.runtimeWorkflowStage || 'qa',
|
|
200
|
+
payload: {
|
|
201
|
+
command: 'security:audit',
|
|
202
|
+
slug,
|
|
203
|
+
classification,
|
|
204
|
+
exitCode: EXIT_CODES.CONTRACT_VIOLATION,
|
|
205
|
+
findingsCount: writeResult.count,
|
|
206
|
+
artifactPath: writeResult.artifactPath || null,
|
|
207
|
+
reason: 'too_many_findings',
|
|
208
|
+
strict
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
return {
|
|
212
|
+
ok: false,
|
|
213
|
+
exitCode: EXIT_CODES.CONTRACT_VIOLATION,
|
|
214
|
+
reason: 'too_many_findings',
|
|
215
|
+
...writeResult
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const hasInconclusive = writeResult.payload.findings.some(
|
|
220
|
+
(f) => (f.status === 'open' || f.status === 'needs_validation') && f.severity === 'inconclusive'
|
|
221
|
+
);
|
|
222
|
+
const exitCode = resolveExitCode({
|
|
223
|
+
classification,
|
|
224
|
+
findings: writeResult.payload.findings,
|
|
225
|
+
hasInconclusive,
|
|
226
|
+
strict
|
|
227
|
+
});
|
|
228
|
+
process.exitCode = exitCode;
|
|
229
|
+
|
|
230
|
+
const summary = writeResult.payload.summary;
|
|
231
|
+
const result = {
|
|
232
|
+
ok: exitCode === EXIT_CODES.PASS,
|
|
233
|
+
exitCode,
|
|
234
|
+
slug,
|
|
235
|
+
classification,
|
|
236
|
+
artifactPath: writeResult.artifactPath,
|
|
237
|
+
summary,
|
|
238
|
+
findingsCount: writeResult.payload.findings.length,
|
|
239
|
+
strict
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
await emitSecurityRuntimeEvent({
|
|
243
|
+
targetDir,
|
|
244
|
+
eventType: 'security_audit_completed',
|
|
245
|
+
message: `security:audit completed for ${slug} (exit=${exitCode})`,
|
|
246
|
+
status: 'completed',
|
|
247
|
+
agentName: options.runtimeAgentName || 'qa',
|
|
248
|
+
source: options.runtimeSource || 'direct',
|
|
249
|
+
workflowState: options.runtimeState || null,
|
|
250
|
+
workflowStage: options.runtimeWorkflowStage || 'qa',
|
|
251
|
+
payload: {
|
|
252
|
+
command: 'security:audit',
|
|
253
|
+
slug,
|
|
254
|
+
classification,
|
|
255
|
+
exitCode,
|
|
256
|
+
findingsCount: result.findingsCount,
|
|
257
|
+
artifactPath: writeResult.artifactPath,
|
|
258
|
+
summary,
|
|
259
|
+
strict
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
if (format === 'json' || options.json) {
|
|
264
|
+
return result;
|
|
265
|
+
}
|
|
266
|
+
const summaryLine = `security:audit (${slug}, ${classification}): ${summary.critical} critical, ${summary.high} high, ${summary.medium} medium, ${summary.low} low, ${summary.inconclusive} inconclusive (exit ${exitCode}).`;
|
|
267
|
+
logger.log(summaryLine);
|
|
268
|
+
for (const f of writeResult.payload.findings) {
|
|
269
|
+
if (f.status !== 'open' && f.status !== 'needs_validation') continue;
|
|
270
|
+
logger.log(` [${f.severity}] ${f.control_id} ${f.scope}`);
|
|
271
|
+
}
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
module.exports = { runSecurityAudit, GENERATOR, VERSION };
|