@coderule/mcp 2.2.1 → 2.2.2
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/dist/cli.cjs +69 -17
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +68 -16
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import fs8 from 'fs/promises';
|
|
3
3
|
import path2 from 'path';
|
|
4
|
+
import { CoderuleClients, ASTHttpClient, SyncHttpClient } from '@coderule/clients';
|
|
4
5
|
import { createHash } from 'crypto';
|
|
5
6
|
import envPaths from 'env-paths';
|
|
6
7
|
import pino from 'pino';
|
|
7
8
|
import os from 'os';
|
|
8
9
|
import Database from 'better-sqlite3';
|
|
9
10
|
import { Qulite, JobStatus, enqueueFsEvent } from '@coderule/qulite';
|
|
10
|
-
import { CoderuleClients, ASTHttpClient, SyncHttpClient } from '@coderule/clients';
|
|
11
11
|
import fs3 from 'fs';
|
|
12
12
|
import { Worker } from 'worker_threads';
|
|
13
13
|
import chokidar from 'chokidar';
|
|
@@ -65,7 +65,7 @@ function collectCandidateSources(options) {
|
|
|
65
65
|
}
|
|
66
66
|
async function pathExists(targetPath) {
|
|
67
67
|
try {
|
|
68
|
-
await
|
|
68
|
+
await fs8.access(targetPath);
|
|
69
69
|
return true;
|
|
70
70
|
} catch {
|
|
71
71
|
return false;
|
|
@@ -73,7 +73,7 @@ async function pathExists(targetPath) {
|
|
|
73
73
|
}
|
|
74
74
|
async function isDirectory(targetPath) {
|
|
75
75
|
try {
|
|
76
|
-
const stat = await
|
|
76
|
+
const stat = await fs8.stat(targetPath);
|
|
77
77
|
return stat.isDirectory();
|
|
78
78
|
} catch {
|
|
79
79
|
return false;
|
|
@@ -257,7 +257,7 @@ async function resolveConfig({
|
|
|
257
257
|
const rootId = sha256(normalized);
|
|
258
258
|
const dataDir = process.env.CODERULE_DATA_DIR || envPaths("coderule").data;
|
|
259
259
|
const watchDir = path2.join(dataDir, "watch");
|
|
260
|
-
await
|
|
260
|
+
await fs8.mkdir(watchDir, { recursive: true });
|
|
261
261
|
const dbPath = path2.join(watchDir, `${rootId}.sqlite`);
|
|
262
262
|
const baseConfig = {
|
|
263
263
|
token: resolvedToken,
|
|
@@ -1033,7 +1033,7 @@ var Hasher = class {
|
|
|
1033
1033
|
}
|
|
1034
1034
|
async ensureExists(absPath, record) {
|
|
1035
1035
|
try {
|
|
1036
|
-
await
|
|
1036
|
+
await fs8.access(absPath);
|
|
1037
1037
|
return true;
|
|
1038
1038
|
} catch (error) {
|
|
1039
1039
|
this.log.warn(
|
|
@@ -1194,7 +1194,7 @@ function cloneStats(stats) {
|
|
|
1194
1194
|
}
|
|
1195
1195
|
async function readSymlinkTarget(absPath, log) {
|
|
1196
1196
|
try {
|
|
1197
|
-
return await
|
|
1197
|
+
return await fs8.readlink(absPath);
|
|
1198
1198
|
} catch (error) {
|
|
1199
1199
|
log.warn({ err: error, path: absPath }, "Failed to read symlink target");
|
|
1200
1200
|
return null;
|
|
@@ -1204,7 +1204,7 @@ async function walkDirectory(current, opts, stats) {
|
|
|
1204
1204
|
const dirLogger = opts.logger;
|
|
1205
1205
|
let dirents;
|
|
1206
1206
|
try {
|
|
1207
|
-
dirents = await
|
|
1207
|
+
dirents = await fs8.readdir(current, { withFileTypes: true });
|
|
1208
1208
|
} catch (error) {
|
|
1209
1209
|
dirLogger.warn({ err: error, path: current }, "Failed to read directory");
|
|
1210
1210
|
return;
|
|
@@ -1223,7 +1223,7 @@ async function walkDirectory(current, opts, stats) {
|
|
|
1223
1223
|
if (dirent.isSymbolicLink() || dirent.isFile()) {
|
|
1224
1224
|
let stat;
|
|
1225
1225
|
try {
|
|
1226
|
-
stat = await
|
|
1226
|
+
stat = await fs8.lstat(absPath);
|
|
1227
1227
|
} catch (error) {
|
|
1228
1228
|
dirLogger.warn({ err: error, path: absPath }, "Failed to stat file");
|
|
1229
1229
|
continue;
|
|
@@ -1366,7 +1366,7 @@ async function uploadMissing(rootPath, missing, syncClient, logger2, maxAttempts
|
|
|
1366
1366
|
for (const missingFile of list) {
|
|
1367
1367
|
const absPath = path2.join(rootPath, missingFile.file_path);
|
|
1368
1368
|
try {
|
|
1369
|
-
const buffer = await
|
|
1369
|
+
const buffer = await fs8.readFile(absPath);
|
|
1370
1370
|
const serviceHash = computeServiceFileHash(
|
|
1371
1371
|
missingFile.file_path,
|
|
1372
1372
|
buffer
|
|
@@ -1679,7 +1679,7 @@ function computeBackoff(attempts) {
|
|
|
1679
1679
|
var PUBLISH_MAX_MS = 5 * 6e4;
|
|
1680
1680
|
async function readSymlinkTarget2(absPath) {
|
|
1681
1681
|
try {
|
|
1682
|
-
return await
|
|
1682
|
+
return await fs8.readlink(absPath);
|
|
1683
1683
|
} catch {
|
|
1684
1684
|
return null;
|
|
1685
1685
|
}
|
|
@@ -1840,7 +1840,7 @@ var ServiceRunner = class {
|
|
|
1840
1840
|
async handleAddChange(absPath, _stats) {
|
|
1841
1841
|
let fileStats;
|
|
1842
1842
|
try {
|
|
1843
|
-
fileStats = await
|
|
1843
|
+
fileStats = await fs8.lstat(absPath);
|
|
1844
1844
|
} catch (error) {
|
|
1845
1845
|
this.runtime.logger.warn(
|
|
1846
1846
|
{ err: error, path: absPath },
|
|
@@ -2150,6 +2150,8 @@ Options:
|
|
|
2150
2150
|
--max-snapshot-attempts <n> Override CODERULE_MAX_SNAPSHOT_ATTEMPTS
|
|
2151
2151
|
--upload-chunk-size <n> Override CODERULE_UPLOAD_CHUNK_SIZE (default 1)
|
|
2152
2152
|
--max-wait-time <sec> Override CODERULE_MAX_WAIT_TIME (default 50s)
|
|
2153
|
+
--dump-bush <path> Download HDF5 bush file to <path> (must end with .h5)
|
|
2154
|
+
--dump-skill Print HDF5 bush reader skill (format docs + examples)
|
|
2153
2155
|
KEY=value Set arbitrary environment variable
|
|
2154
2156
|
--help Show this message
|
|
2155
2157
|
`);
|
|
@@ -2160,6 +2162,8 @@ function parseArgs(argv) {
|
|
|
2160
2162
|
let mode = "service";
|
|
2161
2163
|
let clean = false;
|
|
2162
2164
|
let inlineHasher = false;
|
|
2165
|
+
let dumpBush;
|
|
2166
|
+
let dumpSkill = false;
|
|
2163
2167
|
const env = {};
|
|
2164
2168
|
const args = [...argv];
|
|
2165
2169
|
while (args.length > 0) {
|
|
@@ -2184,6 +2188,22 @@ function parseArgs(argv) {
|
|
|
2184
2188
|
inlineHasher = true;
|
|
2185
2189
|
continue;
|
|
2186
2190
|
}
|
|
2191
|
+
if (arg === "--dump-bush") {
|
|
2192
|
+
if (args.length === 0) {
|
|
2193
|
+
throw new Error("Option --dump-bush requires a file path");
|
|
2194
|
+
}
|
|
2195
|
+
dumpBush = args.shift();
|
|
2196
|
+
if (!dumpBush.endsWith(".h5")) {
|
|
2197
|
+
throw new Error("--dump-bush path must end with .h5");
|
|
2198
|
+
}
|
|
2199
|
+
mode = "initial";
|
|
2200
|
+
continue;
|
|
2201
|
+
}
|
|
2202
|
+
if (arg === "--dump-skill") {
|
|
2203
|
+
dumpSkill = true;
|
|
2204
|
+
mode = "initial";
|
|
2205
|
+
continue;
|
|
2206
|
+
}
|
|
2187
2207
|
if (arg === "--root") {
|
|
2188
2208
|
if (args.length === 0) {
|
|
2189
2209
|
throw new Error("Option --root requires a value");
|
|
@@ -2223,7 +2243,16 @@ function parseArgs(argv) {
|
|
|
2223
2243
|
"Missing token. Provide via argument or CODERULE_TOKEN env."
|
|
2224
2244
|
);
|
|
2225
2245
|
}
|
|
2226
|
-
return {
|
|
2246
|
+
return {
|
|
2247
|
+
token,
|
|
2248
|
+
rootPath,
|
|
2249
|
+
mode,
|
|
2250
|
+
clean,
|
|
2251
|
+
inlineHasher,
|
|
2252
|
+
dumpBush,
|
|
2253
|
+
dumpSkill,
|
|
2254
|
+
env
|
|
2255
|
+
};
|
|
2227
2256
|
}
|
|
2228
2257
|
async function ensureClean(configToken, rootPath) {
|
|
2229
2258
|
const config = await resolveConfig({ token: configToken, rootPath });
|
|
@@ -2232,13 +2261,13 @@ async function ensureClean(configToken, rootPath) {
|
|
|
2232
2261
|
`${config.dbPath}-shm`,
|
|
2233
2262
|
`${config.dbPath}-wal`
|
|
2234
2263
|
];
|
|
2235
|
-
await Promise.all(targets.map((target) =>
|
|
2236
|
-
await
|
|
2264
|
+
await Promise.all(targets.map((target) => fs8.rm(target, { force: true })));
|
|
2265
|
+
await fs8.rm(path2.join(config.dataDir, "watch", `${config.rootId}.sqlite-shm`), {
|
|
2237
2266
|
force: true
|
|
2238
2267
|
}).catch(() => {
|
|
2239
2268
|
});
|
|
2240
2269
|
const dir = path2.dirname(config.dbPath);
|
|
2241
|
-
await
|
|
2270
|
+
await fs8.mkdir(dir, { recursive: true });
|
|
2242
2271
|
console.log(`Removed scanner database at ${config.dbPath}`);
|
|
2243
2272
|
}
|
|
2244
2273
|
async function main() {
|
|
@@ -2263,6 +2292,29 @@ async function main() {
|
|
|
2263
2292
|
rootPath: options.rootPath
|
|
2264
2293
|
});
|
|
2265
2294
|
console.log("Initial sync result:", JSON.stringify(result, null, 2));
|
|
2295
|
+
if (options.dumpBush || options.dumpSkill) {
|
|
2296
|
+
const clients = new CoderuleClients({ token: options.token });
|
|
2297
|
+
try {
|
|
2298
|
+
await clients.sync.checkSnapshotStatus(result.snapshotHash);
|
|
2299
|
+
if (options.dumpBush) {
|
|
2300
|
+
const buf = await clients.sync.downloadSnapshotBush(
|
|
2301
|
+
result.snapshotHash
|
|
2302
|
+
);
|
|
2303
|
+
const dir = path2.dirname(options.dumpBush);
|
|
2304
|
+
await fs8.mkdir(dir, { recursive: true });
|
|
2305
|
+
await fs8.writeFile(options.dumpBush, Buffer.from(buf));
|
|
2306
|
+
console.log(
|
|
2307
|
+
`HDF5 bush saved to ${options.dumpBush} (${buf.byteLength} bytes)`
|
|
2308
|
+
);
|
|
2309
|
+
}
|
|
2310
|
+
if (options.dumpSkill) {
|
|
2311
|
+
const skill = await clients.sync.getHdf5BushReaderSkill();
|
|
2312
|
+
console.log(skill);
|
|
2313
|
+
}
|
|
2314
|
+
} finally {
|
|
2315
|
+
clients.close();
|
|
2316
|
+
}
|
|
2317
|
+
}
|
|
2266
2318
|
} else {
|
|
2267
2319
|
await runService({ token: options.token, rootPath: options.rootPath });
|
|
2268
2320
|
}
|