@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,416 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson compress:agents — Compress agent instruction files to reduce token usage
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* aioson compress:agents . # compress all agents (structural)
|
|
8
|
+
* aioson compress:agents . --agent=dev # compress specific agent
|
|
9
|
+
* aioson compress:agents . --agent=dev,analyst # compress multiple agents
|
|
10
|
+
* aioson compress:agents . --rules # also compress .aioson/rules/
|
|
11
|
+
* aioson compress:agents . --dry-run # preview savings without writing
|
|
12
|
+
* aioson compress:agents . --llm # LLM-assisted (needs ANTHROPIC_API_KEY)
|
|
13
|
+
* aioson compress:agents . --llm --model=haiku # choose model: haiku | sonnet | opus
|
|
14
|
+
* aioson compress:agents . --restore # restore from .original.md backups
|
|
15
|
+
* aioson compress:agents . --stats # show stats only (no changes)
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('node:fs/promises');
|
|
19
|
+
const path = require('node:path');
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Structural compression — no LLM required
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
// Section headers that are purely explanatory with no actionable content.
|
|
26
|
+
// Their rules are already implied by the surrounding content.
|
|
27
|
+
const REMOVABLE_SECTION_HEADERS = [
|
|
28
|
+
'por que isso importa',
|
|
29
|
+
'why this matters',
|
|
30
|
+
'why this is important',
|
|
31
|
+
'por que isso é importante',
|
|
32
|
+
'por que isso é relevante',
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
// Filler phrase prefixes to strip from the start of prose lines
|
|
36
|
+
const FILLER_PREFIXES = [
|
|
37
|
+
/^É importante (notar|ressaltar|observar|destacar) que\s*/i,
|
|
38
|
+
/^Vale (ressaltar|notar|destacar|observar) que\s*/i,
|
|
39
|
+
/^Deve-se (observar|notar|ressaltar) que\s*/i,
|
|
40
|
+
/^Cabe (notar|ressaltar|observar) que\s*/i,
|
|
41
|
+
/^It is important to (note|remember|understand) that\s*/i,
|
|
42
|
+
/^Note that\s*/i,
|
|
43
|
+
/^Please note that\s*/i,
|
|
44
|
+
/^Keep in mind that\s*/i,
|
|
45
|
+
/^As mentioned (earlier|above|before|previously)?,?\s*/i,
|
|
46
|
+
/^Observe que\s*/i,
|
|
47
|
+
/^Ressaltamos que\s*/i,
|
|
48
|
+
/^Destacamos que\s*/i,
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
// Trailing qualifiers that add no information — strip to end of sentence
|
|
52
|
+
const FILLER_TRAILERS = [
|
|
53
|
+
/ — o que (garante|assegura|permite|significa|implica)[^.]*\./g,
|
|
54
|
+
/ — isso (é|se torna|se tornou) (fundamental|importante|necessário|crítico) porque[^.]*\./g,
|
|
55
|
+
/, o que (é|se torna) (esperado|natural|correto)\./g,
|
|
56
|
+
/ como mencionado anteriormente/g,
|
|
57
|
+
/ como dito anteriormente/g,
|
|
58
|
+
/ as (previously|already) mentioned/g,
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Split markdown into an array of sections.
|
|
63
|
+
* Each section: { header: string|null, level: number|null, body: string }
|
|
64
|
+
* Respects fenced code blocks — headings inside code blocks are not treated as section boundaries.
|
|
65
|
+
*/
|
|
66
|
+
function splitSections(text) {
|
|
67
|
+
const sections = [];
|
|
68
|
+
const lines = text.split('\n');
|
|
69
|
+
let currentHeader = null;
|
|
70
|
+
let currentLevel = null;
|
|
71
|
+
let currentBody = [];
|
|
72
|
+
let inCodeBlock = false;
|
|
73
|
+
let frontmatterDone = false;
|
|
74
|
+
let frontmatterLines = [];
|
|
75
|
+
let inFrontmatter = false;
|
|
76
|
+
|
|
77
|
+
// Handle YAML frontmatter at the very top
|
|
78
|
+
if (lines[0] === '---') {
|
|
79
|
+
inFrontmatter = true;
|
|
80
|
+
frontmatterLines.push(lines[0]);
|
|
81
|
+
for (let i = 1; i < lines.length; i++) {
|
|
82
|
+
frontmatterLines.push(lines[i]);
|
|
83
|
+
if (lines[i] === '---') {
|
|
84
|
+
frontmatterDone = true;
|
|
85
|
+
// Emit as a special section with no header
|
|
86
|
+
sections.push({ header: null, level: null, body: frontmatterLines.join('\n') + '\n' });
|
|
87
|
+
frontmatterLines = [];
|
|
88
|
+
inFrontmatter = false;
|
|
89
|
+
// Process remaining lines normally
|
|
90
|
+
const remaining = lines.slice(i + 1);
|
|
91
|
+
return [...sections, ...splitSections(remaining.join('\n'))];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (inFrontmatter) {
|
|
95
|
+
// Malformed frontmatter — treat as body
|
|
96
|
+
return [{ header: null, level: null, body: text }];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (const line of lines) {
|
|
101
|
+
if (line.startsWith('```')) {
|
|
102
|
+
inCodeBlock = !inCodeBlock;
|
|
103
|
+
currentBody.push(line);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!inCodeBlock) {
|
|
108
|
+
const headingMatch = line.match(/^(#{1,3}) (.+)$/);
|
|
109
|
+
if (headingMatch) {
|
|
110
|
+
sections.push({ header: currentHeader, level: currentLevel, body: currentBody.join('\n') });
|
|
111
|
+
currentHeader = line;
|
|
112
|
+
currentLevel = headingMatch[1].length;
|
|
113
|
+
currentBody = [];
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
currentBody.push(line);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
sections.push({ header: currentHeader, level: currentLevel, body: currentBody.join('\n') });
|
|
122
|
+
return sections;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function shouldRemoveSection(header) {
|
|
126
|
+
if (!header) return false;
|
|
127
|
+
const normalized = header.replace(/^#+\s*/, '').toLowerCase().trim();
|
|
128
|
+
return REMOVABLE_SECTION_HEADERS.some(h => normalized === h);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function compressBody(body) {
|
|
132
|
+
let inCodeBlock = false;
|
|
133
|
+
const lines = body.split('\n').map(line => {
|
|
134
|
+
if (line.startsWith('```')) {
|
|
135
|
+
inCodeBlock = !inCodeBlock;
|
|
136
|
+
return line;
|
|
137
|
+
}
|
|
138
|
+
if (inCodeBlock) return line;
|
|
139
|
+
|
|
140
|
+
// Skip: headers, table rows, list items, blockquotes, empty lines
|
|
141
|
+
if (
|
|
142
|
+
line.startsWith('#') || line.startsWith('|') || line.startsWith('>') ||
|
|
143
|
+
line.startsWith('- ') || line.startsWith('* ') || line.startsWith(' - ') ||
|
|
144
|
+
line.startsWith(' * ') || line.trim() === ''
|
|
145
|
+
) return line;
|
|
146
|
+
|
|
147
|
+
let out = line;
|
|
148
|
+
|
|
149
|
+
for (const pattern of FILLER_PREFIXES) {
|
|
150
|
+
const replaced = out.replace(pattern, '');
|
|
151
|
+
if (replaced !== out) {
|
|
152
|
+
out = replaced.charAt(0).toUpperCase() + replaced.slice(1);
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
for (const pattern of FILLER_TRAILERS) {
|
|
158
|
+
out = out.replace(pattern, (m) => '.');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return out;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return lines.join('\n');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function compressStructural(text) {
|
|
168
|
+
const sections = splitSections(text);
|
|
169
|
+
const kept = sections.filter(s => !shouldRemoveSection(s.header));
|
|
170
|
+
|
|
171
|
+
const parts = kept.map(({ header, body }) => {
|
|
172
|
+
const h = header ? header + '\n' : '';
|
|
173
|
+
return h + compressBody(body);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
return parts.join('').replace(/\n{3,}/g, '\n\n').trimEnd() + '\n';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
// LLM compression — calls Anthropic Messages API via fetch
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
|
|
183
|
+
const MODEL_MAP = {
|
|
184
|
+
haiku: 'claude-haiku-4-5-20251001',
|
|
185
|
+
sonnet: 'claude-sonnet-4-6',
|
|
186
|
+
opus: 'claude-opus-4-6',
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const LLM_SYSTEM = `You are a markdown compression expert specializing in AI agent instruction files.
|
|
190
|
+
|
|
191
|
+
Compress the file the user sends. Goal: smallest possible file that preserves 100% of the technical meaning.
|
|
192
|
+
|
|
193
|
+
ALWAYS PRESERVE — never touch these:
|
|
194
|
+
- YAML frontmatter (--- blocks)
|
|
195
|
+
- All fenced code blocks (\`\`\` ... \`\`\`)
|
|
196
|
+
- All markdown tables (| ... |)
|
|
197
|
+
- File paths, URLs, bash commands, CLI flags
|
|
198
|
+
- Every rule, constraint, and actionable instruction
|
|
199
|
+
- Section headers that introduce actionable content
|
|
200
|
+
|
|
201
|
+
REMOVE OR COMPRESS:
|
|
202
|
+
- Sections titled "Por que isso importa" / "Why this matters" / "Rationale" — only if the rule already makes the reason obvious
|
|
203
|
+
- Preamble paragraphs that just restate what the section header says
|
|
204
|
+
- Filler phrase openers: "É importante notar que", "Vale ressaltar que", "It is important to note that", "Note that", "Keep in mind that", etc.
|
|
205
|
+
- Multi-paragraph explanations reducible to 1 dense sentence
|
|
206
|
+
- Trailing qualifiers that add no information
|
|
207
|
+
|
|
208
|
+
OUTPUT: Only the compressed markdown. No preamble, no commentary, no explanation.`;
|
|
209
|
+
|
|
210
|
+
async function compressWithLLM(text, apiKey, model) {
|
|
211
|
+
const resp = await fetch('https://api.anthropic.com/v1/messages', {
|
|
212
|
+
method: 'POST',
|
|
213
|
+
headers: {
|
|
214
|
+
'Content-Type': 'application/json',
|
|
215
|
+
'x-api-key': apiKey,
|
|
216
|
+
'anthropic-version': '2023-06-01',
|
|
217
|
+
},
|
|
218
|
+
body: JSON.stringify({
|
|
219
|
+
model,
|
|
220
|
+
max_tokens: 8192,
|
|
221
|
+
system: LLM_SYSTEM,
|
|
222
|
+
messages: [{ role: 'user', content: text }],
|
|
223
|
+
}),
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
if (!resp.ok) {
|
|
227
|
+
const body = await resp.text().catch(() => '');
|
|
228
|
+
throw new Error(`API ${resp.status}: ${body.slice(0, 200)}`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const data = await resp.json();
|
|
232
|
+
return data.content[0].text;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
// Restore from backups
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
|
|
239
|
+
async function runRestore(dir, agentFilter, logger) {
|
|
240
|
+
const files = (await fs.readdir(dir)).filter(f => f.endsWith('.original.md'));
|
|
241
|
+
const targets = agentFilter
|
|
242
|
+
? files.filter(f => agentFilter.some(a => f === `${a}.original.md`))
|
|
243
|
+
: files;
|
|
244
|
+
|
|
245
|
+
if (targets.length === 0) {
|
|
246
|
+
logger.log('No .original.md backup files found.');
|
|
247
|
+
return { ok: true, restored: 0 };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
for (const file of targets) {
|
|
251
|
+
const src = path.join(dir, file);
|
|
252
|
+
const dest = path.join(dir, file.replace('.original.md', '.md'));
|
|
253
|
+
await fs.copyFile(src, dest);
|
|
254
|
+
await fs.unlink(src);
|
|
255
|
+
logger.log(` Restored: ${file.replace('.original.md', '.md')}`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
logger.log(`\nRestored ${targets.length} file(s). Backup files removed.`);
|
|
259
|
+
return { ok: true, restored: targets.length };
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// ---------------------------------------------------------------------------
|
|
263
|
+
// Compress a single directory of .md files
|
|
264
|
+
// ---------------------------------------------------------------------------
|
|
265
|
+
|
|
266
|
+
async function compressDir(dir, { agentFilter, dryRun, useLLM, apiKey, model, logger }) {
|
|
267
|
+
let files;
|
|
268
|
+
try {
|
|
269
|
+
files = (await fs.readdir(dir)).filter(f => f.endsWith('.md') && !f.endsWith('.original.md'));
|
|
270
|
+
} catch {
|
|
271
|
+
return [];
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const targets = agentFilter
|
|
275
|
+
? files.filter(f => agentFilter.some(a => f === `${a}.md`))
|
|
276
|
+
: files;
|
|
277
|
+
|
|
278
|
+
const results = [];
|
|
279
|
+
|
|
280
|
+
for (const file of targets) {
|
|
281
|
+
const filePath = path.join(dir, file);
|
|
282
|
+
const backupPath = path.join(dir, file.replace('.md', '.original.md'));
|
|
283
|
+
|
|
284
|
+
const original = await fs.readFile(filePath, 'utf8');
|
|
285
|
+
const originalSize = Buffer.byteLength(original, 'utf8');
|
|
286
|
+
|
|
287
|
+
let compressed;
|
|
288
|
+
try {
|
|
289
|
+
compressed = useLLM
|
|
290
|
+
? await compressWithLLM(original, apiKey, model)
|
|
291
|
+
: compressStructural(original);
|
|
292
|
+
} catch (err) {
|
|
293
|
+
logger.error(` ✗ ${file}: ${err.message}`);
|
|
294
|
+
results.push({ file, ok: false, error: err.message });
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const compressedSize = Buffer.byteLength(compressed, 'utf8');
|
|
299
|
+
const saved = originalSize - compressedSize;
|
|
300
|
+
const pct = Math.round((saved / originalSize) * 100);
|
|
301
|
+
|
|
302
|
+
if (pct < 2) {
|
|
303
|
+
logger.log(` · ${file}: ${(originalSize / 1024).toFixed(1)}KB — already compact, skipped`);
|
|
304
|
+
results.push({ file, ok: true, skipped: true, originalSize });
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (dryRun) {
|
|
309
|
+
logger.log(` ~ ${file}: ${(originalSize / 1024).toFixed(1)}KB → ${(compressedSize / 1024).toFixed(1)}KB (−${pct}%)`);
|
|
310
|
+
} else {
|
|
311
|
+
// Write backup only if none exists
|
|
312
|
+
let backedUp = false;
|
|
313
|
+
try {
|
|
314
|
+
await fs.access(backupPath);
|
|
315
|
+
} catch {
|
|
316
|
+
await fs.writeFile(backupPath, original, 'utf8');
|
|
317
|
+
backedUp = true;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
await fs.writeFile(filePath, compressed, 'utf8');
|
|
321
|
+
const tag = backedUp ? ' ← backup saved' : '';
|
|
322
|
+
logger.log(` ✓ ${file}: ${(originalSize / 1024).toFixed(1)}KB → ${(compressedSize / 1024).toFixed(1)}KB (−${pct}%)${tag}`);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
results.push({ file, ok: true, skipped: false, originalSize, compressedSize, saved, pct });
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return results;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ---------------------------------------------------------------------------
|
|
332
|
+
// Main entry point
|
|
333
|
+
// ---------------------------------------------------------------------------
|
|
334
|
+
|
|
335
|
+
async function runCompressAgents({ args, options = {}, logger }) {
|
|
336
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
337
|
+
const agentsDir = path.join(targetDir, '.aioson', 'agents');
|
|
338
|
+
const rulesDir = path.join(targetDir, '.aioson', 'rules');
|
|
339
|
+
|
|
340
|
+
const dryRun = Boolean(options['dry-run'] || options.dry);
|
|
341
|
+
const useLLM = Boolean(options.llm);
|
|
342
|
+
const doRestore = Boolean(options.restore);
|
|
343
|
+
const alsoRules = Boolean(options.rules);
|
|
344
|
+
const statsOnly = Boolean(options.stats);
|
|
345
|
+
const agentFilter = options.agent
|
|
346
|
+
? String(options.agent).split(',').map(a => a.trim()).filter(Boolean)
|
|
347
|
+
: null;
|
|
348
|
+
|
|
349
|
+
// Resolve model alias → full model ID
|
|
350
|
+
const modelAlias = String(options.model || 'haiku').toLowerCase();
|
|
351
|
+
const model = MODEL_MAP[modelAlias] || modelAlias;
|
|
352
|
+
|
|
353
|
+
// --- RESTORE MODE ---
|
|
354
|
+
if (doRestore) {
|
|
355
|
+
try { await fs.access(agentsDir); } catch {
|
|
356
|
+
logger.error(`No .aioson/agents/ directory found in ${targetDir}`);
|
|
357
|
+
return { ok: false, error: 'no_agents_dir' };
|
|
358
|
+
}
|
|
359
|
+
return runRestore(agentsDir, agentFilter, logger);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// --- VALIDATE ---
|
|
363
|
+
try {
|
|
364
|
+
await fs.access(agentsDir);
|
|
365
|
+
} catch {
|
|
366
|
+
logger.error(`No .aioson/agents/ directory found in ${targetDir}`);
|
|
367
|
+
return { ok: false, error: 'no_agents_dir' };
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
let apiKey = null;
|
|
371
|
+
if (useLLM) {
|
|
372
|
+
apiKey = process.env.ANTHROPIC_API_KEY;
|
|
373
|
+
if (!apiKey) {
|
|
374
|
+
logger.error('--llm requires ANTHROPIC_API_KEY to be set');
|
|
375
|
+
return { ok: false, error: 'missing_api_key' };
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// --- COMPRESS ---
|
|
380
|
+
const mode = useLLM ? `LLM (${model})` : 'structural';
|
|
381
|
+
const action = dryRun ? 'Preview' : 'Compress';
|
|
382
|
+
logger.log(`${action} — mode: ${mode}`);
|
|
383
|
+
logger.log('');
|
|
384
|
+
|
|
385
|
+
const sharedOpts = { agentFilter, dryRun: dryRun || statsOnly, useLLM, apiKey, model, logger };
|
|
386
|
+
|
|
387
|
+
logger.log('Agents:');
|
|
388
|
+
const agentResults = await compressDir(agentsDir, sharedOpts);
|
|
389
|
+
|
|
390
|
+
let ruleResults = [];
|
|
391
|
+
if (alsoRules) {
|
|
392
|
+
logger.log('\nRules:');
|
|
393
|
+
ruleResults = await compressDir(rulesDir, { ...sharedOpts, agentFilter: null });
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const allResults = [...agentResults, ...ruleResults];
|
|
397
|
+
const compressed = allResults.filter(r => r.ok && !r.skipped);
|
|
398
|
+
const totalSaved = compressed.reduce((sum, r) => sum + (r.saved || 0), 0);
|
|
399
|
+
const errors = allResults.filter(r => !r.ok);
|
|
400
|
+
|
|
401
|
+
logger.log('');
|
|
402
|
+
logger.log(`─────────────────────────────────────`);
|
|
403
|
+
logger.log(`Files processed : ${allResults.length}`);
|
|
404
|
+
logger.log(`Compressed : ${compressed.length}`);
|
|
405
|
+
if (errors.length) logger.log(`Errors : ${errors.length}`);
|
|
406
|
+
logger.log(`Total saved : ${(totalSaved / 1024).toFixed(1)} KB`);
|
|
407
|
+
if (!dryRun && !statsOnly && compressed.length > 0) {
|
|
408
|
+
logger.log('');
|
|
409
|
+
logger.log('Backups: <agent>.original.md');
|
|
410
|
+
logger.log('Restore: aioson compress:agents . --restore');
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return { ok: true, results: allResults, totalSaved };
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
module.exports = { runCompressAgents };
|
|
@@ -93,7 +93,9 @@ async function runContextHealth({ args, options = {}, logger }) {
|
|
|
93
93
|
return doneFeatures.has(slug);
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
const
|
|
96
|
+
const dbResult = await openRuntimeDb(targetDir, { mustExist: true }).catch(() => ({ db: null, dbPath: null }));
|
|
97
|
+
const db = dbResult ? dbResult.db : null;
|
|
98
|
+
const dbPath = dbResult ? dbResult.dbPath : null;
|
|
97
99
|
const cacheHitRate = await getCacheHitRate(db);
|
|
98
100
|
if (db) db.close();
|
|
99
101
|
|
|
@@ -150,7 +152,7 @@ async function runContextHealth({ args, options = {}, logger }) {
|
|
|
150
152
|
const slug = s.file.replace(/^spec-/, '').replace(/\.md$/, '');
|
|
151
153
|
logger.log(` → ${s.file} (feature: ${slug} is done)`);
|
|
152
154
|
}
|
|
153
|
-
logger.log(` Run: aioson
|
|
155
|
+
logger.log(` Run: aioson feature:archive . --feature=<slug> to archive them`);
|
|
154
156
|
logger.log('');
|
|
155
157
|
}
|
|
156
158
|
|
|
@@ -104,12 +104,27 @@ async function runContextTrim({ args, options = {}, logger }) {
|
|
|
104
104
|
|
|
105
105
|
const totalStaleSaved = staleSpecs.reduce((s, r) => s + r.sizeBytes, 0);
|
|
106
106
|
|
|
107
|
+
// Archive stale specs (executed before any return, including JSON)
|
|
108
|
+
let archivedCount = 0;
|
|
109
|
+
if (staleSpecs.length > 0 && (force || dryRun)) {
|
|
110
|
+
if (!dryRun) {
|
|
111
|
+
await fs.mkdir(archiveDir, { recursive: true });
|
|
112
|
+
for (const s of staleSpecs) {
|
|
113
|
+
const src = path.join(contextDir, s.file);
|
|
114
|
+
const dest = path.join(archiveDir, s.file);
|
|
115
|
+
await fs.rename(src, dest);
|
|
116
|
+
}
|
|
117
|
+
archivedCount = staleSpecs.length;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
107
121
|
if (options.json) {
|
|
108
122
|
return {
|
|
109
123
|
ok: true,
|
|
110
124
|
staleSpecs,
|
|
111
125
|
largeSections,
|
|
112
126
|
totalStaleSavedBytes: totalStaleSaved,
|
|
127
|
+
archived: archivedCount,
|
|
113
128
|
dryRun
|
|
114
129
|
};
|
|
115
130
|
}
|
|
@@ -120,7 +135,7 @@ async function runContextTrim({ args, options = {}, logger }) {
|
|
|
120
135
|
if (staleSpecs.length === 0 && largeSections.length === 0) {
|
|
121
136
|
logger.log('✓ No stale specs or oversized sections found.');
|
|
122
137
|
logger.log('');
|
|
123
|
-
return { ok: true, staleSpecs: [], largeSections: [], totalStaleSavedBytes: 0, dryRun };
|
|
138
|
+
return { ok: true, staleSpecs: [], largeSections: [], totalStaleSavedBytes: 0, archived: 0, dryRun };
|
|
124
139
|
}
|
|
125
140
|
|
|
126
141
|
if (staleSpecs.length > 0) {
|
|
@@ -143,18 +158,9 @@ async function runContextTrim({ args, options = {}, logger }) {
|
|
|
143
158
|
logger.log('');
|
|
144
159
|
}
|
|
145
160
|
|
|
146
|
-
// Archive stale specs
|
|
147
161
|
if (staleSpecs.length > 0) {
|
|
148
162
|
if (force || dryRun) {
|
|
149
163
|
if (!dryRun) {
|
|
150
|
-
await fs.mkdir(archiveDir, { recursive: true });
|
|
151
|
-
for (const s of staleSpecs) {
|
|
152
|
-
const src = path.join(contextDir, s.file);
|
|
153
|
-
const dest = path.join(archiveDir, s.file);
|
|
154
|
-
await fs.rename(src, dest);
|
|
155
|
-
logger.log(` Archived: ${s.file} → context/archive/${s.file}`);
|
|
156
|
-
}
|
|
157
|
-
logger.log('');
|
|
158
164
|
logger.log(`${staleSpecs.length} spec(s) archived to .aioson/context/archive/`);
|
|
159
165
|
} else {
|
|
160
166
|
logger.log(`[dry-run] Would archive ${staleSpecs.length} stale spec(s) to .aioson/context/archive/`);
|
|
@@ -169,7 +175,7 @@ async function runContextTrim({ args, options = {}, logger }) {
|
|
|
169
175
|
staleSpecs,
|
|
170
176
|
largeSections,
|
|
171
177
|
totalStaleSavedBytes: totalStaleSaved,
|
|
172
|
-
archived:
|
|
178
|
+
archived: archivedCount,
|
|
173
179
|
dryRun
|
|
174
180
|
};
|
|
175
181
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const fs = require('node:fs/promises');
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
const readline = require('node:readline');
|
|
6
|
-
const { validateProjectContextFile } = require('../context');
|
|
6
|
+
const { validateProjectContextFile, getInteractionLanguage } = require('../context');
|
|
7
7
|
const { resolveAgentLocale } = require('../locales');
|
|
8
8
|
const { ensureDir } = require('../utils');
|
|
9
9
|
const {
|
|
@@ -17,9 +17,9 @@ function resolveTargetDir(args) {
|
|
|
17
17
|
|
|
18
18
|
async function detectProjectLocale(targetDir) {
|
|
19
19
|
const context = await validateProjectContextFile(targetDir);
|
|
20
|
-
if (context.parsed && context.data
|
|
20
|
+
if (context.parsed && context.data) {
|
|
21
21
|
return {
|
|
22
|
-
locale: resolveAgentLocale(context.data
|
|
22
|
+
locale: resolveAgentLocale(getInteractionLanguage(context.data, 'en')),
|
|
23
23
|
source: 'project-context'
|
|
24
24
|
};
|
|
25
25
|
}
|
|
@@ -27,10 +27,11 @@ function parseFrontmatter(content) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function extractSection(content, sectionName) {
|
|
30
|
-
const
|
|
30
|
+
const escapedSection = String(sectionName).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
31
|
+
const re = new RegExp(`(?:^|\\r?\\n)#{1,4}\\s+${escapedSection}[^\\n]*\\r?\\n([\\s\\S]*?)(?=\\r?\\n#{1,4}\\s+|$)`, 'i');
|
|
31
32
|
const match = content.match(re);
|
|
32
33
|
if (!match) return '';
|
|
33
|
-
return match[
|
|
34
|
+
return match[1].trim();
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
function extractListItems(content, sectionName) {
|
|
@@ -186,14 +187,15 @@ async function processDevlogFile(db, filePath) {
|
|
|
186
187
|
}
|
|
187
188
|
|
|
188
189
|
// Close run
|
|
189
|
-
updateRun(db,
|
|
190
|
+
updateRun(db, {
|
|
191
|
+
runKey,
|
|
190
192
|
status,
|
|
191
193
|
summary,
|
|
192
194
|
finishedAt
|
|
193
195
|
});
|
|
194
196
|
|
|
195
197
|
if (status === 'completed') {
|
|
196
|
-
updateTask(db, taskKey,
|
|
198
|
+
updateTask(db, { taskKey, status: 'completed', finishedAt });
|
|
197
199
|
}
|
|
198
200
|
|
|
199
201
|
// Mark devlog as processed
|