kodelyth-ecc 2.22.0 → 2.23.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/CHANGELOG.md CHANGED
@@ -2,6 +2,69 @@
2
2
 
3
3
  All notable changes to Kodelyth ECC are documented here.
4
4
 
5
+ ## v2.23.0 — Windows has no manual step left (October 2026)
6
+
7
+ 2.22.0 made the Windows install work but left two components needing a manual
8
+ download: RTK and the codebase graph. That turned out to be a gap in ECC, not a
9
+ limitation upstream — **both projects publish Windows builds** and ECC simply
10
+ never fetched them:
11
+
12
+ ```
13
+ rtk-x86_64-pc-windows-msvc.zip
14
+ codebase-memory-mcp-windows-amd64.zip / -arm64.zip
15
+ ```
16
+
17
+ Both now install automatically. Windows is at parity with macOS and Linux.
18
+
19
+ ### How it works
20
+
21
+ A shared `scripts/lib/win-install.js`, used by both. It pulls from GitHub's
22
+ `releases/latest/download/<asset>` URL, which always redirects to the newest
23
+ release — no API call, so no token and no rate limit.
24
+
25
+ Download and extraction use `curl.exe` and `tar.exe`. Both ship with Windows 10
26
+ 1803 and later, and `tar` there is bsdtar, which handles zip. That avoids
27
+ PowerShell quoting entirely. Both are probed before use, so an older machine
28
+ gets a clear message instead of a spawn error.
29
+
30
+ Architecture comes from `process.arch`: the codebase graph has a native arm64
31
+ build, while RTK publishes x86_64 only — fine on arm64 Windows, which runs x64
32
+ under emulation.
33
+
34
+ ### PATH is yours, not ours
35
+
36
+ Binaries land in `%LOCALAPPDATA%\Kodelyth\bin`. ECC does **not** edit your PATH.
37
+ It prints the one command that does:
38
+
39
+ ```powershell
40
+ setx PATH "%PATH%;%LOCALAPPDATA%\Kodelyth\bin"
41
+ ```
42
+
43
+ This mirrors the POSIX path, which reports `~/.local/bin` rather than writing to
44
+ a shell rc. Whether the directory is already persistent is read from
45
+ `HKCU\Environment`, not from `process.env` — the latter would always say yes
46
+ right after the installer prepends it for its own process, and would wrongly
47
+ tell you there is nothing left to do.
48
+
49
+ ### Verified, not asserted
50
+
51
+ The Windows CI job now installs for real and asserts both binaries exist and
52
+ run:
53
+
54
+ ```
55
+ install dir: C:\Users\runneradmin\AppData\Local\Kodelyth\bin
56
+ rtk.exe 10,285,056 bytes
57
+ rtk 0.51.0
58
+ codebase-memory-mcp 0.11.0
59
+ ```
60
+
61
+ `doctor`'s Windows hints changed too. They previously said "no Windows installer
62
+ yet" and pointed at a release page; the install command is now correct on every
63
+ platform, and the hint names the PATH step rather than implying the command
64
+ alone finishes the job.
65
+
66
+ **647 tests passing.**
67
+
5
68
  ## v2.22.0 — Windows actually works now (September 2026)
6
69
 
7
70
  The Windows install was broken in three separate ways. Windows CI had been green
package/README.md CHANGED
@@ -205,18 +205,22 @@ PowerShell 5.1 that ships with the OS. The installer tries `pwsh` first and fall
205
205
  back automatically, and it passes `-ExecutionPolicy Bypass` for its own process
206
206
  only, so you do not need to change your machine's execution policy.
207
207
 
208
- **What is fully automatic on Windows:** the 70 agents, 196 skills, 103 commands,
209
- 15 rules, all 44 hook entries registered into `settings.json`, the ECC MCP server
210
- (16 tools), and Terse mode.
208
+ **Everything installs automatically**, same as macOS and Linux: the 70 agents,
209
+ 196 skills, 103 commands, 15 rules, all 44 hook entries registered into
210
+ `settings.json`, the ECC MCP server (16 tools), Terse mode, **RTK**, and the
211
+ **codebase graph**.
211
212
 
212
- **What still needs one manual step:** RTK and the codebase graph ship as native
213
- binaries without a Windows installer script. ECC tells you so during install and
214
- prints the download link rather than failing or skipping silently:
213
+ The last two are native binaries. ECC downloads the published Windows builds
214
+ straight from GitHub releases and puts them in `%LOCALAPPDATA%\Kodelyth\bin`.
215
+ That directory is not on `PATH` by default, so the installer prints the one
216
+ command that fixes it:
215
217
 
216
- | Component | Windows | Get it |
217
- |---|---|---|
218
- | RTK (token savings) | manual | [rtk-ai/rtk releases](https://github.com/rtk-ai/rtk/releases) |
219
- | Codebase graph | manual | [codebase-memory-mcp releases](https://github.com/DeusData/codebase-memory-mcp/releases) |
218
+ ```powershell
219
+ setx PATH "%PATH%;%LOCALAPPDATA%\Kodelyth\bin"
220
+ ```
221
+
222
+ Run it once, reopen your terminal, done. ECC does not edit `PATH` for you —
223
+ that is your environment to change.
220
224
 
221
225
  **Verify:**
222
226
 
package/VERSION CHANGED
@@ -1 +1 @@
1
- 2.22.0
1
+ 2.23.0
@@ -1850,6 +1850,13 @@ function runPostInstall(status, args) {
1850
1850
  const en = rtk.enableFor(target, { log: () => {} });
1851
1851
  if (en.enabled) {
1852
1852
  w(` ✓ RTK ${(rtk.getVersion() || '').replace(/^rtk /,'')} — wired for ${target}`);
1853
+ // On Windows the binary goes to %LOCALAPPDATA%\Kodelyth\bin. ECC does
1854
+ // not edit PATH for the user, so say plainly what is left to do —
1855
+ // otherwise rtk works during this install and vanishes next shell.
1856
+ if (inst.pathHint) {
1857
+ w(` ! ${inst.dir} is not on your PATH yet`);
1858
+ w(` run once, then reopen your terminal: ${inst.pathHint}`);
1859
+ }
1853
1860
  w(` ✓ Restart your AI tool to activate. 60-90% token savings on shell commands.`);
1854
1861
  } else {
1855
1862
  w(` · skipped: ${en.reason}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kodelyth-ecc",
3
- "version": "2.22.0",
3
+ "version": "2.23.0",
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",
@@ -25,7 +25,32 @@ function getVersion() {
25
25
  function install({ log = () => {} } = {}) {
26
26
  if (isInstalled()) return { installed: false, skipped: true, reason: 'already installed', version: getVersion() };
27
27
  if (os.platform() === 'win32') {
28
- return { installed: false, skipped: true, reason: 'windows requires manual install: https://github.com/DeusData/codebase-memory-mcp/releases' };
28
+ // This project publishes Windows builds for both architectures; ECC just
29
+ // never downloaded them. Pick by process.arch so an arm64 machine gets the
30
+ // native build rather than running x64 under emulation.
31
+ const win = require('../lib/win-install.js');
32
+ const asset = process.arch === 'arm64'
33
+ ? 'codebase-memory-mcp-windows-arm64.zip'
34
+ : 'codebase-memory-mcp-windows-amd64.zip';
35
+ const r = win.installFromRelease({
36
+ repo: 'DeusData/codebase-memory-mcp',
37
+ asset,
38
+ binName: `${BIN}.exe`,
39
+ log,
40
+ });
41
+ if (!r.installed) {
42
+ return { installed: false, skipped: true, reason: `${r.reason} — or install by hand: https://github.com/DeusData/codebase-memory-mcp/releases` };
43
+ }
44
+ if (!isInstalled()) {
45
+ return { installed: false, skipped: true, reason: `installed to ${r.dir} but not runnable from PATH` };
46
+ }
47
+ return {
48
+ installed: true,
49
+ method: 'github-release',
50
+ version: getVersion(),
51
+ dir: r.dir,
52
+ pathHint: r.onPath ? null : win.setxHint(r.dir),
53
+ };
29
54
  }
30
55
  log('[codebase] installing codebase-memory-mcp via official curl script…');
31
56
  const script = 'curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash';
@@ -115,10 +115,11 @@ function checkPromptInjectionGuard() {
115
115
  return { status: PASS, detail: `prompt-injection guard active (mode=${mode})` };
116
116
  }
117
117
 
118
- // Remediation has to be platform-correct or it is worse than none. RTK and the
119
- // codebase graph ship as native binaries with no Windows installer, so
120
- // "kodelythecc rtk install" on Windows just reports that it cannot, and the user
121
- // follows a dead end. Point at the release page there instead.
118
+ // Both tools DO publish Windows builds, and since 2.23.0 ECC downloads them, so
119
+ // the install command is now the right advice on every platform. What differs is
120
+ // what happens afterwards: on Windows the binary lands in
121
+ // %LOCALAPPDATA%\Kodelyth\bin, which is not on PATH by default, so the hint
122
+ // mentions that rather than implying the command alone finishes the job.
122
123
  const IS_WIN = process.platform === 'win32';
123
124
 
124
125
  function checkRtk() {
@@ -126,7 +127,7 @@ function checkRtk() {
126
127
  status: WARN,
127
128
  detail: 'RTK not installed (input savings inactive)',
128
129
  fix: IS_WIN
129
- ? 'no Windows installer yet — download: https://github.com/rtk-ai/rtk/releases'
130
+ ? 'kodelythecc rtk install (installs to %LOCALAPPDATA%\\Kodelyth\\bin — add it to PATH)'
130
131
  : 'kodelythecc rtk install',
131
132
  };
132
133
  try {
@@ -146,7 +147,7 @@ function checkCodebaseGraph() {
146
147
  status: WARN,
147
148
  detail: 'codebase graph not installed (optional)',
148
149
  fix: IS_WIN
149
- ? 'no Windows installer yet — download: https://github.com/DeusData/codebase-memory-mcp/releases'
150
+ ? 'kodelythecc codebase install (installs to %LOCALAPPDATA%\\Kodelyth\\bin — add it to PATH)'
150
151
  : 'kodelythecc codebase install',
151
152
  };
152
153
  return { status: PASS, detail: 'codebase-memory-mcp installed' };
@@ -0,0 +1,157 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Install a released binary on Windows.
5
+ *
6
+ * Both RTK and codebase-memory-mcp publish Windows builds, but ECC never
7
+ * implemented the download path and reported "windows requires manual install"
8
+ * instead. That was a gap here, not a limitation upstream:
9
+ *
10
+ * rtk-x86_64-pc-windows-msvc.zip
11
+ * codebase-memory-mcp-windows-amd64.zip / -arm64.zip
12
+ *
13
+ * Uses GitHub's `releases/latest/download/<asset>` URL, which always redirects
14
+ * to the newest release's asset — no API call, so no token and no rate limit.
15
+ *
16
+ * curl.exe and tar.exe both ship with Windows 10 1803 and later, and tar there
17
+ * is bsdtar, which extracts zip. That avoids PowerShell quoting entirely. Both
18
+ * are probed before use so an older machine gets a clear message rather than a
19
+ * spawn error.
20
+ *
21
+ * PATH is deliberately NOT modified. The POSIX path installs to ~/.local/bin and
22
+ * tells the user to add it; this mirrors that, reporting the exact setx command
23
+ * rather than silently editing a user's environment.
24
+ */
25
+
26
+ const fs = require('fs');
27
+ const os = require('os');
28
+ const path = require('path');
29
+ const { execFileSync, spawnSync } = require('child_process');
30
+
31
+ /** Where ECC puts binaries it installs on Windows. User-writable, no admin. */
32
+ function installDir() {
33
+ const base = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
34
+ return path.join(base, 'Kodelyth', 'bin');
35
+ }
36
+
37
+ function have(bin) {
38
+ try {
39
+ execFileSync(bin, ['--version'], { stdio: 'ignore' });
40
+ return true;
41
+ } catch {
42
+ return false;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * @param {object} opts
48
+ * @param {string} opts.repo "owner/name"
49
+ * @param {string} opts.asset asset filename in the latest release
50
+ * @param {string} opts.binName executable to find after extraction (with .exe)
51
+ * @param {function} [opts.log]
52
+ * @returns {{installed:boolean, reason?:string, dir?:string, binPath?:string, onPath?:boolean}}
53
+ */
54
+ function installFromRelease({ repo, asset, binName, log = () => {} }) {
55
+ if (process.platform !== 'win32') {
56
+ return { installed: false, reason: 'installFromRelease is Windows-only' };
57
+ }
58
+ if (!have('curl')) {
59
+ return { installed: false, reason: 'curl.exe not found (needs Windows 10 1803 or later)' };
60
+ }
61
+ if (!have('tar')) {
62
+ return { installed: false, reason: 'tar.exe not found (needs Windows 10 1803 or later)' };
63
+ }
64
+
65
+ const dir = installDir();
66
+ const url = `https://github.com/${repo}/releases/latest/download/${asset}`;
67
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'ecc-win-'));
68
+ const zip = path.join(tmp, asset);
69
+
70
+ try {
71
+ fs.mkdirSync(dir, { recursive: true });
72
+
73
+ log(`[win] downloading ${asset}…`);
74
+ // -L to follow the release redirect, -f so a 404 is an error rather than
75
+ // an HTML error page written to disk and then "extracted".
76
+ const dl = spawnSync('curl', ['-fsSL', '-o', zip, url], { stdio: 'inherit' });
77
+ if (dl.status !== 0) {
78
+ return { installed: false, reason: `download failed (curl exit ${dl.status}) — ${url}` };
79
+ }
80
+ if (!fs.existsSync(zip) || fs.statSync(zip).size === 0) {
81
+ return { installed: false, reason: `downloaded file is empty — ${url}` };
82
+ }
83
+
84
+ log('[win] extracting…');
85
+ const ex = spawnSync('tar', ['-xf', zip, '-C', dir], { stdio: 'inherit' });
86
+ if (ex.status !== 0) {
87
+ return { installed: false, reason: `extract failed (tar exit ${ex.status})` };
88
+ }
89
+
90
+ // Archives vary: some put the binary at the root, some inside a folder.
91
+ const binPath = findBinary(dir, binName);
92
+ if (!binPath) {
93
+ return { installed: false, reason: `${binName} not found in ${asset} after extraction` };
94
+ }
95
+ // Flatten so the binary sits directly in dir and one PATH entry covers it.
96
+ const finalPath = path.join(dir, binName);
97
+ if (binPath !== finalPath) fs.copyFileSync(binPath, finalPath);
98
+
99
+ // Make it usable in THIS process so a follow-up isInstalled() check passes
100
+ // without the user restarting their shell.
101
+ const sep = path.delimiter;
102
+ if (!(process.env.PATH || '').split(sep).includes(dir)) {
103
+ process.env.PATH = `${dir}${sep}${process.env.PATH || ''}`;
104
+ }
105
+
106
+ return { installed: true, dir, binPath: finalPath, onPath: isOnUserPath(dir) };
107
+ } finally {
108
+ try { fs.rmSync(tmp, { recursive: true, force: true }); } catch { /* temp dir */ }
109
+ }
110
+ }
111
+
112
+ /** Depth-limited search — these archives are shallow; this avoids walking a tree. */
113
+ function findBinary(root, binName, depth = 0) {
114
+ if (depth > 3) return null;
115
+ let entries;
116
+ try {
117
+ entries = fs.readdirSync(root, { withFileTypes: true });
118
+ } catch {
119
+ return null;
120
+ }
121
+ for (const e of entries) {
122
+ const p = path.join(root, e.name);
123
+ if (e.isFile() && e.name.toLowerCase() === binName.toLowerCase()) return p;
124
+ }
125
+ for (const e of entries) {
126
+ if (e.isDirectory()) {
127
+ const found = findBinary(path.join(root, e.name), binName, depth + 1);
128
+ if (found) return found;
129
+ }
130
+ }
131
+ return null;
132
+ }
133
+
134
+ /**
135
+ * Whether the directory is on the user's PERSISTENT PATH, not just this
136
+ * process's. Checking process.env would always say yes right after we prepend
137
+ * it, which would wrongly tell the user there is nothing left to do.
138
+ */
139
+ function isOnUserPath(dir) {
140
+ try {
141
+ const out = execFileSync(
142
+ 'reg',
143
+ ['query', 'HKCU\\Environment', '/v', 'Path'],
144
+ { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }
145
+ );
146
+ return out.toLowerCase().includes(dir.toLowerCase());
147
+ } catch {
148
+ return false;
149
+ }
150
+ }
151
+
152
+ /** The exact command to persist the directory on PATH, for the user to run. */
153
+ function setxHint(dir) {
154
+ return `setx PATH "%PATH%;${dir}"`;
155
+ }
156
+
157
+ module.exports = { installFromRelease, installDir, isOnUserPath, setxHint, findBinary };
@@ -80,13 +80,37 @@ function getVersion() {
80
80
  // ── Install RTK binary ───────────────────────────────────────────────────────
81
81
  // Mac: prefer `brew install rtk` if brew is on PATH (fastest, cached).
82
82
  // Otherwise: pipe the official install script through sh (installs to ~/.local/bin).
83
- // Windows: skipped (needs manual .zip download from releases).
83
+ // Windows: downloads the published .zip from GitHub releases.
84
84
  function install({ log = () => {} } = {}) {
85
85
  if (isInstalled()) {
86
86
  return { installed: false, skipped: true, reason: 'already installed', version: getVersion() };
87
87
  }
88
88
  if (os.platform() === 'win32') {
89
- return { installed: false, skipped: true, reason: 'windows requires manual install: https://github.com/rtk-ai/rtk/releases' };
89
+ // RTK publishes a Windows build; ECC just never downloaded it and told the
90
+ // user to do it by hand. Only x86_64 is published, which is fine on arm64
91
+ // Windows because it runs x64 binaries under emulation.
92
+ const win = require('../lib/win-install.js');
93
+ const r = win.installFromRelease({
94
+ repo: 'rtk-ai/rtk',
95
+ asset: 'rtk-x86_64-pc-windows-msvc.zip',
96
+ binName: 'rtk.exe',
97
+ log,
98
+ });
99
+ if (!r.installed) {
100
+ return { installed: false, skipped: true, reason: `${r.reason} — or install by hand: https://github.com/rtk-ai/rtk/releases` };
101
+ }
102
+ if (!isInstalled()) {
103
+ return { installed: false, skipped: true, reason: `installed to ${r.dir} but not runnable from PATH` };
104
+ }
105
+ return {
106
+ installed: true,
107
+ method: 'github-release',
108
+ version: getVersion(),
109
+ dir: r.dir,
110
+ // Reported so the caller can tell the user what is still needed. PATH is
111
+ // not edited for them — that is their environment to change.
112
+ pathHint: r.onPath ? null : win.setxHint(r.dir),
113
+ };
90
114
  }
91
115
 
92
116
  // Try Homebrew first on macOS.