@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
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson commit:prepare — pre-collect commit context so @committer spends tokens
|
|
5
|
+
* only on creative work (message writing), not on file exploration.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* aioson commit:prepare .
|
|
9
|
+
* aioson commit:prepare . --staged-only
|
|
10
|
+
* aioson commit:prepare . --agent-safe --staged-only --mode=headless
|
|
11
|
+
* aioson commit:prepare . --json
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const fs = require('node:fs');
|
|
15
|
+
const path = require('node:path');
|
|
16
|
+
const { execFileSync } = require('node:child_process');
|
|
17
|
+
const readline = require('node:readline');
|
|
18
|
+
const { runGitGuard } = require('./git-guard');
|
|
19
|
+
const { promptCheckbox } = require('../lib/terminal-checkbox');
|
|
20
|
+
|
|
21
|
+
function runGit(gitRoot, args, options = {}) {
|
|
22
|
+
return execFileSync('git', args, {
|
|
23
|
+
cwd: gitRoot,
|
|
24
|
+
encoding: options.encoding || 'utf8',
|
|
25
|
+
maxBuffer: options.maxBuffer || 8 * 1024 * 1024,
|
|
26
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function resolveGitRoot(projectDir) {
|
|
31
|
+
return String(runGit(projectDir, ['rev-parse', '--show-toplevel'])).trim();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function parseGitStatusShort(gitRoot) {
|
|
35
|
+
const output = runGit(gitRoot, ['status', '--short']);
|
|
36
|
+
const lines = output.split('\n').filter(Boolean);
|
|
37
|
+
const staged = [];
|
|
38
|
+
const unstaged = [];
|
|
39
|
+
const untracked = [];
|
|
40
|
+
|
|
41
|
+
for (const line of lines) {
|
|
42
|
+
const status = line.slice(0, 2);
|
|
43
|
+
const rawPath = line.slice(3);
|
|
44
|
+
// Handle "R" rename format: "R old -> new"
|
|
45
|
+
const filePath = rawPath.includes(' -> ') ? rawPath.split(' -> ').pop() : rawPath;
|
|
46
|
+
|
|
47
|
+
const isStaged = status[0] !== ' ' && status[0] !== '?';
|
|
48
|
+
const isUnstaged = status[1] !== ' ' && status[1] !== '?';
|
|
49
|
+
const isUntracked = status === '??';
|
|
50
|
+
|
|
51
|
+
if (isUntracked) {
|
|
52
|
+
untracked.push(filePath);
|
|
53
|
+
} else {
|
|
54
|
+
if (isStaged) staged.push(filePath);
|
|
55
|
+
if (isUnstaged) unstaged.push(filePath);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return { staged, unstaged, untracked };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function askQuestion(rl, questionText) {
|
|
63
|
+
return new Promise((resolve) => {
|
|
64
|
+
rl.question(questionText, (answer) => {
|
|
65
|
+
resolve(answer.trim());
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function promptFileSelectionCheckbox(files) {
|
|
71
|
+
if (files.length === 0) return [];
|
|
72
|
+
|
|
73
|
+
process.stdout.write('\nSelecione os arquivos para adicionar ao stage (todos começam marcados):\n');
|
|
74
|
+
|
|
75
|
+
const selected = await promptCheckbox(files);
|
|
76
|
+
|
|
77
|
+
return selected; // null = cancelado pelo usuário
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function promptYesNo(questionText) {
|
|
81
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
82
|
+
const answer = await askQuestion(rl, `${questionText} (s/N): `);
|
|
83
|
+
rl.close();
|
|
84
|
+
return answer.toLowerCase() === 's' || answer.toLowerCase() === 'sim';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function promptMenu(items, questionText) {
|
|
88
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
89
|
+
|
|
90
|
+
process.stdout.write('\n');
|
|
91
|
+
items.forEach((item, i) => {
|
|
92
|
+
process.stdout.write(` ${i + 1}. ${item}\n`);
|
|
93
|
+
});
|
|
94
|
+
process.stdout.write('\n');
|
|
95
|
+
|
|
96
|
+
const answer = await askQuestion(rl, `${questionText} `);
|
|
97
|
+
rl.close();
|
|
98
|
+
|
|
99
|
+
const num = parseInt(answer, 10);
|
|
100
|
+
if (isNaN(num) || num < 1 || num > items.length) return -1;
|
|
101
|
+
return num;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function resolveGuardFindings(gitRoot, guardResult, logger) {
|
|
105
|
+
const findings = [
|
|
106
|
+
...(guardResult.errors || []).map((f) => ({ ...f, severity: 'error' })),
|
|
107
|
+
...(guardResult.warnings || []).map((f) => ({ ...f, severity: 'warning' }))
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
if (findings.length === 0) return true;
|
|
111
|
+
|
|
112
|
+
const guardPath = path.join(gitRoot, '.aioson', 'git-guard.json');
|
|
113
|
+
let guardConfig = {};
|
|
114
|
+
try {
|
|
115
|
+
guardConfig = JSON.parse(fs.readFileSync(guardPath, 'utf8'));
|
|
116
|
+
} catch {
|
|
117
|
+
guardConfig = { version: 1, allowPaths: [], contentAllowPaths: [], blockPaths: [], allowExtensions: [], blockExtensions: [] };
|
|
118
|
+
}
|
|
119
|
+
if (!Array.isArray(guardConfig.contentAllowPaths)) guardConfig.contentAllowPaths = [];
|
|
120
|
+
if (!Array.isArray(guardConfig.blockPaths)) guardConfig.blockPaths = [];
|
|
121
|
+
|
|
122
|
+
const toUnstage = [];
|
|
123
|
+
let guardConfigChanged = false;
|
|
124
|
+
|
|
125
|
+
for (const finding of findings) {
|
|
126
|
+
const label = finding.severity === 'error' ? '[ERRO]' : '[AVISO]';
|
|
127
|
+
process.stdout.write(`\n${label} ${finding.path}\n`);
|
|
128
|
+
process.stdout.write(` Motivo: ${finding.reason} [${finding.id}]\n`);
|
|
129
|
+
|
|
130
|
+
const isContent = finding.type === 'content';
|
|
131
|
+
const menuItems = [];
|
|
132
|
+
const actions = [];
|
|
133
|
+
|
|
134
|
+
if (isContent) {
|
|
135
|
+
menuItems.push('Marcar como confiável (adicionar a contentAllowPaths — falso positivo)');
|
|
136
|
+
actions.push('content_allow');
|
|
137
|
+
}
|
|
138
|
+
menuItems.push('Bloquear permanentemente (adicionar a blockPaths)');
|
|
139
|
+
actions.push('block');
|
|
140
|
+
menuItems.push('Remover do stage (não comitar agora)');
|
|
141
|
+
actions.push('unstage');
|
|
142
|
+
if (finding.severity === 'warning') {
|
|
143
|
+
menuItems.push('Ignorar este aviso e continuar');
|
|
144
|
+
actions.push('ignore');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const choice = await promptMenu(menuItems, 'O que fazer com este arquivo?');
|
|
148
|
+
if (choice === -1) {
|
|
149
|
+
logger.log('Entrada inválida — mantendo bloqueio.');
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const action = actions[choice - 1];
|
|
154
|
+
|
|
155
|
+
if (action === 'content_allow') {
|
|
156
|
+
if (!guardConfig.contentAllowPaths.includes(finding.path)) {
|
|
157
|
+
guardConfig.contentAllowPaths.push(finding.path);
|
|
158
|
+
guardConfigChanged = true;
|
|
159
|
+
logger.log(` ✔ Adicionado a contentAllowPaths: ${finding.path}`);
|
|
160
|
+
}
|
|
161
|
+
} else if (action === 'block') {
|
|
162
|
+
const pattern = `${finding.path.includes('**') ? finding.path : finding.path}`;
|
|
163
|
+
if (!guardConfig.blockPaths.includes(pattern)) {
|
|
164
|
+
guardConfig.blockPaths.push(pattern);
|
|
165
|
+
guardConfigChanged = true;
|
|
166
|
+
logger.log(` ✔ Adicionado a blockPaths: ${pattern}`);
|
|
167
|
+
}
|
|
168
|
+
} else if (action === 'unstage') {
|
|
169
|
+
toUnstage.push(finding.path);
|
|
170
|
+
logger.log(` ✔ Marcado para remover do stage: ${finding.path}`);
|
|
171
|
+
} else if (action === 'ignore') {
|
|
172
|
+
logger.log(` ✔ Aviso ignorado: ${finding.path}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (guardConfigChanged) {
|
|
177
|
+
try {
|
|
178
|
+
fs.writeFileSync(guardPath, `${JSON.stringify(guardConfig, null, 2)}\n`, 'utf8');
|
|
179
|
+
logger.log('\n✔ git-guard.json atualizado.');
|
|
180
|
+
} catch (err) {
|
|
181
|
+
logger.error(`Não foi possível salvar git-guard.json: ${err.message}`);
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (toUnstage.length > 0) {
|
|
187
|
+
try {
|
|
188
|
+
runGit(gitRoot, ['restore', '--staged', '--', ...toUnstage]);
|
|
189
|
+
logger.log(`✔ Removidos do stage: ${toUnstage.join(', ')}`);
|
|
190
|
+
} catch (err) {
|
|
191
|
+
logger.error(`Falha ao remover do stage: ${err.message}`);
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function findLatestRelevantPlan(gitRoot) {
|
|
200
|
+
const candidates = [
|
|
201
|
+
path.join(gitRoot, '.aioson', 'plans'),
|
|
202
|
+
path.join(gitRoot, 'plans')
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
for (const dir of candidates) {
|
|
206
|
+
if (!fs.existsSync(dir)) continue;
|
|
207
|
+
const entries = fs.readdirSync(dir)
|
|
208
|
+
.map((name) => {
|
|
209
|
+
const full = path.join(dir, name);
|
|
210
|
+
try {
|
|
211
|
+
const stat = fs.statSync(full);
|
|
212
|
+
return { name, full, mtime: stat.mtime };
|
|
213
|
+
} catch {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
.filter(Boolean)
|
|
218
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
219
|
+
|
|
220
|
+
for (const entry of entries) {
|
|
221
|
+
const manifest = path.join(entry.full, 'manifest.md');
|
|
222
|
+
if (fs.existsSync(manifest)) {
|
|
223
|
+
try {
|
|
224
|
+
return fs.readFileSync(manifest, 'utf8');
|
|
225
|
+
} catch {
|
|
226
|
+
// ignore read errors
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function isPrepStale(prep) {
|
|
236
|
+
if (!prep || !prep.generatedAt) return true;
|
|
237
|
+
const generated = new Date(prep.generatedAt).getTime();
|
|
238
|
+
const now = Date.now();
|
|
239
|
+
return Number.isNaN(generated) || now - generated > 30 * 60 * 1000;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function wasPrepCommitted(prep) {
|
|
243
|
+
return Boolean(prep && prep.committedAt);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function runCommitPrepare({ args, options, logger }) {
|
|
247
|
+
const projectDir = path.resolve(process.cwd(), args[0] || '.');
|
|
248
|
+
const jsonMode = Boolean(options.json);
|
|
249
|
+
const stagedOnly = Boolean(options['staged-only'] || options.stagedOnly);
|
|
250
|
+
const agentSafe = Boolean(options['agent-safe'] || options.agentSafe);
|
|
251
|
+
const requestedMode = String(options.mode || '').trim().toLowerCase();
|
|
252
|
+
const headlessMode = requestedMode === 'headless' || agentSafe;
|
|
253
|
+
const nonInteractive = jsonMode || Boolean(options['non-interactive'] || options.nonInteractive) || agentSafe;
|
|
254
|
+
const hasTty = Boolean(process.stdin && process.stdin.isTTY && process.stdout && process.stdout.isTTY);
|
|
255
|
+
const interactiveSelectionAllowed = !nonInteractive && hasTty && !headlessMode;
|
|
256
|
+
|
|
257
|
+
let gitRoot;
|
|
258
|
+
try {
|
|
259
|
+
gitRoot = resolveGitRoot(projectDir);
|
|
260
|
+
} catch (error) {
|
|
261
|
+
const failure = {
|
|
262
|
+
ok: false,
|
|
263
|
+
error: 'not_a_git_repository',
|
|
264
|
+
message: `Unable to find git root in ${projectDir}: ${error.message}`
|
|
265
|
+
};
|
|
266
|
+
if (jsonMode) return failure;
|
|
267
|
+
logger.error(failure.message);
|
|
268
|
+
process.exitCode = 1;
|
|
269
|
+
return failure;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const prepDir = path.join(gitRoot, '.aioson', 'context');
|
|
273
|
+
const prepPath = path.join(prepDir, 'commit-prep.json');
|
|
274
|
+
|
|
275
|
+
const { staged, unstaged, untracked } = parseGitStatusShort(gitRoot);
|
|
276
|
+
|
|
277
|
+
let existingPrep = null;
|
|
278
|
+
try {
|
|
279
|
+
existingPrep = JSON.parse(fs.readFileSync(prepPath, 'utf8'));
|
|
280
|
+
} catch {
|
|
281
|
+
existingPrep = null;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const currentStagedSet = new Set(staged);
|
|
285
|
+
const prepStagedSet = new Set(Array.isArray(existingPrep?.stagedFiles) ? existingPrep.stagedFiles : []);
|
|
286
|
+
const stagedFilesChanged = currentStagedSet.size !== prepStagedSet.size || [...currentStagedSet].some((f) => !prepStagedSet.has(f));
|
|
287
|
+
|
|
288
|
+
const shouldReuse = existingPrep && existingPrep.ready && !isPrepStale(existingPrep) && !wasPrepCommitted(existingPrep) && !stagedFilesChanged;
|
|
289
|
+
|
|
290
|
+
if (shouldReuse && stagedOnly) {
|
|
291
|
+
if (!jsonMode) {
|
|
292
|
+
logger.log('Reutilizando commit-prep.json existente e válido.');
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
ok: true,
|
|
296
|
+
gitRoot,
|
|
297
|
+
prepPath,
|
|
298
|
+
reused: true,
|
|
299
|
+
stagedCount: Array.isArray(existingPrep.stagedFiles) ? existingPrep.stagedFiles.length : 0,
|
|
300
|
+
guardOk: Boolean(existingPrep.guard && existingPrep.guard.ok),
|
|
301
|
+
ready: true
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
const allModified = [...new Set([...unstaged, ...untracked])];
|
|
305
|
+
|
|
306
|
+
let filesToStage = [];
|
|
307
|
+
|
|
308
|
+
if (stagedOnly) {
|
|
309
|
+
filesToStage = [];
|
|
310
|
+
if (!jsonMode) {
|
|
311
|
+
logger.log('Modo --staged-only: usando apenas arquivos já no stage.');
|
|
312
|
+
}
|
|
313
|
+
} else if (allModified.length > 0) {
|
|
314
|
+
if (!jsonMode) {
|
|
315
|
+
logger.log('Arquivos modificados ou não rastreados encontrados:');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (!interactiveSelectionAllowed) {
|
|
319
|
+
const failure = {
|
|
320
|
+
ok: false,
|
|
321
|
+
error: headlessMode ? 'explicit_staging_required_in_headless' : 'explicit_staging_required',
|
|
322
|
+
message: headlessMode
|
|
323
|
+
? 'Modo agent-safe/headless não pode abrir seleção interativa de arquivos. Faça stage explícito antes de continuar ou rode com --staged-only se quiser usar somente o stage atual.'
|
|
324
|
+
: 'Modo não interativo sem TTY não pode abrir seleção de arquivos. Faça stage explícito antes de continuar ou rode com --staged-only.',
|
|
325
|
+
gitRoot,
|
|
326
|
+
stagedFiles: staged,
|
|
327
|
+
unstagedFiles: unstaged,
|
|
328
|
+
untrackedFiles: untracked,
|
|
329
|
+
modifiedFiles: allModified,
|
|
330
|
+
suggestedCommands: headlessMode
|
|
331
|
+
? [
|
|
332
|
+
'git add -- <explicit-paths>',
|
|
333
|
+
'aioson commit:prepare . --agent-safe --staged-only --mode=headless'
|
|
334
|
+
]
|
|
335
|
+
: [
|
|
336
|
+
'git add -- <explicit-paths>',
|
|
337
|
+
'aioson commit:prepare . --staged-only'
|
|
338
|
+
],
|
|
339
|
+
ready: false,
|
|
340
|
+
nonInteractive: true,
|
|
341
|
+
agentSafe,
|
|
342
|
+
mode: requestedMode || null
|
|
343
|
+
};
|
|
344
|
+
if (jsonMode) return failure;
|
|
345
|
+
logger.error(failure.message);
|
|
346
|
+
logger.error('Comandos sugeridos:');
|
|
347
|
+
failure.suggestedCommands.forEach((command) => logger.error(` ${command}`));
|
|
348
|
+
process.exitCode = 1;
|
|
349
|
+
return failure;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const choice = await promptMenu([
|
|
353
|
+
'selecionar arquivos específicos',
|
|
354
|
+
'prosseguir apenas com o que já está no stage',
|
|
355
|
+
'cancelar'
|
|
356
|
+
], 'O que deseja fazer?');
|
|
357
|
+
|
|
358
|
+
if (choice === 1) {
|
|
359
|
+
const selected = await promptFileSelectionCheckbox(allModified);
|
|
360
|
+
if (selected === null) {
|
|
361
|
+
const cancelResult = { ok: false, error: 'cancelled_by_user', message: 'Operação cancelada pelo usuário.' };
|
|
362
|
+
if (jsonMode) return cancelResult;
|
|
363
|
+
logger.log('Cancelado.');
|
|
364
|
+
return cancelResult;
|
|
365
|
+
}
|
|
366
|
+
filesToStage = selected;
|
|
367
|
+
} else if (choice === 2) {
|
|
368
|
+
filesToStage = [];
|
|
369
|
+
} else {
|
|
370
|
+
const cancelResult = { ok: false, error: 'cancelled_by_user', message: 'Operação cancelada pelo usuário.' };
|
|
371
|
+
if (jsonMode) return cancelResult;
|
|
372
|
+
logger.log('Cancelado.');
|
|
373
|
+
return cancelResult;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (filesToStage.length > 0) {
|
|
378
|
+
try {
|
|
379
|
+
runGit(gitRoot, ['add', '--', ...filesToStage]);
|
|
380
|
+
if (!jsonMode) {
|
|
381
|
+
logger.log(`Adicionados ao stage: ${filesToStage.join(', ')}`);
|
|
382
|
+
}
|
|
383
|
+
} catch (error) {
|
|
384
|
+
const failure = {
|
|
385
|
+
ok: false,
|
|
386
|
+
error: 'git_add_failed',
|
|
387
|
+
message: `git add failed: ${error.message}`
|
|
388
|
+
};
|
|
389
|
+
if (jsonMode) return failure;
|
|
390
|
+
logger.error(failure.message);
|
|
391
|
+
process.exitCode = 1;
|
|
392
|
+
return failure;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Re-read staged files after add
|
|
397
|
+
const afterAddStatus = parseGitStatusShort(gitRoot);
|
|
398
|
+
const stagedFiles = afterAddStatus.staged;
|
|
399
|
+
|
|
400
|
+
if (stagedFiles.length === 0) {
|
|
401
|
+
const emptyResult = {
|
|
402
|
+
ok: false,
|
|
403
|
+
error: 'no_staged_files',
|
|
404
|
+
message: 'Nenhum arquivo no stage para commit.',
|
|
405
|
+
gitRoot,
|
|
406
|
+
stagedFiles: [],
|
|
407
|
+
ready: false
|
|
408
|
+
};
|
|
409
|
+
if (jsonMode) return emptyResult;
|
|
410
|
+
logger.error(emptyResult.message);
|
|
411
|
+
process.exitCode = 1;
|
|
412
|
+
return emptyResult;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Run git guard
|
|
416
|
+
let guardResult = await runGitGuard({
|
|
417
|
+
args: [projectDir],
|
|
418
|
+
options: { json: true },
|
|
419
|
+
logger: { log: () => {}, error: () => {} }
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
if (!guardResult.ok) {
|
|
423
|
+
if (jsonMode) {
|
|
424
|
+
return {
|
|
425
|
+
ok: false,
|
|
426
|
+
error: 'guard_failed',
|
|
427
|
+
message: 'aioson git:guard bloqueou o commit. Corrija os problemas antes de continuar.',
|
|
428
|
+
gitRoot,
|
|
429
|
+
guard: guardResult,
|
|
430
|
+
stagedFiles,
|
|
431
|
+
ready: false
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (!interactiveSelectionAllowed) {
|
|
436
|
+
logger.error('aioson git:guard bloqueou o commit. Corrija os problemas antes de continuar.');
|
|
437
|
+
if (guardResult.errors && guardResult.errors.length > 0) {
|
|
438
|
+
logger.error('Erros:');
|
|
439
|
+
guardResult.errors.forEach((e) => logger.error(` - ${e.path}: ${e.reason} [${e.id}]`));
|
|
440
|
+
}
|
|
441
|
+
if (guardResult.warnings && guardResult.warnings.length > 0) {
|
|
442
|
+
logger.error('Avisos:');
|
|
443
|
+
guardResult.warnings.forEach((w) => logger.error(` - ${w.path}: ${w.reason} [${w.id}]`));
|
|
444
|
+
}
|
|
445
|
+
process.exitCode = 1;
|
|
446
|
+
return { ok: false, error: 'guard_failed', message: 'guard bloqueou', gitRoot, guard: guardResult, stagedFiles, ready: false };
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Interactive resolution
|
|
450
|
+
logger.log('\n⚠ git:guard encontrou problemas. Você pode resolver cada um agora:');
|
|
451
|
+
const resolved = await resolveGuardFindings(gitRoot, guardResult, logger);
|
|
452
|
+
if (!resolved) {
|
|
453
|
+
process.exitCode = 1;
|
|
454
|
+
return { ok: false, error: 'guard_resolution_cancelled', message: 'Resolução cancelada pelo usuário.', gitRoot, stagedFiles, ready: false };
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Re-run guard after resolution
|
|
458
|
+
guardResult = await runGitGuard({
|
|
459
|
+
args: [projectDir],
|
|
460
|
+
options: { json: true },
|
|
461
|
+
logger: { log: () => {}, error: () => {} }
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
if (!guardResult.ok) {
|
|
465
|
+
logger.error('\n✖ git:guard ainda bloqueado após resolução:');
|
|
466
|
+
(guardResult.errors || []).forEach((e) => logger.error(` [ERRO] ${e.path}: ${e.reason}`));
|
|
467
|
+
(guardResult.warnings || []).forEach((w) => logger.error(` [AVISO] ${w.path}: ${w.reason}`));
|
|
468
|
+
process.exitCode = 1;
|
|
469
|
+
return { ok: false, error: 'guard_failed', message: 'guard ainda bloqueado após resolução', gitRoot, guard: guardResult, stagedFiles, ready: false };
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Re-read staged files — resolution may have unstaged some
|
|
474
|
+
const finalStagedFiles = parseGitStatusShort(gitRoot).staged;
|
|
475
|
+
|
|
476
|
+
// Collect diff
|
|
477
|
+
let diff = '';
|
|
478
|
+
try {
|
|
479
|
+
diff = runGit(gitRoot, ['diff', '--staged']);
|
|
480
|
+
} catch (error) {
|
|
481
|
+
diff = `// error reading diff: ${error.message}`;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Collect recent log
|
|
485
|
+
let recentLog = [];
|
|
486
|
+
try {
|
|
487
|
+
const logOutput = runGit(gitRoot, ['log', '-n', '3', '--oneline']);
|
|
488
|
+
recentLog = logOutput.split('\n').filter(Boolean);
|
|
489
|
+
} catch {
|
|
490
|
+
recentLog = [];
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Collect project pulse
|
|
494
|
+
let projectPulse = null;
|
|
495
|
+
const pulsePath = path.join(gitRoot, '.aioson', 'context', 'project-pulse.md');
|
|
496
|
+
if (fs.existsSync(pulsePath)) {
|
|
497
|
+
try {
|
|
498
|
+
projectPulse = fs.readFileSync(pulsePath, 'utf8');
|
|
499
|
+
} catch {
|
|
500
|
+
projectPulse = null;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Collect relevant plan
|
|
505
|
+
const relevantPlan = findLatestRelevantPlan(gitRoot);
|
|
506
|
+
|
|
507
|
+
const prep = {
|
|
508
|
+
generatedAt: new Date().toISOString(),
|
|
509
|
+
gitRoot,
|
|
510
|
+
preparationMode: agentSafe ? 'agent_safe' : stagedOnly ? 'staged_only' : interactiveSelectionAllowed ? 'interactive' : 'non_interactive',
|
|
511
|
+
status: {
|
|
512
|
+
staged,
|
|
513
|
+
unstaged,
|
|
514
|
+
untracked,
|
|
515
|
+
filesToStage
|
|
516
|
+
},
|
|
517
|
+
stagedFiles: finalStagedFiles,
|
|
518
|
+
guard: guardResult,
|
|
519
|
+
diff,
|
|
520
|
+
recentLog,
|
|
521
|
+
projectPulse,
|
|
522
|
+
relevantPlan,
|
|
523
|
+
ready: true
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
fs.mkdirSync(prepDir, { recursive: true });
|
|
527
|
+
fs.writeFileSync(prepPath, JSON.stringify(prep, null, 2), 'utf8');
|
|
528
|
+
|
|
529
|
+
if (!jsonMode) {
|
|
530
|
+
logger.log(`\n✔ Commit prep pronto. Dados salvos em: ${prepPath}`);
|
|
531
|
+
logger.log(` Arquivos no stage: ${finalStagedFiles.length}`);
|
|
532
|
+
logger.log(` Guard: passou`);
|
|
533
|
+
logger.log(` Diff: ${diff.split('\n').length} linhas`);
|
|
534
|
+
logger.log(`\nAgora ative @committer — ele usará esses dados sem gastar tokens em exploração.`);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return {
|
|
538
|
+
ok: true,
|
|
539
|
+
gitRoot,
|
|
540
|
+
prepPath,
|
|
541
|
+
stagedCount: finalStagedFiles.length,
|
|
542
|
+
guardOk: true,
|
|
543
|
+
ready: true
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
module.exports = { runCommitPrepare };
|