@coderule/mcp 1.2.0 → 1.4.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 +136 -35
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +1 -2
- package/dist/cli.d.ts +1 -2
- package/dist/cli.js +137 -37
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +135 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +136 -36
- package/dist/index.js.map +1 -1
- package/dist/mcp-cli.cjs +136 -35
- package/dist/mcp-cli.cjs.map +1 -1
- package/dist/mcp-cli.d.cts +1 -2
- package/dist/mcp-cli.d.ts +1 -2
- package/dist/mcp-cli.js +137 -37
- package/dist/mcp-cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
'use strict';
|
|
2
3
|
|
|
3
4
|
var fs4 = require('fs/promises');
|
|
@@ -43,7 +44,7 @@ var DEFAULT_HEARTBEAT_CHECK_INTERVAL_MS = 5e3;
|
|
|
43
44
|
var DEFAULT_QUEUE_POLL_INTERVAL_MS = 500;
|
|
44
45
|
var DEFAULT_HASH_BATCH_SIZE = 32;
|
|
45
46
|
var DEFAULT_MAX_SNAPSHOT_ATTEMPTS = 5;
|
|
46
|
-
var DEFAULT_HTTP_TIMEOUT_MS =
|
|
47
|
+
var DEFAULT_HTTP_TIMEOUT_MS = 12e4;
|
|
47
48
|
|
|
48
49
|
// src/config/Configurator.ts
|
|
49
50
|
var DEFAULT_RETRIEVAL_FORMATTER = "standard";
|
|
@@ -548,6 +549,16 @@ var Outbox = class {
|
|
|
548
549
|
if (purged > 0) {
|
|
549
550
|
this.log.warn({ purged }, "Purged legacy fs_control jobs without kind");
|
|
550
551
|
}
|
|
552
|
+
try {
|
|
553
|
+
const counts = {
|
|
554
|
+
pending: this.queue.countByStatus(qulite.JobStatus.Pending),
|
|
555
|
+
processing: this.queue.countByStatus(qulite.JobStatus.Processing),
|
|
556
|
+
done: this.queue.countByStatus(qulite.JobStatus.Done),
|
|
557
|
+
failed: this.queue.countByStatus(qulite.JobStatus.Failed)
|
|
558
|
+
};
|
|
559
|
+
this.log.debug({ counts }, "Outbox initialized");
|
|
560
|
+
} catch {
|
|
561
|
+
}
|
|
551
562
|
}
|
|
552
563
|
getQueue() {
|
|
553
564
|
return this.queue;
|
|
@@ -1059,44 +1070,109 @@ function computeSnapshot(filesRepo) {
|
|
|
1059
1070
|
totalSize
|
|
1060
1071
|
};
|
|
1061
1072
|
}
|
|
1062
|
-
async function
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
for (const missingFile of missing) {
|
|
1066
|
-
const absPath = path__default.default.join(rootPath, missingFile.file_path);
|
|
1073
|
+
async function withRetries(op, logger2, context, maxAttempts) {
|
|
1074
|
+
let attempt = 0;
|
|
1075
|
+
while (true) {
|
|
1067
1076
|
try {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1077
|
+
return await op();
|
|
1078
|
+
} catch (err) {
|
|
1079
|
+
attempt += 1;
|
|
1080
|
+
if (attempt >= maxAttempts) {
|
|
1081
|
+
logger2.error(
|
|
1082
|
+
{ err, ...context, attempt },
|
|
1083
|
+
"Operation failed after retries"
|
|
1084
|
+
);
|
|
1085
|
+
throw err;
|
|
1086
|
+
}
|
|
1087
|
+
const delay = Math.min(15e3, 1e3 * 2 ** (attempt - 1));
|
|
1074
1088
|
logger2.warn(
|
|
1075
|
-
{ err
|
|
1076
|
-
"
|
|
1089
|
+
{ err, ...context, attempt, delay },
|
|
1090
|
+
"Operation failed; retrying"
|
|
1077
1091
|
);
|
|
1092
|
+
await sleep(delay);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
async function uploadMissing(rootPath, missing, syncClient, logger2, maxAttempts, chunkSize = 64) {
|
|
1097
|
+
if (!missing || missing.length === 0) return;
|
|
1098
|
+
const total = missing.length;
|
|
1099
|
+
const chunks = [];
|
|
1100
|
+
for (let i = 0; i < total; i += chunkSize) {
|
|
1101
|
+
chunks.push(missing.slice(i, i + chunkSize));
|
|
1102
|
+
}
|
|
1103
|
+
for (let idx = 0; idx < chunks.length; idx++) {
|
|
1104
|
+
const list = chunks[idx];
|
|
1105
|
+
const map = /* @__PURE__ */ new Map();
|
|
1106
|
+
for (const missingFile of list) {
|
|
1107
|
+
const absPath = path__default.default.join(rootPath, missingFile.file_path);
|
|
1108
|
+
try {
|
|
1109
|
+
const buffer = await fs4__default.default.readFile(absPath);
|
|
1110
|
+
map.set(missingFile.file_hash, {
|
|
1111
|
+
path: missingFile.file_path,
|
|
1112
|
+
content: buffer
|
|
1113
|
+
});
|
|
1114
|
+
} catch (error) {
|
|
1115
|
+
logger2.warn(
|
|
1116
|
+
{ err: error, relPath: missingFile.file_path },
|
|
1117
|
+
"Failed to read missing file content"
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1078
1120
|
}
|
|
1121
|
+
if (map.size === 0) continue;
|
|
1122
|
+
await withRetries(
|
|
1123
|
+
() => syncClient.uploadFileContent(map),
|
|
1124
|
+
logger2,
|
|
1125
|
+
{
|
|
1126
|
+
op: "uploadFileContent",
|
|
1127
|
+
chunkIndex: idx + 1,
|
|
1128
|
+
chunks: chunks.length,
|
|
1129
|
+
files: map.size
|
|
1130
|
+
},
|
|
1131
|
+
maxAttempts
|
|
1132
|
+
);
|
|
1079
1133
|
}
|
|
1080
|
-
if (map.size === 0) return;
|
|
1081
|
-
await syncClient.uploadFileContent(map);
|
|
1082
1134
|
}
|
|
1083
|
-
async function ensureSnapshotCreated(rootPath, computation, syncClient, logger2) {
|
|
1135
|
+
async function ensureSnapshotCreated(rootPath, computation, syncClient, logger2, options) {
|
|
1084
1136
|
const { snapshotHash, files } = computation;
|
|
1085
|
-
|
|
1137
|
+
const maxAttempts = options?.maxAttempts ?? 5;
|
|
1138
|
+
const uploadChunkSize = options?.uploadChunkSize ?? 64;
|
|
1139
|
+
let status = await withRetries(
|
|
1140
|
+
() => syncClient.checkSnapshotStatus(snapshotHash),
|
|
1141
|
+
logger2,
|
|
1142
|
+
{ op: "checkSnapshotStatus", snapshotHash },
|
|
1143
|
+
maxAttempts
|
|
1144
|
+
);
|
|
1086
1145
|
if (status.status === "READY") {
|
|
1087
1146
|
logger2.info({ snapshotHash }, "Snapshot already READY");
|
|
1088
1147
|
return;
|
|
1089
1148
|
}
|
|
1090
1149
|
if (status.status === "NOT_FOUND" || status.status === "MISSING_CONTENT") {
|
|
1091
|
-
status = await
|
|
1150
|
+
status = await withRetries(
|
|
1151
|
+
() => syncClient.createSnapshot(snapshotHash, files),
|
|
1152
|
+
logger2,
|
|
1153
|
+
{ op: "createSnapshot", snapshotHash },
|
|
1154
|
+
maxAttempts
|
|
1155
|
+
);
|
|
1092
1156
|
}
|
|
1093
1157
|
if (status.status === "MISSING_CONTENT" && status.missing_files?.length) {
|
|
1094
1158
|
logger2.info(
|
|
1095
1159
|
{ missing: status.missing_files.length },
|
|
1096
1160
|
"Uploading missing file content"
|
|
1097
1161
|
);
|
|
1098
|
-
await uploadMissing(
|
|
1099
|
-
|
|
1162
|
+
await uploadMissing(
|
|
1163
|
+
rootPath,
|
|
1164
|
+
status.missing_files,
|
|
1165
|
+
syncClient,
|
|
1166
|
+
logger2,
|
|
1167
|
+
maxAttempts,
|
|
1168
|
+
uploadChunkSize
|
|
1169
|
+
);
|
|
1170
|
+
status = await withRetries(
|
|
1171
|
+
() => syncClient.createSnapshot(snapshotHash, files),
|
|
1172
|
+
logger2,
|
|
1173
|
+
{ op: "createSnapshot", snapshotHash },
|
|
1174
|
+
maxAttempts
|
|
1175
|
+
);
|
|
1100
1176
|
}
|
|
1101
1177
|
let attempt = 0;
|
|
1102
1178
|
while (status.status !== "READY") {
|
|
@@ -1106,13 +1182,24 @@ async function ensureSnapshotCreated(rootPath, computation, syncClient, logger2)
|
|
|
1106
1182
|
const delay = Math.min(5e3, 1e3 * Math.max(1, 2 ** attempt));
|
|
1107
1183
|
await sleep(delay);
|
|
1108
1184
|
attempt += 1;
|
|
1109
|
-
status = await
|
|
1185
|
+
status = await withRetries(
|
|
1186
|
+
() => syncClient.checkSnapshotStatus(snapshotHash),
|
|
1187
|
+
logger2,
|
|
1188
|
+
{ op: "checkSnapshotStatus", snapshotHash },
|
|
1189
|
+
maxAttempts
|
|
1190
|
+
);
|
|
1110
1191
|
}
|
|
1111
1192
|
logger2.info({ snapshotHash }, "Snapshot READY");
|
|
1112
1193
|
}
|
|
1113
|
-
async function publishSnapshot(rootPath, filesRepo, snapshotsRepo, syncClient, logger2) {
|
|
1194
|
+
async function publishSnapshot(rootPath, filesRepo, snapshotsRepo, syncClient, logger2, options) {
|
|
1114
1195
|
const computation = computeSnapshot(filesRepo);
|
|
1115
|
-
await ensureSnapshotCreated(
|
|
1196
|
+
await ensureSnapshotCreated(
|
|
1197
|
+
rootPath,
|
|
1198
|
+
computation,
|
|
1199
|
+
syncClient,
|
|
1200
|
+
logger2,
|
|
1201
|
+
options
|
|
1202
|
+
);
|
|
1116
1203
|
const createdAt = Date.now();
|
|
1117
1204
|
snapshotsRepo.insert(
|
|
1118
1205
|
computation.snapshotHash,
|
|
@@ -1152,7 +1239,8 @@ async function runInitialSyncPipeline(runtime) {
|
|
|
1152
1239
|
runtime.filesRepo,
|
|
1153
1240
|
runtime.snapshotsRepo,
|
|
1154
1241
|
runtime.clients.sync,
|
|
1155
|
-
syncLogger
|
|
1242
|
+
syncLogger,
|
|
1243
|
+
{ maxAttempts: runtime.config.maxSnapshotAttempts }
|
|
1156
1244
|
);
|
|
1157
1245
|
return result;
|
|
1158
1246
|
}
|
|
@@ -1555,7 +1643,8 @@ var ServiceRunner = class {
|
|
|
1555
1643
|
this.runtime.filesRepo,
|
|
1556
1644
|
this.runtime.snapshotsRepo,
|
|
1557
1645
|
this.runtime.clients.sync,
|
|
1558
|
-
log
|
|
1646
|
+
log,
|
|
1647
|
+
{ maxAttempts: this.runtime.config.maxSnapshotAttempts }
|
|
1559
1648
|
);
|
|
1560
1649
|
this.runtime.outbox.ack(job.id, this.fsControlLeaseOwner);
|
|
1561
1650
|
this.state.updateSnapshotReady(result.createdAt);
|
|
@@ -1636,15 +1725,27 @@ async function runService(params) {
|
|
|
1636
1725
|
try {
|
|
1637
1726
|
runner = new ServiceRunner(runtime);
|
|
1638
1727
|
await runner.prepareWatcher(true);
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1728
|
+
let initialCreatedAt;
|
|
1729
|
+
try {
|
|
1730
|
+
const initial = await runInitialSyncPipeline(runtime);
|
|
1731
|
+
runtime.logger.info(
|
|
1732
|
+
{
|
|
1733
|
+
snapshotHash: initial.snapshotHash,
|
|
1734
|
+
filesCount: initial.filesCount
|
|
1735
|
+
},
|
|
1736
|
+
"Initial sync completed; entering continuous mode"
|
|
1737
|
+
);
|
|
1738
|
+
initialCreatedAt = initial.createdAt;
|
|
1739
|
+
} catch (error) {
|
|
1740
|
+
runtime.logger.warn(
|
|
1741
|
+
{ err: error },
|
|
1742
|
+
"Initial sync failed; enqueuing snapshot job and continuing"
|
|
1743
|
+
);
|
|
1744
|
+
runtime.outbox.enqueueSnapshot(runtime.config.rootId, 0);
|
|
1745
|
+
}
|
|
1746
|
+
if (initialCreatedAt) {
|
|
1747
|
+
runner.recordInitialSnapshot(initialCreatedAt);
|
|
1748
|
+
}
|
|
1648
1749
|
await runner.startLoops();
|
|
1649
1750
|
await runner.enableWatcherProcessing();
|
|
1650
1751
|
runtime.logger.info("Coderule scanner service is running");
|