refacil-sdd-ai 2.6.0 → 2.7.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/README.md +3 -3
- package/bin/cli.js +48 -12
- package/lib/compact/bash.js +8 -2
- package/lib/compact/rules.js +47 -1
- package/lib/compact/telemetry.js +50 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ refacil-sdd-ai update # Actualizar skills y hooks a la ultima version
|
|
|
56
56
|
refacil-sdd-ai check-update # Verifica si hay una version mas reciente en npm (usado por hook)
|
|
57
57
|
refacil-sdd-ai check-review # Verifica que el review se haya completado (usado por hook)
|
|
58
58
|
refacil-sdd-ai compact-bash # Hook de rewrite de comandos Bash bare (usado por hook, no invocar manual)
|
|
59
|
-
refacil-sdd-ai compact stats #
|
|
59
|
+
refacil-sdd-ai compact stats # Estadisticas completas (hook + ya-compacto) + tokens estimados + USD
|
|
60
60
|
refacil-sdd-ai compact disable # Desactiva el hook compact-bash sin desinstalarlo
|
|
61
61
|
refacil-sdd-ai compact enable # Reactiva el hook compact-bash
|
|
62
62
|
refacil-sdd-ai compact clear-log # Limpia ~/.refacil-sdd-ai/compact.log
|
|
@@ -431,13 +431,13 @@ Fase 2A — linters, type checkers, build, sistema:
|
|
|
431
431
|
**Subcomandos de control**:
|
|
432
432
|
|
|
433
433
|
```bash
|
|
434
|
-
refacil-sdd-ai compact stats #
|
|
434
|
+
refacil-sdd-ai compact stats # estadisticas completas (hook + ya-compacto) + tokens estimados + USD
|
|
435
435
|
refacil-sdd-ai compact disable # desactiva el hook sin desinstalar
|
|
436
436
|
refacil-sdd-ai compact enable # reactiva el hook
|
|
437
437
|
refacil-sdd-ai compact clear-log # limpia ~/.refacil-sdd-ai/compact.log
|
|
438
438
|
```
|
|
439
439
|
|
|
440
|
-
**Telemetria**: cada
|
|
440
|
+
**Telemetria**: cada evento genera una linea JSON en `~/.refacil-sdd-ai/compact.log` con timestamp, ruleId y estimacion de tokens. Hay dos tipos de evento: `hook_rewrite` (el hook reescribe) y `already_compact` (el comando ya llega compacto, asumido por skill/agente). `compact stats` muestra ambos por defecto y calcula costo estimado (a razon de $3/MTok input de Sonnet, conservador). La telemetria es local; nada se envia a la nube.
|
|
441
441
|
|
|
442
442
|
**Flujo del hook**:
|
|
443
443
|
|
package/bin/cli.js
CHANGED
|
@@ -535,29 +535,65 @@ function handleCompactSubcommand(sub) {
|
|
|
535
535
|
|
|
536
536
|
function showCompactStats() {
|
|
537
537
|
const s = compactTelemetry.stats();
|
|
538
|
-
if (s.
|
|
539
|
-
console.log('\n No hay
|
|
538
|
+
if (s.totalEvents === 0) {
|
|
539
|
+
console.log('\n No hay eventos registrados todavia. Ejecuta comandos Bash para generar telemetria de compactacion.\n');
|
|
540
540
|
return;
|
|
541
541
|
}
|
|
542
542
|
|
|
543
|
-
const
|
|
543
|
+
const sortedRewrites = Object.entries(s.byRule)
|
|
544
|
+
.filter(([, data]) => data.rewriteCount > 0)
|
|
545
|
+
.sort((a, b) => b[1].rewriteSaved - a[1].rewriteSaved);
|
|
546
|
+
const sortedAlreadyCompact = Object.entries(s.byRule)
|
|
547
|
+
.filter(([, data]) => data.alreadyCompactCount > 0)
|
|
548
|
+
.sort((a, b) => b[1].alreadyCompactPotential - a[1].alreadyCompactPotential);
|
|
544
549
|
|
|
545
|
-
console.log(`\n compact-bash stats
|
|
546
|
-
|
|
547
|
-
|
|
550
|
+
console.log(`\n compact-bash stats\n`);
|
|
551
|
+
console.log(` Rewrites por hook: ${s.totalRewrites}`);
|
|
552
|
+
console.log(` Comandos ya compactos detectados (skill/agente): ${s.totalAlreadyCompact}\n`);
|
|
553
|
+
|
|
554
|
+
if (sortedRewrites.length > 0) {
|
|
555
|
+
console.log(' Ahorro aplicado por hook (rewrite):');
|
|
556
|
+
for (const [id, data] of sortedRewrites) {
|
|
557
|
+
const kTokens = (data.rewriteSaved / 1000).toFixed(1);
|
|
558
|
+
console.log(
|
|
559
|
+
` ${id.padEnd(18)} ${String(data.rewriteCount).padStart(6)} rewrites ~${kTokens.padStart(7)}k tokens`,
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
const totalHookK = (s.totalSaved / 1000).toFixed(1);
|
|
563
|
+
const hookUsd = ((s.totalSaved / 1_000_000) * 3).toFixed(2);
|
|
564
|
+
console.log(` ${'-'.repeat(62)}`);
|
|
565
|
+
console.log(
|
|
566
|
+
` ${'Total hook'.padEnd(18)} ${String(s.totalRewrites).padStart(6)} rewrites ~${totalHookK.padStart(7)}k tokens (~$${hookUsd} USD)`,
|
|
567
|
+
);
|
|
568
|
+
console.log('');
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (sortedAlreadyCompact.length > 0) {
|
|
572
|
+
console.log(' Ahorro potencial ya capturado por skill/agente (sin rewrite):');
|
|
573
|
+
for (const [id, data] of sortedAlreadyCompact) {
|
|
574
|
+
const kTokens = (data.alreadyCompactPotential / 1000).toFixed(1);
|
|
575
|
+
console.log(
|
|
576
|
+
` ${id.padEnd(18)} ${String(data.alreadyCompactCount).padStart(6)} eventos ~${kTokens.padStart(7)}k tokens potenciales`,
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
const totalAgentK = (s.totalAlreadyCompactPotential / 1000).toFixed(1);
|
|
580
|
+
const agentUsd = ((s.totalAlreadyCompactPotential / 1_000_000) * 3).toFixed(2);
|
|
581
|
+
console.log(` ${'-'.repeat(62)}`);
|
|
548
582
|
console.log(
|
|
549
|
-
` ${
|
|
583
|
+
` ${'Total skill'.padEnd(18)} ${String(s.totalAlreadyCompact).padStart(6)} eventos ~${totalAgentK.padStart(7)}k tokens (~$${agentUsd} USD)`,
|
|
550
584
|
);
|
|
585
|
+
console.log('');
|
|
551
586
|
}
|
|
552
|
-
|
|
553
|
-
const
|
|
587
|
+
|
|
588
|
+
const totalK = (s.totalObservedPotential / 1000).toFixed(1);
|
|
589
|
+
const totalUsd = ((s.totalObservedPotential / 1_000_000) * 3).toFixed(2);
|
|
554
590
|
console.log(` ${'-'.repeat(62)}`);
|
|
555
591
|
console.log(
|
|
556
|
-
` ${'Total'.padEnd(18)} ${String(s.
|
|
592
|
+
` ${'Total observado'.padEnd(18)} ${String(s.totalEvents).padStart(6)} eventos ~${totalK.padStart(7)}k tokens (~$${totalUsd} USD, Sonnet input)`,
|
|
557
593
|
);
|
|
558
594
|
console.log(`\n Log: ${compactTelemetry.LOG_PATH}`);
|
|
559
595
|
if (compactTelemetry.isDisabled()) {
|
|
560
|
-
console.log(' Estado: DESHABILITADO (no se registran nuevos
|
|
596
|
+
console.log(' Estado: DESHABILITADO (no se registran nuevos eventos)');
|
|
561
597
|
}
|
|
562
598
|
console.log('');
|
|
563
599
|
}
|
|
@@ -573,7 +609,7 @@ function help() {
|
|
|
573
609
|
check-review Verifica que el review se haya completado (usado por hook PreToolUse)
|
|
574
610
|
compact-bash Reescribe comandos Bash bare para reducir tokens (usado por hook PreToolUse)
|
|
575
611
|
compact Subcomandos del hook compact-bash:
|
|
576
|
-
compact stats - Estadisticas
|
|
612
|
+
compact stats - Estadisticas completas (hook + ya-compacto) y ahorro estimado
|
|
577
613
|
compact disable - Desactiva el rewrite temporalmente
|
|
578
614
|
compact enable - Re-activa el rewrite
|
|
579
615
|
compact clear-log - Borra el log historico
|
package/lib/compact/bash.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
-
const { findRule } = require('./rules');
|
|
2
|
+
const { findRule, findAlreadyCompactRule } = require('./rules');
|
|
3
3
|
const telemetry = require('./telemetry');
|
|
4
4
|
|
|
5
5
|
function run() {
|
|
@@ -19,7 +19,13 @@ function run() {
|
|
|
19
19
|
if (typeof origCommand !== 'string') return;
|
|
20
20
|
|
|
21
21
|
const rule = findRule(origCommand);
|
|
22
|
-
if (!rule)
|
|
22
|
+
if (!rule) {
|
|
23
|
+
const compactRule = findAlreadyCompactRule(origCommand);
|
|
24
|
+
if (compactRule) {
|
|
25
|
+
telemetry.logAlreadyCompact(compactRule.id, compactRule.savedTokensEst);
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
23
29
|
|
|
24
30
|
let newCommand;
|
|
25
31
|
try {
|
package/lib/compact/rules.js
CHANGED
|
@@ -13,6 +13,9 @@ const RULES = [
|
|
|
13
13
|
id: 'git-log',
|
|
14
14
|
match: (cmd) =>
|
|
15
15
|
/^\s*git\s+log(\s|$)/.test(cmd) && !hasFlagAfterBase(cmd, 2),
|
|
16
|
+
compactMatch: (cmd) =>
|
|
17
|
+
/^\s*git\s+log(\s|$)/.test(cmd) &&
|
|
18
|
+
(/--oneline\b/.test(cmd) || /(^|\s)-\d+\b/.test(cmd)),
|
|
16
19
|
rewrite: (cmd) => cmd.replace(/^(\s*git\s+log)/, '$1 --oneline -20'),
|
|
17
20
|
reason: 'git log → --oneline -20',
|
|
18
21
|
savedTokensEst: 850,
|
|
@@ -21,6 +24,9 @@ const RULES = [
|
|
|
21
24
|
id: 'git-status',
|
|
22
25
|
match: (cmd) =>
|
|
23
26
|
/^\s*git\s+status(\s|$)/.test(cmd) && !hasFlagAfterBase(cmd, 2),
|
|
27
|
+
compactMatch: (cmd) =>
|
|
28
|
+
/^\s*git\s+status(\s|$)/.test(cmd) &&
|
|
29
|
+
(/\s-s(\s|$)/.test(cmd) || /--short\b/.test(cmd)),
|
|
24
30
|
rewrite: (cmd) => cmd.replace(/^(\s*git\s+status)/, '$1 -s'),
|
|
25
31
|
reason: 'git status → -s',
|
|
26
32
|
savedTokensEst: 120,
|
|
@@ -28,6 +34,7 @@ const RULES = [
|
|
|
28
34
|
{
|
|
29
35
|
id: 'git-diff',
|
|
30
36
|
match: (cmd) => /^\s*git\s+diff\s*$/.test(cmd),
|
|
37
|
+
compactMatch: (cmd) => /^\s*git\s+diff(\s|$)/.test(cmd) && /--stat\b/.test(cmd),
|
|
31
38
|
rewrite: (cmd) => cmd.replace(/^(\s*git\s+diff)\s*$/, '$1 --stat'),
|
|
32
39
|
reason: 'git diff → --stat',
|
|
33
40
|
savedTokensEst: 400,
|
|
@@ -36,6 +43,7 @@ const RULES = [
|
|
|
36
43
|
id: 'git-show',
|
|
37
44
|
match: (cmd) =>
|
|
38
45
|
/^\s*git\s+show(\s|$)/.test(cmd) && !hasFlagAfterBase(cmd, 2),
|
|
46
|
+
compactMatch: (cmd) => /^\s*git\s+show(\s|$)/.test(cmd) && /--stat\b/.test(cmd),
|
|
39
47
|
rewrite: (cmd) => cmd.replace(/^(\s*git\s+show)/, '$1 --stat'),
|
|
40
48
|
reason: 'git show → --stat',
|
|
41
49
|
savedTokensEst: 200,
|
|
@@ -49,6 +57,9 @@ const RULES = [
|
|
|
49
57
|
if (/\s--since\b/.test(cmd)) return false;
|
|
50
58
|
return true;
|
|
51
59
|
},
|
|
60
|
+
compactMatch: (cmd) =>
|
|
61
|
+
/^\s*docker\s+logs(\s|$)/.test(cmd) &&
|
|
62
|
+
(/\s--tail\b/.test(cmd) || /\s-n\s+\d/.test(cmd) || /\s--since\b/.test(cmd)),
|
|
52
63
|
rewrite: (cmd) => cmd.replace(/^(\s*docker\s+logs)/, '$1 --tail 100'),
|
|
53
64
|
reason: 'docker logs → --tail 100',
|
|
54
65
|
savedTokensEst: 1500,
|
|
@@ -56,6 +67,9 @@ const RULES = [
|
|
|
56
67
|
{
|
|
57
68
|
id: 'pkg-test',
|
|
58
69
|
match: (cmd) => /^\s*(npm|yarn|pnpm)\s+(test|t)\s*$/.test(cmd),
|
|
70
|
+
compactMatch: (cmd) =>
|
|
71
|
+
/^\s*(npm|yarn|pnpm)\s+(test|t)\b/.test(cmd) &&
|
|
72
|
+
(hasPipeOrRedirect(cmd) || /--silent\b/.test(cmd) || /\b-q\b/.test(cmd)),
|
|
59
73
|
rewrite: (cmd) => `${cmd.trim()} 2>&1 | tail -80`,
|
|
60
74
|
reason: 'test bare → tail -80',
|
|
61
75
|
savedTokensEst: 2400,
|
|
@@ -63,6 +77,9 @@ const RULES = [
|
|
|
63
77
|
{
|
|
64
78
|
id: 'jest-bare',
|
|
65
79
|
match: (cmd) => /^\s*(npx\s+)?jest\s*$/.test(cmd),
|
|
80
|
+
compactMatch: (cmd) =>
|
|
81
|
+
/^\s*(npx\s+)?jest(\s|$)/.test(cmd) &&
|
|
82
|
+
(/--silent\b/.test(cmd) || /--reporters=summary\b/.test(cmd)),
|
|
66
83
|
rewrite: (cmd) =>
|
|
67
84
|
cmd.replace(/^(\s*(?:npx\s+)?jest)\s*$/, '$1 --silent --reporters=summary'),
|
|
68
85
|
reason: 'jest → silent summary',
|
|
@@ -71,6 +88,7 @@ const RULES = [
|
|
|
71
88
|
{
|
|
72
89
|
id: 'pytest-bare',
|
|
73
90
|
match: (cmd) => /^\s*pytest\s*$/.test(cmd),
|
|
91
|
+
compactMatch: (cmd) => /^\s*pytest(\s|$)/.test(cmd) && /(^|\s)-q(\s|$)/.test(cmd),
|
|
74
92
|
rewrite: (cmd) => cmd.replace(/^(\s*pytest)\s*$/, '$1 -q'),
|
|
75
93
|
reason: 'pytest → -q',
|
|
76
94
|
savedTokensEst: 600,
|
|
@@ -79,6 +97,9 @@ const RULES = [
|
|
|
79
97
|
{
|
|
80
98
|
id: 'eslint',
|
|
81
99
|
match: (cmd) => /^\s*eslint(\s+[^-]\S*)*\s*$/.test(cmd),
|
|
100
|
+
compactMatch: (cmd) =>
|
|
101
|
+
/^\s*eslint(\s|$)/.test(cmd) &&
|
|
102
|
+
(/--format\s+compact\b/.test(cmd) || /--quiet\b/.test(cmd)),
|
|
82
103
|
rewrite: (cmd) => {
|
|
83
104
|
const tokens = cmd.trim().split(/\s+/);
|
|
84
105
|
if (tokens.length === 1) {
|
|
@@ -93,6 +114,8 @@ const RULES = [
|
|
|
93
114
|
id: 'biome-check',
|
|
94
115
|
match: (cmd) =>
|
|
95
116
|
/^\s*biome\s+check(\s|$)/.test(cmd) && !/--reporter\b/.test(cmd),
|
|
117
|
+
compactMatch: (cmd) =>
|
|
118
|
+
/^\s*biome\s+check(\s|$)/.test(cmd) && /--reporter=summary\b/.test(cmd),
|
|
96
119
|
rewrite: (cmd) =>
|
|
97
120
|
cmd.replace(/^(\s*biome\s+check)/, '$1 --reporter=summary'),
|
|
98
121
|
reason: 'biome check → --reporter=summary',
|
|
@@ -106,6 +129,8 @@ const RULES = [
|
|
|
106
129
|
if (hasPipeOrRedirect(cmd)) return false;
|
|
107
130
|
return true;
|
|
108
131
|
},
|
|
132
|
+
compactMatch: (cmd) =>
|
|
133
|
+
/^\s*(npx\s+)?tsc(\s|$)/.test(cmd) && hasPipeOrRedirect(cmd),
|
|
109
134
|
rewrite: (cmd) => `${cmd.trim()} 2>&1 | head -80`,
|
|
110
135
|
reason: 'tsc → head -80',
|
|
111
136
|
savedTokensEst: 1200,
|
|
@@ -114,6 +139,8 @@ const RULES = [
|
|
|
114
139
|
id: 'prettier-check',
|
|
115
140
|
match: (cmd) =>
|
|
116
141
|
/^\s*prettier\s+--check\b/.test(cmd) && !/--loglevel\b/.test(cmd),
|
|
142
|
+
compactMatch: (cmd) =>
|
|
143
|
+
/^\s*prettier\s+--check\b/.test(cmd) && /--loglevel\b/.test(cmd),
|
|
117
144
|
rewrite: (cmd) =>
|
|
118
145
|
cmd.replace(/^(\s*prettier\s+--check)/, '$1 --loglevel warn'),
|
|
119
146
|
reason: 'prettier --check → --loglevel warn',
|
|
@@ -122,6 +149,7 @@ const RULES = [
|
|
|
122
149
|
{
|
|
123
150
|
id: 'npm-audit',
|
|
124
151
|
match: (cmd) => /^\s*npm\s+audit\s*$/.test(cmd),
|
|
152
|
+
compactMatch: (cmd) => /^\s*npm\s+audit(\s|$)/.test(cmd) && hasPipeOrRedirect(cmd),
|
|
125
153
|
rewrite: (cmd) => `${cmd.trim()} 2>&1 | tail -10`,
|
|
126
154
|
reason: 'npm audit → tail -10',
|
|
127
155
|
savedTokensEst: 900,
|
|
@@ -129,6 +157,7 @@ const RULES = [
|
|
|
129
157
|
{
|
|
130
158
|
id: 'npm-ls',
|
|
131
159
|
match: (cmd) => /^\s*npm\s+ls\s*$/.test(cmd),
|
|
160
|
+
compactMatch: (cmd) => /^\s*npm\s+ls(\s|$)/.test(cmd) && /--depth=0\b/.test(cmd),
|
|
132
161
|
rewrite: (cmd) => cmd.replace(/^(\s*npm\s+ls)/, '$1 --depth=0'),
|
|
133
162
|
reason: 'npm ls → --depth=0',
|
|
134
163
|
savedTokensEst: 700,
|
|
@@ -136,6 +165,8 @@ const RULES = [
|
|
|
136
165
|
{
|
|
137
166
|
id: 'cargo-bare',
|
|
138
167
|
match: (cmd) => /^\s*cargo\s+(build|test|check)\s*$/.test(cmd),
|
|
168
|
+
compactMatch: (cmd) =>
|
|
169
|
+
/^\s*cargo\s+(build|test|check)(\s|$)/.test(cmd) && /--quiet\b/.test(cmd),
|
|
139
170
|
rewrite: (cmd) => `${cmd.trim()} --quiet`,
|
|
140
171
|
reason: 'cargo → --quiet',
|
|
141
172
|
savedTokensEst: 400,
|
|
@@ -149,6 +180,7 @@ const RULES = [
|
|
|
149
180
|
if (hasPipeOrRedirect(cmd)) return false;
|
|
150
181
|
return true;
|
|
151
182
|
},
|
|
183
|
+
compactMatch: (cmd) => /^\s*go\s+test(\s|$)/.test(cmd) && hasPipeOrRedirect(cmd),
|
|
152
184
|
rewrite: (cmd) => `${cmd.trim()} 2>&1 | tail -80`,
|
|
153
185
|
reason: 'go test → tail -80',
|
|
154
186
|
savedTokensEst: 1500,
|
|
@@ -156,6 +188,7 @@ const RULES = [
|
|
|
156
188
|
{
|
|
157
189
|
id: 'mvn-test',
|
|
158
190
|
match: (cmd) => /^\s*mvn\s+test\s*$/.test(cmd),
|
|
191
|
+
compactMatch: (cmd) => /^\s*mvn\s+test(\s|$)/.test(cmd) && /(^|\s)-q(\s|$)/.test(cmd),
|
|
159
192
|
rewrite: (cmd) => `${cmd.trim()} -q`,
|
|
160
193
|
reason: 'mvn test → -q',
|
|
161
194
|
savedTokensEst: 1800,
|
|
@@ -163,6 +196,9 @@ const RULES = [
|
|
|
163
196
|
{
|
|
164
197
|
id: 'gradle-test',
|
|
165
198
|
match: (cmd) => /^\s*(\.\/gradlew|gradle)\s+test\s*$/.test(cmd),
|
|
199
|
+
compactMatch: (cmd) =>
|
|
200
|
+
/^\s*(\.\/gradlew|gradle)\s+test(\s|$)/.test(cmd) &&
|
|
201
|
+
/(^|\s)-q(\s|$)/.test(cmd),
|
|
166
202
|
rewrite: (cmd) => `${cmd.trim()} -q`,
|
|
167
203
|
reason: 'gradle test → -q',
|
|
168
204
|
savedTokensEst: 1500,
|
|
@@ -187,4 +223,14 @@ function findRule(cmd) {
|
|
|
187
223
|
return null;
|
|
188
224
|
}
|
|
189
225
|
|
|
190
|
-
|
|
226
|
+
function findAlreadyCompactRule(cmd) {
|
|
227
|
+
if (typeof cmd !== 'string' || !cmd.trim()) return null;
|
|
228
|
+
for (const rule of RULES) {
|
|
229
|
+
if (typeof rule.compactMatch === 'function' && rule.compactMatch(cmd)) {
|
|
230
|
+
return rule;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
module.exports = { RULES, findRule, findAlreadyCompactRule };
|
package/lib/compact/telemetry.js
CHANGED
|
@@ -16,14 +16,16 @@ function isDisabled() {
|
|
|
16
16
|
return fs.existsSync(DISABLED_PATH);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
function
|
|
19
|
+
function logEvent(eventType, ruleId, savedTokensEst, meta = {}) {
|
|
20
20
|
try {
|
|
21
21
|
ensureDir();
|
|
22
22
|
const line =
|
|
23
23
|
JSON.stringify({
|
|
24
24
|
ts: new Date().toISOString(),
|
|
25
|
+
eventType: eventType || 'hook_rewrite',
|
|
25
26
|
ruleId,
|
|
26
27
|
savedTokensEst: savedTokensEst || 0,
|
|
28
|
+
...meta,
|
|
27
29
|
}) + '\n';
|
|
28
30
|
fs.appendFileSync(LOG_PATH, line);
|
|
29
31
|
} catch (_) {
|
|
@@ -31,6 +33,17 @@ function logRewrite(ruleId, savedTokensEst) {
|
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
|
|
36
|
+
function logRewrite(ruleId, savedTokensEst) {
|
|
37
|
+
logEvent('hook_rewrite', ruleId, savedTokensEst);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function logAlreadyCompact(ruleId, savedTokensEst) {
|
|
41
|
+
// Assumption: command arrived compact due to skills/agent discipline.
|
|
42
|
+
logEvent('already_compact', ruleId, savedTokensEst, {
|
|
43
|
+
source: 'skill_assumed',
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
34
47
|
function readLog() {
|
|
35
48
|
try {
|
|
36
49
|
const content = fs.readFileSync(LOG_PATH, 'utf8');
|
|
@@ -54,13 +67,43 @@ function stats() {
|
|
|
54
67
|
const entries = readLog();
|
|
55
68
|
const byRule = {};
|
|
56
69
|
let totalSaved = 0;
|
|
70
|
+
let totalAlreadyCompactPotential = 0;
|
|
71
|
+
let totalAlreadyCompact = 0;
|
|
72
|
+
let totalRewrites = 0;
|
|
73
|
+
|
|
57
74
|
for (const e of entries) {
|
|
58
|
-
|
|
59
|
-
byRule[e.ruleId]
|
|
60
|
-
|
|
61
|
-
|
|
75
|
+
const eventType = e.eventType || 'hook_rewrite';
|
|
76
|
+
if (!byRule[e.ruleId]) {
|
|
77
|
+
byRule[e.ruleId] = {
|
|
78
|
+
rewriteCount: 0,
|
|
79
|
+
rewriteSaved: 0,
|
|
80
|
+
alreadyCompactCount: 0,
|
|
81
|
+
alreadyCompactPotential: 0,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (eventType === 'already_compact') {
|
|
86
|
+
byRule[e.ruleId].alreadyCompactCount++;
|
|
87
|
+
byRule[e.ruleId].alreadyCompactPotential += e.savedTokensEst || 0;
|
|
88
|
+
totalAlreadyCompact++;
|
|
89
|
+
totalAlreadyCompactPotential += e.savedTokensEst || 0;
|
|
90
|
+
} else {
|
|
91
|
+
byRule[e.ruleId].rewriteCount++;
|
|
92
|
+
byRule[e.ruleId].rewriteSaved += e.savedTokensEst || 0;
|
|
93
|
+
totalRewrites++;
|
|
94
|
+
totalSaved += e.savedTokensEst || 0;
|
|
95
|
+
}
|
|
62
96
|
}
|
|
63
|
-
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
byRule,
|
|
100
|
+
totalSaved,
|
|
101
|
+
totalRewrites,
|
|
102
|
+
totalAlreadyCompact,
|
|
103
|
+
totalAlreadyCompactPotential,
|
|
104
|
+
totalObservedPotential: totalSaved + totalAlreadyCompactPotential,
|
|
105
|
+
totalEvents: entries.length,
|
|
106
|
+
};
|
|
64
107
|
}
|
|
65
108
|
|
|
66
109
|
function disable() {
|
|
@@ -86,6 +129,7 @@ module.exports = {
|
|
|
86
129
|
DISABLED_PATH,
|
|
87
130
|
isDisabled,
|
|
88
131
|
logRewrite,
|
|
132
|
+
logAlreadyCompact,
|
|
89
133
|
stats,
|
|
90
134
|
disable,
|
|
91
135
|
enable,
|
package/package.json
CHANGED