@opencodehub/cli 0.1.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/LICENSE +202 -0
- package/README.md +85 -0
- package/dist/agent-context.d.ts +54 -0
- package/dist/agent-context.d.ts.map +1 -0
- package/dist/agent-context.js +122 -0
- package/dist/agent-context.js.map +1 -0
- package/dist/cobol-proleap-setup.d.ts +77 -0
- package/dist/cobol-proleap-setup.d.ts.map +1 -0
- package/dist/cobol-proleap-setup.js +289 -0
- package/dist/cobol-proleap-setup.js.map +1 -0
- package/dist/commands/analyze.d.ts +234 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +1096 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/augment.d.ts +48 -0
- package/dist/commands/augment.d.ts.map +1 -0
- package/dist/commands/augment.js +249 -0
- package/dist/commands/augment.js.map +1 -0
- package/dist/commands/baseline.d.ts +68 -0
- package/dist/commands/baseline.d.ts.map +1 -0
- package/dist/commands/baseline.js +110 -0
- package/dist/commands/baseline.js.map +1 -0
- package/dist/commands/bench.d.ts +54 -0
- package/dist/commands/bench.d.ts.map +1 -0
- package/dist/commands/bench.js +283 -0
- package/dist/commands/bench.js.map +1 -0
- package/dist/commands/ci-init.d.ts +37 -0
- package/dist/commands/ci-init.d.ts.map +1 -0
- package/dist/commands/ci-init.js +115 -0
- package/dist/commands/ci-init.js.map +1 -0
- package/dist/commands/clean.d.ts +13 -0
- package/dist/commands/clean.d.ts.map +1 -0
- package/dist/commands/clean.js +38 -0
- package/dist/commands/clean.js.map +1 -0
- package/dist/commands/code-pack.d.ts +105 -0
- package/dist/commands/code-pack.d.ts.map +1 -0
- package/dist/commands/code-pack.js +187 -0
- package/dist/commands/code-pack.js.map +1 -0
- package/dist/commands/context.d.ts +30 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +237 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/detect-changes.d.ts +26 -0
- package/dist/commands/detect-changes.d.ts.map +1 -0
- package/dist/commands/detect-changes.js +73 -0
- package/dist/commands/detect-changes.js.map +1 -0
- package/dist/commands/doctor.d.ts +52 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +472 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/find-enclosing-symbol.d.ts +67 -0
- package/dist/commands/find-enclosing-symbol.d.ts.map +1 -0
- package/dist/commands/find-enclosing-symbol.js +106 -0
- package/dist/commands/find-enclosing-symbol.js.map +1 -0
- package/dist/commands/group.d.ts +123 -0
- package/dist/commands/group.d.ts.map +1 -0
- package/dist/commands/group.js +448 -0
- package/dist/commands/group.js.map +1 -0
- package/dist/commands/impact.d.ts +23 -0
- package/dist/commands/impact.d.ts.map +1 -0
- package/dist/commands/impact.js +91 -0
- package/dist/commands/impact.js.map +1 -0
- package/dist/commands/index-repo.d.ts +39 -0
- package/dist/commands/index-repo.d.ts.map +1 -0
- package/dist/commands/index-repo.js +148 -0
- package/dist/commands/index-repo.js.map +1 -0
- package/dist/commands/ingest-sarif.d.ts +64 -0
- package/dist/commands/ingest-sarif.d.ts.map +1 -0
- package/dist/commands/ingest-sarif.js +381 -0
- package/dist/commands/ingest-sarif.js.map +1 -0
- package/dist/commands/init.d.ts +75 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +315 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +17 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +79 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/mcp.d.ts +8 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +28 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/open-store.d.ts +25 -0
- package/dist/commands/open-store.d.ts.map +1 -0
- package/dist/commands/open-store.js +47 -0
- package/dist/commands/open-store.js.map +1 -0
- package/dist/commands/pack.d.ts +35 -0
- package/dist/commands/pack.d.ts.map +1 -0
- package/dist/commands/pack.js +83 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/commands/query.d.ts +85 -0
- package/dist/commands/query.d.ts.map +1 -0
- package/dist/commands/query.js +309 -0
- package/dist/commands/query.js.map +1 -0
- package/dist/commands/scan.d.ts +81 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +407 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/setup.d.ts +178 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +370 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/sql.d.ts +19 -0
- package/dist/commands/sql.d.ts.map +1 -0
- package/dist/commands/sql.js +51 -0
- package/dist/commands/sql.js.map +1 -0
- package/dist/commands/status.d.ts +13 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +66 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/verdict-render.d.ts +33 -0
- package/dist/commands/verdict-render.d.ts.map +1 -0
- package/dist/commands/verdict-render.js +123 -0
- package/dist/commands/verdict-render.js.map +1 -0
- package/dist/commands/verdict.d.ts +61 -0
- package/dist/commands/verdict.d.ts.map +1 -0
- package/dist/commands/verdict.js +146 -0
- package/dist/commands/verdict.js.map +1 -0
- package/dist/commands/wiki.d.ts +26 -0
- package/dist/commands/wiki.d.ts.map +1 -0
- package/dist/commands/wiki.js +74 -0
- package/dist/commands/wiki.js.map +1 -0
- package/dist/editors/claude-code.d.ts +23 -0
- package/dist/editors/claude-code.d.ts.map +1 -0
- package/dist/editors/claude-code.js +58 -0
- package/dist/editors/claude-code.js.map +1 -0
- package/dist/editors/codex.d.ts +22 -0
- package/dist/editors/codex.d.ts.map +1 -0
- package/dist/editors/codex.js +59 -0
- package/dist/editors/codex.js.map +1 -0
- package/dist/editors/cursor.d.ts +13 -0
- package/dist/editors/cursor.d.ts.map +1 -0
- package/dist/editors/cursor.js +21 -0
- package/dist/editors/cursor.js.map +1 -0
- package/dist/editors/index.d.ts +12 -0
- package/dist/editors/index.d.ts.map +1 -0
- package/dist/editors/index.js +11 -0
- package/dist/editors/index.js.map +1 -0
- package/dist/editors/opencode.d.ts +23 -0
- package/dist/editors/opencode.d.ts.map +1 -0
- package/dist/editors/opencode.js +61 -0
- package/dist/editors/opencode.js.map +1 -0
- package/dist/editors/types.d.ts +33 -0
- package/dist/editors/types.d.ts.map +1 -0
- package/dist/editors/types.js +19 -0
- package/dist/editors/types.js.map +1 -0
- package/dist/editors/windows-wrap.d.ts +19 -0
- package/dist/editors/windows-wrap.d.ts.map +1 -0
- package/dist/editors/windows-wrap.js +28 -0
- package/dist/editors/windows-wrap.js.map +1 -0
- package/dist/editors/windsurf.d.ts +12 -0
- package/dist/editors/windsurf.d.ts.map +1 -0
- package/dist/editors/windsurf.js +21 -0
- package/dist/editors/windsurf.js.map +1 -0
- package/dist/embedder-downloader.d.ts +87 -0
- package/dist/embedder-downloader.d.ts.map +1 -0
- package/dist/embedder-downloader.js +261 -0
- package/dist/embedder-downloader.js.map +1 -0
- package/dist/fs-atomic.d.ts +22 -0
- package/dist/fs-atomic.d.ts.map +1 -0
- package/dist/fs-atomic.js +28 -0
- package/dist/fs-atomic.js.map +1 -0
- package/dist/groups.d.ts +64 -0
- package/dist/groups.d.ts.map +1 -0
- package/dist/groups.js +172 -0
- package/dist/groups.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +703 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/is-indexed.d.ts +20 -0
- package/dist/lib/is-indexed.d.ts.map +1 -0
- package/dist/lib/is-indexed.js +35 -0
- package/dist/lib/is-indexed.js.map +1 -0
- package/dist/registry.d.ts +64 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +145 -0
- package/dist/registry.js.map +1 -0
- package/dist/scip-downloader.d.ts +138 -0
- package/dist/scip-downloader.d.ts.map +1 -0
- package/dist/scip-downloader.js +372 -0
- package/dist/scip-downloader.js.map +1 -0
- package/dist/scip-pins.d.ts +99 -0
- package/dist/scip-pins.d.ts.map +1 -0
- package/dist/scip-pins.js +195 -0
- package/dist/scip-pins.js.map +1 -0
- package/dist/skills-gen.d.ts +47 -0
- package/dist/skills-gen.d.ts.map +1 -0
- package/dist/skills-gen.js +292 -0
- package/dist/skills-gen.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHA256-pinned downloader for gte-modernbert-base weights.
|
|
3
|
+
*
|
|
4
|
+
* Resolves the target directory via {@link resolveModelDir}, then for each
|
|
5
|
+
* pinned file in {@link GTE_MODERNBERT_BASE_PINS}:
|
|
6
|
+
* 1. Skip when the file already exists and its SHA256 matches the pin.
|
|
7
|
+
* 2. Otherwise stream-download to `<target>.tmp`, hash during write, verify
|
|
8
|
+
* hash, and atomically rename to the final path.
|
|
9
|
+
*
|
|
10
|
+
* Retries transient network errors (ECONNRESET / timeout / 5xx) up to 3 times
|
|
11
|
+
* with exponential backoff (100ms, 500ms, 2s). A SHA256 mismatch is a hard
|
|
12
|
+
* error — the `.tmp` file is deleted and the error thrown. We never ship
|
|
13
|
+
* weights that don't match the pin.
|
|
14
|
+
*
|
|
15
|
+
* All disk access is streaming; we never buffer a 596 MB file in memory.
|
|
16
|
+
*/
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
18
|
+
import { createReadStream, createWriteStream } from "node:fs";
|
|
19
|
+
import { mkdir, rename, stat, unlink } from "node:fs/promises";
|
|
20
|
+
import { dirname, join } from "node:path";
|
|
21
|
+
import { Readable, Writable } from "node:stream";
|
|
22
|
+
import { pipeline as streamPipeline } from "node:stream/promises";
|
|
23
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
24
|
+
import { GTE_MODERNBERT_BASE_PINS, resolveModelDir } from "@opencodehub/embedder";
|
|
25
|
+
const DEFAULT_BACKOFF_MS = [100, 500, 2000];
|
|
26
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
27
|
+
/**
|
|
28
|
+
* Thrown when a downloaded file's SHA256 doesn't match the pinned value.
|
|
29
|
+
*
|
|
30
|
+
* The temp file is deleted before this throws so partial corrupt payloads
|
|
31
|
+
* never linger on disk.
|
|
32
|
+
*/
|
|
33
|
+
export class Sha256MismatchError extends Error {
|
|
34
|
+
code = "EMBEDDER_SHA256_MISMATCH";
|
|
35
|
+
fileName;
|
|
36
|
+
expected;
|
|
37
|
+
actual;
|
|
38
|
+
constructor(fileName, expected, actual) {
|
|
39
|
+
super(`SHA256 mismatch for ${fileName}: expected ${expected}, got ${actual}`);
|
|
40
|
+
this.name = "Sha256MismatchError";
|
|
41
|
+
this.fileName = fileName;
|
|
42
|
+
this.expected = expected;
|
|
43
|
+
this.actual = actual;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Thrown for all non-hash download failures (404, network, etc.). Carries the
|
|
48
|
+
* URL in the message so operators can reproduce with curl.
|
|
49
|
+
*/
|
|
50
|
+
export class DownloadError extends Error {
|
|
51
|
+
code = "EMBEDDER_DOWNLOAD_FAILED";
|
|
52
|
+
url;
|
|
53
|
+
constructor(url, message, options) {
|
|
54
|
+
super(`Download failed for ${url}: ${message}`, options);
|
|
55
|
+
this.name = "DownloadError";
|
|
56
|
+
this.url = url;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Hash an existing file on disk in streaming fashion.
|
|
61
|
+
*
|
|
62
|
+
* Returns `undefined` if the file does not exist — callers use that as the
|
|
63
|
+
* "not yet downloaded" signal rather than a dedicated stat() probe.
|
|
64
|
+
*/
|
|
65
|
+
async function hashFileIfExists(path) {
|
|
66
|
+
try {
|
|
67
|
+
await stat(path);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
const hasher = createHash("sha256");
|
|
73
|
+
const rs = createReadStream(path);
|
|
74
|
+
await streamPipeline(rs, new Writable({
|
|
75
|
+
write(chunk, _enc, cb) {
|
|
76
|
+
// Convert Buffer → Uint8Array view so strict TS typings accept it.
|
|
77
|
+
hasher.update(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength));
|
|
78
|
+
cb();
|
|
79
|
+
},
|
|
80
|
+
}));
|
|
81
|
+
return hasher.digest("hex");
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Decide whether a network error is retryable. We treat `ECONNRESET`,
|
|
85
|
+
* `ETIMEDOUT`, `EAI_AGAIN`, `ECONNREFUSED`, generic `AbortError` on timeout,
|
|
86
|
+
* and 5xx HTTP responses as transient. SHA mismatch and 4xx are permanent.
|
|
87
|
+
*/
|
|
88
|
+
function isRetryableError(err) {
|
|
89
|
+
if (err instanceof Sha256MismatchError)
|
|
90
|
+
return false;
|
|
91
|
+
if (!(err instanceof Error))
|
|
92
|
+
return false;
|
|
93
|
+
const transientCodes = new Set([
|
|
94
|
+
"ECONNRESET",
|
|
95
|
+
"ETIMEDOUT",
|
|
96
|
+
"EAI_AGAIN",
|
|
97
|
+
"ECONNREFUSED",
|
|
98
|
+
"ENETUNREACH",
|
|
99
|
+
"UND_ERR_SOCKET",
|
|
100
|
+
]);
|
|
101
|
+
// Walk the error + its .cause chain; the network-layer code lives on the
|
|
102
|
+
// underlying cause when we've wrapped the error as a DownloadError.
|
|
103
|
+
let cur = err;
|
|
104
|
+
let hops = 0;
|
|
105
|
+
while (cur instanceof Error && hops < 8) {
|
|
106
|
+
const codeCandidate = cur.code;
|
|
107
|
+
if (typeof codeCandidate === "string" && transientCodes.has(codeCandidate)) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
cur = cur.cause;
|
|
111
|
+
hops += 1;
|
|
112
|
+
}
|
|
113
|
+
// DownloadError with a 5xx status is retryable; the message encodes the code.
|
|
114
|
+
if (err instanceof DownloadError && /HTTP 5\d\d/.test(err.message)) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Stream one pinned file to disk. Hash-as-we-write, verify, and atomic rename.
|
|
121
|
+
* Does NOT retry — that's the caller's job via {@link withRetry}.
|
|
122
|
+
*/
|
|
123
|
+
async function downloadOne(pin, targetPath, fetchImpl) {
|
|
124
|
+
const tmpPath = `${targetPath}.tmp`;
|
|
125
|
+
// Best-effort cleanup of any stale tmp from a previous failed run.
|
|
126
|
+
try {
|
|
127
|
+
await unlink(tmpPath);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Doesn't exist — fine.
|
|
131
|
+
}
|
|
132
|
+
let res;
|
|
133
|
+
try {
|
|
134
|
+
res = await fetchImpl(pin.url, { redirect: "follow" });
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
throw new DownloadError(pin.url, err instanceof Error ? err.message : String(err), err instanceof Error ? { cause: err } : undefined);
|
|
138
|
+
}
|
|
139
|
+
if (!res.ok) {
|
|
140
|
+
throw new DownloadError(pin.url, `HTTP ${res.status} ${res.statusText}`);
|
|
141
|
+
}
|
|
142
|
+
if (res.body === null) {
|
|
143
|
+
throw new DownloadError(pin.url, "response body is null");
|
|
144
|
+
}
|
|
145
|
+
const hasher = createHash("sha256");
|
|
146
|
+
let bytesWritten = 0;
|
|
147
|
+
const writeStream = createWriteStream(tmpPath);
|
|
148
|
+
// Web ReadableStream → Node Readable bridge. `fetch` returns a Web stream
|
|
149
|
+
// in all Node releases we support (>=20). We assert through the Node
|
|
150
|
+
// stream/web type because `fetch`'s global typings reference lib.dom which
|
|
151
|
+
// we deliberately exclude from this package.
|
|
152
|
+
const bodyAsNode = Readable.fromWeb(res.body);
|
|
153
|
+
try {
|
|
154
|
+
await streamPipeline(bodyAsNode, new Writable({
|
|
155
|
+
write(chunk, _enc, cb) {
|
|
156
|
+
const view = new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
|
157
|
+
hasher.update(view);
|
|
158
|
+
bytesWritten += chunk.byteLength;
|
|
159
|
+
if (!writeStream.write(chunk)) {
|
|
160
|
+
writeStream.once("drain", () => cb());
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
cb();
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
final(cb) {
|
|
167
|
+
writeStream.end(() => cb());
|
|
168
|
+
},
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
// Clean up partial tmp before bubbling — no corrupt files on disk.
|
|
173
|
+
try {
|
|
174
|
+
await unlink(tmpPath);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// Nothing to do.
|
|
178
|
+
}
|
|
179
|
+
throw new DownloadError(pin.url, err instanceof Error ? err.message : String(err), err instanceof Error ? { cause: err } : undefined);
|
|
180
|
+
}
|
|
181
|
+
const actual = hasher.digest("hex");
|
|
182
|
+
if (actual !== pin.sha256) {
|
|
183
|
+
try {
|
|
184
|
+
await unlink(tmpPath);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
// Nothing to do.
|
|
188
|
+
}
|
|
189
|
+
throw new Sha256MismatchError(pin.name, pin.sha256, actual);
|
|
190
|
+
}
|
|
191
|
+
await rename(tmpPath, targetPath);
|
|
192
|
+
return bytesWritten;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Run `task` with exponential backoff. The error type determines whether a
|
|
196
|
+
* retry is attempted; non-transient errors bubble immediately.
|
|
197
|
+
*/
|
|
198
|
+
async function withRetry(task, maxRetries, backoffMs) {
|
|
199
|
+
let lastErr;
|
|
200
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
201
|
+
try {
|
|
202
|
+
return await task();
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
lastErr = err;
|
|
206
|
+
if (!isRetryableError(err) || attempt === maxRetries - 1) {
|
|
207
|
+
throw err;
|
|
208
|
+
}
|
|
209
|
+
const waitMs = backoffMs[attempt] ?? backoffMs[backoffMs.length - 1] ?? 0;
|
|
210
|
+
if (waitMs > 0) {
|
|
211
|
+
await delay(waitMs);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Unreachable — the loop always either returns or throws.
|
|
216
|
+
throw lastErr;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Download every pinned file for the requested variant, skipping files whose
|
|
220
|
+
* on-disk SHA256 already matches the pin (unless `force` is set).
|
|
221
|
+
*
|
|
222
|
+
* Returns `{downloaded, skipped, totalBytes}` where `totalBytes` counts the
|
|
223
|
+
* newly-downloaded bytes only (skipped files are not re-hashed into the
|
|
224
|
+
* total).
|
|
225
|
+
*/
|
|
226
|
+
export async function downloadEmbedderWeights(opts) {
|
|
227
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
228
|
+
if (typeof fetchImpl !== "function") {
|
|
229
|
+
throw new Error("Global fetch is not available. Node >= 18 required; supply opts.fetchImpl otherwise.");
|
|
230
|
+
}
|
|
231
|
+
const maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
232
|
+
const backoffMs = opts.backoffMs ?? DEFAULT_BACKOFF_MS;
|
|
233
|
+
const modelDir = resolveModelDir(opts.modelDir, opts.variant);
|
|
234
|
+
await mkdir(modelDir, { recursive: true });
|
|
235
|
+
const files = GTE_MODERNBERT_BASE_PINS[opts.variant].files;
|
|
236
|
+
let downloaded = 0;
|
|
237
|
+
let skipped = 0;
|
|
238
|
+
let totalBytes = 0;
|
|
239
|
+
for (let i = 0; i < files.length; i++) {
|
|
240
|
+
const pin = files[i];
|
|
241
|
+
const target = join(modelDir, pin.name);
|
|
242
|
+
const pct = Math.round((i / files.length) * 100);
|
|
243
|
+
opts.onProgress?.(pct, pin.name);
|
|
244
|
+
if (!opts.force) {
|
|
245
|
+
const existing = await hashFileIfExists(target);
|
|
246
|
+
if (existing === pin.sha256) {
|
|
247
|
+
skipped += 1;
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Ensure parent dir exists (target itself lives directly under modelDir
|
|
252
|
+
// so this is mostly belt-and-suspenders for unusual overrides).
|
|
253
|
+
await mkdir(dirname(target), { recursive: true });
|
|
254
|
+
const bytes = await withRetry(() => downloadOne(pin, target, fetchImpl), maxRetries, backoffMs);
|
|
255
|
+
downloaded += 1;
|
|
256
|
+
totalBytes += bytes;
|
|
257
|
+
}
|
|
258
|
+
opts.onProgress?.(100, "done");
|
|
259
|
+
return { downloaded, skipped, totalBytes, modelDir };
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=embedder-downloader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedder-downloader.js","sourceRoot":"","sources":["../src/embedder-downloader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin async wrapper around `write-file-atomic` that encodes our invariants:
|
|
3
|
+
* - always UTF-8
|
|
4
|
+
* - always fsync the temp file before rename
|
|
5
|
+
* - always a trailing newline (makes diffs readable across editors)
|
|
6
|
+
*
|
|
7
|
+
* `write-file-atomic` already handles the pid/ts-suffixed temp file, fsync, and
|
|
8
|
+
* atomic rename. We centralize the import so the rest of the package depends on
|
|
9
|
+
* a single import shape — and so tests can swap in an in-memory implementation
|
|
10
|
+
* via dependency injection if they want.
|
|
11
|
+
*/
|
|
12
|
+
export interface WriteAtomicOptions {
|
|
13
|
+
readonly mode?: number;
|
|
14
|
+
/** If true, do not add a trailing newline. Defaults to false. */
|
|
15
|
+
readonly raw?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Write `contents` to `path` atomically. The parent directory must already
|
|
19
|
+
* exist — callers that cannot guarantee that should `mkdir -p` first.
|
|
20
|
+
*/
|
|
21
|
+
export declare function writeFileAtomic(path: string, contents: string, opts?: WriteAtomicOptions): Promise<void>;
|
|
22
|
+
//# sourceMappingURL=fs-atomic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-atomic.d.ts","sourceRoot":"","sources":["../src/fs-atomic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAUf"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin async wrapper around `write-file-atomic` that encodes our invariants:
|
|
3
|
+
* - always UTF-8
|
|
4
|
+
* - always fsync the temp file before rename
|
|
5
|
+
* - always a trailing newline (makes diffs readable across editors)
|
|
6
|
+
*
|
|
7
|
+
* `write-file-atomic` already handles the pid/ts-suffixed temp file, fsync, and
|
|
8
|
+
* atomic rename. We centralize the import so the rest of the package depends on
|
|
9
|
+
* a single import shape — and so tests can swap in an in-memory implementation
|
|
10
|
+
* via dependency injection if they want.
|
|
11
|
+
*/
|
|
12
|
+
import { default as wfa } from "write-file-atomic";
|
|
13
|
+
/**
|
|
14
|
+
* Write `contents` to `path` atomically. The parent directory must already
|
|
15
|
+
* exist — callers that cannot guarantee that should `mkdir -p` first.
|
|
16
|
+
*/
|
|
17
|
+
export async function writeFileAtomic(path, contents, opts = {}) {
|
|
18
|
+
const payload = opts.raw === true || contents.endsWith("\n") ? contents : `${contents}\n`;
|
|
19
|
+
const writeOpts = {
|
|
20
|
+
encoding: "utf8",
|
|
21
|
+
fsync: true,
|
|
22
|
+
};
|
|
23
|
+
if (opts.mode !== undefined) {
|
|
24
|
+
writeOpts.mode = opts.mode;
|
|
25
|
+
}
|
|
26
|
+
await wfa(path, payload, writeOpts);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=fs-atomic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-atomic.js","sourceRoot":"","sources":["../src/fs-atomic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAQnD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,QAAgB,EAChB,OAA2B,EAAE;IAE7B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,KAAK,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,CAAC;IAC1F,MAAM,SAAS,GAAgE;QAC7E,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,IAAI;KACZ,CAAC;IACF,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,SAAS,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IAC7B,CAAC;IACD,MAAM,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;AACtC,CAAC"}
|
package/dist/groups.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-repo group registry at `~/.codehub/groups/<name>.json`.
|
|
3
|
+
*
|
|
4
|
+
* A group is a named bundle of already-indexed repos. Each group lives in its
|
|
5
|
+
* own JSON file so that:
|
|
6
|
+
* - `write-file-atomic` rewrites of one group never serialize against another,
|
|
7
|
+
* - deletion is a single `unlink`, and
|
|
8
|
+
* - additive use (two users sharing `~/.codehub` via sync) sees minimal
|
|
9
|
+
* conflicts.
|
|
10
|
+
*
|
|
11
|
+
* The on-disk shape is intentionally minimal (name + createdAt + repos[] +
|
|
12
|
+
* optional description). Callers that need richer metadata should compose
|
|
13
|
+
* against `~/.codehub/registry.json` via `readRegistry` at call time — we do
|
|
14
|
+
* NOT duplicate per-repo stats into the group file.
|
|
15
|
+
*
|
|
16
|
+
* Determinism: `repos[]` is sorted by `name` on every write; on-disk JSON ends
|
|
17
|
+
* with a single trailing newline; writes go through `write-file-atomic`. Group
|
|
18
|
+
* names must be filesystem-safe (`[a-z0-9_-]+`) and are validated before any
|
|
19
|
+
* filesystem call.
|
|
20
|
+
*/
|
|
21
|
+
/** Per-group subdirectory under `~/.codehub`. */
|
|
22
|
+
export declare const GROUPS_DIR_NAME = "groups";
|
|
23
|
+
/** Allowed group names. Matches a single path segment that is safe on macOS, Linux, and Windows. */
|
|
24
|
+
export declare const GROUP_NAME_PATTERN: RegExp;
|
|
25
|
+
export interface GroupRepo {
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly path: string;
|
|
28
|
+
}
|
|
29
|
+
export interface GroupEntry {
|
|
30
|
+
readonly name: string;
|
|
31
|
+
readonly createdAt: string;
|
|
32
|
+
readonly repos: readonly GroupRepo[];
|
|
33
|
+
readonly description?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface GroupsOptions {
|
|
36
|
+
/** Override `~` root used to locate `~/.codehub/groups` (tests pass a tmpdir). */
|
|
37
|
+
readonly home?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Validate a group name up front so we never create filesystem paths from
|
|
41
|
+
* arbitrary user input. Throws on bad names.
|
|
42
|
+
*/
|
|
43
|
+
export declare function assertValidGroupName(name: string): void;
|
|
44
|
+
/** Resolve the absolute path of the `groups/` directory. */
|
|
45
|
+
export declare function resolveGroupsDir(opts?: GroupsOptions): string;
|
|
46
|
+
/** Resolve the absolute path of a group's JSON file. */
|
|
47
|
+
export declare function resolveGroupFile(name: string, opts?: GroupsOptions): string;
|
|
48
|
+
/** Read a single group by name. Returns `null` when the file does not exist. */
|
|
49
|
+
export declare function readGroup(name: string, opts?: GroupsOptions): Promise<GroupEntry | null>;
|
|
50
|
+
/**
|
|
51
|
+
* Write a group to disk atomically. The `repos` array is sorted by `name` so
|
|
52
|
+
* byte-for-byte output is stable across invocations. Creates the parent
|
|
53
|
+
* directory when missing.
|
|
54
|
+
*/
|
|
55
|
+
export declare function writeGroup(group: GroupEntry, opts?: GroupsOptions): Promise<void>;
|
|
56
|
+
/** Delete a group. Returns `true` if the file existed, `false` otherwise. */
|
|
57
|
+
export declare function deleteGroup(name: string, opts?: GroupsOptions): Promise<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* Enumerate every group under `~/.codehub/groups`. Returned entries are
|
|
60
|
+
* sorted by name. Unreadable/malformed files are skipped with an error logged
|
|
61
|
+
* to stderr rather than tearing down the caller.
|
|
62
|
+
*/
|
|
63
|
+
export declare function listGroups(opts?: GroupsOptions): Promise<readonly GroupEntry[]>;
|
|
64
|
+
//# sourceMappingURL=groups.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groups.d.ts","sourceRoot":"","sources":["../src/groups.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AASH,iDAAiD;AACjD,eAAO,MAAM,eAAe,WAAW,CAAC;AAExC,oGAAoG;AACpG,eAAO,MAAM,kBAAkB,QAAkB,CAAC;AAElD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;IACrC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAOvD;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,aAAkB,GAAG,MAAM,CAGjE;AAED,wDAAwD;AACxD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAG/E;AAED,gFAAgF;AAChF,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAY5B;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAe3F;AAED,6EAA6E;AAC7E,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAU1F;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,SAAS,UAAU,EAAE,CAAC,CA0BzF"}
|
package/dist/groups.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-repo group registry at `~/.codehub/groups/<name>.json`.
|
|
3
|
+
*
|
|
4
|
+
* A group is a named bundle of already-indexed repos. Each group lives in its
|
|
5
|
+
* own JSON file so that:
|
|
6
|
+
* - `write-file-atomic` rewrites of one group never serialize against another,
|
|
7
|
+
* - deletion is a single `unlink`, and
|
|
8
|
+
* - additive use (two users sharing `~/.codehub` via sync) sees minimal
|
|
9
|
+
* conflicts.
|
|
10
|
+
*
|
|
11
|
+
* The on-disk shape is intentionally minimal (name + createdAt + repos[] +
|
|
12
|
+
* optional description). Callers that need richer metadata should compose
|
|
13
|
+
* against `~/.codehub/registry.json` via `readRegistry` at call time — we do
|
|
14
|
+
* NOT duplicate per-repo stats into the group file.
|
|
15
|
+
*
|
|
16
|
+
* Determinism: `repos[]` is sorted by `name` on every write; on-disk JSON ends
|
|
17
|
+
* with a single trailing newline; writes go through `write-file-atomic`. Group
|
|
18
|
+
* names must be filesystem-safe (`[a-z0-9_-]+`) and are validated before any
|
|
19
|
+
* filesystem call.
|
|
20
|
+
*/
|
|
21
|
+
// biome-ignore-all lint/complexity/useLiteralKeys: dot-access disallowed on Record index signatures
|
|
22
|
+
import { mkdir, readdir, readFile, unlink } from "node:fs/promises";
|
|
23
|
+
import { homedir } from "node:os";
|
|
24
|
+
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
25
|
+
import { writeFileAtomic } from "./fs-atomic.js";
|
|
26
|
+
import { CODEHUB_HOME_DIR } from "./registry.js";
|
|
27
|
+
/** Per-group subdirectory under `~/.codehub`. */
|
|
28
|
+
export const GROUPS_DIR_NAME = "groups";
|
|
29
|
+
/** Allowed group names. Matches a single path segment that is safe on macOS, Linux, and Windows. */
|
|
30
|
+
export const GROUP_NAME_PATTERN = /^[a-z0-9_-]+$/;
|
|
31
|
+
/**
|
|
32
|
+
* Validate a group name up front so we never create filesystem paths from
|
|
33
|
+
* arbitrary user input. Throws on bad names.
|
|
34
|
+
*/
|
|
35
|
+
export function assertValidGroupName(name) {
|
|
36
|
+
if (!GROUP_NAME_PATTERN.test(name)) {
|
|
37
|
+
throw new Error(`Invalid group name "${name}". Names must match ${GROUP_NAME_PATTERN} ` +
|
|
38
|
+
"(lowercase letters, digits, underscore, hyphen).");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Resolve the absolute path of the `groups/` directory. */
|
|
42
|
+
export function resolveGroupsDir(opts = {}) {
|
|
43
|
+
const home = opts.home ?? homedir();
|
|
44
|
+
return resolve(home, CODEHUB_HOME_DIR, GROUPS_DIR_NAME);
|
|
45
|
+
}
|
|
46
|
+
/** Resolve the absolute path of a group's JSON file. */
|
|
47
|
+
export function resolveGroupFile(name, opts = {}) {
|
|
48
|
+
assertValidGroupName(name);
|
|
49
|
+
return join(resolveGroupsDir(opts), `${name}.json`);
|
|
50
|
+
}
|
|
51
|
+
/** Read a single group by name. Returns `null` when the file does not exist. */
|
|
52
|
+
export async function readGroup(name, opts = {}) {
|
|
53
|
+
assertValidGroupName(name);
|
|
54
|
+
const file = resolveGroupFile(name, opts);
|
|
55
|
+
let raw;
|
|
56
|
+
try {
|
|
57
|
+
raw = await readFile(file, "utf8");
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
if (err.code === "ENOENT")
|
|
61
|
+
return null;
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
const parsed = JSON.parse(raw);
|
|
65
|
+
return validateGroup(parsed, file);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Write a group to disk atomically. The `repos` array is sorted by `name` so
|
|
69
|
+
* byte-for-byte output is stable across invocations. Creates the parent
|
|
70
|
+
* directory when missing.
|
|
71
|
+
*/
|
|
72
|
+
export async function writeGroup(group, opts = {}) {
|
|
73
|
+
assertValidGroupName(group.name);
|
|
74
|
+
const file = resolveGroupFile(group.name, opts);
|
|
75
|
+
await mkdir(dirname(file), { recursive: true });
|
|
76
|
+
const sortedRepos = [...group.repos]
|
|
77
|
+
.map((r) => ({ name: r.name, path: r.path }))
|
|
78
|
+
.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
79
|
+
const payload = {
|
|
80
|
+
name: group.name,
|
|
81
|
+
createdAt: group.createdAt,
|
|
82
|
+
repos: sortedRepos,
|
|
83
|
+
...(group.description !== undefined ? { description: group.description } : {}),
|
|
84
|
+
};
|
|
85
|
+
const serialized = `${JSON.stringify(payload, null, 2)}\n`;
|
|
86
|
+
await writeFileAtomic(file, serialized, { raw: true });
|
|
87
|
+
}
|
|
88
|
+
/** Delete a group. Returns `true` if the file existed, `false` otherwise. */
|
|
89
|
+
export async function deleteGroup(name, opts = {}) {
|
|
90
|
+
assertValidGroupName(name);
|
|
91
|
+
const file = resolveGroupFile(name, opts);
|
|
92
|
+
try {
|
|
93
|
+
await unlink(file);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
if (err.code === "ENOENT")
|
|
98
|
+
return false;
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Enumerate every group under `~/.codehub/groups`. Returned entries are
|
|
104
|
+
* sorted by name. Unreadable/malformed files are skipped with an error logged
|
|
105
|
+
* to stderr rather than tearing down the caller.
|
|
106
|
+
*/
|
|
107
|
+
export async function listGroups(opts = {}) {
|
|
108
|
+
const dir = resolveGroupsDir(opts);
|
|
109
|
+
let dirents;
|
|
110
|
+
try {
|
|
111
|
+
dirents = await readdir(dir);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
if (err.code === "ENOENT")
|
|
115
|
+
return [];
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
const names = dirents
|
|
119
|
+
.filter((f) => extname(f) === ".json")
|
|
120
|
+
.map((f) => basename(f, ".json"))
|
|
121
|
+
.filter((n) => GROUP_NAME_PATTERN.test(n))
|
|
122
|
+
.sort();
|
|
123
|
+
const out = [];
|
|
124
|
+
for (const name of names) {
|
|
125
|
+
try {
|
|
126
|
+
const group = await readGroup(name, opts);
|
|
127
|
+
if (group)
|
|
128
|
+
out.push(group);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
132
|
+
console.warn(`codehub groups: skipping malformed group "${name}": ${msg}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
// ----------------------------------------------------------------------------
|
|
138
|
+
// Internal helpers
|
|
139
|
+
// ----------------------------------------------------------------------------
|
|
140
|
+
function validateGroup(value, file) {
|
|
141
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
142
|
+
throw new Error(`Invalid group at ${file}: expected top-level object`);
|
|
143
|
+
}
|
|
144
|
+
const raw = value;
|
|
145
|
+
if (typeof raw["name"] !== "string") {
|
|
146
|
+
throw new Error(`Invalid group at ${file}: missing "name"`);
|
|
147
|
+
}
|
|
148
|
+
if (typeof raw["createdAt"] !== "string") {
|
|
149
|
+
throw new Error(`Invalid group at ${file}: missing "createdAt"`);
|
|
150
|
+
}
|
|
151
|
+
if (!Array.isArray(raw["repos"])) {
|
|
152
|
+
throw new Error(`Invalid group at ${file}: missing "repos" array`);
|
|
153
|
+
}
|
|
154
|
+
const repos = [];
|
|
155
|
+
for (const entry of raw["repos"]) {
|
|
156
|
+
if (typeof entry !== "object" || entry === null)
|
|
157
|
+
continue;
|
|
158
|
+
const r = entry;
|
|
159
|
+
if (typeof r["name"] !== "string" || typeof r["path"] !== "string")
|
|
160
|
+
continue;
|
|
161
|
+
repos.push({ name: r["name"], path: r["path"] });
|
|
162
|
+
}
|
|
163
|
+
repos.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
164
|
+
const out = {
|
|
165
|
+
name: raw["name"],
|
|
166
|
+
createdAt: raw["createdAt"],
|
|
167
|
+
repos,
|
|
168
|
+
...(typeof raw["description"] === "string" ? { description: raw["description"] } : {}),
|
|
169
|
+
};
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=groups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groups.js","sourceRoot":"","sources":["../src/groups.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `codehub` CLI entrypoint.
|
|
4
|
+
*
|
|
5
|
+
* Every subcommand is loaded lazily via `await import(...)` so that
|
|
6
|
+
* `codehub --help` (and `codehub <command> --help`) stays fast: no DuckDB
|
|
7
|
+
* native binding, no pipeline, no MCP SDK unless we are actually going to
|
|
8
|
+
* run that subcommand.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG"}
|