kodelyth-ecc 2.3.0 → 2.4.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 CHANGED
@@ -2,6 +2,76 @@
2
2
 
3
3
  All notable changes to Kodelyth ECC are documented here.
4
4
 
5
+ ## v2.4.1 — Intent routing v2 (July 2026)
6
+
7
+ Full design pass on `rules/common/agent-intent-routing.md` — the always-on rule that maps plain-language user intent to specialist agents. Deferred from 2.4.0.
8
+
9
+ ### Added — 8 new routing dimensions layered above the existing 10-tier signal tables
10
+
11
+ 1. **Confidence tiers** — high (route silently), medium (route + "not X? say so" tail), low (name 2 candidates, ask), none (answer directly, don't announce)
12
+ 2. **Session-state awareness** — once routed to an agent, stay in its voice for follow-ups. Do NOT re-announce the same routing. Only re-route when the user's message contains a stronger signal for a different agent
13
+ 3. **Anti-routing whitelist** — 6 situations where routing MUST be skipped (under 5 words with no code, one-line factual questions, explicit `use X`, "don't route", mid-workflow, ECC-itself bug reports)
14
+ 4. **New signal families for v2.4+** — routes for `/terse`, `/terse-compress`, `codebase-memory-mcp` queries, `kodelythecc uninstall`, `kodelythecc dashboard`, IDE install
15
+ 5. **Compound intent → parallel commands** — when 2 tables match at once, fire the parallel command instead of both agents sequentially (security+review → `/security-audit`, bug+multi-layer → `/debug-blitz`, etc.)
16
+ 6. **Announcement style adapts to terse mode** — if `/terse` is active this session, drop the tip line and use one-token announcement `→ debug-detective` instead of the full form
17
+ 7. **Cultural / multi-language cues** — read emotional markers in any language, strip filler like "bro"/"yaar"/"man", respond in the user's this-turn language, never translate code/errors/commands
18
+ 8. **Evolve integration** — routing misses feed `~/.kodelythecc/evolve/routing-misses.jsonl` so the evolve pipeline can propose new triggers later
19
+
20
+ ### Added — 5 new output-format examples
21
+
22
+ - Default (verbose)
23
+ - Terse mode active — one-token announcement
24
+ - Medium-confidence single match — with "wrong?" tail
25
+ - Low-confidence, two candidates — asks user to pick
26
+ - Sticky routing continuation — no re-announcement
27
+ - Compound intent → parallel command
28
+
29
+ ### Verified
30
+
31
+ - All 21 tests pass
32
+ - Rule file grew from 707 → 832 lines (net +125 lines of new dimensions), 69 sections total
33
+ - The 10-tier priority signal tables (unchanged) remain the workhorse; the 8 new dimensions layer above them
34
+
35
+ ## v2.4.0 — MCP auto-register + full uninstall (July 2026)
36
+
37
+ Real bugs surfaced by live user testing on a fresh Mac install.
38
+
39
+ ### Fixed
40
+
41
+ - **ECC's own MCP server was never registered anywhere** on install. Result: Claude Desktop showed "1 setup issue: MCP", the Codebase / MCP status views showed nothing, and no tool got to talk to our own MCP. `scripts/mcp/register-self.js` now writes `kodelyth-ecc` under `mcpServers` in both `~/.claude.json` (Claude Code) and `~/Library/Application Support/Claude/claude_desktop_config.json` (Claude Desktop). Idempotent — no duplicates on re-run.
42
+ - **Codebase Architecture snapshot was empty** on the dashboard when no active session graph existed. Dashboard now falls back to a per-project list (project name + nodes + edges) via `list_projects`, so users can see the 8 projects codebase-memory-mcp has indexed even before opening one in-session.
43
+ - **`mcp-register` subcommand was swallowed** by the `mcp-*` catch-all (like `mcp-status` was earlier). Excluded properly.
44
+
45
+ ### Added
46
+
47
+ **MCP self-registration**
48
+ - `kodelythecc mcp-register` — write ECC's MCP entry into Claude Code + Desktop configs
49
+ - `kodelythecc mcp-register --status` — show which configs already have it
50
+ - `kodelythecc mcp-register --unregister` — remove ECC's entry
51
+ - **Auto-runs in post-install** — after `--target claude-code` succeeds, ECC registers itself in both configs and prints a summary. Opt out with `--no-mcp-register`
52
+
53
+ **Full uninstall** (`scripts/cli/uninstall.js`)
54
+ - New menu row: **Uninstall ECC completely**
55
+ - CLI: `kodelythecc uninstall --dry-run | --yes | --yes --keep-memory`
56
+ - Removes only files that were shipped by ECC (checks against the package's own `agents/skills/commands/hooks/rules/scripts/` — safe for user-authored siblings)
57
+ - Unwires RTK (`rtk init -g --uninstall`)
58
+ - Removes codebase-memory-mcp agent configs (`codebase-memory-mcp uninstall`)
59
+ - Removes ECC's MCP entry from Claude Code + Desktop
60
+ - Removes `~/.kodelythecc/` (memory + ledgers + cache)
61
+ - Removes legacy `.kodelyth.backup-*` dirs
62
+ - Dry-run mode identifies **759 ECC files** across 6 subdirs on a fresh install
63
+
64
+ ### Verified live end-to-end on this Mac
65
+
66
+ - `mcp-register --status` (before): both configs empty
67
+ - `mcp-register` writes both:
68
+ ```json
69
+ "kodelyth-ecc": { "command": "kodelythecc", "args": ["mcp"], "env": {} }
70
+ ```
71
+ - `~/.claude.json` now has `mcpServers.kodelyth-ecc` + existing `mcpServers.codebase-memory-mcp` (co-existing, no clobber)
72
+ - `uninstall --dry-run` correctly counts 70 agents + 301 skills + 99 commands + 12 hooks + 104 rules + 173 scripts = 759 files, plus 1 backup dir
73
+ - Nothing removed on dry-run — verified
74
+
5
75
  ## v2.3.0 — Interactive arrow-key CLI menu (July 2026)
6
76
 
7
77
  Run `kodelythecc` (or `kodelyth-ecc`) with no args in a real terminal and an arrow-key menu opens.
package/README.md CHANGED
@@ -19,11 +19,22 @@
19
19
  ![Auto Recall](https://img.shields.io/badge/Auto%20Chat%20Recall-on-blueviolet)
20
20
  ![Parallel Agents](https://img.shields.io/badge/Parallel%20Agents-new-red)
21
21
  ![Image Generation](https://img.shields.io/badge/AI%20Image%20Gen-new-yellow)
22
+ ![RTK](https://img.shields.io/badge/RTK-input%20savings-orange)
23
+ ![Terse Mode](https://img.shields.io/badge/Terse%20Mode-output%20savings-orange)
24
+ ![Codebase Graph](https://img.shields.io/badge/Codebase%20Graph-158%20languages-green)
25
+ ![Interactive CLI](https://img.shields.io/badge/CLI-interactive%20menu-blue)
22
26
 
23
27
  </div>
24
28
 
25
29
  **Kodelyth ECC** is a production-grade AI coding toolkit — **70 specialist agents (incl. an 8-agent devil-mode adversarial crew), 194 skills, 97 commands**, a god-tier **semantic intent-routing system**, local self-learning memory, MCP server, swarm orchestrator, and an observability dashboard — all local, zero telemetry.
26
30
 
31
+ Now bundled with:
32
+
33
+ - **RTK** (Rust Token Killer, Apache-2.0) — auto-compresses shell command output for **60-90% input token savings**
34
+ - **Terse mode** (ECC-native, inspired by Caveman) — 4-level output-token compression dial for **40-70% output savings**
35
+ - **Codebase graph** (via [codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp), MIT) — AST-parsed knowledge graph across 158 languages; structural queries at **99% fewer tokens** than file-by-file grep
36
+ - **Interactive CLI** — type `kodelythecc` alone in a terminal for an arrow-key menu with live update check, dashboard, background daemon
37
+
27
38
  Works with **Claude Code**, **Windsurf**, **Cursor**, **Codex CLI**, **Google Antigravity**, **OpenCode**, **Cline**, **Roo Code**, **Aider**, **Kimi**, and **Gemini CLI**.
28
39
 
29
40
  > No telemetry. No cloud. Just rules, agents, skills, MCP server, and your own private memory store — all on your disk. The local dashboard gives you full visibility without sending anything anywhere.
@@ -88,6 +99,25 @@ You never typed `use debug-detective`. You didn't have to. The toolkit read the
88
99
  <img src="social/section-install.svg" alt="Install — One command, 11 platforms, any OS" width="900"/>
89
100
  </div>
90
101
 
102
+ ### The lazy install (one command, everything wired up)
103
+
104
+ ```bash
105
+ npm i -g kodelyth-ecc
106
+ kodelythecc --target claude-code --codebase-graph
107
+ # then restart your AI tool
108
+ ```
109
+
110
+ That's it. This single flow:
111
+
112
+ 1. Installs both binaries (`kodelyth-ecc` and short-form `kodelythecc`) to your PATH
113
+ 2. Copies 70 agents + 194 skills + 97 commands + 22 hooks + 14 rules into your AI tool's config dir
114
+ 3. Auto-installs **RTK** binary and wires its PreToolUse hook (input compression starts on next AI restart)
115
+ 4. Installs **Terse mode** skill + `/terse` and `/terse-compress` slash commands (dormant — user types `/terse` to activate)
116
+ 5. Auto-installs **codebase-memory-mcp** and registers its MCP entries in your AI tool (with `--codebase-graph`)
117
+ 6. Runs legacy-memory migration if you had `~/.kodelyth/` from an older install → `~/.kodelythecc/`
118
+
119
+ After it finishes, run `kodelythecc` alone to open the interactive menu.
120
+
91
121
  ### Option 1 — npx from npm (recommended, any platform)
92
122
 
93
123
  ```bash
@@ -398,6 +428,169 @@ Full reference: [`docs/dashboard.md`](docs/dashboard.md).
398
428
 
399
429
  ---
400
430
 
431
+ ## RTK — Input Token Savings (60-90%)
432
+
433
+ [RTK (Rust Token Killer)](https://github.com/rtk-ai/rtk) — Apache-2.0, single Rust binary — intercepts shell commands before they run and filters the output. Common commands like `git status`, `ls`, `cargo test`, `docker ps` return ~80% less text with zero information loss for the LLM.
434
+
435
+ ECC bundles RTK end-to-end:
436
+
437
+ - Auto-installs the binary via Homebrew (macOS) or curl script (Linux / WSL)
438
+ - Auto-configures the PreToolUse hook in your AI tool's settings
439
+ - Live ledger surfaced in the dashboard's **Token Savings** tab
440
+
441
+ ### Manage from the CLI
442
+
443
+ ```bash
444
+ kodelythecc rtk install # install rtk binary
445
+ kodelythecc rtk enable --target X # wire into one IDE
446
+ kodelythecc rtk enable --all # wire into every ECC-installed IDE at once
447
+ kodelythecc rtk status # version + active integrations
448
+ kodelythecc rtk gain --all # raw rtk savings output
449
+ kodelythecc rtk --help # focused help
450
+ ```
451
+
452
+ ### Live proof (from this repo maintainer's Mac)
453
+
454
+ ```
455
+ total_commands: 1,285
456
+ total_input: 7,964,612 (raw)
457
+ total_output: 2,858,501 (after RTK filter)
458
+ total_saved: 5,107,394 ← 64.1% average reduction
459
+ ```
460
+
461
+ ---
462
+
463
+ ## Terse Mode — Output Token Savings (40-70%)
464
+
465
+ RTK compresses input. **Terse mode** compresses output. Together they stack — savings on both sides of every turn.
466
+
467
+ ECC's own implementation, inspired by [Caveman](https://github.com/JuliusBrussee/caveman) (MIT), independently written. Ships as a skill + two slash commands + a deterministic zero-dep memory-file compressor.
468
+
469
+ ### Four levels
470
+
471
+ Type `/terse` in your AI tool. Level sticks until you switch or session ends.
472
+
473
+ | Level | Style |
474
+ |---|---|
475
+ | `/terse off` | Normal AI voice |
476
+ | `/terse lite` | Light trim, drop filler ("basically", "essentially") |
477
+ | `/terse full` | Telegram-style fragments (default) |
478
+ | `/terse ultra` | Maximum compression, symbols over words |
479
+
480
+ **Byte-preserved always**: fenced code blocks, inline code, shell commands, error text, URLs, file paths, identifiers, numbers, versions.
481
+
482
+ ### Compress memory files permanently
483
+
484
+ `/terse-compress` (or `kodelythecc terse compress <file>`) rewrites `CLAUDE.md`-style memory files into terse form so they cost fewer tokens **every session forever**. ~30% average byte reduction on real prose, 100% code/URL/path integrity.
485
+
486
+ ### CLI
487
+
488
+ ```bash
489
+ kodelythecc terse status # skill install state
490
+ kodelythecc terse stats # tokens saved from ledger
491
+ kodelythecc terse compress <file> # rewrite a file, byte-preserves code
492
+ kodelythecc terse enable --all # install skill + commands into every ECC IDE
493
+ kodelythecc terse --help
494
+ ```
495
+
496
+ ---
497
+
498
+ ## Codebase Graph — 158 Languages, Structural Queries
499
+
500
+ Powered by [DeusData/codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp) (MIT). AST-parsed knowledge graph via tree-sitter across **158 languages**, Hybrid LSP semantic type resolution for 11 major languages, cross-service HTTP/gRPC/GraphQL linking, 14 MCP tools for structural queries.
501
+
502
+ **Why this matters**: "Who calls `ProcessOrder`?" via file-by-file grep = ~412k tokens. Same question via the graph = ~3.4k tokens. That's a **99% reduction** on structural questions.
503
+
504
+ ### Auto-install path
505
+
506
+ Pass `--codebase-graph` on ECC install and it auto-runs their official curl script + auto-configures the MCP server entry in every installed AI-coding agent.
507
+
508
+ ```bash
509
+ kodelythecc --target claude-code --codebase-graph
510
+ # ↑ installs ECC + RTK + Terse + codebase-memory-mcp, all wired up
511
+ ```
512
+
513
+ Then in your AI tool, say **"Index this project"**. Done.
514
+
515
+ ### CLI
516
+
517
+ ```bash
518
+ kodelythecc codebase install # install + auto-register
519
+ kodelythecc codebase status # version + indexed projects
520
+ kodelythecc codebase query search_graph '{"name_pattern": ".*Handler.*"}'
521
+ kodelythecc codebase query trace_path '{"function_name": "main"}'
522
+ kodelythecc codebase query get_architecture '{}'
523
+ kodelythecc codebase --help
524
+ ```
525
+
526
+ ---
527
+
528
+ ## Interactive CLI Menu
529
+
530
+ Type `kodelythecc` alone in a real terminal → arrow-key menu opens.
531
+
532
+ ```
533
+ ⚙ Kodelyth ECC v2.3.0 · Elite Code Crew up to date
534
+
535
+ ▸ Open Dashboard localhost — RTK, Terse, Codebase, Memory
536
+ Install ECC for another IDE 13-target picker
537
+ RTK status Version + wired IDEs + savings
538
+ Terse status Skill install state, ledger totals
539
+ Codebase graph status 158 languages, structural queries
540
+ Memory stats BM25 recall — captures, projects, tags
541
+ Run in background Detached dashboard daemon
542
+ Exit
543
+
544
+ ↑/↓ navigate · ⏎ select · q / esc / Ctrl+C to quit
545
+ ```
546
+
547
+ ### Behaviour rules
548
+
549
+ | Situation | Menu opens? |
550
+ |---|---|
551
+ | `kodelythecc` in Terminal / iTerm | **Yes** |
552
+ | `kodelythecc rtk status` (any subcommand) | No — runs subcommand |
553
+ | `echo hi \| kodelythecc` (piped) | No — runs installer |
554
+ | CI environment (`$CI` set) | No |
555
+ | `KODELYTH_NO_MENU=1 kodelythecc` | No |
556
+
557
+ ### Uninstall
558
+
559
+ The menu's **Uninstall ECC completely** row runs an interactive full cleanup: removes the 759 ECC-installed files from `~/.claude/`, unwires RTK from your AI tool, removes codebase-memory-mcp agent configs, removes ECC's MCP entry from Claude Code + Claude Desktop, and deletes `~/.kodelythecc/` (memory + ledgers). Prompts confirm before anything is deleted; a dry-run mode previews what would be removed without touching anything.
560
+
561
+ You can also run it non-interactively:
562
+
563
+ ```bash
564
+ kodelythecc uninstall --dry-run # preview what would be removed
565
+ kodelythecc uninstall --yes # full cleanup
566
+ kodelythecc uninstall --yes --keep-memory # remove files but keep ~/.kodelythecc/
567
+ npm uninstall -g kodelyth-ecc # finally remove the npm package itself
568
+ ```
569
+
570
+ ### Update check
571
+
572
+ The menu polls `https://registry.npmjs.org/kodelyth-ecc/latest` on open. Cached 24h in `~/.kodelythecc/update-check.json`. When a newer version exists, an extra menu row appears at the top:
573
+
574
+ ```
575
+ ▸ Update to v2.3.1 [NEW] npm i -g kodelyth-ecc
576
+ ```
577
+
578
+ ### Background daemon
579
+
580
+ Selecting "Run in background" forks the dashboard as a detached process:
581
+
582
+ ```
583
+ ✓ Dashboard daemon started (pid 12345)
584
+ URL: http://127.0.0.1:5747
585
+ Log: /Users/you/.kodelythecc/dashboard-daemon.log
586
+ Pid: /Users/you/.kodelythecc/dashboard-daemon.pid
587
+ Stop: kill $(cat ~/.kodelythecc/dashboard-daemon.pid)
588
+ ```
589
+
590
+ Survives shell exit. Real daemon.
591
+
592
+ ---
593
+
401
594
  ## Kodelyth Memory — Local Self-Learning
402
595
 
403
596
  <div align="center">
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.3.0
1
+ 2.4.1
@@ -135,7 +135,7 @@ if (args[0] === 'mcp') {
135
135
  // kodelyth-ecc mcp-remove <name>
136
136
  // kodelyth-ecc mcp-tools <name>
137
137
  // kodelyth-ecc mcp-call <name> <tool> [--json '{"arg":"value"}']
138
- if (args[0] && args[0].startsWith('mcp-')) {
138
+ if (args[0] && args[0].startsWith('mcp-') && !['mcp-register'].includes(args[0])) {
139
139
  (async () => {
140
140
  const sub = args[0].slice(4);
141
141
  const client = require(path.join(ROOT, 'scripts', 'mcp', 'client.js'));
@@ -339,6 +339,40 @@ if (args[0] === 'rtk') {
339
339
  return;
340
340
  }
341
341
 
342
+ // ── Subcommand: uninstall (full ECC removal) ────────────────────────────────
343
+ if (args[0] === 'uninstall') {
344
+ const un = require(path.join(ROOT, 'scripts', 'cli', 'uninstall.js'));
345
+ const dryRun = args.includes('--dry-run');
346
+ const keepMemory = args.includes('--keep-memory');
347
+ const yes = args.includes('--yes') || args.includes('-y');
348
+ if (!yes && !dryRun) {
349
+ process.stderr.write('This removes ECC files, RTK hooks, codebase-memory-mcp configs, and (unless --keep-memory) ~/.kodelythecc/. Add --yes to confirm or --dry-run to preview.\n');
350
+ process.exit(1);
351
+ }
352
+ const r = un.run({ log: (m) => process.stdout.write(m + '\n'), dryRun, keepMemory });
353
+ process.stdout.write(`\nRemoved ${r.removed_files} files across ${r.subsystems_uninstalled.length} subsystems.\n`);
354
+ if (r.errors.length) process.stdout.write(`Errors: ${r.errors.length}\n${r.errors.map(e => ' ' + e).join('\n')}\n`);
355
+ process.stdout.write(dryRun ? '(dry-run — no changes made)\n' : 'ECC removed. Uninstall the npm package: npm uninstall -g kodelyth-ecc\n');
356
+ process.exit(0);
357
+ }
358
+
359
+ // ── Subcommand: mcp-register (self-register ECC MCP in Claude Code + Desktop)
360
+ if (args[0] === 'mcp-register') {
361
+ const reg = require(path.join(ROOT, 'scripts', 'mcp', 'register-self.js'));
362
+ if (args.includes('--status')) {
363
+ const s = reg.statusAll();
364
+ for (const row of s) process.stdout.write(`${row.present ? '✓' : '·'} ${row.file}${row.exists ? '' : ' (file missing)'}\n`);
365
+ process.exit(0);
366
+ }
367
+ if (args.includes('--unregister')) {
368
+ reg.unregisterAll({ log: (m) => process.stdout.write(m + '\n') });
369
+ process.exit(0);
370
+ }
371
+ reg.registerAll({ log: (m) => process.stdout.write(m + '\n') });
372
+ process.stdout.write('\nRestart Claude Code / Claude Desktop to pick up the new MCP server.\n');
373
+ process.exit(0);
374
+ }
375
+
342
376
  // ── Subcommand: codebase (DeusData code-graph MCP integration) ───────────────
343
377
  // Usage:
344
378
  // kodelyth-ecc codebase install install the codebase-memory-mcp binary
@@ -1451,6 +1485,22 @@ if (isWin) {
1451
1485
  fs.chmodSync(sh, 0o755);
1452
1486
  const result = spawnSync('bash', [sh, ...args], { stdio: 'inherit', shell: false });
1453
1487
 
1488
+ // Post-install: auto-register ECC's own MCP server in Claude Code + Desktop.
1489
+ if (result.status === 0 && !args.includes('--no-mcp-register')) {
1490
+ try {
1491
+ const reg = require(path.join(ROOT, 'scripts', 'mcp', 'register-self.js'));
1492
+ process.stdout.write('\n━ ECC MCP server registration ' + '─'.repeat(31) + '\n');
1493
+ const rows = reg.registerAll({ log: () => {} });
1494
+ for (const r of rows) {
1495
+ const marker = r.action === 'added' ? '✓ added' : r.action === 'updated' ? '✓ updated' : r.action === 'unchanged' ? '· unchanged' : `· ${r.action}`;
1496
+ process.stdout.write(` ${marker}: ${r.file}\n`);
1497
+ }
1498
+ process.stdout.write(` · Restart Claude Code / Claude Desktop to pick up the server\n`);
1499
+ } catch (e) {
1500
+ process.stderr.write(`[mcp] self-register skipped: ${e.message}\n`);
1501
+ }
1502
+ }
1503
+
1454
1504
  // Post-install: auto-install + wire RTK for the target IDE (opt-out via --no-rtk).
1455
1505
  if (result.status === 0 && !args.includes('--no-rtk')) {
1456
1506
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kodelyth-ecc",
3
- "version": "2.3.0",
3
+ "version": "2.4.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",
@@ -16,6 +16,96 @@ If multiple agents match, pick the **highest priority** below (priority decrease
16
16
 
17
17
  ---
18
18
 
19
+ ## Routing v2 — The Eight Dimensions
20
+
21
+ The signal tables below tell you **which agent** matches. These dimensions tell you **how confidently to route, when to stay silent, how to announce, and how to handle compound intent**. Apply them in order.
22
+
23
+ ### 1. Confidence tiers
24
+
25
+ | Tier | Trigger | AI behaviour |
26
+ |---|---|---|
27
+ | **High** — 2+ signals from one table, OR 1 signal + emotion, OR explicit `use X` / `@X` | Route immediately with one-line announcement |
28
+ | **Medium** — 1 clean signal, no counter-signals | Route with one-line announcement AND a "Not X? Say so, I'll switch" tail |
29
+ | **Low** — 1 weak signal, or signals from 2+ tables of similar priority | **Do NOT auto-route.** Name the 2 best candidates in one line, ask which fits |
30
+ | **None** — no signal, or explicit anti-routing | Answer directly, no routing announcement |
31
+
32
+ ### 2. Session-state awareness (sticky routing)
33
+
34
+ Once you have routed to an agent this session, **stay in that agent's voice** for follow-ups on the same thread unless:
35
+
36
+ - The user's next message contains a **stronger signal** for a different agent
37
+ - The user says "back to normal", "stop routing", "just answer me"
38
+ - The task has clearly concluded (test passes, PR merged, question answered)
39
+
40
+ **Never re-announce the same routing.** Sticky = quiet. Only announce again when the agent actually changes.
41
+
42
+ ### 3. Anti-routing whitelist
43
+
44
+ Route to **no one** in these cases (skip Priority 1-10 entirely):
45
+
46
+ - Message is under 5 words AND has no error/code paste (e.g. "hi", "ok", "thanks", "cool", "yes")
47
+ - Message is a factual question with a one-line answer ("what does `git stash pop` do?")
48
+ - User already invoked with `use X`, `@X`, `run <agent>` — respect explicit choice
49
+ - User said "don't route" / "just answer" / "stop routing" this session
50
+ - User is in the middle of a multi-step interactive workflow the previous agent started
51
+ - The message is a bug report about ECC itself (routing bugs, install bugs) — answer as the maintainer, not as a specialist
52
+
53
+ ### 4. New signal families (v2.4+)
54
+
55
+ Beyond the 10 priority tiers below, watch for these newer signals — they map to features shipped in ECC 2.x:
56
+
57
+ | User says | Route to |
58
+ |---|---|
59
+ | "compress this memory file" / "shrink CLAUDE.md" / "make my rules smaller" | `/terse-compress` |
60
+ | "talk shorter" / "be brief" / "less verbose" / "caveman mode" | `/terse` (skill activation) |
61
+ | "who calls X" / "where is X used" / "trace the call chain" / "impact analysis" | `codebase-memory-mcp` via `search_graph` / `trace_path` |
62
+ | "index this project" / "build the graph" / "scan the codebase" | `codebase-memory-mcp` via `index_repository` |
63
+ | "remove ECC" / "uninstall kodelythecc" / "clean this up" | Suggest `kodelythecc uninstall --dry-run` |
64
+ | "how much did I save" / "show my token savings" / "RTK stats" | `kodelythecc dashboard` OR `kodelythecc rtk gain` |
65
+ | "install for another IDE" / "add to Cursor / Windsurf / Antigravity" | `kodelythecc --target <ide>` |
66
+
67
+ ### 5. Compound intent → parallel agents
68
+
69
+ Some messages match **two priority tables at once**. When they do, fire the parallel command, not both agents sequentially.
70
+
71
+ | User signals | Fire |
72
+ |---|---|
73
+ | security question + review question | `/security-audit` |
74
+ | bug + been-stuck-for-hours + multi-layer | `/debug-blitz` |
75
+ | architecture + security + a11y (new project) | `/project-launch` |
76
+ | pre-release + full audit | `/pre-release` |
77
+ | refactor + types + tests | `/refactor-sprint` |
78
+ | attacker mindset + multi-vector | `/devil-mode` |
79
+ | new codebase + orientation | `/onboard` |
80
+ | general audit + multiple angles | `/team-review` |
81
+
82
+ ### 6. Announcement style adapts to terse mode
83
+
84
+ If the user has typed `/terse` this session:
85
+
86
+ - Drop the `Tip: next time you can type "use <agent>"` line
87
+ - Use a one-token announcement: `→ debug-detective` instead of `→ Routing to debug-detective (stack trace + frustration match)`
88
+ - No trailing decoration
89
+
90
+ If terse is **off**, use the full form documented in the "Output Format" section at the bottom.
91
+
92
+ ### 7. Cultural + multi-language cues
93
+
94
+ The user may write in a mixed register (English + native language + technical shorthand). Read the cues:
95
+
96
+ - Emotional markers in any language route the same way: "arre yaar broken hai" = frustration = `debug-detective`
97
+ - Filler like "bro", "yaar", "man", "please" is not a signal — strip it, read the substance
98
+ - If the user's message language differs from previous turns, respond in the same language they used **this turn**, not their previous one
99
+ - Code identifiers, commands, and error text stay in their original language (never translate `NullPointerException`)
100
+
101
+ ### 8. Evolve integration — routing misses become proposals
102
+
103
+ When you route (or explicitly do NOT route because the signal was weak) and the outcome is unsatisfying, the ECC evolve system writes this to `~/.kodelythecc/evolve/routing-misses.jsonl` so proposals for new triggers can be surfaced later.
104
+
105
+ You never write this file yourself. Just be honest in the routing announcement: if the match is weak, say "medium confidence — routing to X, not Y, because Z" so the evolve pipeline has a clean signal.
106
+
107
+ ---
108
+
19
109
  ## How to Apply This Rule — Semantic Intent, Not Keyword Matching
20
110
 
21
111
  **Read the intent behind the words, not just the words.**
@@ -696,6 +786,7 @@ When the user's request spans multiple concerns, name the parallel agents:
696
786
 
697
787
  ## Output Format When Routing
698
788
 
789
+ **Default (verbose)**:
699
790
  ```
700
791
  → Routing to debug-detective (stack trace + frustration signals match the bug-tracking pattern)
701
792
 
@@ -704,4 +795,38 @@ When the user's request spans multiple concerns, name the parallel agents:
704
795
  Tip: next time you can type "use debug-detective" to invoke me directly.
705
796
  ```
706
797
 
707
- This keeps the user **informed**, **never surprised**, and **learning the toolkit** with every interaction.
798
+ **Terse mode active (see Dimension 6)**:
799
+ ```
800
+ → debug-detective
801
+
802
+ [response — no tip line, no explanation of why]
803
+ ```
804
+
805
+ **Medium-confidence single match** (add a "wrong?" tail):
806
+ ```
807
+ → Routing to code-reviewer (single file paste, no other context — treating as review)
808
+
809
+ [response as code-reviewer]
810
+
811
+ Not what you wanted? Say "use debug-detective" or "just answer" to switch.
812
+ ```
813
+
814
+ **Low-confidence, two candidates** (ask, do not pick):
815
+ ```
816
+ Two agents fit this: debug-detective (bug + error) or silent-failure-hunter (no error thrown).
817
+ Which one? Or should I answer directly?
818
+ ```
819
+
820
+ **Sticky routing continuation** (already in an agent, no announcement):
821
+ ```
822
+ [response continues in the same agent's voice — no re-announcement]
823
+ ```
824
+
825
+ **Compound intent → parallel command**:
826
+ ```
827
+ → Firing /debug-blitz — 3 agents in parallel (debug-detective + silent-failure-hunter + env-debugger)
828
+
829
+ [synthesised result]
830
+ ```
831
+
832
+ This keeps the user **informed**, **never surprised**, and **learning the toolkit** with every interaction — while still respecting terse mode and session context.
@@ -89,6 +89,11 @@ async function buildOptions({ ROOT }) {
89
89
  hint: 'Detach dashboard as a daemon so /api routes stay reachable',
90
90
  run: () => runBackground(),
91
91
  });
92
+ opts.push({
93
+ label: 'Uninstall ECC completely',
94
+ hint: 'Remove agents/skills/commands/hooks, RTK hook, codebase-mcp, and ~/.kodelythecc/',
95
+ run: () => runUninstall(ROOT),
96
+ });
92
97
  opts.push({
93
98
  label: 'Exit',
94
99
  hint: '',
@@ -149,6 +154,42 @@ async function pickIdeAndInstall(ROOT) {
149
154
  waitForEnter().then(() => main().catch(() => process.exit(0)));
150
155
  }
151
156
 
157
+ async function runUninstall(ROOT) {
158
+ cleanup();
159
+ console.log(`${C.red}${C.bold}⚠ Uninstall Kodelyth ECC${C.reset}`);
160
+ console.log('');
161
+ console.log('This will remove:');
162
+ console.log(` ${C.gray}·${C.reset} All ECC agents/skills/commands/hooks/rules installed under ~/.claude/`);
163
+ console.log(` ${C.gray}·${C.reset} RTK hook (rtk binary stays — remove with brew uninstall rtk)`);
164
+ console.log(` ${C.gray}·${C.reset} codebase-memory-mcp agent configs (binary stays)`);
165
+ console.log(` ${C.gray}·${C.reset} ECC MCP server entry from Claude Code + Claude Desktop`);
166
+ console.log(` ${C.gray}·${C.reset} ~/.kodelythecc/ (memory, ledgers, cache) — unless you keep it`);
167
+ console.log('');
168
+ const choice = await pick('Confirm', [
169
+ 'Uninstall — remove EVERYTHING including memory',
170
+ 'Uninstall — keep ~/.kodelythecc/ memory + ledgers',
171
+ 'Dry run — show what would be removed, change nothing',
172
+ 'Cancel',
173
+ ]);
174
+ if (choice == null || choice === 3) return main();
175
+ const dryRun = choice === 2;
176
+ const keepMemory = choice === 1;
177
+ cleanup();
178
+ console.log('');
179
+ const un = require(path.join(ROOT, 'scripts', 'cli', 'uninstall.js'));
180
+ const r = un.run({ log: (m) => console.log(m), dryRun, keepMemory });
181
+ console.log('');
182
+ console.log(`${C.green}✓${C.reset} Removed ${C.bold}${r.removed_files}${C.reset} files across ${r.subsystems_uninstalled.length} subsystems.`);
183
+ if (r.errors.length) console.log(`${C.yellow}Errors: ${r.errors.length}${C.reset}`);
184
+ if (dryRun) {
185
+ console.log(`${C.dim}(dry-run — nothing was changed)${C.reset}`);
186
+ } else {
187
+ console.log('');
188
+ console.log(`Finish by removing the npm package: ${C.cyan}npm uninstall -g kodelyth-ecc${C.reset}`);
189
+ }
190
+ process.exit(0);
191
+ }
192
+
152
193
  function runBackground() {
153
194
  cleanup();
154
195
  const logDir = path.join(os.homedir(), '.kodelythecc');
@@ -0,0 +1,148 @@
1
+ // scripts/cli/uninstall.js
2
+ // Full ECC cleanup — reverses everything the installer + post-install did.
3
+ // Safe: only removes files installed BY ECC (checks for known markers).
4
+ // Never touches user's own custom agents/skills/commands they added themselves.
5
+
6
+ 'use strict';
7
+
8
+ const fs = require('fs');
9
+ const os = require('os');
10
+ const path = require('path');
11
+ const { spawnSync } = require('child_process');
12
+
13
+ // ── What ECC ships — used to identify which files WE installed ─────────────
14
+ function listShippedFiles(ROOT, subdir) {
15
+ const src = path.join(ROOT, subdir);
16
+ if (!fs.existsSync(src)) return [];
17
+ const out = [];
18
+ const walk = (dir, prefix = '') => {
19
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
20
+ const rel = path.join(prefix, entry.name);
21
+ const abs = path.join(dir, entry.name);
22
+ if (entry.isDirectory()) walk(abs, rel);
23
+ else out.push(rel);
24
+ }
25
+ };
26
+ walk(src);
27
+ return out;
28
+ }
29
+
30
+ // Only remove files that also exist in the ECC package.
31
+ // Preserves user-authored files in the same directory.
32
+ function removeInstalledFiles(destDir, shipped) {
33
+ if (!fs.existsSync(destDir)) return { removed: 0, skipped: 0 };
34
+ let removed = 0, skipped = 0;
35
+ for (const rel of shipped) {
36
+ const abs = path.join(destDir, rel);
37
+ if (fs.existsSync(abs)) {
38
+ try { fs.unlinkSync(abs); removed++; } catch { skipped++; }
39
+ }
40
+ }
41
+ // Clean up now-empty ECC-owned directories.
42
+ const dirs = new Set(shipped.map(f => path.dirname(f)).filter(d => d !== '.'));
43
+ for (const rel of [...dirs].sort((a, b) => b.length - a.length)) {
44
+ const abs = path.join(destDir, rel);
45
+ try {
46
+ if (fs.existsSync(abs) && fs.readdirSync(abs).length === 0) fs.rmdirSync(abs);
47
+ } catch { /* keep going */ }
48
+ }
49
+ return { removed, skipped };
50
+ }
51
+
52
+ function rmrf(dir) {
53
+ try { fs.rmSync(dir, { recursive: true, force: true }); return true; }
54
+ catch { return false; }
55
+ }
56
+
57
+ // ── The uninstall plan (dry-run friendly) ──────────────────────────────────
58
+ function plan(ROOT) {
59
+ const home = os.homedir();
60
+ const claudeDir = path.join(home, '.claude');
61
+ const shipped = {
62
+ agents: listShippedFiles(ROOT, 'agents'),
63
+ skills: listShippedFiles(ROOT, 'skills'),
64
+ commands: listShippedFiles(ROOT, 'commands'),
65
+ hooks: listShippedFiles(ROOT, 'hooks'),
66
+ rules: listShippedFiles(ROOT, 'rules'),
67
+ scripts: listShippedFiles(ROOT, 'scripts'),
68
+ };
69
+ const dests = {
70
+ agents: path.join(claudeDir, 'agents'),
71
+ skills: path.join(claudeDir, 'skills'),
72
+ commands: path.join(claudeDir, 'commands'),
73
+ hooks: path.join(claudeDir, 'hooks'),
74
+ rules: path.join(claudeDir, 'rules'),
75
+ scripts: path.join(claudeDir, 'scripts'),
76
+ };
77
+ return { home, claudeDir, shipped, dests };
78
+ }
79
+
80
+ // ── Run the uninstall ──────────────────────────────────────────────────────
81
+ function run({ log = () => {}, keepMemory = false, dryRun = false } = {}) {
82
+ const ROOT = path.join(__dirname, '..', '..');
83
+ const p = plan(ROOT);
84
+ const results = { removed_files: 0, dirs_removed: [], subsystems_uninstalled: [], errors: [] };
85
+
86
+ log('Removing ECC-installed files from ~/.claude/ …');
87
+ for (const kind of Object.keys(p.shipped)) {
88
+ if (dryRun) {
89
+ log(` [dry-run] would remove ${p.shipped[kind].length} ${kind} files from ${p.dests[kind]}`);
90
+ continue;
91
+ }
92
+ const r = removeInstalledFiles(p.dests[kind], p.shipped[kind]);
93
+ results.removed_files += r.removed;
94
+ log(` ${kind}: removed ${r.removed} files (${r.skipped} skipped)`);
95
+ }
96
+
97
+ // Remove ECC's own MCP entries from Claude Code / Claude Desktop configs.
98
+ try {
99
+ const reg = require('../mcp/register-self.js');
100
+ if (!dryRun) reg.unregisterAll({ log: (m) => log(' ' + m) });
101
+ else log(' [dry-run] would unregister kodelyth-ecc MCP server from Claude Code + Desktop');
102
+ results.subsystems_uninstalled.push('mcp-registration');
103
+ } catch (e) { results.errors.push('mcp-unregister: ' + e.message); }
104
+
105
+ // Remove RTK integration (uses their own uninstall flag).
106
+ try {
107
+ log('Unwiring RTK integrations …');
108
+ if (!dryRun) {
109
+ const r = spawnSync('rtk', ['init', '-g', '--uninstall'], { encoding: 'utf8' });
110
+ log(r.status === 0 ? ' ✓ rtk uninstalled from claude-code' : ' · rtk uninstall skipped (may not be present)');
111
+ }
112
+ results.subsystems_uninstalled.push('rtk');
113
+ } catch (e) { results.errors.push('rtk: ' + e.message); }
114
+
115
+ // Remove codebase-memory-mcp registration (their own uninstall).
116
+ try {
117
+ log('Uninstalling codebase-memory-mcp agent configs …');
118
+ if (!dryRun) {
119
+ const r = spawnSync('codebase-memory-mcp', ['uninstall'], { encoding: 'utf8' });
120
+ log(r.status === 0 ? ' ✓ codebase-memory-mcp configs removed' : ' · codebase-memory-mcp uninstall skipped (binary not present)');
121
+ }
122
+ results.subsystems_uninstalled.push('codebase-memory-mcp');
123
+ } catch (e) { results.errors.push('codebase-memory-mcp: ' + e.message); }
124
+
125
+ // Remove memory + ledgers.
126
+ if (!keepMemory) {
127
+ log(`${dryRun ? '[dry-run] would remove' : 'Removing'} ~/.kodelythecc/ (memory, ledgers, cache) …`);
128
+ const target = path.join(p.home, '.kodelythecc');
129
+ if (!dryRun && rmrf(target)) results.dirs_removed.push(target);
130
+ } else {
131
+ log('Keeping ~/.kodelythecc/ (memory preserved as requested)');
132
+ }
133
+
134
+ // Remove legacy migration backup if present.
135
+ try {
136
+ for (const name of fs.readdirSync(p.home)) {
137
+ if (name.startsWith('.kodelyth.backup-')) {
138
+ const abs = path.join(p.home, name);
139
+ if (dryRun) log(` [dry-run] would remove backup ${abs}`);
140
+ else { rmrf(abs); results.dirs_removed.push(abs); }
141
+ }
142
+ }
143
+ } catch { /* home dir listing failed — skip */ }
144
+
145
+ return results;
146
+ }
147
+
148
+ module.exports = { plan, run };
@@ -86,6 +86,21 @@ function dashboardSnapshot() {
86
86
  const st = status();
87
87
  if (!st.installed) return { ok: false, installed: false, install_hint: 'Run: kodelyth-ecc codebase install' };
88
88
  const out = { ok: true, installed: true, version: st.version, indexed_projects: st.indexed_projects, cache_dir: st.cache_dir };
89
+ // Try to list projects with names — richer than just a count.
90
+ try {
91
+ const list = query('list_projects', '{}');
92
+ if (Array.isArray(list)) {
93
+ out.projects = list.slice(0, 20).map(p => ({
94
+ name: p.name || p.path || p.project || 'unnamed',
95
+ path: p.path || null,
96
+ nodes: p.node_count ?? p.nodes ?? null,
97
+ edges: p.edge_count ?? p.edges ?? null,
98
+ }));
99
+ } else if (list && Array.isArray(list.projects)) {
100
+ out.projects = list.projects.slice(0, 20);
101
+ }
102
+ } catch { /* older binaries may not support list_projects */ }
103
+ // Try architecture snapshot for whichever project is 'active'.
89
104
  try {
90
105
  const arch = query('get_architecture', '{}');
91
106
  if (arch && typeof arch === 'object') {
@@ -96,7 +111,7 @@ function dashboardSnapshot() {
96
111
  entry_points: (arch.entry_points || []).slice(0, 5),
97
112
  };
98
113
  }
99
- } catch { /* no active project yet */ }
114
+ } catch { /* no active project yet — dashboard shows CTA */ }
100
115
  return out;
101
116
  }
102
117
 
@@ -813,6 +813,16 @@ kodelyth-ecc codebase query detect_changes '{}'</pre>
813
813
  <td><div style="font-family:monospace;font-size:12px;line-height:1.6;">${a.entry_points.map(e => `<div>${escapeHtml(String(e.name || e))}</div>`).join('')}</div></td></tr>` : ''}
814
814
  </tbody>
815
815
  </table>`;
816
+ } else if ((r.projects || []).length) {
817
+ $('#codebaseArch').innerHTML = `<div class="muted" style="font-size:13px;">
818
+ ${(r.projects || []).length} project(s) indexed. Architecture snapshot is per-active-session — open a project in your AI tool and it appears here.
819
+ </div><table style="margin-top:10px;">
820
+ <thead><tr><th>Project</th><th style="text-align:right;">Nodes</th><th style="text-align:right;">Edges</th></tr></thead>
821
+ <tbody>${r.projects.map(p => `<tr>
822
+ <td><code style="font-size:11.5px;">${escapeHtml(p.name)}</code></td>
823
+ <td style="text-align:right;">${fmtN(p.nodes || 0)}</td>
824
+ <td style="text-align:right;">${fmtN(p.edges || 0)}</td>
825
+ </tr>`).join('')}</tbody></table>`;
816
826
  } else {
817
827
  $('#codebaseArch').innerHTML = '<div class="empty">no active project graph yet — open a repo in your AI tool and say "Index this project"</div>';
818
828
  }
@@ -0,0 +1,116 @@
1
+ // scripts/mcp/register-self.js
2
+ // Auto-register ECC's own MCP server in Claude Code (~/.claude.json) and
3
+ // Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json).
4
+ //
5
+ // Idempotent — updates in place, never duplicates. Handles missing files.
6
+
7
+ 'use strict';
8
+
9
+ const fs = require('fs');
10
+ const os = require('os');
11
+ const path = require('path');
12
+
13
+ const SERVER_NAME = 'kodelyth-ecc';
14
+
15
+ function claudeCodeConfigPath() {
16
+ // Claude Code reads user-level MCP from ~/.claude.json
17
+ return path.join(os.homedir(), '.claude.json');
18
+ }
19
+
20
+ function claudeDesktopConfigPath() {
21
+ const home = os.homedir();
22
+ if (os.platform() === 'darwin') return path.join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
23
+ if (os.platform() === 'win32') return path.join(process.env.APPDATA || '', 'Claude', 'claude_desktop_config.json');
24
+ return path.join(home, '.config', 'Claude', 'claude_desktop_config.json');
25
+ }
26
+
27
+ function readJson(file) {
28
+ try { return JSON.parse(fs.readFileSync(file, 'utf8')); } catch { return null; }
29
+ }
30
+
31
+ function writeJson(file, obj) {
32
+ fs.mkdirSync(path.dirname(file), { recursive: true });
33
+ fs.writeFileSync(file, JSON.stringify(obj, null, 2));
34
+ }
35
+
36
+ function serverEntry() {
37
+ return {
38
+ command: 'kodelythecc',
39
+ args: ['mcp'],
40
+ env: {},
41
+ };
42
+ }
43
+
44
+ function registerInFile(file, opts = {}) {
45
+ const existing = readJson(file) || {};
46
+ const servers = existing.mcpServers || {};
47
+ const already = servers[SERVER_NAME];
48
+ const desired = serverEntry();
49
+ if (already && JSON.stringify(already) === JSON.stringify(desired)) {
50
+ return { file, action: 'unchanged' };
51
+ }
52
+ servers[SERVER_NAME] = desired;
53
+ const next = { ...existing, mcpServers: servers };
54
+ if (!opts.dryRun) writeJson(file, next);
55
+ return { file, action: already ? 'updated' : 'added' };
56
+ }
57
+
58
+ function unregisterInFile(file) {
59
+ const existing = readJson(file);
60
+ if (!existing || !existing.mcpServers || !existing.mcpServers[SERVER_NAME]) {
61
+ return { file, action: 'not-present' };
62
+ }
63
+ delete existing.mcpServers[SERVER_NAME];
64
+ writeJson(file, existing);
65
+ return { file, action: 'removed' };
66
+ }
67
+
68
+ function registerAll({ log = () => {} } = {}) {
69
+ const results = [];
70
+ for (const p of [claudeCodeConfigPath(), claudeDesktopConfigPath()]) {
71
+ try {
72
+ const r = registerInFile(p);
73
+ log(` ${r.action}: ${r.file}`);
74
+ results.push(r);
75
+ } catch (e) {
76
+ log(` skipped ${p}: ${e.message}`);
77
+ results.push({ file: p, action: 'error', error: e.message });
78
+ }
79
+ }
80
+ return results;
81
+ }
82
+
83
+ function unregisterAll({ log = () => {} } = {}) {
84
+ const results = [];
85
+ for (const p of [claudeCodeConfigPath(), claudeDesktopConfigPath()]) {
86
+ try {
87
+ const r = unregisterInFile(p);
88
+ log(` ${r.action}: ${r.file}`);
89
+ results.push(r);
90
+ } catch (e) {
91
+ log(` skipped ${p}: ${e.message}`);
92
+ results.push({ file: p, action: 'error', error: e.message });
93
+ }
94
+ }
95
+ return results;
96
+ }
97
+
98
+ function statusAll() {
99
+ const rows = [];
100
+ for (const p of [claudeCodeConfigPath(), claudeDesktopConfigPath()]) {
101
+ const cfg = readJson(p);
102
+ const present = !!(cfg && cfg.mcpServers && cfg.mcpServers[SERVER_NAME]);
103
+ rows.push({ file: p, present, exists: !!cfg });
104
+ }
105
+ return rows;
106
+ }
107
+
108
+ module.exports = {
109
+ SERVER_NAME,
110
+ serverEntry,
111
+ claudeCodeConfigPath,
112
+ claudeDesktopConfigPath,
113
+ registerAll,
114
+ unregisterAll,
115
+ statusAll,
116
+ };