@coderule/mcp 2.2.0 → 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.js CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import fs5 from 'fs/promises';
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 fs5.access(targetPath);
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 fs5.stat(targetPath);
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 fs5.mkdir(watchDir, { recursive: true });
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 fs5.access(absPath);
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 fs5.readlink(absPath);
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 fs5.readdir(current, { withFileTypes: true });
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 fs5.lstat(absPath);
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 fs5.readFile(absPath);
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 fs5.readlink(absPath);
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 fs5.lstat(absPath);
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 { token, rootPath, mode, clean, inlineHasher, env };
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) => fs5.rm(target, { force: true })));
2236
- await fs5.rm(path2.join(config.dataDir, "watch", `${config.rootId}.sqlite-shm`), {
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 fs5.mkdir(dir, { recursive: true });
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
  }