@coderule/mcp 1.5.0 → 1.6.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/mcp-cli.cjs CHANGED
@@ -48,6 +48,8 @@ var DEFAULT_QUEUE_POLL_INTERVAL_MS = 500;
48
48
  var DEFAULT_HASH_BATCH_SIZE = 32;
49
49
  var DEFAULT_MAX_SNAPSHOT_ATTEMPTS = 5;
50
50
  var DEFAULT_HTTP_TIMEOUT_MS = 12e4;
51
+ var DEFAULT_UPLOAD_CHUNK_SIZE = 1;
52
+ var DEFAULT_MAX_QUERY_WAIT_MS = 5e4;
51
53
 
52
54
  // src/config/Configurator.ts
53
55
  var DEFAULT_RETRIEVAL_FORMATTER = "standard";
@@ -75,6 +77,14 @@ function parseInteger(value, fallback) {
75
77
  }
76
78
  return parsed;
77
79
  }
80
+ function parseSecondsToMs(value, fallbackMs) {
81
+ if (!value) return fallbackMs;
82
+ const seconds = Number.parseInt(value, 10);
83
+ if (Number.isNaN(seconds) || seconds <= 0) {
84
+ throw new Error(`Invalid seconds value: ${value}`);
85
+ }
86
+ return seconds * 1e3;
87
+ }
78
88
  function parseFormatter(value) {
79
89
  if (!value) return DEFAULT_RETRIEVAL_FORMATTER;
80
90
  const normalized = value.toLowerCase();
@@ -121,7 +131,9 @@ async function resolveConfig({
121
131
  maxSnapshotAttempts: DEFAULTS.maxSnapshotAttempts,
122
132
  retrievalFormatter: parseFormatter(
123
133
  process.env.CODERULE_RETRIEVAL_FORMATTER
124
- )
134
+ ),
135
+ uploadChunkSize: DEFAULT_UPLOAD_CHUNK_SIZE,
136
+ maxQueryWaitMs: DEFAULT_MAX_QUERY_WAIT_MS
125
137
  };
126
138
  if (process.env.CODERULE_SNAPSHOT_DEBOUNCE_MS) {
127
139
  baseConfig.snapshotDebounceMs = parseInteger(
@@ -163,6 +175,16 @@ async function resolveConfig({
163
175
  process.env.CODERULE_HTTP_TIMEOUT,
164
176
  DEFAULT_HTTP_TIMEOUT_MS
165
177
  );
178
+ if (process.env.CODERULE_UPLOAD_CHUNK_SIZE) {
179
+ baseConfig.uploadChunkSize = parseInteger(
180
+ process.env.CODERULE_UPLOAD_CHUNK_SIZE,
181
+ baseConfig.uploadChunkSize
182
+ );
183
+ }
184
+ baseConfig.maxQueryWaitMs = parseSecondsToMs(
185
+ process.env.CODERULE_MAX_WAIT_TIME,
186
+ baseConfig.maxQueryWaitMs
187
+ );
166
188
  logger.debug(
167
189
  {
168
190
  rootPath,
@@ -1096,7 +1118,7 @@ async function withRetries(op, logger2, context, maxAttempts) {
1096
1118
  }
1097
1119
  }
1098
1120
  }
1099
- async function uploadMissing(rootPath, missing, syncClient, logger2, maxAttempts, chunkSize = 64) {
1121
+ async function uploadMissing(rootPath, missing, syncClient, logger2, maxAttempts, chunkSize = 1) {
1100
1122
  if (!missing || missing.length === 0) return;
1101
1123
  const total = missing.length;
1102
1124
  const chunks = [];
@@ -1138,7 +1160,7 @@ async function uploadMissing(rootPath, missing, syncClient, logger2, maxAttempts
1138
1160
  async function ensureSnapshotCreated(rootPath, computation, syncClient, logger2, options) {
1139
1161
  const { snapshotHash, files } = computation;
1140
1162
  const maxAttempts = options?.maxAttempts ?? 5;
1141
- const uploadChunkSize = options?.uploadChunkSize ?? 64;
1163
+ const uploadChunkSize = options?.uploadChunkSize ?? 1;
1142
1164
  let status = await withRetries(
1143
1165
  () => syncClient.checkSnapshotStatus(snapshotHash),
1144
1166
  logger2,
@@ -1243,7 +1265,10 @@ async function runInitialSyncPipeline(runtime) {
1243
1265
  runtime.snapshotsRepo,
1244
1266
  runtime.clients.sync,
1245
1267
  syncLogger,
1246
- { maxAttempts: runtime.config.maxSnapshotAttempts }
1268
+ {
1269
+ maxAttempts: runtime.config.maxSnapshotAttempts,
1270
+ uploadChunkSize: runtime.config.uploadChunkSize
1271
+ }
1247
1272
  );
1248
1273
  return result;
1249
1274
  }
@@ -1647,7 +1672,10 @@ var ServiceRunner = class {
1647
1672
  this.runtime.snapshotsRepo,
1648
1673
  this.runtime.clients.sync,
1649
1674
  log,
1650
- { maxAttempts: this.runtime.config.maxSnapshotAttempts }
1675
+ {
1676
+ maxAttempts: this.runtime.config.maxSnapshotAttempts,
1677
+ uploadChunkSize: this.runtime.config.uploadChunkSize
1678
+ }
1651
1679
  );
1652
1680
  this.runtime.outbox.ack(job.id, this.fsControlLeaseOwner);
1653
1681
  this.state.updateSnapshotReady(result.createdAt);
@@ -1770,6 +1798,37 @@ function createMcpServer({
1770
1798
  runtime,
1771
1799
  runner
1772
1800
  }) {
1801
+ async function sleep3(ms) {
1802
+ return new Promise((resolve) => setTimeout(resolve, ms));
1803
+ }
1804
+ async function waitForLocalSnapshot(deadlineMs) {
1805
+ let latest = runtime.snapshotsRepo.getLatest();
1806
+ while (!latest && Date.now() < deadlineMs) {
1807
+ await sleep3(250);
1808
+ latest = runtime.snapshotsRepo.getLatest();
1809
+ }
1810
+ return latest;
1811
+ }
1812
+ async function waitForServerReady(initialHash, deadlineMs) {
1813
+ let currentHash = initialHash;
1814
+ while (Date.now() < deadlineMs) {
1815
+ try {
1816
+ const status = await runtime.clients.sync.checkSnapshotStatus(currentHash);
1817
+ if (status.status === "READY") {
1818
+ return currentHash;
1819
+ }
1820
+ if (status.status === "FAILED") {
1821
+ }
1822
+ } catch {
1823
+ }
1824
+ await sleep3(500);
1825
+ const latest = runtime.snapshotsRepo.getLatest();
1826
+ if (latest && latest.snapshot_hash !== currentHash) {
1827
+ currentHash = latest.snapshot_hash;
1828
+ }
1829
+ }
1830
+ return void 0;
1831
+ }
1773
1832
  const server = new mcp_js.McpServer({
1774
1833
  name: SERVER_NAME,
1775
1834
  version: SERVER_VERSION,
@@ -1805,23 +1864,31 @@ function createMcpServer({
1805
1864
  query,
1806
1865
  budgetTokens
1807
1866
  }) => {
1808
- const latest = runtime.snapshotsRepo.getLatest();
1867
+ const deadline = Date.now() + runtime.config.maxQueryWaitMs;
1868
+ const latest = await waitForLocalSnapshot(deadline);
1809
1869
  if (!latest) {
1810
- const message = "No snapshots available yet. Run indexing first.";
1811
- return {
1812
- content: [{ type: "text", text: message }],
1813
- isError: true
1814
- };
1870
+ const statusText = formatStatus(collectIndexingStatus(runtime, runner));
1871
+ const text = `We are not ready....
1872
+ ${statusText}`;
1873
+ return { content: [{ type: "text", text }] };
1874
+ }
1875
+ const readyHash = await waitForServerReady(
1876
+ latest.snapshot_hash,
1877
+ deadline
1878
+ );
1879
+ if (!readyHash) {
1880
+ const statusText = formatStatus(collectIndexingStatus(runtime, runner));
1881
+ const text = `We are not ready....
1882
+ ${statusText}`;
1883
+ return { content: [{ type: "text", text }] };
1815
1884
  }
1816
1885
  const effectiveBudget = Math.max(100, budgetTokens ?? 3e3);
1817
1886
  try {
1818
1887
  const result = await runtime.clients.retrieval.query(
1819
- latest.snapshot_hash,
1888
+ readyHash,
1820
1889
  query,
1821
1890
  effectiveBudget,
1822
- {
1823
- formatter: runtime.config.retrievalFormatter
1824
- }
1891
+ { formatter: runtime.config.retrievalFormatter }
1825
1892
  );
1826
1893
  return {
1827
1894
  content: [
@@ -1860,7 +1927,9 @@ var ENV_FLAG_MAP = {
1860
1927
  "queue-poll": "CODERULE_QUEUE_POLL_INTERVAL_MS",
1861
1928
  "hash-batch": "CODERULE_HASH_BATCH_SIZE",
1862
1929
  "hash-lease": "CODERULE_HASH_LEASE_MS",
1863
- "max-snapshot-attempts": "CODERULE_MAX_SNAPSHOT_ATTEMPTS"
1930
+ "max-snapshot-attempts": "CODERULE_MAX_SNAPSHOT_ATTEMPTS",
1931
+ "upload-chunk-size": "CODERULE_UPLOAD_CHUNK_SIZE",
1932
+ "max-wait-time": "CODERULE_MAX_WAIT_TIME"
1864
1933
  };
1865
1934
  function printUsage() {
1866
1935
  console.log(`Usage: coderule-mcp-server [token] [options]
@@ -1902,6 +1971,12 @@ function printUsage() {
1902
1971
  console.log(
1903
1972
  " --max-snapshot-attempts <n> Override CODERULE_MAX_SNAPSHOT_ATTEMPTS"
1904
1973
  );
1974
+ console.log(
1975
+ " --upload-chunk-size <n> Override CODERULE_UPLOAD_CHUNK_SIZE (default 1)"
1976
+ );
1977
+ console.log(
1978
+ " --max-wait-time <sec> Override CODERULE_MAX_WAIT_TIME (default 50s)"
1979
+ );
1905
1980
  console.log(
1906
1981
  " KEY=value Set arbitrary environment variable"
1907
1982
  );
@@ -2023,6 +2098,10 @@ async function main() {
2023
2098
  const runner = new ServiceRunner(runtime);
2024
2099
  try {
2025
2100
  await runner.prepareWatcher(true);
2101
+ const server = createMcpServer({ runtime, runner });
2102
+ const transport = new stdio_js.StdioServerTransport();
2103
+ await server.connect(transport);
2104
+ runtime.logger.info("MCP server connected via stdio");
2026
2105
  let initialCreatedAt;
2027
2106
  try {
2028
2107
  const initial = await runInitialSyncPipeline(runtime);
@@ -2031,7 +2110,7 @@ async function main() {
2031
2110
  snapshotHash: initial.snapshotHash,
2032
2111
  filesCount: initial.filesCount
2033
2112
  },
2034
- "Initial sync completed; starting MCP server"
2113
+ "Initial sync completed; entering continuous mode"
2035
2114
  );
2036
2115
  initialCreatedAt = initial.createdAt;
2037
2116
  } catch (error) {
@@ -2046,10 +2125,6 @@ async function main() {
2046
2125
  }
2047
2126
  await runner.startLoops();
2048
2127
  await runner.enableWatcherProcessing();
2049
- const server = createMcpServer({ runtime, runner });
2050
- const transport = new stdio_js.StdioServerTransport();
2051
- await server.connect(transport);
2052
- runtime.logger.info("MCP server connected via stdio");
2053
2128
  const signal = await awaitShutdownSignals();
2054
2129
  runtime.logger.info({ signal }, "Shutdown signal received");
2055
2130
  if (typeof transport.close === "function") {