@jaimevalasek/aioson 1.6.0 → 1.7.2
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 +74 -0
- package/README.md +729 -232
- package/docs/design-previews/pt.squarespace.com-homepage.html +889 -0
- package/docs/integrations/sdlc-genius-boundary.md +76 -0
- package/docs/integrations/sdlc-genius-eval-matrix.md +75 -0
- package/docs/integrations/sdlc-genius-install-checklist.md +93 -0
- package/docs/integrations/sdlc-genius-review-samples.md +86 -0
- package/docs/pt/README.md +3 -0
- package/docs/pt/agentes.md +1 -0
- package/docs/pt/comandos-cli.md +888 -2
- package/docs/pt/design-hybrid-forge.md +255 -6
- package/docs/pt/devlog-pipeline.md +270 -0
- package/docs/pt/fluxo-artefatos.md +178 -0
- package/docs/pt/hooks-session-guard.md +454 -0
- package/docs/pt/monitor-de-contexto.md +59 -5
- package/docs/pt/sdd-automation-scripts.md +557 -0
- package/docs/pt/site-forge.md +309 -0
- package/docs/pt/spec-learnings-pipeline.md +265 -0
- package/package.json +1 -1
- package/src/a2a/client.js +165 -0
- package/src/a2a/server.js +223 -0
- package/src/cli.js +235 -1
- package/src/commands/agent-audit.js +397 -0
- package/src/commands/agent-export-skill.js +229 -0
- package/src/commands/artifact-validate.js +189 -0
- package/src/commands/brief-gen.js +405 -0
- package/src/commands/brief-validate.js +65 -0
- package/src/commands/classify.js +256 -0
- package/src/commands/context-compact.js +49 -0
- package/src/commands/context-health.js +175 -0
- package/src/commands/context-monitor.js +71 -0
- package/src/commands/context-trim.js +177 -0
- package/src/commands/detect-test-runner.js +55 -0
- package/src/commands/devlog-export-brains.js +27 -0
- package/src/commands/devlog-process.js +292 -0
- package/src/commands/devlog-watch.js +131 -0
- package/src/commands/feature-close.js +165 -0
- package/src/commands/gate-check.js +228 -0
- package/src/commands/hooks-emit.js +253 -0
- package/src/commands/hooks-install.js +347 -0
- package/src/commands/learning-auto-promote.js +195 -0
- package/src/commands/learning-evolve.js +18 -9
- package/src/commands/learning-export.js +103 -0
- package/src/commands/learning-rollback.js +164 -0
- package/src/commands/live.js +25 -1
- package/src/commands/pattern-detect.js +33 -0
- package/src/commands/preflight-context.js +30 -0
- package/src/commands/preflight.js +208 -0
- package/src/commands/pulse-update.js +130 -0
- package/src/commands/runner-daemon.js +274 -0
- package/src/commands/runner-plan.js +70 -0
- package/src/commands/runner-queue-from-plan.js +166 -0
- package/src/commands/runner-queue.js +189 -0
- package/src/commands/runner-run.js +129 -0
- package/src/commands/runtime.js +47 -1
- package/src/commands/self-implement-loop.js +256 -0
- package/src/commands/session-guard.js +218 -0
- package/src/commands/sizing.js +165 -0
- package/src/commands/skill.js +65 -0
- package/src/commands/spec-checkpoint.js +177 -0
- package/src/commands/spec-status.js +79 -0
- package/src/commands/spec-sync.js +190 -0
- package/src/commands/spec-tasks.js +288 -0
- package/src/commands/squad-autorun.js +1220 -0
- package/src/commands/squad-bus.js +217 -0
- package/src/commands/squad-card.js +149 -0
- package/src/commands/squad-daemon.js +134 -0
- package/src/commands/squad-dependency-graph.js +164 -0
- package/src/commands/squad-review.js +106 -0
- package/src/commands/squad-scaffold.js +55 -0
- package/src/commands/squad-tool-register.js +157 -0
- package/src/commands/state-save.js +122 -0
- package/src/commands/update.js +2 -0
- package/src/commands/verify-gate.js +572 -0
- package/src/commands/workflow-execute.js +241 -0
- package/src/constants.js +22 -0
- package/src/install-profile.js +2 -2
- package/src/install-wizard.js +3 -2
- package/src/installer.js +6 -0
- package/src/lib/health-check.js +158 -0
- package/src/lib/hook-protocol.js +76 -0
- package/src/mcp/apps/squad-dashboard/app.js +163 -0
- package/src/mcp/apps/squad-dashboard/index.html +261 -0
- package/src/mcp/apps/squad-dashboard/mcp-manifest.json +23 -0
- package/src/mcp/resources/squad-state.js +130 -0
- package/src/preflight-engine.js +443 -0
- package/src/runner/cascade.js +97 -0
- package/src/runner/cli-launcher.js +109 -0
- package/src/runner/plan-importer.js +63 -0
- package/src/runner/queue-store.js +159 -0
- package/src/runtime-store.js +61 -3
- package/src/squad/agent-teams-adapter.js +264 -0
- package/src/squad/brief-validator.js +350 -0
- package/src/squad/bus-bridge.js +140 -0
- package/src/squad/context-compactor.js +265 -0
- package/src/squad/cross-ai-synthesizer.js +250 -0
- package/src/squad/hooks-generator.js +196 -0
- package/src/squad/inter-squad-events.js +175 -0
- package/src/squad/intra-bus.js +345 -0
- package/src/squad/learning-extractor.js +213 -0
- package/src/squad/pattern-detector.js +365 -0
- package/src/squad/preflight-context.js +296 -0
- package/src/squad/recovery-context.js +242 -71
- package/src/squad/reflection.js +365 -0
- package/src/squad/squad-scaffold.js +177 -0
- package/src/squad/state-manager.js +310 -0
- package/src/squad/task-decomposer.js +652 -0
- package/src/squad/verify-gate.js +303 -0
- package/src/updater.js +4 -5
- package/src/worker-runner.js +186 -1
- package/template/.aioson/agents/analyst.md +62 -1
- package/template/.aioson/agents/architect.md +61 -1
- package/template/.aioson/agents/copywriter.md +463 -0
- package/template/.aioson/agents/design-hybrid-forge.md +14 -0
- package/template/.aioson/agents/dev.md +271 -25
- package/template/.aioson/agents/deyvin.md +67 -8
- package/template/.aioson/agents/discovery-design-doc.md +44 -0
- package/template/.aioson/agents/genome.md +14 -0
- package/template/.aioson/agents/neo.md +83 -2
- package/template/.aioson/agents/orache.md +50 -4
- package/template/.aioson/agents/orchestrator.md +197 -1
- package/template/.aioson/agents/pm.md +35 -0
- package/template/.aioson/agents/product.md +50 -5
- package/template/.aioson/agents/profiler-enricher.md +14 -0
- package/template/.aioson/agents/profiler-forge.md +14 -0
- package/template/.aioson/agents/profiler-researcher.md +14 -0
- package/template/.aioson/agents/qa.md +273 -21
- package/template/.aioson/agents/setup.md +96 -10
- package/template/.aioson/agents/sheldon.md +131 -6
- package/template/.aioson/agents/site-forge.md +1753 -0
- package/template/.aioson/agents/squad.md +352 -0
- package/template/.aioson/agents/tester.md +53 -0
- package/template/.aioson/agents/ux-ui.md +203 -4
- package/template/.aioson/brains/README.md +128 -0
- package/template/.aioson/brains/_index.json +16 -0
- package/template/.aioson/brains/scripts/query.js +103 -0
- package/template/.aioson/brains/site-forge/visual-patterns.brain.json +205 -0
- package/template/.aioson/config.md +143 -13
- package/template/.aioson/constitution.md +33 -0
- package/template/.aioson/context/project-pulse.md +34 -0
- package/template/.aioson/docs/LAYERS.md +79 -0
- package/template/.aioson/docs/README.md +76 -0
- package/template/.aioson/docs/example-external-api-context.md +72 -0
- package/template/.aioson/genomes/copywriting.md +204 -0
- package/template/.aioson/locales/en/agents/architect.md +17 -0
- package/template/.aioson/locales/en/agents/dev.md +79 -13
- package/template/.aioson/locales/en/agents/orache.md +6 -0
- package/template/.aioson/locales/en/agents/orchestrator.md +24 -0
- package/template/.aioson/locales/en/agents/product.md +50 -0
- package/template/.aioson/locales/en/agents/sheldon.md +115 -0
- package/template/.aioson/locales/en/agents/squad.md +14 -0
- package/template/.aioson/locales/en/agents/tester.md +6 -0
- package/template/.aioson/locales/es/agents/analyst.md +2 -0
- package/template/.aioson/locales/es/agents/architect.md +19 -0
- package/template/.aioson/locales/es/agents/dev.md +64 -4
- package/template/.aioson/locales/es/agents/deyvin.md +2 -0
- package/template/.aioson/locales/es/agents/discovery-design-doc.md +2 -0
- package/template/.aioson/locales/es/agents/genome.md +2 -0
- package/template/.aioson/locales/es/agents/neo.md +2 -0
- package/template/.aioson/locales/es/agents/orache.md +2 -0
- package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/es/agents/pair.md +2 -0
- package/template/.aioson/locales/es/agents/pm.md +2 -0
- package/template/.aioson/locales/es/agents/product.md +52 -0
- package/template/.aioson/locales/es/agents/profiler-enricher.md +2 -0
- package/template/.aioson/locales/es/agents/profiler-forge.md +2 -0
- package/template/.aioson/locales/es/agents/profiler-researcher.md +2 -0
- package/template/.aioson/locales/es/agents/qa.md +2 -0
- package/template/.aioson/locales/es/agents/setup.md +2 -0
- package/template/.aioson/locales/es/agents/sheldon.md +117 -0
- package/template/.aioson/locales/es/agents/squad.md +16 -0
- package/template/.aioson/locales/es/agents/tester.md +9 -0
- package/template/.aioson/locales/es/agents/ux-ui.md +2 -0
- package/template/.aioson/locales/fr/agents/analyst.md +2 -0
- package/template/.aioson/locales/fr/agents/architect.md +19 -0
- package/template/.aioson/locales/fr/agents/dev.md +64 -4
- package/template/.aioson/locales/fr/agents/deyvin.md +2 -0
- package/template/.aioson/locales/fr/agents/discovery-design-doc.md +2 -0
- package/template/.aioson/locales/fr/agents/genome.md +2 -0
- package/template/.aioson/locales/fr/agents/neo.md +2 -0
- package/template/.aioson/locales/fr/agents/orache.md +2 -0
- package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/fr/agents/pair.md +2 -0
- package/template/.aioson/locales/fr/agents/pm.md +2 -0
- package/template/.aioson/locales/fr/agents/product.md +52 -0
- package/template/.aioson/locales/fr/agents/profiler-enricher.md +2 -0
- package/template/.aioson/locales/fr/agents/profiler-forge.md +2 -0
- package/template/.aioson/locales/fr/agents/profiler-researcher.md +2 -0
- package/template/.aioson/locales/fr/agents/qa.md +2 -0
- package/template/.aioson/locales/fr/agents/setup.md +2 -0
- package/template/.aioson/locales/fr/agents/sheldon.md +117 -0
- package/template/.aioson/locales/fr/agents/squad.md +16 -0
- package/template/.aioson/locales/fr/agents/tester.md +9 -0
- package/template/.aioson/locales/fr/agents/ux-ui.md +2 -0
- package/template/.aioson/locales/pt-BR/agents/analyst.md +64 -3
- package/template/.aioson/locales/pt-BR/agents/architect.md +42 -0
- package/template/.aioson/locales/pt-BR/agents/dev.md +147 -14
- package/template/.aioson/locales/pt-BR/agents/deyvin.md +47 -0
- package/template/.aioson/locales/pt-BR/agents/neo.md +62 -1
- package/template/.aioson/locales/pt-BR/agents/orchestrator.md +158 -2
- package/template/.aioson/locales/pt-BR/agents/pm.md +95 -1
- package/template/.aioson/locales/pt-BR/agents/product.md +145 -18
- package/template/.aioson/locales/pt-BR/agents/qa.md +16 -0
- package/template/.aioson/locales/pt-BR/agents/setup.md +101 -18
- package/template/.aioson/locales/pt-BR/agents/sheldon.md +132 -1
- package/template/.aioson/locales/pt-BR/agents/squad.md +14 -0
- package/template/.aioson/locales/pt-BR/agents/tester.md +449 -0
- package/template/.aioson/rules/README.md +69 -0
- package/template/.aioson/rules/data-format-convention.md +136 -0
- package/template/.aioson/rules/example-monetary-values.md +30 -0
- package/template/.aioson/schemas/squad-manifest.schema.json +124 -3
- package/template/.aioson/skills/design/cognitive-core-ui/references/motion.md +2 -0
- package/template/.aioson/skills/design/pt.squarespace.com/.skill-meta.json +31 -0
- package/template/.aioson/skills/design/pt.squarespace.com/SKILL.md +66 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/components.md +368 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/design-tokens.md +150 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/motion.md +270 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/patterns.md +189 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/websites.md +165 -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/SKILL.md +1 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/analyst.md +30 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/architect.md +23 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +47 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/deyvin.md +27 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +35 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/product.md +25 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/qa.md +30 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/sheldon.md +25 -0
- package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +4 -1
- package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +15 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +32 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +20 -0
- package/template/.aioson/skills/process/simplify/SKILL.md +173 -0
- package/template/.aioson/skills/static/context-budget-guide.md +46 -0
- package/template/.aioson/skills/static/harness-sensors.md +74 -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/multi-agent-patterns.md +43 -0
- package/template/.aioson/skills/static/react-motion-patterns.md +22 -0
- package/template/.aioson/skills/static/static-html-patterns/checklists.md +43 -0
- package/template/.aioson/skills/static/static-html-patterns/css-tokens.md +609 -0
- package/template/.aioson/skills/static/static-html-patterns/motion.md +193 -0
- package/template/.aioson/skills/static/static-html-patterns/premium.md +711 -0
- package/template/.aioson/skills/static/static-html-patterns/structure.md +209 -0
- package/template/.aioson/skills/static/static-html-patterns/utilities.md +190 -0
- package/template/.aioson/skills/static/static-html-patterns.md +58 -1913
- package/template/.aioson/skills/static/threejs-patterns.md +929 -0
- package/template/.aioson/skills/static/ui-ux-modern.md +1 -0
- package/template/.aioson/skills/static/web-research-cache.md +112 -0
- package/template/.aioson/tasks/implementation-plan.md +21 -1
- package/template/.aioson/tasks/squad-create.md +22 -0
- package/template/.aioson/tasks/squad-design.md +30 -0
- package/template/.aioson/templates/squads/digital-marketing-agency/template.json +96 -0
- package/template/.claude/commands/aioson/agent/design-hybrid-forge.md +5 -0
- package/template/.claude/commands/aioson/agent/orache.md +5 -0
- package/template/.claude/commands/aioson/agent/sheldon.md +5 -0
- package/template/.claude/commands/aioson/agent/site-forge.md +5 -0
- package/template/AGENTS.md +55 -3
- package/template/CLAUDE.md +31 -0
- package/template/OPENCODE.md +4 -0
- package/template/researchs/.gitkeep +0 -0
- 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,256 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson classify — deterministic classification scoring (MICRO/SMALL/MEDIUM).
|
|
5
|
+
*
|
|
6
|
+
* Reads prd-{slug}.md or requirements-{slug}.md and counts complexity indicators.
|
|
7
|
+
* Falls back to --interactive mode if insufficient data.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* aioson classify . --feature=checkout
|
|
11
|
+
* aioson classify . --feature=checkout --json
|
|
12
|
+
* aioson classify . --interactive
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const path = require('node:path');
|
|
16
|
+
const readline = require('node:readline');
|
|
17
|
+
const { readFileSafe, contextDir } = require('../preflight-engine');
|
|
18
|
+
|
|
19
|
+
const BAR = '━'.repeat(30);
|
|
20
|
+
|
|
21
|
+
// Scoring thresholds
|
|
22
|
+
// user_types: 1→0, 2→1, 3+→2
|
|
23
|
+
// external_integrations: 0→0, 1-2→1, 3+→2
|
|
24
|
+
// rule_complexity: none→0, some→1, complex→2
|
|
25
|
+
// Score: 0-1=MICRO, 2-3=SMALL, 4-6=MEDIUM
|
|
26
|
+
|
|
27
|
+
function scoreUserTypes(count) {
|
|
28
|
+
if (count >= 3) return 2;
|
|
29
|
+
if (count >= 2) return 1;
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function scoreIntegrations(count) {
|
|
34
|
+
if (count >= 3) return 2;
|
|
35
|
+
if (count >= 1) return 1;
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function scoreComplexity(level) {
|
|
40
|
+
if (level === 'complex') return 2;
|
|
41
|
+
if (level === 'some') return 1;
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function scoreToClassification(score) {
|
|
46
|
+
if (score <= 1) return 'MICRO';
|
|
47
|
+
if (score <= 3) return 'SMALL';
|
|
48
|
+
return 'MEDIUM';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function classificationToPhaseDepth(classification) {
|
|
52
|
+
if (classification === 'MICRO') {
|
|
53
|
+
return {
|
|
54
|
+
specify: 'brief note or inline',
|
|
55
|
+
research: 'not needed',
|
|
56
|
+
requirements: 'optional',
|
|
57
|
+
design: 'skip',
|
|
58
|
+
plan: 'optional',
|
|
59
|
+
execute: 'direct from task description'
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (classification === 'SMALL') {
|
|
63
|
+
return {
|
|
64
|
+
specify: 'full PRD',
|
|
65
|
+
research: 'recommended (@sheldon)',
|
|
66
|
+
requirements: 'required (requirements-{slug}.md)',
|
|
67
|
+
design: 'selective (only if new pattern)',
|
|
68
|
+
plan: 'recommended',
|
|
69
|
+
execute: 'from requirements + spec'
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
specify: 'full PRD + stakeholder review',
|
|
74
|
+
research: 'required (@sheldon)',
|
|
75
|
+
requirements: 'required + conformance YAML',
|
|
76
|
+
design: 'required (@ux-ui + @architect)',
|
|
77
|
+
plan: 'required + @pm backlog',
|
|
78
|
+
execute: 'from approved plan, phased delivery'
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Pattern-based auto-detection from markdown content
|
|
83
|
+
|
|
84
|
+
const USER_TYPE_PATTERNS = [
|
|
85
|
+
/\b(admin|administrator)\b/gi,
|
|
86
|
+
/\b(user|customer|client|buyer|seller|vendor|manager|operator|guest|visitor|member|owner|reviewer|moderator)\b/gi,
|
|
87
|
+
/\bAs an? ([a-z]+)/gi,
|
|
88
|
+
/\brole[s]?\b.*?:\s*([^,\n]+)/gi
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const INTEGRATION_PATTERNS = [
|
|
92
|
+
/\b(stripe|paypal|braintree|square)\b/gi,
|
|
93
|
+
/\b(sendgrid|mailchimp|ses|postmark|smtp)\b/gi,
|
|
94
|
+
/\b(twilio|vonage|nexmo)\b/gi,
|
|
95
|
+
/\b(s3|cloudinary|gcs|azure blob)\b/gi,
|
|
96
|
+
/\b(oauth|jwt|saml|sso|auth0|firebase auth)\b/gi,
|
|
97
|
+
/\b(redis|memcached|elasticsearch|algolia)\b/gi,
|
|
98
|
+
/\bAPI\s+(integration|endpoint|call)\b/gi,
|
|
99
|
+
/\bthird.party\b/gi,
|
|
100
|
+
/\bwebhook[s]?\b/gi,
|
|
101
|
+
/\bexternal\s+service\b/gi
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
const COMPLEXITY_HIGH_PATTERNS = [
|
|
105
|
+
/\b(multi.step|multi-phase|pipeline|workflow)\b/gi,
|
|
106
|
+
/\b(state machine|finite state|transition)\b/gi,
|
|
107
|
+
/\b(calculation|formula|algorithm|score|pricing engine)\b/gi,
|
|
108
|
+
/\b(complex|intricate|elaborate)\s+(logic|rule|condition)/gi,
|
|
109
|
+
/\b(concurrent|parallel|async|queue)\b/gi,
|
|
110
|
+
/\b(if.+then.+else|conditional|depends on)\b/gi
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
const COMPLEXITY_SOME_PATTERNS = [
|
|
114
|
+
/\b(validation|constraint|rule)\b/gi,
|
|
115
|
+
/\b(permission|role.based|access control)\b/gi,
|
|
116
|
+
/\b(notification|trigger|event)\b/gi
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
function analyzeContent(content) {
|
|
120
|
+
// Count unique user types
|
|
121
|
+
const userTypeSet = new Set();
|
|
122
|
+
for (const pattern of USER_TYPE_PATTERNS) {
|
|
123
|
+
let m;
|
|
124
|
+
while ((m = pattern.exec(content)) !== null) {
|
|
125
|
+
userTypeSet.add(m[1] ? m[1].toLowerCase() : m[0].toLowerCase());
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const userTypeCount = Math.min(userTypeSet.size, 5);
|
|
129
|
+
|
|
130
|
+
// Count integrations
|
|
131
|
+
const integrationSet = new Set();
|
|
132
|
+
for (const pattern of INTEGRATION_PATTERNS) {
|
|
133
|
+
let m;
|
|
134
|
+
while ((m = pattern.exec(content)) !== null) {
|
|
135
|
+
integrationSet.add(m[0].toLowerCase());
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const integrationCount = integrationSet.size;
|
|
139
|
+
|
|
140
|
+
// Complexity level
|
|
141
|
+
let complexityLevel = 'none';
|
|
142
|
+
const highMatches = COMPLEXITY_HIGH_PATTERNS.some((p) => p.test(content));
|
|
143
|
+
if (highMatches) {
|
|
144
|
+
complexityLevel = 'complex';
|
|
145
|
+
} else {
|
|
146
|
+
const someMatches = COMPLEXITY_SOME_PATTERNS.some((p) => p.test(content));
|
|
147
|
+
if (someMatches) complexityLevel = 'some';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { userTypeCount, integrationCount, complexityLevel };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function runInteractive(logger) {
|
|
154
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
155
|
+
const ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
logger.log('');
|
|
159
|
+
logger.log('Classification — Interactive Mode');
|
|
160
|
+
logger.log(BAR);
|
|
161
|
+
|
|
162
|
+
const utRaw = await ask('User types (1 / 2 / 3+): ');
|
|
163
|
+
const userTypeCount = parseInt(utRaw) || 1;
|
|
164
|
+
|
|
165
|
+
const intRaw = await ask('External integrations (0 / 1-2 / 3+): ');
|
|
166
|
+
const integrationCount = parseInt(intRaw) || 0;
|
|
167
|
+
|
|
168
|
+
const cxRaw = await ask('Business rule complexity (none / some / complex): ');
|
|
169
|
+
const complexityLevel = ['none', 'some', 'complex'].includes(cxRaw.trim().toLowerCase())
|
|
170
|
+
? cxRaw.trim().toLowerCase()
|
|
171
|
+
: 'none';
|
|
172
|
+
|
|
173
|
+
rl.close();
|
|
174
|
+
return { userTypeCount, integrationCount, complexityLevel };
|
|
175
|
+
} catch {
|
|
176
|
+
rl.close();
|
|
177
|
+
return { userTypeCount: 1, integrationCount: 0, complexityLevel: 'none' };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function runClassify({ args, options = {}, logger }) {
|
|
182
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
183
|
+
const slug = options.feature ? String(options.feature) : null;
|
|
184
|
+
const interactive = Boolean(options.interactive);
|
|
185
|
+
|
|
186
|
+
let userTypeCount, integrationCount, complexityLevel;
|
|
187
|
+
let sourceFile = null;
|
|
188
|
+
|
|
189
|
+
if (interactive) {
|
|
190
|
+
({ userTypeCount, integrationCount, complexityLevel } = await runInteractive(logger));
|
|
191
|
+
} else {
|
|
192
|
+
// Auto-detect from PRD or requirements file
|
|
193
|
+
const dir = contextDir(targetDir);
|
|
194
|
+
const candidates = slug
|
|
195
|
+
? [
|
|
196
|
+
path.join(dir, `requirements-${slug}.md`),
|
|
197
|
+
path.join(dir, `prd-${slug}.md`),
|
|
198
|
+
path.join(dir, `sheldon-enrichment-${slug}.md`)
|
|
199
|
+
]
|
|
200
|
+
: [path.join(dir, 'requirements.md'), path.join(dir, 'prd.md')];
|
|
201
|
+
|
|
202
|
+
let content = null;
|
|
203
|
+
for (const candidate of candidates) {
|
|
204
|
+
content = await readFileSafe(candidate);
|
|
205
|
+
if (content) { sourceFile = path.relative(targetDir, candidate); break; }
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!content) {
|
|
209
|
+
if (options.json) return { ok: false, reason: 'no_source', message: 'No prd or requirements file found. Use --interactive or --feature=<slug>.' };
|
|
210
|
+
logger.log('No source file found. Use --interactive or provide --feature=<slug>.');
|
|
211
|
+
return { ok: false };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
({ userTypeCount, integrationCount, complexityLevel } = analyzeContent(content));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const utScore = scoreUserTypes(userTypeCount);
|
|
218
|
+
const intScore = scoreIntegrations(integrationCount);
|
|
219
|
+
const cxScore = scoreComplexity(complexityLevel);
|
|
220
|
+
const totalScore = utScore + intScore + cxScore;
|
|
221
|
+
const classification = scoreToClassification(totalScore);
|
|
222
|
+
const phaseDepth = classificationToPhaseDepth(classification);
|
|
223
|
+
|
|
224
|
+
const result = {
|
|
225
|
+
ok: true,
|
|
226
|
+
feature_slug: slug,
|
|
227
|
+
source_file: sourceFile,
|
|
228
|
+
inputs: { user_types: userTypeCount, external_integrations: integrationCount, rule_complexity: complexityLevel },
|
|
229
|
+
scores: { user_types: utScore, integrations: intScore, complexity: cxScore, total: totalScore },
|
|
230
|
+
classification,
|
|
231
|
+
phase_depth: phaseDepth
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
if (options.json) return result;
|
|
235
|
+
|
|
236
|
+
const header = slug ? `Classification — ${slug}` : 'Classification';
|
|
237
|
+
logger.log('');
|
|
238
|
+
logger.log(header);
|
|
239
|
+
logger.log(BAR);
|
|
240
|
+
if (sourceFile) logger.log(`Source: ${sourceFile}`);
|
|
241
|
+
logger.log(`User types: ${userTypeCount} → +${utScore}`);
|
|
242
|
+
logger.log(`External integrations: ${integrationCount} → +${intScore}`);
|
|
243
|
+
logger.log(`Business rule complexity: ${complexityLevel} → +${cxScore}`);
|
|
244
|
+
logger.log(BAR);
|
|
245
|
+
logger.log(`Score: ${totalScore} → ${classification}`);
|
|
246
|
+
logger.log('');
|
|
247
|
+
logger.log('Phase depth:');
|
|
248
|
+
for (const [phase, desc] of Object.entries(phaseDepth)) {
|
|
249
|
+
logger.log(` ${phase.padEnd(14)}: ${desc}`);
|
|
250
|
+
}
|
|
251
|
+
logger.log('');
|
|
252
|
+
|
|
253
|
+
return result;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
module.exports = { runClassify };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson context:compact — Standalone context compaction
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* aioson context:compact . --agent=dev --input=devlog.md
|
|
8
|
+
* aioson context:compact . --agent=orache --input=notes.md --session=abc-123
|
|
9
|
+
* aioson context:compact . --agent=dev --json
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const path = require('node:path');
|
|
13
|
+
const { compactContext } = require('../squad/context-compactor');
|
|
14
|
+
|
|
15
|
+
async function runContextCompact({ args, options = {}, logger }) {
|
|
16
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
17
|
+
const agent = String(options.agent || options.a || 'dev').trim();
|
|
18
|
+
const input = options.input ? String(options.input).trim() : undefined;
|
|
19
|
+
const session = options.session ? String(options.session).trim() : undefined;
|
|
20
|
+
|
|
21
|
+
if (!input) {
|
|
22
|
+
logger.error('Error: --input=<path> is required (path to devlog, notes, or output)');
|
|
23
|
+
return { ok: false, error: 'missing_input' };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const result = await compactContext(targetDir, { agent, input, session });
|
|
27
|
+
|
|
28
|
+
if (!result.ok) {
|
|
29
|
+
logger.error(`Error: ${result.error}`);
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (options.json) return result.summary;
|
|
34
|
+
|
|
35
|
+
const s = result.summary.summary;
|
|
36
|
+
logger.log(`Context compacted for @${agent}`);
|
|
37
|
+
logger.log(` Session: ${result.summary.session_id}`);
|
|
38
|
+
logger.log(` Tools: ${s.tools_used.length} detected`);
|
|
39
|
+
logger.log(` Requests: ${s.recent_requests.length} extracted`);
|
|
40
|
+
logger.log(` Pending: ${s.pending_work.length} items`);
|
|
41
|
+
logger.log(` Files: ${s.key_files.length} referenced`);
|
|
42
|
+
logger.log(` Timeline: ${s.timeline.length} events`);
|
|
43
|
+
logger.log('');
|
|
44
|
+
logger.log(`Output: ${path.relative(targetDir, result.path)}`);
|
|
45
|
+
|
|
46
|
+
return { ok: true, ...result.summary };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = { runContextCompact };
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { openRuntimeDb } = require('../runtime-store');
|
|
6
|
+
|
|
7
|
+
const CHARS_PER_TOKEN = 4;
|
|
8
|
+
const HEAVY_TOKEN_THRESHOLD = 5000; // ~20KB
|
|
9
|
+
const CRITICAL_TOKEN_THRESHOLD = 12500; // ~50KB
|
|
10
|
+
|
|
11
|
+
function estimateTokens(content) {
|
|
12
|
+
return Math.ceil(content.length / CHARS_PER_TOKEN);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function formatBytes(bytes) {
|
|
16
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
17
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function formatTokens(n) {
|
|
21
|
+
return `~${n.toLocaleString()}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function loadFeatureStatuses(contextDir) {
|
|
25
|
+
const featuresPath = path.join(contextDir, 'features.md');
|
|
26
|
+
try {
|
|
27
|
+
const content = await fs.readFile(featuresPath, 'utf8');
|
|
28
|
+
const done = new Set();
|
|
29
|
+
for (const line of content.split(/\r?\n/)) {
|
|
30
|
+
// Match lines like: - auth: done or | auth | done |
|
|
31
|
+
const m = line.match(/[-|]\s*([a-z0-9_-]+)\s*[:|]\s*done/i);
|
|
32
|
+
if (m) done.add(m[1].toLowerCase());
|
|
33
|
+
}
|
|
34
|
+
return done;
|
|
35
|
+
} catch {
|
|
36
|
+
return new Set();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function getCacheHitRate(db) {
|
|
41
|
+
if (!db) return null;
|
|
42
|
+
try {
|
|
43
|
+
const rows = db.prepare(`
|
|
44
|
+
SELECT COUNT(*) as total,
|
|
45
|
+
SUM(CASE WHEN event_type = 'cache_hit' THEN 1 ELSE 0 END) as hits
|
|
46
|
+
FROM execution_events
|
|
47
|
+
WHERE created_at >= datetime('now', '-7 days')
|
|
48
|
+
`).get();
|
|
49
|
+
if (!rows || rows.total === 0) return null;
|
|
50
|
+
return Math.round((rows.hits / rows.total) * 100);
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function runContextHealth({ args, options = {}, logger }) {
|
|
57
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
58
|
+
const contextDir = path.join(targetDir, '.aioson', 'context');
|
|
59
|
+
|
|
60
|
+
let entries;
|
|
61
|
+
try {
|
|
62
|
+
entries = await fs.readdir(contextDir);
|
|
63
|
+
} catch {
|
|
64
|
+
if (!options.json) logger.log('No .aioson/context/ directory found.');
|
|
65
|
+
return { ok: false, reason: 'no_context_dir' };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const mdFiles = entries.filter((f) => f.endsWith('.md'));
|
|
69
|
+
const report = [];
|
|
70
|
+
let totalTokens = 0;
|
|
71
|
+
|
|
72
|
+
for (const file of mdFiles) {
|
|
73
|
+
try {
|
|
74
|
+
const content = await fs.readFile(path.join(contextDir, file), 'utf8');
|
|
75
|
+
const tokens = estimateTokens(content);
|
|
76
|
+
totalTokens += tokens;
|
|
77
|
+
report.push({
|
|
78
|
+
file,
|
|
79
|
+
sizeBytes: content.length,
|
|
80
|
+
tokens,
|
|
81
|
+
heavy: tokens > HEAVY_TOKEN_THRESHOLD,
|
|
82
|
+
critical: tokens > CRITICAL_TOKEN_THRESHOLD
|
|
83
|
+
});
|
|
84
|
+
} catch { /* skip unreadable files */ }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
report.sort((a, b) => b.tokens - a.tokens);
|
|
88
|
+
|
|
89
|
+
const doneFeatures = await loadFeatureStatuses(contextDir);
|
|
90
|
+
const staleSpecs = report.filter((r) => {
|
|
91
|
+
if (!r.file.startsWith('spec-')) return false;
|
|
92
|
+
const slug = r.file.replace(/^spec-/, '').replace(/\.md$/, '');
|
|
93
|
+
return doneFeatures.has(slug);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const { db, dbPath } = await openRuntimeDb(targetDir, { mustExist: true }).catch(() => ({ db: null, dbPath: null }));
|
|
97
|
+
const cacheHitRate = await getCacheHitRate(db);
|
|
98
|
+
if (db) db.close();
|
|
99
|
+
|
|
100
|
+
const skeletonPresent = entries.includes('skeleton-system.md') || entries.includes('skeleton.md');
|
|
101
|
+
|
|
102
|
+
if (options.json) {
|
|
103
|
+
return {
|
|
104
|
+
ok: true,
|
|
105
|
+
totalTokens,
|
|
106
|
+
files: report,
|
|
107
|
+
staleSpecs: staleSpecs.map((s) => s.file),
|
|
108
|
+
cacheHitRate,
|
|
109
|
+
skeletonPresent,
|
|
110
|
+
dbPath
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const COL_FILE = 28;
|
|
115
|
+
const COL_SIZE = 10;
|
|
116
|
+
const COL_TOKENS = 16;
|
|
117
|
+
|
|
118
|
+
logger.log(`Context Health Report — ${path.basename(targetDir)}`);
|
|
119
|
+
logger.log('─'.repeat(56));
|
|
120
|
+
logger.log('Files'.padEnd(COL_FILE) + 'Size'.padEnd(COL_SIZE) + 'Tokens (est.)');
|
|
121
|
+
logger.log('─'.repeat(56));
|
|
122
|
+
|
|
123
|
+
for (const r of report) {
|
|
124
|
+
const flag = r.critical ? ' !! CRITICAL' : r.heavy ? ' ⚠ HEAVY' : '';
|
|
125
|
+
logger.log(
|
|
126
|
+
r.file.padEnd(COL_FILE) +
|
|
127
|
+
formatBytes(r.sizeBytes).padEnd(COL_SIZE) +
|
|
128
|
+
formatTokens(r.tokens) + flag
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
logger.log('─'.repeat(56));
|
|
133
|
+
logger.log(`Total context load:`.padEnd(COL_FILE + COL_SIZE) + formatTokens(totalTokens) + ' tokens');
|
|
134
|
+
logger.log('');
|
|
135
|
+
|
|
136
|
+
const heavyFiles = report.filter((r) => r.heavy);
|
|
137
|
+
if (heavyFiles.length > 0) {
|
|
138
|
+
for (const r of heavyFiles) {
|
|
139
|
+
const label = r.critical ? 'CRITICAL' : 'heavy';
|
|
140
|
+
logger.log(`⚠ ${r.file} is ${label} (${formatBytes(r.sizeBytes)}). Consider:`);
|
|
141
|
+
logger.log(` → Run: aioson context:pack . --scope=<feature>`);
|
|
142
|
+
logger.log(` Creates a scoped context for a specific feature`);
|
|
143
|
+
}
|
|
144
|
+
logger.log('');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (staleSpecs.length > 0) {
|
|
148
|
+
logger.log(`⚠ ${staleSpecs.length} stale spec file(s) (features: done):`);
|
|
149
|
+
for (const s of staleSpecs) {
|
|
150
|
+
const slug = s.file.replace(/^spec-/, '').replace(/\.md$/, '');
|
|
151
|
+
logger.log(` → ${s.file} (feature: ${slug} is done)`);
|
|
152
|
+
}
|
|
153
|
+
logger.log(` Run: aioson context:trim . to archive them`);
|
|
154
|
+
logger.log('');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (cacheHitRate !== null) {
|
|
158
|
+
logger.log(`✓ Cache hit rate: ${cacheHitRate}% (last 7 days)`);
|
|
159
|
+
}
|
|
160
|
+
if (skeletonPresent) {
|
|
161
|
+
logger.log(`✓ skeleton-system.md present — agents can use as lightweight index`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
ok: true,
|
|
166
|
+
totalTokens,
|
|
167
|
+
files: report,
|
|
168
|
+
staleSpecs: staleSpecs.map((s) => s.file),
|
|
169
|
+
cacheHitRate,
|
|
170
|
+
skeletonPresent,
|
|
171
|
+
dbPath
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
module.exports = { runContextHealth };
|
|
@@ -6,6 +6,13 @@ const {
|
|
|
6
6
|
computeWarningLevel,
|
|
7
7
|
THRESHOLDS
|
|
8
8
|
} = require('../squad-dashboard/context-monitor');
|
|
9
|
+
const { openRuntimeDb, appendRunEvent } = require('../runtime-store');
|
|
10
|
+
|
|
11
|
+
const PROJECT_BUDGET_ZONES = {
|
|
12
|
+
safe: 0.60,
|
|
13
|
+
warning: 0.80,
|
|
14
|
+
critical: 1.00
|
|
15
|
+
};
|
|
9
16
|
|
|
10
17
|
const BAR_WIDTH = 20;
|
|
11
18
|
const LEVEL_ICONS = { normal: ' ', warning: '⚠', critical: '!', overflow: 'X', unknown: '?' };
|
|
@@ -36,15 +43,79 @@ function renderAgent(slug, agent) {
|
|
|
36
43
|
return line;
|
|
37
44
|
}
|
|
38
45
|
|
|
46
|
+
async function emitBudgetEvent(cwd, { tokens, budget, pct, zone, agentName }) {
|
|
47
|
+
const { db } = await openRuntimeDb(cwd, { mustExist: true }).catch(() => ({ db: null }));
|
|
48
|
+
if (!db) return;
|
|
49
|
+
try {
|
|
50
|
+
const run = db.prepare(
|
|
51
|
+
"SELECT run_key FROM agent_runs WHERE status = 'running' ORDER BY updated_at DESC LIMIT 1"
|
|
52
|
+
).get();
|
|
53
|
+
if (run) {
|
|
54
|
+
appendRunEvent(db, {
|
|
55
|
+
runKey: run.run_key,
|
|
56
|
+
eventType: zone === 'critical' ? 'context_budget_critical' : 'context_budget_warning',
|
|
57
|
+
phase: 'live',
|
|
58
|
+
status: 'running',
|
|
59
|
+
message: `Context at ${pct}% of budget (${tokens.toLocaleString()} tokens)`,
|
|
60
|
+
payload: { tokens, budget, pct, zone, agentName: agentName || null },
|
|
61
|
+
createdAt: new Date().toISOString()
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
} finally {
|
|
65
|
+
db.close();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
39
69
|
async function runContextMonitor({ args, options, logger }) {
|
|
40
70
|
const cwd = path.resolve(process.cwd(), args[0] || '.');
|
|
41
71
|
const squadSlug = options.squad || null;
|
|
42
72
|
const agentSlug = options.agent || null;
|
|
73
|
+
const budget = options.budget ? Number(options.budget) : null;
|
|
74
|
+
|
|
75
|
+
// Project-level budget monitoring (--budget=<tokens>)
|
|
76
|
+
if (budget && !squadSlug) {
|
|
77
|
+
const tokens = options.tokens ? Number(options.tokens) : null;
|
|
78
|
+
if (tokens !== null) {
|
|
79
|
+
const pct = Math.round((tokens / budget) * 100);
|
|
80
|
+
const zone = pct >= 100 ? 'overflow'
|
|
81
|
+
: pct >= PROJECT_BUDGET_ZONES.warning * 100 ? 'critical'
|
|
82
|
+
: pct >= PROJECT_BUDGET_ZONES.safe * 100 ? 'warning'
|
|
83
|
+
: 'safe';
|
|
84
|
+
|
|
85
|
+
const icon = zone === 'overflow' ? 'X' : zone === 'critical' ? '!' : zone === 'warning' ? '⚠' : '✓';
|
|
86
|
+
|
|
87
|
+
if (!options.json) {
|
|
88
|
+
logger.log(` ${icon} Context: ${tokens.toLocaleString()} tokens (${pct}%) — ${zone.toUpperCase()}`);
|
|
89
|
+
if (zone === 'warning') {
|
|
90
|
+
logger.log(` Suggestion: /clear before next agent activation`);
|
|
91
|
+
} else if (zone === 'critical' || zone === 'overflow') {
|
|
92
|
+
logger.log(` Run: aioson context:health . for reduction options`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (zone === 'warning' || zone === 'critical' || zone === 'overflow') {
|
|
97
|
+
await emitBudgetEvent(cwd, { tokens, budget, pct, zone, agentName: agentSlug });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (options.json) {
|
|
101
|
+
return { ok: true, tokens, budget, pct, zone };
|
|
102
|
+
}
|
|
103
|
+
return { ok: true, tokens, budget, pct, zone };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!options.json) {
|
|
107
|
+
logger.log(` Budget: ${budget.toLocaleString()} tokens`);
|
|
108
|
+
logger.log(` Zones: safe=<${PROJECT_BUDGET_ZONES.safe * 100}% warning=${PROJECT_BUDGET_ZONES.safe * 100}-${PROJECT_BUDGET_ZONES.warning * 100}% critical=>=${PROJECT_BUDGET_ZONES.warning * 100}%`);
|
|
109
|
+
logger.log(` Use --tokens=<n> to check against budget`);
|
|
110
|
+
}
|
|
111
|
+
return { ok: true, budget, zones: PROJECT_BUDGET_ZONES };
|
|
112
|
+
}
|
|
43
113
|
|
|
44
114
|
if (!squadSlug) {
|
|
45
115
|
logger.log('\n Context Monitor\n');
|
|
46
116
|
logger.log(' No squad specified. Use --squad=<slug> to monitor a squad.');
|
|
47
117
|
logger.log(' Example: aioson context:monitor . --squad=my-squad');
|
|
118
|
+
logger.log(' Or use --budget=<tokens> --tokens=<current> for project-level monitoring.');
|
|
48
119
|
logger.log('');
|
|
49
120
|
return { ok: true, squads: [] };
|
|
50
121
|
}
|