@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
package/src/commands/live.js
CHANGED
|
@@ -18,6 +18,8 @@ const {
|
|
|
18
18
|
} = require('../runtime-store');
|
|
19
19
|
const { ensureDir, exists } = require('../utils');
|
|
20
20
|
const { SUPPORTED_PROMPT_TOOLS } = require('../prompt-tool');
|
|
21
|
+
const { isTmuxAvailable, launchTmuxSession, buildSessionName, hasSession, attachSession } = require('../lib/tmux-launcher');
|
|
22
|
+
const { resolveResumeArgs } = require('../lib/tool-capabilities');
|
|
21
23
|
|
|
22
24
|
const LIVE_EVENTS_LIMIT = 10;
|
|
23
25
|
const LIVE_MESSAGE_LIMIT = 500;
|
|
@@ -99,6 +101,15 @@ function parseJsonOption(value) {
|
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
|
|
104
|
+
// Combine `--resume` (mapped per-tool via TOOL_CAPS) with user-provided `--tool-args`.
|
|
105
|
+
// Resume args go FIRST so that codex `resume --last` (subcommand) lands at argv[1].
|
|
106
|
+
function buildLaunchArgs(options, tool) {
|
|
107
|
+
const resumeOpt = options.resume !== undefined ? options.resume : options.Resume;
|
|
108
|
+
const resumeArgs = resolveResumeArgs(tool, resumeOpt);
|
|
109
|
+
const userArgs = parseToolArgs(options['tool-args'] || options.toolArgs);
|
|
110
|
+
return [...resumeArgs, ...userArgs];
|
|
111
|
+
}
|
|
112
|
+
|
|
102
113
|
function parseToolArgs(value) {
|
|
103
114
|
if (value === undefined || value === null || value === '') return [];
|
|
104
115
|
if (Array.isArray(value)) return value.map((entry) => String(entry));
|
|
@@ -732,6 +743,245 @@ function renderLiveSummary(snapshot) {
|
|
|
732
743
|
return lines.join('\n');
|
|
733
744
|
}
|
|
734
745
|
|
|
746
|
+
// ANSI color helpers (no external deps)
|
|
747
|
+
const ANSI = {
|
|
748
|
+
reset: '\x1b[0m',
|
|
749
|
+
bold: '\x1b[1m',
|
|
750
|
+
dim: '\x1b[2m',
|
|
751
|
+
green: '\x1b[32m',
|
|
752
|
+
yellow: '\x1b[33m',
|
|
753
|
+
red: '\x1b[31m',
|
|
754
|
+
cyan: '\x1b[36m',
|
|
755
|
+
magenta: '\x1b[35m',
|
|
756
|
+
blue: '\x1b[34m',
|
|
757
|
+
gray: '\x1b[90m'
|
|
758
|
+
};
|
|
759
|
+
|
|
760
|
+
function colorForContext(pct) {
|
|
761
|
+
if (pct >= 90) return ANSI.red;
|
|
762
|
+
if (pct >= 70) return ANSI.yellow;
|
|
763
|
+
return ANSI.green;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
function colorForPhase(phase) {
|
|
767
|
+
if (phase === 'active') return ANSI.green;
|
|
768
|
+
if (phase === 'closed') return ANSI.gray;
|
|
769
|
+
return ANSI.yellow;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function colorForProcess(state) {
|
|
773
|
+
if (state === 'alive') return ANSI.green;
|
|
774
|
+
if (state === 'dead') return ANSI.red;
|
|
775
|
+
return ANSI.gray;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
function formatDurationCompact(startedAt) {
|
|
779
|
+
if (!startedAt) return '';
|
|
780
|
+
const ms = Date.now() - Date.parse(startedAt);
|
|
781
|
+
if (!Number.isFinite(ms) || ms < 0) return '';
|
|
782
|
+
const m = Math.floor(ms / 60000);
|
|
783
|
+
const s = Math.floor((ms % 60000) / 1000);
|
|
784
|
+
if (m > 60) {
|
|
785
|
+
const h = Math.floor(m / 60);
|
|
786
|
+
return `${h}h${m % 60}m`;
|
|
787
|
+
}
|
|
788
|
+
return `${m}m${s}s`;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* Print a one-line compact status bar with ANSI colors.
|
|
793
|
+
* Designed for small tmux panes (~4 lines).
|
|
794
|
+
*/
|
|
795
|
+
function printCompactStatus(snapshot, logger) {
|
|
796
|
+
const agent = snapshot.agent || '-';
|
|
797
|
+
const tool = snapshot.tool || '-';
|
|
798
|
+
const phase = snapshot.phase || 'idle';
|
|
799
|
+
const proc = snapshot.processState || 'not_tracked';
|
|
800
|
+
const pid = snapshot.pid || null;
|
|
801
|
+
|
|
802
|
+
// Context percentage if available
|
|
803
|
+
let ctxStr = '';
|
|
804
|
+
if (snapshot.run && snapshot.run.context_pct != null) {
|
|
805
|
+
const pct = Number(snapshot.run.context_pct) || 0;
|
|
806
|
+
ctxStr = `${colorForContext(pct)}ctx:${pct}%${ANSI.reset}`;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// Token / cost if available
|
|
810
|
+
let costStr = '';
|
|
811
|
+
if (snapshot.stats && snapshot.stats.tokens_total) {
|
|
812
|
+
const tokens = snapshot.stats.tokens_total;
|
|
813
|
+
const cost = snapshot.stats.cost_usd;
|
|
814
|
+
costStr = `${ANSI.cyan}${tokens >= 1000 ? (tokens / 1000).toFixed(1) + 'k' : tokens}tk${ANSI.reset}`;
|
|
815
|
+
if (cost != null) {
|
|
816
|
+
costStr += `${ANSI.gray}/${ANSI.reset}${ANSI.cyan}$${cost.toFixed(3)}${ANSI.reset}`;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// Plan progress
|
|
821
|
+
let planStr = '';
|
|
822
|
+
const planDone = snapshot.stats?.plan_steps_done ?? 0;
|
|
823
|
+
const planTotal = snapshot.stats?.plan_steps_total ?? 0;
|
|
824
|
+
if (planTotal > 0) {
|
|
825
|
+
planStr = `${ANSI.magenta}plan:${planDone}/${planTotal}${ANSI.reset}`;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// Duration
|
|
829
|
+
const dur = formatDurationCompact(snapshot.startedAt);
|
|
830
|
+
const durStr = dur ? `${ANSI.blue}${dur}${ANSI.reset}` : '';
|
|
831
|
+
|
|
832
|
+
// Recent event
|
|
833
|
+
let eventStr = '';
|
|
834
|
+
if (snapshot.recentEvents && snapshot.recentEvents.length > 0) {
|
|
835
|
+
const ev = snapshot.recentEvents[snapshot.recentEvents.length - 1];
|
|
836
|
+
eventStr = `${ANSI.gray}${ev.type}${ANSI.reset}`;
|
|
837
|
+
if (ev.summary) {
|
|
838
|
+
const short = String(ev.summary).slice(0, 35);
|
|
839
|
+
eventStr += `:${ANSI.gray}${short}${ANSI.reset}`;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// Warning
|
|
844
|
+
let warnStr = '';
|
|
845
|
+
if (snapshot.warning) {
|
|
846
|
+
warnStr = `${ANSI.red}⚠ ${snapshot.warning}${ANSI.reset}`;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// Build line 1
|
|
850
|
+
const parts = [
|
|
851
|
+
`${colorForPhase(phase)}●${ANSI.reset}`,
|
|
852
|
+
`${ANSI.bold}${agent}${ANSI.reset}`,
|
|
853
|
+
`|`,
|
|
854
|
+
`${ANSI.blue}${tool}${ANSI.reset}`,
|
|
855
|
+
`|`,
|
|
856
|
+
`${colorForProcess(proc)}${proc}${ANSI.reset}`,
|
|
857
|
+
pid ? `${ANSI.gray}(pid:${pid})${ANSI.reset}` : '',
|
|
858
|
+
ctxStr,
|
|
859
|
+
costStr,
|
|
860
|
+
planStr,
|
|
861
|
+
durStr,
|
|
862
|
+
eventStr,
|
|
863
|
+
warnStr
|
|
864
|
+
].filter(Boolean);
|
|
865
|
+
|
|
866
|
+
logger.log(parts.join(' '));
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* Print two plain-text lines optimized for tmux status-bar.
|
|
871
|
+
* No ANSI colors — tmux handles its own styling.
|
|
872
|
+
* Designed for a 2-line pane.
|
|
873
|
+
*/
|
|
874
|
+
function renderMiniBar(pct, width = 10, usedLabel = '', totalLabel = '') {
|
|
875
|
+
const filled = Math.round((pct / 100) * width);
|
|
876
|
+
const empty = width - filled;
|
|
877
|
+
const bar = '█'.repeat(filled) + '░'.repeat(empty);
|
|
878
|
+
const color = pct > 80 ? '\x1b[31m' : pct > 50 ? '\x1b[33m' : '\x1b[32m';
|
|
879
|
+
const reset = '\x1b[0m';
|
|
880
|
+
const abs = usedLabel && totalLabel ? ` ${usedLabel}/${totalLabel}` : '';
|
|
881
|
+
return `${color}[${bar}]${reset}${abs} ${pct}%`;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
function formatProjectPath(targetDir) {
|
|
885
|
+
if (!targetDir) return '-';
|
|
886
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
887
|
+
let path = String(targetDir).replace(/\\/g, '/');
|
|
888
|
+
if (home && path.startsWith(home.replace(/\\/g, '/'))) {
|
|
889
|
+
path = '~' + path.slice(home.length);
|
|
890
|
+
}
|
|
891
|
+
if (path.length <= 28) return path;
|
|
892
|
+
// Too long: keep last 2 segments with ellipsis
|
|
893
|
+
const segments = path.split('/').filter(Boolean);
|
|
894
|
+
if (segments.length <= 2) return path;
|
|
895
|
+
const lastTwo = segments.slice(-2).join('/');
|
|
896
|
+
return `~/.../${lastTwo}`;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
function printTmuxBar(snapshot) {
|
|
900
|
+
const agent = snapshot.agent || '-';
|
|
901
|
+
const tool = snapshot.tool || '-';
|
|
902
|
+
const phase = snapshot.phase || 'idle';
|
|
903
|
+
const projectDir = formatProjectPath(snapshot.targetDir);
|
|
904
|
+
const dur = formatDurationCompact(snapshot.startedAt);
|
|
905
|
+
|
|
906
|
+
// Build core info
|
|
907
|
+
const parts = [];
|
|
908
|
+
parts.push(`\x1b[1;36m${projectDir}\x1b[0m`);
|
|
909
|
+
parts.push(`\x1b[1;35m${agent}\x1b[0m`);
|
|
910
|
+
parts.push(`\x1b[90m${tool}\x1b[0m`);
|
|
911
|
+
|
|
912
|
+
if (phase === 'active') {
|
|
913
|
+
parts.push(`\x1b[32m●\x1b[0m`);
|
|
914
|
+
} else if (phase === 'closed') {
|
|
915
|
+
parts.push(`\x1b[31m○\x1b[0m`);
|
|
916
|
+
} else {
|
|
917
|
+
parts.push(`\x1b[33m${phase}\x1b[0m`);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
if (dur) {
|
|
921
|
+
parts.push(dur);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// Plan progress
|
|
925
|
+
const planDone = snapshot.stats?.plan_steps_done ?? 0;
|
|
926
|
+
const planTotal = snapshot.stats?.plan_steps_total ?? 0;
|
|
927
|
+
if (planTotal > 0) {
|
|
928
|
+
parts.push(`step ${planDone}/${planTotal}`);
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// Context bar with absolute numbers
|
|
932
|
+
if (snapshot.run && snapshot.run.context_pct != null) {
|
|
933
|
+
const pct = Number(snapshot.run.context_pct) || 0;
|
|
934
|
+
parts.push(`ctx ${renderMiniBar(pct)}`);
|
|
935
|
+
} else if (snapshot.contextEstimated) {
|
|
936
|
+
const est = snapshot.contextEstimated;
|
|
937
|
+
const pct = est.pct ?? 0;
|
|
938
|
+
const used = est.estimatedTokens >= 1000 ? (est.estimatedTokens / 1000).toFixed(1) + 'k' : String(est.estimatedTokens);
|
|
939
|
+
const total = est.windowSize >= 1000 ? (est.windowSize / 1000).toFixed(1) + 'k' : String(est.windowSize);
|
|
940
|
+
parts.push(`ctx ${renderMiniBar(pct, 10, used, total)}`);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// Cost
|
|
944
|
+
if (snapshot.stats && snapshot.stats.tokens_total) {
|
|
945
|
+
const tokens = snapshot.stats.tokens_total;
|
|
946
|
+
const cost = snapshot.stats.cost_usd;
|
|
947
|
+
const tk = tokens >= 1000 ? (tokens / 1000).toFixed(1) + 'k' : tokens;
|
|
948
|
+
if (cost != null) {
|
|
949
|
+
parts.push(`$${cost.toFixed(2)} (${tk}tk)`);
|
|
950
|
+
} else {
|
|
951
|
+
parts.push(`${tk}tk`);
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// Recent useful event (skip session_started boilerplate)
|
|
956
|
+
let lastEvent = null;
|
|
957
|
+
if (snapshot.recentEvents && snapshot.recentEvents.length > 0) {
|
|
958
|
+
for (let i = snapshot.recentEvents.length - 1; i >= 0; i--) {
|
|
959
|
+
const ev = snapshot.recentEvents[i];
|
|
960
|
+
const type = String(ev.type || '');
|
|
961
|
+
if (type !== 'session_started' && type !== 'session_closed') {
|
|
962
|
+
lastEvent = ev;
|
|
963
|
+
break;
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
if (lastEvent) {
|
|
968
|
+
const short = String(lastEvent.summary || lastEvent.type || '').slice(0, 40);
|
|
969
|
+
if (short) {
|
|
970
|
+
parts.push(`\x1b[90m${short}\x1b[0m`);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// Warning
|
|
975
|
+
if (snapshot.warning) {
|
|
976
|
+
parts.push(`\x1b[1;31m! ${snapshot.warning}\x1b[0m`);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// When running inside the tmux updater, omit newline so the line can be overwritten.
|
|
980
|
+
// When called directly by a user, append newline for clean shell prompt.
|
|
981
|
+
const suffix = process.env.AIOSON_TMUX_BAR ? '' : '\n';
|
|
982
|
+
process.stdout.write(parts.join(' │ ') + suffix);
|
|
983
|
+
}
|
|
984
|
+
|
|
735
985
|
function printLiveStatusSnapshot(snapshot, logger) {
|
|
736
986
|
logger.log(`Live session: ${snapshot.sessionKey || 'none'}`);
|
|
737
987
|
logger.log(`Phase: ${snapshot.phase}`);
|
|
@@ -819,11 +1069,17 @@ async function getLiveStatusSnapshot(targetDir, t, options = {}) {
|
|
|
819
1069
|
});
|
|
820
1070
|
state.stats = normalizeLiveStats(state.stats, planStats);
|
|
821
1071
|
|
|
1072
|
+
// Prefer run.agent_name when no explicit --agent was passed;
|
|
1073
|
+
// this lets events emitted by other agents update the bar dynamically.
|
|
1074
|
+
const effectiveAgent = options.agent
|
|
1075
|
+
? context.agentName
|
|
1076
|
+
: (context.run?.agent_name || context.agentName);
|
|
1077
|
+
|
|
822
1078
|
const snapshot = {
|
|
823
1079
|
ok: true,
|
|
824
1080
|
targetDir,
|
|
825
1081
|
dbPath,
|
|
826
|
-
agent:
|
|
1082
|
+
agent: effectiveAgent,
|
|
827
1083
|
tool: state.tool_session || null,
|
|
828
1084
|
phase: context.phase,
|
|
829
1085
|
open: context.open,
|
|
@@ -839,11 +1095,21 @@ async function getLiveStatusSnapshot(targetDir, t, options = {}) {
|
|
|
839
1095
|
task: context.task,
|
|
840
1096
|
stats: state.stats,
|
|
841
1097
|
recentEvents: Array.isArray(state.last_events) && state.last_events.length > 0 ? state.last_events : context.recentEvents,
|
|
1098
|
+
contextEstimated: state.context_estimated || null,
|
|
842
1099
|
warning: context.processState === 'dead' && context.phase === 'active'
|
|
843
1100
|
? t('live.process_dead_warning')
|
|
844
1101
|
: null
|
|
845
1102
|
};
|
|
846
1103
|
|
|
1104
|
+
// Fallback: estimate context on-the-fly if not recorded at session start
|
|
1105
|
+
if (!snapshot.contextEstimated && snapshot.phase !== 'idle') {
|
|
1106
|
+
try {
|
|
1107
|
+
snapshot.contextEstimated = await estimateContextSize(targetDir);
|
|
1108
|
+
} catch {
|
|
1109
|
+
// non-fatal
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
|
|
847
1113
|
return snapshot;
|
|
848
1114
|
} finally {
|
|
849
1115
|
db.close();
|
|
@@ -880,6 +1146,16 @@ async function runLiveStart({ args, options = {}, logger, t }) {
|
|
|
880
1146
|
throw new Error(t('live.tool_binary_not_found', { binary: toolBinary }));
|
|
881
1147
|
}
|
|
882
1148
|
|
|
1149
|
+
const useTmux = Boolean(options.tmux) || process.env.AIOSON_TMUX === '1';
|
|
1150
|
+
|
|
1151
|
+
// Pre-check tmux availability so we can warn early
|
|
1152
|
+
if (useTmux && !noLaunch) {
|
|
1153
|
+
const tmuxOk = await isTmuxAvailable();
|
|
1154
|
+
if (!tmuxOk && !options.json) {
|
|
1155
|
+
logger.log(t('live.tmux_not_found', { tool }));
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
883
1159
|
const { db, dbPath, runtimeDir } = await openRuntimeDb(targetDir);
|
|
884
1160
|
|
|
885
1161
|
try {
|
|
@@ -895,56 +1171,107 @@ async function runLiveStart({ args, options = {}, logger, t }) {
|
|
|
895
1171
|
projectPath: targetDir
|
|
896
1172
|
});
|
|
897
1173
|
|
|
898
|
-
|
|
899
|
-
if (
|
|
900
|
-
|
|
901
|
-
|
|
1174
|
+
// ── Tmux session recovery: if tmux was killed, close the stale live session ──
|
|
1175
|
+
if (useTmux) {
|
|
1176
|
+
const sessionName = buildSessionName(targetDir, agentName);
|
|
1177
|
+
const tmuxAlive = await hasSession(sessionName);
|
|
1178
|
+
if (!tmuxAlive) {
|
|
1179
|
+
// Tmux is gone — close the stale live session in DB and continue to create new
|
|
1180
|
+
const now = new Date().toISOString();
|
|
1181
|
+
updateRun(db, {
|
|
1182
|
+
runKey: existing.run.run_key,
|
|
1183
|
+
status: 'completed',
|
|
1184
|
+
summary: 'Closed because tmux session was terminated',
|
|
1185
|
+
eventType: 'session_closed',
|
|
1186
|
+
phase: 'live',
|
|
1187
|
+
message: 'Tmux session ended — live session auto-closed'
|
|
1188
|
+
});
|
|
1189
|
+
if (existing.task?.task_key) {
|
|
1190
|
+
updateTask(db, {
|
|
1191
|
+
taskKey: existing.task.task_key,
|
|
1192
|
+
status: 'completed',
|
|
1193
|
+
goal: 'Auto-closed after tmux termination'
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
await clearAgentSession(runtimeDir, agentName);
|
|
1197
|
+
if (!options.json) {
|
|
1198
|
+
logger.log(t('live.tmux_recreate', { agent: agentName, session: existing.sessionKey }));
|
|
1199
|
+
}
|
|
1200
|
+
// Fall through to create a new session below
|
|
1201
|
+
} else {
|
|
1202
|
+
// Tmux still alive — reattach instead of creating new
|
|
1203
|
+
if (!options.json) {
|
|
1204
|
+
logger.log(t('live.tmux_reattach', { agent: agentName, session: existing.sessionKey }));
|
|
1205
|
+
}
|
|
1206
|
+
const sessionName = buildSessionName(targetDir, agentName);
|
|
1207
|
+
await attachSession(sessionName);
|
|
1208
|
+
return {
|
|
1209
|
+
ok: true,
|
|
1210
|
+
targetDir,
|
|
1211
|
+
dbPath,
|
|
1212
|
+
tmux: true,
|
|
1213
|
+
reused: true,
|
|
1214
|
+
agent: existing.agentName,
|
|
1215
|
+
tool: state.tool_session || tool,
|
|
1216
|
+
taskKey: existing.task?.task_key || existing.sessionRef?.taskKey || null,
|
|
1217
|
+
runKey: existing.run.run_key,
|
|
1218
|
+
sessionKey: existing.sessionKey,
|
|
1219
|
+
open: true
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
} else {
|
|
1223
|
+
// Non-tmux reuse logic (original behavior)
|
|
1224
|
+
const existingTool = state.tool_session || null;
|
|
1225
|
+
if (existingTool && existingTool !== tool) {
|
|
1226
|
+
throw new Error(t('live.tool_mismatch', { existing: existingTool, requested: tool }));
|
|
1227
|
+
}
|
|
902
1228
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1229
|
+
const attach = Boolean(options.attach);
|
|
1230
|
+
let attachChild = null;
|
|
1231
|
+
let attachResult = null;
|
|
906
1232
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1233
|
+
if (attach && !noLaunch) {
|
|
1234
|
+
attachChild = spawn(binaryPath, buildLaunchArgs(options, tool), {
|
|
1235
|
+
cwd: targetDir,
|
|
1236
|
+
env: process.env,
|
|
1237
|
+
stdio: 'inherit'
|
|
1238
|
+
});
|
|
1239
|
+
state.child_pid = attachChild.pid || null;
|
|
1240
|
+
if (existing.task?.task_key) {
|
|
1241
|
+
const taskMeta = parseTaskMeta(existing.task);
|
|
1242
|
+
taskMeta.child_pid = state.child_pid;
|
|
1243
|
+
updateTask(db, { taskKey: existing.task.task_key, metaJson: taskMeta });
|
|
1244
|
+
}
|
|
918
1245
|
}
|
|
919
|
-
}
|
|
920
1246
|
|
|
921
|
-
|
|
1247
|
+
await writeLiveState(runtimeDir, existing.sessionKey, state);
|
|
922
1248
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1249
|
+
if (!options.json) {
|
|
1250
|
+
logger.log(t('live.session_already_active', { agent: agentName, session: existing.sessionKey, runKey: existing.run.run_key, dbPath }));
|
|
1251
|
+
}
|
|
926
1252
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1253
|
+
if (attachChild) {
|
|
1254
|
+
attachResult = await waitForChild(attachChild);
|
|
1255
|
+
}
|
|
930
1256
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1257
|
+
return {
|
|
1258
|
+
ok: true,
|
|
1259
|
+
targetDir,
|
|
1260
|
+
dbPath,
|
|
1261
|
+
agent: existing.agentName,
|
|
1262
|
+
tool: state.tool_session || tool,
|
|
1263
|
+
taskKey: existing.task?.task_key || existing.sessionRef?.taskKey || null,
|
|
1264
|
+
runKey: existing.run.run_key,
|
|
1265
|
+
sessionKey: existing.sessionKey,
|
|
1266
|
+
pid: state.child_pid || null,
|
|
1267
|
+
processState: detectProcessState(state.child_pid),
|
|
1268
|
+
reused: true,
|
|
1269
|
+
open: true,
|
|
1270
|
+
attached: attach,
|
|
1271
|
+
childExitCode: attachResult?.code ?? null,
|
|
1272
|
+
childSignal: attachResult?.signal ?? null
|
|
1273
|
+
};
|
|
1274
|
+
}
|
|
948
1275
|
}
|
|
949
1276
|
|
|
950
1277
|
const now = new Date().toISOString();
|
|
@@ -994,17 +1321,46 @@ async function runLiveStart({ args, options = {}, logger, t }) {
|
|
|
994
1321
|
|
|
995
1322
|
let child = null;
|
|
996
1323
|
let childResult = null;
|
|
1324
|
+
let tmuxResult = null;
|
|
997
1325
|
if (!noLaunch) {
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1326
|
+
if (useTmux) {
|
|
1327
|
+
const tmuxOk = await isTmuxAvailable();
|
|
1328
|
+
if (tmuxOk) {
|
|
1329
|
+
if (!options.json) {
|
|
1330
|
+
logger.log(t('live.tmux_starting', { agent: agentName, tool }));
|
|
1331
|
+
}
|
|
1332
|
+
tmuxResult = await launchTmuxSession({
|
|
1333
|
+
targetDir,
|
|
1334
|
+
agentName,
|
|
1335
|
+
tool,
|
|
1336
|
+
binaryPath,
|
|
1337
|
+
toolArgs: buildLaunchArgs(options, tool)
|
|
1338
|
+
});
|
|
1339
|
+
} else {
|
|
1340
|
+
// Fallback to normal spawn if tmux not available
|
|
1341
|
+
child = spawn(binaryPath, buildLaunchArgs(options, tool), {
|
|
1342
|
+
cwd: targetDir,
|
|
1343
|
+
env: process.env,
|
|
1344
|
+
stdio: 'inherit'
|
|
1345
|
+
});
|
|
1346
|
+
taskMeta.child_pid = child.pid || null;
|
|
1347
|
+
updateTask(db, {
|
|
1348
|
+
taskKey,
|
|
1349
|
+
metaJson: taskMeta
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
} else {
|
|
1353
|
+
child = spawn(binaryPath, buildLaunchArgs(options, tool), {
|
|
1354
|
+
cwd: targetDir,
|
|
1355
|
+
env: process.env,
|
|
1356
|
+
stdio: 'inherit'
|
|
1357
|
+
});
|
|
1358
|
+
taskMeta.child_pid = child.pid || null;
|
|
1359
|
+
updateTask(db, {
|
|
1360
|
+
taskKey,
|
|
1361
|
+
metaJson: taskMeta
|
|
1362
|
+
});
|
|
1363
|
+
}
|
|
1008
1364
|
}
|
|
1009
1365
|
|
|
1010
1366
|
await writeAgentSession(runtimeDir, agentName, {
|
|
@@ -1051,6 +1407,14 @@ async function runLiveStart({ args, options = {}, logger, t }) {
|
|
|
1051
1407
|
}]
|
|
1052
1408
|
});
|
|
1053
1409
|
|
|
1410
|
+
// Estimate context size for observability
|
|
1411
|
+
try {
|
|
1412
|
+
const ctxEst = await estimateContextSize(targetDir);
|
|
1413
|
+
state.context_estimated = ctxEst;
|
|
1414
|
+
} catch {
|
|
1415
|
+
// non-fatal
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1054
1418
|
await writeLiveState(runtimeDir, sessionKey, state);
|
|
1055
1419
|
await appendLiveEvent(runtimeDir, sessionKey, {
|
|
1056
1420
|
ts: now,
|
|
@@ -1097,6 +1461,25 @@ async function runLiveStart({ args, options = {}, logger, t }) {
|
|
|
1097
1461
|
childResult = await waitForChild(child);
|
|
1098
1462
|
}
|
|
1099
1463
|
|
|
1464
|
+
if (tmuxResult) {
|
|
1465
|
+
return {
|
|
1466
|
+
ok: true,
|
|
1467
|
+
targetDir,
|
|
1468
|
+
dbPath,
|
|
1469
|
+
tmux: true,
|
|
1470
|
+
sessionName: tmuxResult.sessionName,
|
|
1471
|
+
agent: agentName,
|
|
1472
|
+
tool,
|
|
1473
|
+
taskKey,
|
|
1474
|
+
runKey,
|
|
1475
|
+
sessionKey,
|
|
1476
|
+
pid: null,
|
|
1477
|
+
processState: 'tmux',
|
|
1478
|
+
reused: false,
|
|
1479
|
+
open: true
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1100
1483
|
return {
|
|
1101
1484
|
ok: true,
|
|
1102
1485
|
targetDir,
|
|
@@ -1426,7 +1809,13 @@ async function runLiveStatus({ args, options = {}, logger, t }) {
|
|
|
1426
1809
|
if (!watchSeconds) {
|
|
1427
1810
|
const snapshot = await getLiveStatusSnapshot(targetDir, t, options);
|
|
1428
1811
|
if (!options.json) {
|
|
1429
|
-
|
|
1812
|
+
if (options.format === 'compact') {
|
|
1813
|
+
printCompactStatus(snapshot, logger);
|
|
1814
|
+
} else if (options.format === 'tmux-bar') {
|
|
1815
|
+
printTmuxBar(snapshot, logger);
|
|
1816
|
+
} else {
|
|
1817
|
+
printLiveStatusSnapshot(snapshot, logger);
|
|
1818
|
+
}
|
|
1430
1819
|
}
|
|
1431
1820
|
return snapshot;
|
|
1432
1821
|
}
|
|
@@ -1442,7 +1831,13 @@ async function runLiveStatus({ args, options = {}, logger, t }) {
|
|
|
1442
1831
|
if (process.stdout && process.stdout.isTTY) {
|
|
1443
1832
|
process.stdout.write('\x1Bc');
|
|
1444
1833
|
}
|
|
1445
|
-
|
|
1834
|
+
if (options.format === 'compact') {
|
|
1835
|
+
printCompactStatus(snapshot, logger);
|
|
1836
|
+
} else if (options.format === 'tmux-bar') {
|
|
1837
|
+
printTmuxBar(snapshot, logger);
|
|
1838
|
+
} else {
|
|
1839
|
+
printLiveStatusSnapshot(snapshot, logger);
|
|
1840
|
+
}
|
|
1446
1841
|
if (stopped) break;
|
|
1447
1842
|
await sleep(Math.round(watchSeconds * 1000));
|
|
1448
1843
|
}
|
|
@@ -1632,6 +2027,7 @@ async function runLiveList({ args, options = {}, logger, t }) {
|
|
|
1632
2027
|
}
|
|
1633
2028
|
|
|
1634
2029
|
module.exports = {
|
|
2030
|
+
buildLaunchArgs,
|
|
1635
2031
|
runLiveStart,
|
|
1636
2032
|
runRuntimeEmit,
|
|
1637
2033
|
runLiveHandoff,
|
|
@@ -1639,3 +2035,48 @@ module.exports = {
|
|
|
1639
2035
|
runLiveClose,
|
|
1640
2036
|
runLiveList
|
|
1641
2037
|
};
|
|
2038
|
+
|
|
2039
|
+
// ── Context estimation helpers ──
|
|
2040
|
+
|
|
2041
|
+
const CONTEXT_FILES = [
|
|
2042
|
+
'.aioson/context/project.context.md',
|
|
2043
|
+
'.aioson/context/spec.md',
|
|
2044
|
+
'.aioson/context/features.md',
|
|
2045
|
+
'.aioson/context/context-pack.md',
|
|
2046
|
+
'.aioson/context/discovery.md',
|
|
2047
|
+
'.aioson/context/architecture.md',
|
|
2048
|
+
'.aioson/context/readiness.md',
|
|
2049
|
+
'.aioson/context/design-doc.md',
|
|
2050
|
+
'.aioson/context/skeleton-system.md'
|
|
2051
|
+
];
|
|
2052
|
+
|
|
2053
|
+
async function estimateContextSize(projectDir) {
|
|
2054
|
+
let totalBytes = 0;
|
|
2055
|
+
const foundFiles = [];
|
|
2056
|
+
|
|
2057
|
+
for (const rel of CONTEXT_FILES) {
|
|
2058
|
+
const filePath = path.join(projectDir, rel);
|
|
2059
|
+
try {
|
|
2060
|
+
const stat = await fs.stat(filePath);
|
|
2061
|
+
if (stat.isFile()) {
|
|
2062
|
+
totalBytes += stat.size;
|
|
2063
|
+
foundFiles.push(rel);
|
|
2064
|
+
}
|
|
2065
|
+
} catch {
|
|
2066
|
+
// ignore missing files
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
// Heuristic: ~4 chars per token (english-ish text)
|
|
2071
|
+
const estimatedTokens = Math.round(totalBytes / 4);
|
|
2072
|
+
// Default window size assumption (200k for Sonnet-class)
|
|
2073
|
+
const windowSize = 200000;
|
|
2074
|
+
|
|
2075
|
+
return {
|
|
2076
|
+
totalBytes,
|
|
2077
|
+
estimatedTokens,
|
|
2078
|
+
windowSize,
|
|
2079
|
+
pct: Math.min(100, Math.round((estimatedTokens / windowSize) * 100)),
|
|
2080
|
+
files: foundFiles
|
|
2081
|
+
};
|
|
2082
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const path = require('node:path');
|
|
4
|
-
const { applyAgentLocale,
|
|
5
|
-
const { validateProjectContextFile } = require('../context');
|
|
4
|
+
const { applyAgentLocale, normalizeInteractionLanguage } = require('../locales');
|
|
5
|
+
const { validateProjectContextFile, getInteractionLanguage } = require('../context');
|
|
6
6
|
|
|
7
7
|
async function runLocaleApply({ args, options, logger, t }) {
|
|
8
8
|
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
@@ -11,13 +11,16 @@ async function runLocaleApply({ args, options, logger, t }) {
|
|
|
11
11
|
let requestedLanguage = options.language || options.lang || '';
|
|
12
12
|
if (!requestedLanguage) {
|
|
13
13
|
const context = await validateProjectContextFile(targetDir);
|
|
14
|
-
if (context.parsed && context.data
|
|
15
|
-
requestedLanguage = context.data
|
|
14
|
+
if (context.parsed && context.data) {
|
|
15
|
+
requestedLanguage = getInteractionLanguage(context.data, 'en');
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const
|
|
20
|
-
|
|
19
|
+
const result = await applyAgentLocale(
|
|
20
|
+
targetDir,
|
|
21
|
+
normalizeInteractionLanguage(requestedLanguage || 'en'),
|
|
22
|
+
{ dryRun }
|
|
23
|
+
);
|
|
21
24
|
|
|
22
25
|
logger.log(
|
|
23
26
|
dryRun
|