smart-context-mcp 1.5.0 → 1.6.1
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/README.md +77 -0
- package/package.json +9 -2
- package/scripts/doctor-state.js +89 -0
- package/scripts/init-clients.js +48 -7
- package/scripts/report-metrics.js +12 -1
- package/scripts/report-workflow-metrics.js +35 -2
- package/scripts/task-runner.js +238 -0
- package/src/analytics/product-quality.js +206 -0
- package/src/client-contract.js +153 -0
- package/src/context-patterns.js +11 -0
- package/src/hooks/claude-hooks.js +48 -49
- package/src/metrics.js +19 -16
- package/src/orchestration/headless-wrapper.js +20 -26
- package/src/repo-safety.js +21 -0
- package/src/server.js +14 -4
- package/src/storage/sqlite.js +282 -13
- package/src/task-runner/policy.js +354 -0
- package/src/task-runner.js +659 -0
- package/src/tools/smart-doctor.js +418 -0
- package/src/tools/smart-metrics.js +54 -30
- package/src/tools/smart-status.js +79 -7
- package/src/tools/smart-summary.js +29 -29
- package/src/tools/smart-turn.js +455 -14
- package/src/utils/mutation-safety.js +85 -0
- package/src/utils/runtime-config.js +2 -2
- package/src/workflow-tracker.js +261 -39
package/README.md
CHANGED
|
@@ -14,6 +14,14 @@ npx smart-context-init --target . --clients cursor
|
|
|
14
14
|
```
|
|
15
15
|
Restart Cursor. Done.
|
|
16
16
|
|
|
17
|
+
Optional assisted mode for long tasks:
|
|
18
|
+
```bash
|
|
19
|
+
./.devctx/bin/cursor-devctx task --prompt "your task" -- <agent-command> [args...]
|
|
20
|
+
./.devctx/bin/cursor-devctx implement --prompt "implement the auth guard" -- <agent-command> [args...]
|
|
21
|
+
./.devctx/bin/cursor-devctx review --prompt "review the latest diff" -- <agent-command> [args...]
|
|
22
|
+
./.devctx/bin/cursor-devctx doctor
|
|
23
|
+
```
|
|
24
|
+
|
|
17
25
|
### Codex CLI
|
|
18
26
|
```bash
|
|
19
27
|
npm install -g smart-context-mcp
|
|
@@ -44,6 +52,41 @@ Restart your AI client. Done.
|
|
|
44
52
|
|
|
45
53
|
---
|
|
46
54
|
|
|
55
|
+
## `1.6.0` Task Runner
|
|
56
|
+
|
|
57
|
+
`1.6.0` adds `smart-context-task`, a workflow-oriented CLI on top of the raw MCP tools.
|
|
58
|
+
|
|
59
|
+
Use it when you want a more repeatable path than “agent reads rules and hopefully picks the right flow”.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
smart-context-task task --prompt "inspect the auth flow and continue the bugfix"
|
|
63
|
+
smart-context-task implement --prompt "add a token guard to loginHandler"
|
|
64
|
+
smart-context-task continue --session-id my-session-id
|
|
65
|
+
smart-context-task review --prompt "review the latest diff"
|
|
66
|
+
smart-context-task doctor
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The runner now covers:
|
|
70
|
+
|
|
71
|
+
- `task`
|
|
72
|
+
- `implement`
|
|
73
|
+
- `continue`
|
|
74
|
+
- `resume`
|
|
75
|
+
- `review`
|
|
76
|
+
- `debug`
|
|
77
|
+
- `refactor`
|
|
78
|
+
- `test`
|
|
79
|
+
- `doctor`
|
|
80
|
+
- `status`
|
|
81
|
+
- `checkpoint`
|
|
82
|
+
- `cleanup`
|
|
83
|
+
|
|
84
|
+
For Cursor projects, `smart-context-init` also generates `./.devctx/bin/cursor-devctx`, which routes through the same runner/policy stack.
|
|
85
|
+
|
|
86
|
+
See [Task Runner Workflows](../../docs/task-runner.md) for the full behavior and command guidance.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
47
90
|
## 📊 Real Metrics
|
|
48
91
|
|
|
49
92
|
**Production use on this project:**
|
|
@@ -167,11 +210,17 @@ Use devctx: smart_turn(start) → smart_context → smart_turn(end)
|
|
|
167
210
|
- ✅ Rules **guide** the agent (not enforce)
|
|
168
211
|
- ✅ Agent can use built-in tools when appropriate
|
|
169
212
|
- ✅ Token savings: 85-90% on complex tasks
|
|
213
|
+
- ✅ Reports can show both gross savings and net savings after context overhead
|
|
214
|
+
- ✅ Workflow JSON/reporting now exposes net-metrics coverage, so historical rows without persisted overhead are explicit
|
|
215
|
+
- ✅ `smart_metrics` now exposes measured orchestration-quality signals from `smart_turn` (continuity recovery, blocked-state remediation coverage, context-refresh signals)
|
|
216
|
+
- ✅ If `.devctx/state.sqlite` is tracked or staged, runtime SQLite mutations pause across checkpoints, workflow tracking, hook state, and pattern learning
|
|
170
217
|
|
|
171
218
|
Check actual usage:
|
|
172
219
|
- **Real-time feedback** - Enabled by default (disable with `export DEVCTX_SHOW_USAGE=false`)
|
|
173
220
|
- `npm run report:metrics` - Tool-level savings + adoption analysis
|
|
174
221
|
- `npm run report:workflows` - Workflow-level savings (requires `DEVCTX_WORKFLOW_TRACKING=true`)
|
|
222
|
+
- `npm run benchmark:orchestration` - Repeatable orchestration regression suite for continuity, refresh, blocked-state remediation, and checkpoint quality
|
|
223
|
+
- `npm run benchmark:orchestration:release` - Same suite with a checked-in release baseline, used by CI and `prepublishOnly`
|
|
175
224
|
|
|
176
225
|
## What it does
|
|
177
226
|
|
|
@@ -392,6 +441,23 @@ Maintain task checkpoint:
|
|
|
392
441
|
```
|
|
393
442
|
|
|
394
443
|
Stores compressed task state (~100 tokens: goal, status, decisions, blockers), not full conversation. Supports both flat and nested parameter formats.
|
|
444
|
+
When git hygiene or SQLite storage health affects persisted state, responses expose `mutationSafety`, `repoSafety`, `degradedMode`, and `storageHealth` so clients can remediate consistently.
|
|
445
|
+
|
|
446
|
+
### smart_doctor
|
|
447
|
+
|
|
448
|
+
Run a single operational health check across repo hygiene, SQLite state, compaction hygiene, and legacy cleanup:
|
|
449
|
+
|
|
450
|
+
```javascript
|
|
451
|
+
smart_doctor({})
|
|
452
|
+
smart_doctor({ verifyIntegrity: false })
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
CLI:
|
|
456
|
+
|
|
457
|
+
```bash
|
|
458
|
+
smart-context-doctor --json
|
|
459
|
+
smart-context-doctor --no-integrity
|
|
460
|
+
```
|
|
395
461
|
|
|
396
462
|
### smart_status
|
|
397
463
|
|
|
@@ -403,6 +469,17 @@ Display current session context:
|
|
|
403
469
|
```
|
|
404
470
|
|
|
405
471
|
Shows goal, status, recent decisions, touched files, and progress. Updates automatically with each MCP operation.
|
|
472
|
+
When repo safety or SQLite health blocks normal state access, `smart_status` still exposes the same safety contract plus `storageHealth`.
|
|
473
|
+
|
|
474
|
+
### SQLite Recovery
|
|
475
|
+
|
|
476
|
+
If `.devctx/state.sqlite` is unhealthy, use the surfaced `storageHealth.issue`:
|
|
477
|
+
|
|
478
|
+
- `missing`: initialize local state with a persisted action
|
|
479
|
+
- `oversized`: run `smart_summary compact`
|
|
480
|
+
- `locked`: stop competing devctx writers, then retry
|
|
481
|
+
- `corrupted`: back up and remove the file so devctx can recreate it
|
|
482
|
+
- broader inspection: run `smart_doctor` / `smart-context-doctor`
|
|
406
483
|
|
|
407
484
|
### smart_edit
|
|
408
485
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smart-context-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "MCP server that reduces agent token usage by 90% with intelligent context compression, task checkpoint persistence, and workflow-aware agent guidance.",
|
|
5
5
|
"author": "Francisco Caballero Portero <fcp1978@hotmail.com>",
|
|
6
6
|
"type": "module",
|
|
@@ -14,9 +14,11 @@
|
|
|
14
14
|
},
|
|
15
15
|
"bin": {
|
|
16
16
|
"smart-context-headless": "scripts/headless-wrapper.js",
|
|
17
|
+
"smart-context-task": "scripts/task-runner.js",
|
|
17
18
|
"smart-context-server": "scripts/devctx-server.js",
|
|
18
19
|
"smart-context-init": "scripts/init-clients.js",
|
|
19
20
|
"smart-context-report": "scripts/report-metrics.js",
|
|
21
|
+
"smart-context-doctor": "scripts/doctor-state.js",
|
|
20
22
|
"smart-context-protect": "scripts/check-repo-safety.js"
|
|
21
23
|
},
|
|
22
24
|
"exports": {
|
|
@@ -27,9 +29,11 @@
|
|
|
27
29
|
"src/",
|
|
28
30
|
"scripts/claude-hook.js",
|
|
29
31
|
"scripts/check-repo-safety.js",
|
|
32
|
+
"scripts/doctor-state.js",
|
|
30
33
|
"scripts/devctx-server.js",
|
|
31
34
|
"scripts/headless-wrapper.js",
|
|
32
35
|
"scripts/init-clients.js",
|
|
36
|
+
"scripts/task-runner.js",
|
|
33
37
|
"scripts/report-metrics.js",
|
|
34
38
|
"scripts/report-workflow-metrics.js",
|
|
35
39
|
"scripts/report-adoption-metrics.js"
|
|
@@ -55,6 +59,8 @@
|
|
|
55
59
|
"test": "node --test --test-concurrency=1 ./tests/*.test.js",
|
|
56
60
|
"verify": "node ./scripts/verify-features-direct.js",
|
|
57
61
|
"benchmark": "node ./scripts/run-benchmark.js",
|
|
62
|
+
"benchmark:orchestration": "node ./evals/orchestration-benchmark.js",
|
|
63
|
+
"benchmark:orchestration:release": "node ./evals/orchestration-benchmark.js --baseline=./evals/orchestration-release-baseline.json",
|
|
58
64
|
"eval": "node ./evals/harness.js",
|
|
59
65
|
"eval:context": "node ./evals/harness.js --tool=context",
|
|
60
66
|
"eval:both": "node ./evals/harness.js --tool=both",
|
|
@@ -62,7 +68,8 @@
|
|
|
62
68
|
"eval:report": "node ./evals/report.js",
|
|
63
69
|
"report:metrics": "node ./scripts/report-metrics.js",
|
|
64
70
|
"report:workflows": "node ./scripts/report-workflow-metrics.js",
|
|
65
|
-
"report:adoption": "node ./scripts/report-adoption-metrics.js"
|
|
71
|
+
"report:adoption": "node ./scripts/report-adoption-metrics.js",
|
|
72
|
+
"prepublishOnly": "npm test && npm run benchmark:orchestration:release"
|
|
66
73
|
},
|
|
67
74
|
"dependencies": {
|
|
68
75
|
"@modelcontextprotocol/sdk": "^1.13.0",
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { smartDoctor } from '../src/tools/smart-doctor.js';
|
|
5
|
+
import { setProjectRoot } from '../src/utils/runtime-config.js';
|
|
6
|
+
|
|
7
|
+
const writeStdout = (text) => {
|
|
8
|
+
fs.writeSync(process.stdout.fd, text);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const writeStderr = (text) => {
|
|
12
|
+
fs.writeSync(process.stderr.fd, text);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const parseArgs = (argv) => {
|
|
16
|
+
const options = {
|
|
17
|
+
projectRoot: process.cwd(),
|
|
18
|
+
json: false,
|
|
19
|
+
verifyIntegrity: true,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
23
|
+
const token = argv[index];
|
|
24
|
+
|
|
25
|
+
if (token === '--project-root') {
|
|
26
|
+
const next = argv[index + 1];
|
|
27
|
+
if (!next || next.startsWith('--')) {
|
|
28
|
+
throw new Error('Missing value for --project-root');
|
|
29
|
+
}
|
|
30
|
+
options.projectRoot = path.resolve(next);
|
|
31
|
+
index += 1;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (token === '--json') {
|
|
36
|
+
options.json = true;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (token === '--no-integrity') {
|
|
41
|
+
options.verifyIntegrity = false;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
throw new Error(`Unknown argument: ${token}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return options;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const printHuman = (result) => {
|
|
52
|
+
const writer = result.overall === 'error' ? writeStderr : writeStdout;
|
|
53
|
+
writer(`devctx doctor: ${result.overall}\n`);
|
|
54
|
+
writer(`${result.message}\n`);
|
|
55
|
+
|
|
56
|
+
for (const check of result.checks ?? []) {
|
|
57
|
+
writer(`\n[${check.status}] ${check.id}: ${check.message}\n`);
|
|
58
|
+
for (const action of check.recommendedActions ?? []) {
|
|
59
|
+
writer(`- ${action}\n`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const main = async () => {
|
|
65
|
+
const options = parseArgs(process.argv.slice(2));
|
|
66
|
+
setProjectRoot(options.projectRoot);
|
|
67
|
+
|
|
68
|
+
const result = await smartDoctor({
|
|
69
|
+
verifyIntegrity: options.verifyIntegrity,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (options.json) {
|
|
73
|
+
const output = `${JSON.stringify(result, null, 2)}\n`;
|
|
74
|
+
if (result.overall === 'error') {
|
|
75
|
+
writeStderr(output);
|
|
76
|
+
} else {
|
|
77
|
+
writeStdout(output);
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
printHuman(result);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
process.exitCode = result.overall === 'error' ? 1 : 0;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
main().catch((error) => {
|
|
87
|
+
writeStderr(`${error.message}\n`);
|
|
88
|
+
process.exitCode = 1;
|
|
89
|
+
});
|
package/scripts/init-clients.js
CHANGED
|
@@ -3,6 +3,7 @@ import { execFileSync } from 'node:child_process';
|
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { CLIENT_CONTRACT_RULE_LINES } from '../src/client-contract.js';
|
|
6
7
|
|
|
7
8
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
8
9
|
const scriptsDir = path.dirname(currentFilePath);
|
|
@@ -164,6 +165,35 @@ const updateCursorConfig = (targetDir, serverConfig, dryRun) => {
|
|
|
164
165
|
writeFile(filePath, `${JSON.stringify(current, null, 2)}\n`, dryRun);
|
|
165
166
|
};
|
|
166
167
|
|
|
168
|
+
const buildCursorAssistedLauncher = (targetDir) => {
|
|
169
|
+
const runnerScript = normalizeCommandPath(path.relative(targetDir, path.join(devctxDir, 'scripts', 'task-runner.js')));
|
|
170
|
+
return `#!/bin/sh
|
|
171
|
+
set -eu
|
|
172
|
+
|
|
173
|
+
script_dir="$(CDPATH= cd -- "$(dirname "$0")" && pwd)"
|
|
174
|
+
project_root="$(CDPATH= cd -- "$script_dir/../.." && pwd)"
|
|
175
|
+
|
|
176
|
+
export DEVCTX_PROJECT_ROOT="$project_root"
|
|
177
|
+
|
|
178
|
+
if [ "$#" -gt 0 ] && [ "\${1#-}" = "$1" ]; then
|
|
179
|
+
subcommand="$1"
|
|
180
|
+
shift
|
|
181
|
+
exec "${process.execPath}" "$project_root/${runnerScript}" "$subcommand" --client cursor "$@"
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
exec "${process.execPath}" "$project_root/${runnerScript}" task --client cursor "$@"
|
|
185
|
+
`;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const updateCursorAssistedLauncher = (targetDir, dryRun) => {
|
|
189
|
+
const filePath = path.join(targetDir, '.devctx', 'bin', 'cursor-devctx');
|
|
190
|
+
writeFile(filePath, buildCursorAssistedLauncher(targetDir), dryRun);
|
|
191
|
+
|
|
192
|
+
if (!dryRun) {
|
|
193
|
+
fs.chmodSync(filePath, 0o755);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
167
197
|
const updateClaudeConfig = (targetDir, serverConfig, dryRun) => {
|
|
168
198
|
const filePath = path.join(targetDir, '.mcp.json');
|
|
169
199
|
const current = readJson(filePath, { mcpServers: {} });
|
|
@@ -375,15 +405,25 @@ const updatePreCommitHook = (targetDir, dryRun) => {
|
|
|
375
405
|
// Agent rules — instruct agents to prefer devctx tools over built-in ones
|
|
376
406
|
// ---------------------------------------------------------------------------
|
|
377
407
|
|
|
378
|
-
const agentRuleBody = `**First time in project?** Run build_index to enable search/context quality.
|
|
408
|
+
const agentRuleBody = `**First time in project?** Run build_index(incremental=true) to enable search/context quality.
|
|
379
409
|
|
|
380
410
|
Prefer devctx MCP for non-trivial tasks:
|
|
381
|
-
-
|
|
382
|
-
- smart_search(intent=...)
|
|
383
|
-
-
|
|
384
|
-
- smart_shell instead of Shell
|
|
411
|
+
- smart_turn(start, userPrompt, ensureSession=true) before multi-step work
|
|
412
|
+
- smart_context(...) or smart_search(intent=...) to build context cheaply
|
|
413
|
+
- smart_read(outline|signatures|symbol) before full reads
|
|
414
|
+
- smart_shell instead of Shell for safe diagnostics
|
|
415
|
+
- smart_turn(end, event=milestone) after meaningful progress
|
|
416
|
+
|
|
417
|
+
If devctx MCP is installed and enabled, default to devctx on every non-trivial multi-file or multi-step task. Skip it only for genuinely trivial work, and then state why it was skipped.
|
|
418
|
+
|
|
419
|
+
Client contract:
|
|
420
|
+
- ${CLIENT_CONTRACT_RULE_LINES.join('\n- ')}
|
|
385
421
|
|
|
386
|
-
|
|
422
|
+
Cursor assisted mode:
|
|
423
|
+
- For long or continuity-sensitive tasks, prefer the local launcher \`./.devctx/bin/cursor-devctx\`
|
|
424
|
+
- Usage: \`./.devctx/bin/cursor-devctx task --prompt "your task" -- <agent-command> [args...]\`
|
|
425
|
+
- Specialized flows: \`review\`, \`debug\`, \`refactor\`, \`test\`, \`doctor\`, \`status\`, \`checkpoint\`, \`cleanup\`
|
|
426
|
+
- This launcher wraps the prompt with smart_turn(start/end) orchestration and the shared operational contract
|
|
387
427
|
|
|
388
428
|
Reading cascade: outline → signatures → symbol → full (last resort)
|
|
389
429
|
|
|
@@ -393,7 +433,7 @@ Detailed workflows: .cursor/rules/profiles-compact/ (debugging, code-review, ref
|
|
|
393
433
|
|
|
394
434
|
If you didn't use devctx tools in a non-trivial programming task, add at the end:
|
|
395
435
|
|
|
396
|
-
**Note:** devctx not used because: [task too simple | MCP unavailable | index not built | already had sufficient context | native tool more direct for this case]. To use devctx next time: "Use smart-context-mcp: smart_turn(start) → smart_context/smart_search → smart_read → smart_turn(end)"`;
|
|
436
|
+
**Note:** devctx not used because: [task too simple | MCP unavailable | index not built | already had sufficient context | native tool more direct for this case]. To use devctx next time: "Use smart-context-mcp: smart_turn(start, userPrompt, ensureSession=true) → smart_context/smart_search → smart_read → smart_turn(end, event=milestone)"`;
|
|
397
437
|
|
|
398
438
|
const cursorRuleContent = `---
|
|
399
439
|
description: Prefer devctx MCP tools for non-trivial tasks
|
|
@@ -515,6 +555,7 @@ const main = () => {
|
|
|
515
555
|
if (clientSet.has('cursor')) {
|
|
516
556
|
updateCursorConfig(targetDir, serverConfig, options.dryRun);
|
|
517
557
|
updateCursorRule(targetDir, options.dryRun);
|
|
558
|
+
updateCursorAssistedLauncher(targetDir, options.dryRun);
|
|
518
559
|
}
|
|
519
560
|
|
|
520
561
|
if (clientSet.has('codex')) {
|
|
@@ -3,6 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { smartMetrics } from '../src/tools/smart-metrics.js';
|
|
5
5
|
import { formatAdoptionReport } from '../src/analytics/adoption.js';
|
|
6
|
+
import { formatProductQualityReport } from '../src/analytics/product-quality.js';
|
|
6
7
|
|
|
7
8
|
const requireValue = (argv, index, flag) => {
|
|
8
9
|
const value = argv[index + 1];
|
|
@@ -60,6 +61,8 @@ export const createReport = async (options) => {
|
|
|
60
61
|
toolFilter: options.tool,
|
|
61
62
|
invalidLines: result.invalidLines,
|
|
62
63
|
summary: result.summary,
|
|
64
|
+
adoption: result.adoption,
|
|
65
|
+
productQuality: result.productQuality,
|
|
63
66
|
};
|
|
64
67
|
};
|
|
65
68
|
|
|
@@ -73,6 +76,10 @@ const printHuman = (report) => {
|
|
|
73
76
|
console.log(`Raw tokens: ${formatNumber(report.summary.rawTokens)}`);
|
|
74
77
|
console.log(`Final tokens: ${formatNumber(report.summary.compressedTokens)}`);
|
|
75
78
|
console.log(`Saved tokens: ${formatNumber(report.summary.savedTokens)} (${report.summary.savingsPct}%)`);
|
|
79
|
+
console.log(`Net saved: ${formatNumber(report.summary.netSavedTokens)} (${report.summary.netSavingsPct}%)`);
|
|
80
|
+
if (report.summary.overheadTokens > 0) {
|
|
81
|
+
console.log(`Overhead: ${formatNumber(report.summary.overheadTokens)} (${report.summary.overheadPctOfRaw}% of raw)`);
|
|
82
|
+
}
|
|
76
83
|
if (report.invalidLines.length > 0) {
|
|
77
84
|
console.log(`Invalid JSONL: ${report.invalidLines.join(', ')}`);
|
|
78
85
|
}
|
|
@@ -86,13 +93,17 @@ const printHuman = (report) => {
|
|
|
86
93
|
|
|
87
94
|
for (const tool of report.summary.tools) {
|
|
88
95
|
console.log(
|
|
89
|
-
` ${tool.tool.padEnd(14)} count=${formatNumber(tool.count)} raw=${formatNumber(tool.rawTokens)} final=${formatNumber(tool.compressedTokens)} saved=${formatNumber(tool.savedTokens)} (${tool.savingsPct}%)`
|
|
96
|
+
` ${tool.tool.padEnd(14)} count=${formatNumber(tool.count)} raw=${formatNumber(tool.rawTokens)} final=${formatNumber(tool.compressedTokens)} saved=${formatNumber(tool.savedTokens)} (${tool.savingsPct}%) net=${formatNumber(tool.netSavedTokens)} (${tool.netSavingsPct}%)`
|
|
90
97
|
);
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
if (report.adoption) {
|
|
94
101
|
console.log(formatAdoptionReport(report.adoption));
|
|
95
102
|
}
|
|
103
|
+
|
|
104
|
+
if (report.productQuality?.turnsMeasured > 0) {
|
|
105
|
+
console.log(formatProductQualityReport(report.productQuality));
|
|
106
|
+
}
|
|
96
107
|
};
|
|
97
108
|
|
|
98
109
|
export const main = async () => {
|
|
@@ -116,14 +116,31 @@ const printSummary = (summary) => {
|
|
|
116
116
|
const totalRaw = summary.reduce((sum, s) => sum + s.total_raw_tokens, 0);
|
|
117
117
|
const totalCompressed = summary.reduce((sum, s) => sum + s.total_compressed_tokens, 0);
|
|
118
118
|
const totalSaved = summary.reduce((sum, s) => sum + s.total_saved_tokens, 0);
|
|
119
|
+
const totalOverhead = summary.reduce((sum, s) => sum + (s.total_overhead_tokens || 0), 0);
|
|
120
|
+
const totalNetSaved = summary.reduce((sum, s) => sum + (s.total_net_saved_tokens || 0), 0);
|
|
121
|
+
const totalNetCoverage = summary.reduce(
|
|
122
|
+
(sum, s) => sum + (s.netMetricsCoverage?.coveredWorkflows ?? s.net_metrics_count ?? 0),
|
|
123
|
+
0,
|
|
124
|
+
);
|
|
119
125
|
const totalBaseline = summary.reduce((sum, s) => sum + s.total_baseline_tokens, 0);
|
|
126
|
+
const totalSavedPct = totalRaw > 0 ? ((totalSaved / totalRaw) * 100).toFixed(2) : '0.00';
|
|
127
|
+
const totalNetSavedPct = totalRaw > 0 ? ((totalNetSaved / totalRaw) * 100).toFixed(2) : '0.00';
|
|
128
|
+
const baselineSavingsPct = totalBaseline > 0
|
|
129
|
+
? (((totalBaseline - totalCompressed) / totalBaseline) * 100).toFixed(2)
|
|
130
|
+
: '0.00';
|
|
120
131
|
|
|
121
132
|
console.log(`Total Workflows: ${formatNumber(totalWorkflows)}`);
|
|
122
133
|
console.log(`Total Raw Tokens: ${formatNumber(totalRaw)}`);
|
|
123
134
|
console.log(`Total Compressed Tokens: ${formatNumber(totalCompressed)}`);
|
|
124
|
-
console.log(`Total Saved Tokens: ${formatNumber(totalSaved)} (${
|
|
135
|
+
console.log(`Total Saved Tokens: ${formatNumber(totalSaved)} (${totalSavedPct}%)`);
|
|
136
|
+
if (totalNetCoverage > 0) {
|
|
137
|
+
console.log(`Total Overhead Tokens: ${formatNumber(totalOverhead)}`);
|
|
138
|
+
console.log(
|
|
139
|
+
`Total Net Saved Tokens${totalNetCoverage < totalWorkflows ? ` (${formatNumber(totalNetCoverage)}/${formatNumber(totalWorkflows)} workflows)` : ''}: ${formatNumber(totalNetSaved)} (${totalNetSavedPct}%)`,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
125
142
|
console.log(`Total Baseline Tokens: ${formatNumber(totalBaseline)}`);
|
|
126
|
-
console.log(`Savings vs Baseline: ${formatNumber(totalBaseline - totalCompressed)} (${
|
|
143
|
+
console.log(`Savings vs Baseline: ${formatNumber(totalBaseline - totalCompressed)} (${baselineSavingsPct}%)`);
|
|
127
144
|
console.log('');
|
|
128
145
|
console.log('By Workflow Type:');
|
|
129
146
|
console.log('─'.repeat(120));
|
|
@@ -169,6 +186,13 @@ const printSummary = (summary) => {
|
|
|
169
186
|
console.log(` Total Raw Tokens: ${formatNumber(s.total_raw_tokens)}`);
|
|
170
187
|
console.log(` Total Compressed Tokens: ${formatNumber(s.total_compressed_tokens)}`);
|
|
171
188
|
console.log(` Total Saved Tokens: ${formatNumber(s.total_saved_tokens)} (${s.avgSavingsPct}%)`);
|
|
189
|
+
const coveredWorkflows = s.netMetricsCoverage?.coveredWorkflows ?? s.net_metrics_count ?? 0;
|
|
190
|
+
if (coveredWorkflows > 0) {
|
|
191
|
+
console.log(` Total Overhead Tokens: ${formatNumber(s.total_overhead_tokens || 0)}`);
|
|
192
|
+
console.log(
|
|
193
|
+
` Total Net Saved Tokens${coveredWorkflows < s.count ? ` (${formatNumber(coveredWorkflows)}/${formatNumber(s.count)} workflows)` : ''}: ${formatNumber(s.total_net_saved_tokens || 0)}`,
|
|
194
|
+
);
|
|
195
|
+
}
|
|
172
196
|
console.log(` Baseline Tokens: ${formatNumber(s.total_baseline_tokens)}`);
|
|
173
197
|
console.log(` Savings vs Baseline: ${formatNumber(s.total_baseline_tokens - s.total_compressed_tokens)} (${s.avgVsBaselinePct}%)`);
|
|
174
198
|
console.log('');
|
|
@@ -205,6 +229,15 @@ const printWorkflows = (workflows) => {
|
|
|
205
229
|
console.log(` Raw Tokens: ${formatNumber(w.raw_tokens)}`);
|
|
206
230
|
console.log(` Compressed Tokens: ${formatNumber(w.compressed_tokens)}`);
|
|
207
231
|
console.log(` Saved Tokens: ${formatNumber(w.saved_tokens)} (${w.savings_pct}%)`);
|
|
232
|
+
if (w.overheadTokens !== undefined) {
|
|
233
|
+
console.log(` Overhead Tokens: ${formatNumber(w.overheadTokens)}`);
|
|
234
|
+
}
|
|
235
|
+
if (w.netSavedTokens !== undefined) {
|
|
236
|
+
console.log(` Net Saved Tokens: ${formatNumber(w.netSavedTokens)}`);
|
|
237
|
+
}
|
|
238
|
+
if (w.netMetricsCoverage?.available === false) {
|
|
239
|
+
console.log(' Net Metrics Coverage: unavailable');
|
|
240
|
+
}
|
|
208
241
|
console.log(` Baseline Tokens: ${formatNumber(w.baseline_tokens)}`);
|
|
209
242
|
console.log(` Savings vs Baseline: ${formatNumber(w.baseline_tokens - w.compressed_tokens)} (${w.vs_baseline_pct}%)`);
|
|
210
243
|
}
|