@coderule/mcp 1.5.0 → 1.6.1
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 +71 -17
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +71 -17
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +66 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +66 -16
- package/dist/index.js.map +1 -1
- package/dist/mcp-cli.cjs +111 -31
- package/dist/mcp-cli.cjs.map +1 -1
- package/dist/mcp-cli.js +111 -31
- package/dist/mcp-cli.js.map +1 -1
- package/package.json +1 -1
package/dist/mcp-cli.js
CHANGED
|
@@ -33,6 +33,8 @@ var DEFAULT_QUEUE_POLL_INTERVAL_MS = 500;
|
|
|
33
33
|
var DEFAULT_HASH_BATCH_SIZE = 32;
|
|
34
34
|
var DEFAULT_MAX_SNAPSHOT_ATTEMPTS = 5;
|
|
35
35
|
var DEFAULT_HTTP_TIMEOUT_MS = 12e4;
|
|
36
|
+
var DEFAULT_UPLOAD_CHUNK_SIZE = 1;
|
|
37
|
+
var DEFAULT_MAX_QUERY_WAIT_MS = 5e4;
|
|
36
38
|
|
|
37
39
|
// src/config/Configurator.ts
|
|
38
40
|
var DEFAULT_RETRIEVAL_FORMATTER = "standard";
|
|
@@ -60,6 +62,14 @@ function parseInteger(value, fallback) {
|
|
|
60
62
|
}
|
|
61
63
|
return parsed;
|
|
62
64
|
}
|
|
65
|
+
function parseSecondsToMs(value, fallbackMs) {
|
|
66
|
+
if (!value) return fallbackMs;
|
|
67
|
+
const seconds = Number.parseInt(value, 10);
|
|
68
|
+
if (Number.isNaN(seconds) || seconds <= 0) {
|
|
69
|
+
throw new Error(`Invalid seconds value: ${value}`);
|
|
70
|
+
}
|
|
71
|
+
return seconds * 1e3;
|
|
72
|
+
}
|
|
63
73
|
function parseFormatter(value) {
|
|
64
74
|
if (!value) return DEFAULT_RETRIEVAL_FORMATTER;
|
|
65
75
|
const normalized = value.toLowerCase();
|
|
@@ -106,7 +116,9 @@ async function resolveConfig({
|
|
|
106
116
|
maxSnapshotAttempts: DEFAULTS.maxSnapshotAttempts,
|
|
107
117
|
retrievalFormatter: parseFormatter(
|
|
108
118
|
process.env.CODERULE_RETRIEVAL_FORMATTER
|
|
109
|
-
)
|
|
119
|
+
),
|
|
120
|
+
uploadChunkSize: DEFAULT_UPLOAD_CHUNK_SIZE,
|
|
121
|
+
maxQueryWaitMs: DEFAULT_MAX_QUERY_WAIT_MS
|
|
110
122
|
};
|
|
111
123
|
if (process.env.CODERULE_SNAPSHOT_DEBOUNCE_MS) {
|
|
112
124
|
baseConfig.snapshotDebounceMs = parseInteger(
|
|
@@ -148,6 +160,16 @@ async function resolveConfig({
|
|
|
148
160
|
process.env.CODERULE_HTTP_TIMEOUT,
|
|
149
161
|
DEFAULT_HTTP_TIMEOUT_MS
|
|
150
162
|
);
|
|
163
|
+
if (process.env.CODERULE_UPLOAD_CHUNK_SIZE) {
|
|
164
|
+
baseConfig.uploadChunkSize = parseInteger(
|
|
165
|
+
process.env.CODERULE_UPLOAD_CHUNK_SIZE,
|
|
166
|
+
baseConfig.uploadChunkSize
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
baseConfig.maxQueryWaitMs = parseSecondsToMs(
|
|
170
|
+
process.env.CODERULE_MAX_WAIT_TIME,
|
|
171
|
+
baseConfig.maxQueryWaitMs
|
|
172
|
+
);
|
|
151
173
|
logger.debug(
|
|
152
174
|
{
|
|
153
175
|
rootPath,
|
|
@@ -1081,7 +1103,7 @@ async function withRetries(op, logger2, context, maxAttempts) {
|
|
|
1081
1103
|
}
|
|
1082
1104
|
}
|
|
1083
1105
|
}
|
|
1084
|
-
async function uploadMissing(rootPath, missing, syncClient, logger2, maxAttempts, chunkSize =
|
|
1106
|
+
async function uploadMissing(rootPath, missing, syncClient, logger2, maxAttempts, chunkSize = 1) {
|
|
1085
1107
|
if (!missing || missing.length === 0) return;
|
|
1086
1108
|
const total = missing.length;
|
|
1087
1109
|
const chunks = [];
|
|
@@ -1123,7 +1145,7 @@ async function uploadMissing(rootPath, missing, syncClient, logger2, maxAttempts
|
|
|
1123
1145
|
async function ensureSnapshotCreated(rootPath, computation, syncClient, logger2, options) {
|
|
1124
1146
|
const { snapshotHash, files } = computation;
|
|
1125
1147
|
const maxAttempts = options?.maxAttempts ?? 5;
|
|
1126
|
-
const uploadChunkSize = options?.uploadChunkSize ??
|
|
1148
|
+
const uploadChunkSize = options?.uploadChunkSize ?? 1;
|
|
1127
1149
|
let status = await withRetries(
|
|
1128
1150
|
() => syncClient.checkSnapshotStatus(snapshotHash),
|
|
1129
1151
|
logger2,
|
|
@@ -1205,7 +1227,7 @@ async function publishSnapshot(rootPath, filesRepo, snapshotsRepo, syncClient, l
|
|
|
1205
1227
|
}
|
|
1206
1228
|
|
|
1207
1229
|
// src/service/InitialSync.ts
|
|
1208
|
-
async function runInitialSyncPipeline(runtime) {
|
|
1230
|
+
async function runInitialSyncPipeline(runtime, options) {
|
|
1209
1231
|
const inventoryLogger = runtime.logger.child({ scope: "inventory" });
|
|
1210
1232
|
await runInventory({
|
|
1211
1233
|
rootPath: runtime.config.rootPath,
|
|
@@ -1221,16 +1243,22 @@ async function runInitialSyncPipeline(runtime) {
|
|
|
1221
1243
|
hashLogger.debug("Hasher processed batch");
|
|
1222
1244
|
}
|
|
1223
1245
|
}
|
|
1224
|
-
const
|
|
1225
|
-
const
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
{ maxAttempts: runtime.config.maxSnapshotAttempts }
|
|
1246
|
+
const computation = computeSnapshot(runtime.filesRepo);
|
|
1247
|
+
const createdAt = Date.now();
|
|
1248
|
+
runtime.snapshotsRepo.insert(
|
|
1249
|
+
computation.snapshotHash,
|
|
1250
|
+
computation.filesCount,
|
|
1251
|
+
computation.totalSize,
|
|
1252
|
+
createdAt
|
|
1232
1253
|
);
|
|
1233
|
-
|
|
1254
|
+
runtime.outbox.enqueueSnapshot(runtime.config.rootId, 0);
|
|
1255
|
+
return {
|
|
1256
|
+
snapshotHash: computation.snapshotHash,
|
|
1257
|
+
filesCount: computation.filesCount,
|
|
1258
|
+
totalSize: computation.totalSize,
|
|
1259
|
+
status: "READY",
|
|
1260
|
+
createdAt
|
|
1261
|
+
};
|
|
1234
1262
|
}
|
|
1235
1263
|
async function createChokidarWatcher(options, usePolling) {
|
|
1236
1264
|
const log = options.logger.child({
|
|
@@ -1632,7 +1660,10 @@ var ServiceRunner = class {
|
|
|
1632
1660
|
this.runtime.snapshotsRepo,
|
|
1633
1661
|
this.runtime.clients.sync,
|
|
1634
1662
|
log,
|
|
1635
|
-
{
|
|
1663
|
+
{
|
|
1664
|
+
maxAttempts: this.runtime.config.maxSnapshotAttempts,
|
|
1665
|
+
uploadChunkSize: this.runtime.config.uploadChunkSize
|
|
1666
|
+
}
|
|
1636
1667
|
);
|
|
1637
1668
|
this.runtime.outbox.ack(job.id, this.fsControlLeaseOwner);
|
|
1638
1669
|
this.state.updateSnapshotReady(result.createdAt);
|
|
@@ -1755,6 +1786,37 @@ function createMcpServer({
|
|
|
1755
1786
|
runtime,
|
|
1756
1787
|
runner
|
|
1757
1788
|
}) {
|
|
1789
|
+
async function sleep3(ms) {
|
|
1790
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1791
|
+
}
|
|
1792
|
+
async function waitForLocalSnapshot(deadlineMs) {
|
|
1793
|
+
let latest = runtime.snapshotsRepo.getLatest();
|
|
1794
|
+
while (!latest && Date.now() < deadlineMs) {
|
|
1795
|
+
await sleep3(250);
|
|
1796
|
+
latest = runtime.snapshotsRepo.getLatest();
|
|
1797
|
+
}
|
|
1798
|
+
return latest;
|
|
1799
|
+
}
|
|
1800
|
+
async function waitForServerReady(initialHash, deadlineMs) {
|
|
1801
|
+
let currentHash = initialHash;
|
|
1802
|
+
while (Date.now() < deadlineMs) {
|
|
1803
|
+
try {
|
|
1804
|
+
const status = await runtime.clients.sync.checkSnapshotStatus(currentHash);
|
|
1805
|
+
if (status.status === "READY") {
|
|
1806
|
+
return currentHash;
|
|
1807
|
+
}
|
|
1808
|
+
if (status.status === "FAILED") {
|
|
1809
|
+
}
|
|
1810
|
+
} catch {
|
|
1811
|
+
}
|
|
1812
|
+
await sleep3(500);
|
|
1813
|
+
const latest = runtime.snapshotsRepo.getLatest();
|
|
1814
|
+
if (latest && latest.snapshot_hash !== currentHash) {
|
|
1815
|
+
currentHash = latest.snapshot_hash;
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
return void 0;
|
|
1819
|
+
}
|
|
1758
1820
|
const server = new McpServer({
|
|
1759
1821
|
name: SERVER_NAME,
|
|
1760
1822
|
version: SERVER_VERSION,
|
|
@@ -1790,23 +1852,31 @@ function createMcpServer({
|
|
|
1790
1852
|
query,
|
|
1791
1853
|
budgetTokens
|
|
1792
1854
|
}) => {
|
|
1793
|
-
const
|
|
1855
|
+
const deadline = Date.now() + runtime.config.maxQueryWaitMs;
|
|
1856
|
+
const latest = await waitForLocalSnapshot(deadline);
|
|
1794
1857
|
if (!latest) {
|
|
1795
|
-
const
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1858
|
+
const statusText = formatStatus(collectIndexingStatus(runtime, runner));
|
|
1859
|
+
const text = `We are not ready....
|
|
1860
|
+
${statusText}`;
|
|
1861
|
+
return { content: [{ type: "text", text }] };
|
|
1862
|
+
}
|
|
1863
|
+
const readyHash = await waitForServerReady(
|
|
1864
|
+
latest.snapshot_hash,
|
|
1865
|
+
deadline
|
|
1866
|
+
);
|
|
1867
|
+
if (!readyHash) {
|
|
1868
|
+
const statusText = formatStatus(collectIndexingStatus(runtime, runner));
|
|
1869
|
+
const text = `We are not ready....
|
|
1870
|
+
${statusText}`;
|
|
1871
|
+
return { content: [{ type: "text", text }] };
|
|
1800
1872
|
}
|
|
1801
1873
|
const effectiveBudget = Math.max(100, budgetTokens ?? 3e3);
|
|
1802
1874
|
try {
|
|
1803
1875
|
const result = await runtime.clients.retrieval.query(
|
|
1804
|
-
|
|
1876
|
+
readyHash,
|
|
1805
1877
|
query,
|
|
1806
1878
|
effectiveBudget,
|
|
1807
|
-
{
|
|
1808
|
-
formatter: runtime.config.retrievalFormatter
|
|
1809
|
-
}
|
|
1879
|
+
{ formatter: runtime.config.retrievalFormatter }
|
|
1810
1880
|
);
|
|
1811
1881
|
return {
|
|
1812
1882
|
content: [
|
|
@@ -1845,7 +1915,9 @@ var ENV_FLAG_MAP = {
|
|
|
1845
1915
|
"queue-poll": "CODERULE_QUEUE_POLL_INTERVAL_MS",
|
|
1846
1916
|
"hash-batch": "CODERULE_HASH_BATCH_SIZE",
|
|
1847
1917
|
"hash-lease": "CODERULE_HASH_LEASE_MS",
|
|
1848
|
-
"max-snapshot-attempts": "CODERULE_MAX_SNAPSHOT_ATTEMPTS"
|
|
1918
|
+
"max-snapshot-attempts": "CODERULE_MAX_SNAPSHOT_ATTEMPTS",
|
|
1919
|
+
"upload-chunk-size": "CODERULE_UPLOAD_CHUNK_SIZE",
|
|
1920
|
+
"max-wait-time": "CODERULE_MAX_WAIT_TIME"
|
|
1849
1921
|
};
|
|
1850
1922
|
function printUsage() {
|
|
1851
1923
|
console.log(`Usage: coderule-mcp-server [token] [options]
|
|
@@ -1887,6 +1959,12 @@ function printUsage() {
|
|
|
1887
1959
|
console.log(
|
|
1888
1960
|
" --max-snapshot-attempts <n> Override CODERULE_MAX_SNAPSHOT_ATTEMPTS"
|
|
1889
1961
|
);
|
|
1962
|
+
console.log(
|
|
1963
|
+
" --upload-chunk-size <n> Override CODERULE_UPLOAD_CHUNK_SIZE (default 1)"
|
|
1964
|
+
);
|
|
1965
|
+
console.log(
|
|
1966
|
+
" --max-wait-time <sec> Override CODERULE_MAX_WAIT_TIME (default 50s)"
|
|
1967
|
+
);
|
|
1890
1968
|
console.log(
|
|
1891
1969
|
" KEY=value Set arbitrary environment variable"
|
|
1892
1970
|
);
|
|
@@ -2008,15 +2086,21 @@ async function main() {
|
|
|
2008
2086
|
const runner = new ServiceRunner(runtime);
|
|
2009
2087
|
try {
|
|
2010
2088
|
await runner.prepareWatcher(true);
|
|
2089
|
+
const server = createMcpServer({ runtime, runner });
|
|
2090
|
+
const transport = new StdioServerTransport();
|
|
2091
|
+
await server.connect(transport);
|
|
2092
|
+
runtime.logger.info("MCP server connected via stdio");
|
|
2011
2093
|
let initialCreatedAt;
|
|
2012
2094
|
try {
|
|
2013
|
-
const initial = await runInitialSyncPipeline(runtime
|
|
2095
|
+
const initial = await runInitialSyncPipeline(runtime, {
|
|
2096
|
+
blockUntilReady: false
|
|
2097
|
+
});
|
|
2014
2098
|
runtime.logger.info(
|
|
2015
2099
|
{
|
|
2016
2100
|
snapshotHash: initial.snapshotHash,
|
|
2017
2101
|
filesCount: initial.filesCount
|
|
2018
2102
|
},
|
|
2019
|
-
"Initial sync completed;
|
|
2103
|
+
"Initial sync completed; entering continuous mode"
|
|
2020
2104
|
);
|
|
2021
2105
|
initialCreatedAt = initial.createdAt;
|
|
2022
2106
|
} catch (error) {
|
|
@@ -2031,10 +2115,6 @@ async function main() {
|
|
|
2031
2115
|
}
|
|
2032
2116
|
await runner.startLoops();
|
|
2033
2117
|
await runner.enableWatcherProcessing();
|
|
2034
|
-
const server = createMcpServer({ runtime, runner });
|
|
2035
|
-
const transport = new StdioServerTransport();
|
|
2036
|
-
await server.connect(transport);
|
|
2037
|
-
runtime.logger.info("MCP server connected via stdio");
|
|
2038
2118
|
const signal = await awaitShutdownSignals();
|
|
2039
2119
|
runtime.logger.info({ signal }, "Shutdown signal received");
|
|
2040
2120
|
if (typeof transport.close === "function") {
|