contextecf-codeledger 0.10.7

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/LICENSE ADDED
@@ -0,0 +1,61 @@
1
+ CodeLedger Core Engine License
2
+ Version 1.0, 2025
3
+
4
+ Copyright (c) 2025 Intelligent Context AI, Inc.
5
+ All rights reserved.
6
+
7
+ GRANT OF LICENSE
8
+
9
+ Subject to the terms of this license, Intelligent Context AI, Inc. ("Licensor")
10
+ grants you a non-exclusive, non-transferable, revocable license to use the
11
+ CodeLedger Core Engine binary ("Software") under the following conditions:
12
+
13
+ 1. INDIVIDUAL USE (FREE)
14
+ You may use the Software for personal, non-commercial development work
15
+ at no cost. This includes individual developers using the Software on
16
+ their own projects or contributing to open-source projects.
17
+
18
+ 2. OPEN-SOURCE PROJECTS (FREE)
19
+ You may use the Software in open-source projects licensed under
20
+ OSI-approved licenses at no cost.
21
+
22
+ 3. COMMERCIAL USE (LICENSE REQUIRED)
23
+ Use of the Software in commercial settings, including but not limited to:
24
+ - CI/CD pipelines
25
+ - Team development environments (>1 developer)
26
+ - Enterprise deployments
27
+ - Products or services that incorporate the Software
28
+ requires a CodeLedger Pro license. Contact team@codeledger.dev for pricing.
29
+
30
+ RESTRICTIONS
31
+
32
+ You may NOT:
33
+ - Reverse engineer, decompile, or disassemble the Software
34
+ - Redistribute the Software as a standalone product
35
+ - Remove or modify any license notices or proprietary markings
36
+ - Use the Software to build a competing product or service
37
+
38
+ PRIVACY GUARANTEE
39
+
40
+ The Software:
41
+ - Runs entirely on your local machine
42
+ - Makes no network calls
43
+ - Collects no telemetry, analytics, or usage data
44
+ - Does not transmit your source code or any data to external services
45
+
46
+ DISCLAIMER
47
+
48
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49
+ IMPLIED. IN NO EVENT SHALL THE LICENSOR BE LIABLE FOR ANY CLAIM, DAMAGES, OR
50
+ OTHER LIABILITY ARISING FROM THE USE OF THE SOFTWARE.
51
+
52
+ TERMINATION
53
+
54
+ This license terminates automatically if you breach any of its terms.
55
+ Upon termination, you must destroy all copies of the Software.
56
+
57
+ CONTACT
58
+
59
+ Intelligent Context AI, Inc.
60
+ team@codeledger.dev
61
+ https://codeledger.dev/license
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # contextecf-codeledger — CodeLedger by ContextECF
2
+
3
+ **Deterministic, bounded context selection for AI coding agents.**
4
+ Published by [ContextECF](https://codeledger.dev) (Intelligent Context AI, Inc.).
5
+
6
+ This is the **unscoped mirror** of [`@codeledger/cli`](https://www.npmjs.com/package/@codeledger/cli). Both packages install the exact same binary. Use whichever you prefer:
7
+
8
+ ```bash
9
+ npm install -g contextecf-codeledger # this package
10
+ npm install -g @codeledger/cli # scoped original
11
+ ```
12
+
13
+ ## Why two packages?
14
+
15
+ An unrelated package named `codeledger` (unscoped, no `@`) exists on npm by a different author. AI coding agents often guess `npm install codeledger` and install the wrong thing. This unscoped `contextecf-codeledger` package gives agents (and humans) a discoverable name that works on the first try.
16
+
17
+ ## Quick start
18
+
19
+ ```bash
20
+ codeledger init
21
+ codeledger activate --task "describe your task"
22
+ codeledger mcp start # for Claude Desktop / Cursor MCP integration
23
+ ```
24
+
25
+ ## Links
26
+
27
+ - Website: https://codeledger.dev
28
+ - Demo: https://demo.codeledger.dev
29
+ - Source: https://github.com/codeledgerECF/codeledger
30
+ - npm (scoped): https://www.npmjs.com/package/@codeledger/cli
31
+ - npm (unscoped): https://www.npmjs.com/package/contextecf-codeledger
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * CodeLedger npm launcher — thin shim (unscoped mirror).
4
+ *
5
+ * This is the unscoped mirror of @codeledger/cli. Both packages install
6
+ * the exact same hardened binary. You can install either:
7
+ *
8
+ * npm install -g contextecf-codeledger (this package)
9
+ * npm install -g @codeledger/cli (scoped original)
10
+ *
11
+ * This file contains no engine code. All CodeLedger functionality lives
12
+ * inside the hardened binary downloaded during postinstall.
13
+ */
14
+
15
+ 'use strict';
16
+
17
+ const { spawnSync } = require('node:child_process');
18
+ const { existsSync } = require('node:fs');
19
+ const { join } = require('node:path');
20
+ const { homedir, platform } = require('node:os');
21
+
22
+ const { version } = require('../package.json');
23
+
24
+ const CACHE_DIR =
25
+ process.env.CODELEDGER_CACHE_DIR ||
26
+ join(homedir(), '.cache', 'codeledger', 'bin');
27
+
28
+ const BINARY_NAME =
29
+ platform() === 'win32'
30
+ ? `codeledger-hardened-v${version}.exe`
31
+ : `codeledger-hardened-v${version}`;
32
+
33
+ const BINARY_PATH = join(CACHE_DIR, BINARY_NAME);
34
+
35
+ function die(msg, code = 1) {
36
+ process.stderr.write(`codeledger: ${msg}\n`);
37
+ process.exit(code);
38
+ }
39
+
40
+ if (!existsSync(BINARY_PATH)) {
41
+ const installerPath = join(__dirname, '..', 'scripts', 'postinstall.js');
42
+ die(
43
+ [
44
+ `hardened binary for v${version} not found at ${BINARY_PATH}.`,
45
+ '',
46
+ 'The postinstall step may have been skipped (e.g. --ignore-scripts).',
47
+ 'Recover with one of:',
48
+ ` 1. npm rebuild contextecf-codeledger`,
49
+ ` 2. node "${installerPath}"`,
50
+ ` 3. Re-run the install without --ignore-scripts`,
51
+ '',
52
+ 'Or download the binary manually from:',
53
+ ` https://github.com/codeledgerECF/codeledger/releases/tag/v${version}`,
54
+ ].join('\n'),
55
+ );
56
+ }
57
+
58
+ const result = spawnSync(BINARY_PATH, process.argv.slice(2), {
59
+ stdio: 'inherit',
60
+ env: process.env,
61
+ });
62
+
63
+ if (result.error) {
64
+ die(`failed to spawn binary: ${result.error.message}`);
65
+ }
66
+
67
+ process.exit(result.status ?? 1);
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "contextecf-codeledger",
3
+ "version": "0.10.7",
4
+ "mcpName": "io.github.codeledgerECF/codeledger",
5
+ "description": "CodeLedger by ContextECF — deterministic context selection for AI coding agents. This is the unscoped mirror of @codeledger/cli; both install the same binary.",
6
+ "type": "commonjs",
7
+ "bin": {
8
+ "codeledger": "./bin/codeledger.js"
9
+ },
10
+ "scripts": {
11
+ "postinstall": "node scripts/postinstall.js"
12
+ },
13
+ "files": [
14
+ "bin/",
15
+ "scripts/",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "dependencies": {},
20
+ "engines": {
21
+ "node": ">=18"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "github:codeledgerECF/codeledger-blackbox"
26
+ },
27
+ "license": "SEE LICENSE IN LICENSE",
28
+ "keywords": [
29
+ "codeledger",
30
+ "contextecf",
31
+ "context",
32
+ "ai",
33
+ "claude",
34
+ "cursor",
35
+ "windsurf",
36
+ "codex",
37
+ "mcp",
38
+ "mcp-server"
39
+ ],
40
+ "publishConfig": {
41
+ "access": "public"
42
+ }
43
+ }
@@ -0,0 +1,285 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * CodeLedger postinstall — download + verify the hardened binary.
4
+ *
5
+ * Runs automatically on `npm install -g @codeledger/cli`. Downloads the
6
+ * platform-specific hardened binary from the GitHub Release for this
7
+ * exact version, verifies its SHA256 against SHA256SUMS-v<version>.txt
8
+ * (also downloaded from the release), and writes it to the cache dir.
9
+ *
10
+ * Environment variables (all optional):
11
+ * CODELEDGER_SKIP_POSTINSTALL=1 — skip entirely (air-gapped installs)
12
+ * CODELEDGER_BINARY_URL=<url> — override the release download base URL
13
+ * (for corporate mirrors / internal CDNs).
14
+ * Must serve the same filenames and a
15
+ * SHA256SUMS-v<version>.txt sibling file.
16
+ * CODELEDGER_CACHE_DIR=<path> — override the cache directory
17
+ * (default: ~/.cache/codeledger/bin)
18
+ *
19
+ * This file contains no engine logic. It only fetches, verifies, and writes
20
+ * bytes. Safe to inspect, safe to mirror, safe to audit.
21
+ */
22
+
23
+ 'use strict';
24
+
25
+ const https = require('node:https');
26
+ const { URL } = require('node:url');
27
+ const { createHash } = require('node:crypto');
28
+ const {
29
+ mkdirSync,
30
+ writeFileSync,
31
+ chmodSync,
32
+ existsSync,
33
+ unlinkSync,
34
+ } = require('node:fs');
35
+ const { join } = require('node:path');
36
+ const { homedir, platform, arch } = require('node:os');
37
+
38
+ const { version } = require('../package.json');
39
+
40
+ // ─── config ──────────────────────────────────────────────────────────────────
41
+
42
+ if (process.env.CODELEDGER_SKIP_POSTINSTALL === '1') {
43
+ console.log(
44
+ 'codeledger: CODELEDGER_SKIP_POSTINSTALL=1 set, skipping hardened binary download.',
45
+ );
46
+ process.exit(0);
47
+ }
48
+
49
+ // Skip when running inside the blackbox monorepo itself (dev mode). The
50
+ // presence of pnpm-workspace.yaml two directories up is a reliable signal
51
+ // that we're not a real end-user install — we're running during `pnpm
52
+ // install` from the workspace root, and the release binary for this
53
+ // version may not even exist yet.
54
+ try {
55
+ const path = require('node:path');
56
+ const fs = require('node:fs');
57
+ const workspaceRoot = path.resolve(__dirname, '..', '..', '..');
58
+ if (fs.existsSync(path.join(workspaceRoot, 'pnpm-workspace.yaml'))) {
59
+ console.log(
60
+ 'codeledger: in-workspace dev install detected, skipping hardened binary download.',
61
+ );
62
+ process.exit(0);
63
+ }
64
+ } catch {
65
+ // fall through to normal install
66
+ }
67
+
68
+ // darwin-x64 is temporarily absent from v0.10.6 — no working Intel
69
+ // Mac runner on the release CI plan as of 2026-04-09. Intel Mac
70
+ // users hit the "unsupported platform" soft-fail below, which tells
71
+ // them to download manually from the GitHub Release. Re-add when a
72
+ // working Intel Mac runner label exists (see release-dispatch.yml
73
+ // matrix comment).
74
+ const PLATFORM_MAP = {
75
+ 'darwin-arm64': 'darwin-arm64',
76
+ 'linux-x64': 'linux-x64',
77
+ };
78
+
79
+ const platformKey = `${platform()}-${arch()}`;
80
+ const platformSuffix = PLATFORM_MAP[platformKey];
81
+
82
+ if (!platformSuffix) {
83
+ console.error(
84
+ `codeledger: unsupported platform ${platformKey}. Supported: ${Object.keys(
85
+ PLATFORM_MAP,
86
+ ).join(', ')}`,
87
+ );
88
+ console.error(
89
+ `codeledger: v${version} does not provide a hardened binary for ${platformKey}.`,
90
+ );
91
+ console.error(
92
+ 'codeledger: you can still run from source by cloning the blackbox repo.',
93
+ );
94
+ // Fail softly: don't block `npm install` for unsupported platforms. The
95
+ // bin shim will tell the user what happened when they first run `codeledger`.
96
+ process.exit(0);
97
+ }
98
+
99
+ // Binaries are hosted on the PUBLIC codeledgerECF/codeledger repo
100
+ // releases (not the private codeledger-blackbox repo — its release
101
+ // assets are not anonymously downloadable). The release pipeline in
102
+ // codeledger-blackbox builds the binaries, then a promote_binaries
103
+ // job uploads them cross-repo to the public release using a PAT.
104
+ // Users' `npm install -g @codeledger/cli` fetches from the public
105
+ // URL with no auth required.
106
+ const RELEASE_BASE =
107
+ process.env.CODELEDGER_BINARY_URL ||
108
+ `https://github.com/codeledgerECF/codeledger/releases/download/v${version}`;
109
+
110
+ const BINARY_REMOTE_NAME = `codeledger-hardened-${platformSuffix}-v${version}`;
111
+ const BINARY_URL = `${RELEASE_BASE}/${BINARY_REMOTE_NAME}`;
112
+ const CHECKSUMS_URL = `${RELEASE_BASE}/SHA256SUMS-v${version}.txt`;
113
+
114
+ const CACHE_DIR =
115
+ process.env.CODELEDGER_CACHE_DIR ||
116
+ join(homedir(), '.cache', 'codeledger', 'bin');
117
+ const BINARY_LOCAL_NAME = `codeledger-hardened-v${version}`;
118
+ const BINARY_LOCAL_PATH = join(CACHE_DIR, BINARY_LOCAL_NAME);
119
+
120
+ // ─── http ────────────────────────────────────────────────────────────────────
121
+
122
+ function fetchBufferOnce(url, redirectDepth = 0) {
123
+ if (redirectDepth > 5) {
124
+ return Promise.reject(new Error(`too many redirects fetching ${url}`));
125
+ }
126
+ return new Promise((resolve, reject) => {
127
+ const req = https.get(
128
+ url,
129
+ {
130
+ headers: {
131
+ 'User-Agent': `codeledger-installer/${version}`,
132
+ Accept: 'application/octet-stream',
133
+ },
134
+ },
135
+ (res) => {
136
+ if (
137
+ (res.statusCode === 301 ||
138
+ res.statusCode === 302 ||
139
+ res.statusCode === 307 ||
140
+ res.statusCode === 308) &&
141
+ res.headers.location
142
+ ) {
143
+ res.resume();
144
+ const next = new URL(res.headers.location, url).toString();
145
+ fetchBufferOnce(next, redirectDepth + 1).then(resolve, reject);
146
+ return;
147
+ }
148
+ if (res.statusCode !== 200) {
149
+ res.resume();
150
+ const err = new Error(`HTTP ${res.statusCode} fetching ${url}`);
151
+ err.statusCode = res.statusCode;
152
+ reject(err);
153
+ return;
154
+ }
155
+ const chunks = [];
156
+ res.on('data', (c) => chunks.push(c));
157
+ res.on('end', () => resolve(Buffer.concat(chunks)));
158
+ res.on('error', reject);
159
+ },
160
+ );
161
+ req.on('error', reject);
162
+ req.setTimeout(60_000, () => {
163
+ req.destroy(new Error(`timeout fetching ${url}`));
164
+ });
165
+ });
166
+ }
167
+
168
+ // Retry wrapper that tolerates the post-publish race window.
169
+ //
170
+ // The release pipeline publishes the npm wrapper BEFORE the hardened
171
+ // binaries land on the public GitHub release (see the Phase 1d comment
172
+ // in release-dispatch.yml). For up to ~10 minutes after a user first
173
+ // sees @codeledger/cli@<version> on npm, the hardened binary URL may
174
+ // 404. This wrapper retries 404s with exponential backoff (10s, 20s,
175
+ // 40s, 60s, 60s, 60s, 60s, 60s, 60s, 60s → 450s total) so installs
176
+ // during the race window eventually succeed instead of hard-failing.
177
+ //
178
+ // Non-404 errors (DNS, network, timeouts) fail fast — retrying a DNS
179
+ // failure won't help.
180
+ async function fetchBuffer(url) {
181
+ const backoffs = [10, 20, 40, 60, 60, 60, 60, 60, 60, 60]; // seconds
182
+ let lastErr;
183
+ for (let i = 0; i <= backoffs.length; i++) {
184
+ try {
185
+ return await fetchBufferOnce(url);
186
+ } catch (err) {
187
+ lastErr = err;
188
+ // Only retry on 404 — everything else is a hard failure
189
+ if (err.statusCode !== 404) throw err;
190
+ if (i === backoffs.length) break;
191
+ const wait = backoffs[i];
192
+ console.log(
193
+ `codeledger: 404 fetching ${url.split('/').pop()} — retrying in ${wait}s ` +
194
+ `(attempt ${i + 1}/${backoffs.length + 1}, ride race window)`,
195
+ );
196
+ await new Promise((r) => setTimeout(r, wait * 1000));
197
+ }
198
+ }
199
+ throw lastErr;
200
+ }
201
+
202
+ // ─── checksum parsing ───────────────────────────────────────────────────────
203
+
204
+ function findExpectedSha(checksumsText, filename) {
205
+ // SHA256SUMS format: "<hex> <filename>\n" per line (coreutils sha256sum)
206
+ const lines = checksumsText.split('\n');
207
+ for (const line of lines) {
208
+ const trimmed = line.trim();
209
+ if (!trimmed || trimmed.startsWith('#')) continue;
210
+ const parts = trimmed.split(/\s+/);
211
+ if (parts.length < 2) continue;
212
+ const [hex, ...nameParts] = parts;
213
+ const name = nameParts.join(' ').replace(/^\*/, ''); // strip binary-mode prefix
214
+ if (name === filename) {
215
+ return hex.toLowerCase();
216
+ }
217
+ }
218
+ return null;
219
+ }
220
+
221
+ // ─── main ────────────────────────────────────────────────────────────────────
222
+
223
+ async function main() {
224
+ console.log(`codeledger: installing v${version} hardened binary for ${platformKey}`);
225
+ console.log(` source: ${BINARY_URL}`);
226
+
227
+ const [checksumsBuf, binary] = await Promise.all([
228
+ fetchBuffer(CHECKSUMS_URL),
229
+ fetchBuffer(BINARY_URL),
230
+ ]);
231
+ const checksums = checksumsBuf.toString('utf8');
232
+
233
+ const expectedSha = findExpectedSha(checksums, BINARY_REMOTE_NAME);
234
+ if (!expectedSha) {
235
+ throw new Error(
236
+ `${BINARY_REMOTE_NAME} not listed in SHA256SUMS-v${version}.txt — cannot verify binary integrity`,
237
+ );
238
+ }
239
+
240
+ const actualSha = createHash('sha256').update(binary).digest('hex');
241
+ if (actualSha !== expectedSha) {
242
+ throw new Error(
243
+ `SHA256 mismatch for ${BINARY_REMOTE_NAME}:\n expected ${expectedSha}\n got ${actualSha}`,
244
+ );
245
+ }
246
+
247
+ mkdirSync(CACHE_DIR, { recursive: true });
248
+
249
+ // Atomic-ish write: write to tmp, rename
250
+ const tmpPath = `${BINARY_LOCAL_PATH}.tmp`;
251
+ if (existsSync(tmpPath)) unlinkSync(tmpPath);
252
+ writeFileSync(tmpPath, binary);
253
+ chmodSync(tmpPath, 0o755);
254
+ if (existsSync(BINARY_LOCAL_PATH)) unlinkSync(BINARY_LOCAL_PATH);
255
+ // rename via fs for portability
256
+ require('node:fs').renameSync(tmpPath, BINARY_LOCAL_PATH);
257
+
258
+ console.log(`codeledger: installed ${BINARY_LOCAL_PATH}`);
259
+ console.log(` sha256: ${actualSha}`);
260
+ console.log('codeledger: run `codeledger --version` to verify');
261
+ }
262
+
263
+ // Only run main() when invoked directly (npm postinstall, node scripts/postinstall.js).
264
+ // When require()'d from tests, just export the helper functions.
265
+ if (require.main === module) {
266
+ main().catch((err) => {
267
+ console.error(`codeledger: postinstall failed — ${err.message}`);
268
+ console.error('');
269
+ console.error('Recovery options:');
270
+ console.error(' 1. Retry: npm rebuild @codeledger/cli');
271
+ console.error(' 2. Air-gapped install:');
272
+ console.error(' CODELEDGER_SKIP_POSTINSTALL=1 npm install -g @codeledger/cli');
273
+ console.error(' then manually place the binary at:');
274
+ console.error(` ${BINARY_LOCAL_PATH}`);
275
+ console.error(' 3. Use a mirror:');
276
+ console.error(' CODELEDGER_BINARY_URL=https://your-mirror/path npm install -g @codeledger/cli');
277
+ console.error('');
278
+ console.error(
279
+ `Manual download: https://github.com/codeledgerECF/codeledger-blackbox/releases/tag/v${version}`,
280
+ );
281
+ process.exit(1);
282
+ });
283
+ }
284
+
285
+ module.exports = { findExpectedSha, PLATFORM_MAP };