@coderule/mcp 1.7.2 → 2.0.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/dist/cli.cjs +224 -45
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +220 -42
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +203 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +199 -31
- package/dist/index.js.map +1 -1
- package/dist/mcp-cli.cjs +236 -46
- package/dist/mcp-cli.cjs.map +1 -1
- package/dist/mcp-cli.js +232 -43
- package/dist/mcp-cli.js.map +1 -1
- package/package.json +6 -4
package/dist/mcp-cli.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import fs5 from 'fs/promises';
|
|
3
|
+
import path2 from 'path';
|
|
4
4
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
5
|
import { createHash } from 'crypto';
|
|
6
6
|
import envPaths from 'env-paths';
|
|
7
7
|
import pino from 'pino';
|
|
8
|
+
import os from 'os';
|
|
8
9
|
import Database from 'better-sqlite3';
|
|
9
10
|
import { Qulite, JobStatus, enqueueFsEvent } from '@coderule/qulite';
|
|
10
11
|
import { CoderuleClients, ASTHttpClient, SyncHttpClient } from '@coderule/clients';
|
|
11
|
-
import
|
|
12
|
+
import fs3 from 'fs';
|
|
12
13
|
import { Worker } from 'worker_threads';
|
|
13
14
|
import chokidar from 'chokidar';
|
|
14
15
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
@@ -35,6 +36,166 @@ var DEFAULT_MAX_SNAPSHOT_ATTEMPTS = 5;
|
|
|
35
36
|
var DEFAULT_HTTP_TIMEOUT_MS = 12e4;
|
|
36
37
|
var DEFAULT_UPLOAD_CHUNK_SIZE = 1;
|
|
37
38
|
var DEFAULT_MAX_QUERY_WAIT_MS = 5e4;
|
|
39
|
+
function collectCandidateSources(options) {
|
|
40
|
+
const sources = [];
|
|
41
|
+
if (options?.cliRoot) {
|
|
42
|
+
sources.push({
|
|
43
|
+
value: options.cliRoot,
|
|
44
|
+
source: "cli-arg",
|
|
45
|
+
baseConfidence: 1
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (process.env.CODERULE_ROOT) {
|
|
49
|
+
sources.push({
|
|
50
|
+
value: process.env.CODERULE_ROOT,
|
|
51
|
+
source: "env-coderule-root",
|
|
52
|
+
baseConfidence: 0.9
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (process.env.WORKSPACE_FOLDER_PATHS) {
|
|
56
|
+
sources.push({
|
|
57
|
+
value: process.env.WORKSPACE_FOLDER_PATHS,
|
|
58
|
+
source: "env-workspace",
|
|
59
|
+
baseConfidence: 0.8
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
sources.push({
|
|
63
|
+
value: process.cwd(),
|
|
64
|
+
source: "process-cwd",
|
|
65
|
+
baseConfidence: 0.6
|
|
66
|
+
});
|
|
67
|
+
return sources;
|
|
68
|
+
}
|
|
69
|
+
async function pathExists(targetPath) {
|
|
70
|
+
try {
|
|
71
|
+
await fs5.access(targetPath);
|
|
72
|
+
return true;
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async function isDirectory(targetPath) {
|
|
78
|
+
try {
|
|
79
|
+
const stat = await fs5.stat(targetPath);
|
|
80
|
+
return stat.isDirectory();
|
|
81
|
+
} catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function hasGitDirectory(rootPath) {
|
|
86
|
+
const gitPath = path2.join(rootPath, ".git");
|
|
87
|
+
return pathExists(gitPath);
|
|
88
|
+
}
|
|
89
|
+
function isShallowPath(absolutePath) {
|
|
90
|
+
const normalized = absolutePath.replace(/\\/g, "/");
|
|
91
|
+
const separatorCount = (normalized.match(/\//g) || []).length;
|
|
92
|
+
return separatorCount <= 1;
|
|
93
|
+
}
|
|
94
|
+
function isHomeDirectory(candidatePath) {
|
|
95
|
+
const home = os.homedir();
|
|
96
|
+
const normalizedCandidate = path2.normalize(candidatePath);
|
|
97
|
+
const normalizedHome = path2.normalize(home);
|
|
98
|
+
return normalizedCandidate === normalizedHome;
|
|
99
|
+
}
|
|
100
|
+
async function applyModifiers(candidate) {
|
|
101
|
+
const modifiers = [];
|
|
102
|
+
if (await hasGitDirectory(candidate.path)) {
|
|
103
|
+
modifiers.push({ reason: "has .git directory", delta: 0.1 });
|
|
104
|
+
}
|
|
105
|
+
if (isShallowPath(candidate.path)) {
|
|
106
|
+
modifiers.push({ reason: "shallow path (likely root)", delta: -0.2 });
|
|
107
|
+
}
|
|
108
|
+
if (isHomeDirectory(candidate.path)) {
|
|
109
|
+
modifiers.push({ reason: "is home directory", delta: -0.3 });
|
|
110
|
+
}
|
|
111
|
+
const totalModifier = modifiers.reduce((sum, m) => sum + m.delta, 0);
|
|
112
|
+
const finalConfidence = candidate.baseConfidence + totalModifier;
|
|
113
|
+
return {
|
|
114
|
+
...candidate,
|
|
115
|
+
modifiers,
|
|
116
|
+
finalConfidence
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
async function createCandidate(source) {
|
|
120
|
+
const absolutePath = path2.resolve(source.value);
|
|
121
|
+
const exists = await pathExists(absolutePath);
|
|
122
|
+
const isDir = exists ? await isDirectory(absolutePath) : false;
|
|
123
|
+
const candidate = {
|
|
124
|
+
path: absolutePath,
|
|
125
|
+
source: source.source,
|
|
126
|
+
baseConfidence: source.baseConfidence,
|
|
127
|
+
modifiers: [],
|
|
128
|
+
finalConfidence: source.baseConfidence,
|
|
129
|
+
exists,
|
|
130
|
+
isDirectory: isDir
|
|
131
|
+
};
|
|
132
|
+
if (exists && isDir) {
|
|
133
|
+
return applyModifiers(candidate);
|
|
134
|
+
}
|
|
135
|
+
return candidate;
|
|
136
|
+
}
|
|
137
|
+
async function resolveRootPath(options) {
|
|
138
|
+
const logger2 = options?.logger;
|
|
139
|
+
const sources = collectCandidateSources(options);
|
|
140
|
+
const candidates = await Promise.all(sources.map(createCandidate));
|
|
141
|
+
logger2?.debug(
|
|
142
|
+
{
|
|
143
|
+
candidates: candidates.map((c) => ({
|
|
144
|
+
path: c.path,
|
|
145
|
+
source: c.source,
|
|
146
|
+
baseConfidence: c.baseConfidence,
|
|
147
|
+
finalConfidence: c.finalConfidence,
|
|
148
|
+
exists: c.exists,
|
|
149
|
+
isDirectory: c.isDirectory,
|
|
150
|
+
modifiers: c.modifiers
|
|
151
|
+
}))
|
|
152
|
+
},
|
|
153
|
+
"Collected root path candidates"
|
|
154
|
+
);
|
|
155
|
+
const validCandidates = candidates.filter((c) => c.exists && c.isDirectory);
|
|
156
|
+
if (validCandidates.length === 0) {
|
|
157
|
+
const attempted = candidates.map((c) => c.path).join(", ");
|
|
158
|
+
throw new Error(
|
|
159
|
+
`No valid root directory found. Attempted: ${attempted}. Ensure the directory exists and is accessible.`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
const sourcePriority = {
|
|
163
|
+
"cli-arg": 1,
|
|
164
|
+
"env-coderule-root": 2,
|
|
165
|
+
"env-workspace": 3,
|
|
166
|
+
"process-cwd": 4
|
|
167
|
+
};
|
|
168
|
+
validCandidates.sort((a, b) => {
|
|
169
|
+
const confidenceDiff = b.finalConfidence - a.finalConfidence;
|
|
170
|
+
if (confidenceDiff !== 0) {
|
|
171
|
+
return confidenceDiff;
|
|
172
|
+
}
|
|
173
|
+
return sourcePriority[a.source] - sourcePriority[b.source];
|
|
174
|
+
});
|
|
175
|
+
const best = validCandidates[0];
|
|
176
|
+
if (best.finalConfidence < 0.7) {
|
|
177
|
+
logger2?.warn(
|
|
178
|
+
{
|
|
179
|
+
path: best.path,
|
|
180
|
+
source: best.source,
|
|
181
|
+
confidence: best.finalConfidence,
|
|
182
|
+
modifiers: best.modifiers
|
|
183
|
+
},
|
|
184
|
+
"Selected root path has low confidence"
|
|
185
|
+
);
|
|
186
|
+
} else {
|
|
187
|
+
logger2?.info(
|
|
188
|
+
{
|
|
189
|
+
path: best.path,
|
|
190
|
+
source: best.source,
|
|
191
|
+
confidence: best.finalConfidence,
|
|
192
|
+
modifiers: best.modifiers
|
|
193
|
+
},
|
|
194
|
+
"Resolved root path"
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
return best;
|
|
198
|
+
}
|
|
38
199
|
|
|
39
200
|
// src/config/Configurator.ts
|
|
40
201
|
var DEFAULT_RETRIEVAL_FORMATTER = "standard";
|
|
@@ -47,9 +208,9 @@ var DEFAULTS = {
|
|
|
47
208
|
maxSnapshotAttempts: DEFAULT_MAX_SNAPSHOT_ATTEMPTS
|
|
48
209
|
};
|
|
49
210
|
function normalizeRoot(root) {
|
|
50
|
-
const resolved =
|
|
51
|
-
const normalized =
|
|
52
|
-
return normalized.split(
|
|
211
|
+
const resolved = path2.resolve(root);
|
|
212
|
+
const normalized = path2.normalize(resolved);
|
|
213
|
+
return normalized.split(path2.sep).join("/");
|
|
53
214
|
}
|
|
54
215
|
function sha256(input) {
|
|
55
216
|
return createHash("sha256").update(input).digest("hex");
|
|
@@ -81,7 +242,8 @@ function parseFormatter(value) {
|
|
|
81
242
|
);
|
|
82
243
|
}
|
|
83
244
|
async function resolveConfig({
|
|
84
|
-
token
|
|
245
|
+
token,
|
|
246
|
+
rootPath: cliRoot
|
|
85
247
|
}) {
|
|
86
248
|
const resolvedToken = token ?? process.env.CODERULE_TOKEN;
|
|
87
249
|
if (!resolvedToken) {
|
|
@@ -89,14 +251,17 @@ async function resolveConfig({
|
|
|
89
251
|
"Missing token: provide params.token or CODERULE_TOKEN env"
|
|
90
252
|
);
|
|
91
253
|
}
|
|
92
|
-
const rootCandidate =
|
|
93
|
-
|
|
254
|
+
const rootCandidate = await resolveRootPath({
|
|
255
|
+
cliRoot,
|
|
256
|
+
logger: logger.child({ scope: "root-resolver" })
|
|
257
|
+
});
|
|
258
|
+
const rootPath = rootCandidate.path;
|
|
94
259
|
const normalized = normalizeRoot(rootPath);
|
|
95
260
|
const rootId = sha256(normalized);
|
|
96
261
|
const dataDir = process.env.CODERULE_DATA_DIR || envPaths("coderule").data;
|
|
97
|
-
const watchDir =
|
|
98
|
-
await
|
|
99
|
-
const dbPath =
|
|
262
|
+
const watchDir = path2.join(dataDir, "watch");
|
|
263
|
+
await fs5.mkdir(watchDir, { recursive: true });
|
|
264
|
+
const dbPath = path2.join(watchDir, `${rootId}.sqlite`);
|
|
100
265
|
const baseConfig = {
|
|
101
266
|
token: resolvedToken,
|
|
102
267
|
rootPath,
|
|
@@ -173,6 +338,9 @@ async function resolveConfig({
|
|
|
173
338
|
logger.debug(
|
|
174
339
|
{
|
|
175
340
|
rootPath,
|
|
341
|
+
rootSource: rootCandidate.source,
|
|
342
|
+
rootConfidence: rootCandidate.finalConfidence,
|
|
343
|
+
rootModifiers: rootCandidate.modifiers,
|
|
176
344
|
dbPath,
|
|
177
345
|
dataDir,
|
|
178
346
|
authBaseUrl: baseConfig.authBaseUrl,
|
|
@@ -673,7 +841,7 @@ async function fetchVisitorRules(clients, logger2) {
|
|
|
673
841
|
return rules;
|
|
674
842
|
}
|
|
675
843
|
function toPosix(input) {
|
|
676
|
-
return input.split(
|
|
844
|
+
return input.split(path2.sep).join("/");
|
|
677
845
|
}
|
|
678
846
|
function getLowerBasename(input) {
|
|
679
847
|
const base = input.split("/").pop();
|
|
@@ -692,7 +860,7 @@ function compileRulesBundle(rules) {
|
|
|
692
860
|
if (!info) {
|
|
693
861
|
logger.debug({ path: fullPath }, "Predicate fallback lstat");
|
|
694
862
|
try {
|
|
695
|
-
info =
|
|
863
|
+
info = fs3.lstatSync(fullPath);
|
|
696
864
|
} catch (error) {
|
|
697
865
|
logger.warn(
|
|
698
866
|
{ err: error, path: fullPath },
|
|
@@ -841,14 +1009,14 @@ var Hasher = class {
|
|
|
841
1009
|
await new Promise((resolve) => setImmediate(resolve));
|
|
842
1010
|
}
|
|
843
1011
|
resolveAbsolutePath(record) {
|
|
844
|
-
if (
|
|
1012
|
+
if (path2.isAbsolute(record.display_path)) {
|
|
845
1013
|
return record.display_path;
|
|
846
1014
|
}
|
|
847
|
-
return
|
|
1015
|
+
return path2.join(this.options.rootPath, record.rel_path);
|
|
848
1016
|
}
|
|
849
1017
|
async ensureExists(absPath, record) {
|
|
850
1018
|
try {
|
|
851
|
-
await
|
|
1019
|
+
await fs5.access(absPath);
|
|
852
1020
|
return true;
|
|
853
1021
|
} catch (error) {
|
|
854
1022
|
this.log.warn(
|
|
@@ -871,7 +1039,7 @@ var Hasher = class {
|
|
|
871
1039
|
const service = createHash("sha256");
|
|
872
1040
|
service.update(relPath);
|
|
873
1041
|
service.update("\n");
|
|
874
|
-
const stream =
|
|
1042
|
+
const stream = fs3.createReadStream(absPath);
|
|
875
1043
|
stream.on("data", (chunk) => {
|
|
876
1044
|
content.update(chunk);
|
|
877
1045
|
service.update(chunk);
|
|
@@ -986,13 +1154,13 @@ async function bootstrap(params) {
|
|
|
986
1154
|
return runtime;
|
|
987
1155
|
}
|
|
988
1156
|
function toPosixRelative(root, target) {
|
|
989
|
-
const rel =
|
|
1157
|
+
const rel = path2.relative(root, target);
|
|
990
1158
|
if (!rel || rel === "") return "";
|
|
991
|
-
return rel.split(
|
|
1159
|
+
return rel.split(path2.sep).join("/");
|
|
992
1160
|
}
|
|
993
1161
|
function isInsideRoot(root, target) {
|
|
994
|
-
const rel =
|
|
995
|
-
return rel === "" || !rel.startsWith("..") && !
|
|
1162
|
+
const rel = path2.relative(root, target);
|
|
1163
|
+
return rel === "" || !rel.startsWith("..") && !path2.isAbsolute(rel);
|
|
996
1164
|
}
|
|
997
1165
|
|
|
998
1166
|
// src/fs/Walker.ts
|
|
@@ -1007,7 +1175,7 @@ function cloneStats(stats) {
|
|
|
1007
1175
|
}
|
|
1008
1176
|
async function readSymlinkTarget(absPath, log) {
|
|
1009
1177
|
try {
|
|
1010
|
-
return await
|
|
1178
|
+
return await fs5.readlink(absPath);
|
|
1011
1179
|
} catch (error) {
|
|
1012
1180
|
log.warn({ err: error, path: absPath }, "Failed to read symlink target");
|
|
1013
1181
|
return null;
|
|
@@ -1017,13 +1185,13 @@ async function walkDirectory(current, opts, stats) {
|
|
|
1017
1185
|
const dirLogger = opts.logger;
|
|
1018
1186
|
let dirents;
|
|
1019
1187
|
try {
|
|
1020
|
-
dirents = await
|
|
1188
|
+
dirents = await fs5.readdir(current, { withFileTypes: true });
|
|
1021
1189
|
} catch (error) {
|
|
1022
1190
|
dirLogger.warn({ err: error, path: current }, "Failed to read directory");
|
|
1023
1191
|
return;
|
|
1024
1192
|
}
|
|
1025
1193
|
for (const dirent of dirents) {
|
|
1026
|
-
const absPath =
|
|
1194
|
+
const absPath = path2.join(current, dirent.name);
|
|
1027
1195
|
const relPath = toPosixRelative(opts.rootPath, absPath);
|
|
1028
1196
|
if (dirent.isDirectory()) {
|
|
1029
1197
|
if (shouldPruneDirectory(relPath, opts.bundle)) {
|
|
@@ -1036,7 +1204,7 @@ async function walkDirectory(current, opts, stats) {
|
|
|
1036
1204
|
if (dirent.isSymbolicLink() || dirent.isFile()) {
|
|
1037
1205
|
let stat;
|
|
1038
1206
|
try {
|
|
1039
|
-
stat = await
|
|
1207
|
+
stat = await fs5.lstat(absPath);
|
|
1040
1208
|
} catch (error) {
|
|
1041
1209
|
dirLogger.warn({ err: error, path: absPath }, "Failed to stat file");
|
|
1042
1210
|
continue;
|
|
@@ -1128,9 +1296,9 @@ async function uploadMissing(rootPath, missing, syncClient, logger2, maxAttempts
|
|
|
1128
1296
|
const list = chunks[idx];
|
|
1129
1297
|
const map = /* @__PURE__ */ new Map();
|
|
1130
1298
|
for (const missingFile of list) {
|
|
1131
|
-
const absPath =
|
|
1299
|
+
const absPath = path2.join(rootPath, missingFile.file_path);
|
|
1132
1300
|
try {
|
|
1133
|
-
const buffer = await
|
|
1301
|
+
const buffer = await fs5.readFile(absPath);
|
|
1134
1302
|
map.set(missingFile.file_hash, {
|
|
1135
1303
|
path: missingFile.file_path,
|
|
1136
1304
|
content: buffer
|
|
@@ -1395,7 +1563,7 @@ function computeBackoff(attempts) {
|
|
|
1395
1563
|
}
|
|
1396
1564
|
async function readSymlinkTarget2(absPath) {
|
|
1397
1565
|
try {
|
|
1398
|
-
return await
|
|
1566
|
+
return await fs5.readlink(absPath);
|
|
1399
1567
|
} catch {
|
|
1400
1568
|
return null;
|
|
1401
1569
|
}
|
|
@@ -1536,7 +1704,7 @@ var ServiceRunner = class {
|
|
|
1536
1704
|
async handleEvent(event, absPath, stats) {
|
|
1537
1705
|
if (!this.running) return;
|
|
1538
1706
|
const root = this.runtime.config.rootPath;
|
|
1539
|
-
const absolute =
|
|
1707
|
+
const absolute = path2.isAbsolute(absPath) ? absPath : path2.join(root, absPath);
|
|
1540
1708
|
if (!isInsideRoot(root, absolute)) {
|
|
1541
1709
|
return;
|
|
1542
1710
|
}
|
|
@@ -1556,7 +1724,7 @@ var ServiceRunner = class {
|
|
|
1556
1724
|
async handleAddChange(absPath, _stats) {
|
|
1557
1725
|
let fileStats;
|
|
1558
1726
|
try {
|
|
1559
|
-
fileStats = await
|
|
1727
|
+
fileStats = await fs5.lstat(absPath);
|
|
1560
1728
|
} catch (error) {
|
|
1561
1729
|
this.runtime.logger.warn(
|
|
1562
1730
|
{ err: error, path: absPath },
|
|
@@ -1808,9 +1976,19 @@ function formatStatus(status) {
|
|
|
1808
1976
|
` Pass 2 (Cross-Reference): ${formatDuration(timing.pass2)}`
|
|
1809
1977
|
);
|
|
1810
1978
|
}
|
|
1811
|
-
if (timing.
|
|
1979
|
+
if (timing.pass2_hdf5_compile !== void 0) {
|
|
1980
|
+
lines.push(
|
|
1981
|
+
` HDF5 Compilation: ${formatDuration(timing.pass2_hdf5_compile)}`
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
if (timing.pass2_hdf5_dedup !== void 0) {
|
|
1812
1985
|
lines.push(
|
|
1813
|
-
`
|
|
1986
|
+
` HDF5 Deduplication: ${formatDuration(timing.pass2_hdf5_dedup)}`
|
|
1987
|
+
);
|
|
1988
|
+
}
|
|
1989
|
+
if (timing.pass2_hdf5_write !== void 0) {
|
|
1990
|
+
lines.push(
|
|
1991
|
+
` HDF5 Write I/O: ${formatDuration(timing.pass2_hdf5_write)}`
|
|
1814
1992
|
);
|
|
1815
1993
|
}
|
|
1816
1994
|
const totalTime = (timing.pass1 ?? 0) + (timing.gap ?? 0) + (timing.pass2 ?? 0);
|
|
@@ -2047,7 +2225,6 @@ ${statusText}`;
|
|
|
2047
2225
|
|
|
2048
2226
|
// src/mcp-cli.ts
|
|
2049
2227
|
var ENV_FLAG_MAP = {
|
|
2050
|
-
root: "CODERULE_ROOT",
|
|
2051
2228
|
"data-dir": "CODERULE_DATA_DIR",
|
|
2052
2229
|
"auth-url": "CODERULE_AUTH_URL",
|
|
2053
2230
|
"sync-url": "CODERULE_SYNC_URL",
|
|
@@ -2118,6 +2295,7 @@ function printUsage() {
|
|
|
2118
2295
|
}
|
|
2119
2296
|
function parseArgs(argv) {
|
|
2120
2297
|
let token = process.env.CODERULE_TOKEN;
|
|
2298
|
+
let rootPath;
|
|
2121
2299
|
let clean = false;
|
|
2122
2300
|
let inlineHasher = false;
|
|
2123
2301
|
const env = {};
|
|
@@ -2148,6 +2326,14 @@ function parseArgs(argv) {
|
|
|
2148
2326
|
token = arg.slice("--token=".length);
|
|
2149
2327
|
continue;
|
|
2150
2328
|
}
|
|
2329
|
+
if (arg === "--root") {
|
|
2330
|
+
const value = args.shift();
|
|
2331
|
+
if (!value) {
|
|
2332
|
+
throw new Error("Missing value for --root");
|
|
2333
|
+
}
|
|
2334
|
+
rootPath = value;
|
|
2335
|
+
continue;
|
|
2336
|
+
}
|
|
2151
2337
|
if (arg.startsWith("--")) {
|
|
2152
2338
|
const flag = arg.slice(2);
|
|
2153
2339
|
const envKey = ENV_FLAG_MAP[flag];
|
|
@@ -2180,22 +2366,22 @@ function parseArgs(argv) {
|
|
|
2180
2366
|
"Missing token. Provide via argument or CODERULE_TOKEN environment variable."
|
|
2181
2367
|
);
|
|
2182
2368
|
}
|
|
2183
|
-
return { token, clean, inlineHasher, env };
|
|
2369
|
+
return { token, rootPath, clean, inlineHasher, env };
|
|
2184
2370
|
}
|
|
2185
|
-
async function ensureClean(configToken) {
|
|
2186
|
-
const config = await resolveConfig({ token: configToken });
|
|
2371
|
+
async function ensureClean(configToken, rootPath) {
|
|
2372
|
+
const config = await resolveConfig({ token: configToken, rootPath });
|
|
2187
2373
|
const targets = [
|
|
2188
2374
|
config.dbPath,
|
|
2189
2375
|
`${config.dbPath}-shm`,
|
|
2190
2376
|
`${config.dbPath}-wal`
|
|
2191
2377
|
];
|
|
2192
|
-
await Promise.all(targets.map((target) =>
|
|
2193
|
-
await
|
|
2378
|
+
await Promise.all(targets.map((target) => fs5.rm(target, { force: true })));
|
|
2379
|
+
await fs5.rm(path2.join(config.dataDir, "watch", `${config.rootId}.sqlite-shm`), {
|
|
2194
2380
|
force: true
|
|
2195
2381
|
}).catch(() => {
|
|
2196
2382
|
});
|
|
2197
|
-
const dir =
|
|
2198
|
-
await
|
|
2383
|
+
const dir = path2.dirname(config.dbPath);
|
|
2384
|
+
await fs5.mkdir(dir, { recursive: true });
|
|
2199
2385
|
console.log(`Removed scanner database at ${config.dbPath}`);
|
|
2200
2386
|
}
|
|
2201
2387
|
function awaitShutdownSignals() {
|
|
@@ -2226,9 +2412,12 @@ async function main() {
|
|
|
2226
2412
|
process.env[key] = value;
|
|
2227
2413
|
}
|
|
2228
2414
|
if (options.clean) {
|
|
2229
|
-
await ensureClean(options.token);
|
|
2415
|
+
await ensureClean(options.token, options.rootPath);
|
|
2230
2416
|
}
|
|
2231
|
-
const runtime = await bootstrap({
|
|
2417
|
+
const runtime = await bootstrap({
|
|
2418
|
+
token: options.token,
|
|
2419
|
+
rootPath: options.rootPath
|
|
2420
|
+
});
|
|
2232
2421
|
const runner = new ServiceRunner(runtime);
|
|
2233
2422
|
try {
|
|
2234
2423
|
await runner.prepareWatcher(true);
|