kodelyth-ecc 1.8.6 → 1.9.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/CHANGELOG.md +42 -0
- package/agents/kodelyth-memory.md +1 -1
- package/bin/kodelyth-ecc.js +115 -0
- package/commands/memory-evolve.md +2 -2
- package/commands/memory.md +2 -2
- package/commands/route-model.md +2 -2
- package/commands/update.md +2 -2
- package/package.json +1 -1
- package/rules/common/cost-aware-model-routing.md +2 -2
- package/rules/common/memory-protocol.md +2 -2
- package/rules/common/self-improvement-workflow.md +1 -1
- package/scripts/dashboard/server.js +19 -0
- package/scripts/dashboard/static/index.html +89 -0
- package/scripts/rtk/index.js +186 -0
- package/skills/cost-aware-model-routing/SKILL.md +1 -1
- package/skills/kodelyth-memory/SKILL.md +4 -4
- package/skills/self-evolving-memory/SKILL.md +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to Kodelyth ECC are documented here.
|
|
4
4
|
|
|
5
|
+
## v1.9.1 — Smoothness pass on RTK integration (July 2026)
|
|
6
|
+
|
|
7
|
+
Follow-up polish on 1.9.0. Cleaner output, agents now say the right paths, one-shot multi-IDE RTK setup.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `rtk init --codex/--gemini/--opencode/--agent X` rejected `--auto-patch` and silently failed. `enableFor()` now only passes `--auto-patch` to the default Claude Code hook flow, where RTK accepts it. Multi-IDE enable now succeeds 3/3 instead of 2/3
|
|
12
|
+
- 24 memory-path references across 11 agent/skill/rule/command markdown files still said `~/.kodelyth/` — agents were teaching users the wrong path. Now all say `~/.kodelythecc/` (matches the 1.8.6 runtime rename)
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- `kodelyth-ecc rtk enable --all` — auto-detects every IDE ECC has been installed for on this machine (checks `~/.claude/agents`, `~/.cursor/rules`, `~/.codeium/windsurf`, `~/.antigravity`, `~/.codex`, `~/.config/opencode`, `~/.gemini`) and wires RTK into all of them in one command
|
|
17
|
+
- `scripts/rtk/index.js` — `detectInstalledTargets()` export
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Post-install output: replaced the raw JSON dumps with a tight 3-line summary (RTK version, target IDE, next step)
|
|
22
|
+
- `kodelyth-ecc rtk status`: human-readable by default (was JSON); use `--json` for machine output. Now also lists detected ECC-installed IDEs so you can see which ones `--all` will wire
|
|
23
|
+
|
|
24
|
+
## v1.9.0 — RTK integration + revived dashboard (July 2026)
|
|
25
|
+
|
|
26
|
+
ECC now auto-installs [RTK](https://github.com/rtk-ai/rtk) (Rust Token Killer) and wires its transparent command filter into whichever IDE ECC was installed for. Real token savings (60-90% on shell commands) show up in the dashboard, pulled straight from RTK's own ledger — no synthetic numbers.
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- `scripts/rtk/index.js` — RTK integration module: `install()`, `enableFor(target)`, `disableFor(target)`, `status()`, `savings()`
|
|
31
|
+
- `kodelyth-ecc rtk <install|enable|disable|status|gain>` — CLI subcommands to manage RTK from ECC
|
|
32
|
+
- Post-install auto-hook: after `npx kodelyth-ecc --target <ide>` succeeds, ECC auto-installs the RTK binary (Homebrew on macOS, curl script elsewhere) and runs `rtk init` for the target IDE. Opt out with `--no-rtk`
|
|
33
|
+
- Target map covers 10 install targets: `claude-code`, `cursor`, `cursor-project`, `windsurf-home`, `windsurf-project`, `antigravity`, `codex-home`, `opencode`, `cline`, `gemini-cli`
|
|
34
|
+
- `/api/rtk` + `/api/rtk/status` dashboard endpoints — surface RTK's live ledger
|
|
35
|
+
- New **RTK Savings** tab in the dashboard: total tokens saved, raw tokens seen, avg reduction %, active IDE integrations, 30-day daily bar chart
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Dashboard nav order: `Overview → RTK Savings → Memory → Evolve → Catalog → Sessions`
|
|
40
|
+
|
|
41
|
+
### Notes
|
|
42
|
+
|
|
43
|
+
- Windows auto-install is skipped (RTK requires manual .zip download on native Windows); WSL follows the Linux path
|
|
44
|
+
- RTK setup is best-effort — if brew/curl aren't available, install fails gracefully with a hint to run `kodelyth-ecc rtk install` later
|
|
45
|
+
- Existing RTK installs are detected and reused; no double-install
|
|
46
|
+
|
|
5
47
|
## v1.8.6 — Memory path rename + auto-migration (July 2026)
|
|
6
48
|
|
|
7
49
|
Renamed the on-disk memory root from `~/.kodelyth/` to `~/.kodelythecc/` across every runtime path. Existing installs auto-migrate on first CLI invocation or hook fire — idempotent, non-destructive, keeps a dated backup of the old directory.
|
|
@@ -72,7 +72,7 @@ Anthropic's prompt cache (5-min TTL, 10% cost on hits) and OpenAI's automatic ca
|
|
|
72
72
|
## Honest limits
|
|
73
73
|
|
|
74
74
|
- Retrieval is **BM25 keyword + tag matching**, not semantic. It finds memories that share vocabulary with the query. It will miss semantic matches with no shared words.
|
|
75
|
-
- Memory is **per-machine**. Sync across machines requires the user opting in (Dropbox/iCloud/git on `~/.
|
|
75
|
+
- Memory is **per-machine**. Sync across machines requires the user opting in (Dropbox/iCloud/git on `~/.kodelythecc/memory/`).
|
|
76
76
|
- On cloud-AI platforms (Windsurf, Antigravity), session data is server-side. Memory still works for capture (manual `/memory remember`) but auto-extract from past sessions is unavailable there.
|
|
77
77
|
|
|
78
78
|
## Example interaction
|
package/bin/kodelyth-ecc.js
CHANGED
|
@@ -177,6 +177,89 @@ if (args[0] && args[0].startsWith('mcp-')) {
|
|
|
177
177
|
return;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
// ── Subcommand: rtk (Rust Token Killer integration) ──────────────────────────
|
|
181
|
+
// Usage:
|
|
182
|
+
// kodelyth-ecc rtk install install rtk binary (brew or curl)
|
|
183
|
+
// kodelyth-ecc rtk enable [--target X] wire rtk into an IDE (default: claude-code)
|
|
184
|
+
// kodelyth-ecc rtk disable [--target X] remove rtk hook from an IDE
|
|
185
|
+
// kodelyth-ecc rtk status show binary version + active integrations
|
|
186
|
+
// kodelyth-ecc rtk gain thin wrapper around `rtk gain`
|
|
187
|
+
if (args[0] === 'rtk') {
|
|
188
|
+
const rtk = require(path.join(ROOT, 'scripts', 'rtk', 'index.js'));
|
|
189
|
+
const sub = args[1] || 'status';
|
|
190
|
+
const rest = args.slice(2);
|
|
191
|
+
function flag(name, dflt) {
|
|
192
|
+
const i = rest.indexOf(name);
|
|
193
|
+
return i >= 0 && rest[i + 1] ? rest[i + 1] : dflt;
|
|
194
|
+
}
|
|
195
|
+
const log = (m) => process.stdout.write(m + '\n');
|
|
196
|
+
try {
|
|
197
|
+
if (sub === 'install') {
|
|
198
|
+
const r = rtk.install({ log });
|
|
199
|
+
log(JSON.stringify(r, null, 2));
|
|
200
|
+
process.exit(r.installed || r.skipped ? 0 : 1);
|
|
201
|
+
}
|
|
202
|
+
if (sub === 'enable') {
|
|
203
|
+
// --all mode: wire RTK into every IDE that already has ECC installed.
|
|
204
|
+
if (rest.includes('--all')) {
|
|
205
|
+
rtk.install({ log });
|
|
206
|
+
if (!rtk.isInstalled()) { process.stderr.write('rtk install failed — cannot enable\n'); process.exit(1); }
|
|
207
|
+
const targets = rtk.detectInstalledTargets();
|
|
208
|
+
if (targets.length === 0) {
|
|
209
|
+
log('No IDE installs detected. Install ECC first: npx kodelyth-ecc --target claude-code');
|
|
210
|
+
process.exit(0);
|
|
211
|
+
}
|
|
212
|
+
let ok = 0, fail = 0;
|
|
213
|
+
for (const t of targets) {
|
|
214
|
+
const r = rtk.enableFor(t, { log: () => {} });
|
|
215
|
+
if (r.enabled) { log(` ✓ ${t}`); ok++; } else { log(` · ${t} — ${r.reason || 'skipped'}`); fail++; }
|
|
216
|
+
}
|
|
217
|
+
log(`\nRTK enabled on ${ok}/${targets.length} IDE${targets.length === 1 ? '' : 's'}. Restart each to activate.`);
|
|
218
|
+
process.exit(fail && !ok ? 1 : 0);
|
|
219
|
+
}
|
|
220
|
+
const target = flag('--target', 'claude-code');
|
|
221
|
+
const inst = rtk.install({ log });
|
|
222
|
+
if (!rtk.isInstalled()) { log(JSON.stringify(inst, null, 2)); process.exit(1); }
|
|
223
|
+
const r = rtk.enableFor(target, { log });
|
|
224
|
+
log(JSON.stringify(r, null, 2));
|
|
225
|
+
process.exit(r.enabled ? 0 : 1);
|
|
226
|
+
}
|
|
227
|
+
if (sub === 'disable') {
|
|
228
|
+
const target = flag('--target', 'claude-code');
|
|
229
|
+
const r = rtk.disableFor(target, { log });
|
|
230
|
+
log(JSON.stringify(r, null, 2));
|
|
231
|
+
process.exit(r.disabled ? 0 : 1);
|
|
232
|
+
}
|
|
233
|
+
if (sub === 'status') {
|
|
234
|
+
const st = rtk.status();
|
|
235
|
+
if (rest.includes('--json')) { log(JSON.stringify(st, null, 2)); process.exit(0); }
|
|
236
|
+
if (!st.installed) {
|
|
237
|
+
log('RTK: not installed');
|
|
238
|
+
log(' → install: kodelyth-ecc rtk install');
|
|
239
|
+
process.exit(0);
|
|
240
|
+
}
|
|
241
|
+
log(`RTK: ${st.version}`);
|
|
242
|
+
const ecc = rtk.detectInstalledTargets();
|
|
243
|
+
log(`ECC-installed IDEs: ${ecc.length ? ecc.join(', ') : 'none detected'}`);
|
|
244
|
+
log('RTK integrations:');
|
|
245
|
+
for (const line of st.active) log(' ' + line);
|
|
246
|
+
log('');
|
|
247
|
+
log('Commands: install | enable [--target X | --all] | disable | gain | status --json');
|
|
248
|
+
process.exit(0);
|
|
249
|
+
}
|
|
250
|
+
if (sub === 'gain') {
|
|
251
|
+
const r = spawnSync('rtk', ['gain', ...rest], { stdio: 'inherit' });
|
|
252
|
+
process.exit(r.status ?? 1);
|
|
253
|
+
}
|
|
254
|
+
process.stderr.write('unknown rtk subcommand. try: install | enable | disable | status | gain\n');
|
|
255
|
+
process.exit(2);
|
|
256
|
+
} catch (e) {
|
|
257
|
+
process.stderr.write(`[rtk] ${e.message}\n`);
|
|
258
|
+
process.exit(1);
|
|
259
|
+
}
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
180
263
|
// ── Subcommand: route (cost-aware model tier recommendation) ──────────────────
|
|
181
264
|
// Usage: npx kodelyth-ecc route "<task description>" [--files N] [--agent <name>] [--current <model-id>]
|
|
182
265
|
if (args[0] === 'route') {
|
|
@@ -1023,5 +1106,37 @@ if (isWin) {
|
|
|
1023
1106
|
}
|
|
1024
1107
|
fs.chmodSync(sh, 0o755);
|
|
1025
1108
|
const result = spawnSync('bash', [sh, ...args], { stdio: 'inherit', shell: false });
|
|
1109
|
+
|
|
1110
|
+
// Post-install: auto-install + wire RTK for the target IDE (opt-out via --no-rtk).
|
|
1111
|
+
if (result.status === 0 && !args.includes('--no-rtk')) {
|
|
1112
|
+
try {
|
|
1113
|
+
const rtk = require(path.join(ROOT, 'scripts', 'rtk', 'index.js'));
|
|
1114
|
+
const targetIdx = args.indexOf('--target');
|
|
1115
|
+
const target = targetIdx >= 0 && args[targetIdx + 1] ? args[targetIdx + 1] : 'claude-code';
|
|
1116
|
+
if (rtk.TARGET_MAP[target]) {
|
|
1117
|
+
const w = (m) => process.stdout.write(m + '\n');
|
|
1118
|
+
w('');
|
|
1119
|
+
w('━ RTK token savings ' + '─'.repeat(41));
|
|
1120
|
+
const inst = rtk.install({ log: () => {} }); // silent — we summarise
|
|
1121
|
+
if (inst.installed || inst.reason === 'already installed') {
|
|
1122
|
+
const en = rtk.enableFor(target, { log: () => {} });
|
|
1123
|
+
if (en.enabled) {
|
|
1124
|
+
w(` ✓ RTK ${(rtk.getVersion() || '').replace(/^rtk /,'')} — wired for ${target}`);
|
|
1125
|
+
w(` ✓ Restart your AI tool to activate. 60-90% token savings on shell commands.`);
|
|
1126
|
+
} else {
|
|
1127
|
+
w(` · skipped: ${en.reason}`);
|
|
1128
|
+
w(` → retry: kodelyth-ecc rtk enable --target ${target}`);
|
|
1129
|
+
}
|
|
1130
|
+
} else {
|
|
1131
|
+
w(` · install skipped: ${inst.reason}`);
|
|
1132
|
+
w(` → retry: kodelyth-ecc rtk enable --target ${target}`);
|
|
1133
|
+
}
|
|
1134
|
+
w('');
|
|
1135
|
+
}
|
|
1136
|
+
} catch (e) {
|
|
1137
|
+
process.stderr.write(`[rtk] setup skipped: ${e.message}\n`);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1026
1141
|
process.exit(result.status ?? 1);
|
|
1027
1142
|
}
|
|
@@ -24,7 +24,7 @@ Run the self-evolving memory loop. Inspect what ECC has learned from your sessio
|
|
|
24
24
|
1. **stats** prints the current signal snapshot:
|
|
25
25
|
- reuse: how many memories are tracked, total surfaces, top reused
|
|
26
26
|
- routing misses: how many substantive prompts had zero memory matches, top token clusters
|
|
27
|
-
2. **analyze** applies thresholds and writes proposals to `~/.
|
|
27
|
+
2. **analyze** applies thresholds and writes proposals to `~/.kodelythecc/evolve/proposals.jsonl`. Stable IDs — re-running does NOT duplicate.
|
|
28
28
|
3. **list** filters by state. **show** prints the full draft markdown + evidence.
|
|
29
29
|
4. **accept** writes the draft to its target path under `--root` (defaults to package root). Refuses to overwrite without `--overwrite`. Marks the proposal `accepted` with the absolute path.
|
|
30
30
|
5. **reject** marks a proposal rejected with optional note.
|
|
@@ -63,7 +63,7 @@ Run the self-evolving memory loop. Inspect what ECC has learned from your sessio
|
|
|
63
63
|
|
|
64
64
|
Backed by:
|
|
65
65
|
|
|
66
|
-
- `scripts/evolve/stats.js` — pure record/read of `~/.
|
|
66
|
+
- `scripts/evolve/stats.js` — pure record/read of `~/.kodelythecc/evolve/{reuse.json, routing-misses.jsonl}`
|
|
67
67
|
- `scripts/evolve/analyze.js` — pure functions: signals → proposals
|
|
68
68
|
- `scripts/evolve/proposals.js` — append-only proposal log with state transitions
|
|
69
69
|
- `hooks/memory/auto-recall.js` — fire-and-forget signal recording on every UserPromptSubmit
|
package/commands/memory.md
CHANGED
|
@@ -30,7 +30,7 @@ Capture a new memory. The agent will:
|
|
|
30
30
|
Show the queue of candidate memories extracted automatically by the Stop hook from your last session. Confirm each one to store, or skip.
|
|
31
31
|
|
|
32
32
|
### `/memory forget <id>`
|
|
33
|
-
Mark a memory deleted. It's a soft-delete (the row stays in the log marked `deleted: true`) so you can recover it by editing `~/.
|
|
33
|
+
Mark a memory deleted. It's a soft-delete (the row stays in the log marked `deleted: true`) so you can recover it by editing `~/.kodelythecc/memory/memories.jsonl`.
|
|
34
34
|
|
|
35
35
|
### `/memory list`
|
|
36
36
|
Show all stored memories — id, date, language, problem, tags.
|
|
@@ -55,7 +55,7 @@ use kodelyth-memory
|
|
|
55
55
|
|
|
56
56
|
## Storage location
|
|
57
57
|
|
|
58
|
-
`~/.
|
|
58
|
+
`~/.kodelythecc/memory/` (override with `KODELYTH_MEMORY_DIR` env var)
|
|
59
59
|
|
|
60
60
|
- `memories.jsonl` — the source of truth
|
|
61
61
|
- `index.json` — BM25 inverted index
|
package/commands/route-model.md
CHANGED
|
@@ -5,7 +5,7 @@ argument-hint: "[task description]"
|
|
|
5
5
|
|
|
6
6
|
# /route-model
|
|
7
7
|
|
|
8
|
-
Get an immediate model-tier recommendation for the current task. Combines the `cost-aware-model-routing` rule, the project's `.
|
|
8
|
+
Get an immediate model-tier recommendation for the current task. Combines the `cost-aware-model-routing` rule, the project's `.kodelythecc/router.json` config, and the active session's token-budget pressure.
|
|
9
9
|
|
|
10
10
|
## Usage
|
|
11
11
|
|
|
@@ -33,7 +33,7 @@ If you're already on the right tier, the AI routes silently and confirms in one
|
|
|
33
33
|
## Behind the scenes
|
|
34
34
|
|
|
35
35
|
- Pure deterministic classifier (no LLM call) at `scripts/router/classify.js`.
|
|
36
|
-
- Project config: `.
|
|
36
|
+
- Project config: `.kodelythecc/router.json` (override per team).
|
|
37
37
|
- Env-var overrides: `KODELYTH_ROUTER_{TRIVIAL,STANDARD,HARD,DEFAULT}`.
|
|
38
38
|
- Disable with `KODELYTH_ROUTER=off`.
|
|
39
39
|
- Pairs with the `token-budget` safety hook for spend control.
|
package/commands/update.md
CHANGED
|
@@ -17,7 +17,7 @@ Upgrades your ECC install to the latest version from npm. Reads your existing in
|
|
|
17
17
|
1. Reads `kodelyth-ecc-install-state.json` from your install directory to recover the original `target` and `languages`
|
|
18
18
|
2. Runs `npx kodelyth-ecc@latest` with those same flags
|
|
19
19
|
3. Overwrites agents, skills, rules, and commands with the latest versions
|
|
20
|
-
4. Leaves your memory store (`~/.
|
|
20
|
+
4. Leaves your memory store (`~/.kodelythecc/memory/`) and `tasks/lessons.md` untouched — your learned context is never overwritten
|
|
21
21
|
|
|
22
22
|
## Implementation
|
|
23
23
|
|
|
@@ -76,7 +76,7 @@ npx kodelyth-ecc@latest --target cursor-project # Cursor
|
|
|
76
76
|
|
|
77
77
|
| Path | Protected |
|
|
78
78
|
|------|-----------|
|
|
79
|
-
| `~/.
|
|
79
|
+
| `~/.kodelythecc/memory/` | Your BM25 memory store |
|
|
80
80
|
| `tasks/lessons.md` | Project correction rules |
|
|
81
81
|
| `tasks/todo.md` | Open todos |
|
|
82
82
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kodelyth-ecc",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.1",
|
|
4
4
|
"description": "Production-grade AI coding toolkit — 70 agents (incl. devil-mode adversarial crew), 194 skills, 97 commands, parallel multi-agent commands, semantic intent routing, self-learning memory, and a built-in MCP server (16 tools / 6 prompts / 377 resources) that bridges to Claude Desktop, LangGraph, AutoGen, CrewAI, and OpenAI Agents SDK. Works with Claude Code, Windsurf, Cursor, Codex, Antigravity, OpenCode, Cline, RooCode, Aider, Kimi, and Gemini CLI.",
|
|
5
5
|
"author": "Kodelyth <github.com/sifxprime>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -79,7 +79,7 @@ Emit exactly one block, then proceed normally:
|
|
|
79
79
|
|
|
80
80
|
## Per-team configurability
|
|
81
81
|
|
|
82
|
-
Teams override the defaults via env vars or `.
|
|
82
|
+
Teams override the defaults via env vars or `.kodelythecc/router.json`:
|
|
83
83
|
|
|
84
84
|
### Env vars
|
|
85
85
|
|
|
@@ -91,7 +91,7 @@ Teams override the defaults via env vars or `.kodelyth/router.json`:
|
|
|
91
91
|
| `KODELYTH_ROUTER_HARD=<model-id>` | Override hard tier. |
|
|
92
92
|
| `KODELYTH_ROUTER_DEFAULT=<trivial\|standard\|hard>` | Default tier for ambiguous tasks (default `standard`). |
|
|
93
93
|
|
|
94
|
-
### Project file: `.
|
|
94
|
+
### Project file: `.kodelythecc/router.json`
|
|
95
95
|
|
|
96
96
|
```json
|
|
97
97
|
{
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## What is Kodelyth Memory
|
|
6
6
|
|
|
7
|
-
A local file at `~/.
|
|
7
|
+
A local file at `~/.kodelythecc/memory/memories.jsonl` storing solutions, patterns, and gotchas extracted from past sessions. Retrieval is BM25 (keyword + tag matching). It is **not** a learned model — it is a retrieval store that gives you better context.
|
|
8
8
|
|
|
9
9
|
**Cross-IDE: the same file is read/written by every IDE on this machine.** A memory captured in Claude Code is recall-able from Windsurf, Cursor, Antigravity, Codex, and any other MCP-capable client. There is one shared store.
|
|
10
10
|
|
|
@@ -84,4 +84,4 @@ The injected memory block is structured so its prefix is identical across calls
|
|
|
84
84
|
|
|
85
85
|
If the user asks "how do you know that about me?", answer plainly:
|
|
86
86
|
|
|
87
|
-
> "It's in your local Kodelyth Memory at `~/.
|
|
87
|
+
> "It's in your local Kodelyth Memory at `~/.kodelythecc/memory/`. You can inspect it, edit it, or delete it any time. Nothing was sent anywhere."
|
|
@@ -117,7 +117,7 @@ ECC uses three compounding memory layers — together they make Claude increasin
|
|
|
117
117
|
- Edit freely — these are YOUR rules for this project
|
|
118
118
|
- Example: "Always use pnpm. Never npm. Never yarn."
|
|
119
119
|
|
|
120
|
-
### Layer 2 — Global Memory (`~/.
|
|
120
|
+
### Layer 2 — Global Memory (`~/.kodelythecc/memory/`)
|
|
121
121
|
- Cross-project. BM25 fuzzy search. Solution patterns.
|
|
122
122
|
- Captures solutions from every session
|
|
123
123
|
- Auto-recalls relevant past solutions on every prompt you type
|
|
@@ -279,6 +279,25 @@ function handleRequest(req, res) {
|
|
|
279
279
|
return jsonResponse(res, 200, data.tokenBudgetSnapshot());
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
+
if (p === '/api/rtk/status') {
|
|
283
|
+
const rtk = require('../rtk/index.js');
|
|
284
|
+
return jsonResponse(res, 200, rtk.status());
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (p === '/api/rtk') {
|
|
288
|
+
const rtk = require('../rtk/index.js');
|
|
289
|
+
const st = rtk.status();
|
|
290
|
+
if (!st.installed) {
|
|
291
|
+
return jsonResponse(res, 200, {
|
|
292
|
+
ok: false,
|
|
293
|
+
installed: false,
|
|
294
|
+
install_hint: 'Run: kodelyth-ecc rtk install',
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
const s = rtk.savings({ days: Number(q.get('days')) || 30 });
|
|
298
|
+
return jsonResponse(res, 200, { ok: true, installed: true, version: st.version, active: st.active, ...s });
|
|
299
|
+
}
|
|
300
|
+
|
|
282
301
|
if (p.startsWith('/api/')) return notFound(res);
|
|
283
302
|
|
|
284
303
|
// ── static fallback ───────────────────────────────────────────────────
|
|
@@ -220,6 +220,7 @@
|
|
|
220
220
|
<button id="refreshBtn" class="btn-ghost" title="Refresh active tab (R key)">Refresh</button>
|
|
221
221
|
<nav class="tabs">
|
|
222
222
|
<button data-tab="overview" class="active">Overview</button>
|
|
223
|
+
<button data-tab="rtk">RTK Savings</button>
|
|
223
224
|
<button data-tab="memory">Memory</button>
|
|
224
225
|
<button data-tab="evolve">Evolve</button>
|
|
225
226
|
<button data-tab="catalog">Catalog</button>
|
|
@@ -245,6 +246,27 @@
|
|
|
245
246
|
</div>
|
|
246
247
|
</section>
|
|
247
248
|
|
|
249
|
+
<!-- ───────── RTK SAVINGS ───────── -->
|
|
250
|
+
<section data-panel="rtk" hidden>
|
|
251
|
+
<div class="grid" id="rtkCards"></div>
|
|
252
|
+
<hr class="sep">
|
|
253
|
+
<div class="row">
|
|
254
|
+
<div class="card">
|
|
255
|
+
<h2>Top saving commands</h2>
|
|
256
|
+
<div id="rtkTopCmds">loading…</div>
|
|
257
|
+
</div>
|
|
258
|
+
<div class="card">
|
|
259
|
+
<h2>Active integrations</h2>
|
|
260
|
+
<div id="rtkActive">loading…</div>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
<hr class="sep">
|
|
264
|
+
<div class="card">
|
|
265
|
+
<h2>Daily savings (last 30 days)</h2>
|
|
266
|
+
<div id="rtkDaily">loading…</div>
|
|
267
|
+
</div>
|
|
268
|
+
</section>
|
|
269
|
+
|
|
248
270
|
<!-- ───────── MEMORY ───────── -->
|
|
249
271
|
<section data-panel="memory" hidden>
|
|
250
272
|
<div class="grid" id="memoryCards"></div>
|
|
@@ -630,9 +652,76 @@
|
|
|
630
652
|
}
|
|
631
653
|
}
|
|
632
654
|
|
|
655
|
+
// ───── RTK loader ─────
|
|
656
|
+
async function loadRtk() {
|
|
657
|
+
try {
|
|
658
|
+
const r = await fetch('/api/rtk').then(r => r.json());
|
|
659
|
+
const cards = $('#rtkCards');
|
|
660
|
+
if (!r.installed) {
|
|
661
|
+
cards.innerHTML = `<div class="empty">RTK not installed. Install with:
|
|
662
|
+
<code>kodelyth-ecc rtk install</code>
|
|
663
|
+
<br><br>${escapeHtml(r.install_hint || '')}</div>`;
|
|
664
|
+
$('#rtkTopCmds').innerHTML = '';
|
|
665
|
+
$('#rtkActive').innerHTML = '';
|
|
666
|
+
$('#rtkDaily').innerHTML = '';
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
if (!r.ok || !r.gain) {
|
|
670
|
+
cards.innerHTML = `<div class="empty">RTK installed (${escapeHtml(r.version || '')}) but no savings data yet. Use your AI tool with RTK enabled and refresh.</div>`;
|
|
671
|
+
$('#rtkTopCmds').innerHTML = '';
|
|
672
|
+
$('#rtkActive').innerHTML = (r.active || []).map(a => `<div class="muted">• ${escapeHtml(a)}</div>`).join('') || '<div class="empty">none</div>';
|
|
673
|
+
$('#rtkDaily').innerHTML = '';
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
const g = r.gain || {};
|
|
677
|
+
const s = g.summary || {};
|
|
678
|
+
const totalSaved = s.total_saved ?? 0;
|
|
679
|
+
const totalInput = s.total_input ?? 0;
|
|
680
|
+
const percent = s.avg_savings_pct != null ? Math.round(s.avg_savings_pct) : 0;
|
|
681
|
+
const cmdCount = s.total_commands ?? 0;
|
|
682
|
+
cards.innerHTML = [
|
|
683
|
+
statCard(fmtN(totalSaved), 'Tokens saved (all-time)', `${percent}% avg reduction`),
|
|
684
|
+
statCard(fmtN(cmdCount), 'Commands filtered', 'through RTK'),
|
|
685
|
+
statCard(fmtN(totalInput), 'Raw tokens seen', 'before RTK compression'),
|
|
686
|
+
statCard(escapeHtml((r.version || '—').replace(/^rtk\s+/,'')), 'RTK version', 'active binary'),
|
|
687
|
+
].join('');
|
|
688
|
+
// Per-command breakdown — RTK's `gain` JSON does not expose this today.
|
|
689
|
+
$('#rtkTopCmds').innerHTML = `<div class="muted" style="font-size:12.5px;">
|
|
690
|
+
Per-command breakdown lives in <code>rtk discover</code>. Run it in your terminal for missed savings opportunities.
|
|
691
|
+
</div>`;
|
|
692
|
+
// Active integrations
|
|
693
|
+
$('#rtkActive').innerHTML = (r.active && r.active.length)
|
|
694
|
+
? r.active.map(a => `<div class="muted" style="font-family:monospace;font-size:12px;">${escapeHtml(a)}</div>`).join('')
|
|
695
|
+
: '<div class="empty">no active IDE integrations detected</div>';
|
|
696
|
+
// Daily graph — simple ascii-style bars, RTK schema: g.daily[].saved_tokens
|
|
697
|
+
const daily = g.daily || [];
|
|
698
|
+
if (Array.isArray(daily) && daily.length) {
|
|
699
|
+
const max = Math.max(...daily.map(d => d.saved_tokens || 0));
|
|
700
|
+
$('#rtkDaily').innerHTML = daily.slice(-30).map(d => {
|
|
701
|
+
const saved = d.saved_tokens || 0;
|
|
702
|
+
const pct = max ? (saved / max) * 100 : 0;
|
|
703
|
+
return `<div style="display:flex;gap:8px;align-items:center;margin:3px 0;font-size:12px;">
|
|
704
|
+
<span class="muted" style="width:90px;font-family:monospace;">${escapeHtml(d.date || '')}</span>
|
|
705
|
+
<div style="flex:1;background:#f1f5f9;border-radius:3px;height:14px;overflow:hidden;">
|
|
706
|
+
<div style="background:#34d399;height:100%;width:${pct}%;"></div>
|
|
707
|
+
</div>
|
|
708
|
+
<span style="width:110px;text-align:right;font-family:monospace;">${fmtN(saved)}</span>
|
|
709
|
+
</div>`;
|
|
710
|
+
}).join('');
|
|
711
|
+
} else {
|
|
712
|
+
$('#rtkDaily').innerHTML = '<div class="empty">no daily data yet</div>';
|
|
713
|
+
}
|
|
714
|
+
setLastUpdated();
|
|
715
|
+
} catch (e) {
|
|
716
|
+
$('#rtkCards').innerHTML = `<div class="empty">failed: ${escapeHtml(e.message)}</div>`;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
function fmtN(n) { return Number(n || 0).toLocaleString(); }
|
|
720
|
+
|
|
633
721
|
// ───── tab dispatcher ─────
|
|
634
722
|
function onTabShown(tab) {
|
|
635
723
|
if (tab === 'overview') loadOverview();
|
|
724
|
+
if (tab === 'rtk') loadRtk();
|
|
636
725
|
if (tab === 'memory') loadMemory();
|
|
637
726
|
if (tab === 'evolve') loadEvolve();
|
|
638
727
|
if (tab === 'catalog') loadCatalog();
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// scripts/rtk/index.js
|
|
2
|
+
// RTK (Rust Token Killer) integration — auto-installs and wires RTK into the IDE
|
|
3
|
+
// that ECC was installed for, so shell commands run through RTK's filter for
|
|
4
|
+
// 60-90% token savings.
|
|
5
|
+
//
|
|
6
|
+
// Public API:
|
|
7
|
+
// isInstalled() → boolean
|
|
8
|
+
// install({ log }) → { installed, method, version } | { skipped, reason }
|
|
9
|
+
// enableFor(target,{log})→ { enabled, target, agent, output } | { skipped, reason }
|
|
10
|
+
// status() → { installed, version, agents: [...] }
|
|
11
|
+
// savings({ days }) → parsed `rtk gain --format json` snapshot or null
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
const { execFileSync, spawnSync } = require('child_process');
|
|
15
|
+
const os = require('os');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
|
|
19
|
+
// ── ECC install target → RTK agent flag ──────────────────────────────────────
|
|
20
|
+
// Reference: `rtk init --help` and RTK README "Supported AI Tools" table.
|
|
21
|
+
const TARGET_MAP = {
|
|
22
|
+
'claude-code': ['init', '-g'],
|
|
23
|
+
'cursor': ['init', '-g', '--agent', 'cursor'],
|
|
24
|
+
'cursor-project': ['init', '--agent', 'cursor'],
|
|
25
|
+
'windsurf-home': ['init', '-g', '--agent', 'windsurf'],
|
|
26
|
+
'windsurf-project': ['init', '--agent', 'windsurf'],
|
|
27
|
+
'antigravity': ['init', '--agent', 'antigravity'],
|
|
28
|
+
'codex-home': ['init', '-g', '--codex'],
|
|
29
|
+
'opencode': ['init', '-g', '--opencode'],
|
|
30
|
+
'cline': ['init', '--agent', 'cline'],
|
|
31
|
+
'gemini-cli': ['init', '-g', '--gemini'],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// ── Detect which IDEs ECC has already been installed for on this machine ─────
|
|
35
|
+
// Returns list of ECC install-target strings that have visible ECC artifacts.
|
|
36
|
+
function detectInstalledTargets() {
|
|
37
|
+
const home = os.homedir();
|
|
38
|
+
const targets = [];
|
|
39
|
+
const checks = [
|
|
40
|
+
{ target: 'claude-code', dir: path.join(home, '.claude', 'agents') },
|
|
41
|
+
{ target: 'cursor', dir: path.join(home, '.cursor', 'rules') },
|
|
42
|
+
{ target: 'windsurf-home', dir: path.join(home, '.codeium', 'windsurf', 'memories') },
|
|
43
|
+
{ target: 'antigravity', dir: path.join(home, '.antigravity') },
|
|
44
|
+
{ target: 'codex-home', dir: path.join(home, '.codex') },
|
|
45
|
+
{ target: 'opencode', dir: path.join(home, '.config', 'opencode') },
|
|
46
|
+
{ target: 'gemini-cli', dir: path.join(home, '.gemini') },
|
|
47
|
+
];
|
|
48
|
+
for (const { target, dir } of checks) {
|
|
49
|
+
try {
|
|
50
|
+
if (fs.existsSync(dir) && fs.readdirSync(dir).length > 0) targets.push(target);
|
|
51
|
+
} catch { /* skip */ }
|
|
52
|
+
}
|
|
53
|
+
return targets;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isInstalled() {
|
|
57
|
+
try {
|
|
58
|
+
execFileSync('rtk', ['--version'], { stdio: 'ignore' });
|
|
59
|
+
return true;
|
|
60
|
+
} catch { return false; }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getVersion() {
|
|
64
|
+
try {
|
|
65
|
+
return execFileSync('rtk', ['--version'], { encoding: 'utf8' }).trim();
|
|
66
|
+
} catch { return null; }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ── Install RTK binary ───────────────────────────────────────────────────────
|
|
70
|
+
// Mac: prefer `brew install rtk` if brew is on PATH (fastest, cached).
|
|
71
|
+
// Otherwise: pipe the official install script through sh (installs to ~/.local/bin).
|
|
72
|
+
// Windows: skipped (needs manual .zip download from releases).
|
|
73
|
+
function install({ log = () => {} } = {}) {
|
|
74
|
+
if (isInstalled()) {
|
|
75
|
+
return { installed: false, skipped: true, reason: 'already installed', version: getVersion() };
|
|
76
|
+
}
|
|
77
|
+
if (os.platform() === 'win32') {
|
|
78
|
+
return { installed: false, skipped: true, reason: 'windows requires manual install: https://github.com/rtk-ai/rtk/releases' };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Try Homebrew first on macOS.
|
|
82
|
+
if (os.platform() === 'darwin') {
|
|
83
|
+
try {
|
|
84
|
+
execFileSync('brew', ['--version'], { stdio: 'ignore' });
|
|
85
|
+
log('[rtk] installing via Homebrew…');
|
|
86
|
+
const r = spawnSync('brew', ['install', 'rtk'], { stdio: 'inherit' });
|
|
87
|
+
if (r.status === 0 && isInstalled()) {
|
|
88
|
+
return { installed: true, method: 'brew', version: getVersion() };
|
|
89
|
+
}
|
|
90
|
+
log('[rtk] brew install did not complete; falling back to curl script');
|
|
91
|
+
} catch { /* brew not present */ }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Fall back to the official install script.
|
|
95
|
+
log('[rtk] installing via curl script (installs to ~/.local/bin)…');
|
|
96
|
+
const script = 'curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh';
|
|
97
|
+
const r = spawnSync('sh', ['-c', script], { stdio: 'inherit' });
|
|
98
|
+
if (r.status !== 0) {
|
|
99
|
+
return { installed: false, skipped: true, reason: 'install script failed — install rtk manually: https://github.com/rtk-ai/rtk#installation' };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Make sure ~/.local/bin is on PATH for this process so isInstalled() succeeds.
|
|
103
|
+
const localBin = path.join(os.homedir(), '.local', 'bin');
|
|
104
|
+
if (fs.existsSync(path.join(localBin, 'rtk')) && !process.env.PATH.split(':').includes(localBin)) {
|
|
105
|
+
process.env.PATH = `${localBin}:${process.env.PATH}`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!isInstalled()) {
|
|
109
|
+
return { installed: false, skipped: true, reason: 'installed to ~/.local/bin but not on PATH — add "export PATH=$HOME/.local/bin:$PATH" to your shell rc' };
|
|
110
|
+
}
|
|
111
|
+
return { installed: true, method: 'curl', version: getVersion() };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ── Enable RTK for a specific IDE ────────────────────────────────────────────
|
|
115
|
+
function enableFor(target, { log = () => {} } = {}) {
|
|
116
|
+
if (!isInstalled()) {
|
|
117
|
+
return { enabled: false, skipped: true, reason: 'rtk binary not on PATH' };
|
|
118
|
+
}
|
|
119
|
+
const rtkArgs = TARGET_MAP[target];
|
|
120
|
+
if (!rtkArgs) {
|
|
121
|
+
return { enabled: false, skipped: true, reason: `no RTK mapping for target "${target}"` };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
log(`[rtk] wiring RTK into ${target} …`);
|
|
125
|
+
// --auto-patch is only accepted by the default Claude Code hook flow.
|
|
126
|
+
// Other agent flags (--codex, --gemini, --opencode, --agent X) reject it.
|
|
127
|
+
const finalArgs = target === 'claude-code' ? [...rtkArgs, '--auto-patch'] : rtkArgs;
|
|
128
|
+
const r = spawnSync('rtk', finalArgs, { encoding: 'utf8' });
|
|
129
|
+
const output = (r.stdout || '') + (r.stderr || '');
|
|
130
|
+
if (r.status !== 0) {
|
|
131
|
+
return { enabled: false, skipped: true, reason: 'rtk init failed', output };
|
|
132
|
+
}
|
|
133
|
+
return { enabled: true, target, agent: rtkArgs.join(' '), output: output.trim() };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ── Disable RTK for a specific IDE (removes hook + RTK.md) ───────────────────
|
|
137
|
+
function disableFor(target, { log = () => {} } = {}) {
|
|
138
|
+
if (!isInstalled()) return { disabled: false, skipped: true, reason: 'rtk not installed' };
|
|
139
|
+
const rtkArgs = TARGET_MAP[target];
|
|
140
|
+
if (!rtkArgs) return { disabled: false, skipped: true, reason: `no RTK mapping for target "${target}"` };
|
|
141
|
+
log(`[rtk] removing RTK from ${target} …`);
|
|
142
|
+
const r = spawnSync('rtk', [...rtkArgs, '--uninstall'], { encoding: 'utf8' });
|
|
143
|
+
return { disabled: r.status === 0, output: ((r.stdout || '') + (r.stderr || '')).trim() };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ── Status: what's installed, what's active ──────────────────────────────────
|
|
147
|
+
function status() {
|
|
148
|
+
const installed = isInstalled();
|
|
149
|
+
if (!installed) return { installed: false, version: null, active: [] };
|
|
150
|
+
const version = getVersion();
|
|
151
|
+
const active = [];
|
|
152
|
+
try {
|
|
153
|
+
const r = execFileSync('rtk', ['init', '--show'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
154
|
+
// Only surface the '[ok]' status rows — skip the usage help RTK prints below.
|
|
155
|
+
for (const line of r.split('\n')) {
|
|
156
|
+
const t = line.trim();
|
|
157
|
+
if (t.startsWith('[ok]') || t.startsWith('[--]')) active.push(t);
|
|
158
|
+
}
|
|
159
|
+
} catch { /* older rtk versions may not have --show */ }
|
|
160
|
+
return { installed: true, version, active };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ── Savings: read `rtk gain --format json` for dashboard ─────────────────────
|
|
164
|
+
function savings({ days = 30 } = {}) {
|
|
165
|
+
if (!isInstalled()) return null;
|
|
166
|
+
try {
|
|
167
|
+
const r = execFileSync('rtk', ['gain', '--all', '--format', 'json'], {
|
|
168
|
+
encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], maxBuffer: 16 * 1024 * 1024,
|
|
169
|
+
});
|
|
170
|
+
return { ok: true, days, gain: JSON.parse(r) };
|
|
171
|
+
} catch (e) {
|
|
172
|
+
return { ok: false, error: e.message };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = {
|
|
177
|
+
TARGET_MAP,
|
|
178
|
+
detectInstalledTargets,
|
|
179
|
+
isInstalled,
|
|
180
|
+
getVersion,
|
|
181
|
+
install,
|
|
182
|
+
enableFor,
|
|
183
|
+
disableFor,
|
|
184
|
+
status,
|
|
185
|
+
savings,
|
|
186
|
+
};
|
|
@@ -44,7 +44,7 @@ Weight signals together. Single signals are noisy; three or four together are re
|
|
|
44
44
|
|
|
45
45
|
### 2. Read the team's config
|
|
46
46
|
|
|
47
|
-
Check for `.
|
|
47
|
+
Check for `.kodelythecc/router.json` at the project root and these env vars:
|
|
48
48
|
|
|
49
49
|
```
|
|
50
50
|
KODELYTH_ROUTER off | (unset)
|
|
@@ -16,7 +16,7 @@ description: Local self-learning memory for AI coding sessions. Captures what wo
|
|
|
16
16
|
|
|
17
17
|
```
|
|
18
18
|
┌─────────────────┐ capture ┌─────────────────┐ inject ┌─────────────────┐
|
|
19
|
-
│ Past session │ ─────────────→│ ~/.
|
|
19
|
+
│ Past session │ ─────────────→│ ~/.kodelythecc/ │─────────────→│ Next session │
|
|
20
20
|
│ (you solved X) │ │ memory/ │ │ (X comes up) │
|
|
21
21
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
22
22
|
│
|
|
@@ -29,7 +29,7 @@ description: Local self-learning memory for AI coding sessions. Captures what wo
|
|
|
29
29
|
|
|
30
30
|
## Storage layout
|
|
31
31
|
|
|
32
|
-
All under `~/.
|
|
32
|
+
All under `~/.kodelythecc/memory/` (override with `KODELYTH_MEMORY_DIR`):
|
|
33
33
|
|
|
34
34
|
| File | Purpose |
|
|
35
35
|
|---|---|
|
|
@@ -109,9 +109,9 @@ For Anthropic models the cache TTL is 5 minutes — typing back-to-back during a
|
|
|
109
109
|
## Honest limits
|
|
110
110
|
|
|
111
111
|
- **Not "the model learns"** — the model is unchanged. We're just feeding it better context.
|
|
112
|
-
- **Per-machine by default** — sync via Dropbox/iCloud/git on `~/.
|
|
112
|
+
- **Per-machine by default** — sync via Dropbox/iCloud/git on `~/.kodelythecc/memory/` if needed.
|
|
113
113
|
- **Cloud-AI platforms** (Windsurf, Antigravity, partial Cursor) — session data is server-side. Auto-extract from past sessions doesn't work there. Manual `/memory remember` still does.
|
|
114
|
-
- **Privacy** — every byte stays on your disk. Verify with `ls -la ~/.
|
|
114
|
+
- **Privacy** — every byte stays on your disk. Verify with `ls -la ~/.kodelythecc/memory/`.
|
|
115
115
|
|
|
116
116
|
## Anti-patterns
|
|
117
117
|
|
|
@@ -77,7 +77,7 @@ Snapshot of currently recorded signals:
|
|
|
77
77
|
|
|
78
78
|
### `kodelyth-ecc evolve analyze`
|
|
79
79
|
|
|
80
|
-
Reads signals + your `~/.
|
|
80
|
+
Reads signals + your `~/.kodelythecc/memory/` store, applies thresholds, and writes proposals to `~/.kodelythecc/evolve/proposals.jsonl`. Idempotent — re-running with the same evidence produces the same proposal IDs and does NOT duplicate.
|
|
81
81
|
|
|
82
82
|
| Flag | Default | Effect |
|
|
83
83
|
|---|---|---|
|
|
@@ -111,8 +111,8 @@ Marks a proposal `rejected`. Optional `--note` is preserved for the audit trail.
|
|
|
111
111
|
|
|
112
112
|
The auto-recall hook (`hooks/memory/auto-recall.js`) does two things in addition to its normal job:
|
|
113
113
|
|
|
114
|
-
1. **On a memory surface** — calls `evolve.recordSurface({ memoryId, sessionId, projectRoot })`. This bumps the per-memory counter in `~/.
|
|
115
|
-
2. **On a substantive prompt with zero memory matches** — calls `evolve.recordRoutingMiss({ prompt, sessionId, projectRoot })`. Appends one line to `~/.
|
|
114
|
+
1. **On a memory surface** — calls `evolve.recordSurface({ memoryId, sessionId, projectRoot })`. This bumps the per-memory counter in `~/.kodelythecc/evolve/reuse.json`. Idempotent per `(memoryId, sessionId)` — you can't game the counter by surfacing the same memory ten times in one session.
|
|
115
|
+
2. **On a substantive prompt with zero memory matches** — calls `evolve.recordRoutingMiss({ prompt, sessionId, projectRoot })`. Appends one line to `~/.kodelythecc/evolve/routing-misses.jsonl`. The prompt is capped to 1000 chars and stored alongside its top tokens for clustering.
|
|
116
116
|
|
|
117
117
|
Both calls are **fire-and-forget**: any error is swallowed silently. The hook NEVER blocks recall on stats failure.
|
|
118
118
|
|
|
@@ -157,7 +157,7 @@ Proposal IDs are deterministic over their evidence — the same evidence always
|
|
|
157
157
|
## Storage layout
|
|
158
158
|
|
|
159
159
|
```
|
|
160
|
-
~/.
|
|
160
|
+
~/.kodelythecc/evolve/
|
|
161
161
|
├── reuse.json # per-memory reuse counters
|
|
162
162
|
├── routing-misses.jsonl # append-only miss log
|
|
163
163
|
└── proposals.jsonl # append-only proposal events
|