@reposkein/mcp 0.3.0 → 0.5.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.
Files changed (117) hide show
  1. package/README.md +76 -1
  2. package/binary-digests.json +4 -4
  3. package/dist/SKILL.md +19 -0
  4. package/dist/cli/agentAdapters.d.ts +68 -0
  5. package/dist/cli/agentAdapters.js +223 -0
  6. package/dist/cli/agentAdapters.js.map +1 -0
  7. package/dist/cli/ansi.d.ts +24 -0
  8. package/dist/cli/ansi.js +40 -0
  9. package/dist/cli/ansi.js.map +1 -0
  10. package/dist/cli/doctor.d.ts +34 -2
  11. package/dist/cli/doctor.js +51 -6
  12. package/dist/cli/doctor.js.map +1 -1
  13. package/dist/cli/doctorFreshness.d.ts +43 -0
  14. package/dist/cli/doctorFreshness.js +111 -0
  15. package/dist/cli/doctorFreshness.js.map +1 -0
  16. package/dist/cli/doctorSummaries.d.ts +2 -0
  17. package/dist/cli/doctorSummaries.js +95 -0
  18. package/dist/cli/doctorSummaries.js.map +1 -0
  19. package/dist/cli/federatedDiscovery.d.ts +16 -0
  20. package/dist/cli/federatedDiscovery.js +75 -0
  21. package/dist/cli/federatedDiscovery.js.map +1 -0
  22. package/dist/cli/init.d.ts +69 -6
  23. package/dist/cli/init.js +194 -28
  24. package/dist/cli/init.js.map +1 -1
  25. package/dist/cli/sourceSlices.d.ts +17 -0
  26. package/dist/cli/sourceSlices.js +59 -0
  27. package/dist/cli/sourceSlices.js.map +1 -0
  28. package/dist/cli/stats.d.ts +29 -0
  29. package/dist/cli/stats.js +180 -0
  30. package/dist/cli/stats.js.map +1 -0
  31. package/dist/cli/view.d.ts +71 -3
  32. package/dist/cli/view.js +170 -14
  33. package/dist/cli/view.js.map +1 -1
  34. package/dist/index.d.ts +8 -48
  35. package/dist/index.js +94 -295
  36. package/dist/index.js.map +1 -1
  37. package/dist/indexer/fetchBinary.d.ts +14 -0
  38. package/dist/indexer/fetchBinary.js +81 -40
  39. package/dist/indexer/fetchBinary.js.map +1 -1
  40. package/dist/indexer/indexLock.d.ts +13 -0
  41. package/dist/indexer/indexLock.js +66 -0
  42. package/dist/indexer/indexLock.js.map +1 -0
  43. package/dist/indexer/runIndexer.d.ts +8 -2
  44. package/dist/indexer/runIndexer.js +20 -4
  45. package/dist/indexer/runIndexer.js.map +1 -1
  46. package/dist/serve/serve.d.ts +95 -0
  47. package/dist/serve/serve.js +581 -0
  48. package/dist/serve/serve.js.map +1 -0
  49. package/dist/serve/tokens.d.ts +49 -0
  50. package/dist/serve/tokens.js +108 -0
  51. package/dist/serve/tokens.js.map +1 -0
  52. package/dist/serve/watch.d.ts +73 -0
  53. package/dist/serve/watch.js +135 -0
  54. package/dist/serve/watch.js.map +1 -0
  55. package/dist/server/createMcpServer.d.ts +129 -0
  56. package/dist/server/createMcpServer.js +464 -0
  57. package/dist/server/createMcpServer.js.map +1 -0
  58. package/dist/store/JsonlGraphStore.d.ts +18 -4
  59. package/dist/store/JsonlGraphStore.js +61 -19
  60. package/dist/store/JsonlGraphStore.js.map +1 -1
  61. package/dist/store/decisions.d.ts +20 -2
  62. package/dist/store/decisions.js +35 -2
  63. package/dist/store/decisions.js.map +1 -1
  64. package/dist/store/indexedAt.d.ts +18 -0
  65. package/dist/store/indexedAt.js +56 -0
  66. package/dist/store/indexedAt.js.map +1 -0
  67. package/dist/store/instrumentTool.d.ts +40 -0
  68. package/dist/store/instrumentTool.js +82 -0
  69. package/dist/store/instrumentTool.js.map +1 -0
  70. package/dist/store/repoContextCache.d.ts +15 -0
  71. package/dist/store/repoContextCache.js +26 -0
  72. package/dist/store/repoContextCache.js.map +1 -0
  73. package/dist/store/repoSession.d.ts +63 -0
  74. package/dist/store/repoSession.js +123 -0
  75. package/dist/store/repoSession.js.map +1 -0
  76. package/dist/store/resolveRepoPath.d.ts +31 -0
  77. package/dist/store/resolveRepoPath.js +85 -0
  78. package/dist/store/resolveRepoPath.js.map +1 -0
  79. package/dist/store/sessionLog.d.ts +98 -0
  80. package/dist/store/sessionLog.js +216 -0
  81. package/dist/store/sessionLog.js.map +1 -0
  82. package/dist/store/sessionStats.d.ts +55 -0
  83. package/dist/store/sessionStats.js +140 -0
  84. package/dist/store/sessionStats.js.map +1 -0
  85. package/dist/store/sidecar.d.ts +39 -3
  86. package/dist/store/sidecar.js +89 -5
  87. package/dist/store/sidecar.js.map +1 -1
  88. package/dist/store/summaryShards.d.ts +117 -0
  89. package/dist/store/summaryShards.js +291 -0
  90. package/dist/store/summaryShards.js.map +1 -0
  91. package/dist/store/teamConfig.d.ts +17 -0
  92. package/dist/store/teamConfig.js +55 -0
  93. package/dist/store/teamConfig.js.map +1 -0
  94. package/dist/tools/indexerTools.d.ts +14 -2
  95. package/dist/tools/indexerTools.js +17 -5
  96. package/dist/tools/indexerTools.js.map +1 -1
  97. package/dist/tools/recordDecision.d.ts +3 -0
  98. package/dist/tools/recordDecision.js +7 -2
  99. package/dist/tools/recordDecision.js.map +1 -1
  100. package/dist/tools/writeSemanticSummary.d.ts +4 -1
  101. package/dist/tools/writeSemanticSummary.js +5 -2
  102. package/dist/tools/writeSemanticSummary.js.map +1 -1
  103. package/dist/viz/assets/{graph.worker-CC7BeE-8.js → graph.worker-DkH6-lMU.js} +1 -1
  104. package/dist/viz/assets/index-BnqIVYFE.css +1 -0
  105. package/dist/viz/assets/index-IhtszTp0.js +5 -0
  106. package/dist/viz/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  107. package/dist/viz/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  108. package/dist/viz/assets/jetbrains-mono-latin-700-normal-BYuf6tUa.woff2 +0 -0
  109. package/dist/viz/assets/r3f-Bn9htB92.js +336 -0
  110. package/dist/viz/assets/tanstack-CSzx6NDA.js +62 -0
  111. package/dist/viz/assets/three-Cpu5RUEM.js +4116 -0
  112. package/dist/viz/index.html +5 -4
  113. package/package.json +5 -4
  114. package/dist/viz/assets/index-C_8UkiJ8.js +0 -9
  115. package/dist/viz/assets/r3f-Cku1OhB-.js +0 -277
  116. package/dist/viz/assets/tanstack-DyXcNRWk.js +0 -77
  117. package/dist/viz/assets/three-Z8XaLGmf.js +0 -3839
@@ -1,8 +1,9 @@
1
1
  import { createWriteStream, existsSync, mkdirSync, chmodSync, statSync, readFileSync, unlinkSync, renameSync } from "node:fs";
2
2
  import { createHash, randomBytes } from "node:crypto";
3
- import { get } from "node:https";
4
3
  import { dirname, join } from "node:path";
5
4
  import { fileURLToPath } from "node:url";
5
+ import { pipeline } from "node:stream/promises";
6
+ import { request, EnvHttpProxyAgent } from "undici";
6
7
  /** Supported platform keys → must match the release asset suffixes (D2).
7
8
  * Intel macOS (darwin-x64) is intentionally unsupported: all Macs have shipped
8
9
  * Apple Silicon since 2020, and GitHub's macos-13 Intel runners are scarce and
@@ -28,6 +29,48 @@ export function platformKey(platform = process.platform, arch = process.arch) {
28
29
  export function isWindows(platform = process.platform) {
29
30
  return platform === "win32";
30
31
  }
32
+ /** Whether this host has a prebuilt indexer release asset. Convenience
33
+ * wrapper over `platformKey()` for call sites that just need a boolean
34
+ * (e.g. `init`'s pre-flight check, before attempting any fetch). */
35
+ export function isSupportedPlatform(platform = process.platform, arch = process.arch) {
36
+ return platformKey(platform, arch) !== null;
37
+ }
38
+ /** Printed when a host has no prebuilt indexer (darwin-x64, win32-arm64, …):
39
+ * the from-source fallback plus the offline override env var, so `init` can
40
+ * continue (write agent config, skip only the binary-dependent steps)
41
+ * instead of crashing. See docs/INSTALL.md §2 "Platform support". */
42
+ export function cargoInstallFallbackMessage(platform = process.platform, arch = process.arch) {
43
+ return (`reposkein: no prebuilt indexer for ${platform}-${arch}. Build from source:\n` +
44
+ " git clone https://github.com/reposkein/reposkein.git && cd reposkein\n" +
45
+ " cargo install --path indexer/crates/cli --root ./cargo-out\n" +
46
+ " export REPOSKEIN_INDEXER_BIN=$PWD/cargo-out/bin/reposkein-indexer\n" +
47
+ "Then re-run `reposkein-mcp init` (or `doctor`/`index`) with that env var set — " +
48
+ "REPOSKEIN_INDEXER_BIN is also the offline fallback on supported platforms " +
49
+ "when the GitHub Releases fetch is unreachable.");
50
+ }
51
+ /** Reads HTTP(S)_PROXY / NO_PROXY (either case) via undici's
52
+ * `EnvHttpProxyAgent` — the standard way to proxy `undici.request()` once
53
+ * undici is a direct dependency (the global `fetch`'s own undici instance
54
+ * isn't importable to attach a dispatcher to). Returns `undefined` (use
55
+ * undici's default, non-proxying dispatcher) when no proxy env var is set,
56
+ * so the common case pays zero extra cost. Cached per-process — proxy env
57
+ * vars don't change mid-run. */
58
+ let _proxyDispatcher;
59
+ export function proxyDispatcher() {
60
+ if (_proxyDispatcher !== undefined)
61
+ return _proxyDispatcher ?? undefined;
62
+ const hasProxyEnv = !!(process.env.HTTPS_PROXY ||
63
+ process.env.https_proxy ||
64
+ process.env.HTTP_PROXY ||
65
+ process.env.http_proxy);
66
+ _proxyDispatcher = hasProxyEnv ? new EnvHttpProxyAgent() : null;
67
+ return _proxyDispatcher ?? undefined;
68
+ }
69
+ /** For testing only: reset the cached proxy dispatcher so env var changes
70
+ * take effect on the next call. */
71
+ export function _resetProxyDispatcherCache() {
72
+ _proxyDispatcher = undefined;
73
+ }
31
74
  /** Release asset name for a platform key, e.g. reposkein-indexer-darwin-arm64. */
32
75
  export function assetName(key) {
33
76
  return `reposkein-indexer-${key}${key.startsWith("win32") ? ".exe" : ""}`;
@@ -96,45 +139,43 @@ export function verifyDigest(tempPath, expected) {
96
139
  }
97
140
  /** Follows redirects (GitHub release assets redirect to a CDN) and streams the
98
141
  * body to `dest`. Rejects on non-2xx (after redirects) or network error.
99
- * Redirect hardening: only follows https:// redirects to github.com or *.githubusercontent.com. */
100
- function downloadTo(url, dest, redirects = 5) {
101
- return new Promise((resolve, reject) => {
102
- get(url, (res) => {
103
- const status = res.statusCode ?? 0;
104
- if (status >= 300 && status < 400 && res.headers.location) {
105
- if (redirects <= 0) {
106
- reject(new Error("too many redirects"));
107
- return;
108
- }
109
- const location = res.headers.location;
110
- const next = new URL(location, url);
111
- if (next.protocol !== "https:") {
112
- reject(new Error(`reposkein: redirect to non-https URL rejected: ${next.href}`));
113
- return;
114
- }
115
- const host = next.hostname;
116
- if (host !== "github.com" &&
117
- host !== "objects.githubusercontent.com" &&
118
- !host.endsWith(".githubusercontent.com")) {
119
- reject(new Error(`reposkein: redirect to non-allowlisted host rejected: ${host}`));
120
- return;
121
- }
122
- res.resume();
123
- downloadTo(next.href, dest, redirects - 1).then(resolve, reject);
124
- return;
125
- }
126
- if (status !== 200) {
127
- res.resume();
128
- reject(new Error(`download failed: HTTP ${status} for ${url}`));
129
- return;
130
- }
131
- mkdirSync(dirname(dest), { recursive: true });
132
- const file = createWriteStream(dest);
133
- res.pipe(file);
134
- file.on("finish", () => file.close(() => resolve()));
135
- file.on("error", reject);
136
- }).on("error", reject);
137
- });
142
+ * Redirect hardening: only follows https:// redirects to github.com or
143
+ * *.githubusercontent.com.
144
+ *
145
+ * Uses undici's `request()` (not node:https) so a `proxyDispatcher()` can be
146
+ * attached that's the only way to honor HTTPS_PROXY/NO_PROXY for this
147
+ * fetch, since the global `fetch()`'s own undici instance isn't reachable to
148
+ * set a dispatcher on. `request()` never auto-follows redirects (no redirect
149
+ * interceptor configured), so they're handled manually below to keep the
150
+ * host allowlist in the loop. */
151
+ async function downloadTo(url, dest, redirects = 5) {
152
+ const res = await request(url, { dispatcher: proxyDispatcher() });
153
+ const status = res.statusCode;
154
+ if (status >= 300 && status < 400 && res.headers.location) {
155
+ await res.body.dump().catch(() => { });
156
+ if (redirects <= 0) {
157
+ throw new Error("too many redirects");
158
+ }
159
+ const locationHeader = res.headers.location;
160
+ const location = Array.isArray(locationHeader) ? locationHeader[0] : locationHeader;
161
+ const next = new URL(location, url);
162
+ if (next.protocol !== "https:") {
163
+ throw new Error(`reposkein: redirect to non-https URL rejected: ${next.href}`);
164
+ }
165
+ const host = next.hostname;
166
+ if (host !== "github.com" &&
167
+ host !== "objects.githubusercontent.com" &&
168
+ !host.endsWith(".githubusercontent.com")) {
169
+ throw new Error(`reposkein: redirect to non-allowlisted host rejected: ${host}`);
170
+ }
171
+ return downloadTo(next.href, dest, redirects - 1);
172
+ }
173
+ if (status !== 200) {
174
+ await res.body.dump().catch(() => { });
175
+ throw new Error(`download failed: HTTP ${status} for ${url}`);
176
+ }
177
+ mkdirSync(dirname(dest), { recursive: true });
178
+ await pipeline(res.body, createWriteStream(dest));
138
179
  }
139
180
  /** Downloads the indexer binary for this host into the package cache, verifies
140
181
  * its integrity, makes it executable, and atomically renames it into place.
@@ -1 +1 @@
1
- {"version":3,"file":"fetchBinary.js","sourceRoot":"","sources":["../../src/indexer/fetchBinary.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fetchBinary.js","sourceRoot":"","sources":["../../src/indexer/fetchBinary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /** True when an indexer run is in progress OR queued.
2
+ *
3
+ * Deliberately counts waiters, not just the active holder: the HEAD watcher
4
+ * uses this to SKIP a tick rather than queue behind a tool call, and a tick
5
+ * that queued would fire a redundant index the moment the tool's run
6
+ * finished — for a HEAD the tool's own run has by then already indexed. */
7
+ export declare function isIndexLockHeld(): boolean;
8
+ /** Runs `fn` with exclusive access to the indexer. */
9
+ export declare function withIndexLock<T>(fn: () => Promise<T>): Promise<T>;
10
+ /** Test-only: drains the queue so one suite's leftovers can't wedge the next.
11
+ * Never call this from production code — it does not cancel a running
12
+ * holder, it only waits for the queue to empty. */
13
+ export declare function drainIndexLock(): Promise<void>;
@@ -0,0 +1,66 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ /** Process-wide mutual exclusion for indexer invocations.
3
+ *
4
+ * Every `reposkein-indexer` run writes into the served checkout's
5
+ * `.reposkein/` — `nodes.jsonl`, `edges.jsonl`, the committed summary shards,
6
+ * the pending-drift delta. Two runs at once on one checkout interleave those
7
+ * writes, and the loser's output is whatever the filesystem happened to
8
+ * order last. That was survivable while the server was one stdio process
9
+ * serving one agent: index runs were driven by one caller, one at a time.
10
+ *
11
+ * `serve --http` (REP-17) removes that accident. A write-capable tool call
12
+ * (`reindex_file`, `init_cpg_skeleton`, `record_decision`'s pre-stamp
13
+ * refresh) can now land while the HEAD watcher is mid-reindex, from a
14
+ * different connection, with no shared call stack to serialize them. So the
15
+ * serialization has to be explicit and it has to be somewhere no future
16
+ * caller can forget it — which is inside `spawnIndexer` itself, the single
17
+ * choke point every invocation passes through.
18
+ *
19
+ * Reentrancy-safe: a lock holder that (now or later) reaches `spawnIndexer`
20
+ * again runs straight through instead of deadlocking the process against
21
+ * itself. FIFO: waiters run in arrival order, so a queued tool call can't be
22
+ * starved by a fast-polling watcher. */
23
+ const reentrant = new AsyncLocalStorage();
24
+ /** Tail of the FIFO queue: resolves when every already-queued holder is done. */
25
+ let tail = Promise.resolve();
26
+ /** Holders plus waiters. Drives `isIndexLockHeld` (see its doc comment). */
27
+ let outstanding = 0;
28
+ /** True when an indexer run is in progress OR queued.
29
+ *
30
+ * Deliberately counts waiters, not just the active holder: the HEAD watcher
31
+ * uses this to SKIP a tick rather than queue behind a tool call, and a tick
32
+ * that queued would fire a redundant index the moment the tool's run
33
+ * finished — for a HEAD the tool's own run has by then already indexed. */
34
+ export function isIndexLockHeld() {
35
+ return outstanding > 0;
36
+ }
37
+ /** Runs `fn` with exclusive access to the indexer. */
38
+ export async function withIndexLock(fn) {
39
+ // Already ours (a nested spawn inside a lock-holding operation): proceed.
40
+ if (reentrant.getStore())
41
+ return fn();
42
+ outstanding++;
43
+ let release;
44
+ const mine = new Promise((r) => {
45
+ release = r;
46
+ });
47
+ const prior = tail;
48
+ // A rejection can't come from `mine` (release never throws), but chain
49
+ // defensively: a broken tail would wedge every future acquisition.
50
+ tail = prior.then(() => mine).catch(() => undefined);
51
+ try {
52
+ await prior;
53
+ return await reentrant.run(true, fn);
54
+ }
55
+ finally {
56
+ outstanding--;
57
+ release();
58
+ }
59
+ }
60
+ /** Test-only: drains the queue so one suite's leftovers can't wedge the next.
61
+ * Never call this from production code — it does not cancel a running
62
+ * holder, it only waits for the queue to empty. */
63
+ export async function drainIndexLock() {
64
+ await tail;
65
+ }
66
+ //# sourceMappingURL=indexLock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexLock.js","sourceRoot":"","sources":["../../src/indexer/indexLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;yCAoByC;AAEzC,MAAM,SAAS,GAAG,IAAI,iBAAiB,EAAQ,CAAC;AAEhD,iFAAiF;AACjF,IAAI,IAAI,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;AAC5C,4EAA4E;AAC5E,IAAI,WAAW,GAAG,CAAC,CAAC;AAEpB;;;;;4EAK4E;AAC5E,MAAM,UAAU,eAAe;IAC7B,OAAO,WAAW,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,sDAAsD;AACtD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAI,EAAoB;IACzD,0EAA0E;IAC1E,IAAI,SAAS,CAAC,QAAQ,EAAE;QAAE,OAAO,EAAE,EAAE,CAAC;IAEtC,WAAW,EAAE,CAAC;IACd,IAAI,OAAoB,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE;QACnC,OAAO,GAAG,CAAC,CAAC;IACd,CAAC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,IAAI,CAAC;IACnB,uEAAuE;IACvE,mEAAmE;IACnE,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACrD,IAAI,CAAC;QACH,MAAM,KAAK,CAAC;QACZ,OAAO,MAAM,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACvC,CAAC;YAAS,CAAC;QACT,WAAW,EAAE,CAAC;QACd,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;oDAEoD;AACpD,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,IAAI,CAAC;AACb,CAAC"}
@@ -3,8 +3,14 @@ export interface SpawnResult {
3
3
  stdout: string;
4
4
  stderr: string;
5
5
  }
6
- /** Repo root the indexer operates on: REPOSKEIN_REPO_PATH or cwd. */
7
- export declare function repoPath(): string;
6
+ /** Runs the indexer binary, capped and timed out.
7
+ *
8
+ * Serialized process-wide by `withIndexLock`: every invocation writes into
9
+ * the target checkout's `.reposkein/`, and since REP-17 two callers (a
10
+ * write-capable tool call on one connection, the HEAD watcher on another) can
11
+ * arrive concurrently with no shared call stack to order them. The lock lives
12
+ * HERE rather than at each call site so a new call site cannot forget it —
13
+ * see `indexLock.ts`. */
8
14
  export declare function spawnIndexer(bin: string, args: string[]): Promise<SpawnResult>;
9
15
  export interface IndexJsonStats {
10
16
  repo_id: string;
@@ -1,4 +1,5 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { withIndexLock } from "./indexLock.js";
2
3
  const ALLOWED_KEYS = new Set(["PATH", "HOME", "TMPDIR", "LANG", "LC_ALL", "NEO4J_URI", "NEO4J_USER", "NEO4J_PASSWORD"]);
3
4
  /** Indexer spawn timeout (~10 minutes). Large repos can be slow but shouldn't hang forever. */
4
5
  const INDEXER_TIMEOUT_MS = 600_000;
@@ -13,11 +14,26 @@ function buildChildEnv() {
13
14
  }
14
15
  return env;
15
16
  }
16
- /** Repo root the indexer operates on: REPOSKEIN_REPO_PATH or cwd. */
17
- export function repoPath() {
18
- return process.env.REPOSKEIN_REPO_PATH ?? process.cwd();
19
- }
17
+ // NOTE: there used to be a `repoPath()` here (REPOSKEIN_REPO_PATH ?? cwd),
18
+ // an independent repo-path resolver `tools/indexerTools.ts` called instead
19
+ // of using its caller's already-resolved active repo. That let init/reindex
20
+ // bypass session.select_repo entirely and index the wrong repo in workspace
21
+ // mode — removed; every caller now takes an explicit `repoPath` param
22
+ // sourced from mcp/src/store/repoSession.ts. Don't reintroduce an
23
+ // env/cwd-based resolver here — see mcp/src/store/resolveRepoPath.ts for the
24
+ // one central resolution algorithm.
25
+ /** Runs the indexer binary, capped and timed out.
26
+ *
27
+ * Serialized process-wide by `withIndexLock`: every invocation writes into
28
+ * the target checkout's `.reposkein/`, and since REP-17 two callers (a
29
+ * write-capable tool call on one connection, the HEAD watcher on another) can
30
+ * arrive concurrently with no shared call stack to order them. The lock lives
31
+ * HERE rather than at each call site so a new call site cannot forget it —
32
+ * see `indexLock.ts`. */
20
33
  export function spawnIndexer(bin, args) {
34
+ return withIndexLock(() => spawnIndexerUnlocked(bin, args));
35
+ }
36
+ function spawnIndexerUnlocked(bin, args) {
21
37
  return new Promise((resolve, reject) => {
22
38
  const child = spawn(bin, args, { env: buildChildEnv() });
23
39
  let stdout = "";
@@ -1 +1 @@
1
- {"version":3,"file":"runIndexer.js","sourceRoot":"","sources":["../../src/indexer/runIndexer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runIndexer.js","sourceRoot":"","sources":["../../src/indexer/runIndexer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ import { type IncomingMessage, type ServerResponse } from "node:http";
2
+ import { type CreateMcpServerOptions } from "../server/createMcpServer.js";
3
+ import { type ServeToken } from "./tokens.js";
4
+ /** The one path the MCP Streamable HTTP transport answers on. Everything else
5
+ * is the viewer + `/api/*`, served by view.ts's own handler. */
6
+ export declare const MCP_PATH = "/mcp";
7
+ export interface ServeOptions {
8
+ port: number;
9
+ host: string;
10
+ /** `git rev-parse HEAD` poll interval. 0 disables the watcher. */
11
+ watchIntervalMs: number;
12
+ }
13
+ /** Default bind host. NOT 0.0.0.0: even in the mode that exists to be
14
+ * reachable, exposure is an explicit `--host` decision by the operator. */
15
+ export declare const DEFAULT_SERVE_HOST = "127.0.0.1";
16
+ export declare const DEFAULT_SERVE_PORT = 4318;
17
+ export declare const DEFAULT_WATCH_INTERVAL_MS = 30000;
18
+ export declare function parseServeArgs(argv: string[]): {
19
+ repoPath: string;
20
+ opts: ServeOptions;
21
+ http: boolean;
22
+ };
23
+ type NodeHandler = (req: IncomingMessage, res: ServerResponse) => void;
24
+ export interface CreateServeAppOptions {
25
+ repoPath: string;
26
+ repoId: string;
27
+ tokens: readonly ServeToken[];
28
+ log?: (message: string) => void;
29
+ /** Test seam: replaces `makeViewHandler` (which reads the repo's JSONL and
30
+ * shells out to git at construction time). */
31
+ viewHandlerFactory?: (repoPath: string, repoId: string) => NodeHandler;
32
+ /** Test seam: passed through to every per-connection `createMcpServer`. */
33
+ ensureGraph?: CreateMcpServerOptions["ensureGraph"];
34
+ /** Concurrent-session cap. Defaults to `MAX_SESSIONS` (64); lowered in
35
+ * tests so the cap and the reaper-then-retry path are cheap to exercise. */
36
+ maxSessions?: number;
37
+ /** Idle-session reap threshold. Defaults to `SESSION_IDLE_MS` (5 min). */
38
+ idleMs?: number;
39
+ /** Clock. Injectable so the reaper can be tested without waiting minutes. */
40
+ now?: () => number;
41
+ }
42
+ export interface ServeApp {
43
+ handler: NodeHandler;
44
+ /** Rebuilds the `/api/*` handler. The view handler snapshots node/edge
45
+ * counts and git metadata once per construction, so after a re-index the
46
+ * hosted viewer would otherwise keep reporting the old graph — this is the
47
+ * watcher's `onReindexed` hook, and it is why the MCP tools and the viewer
48
+ * cannot drift apart: they are refreshed by the same event. */
49
+ refresh: () => void;
50
+ /** Closes every session idle past `idleMs` with no request in flight, and
51
+ * returns how many it closed. Called automatically before each new-session
52
+ * attempt (so a server wedged at the cap by dead clients frees itself on
53
+ * the next connect); exposed for tests. */
54
+ sweepIdleSessions: () => number;
55
+ close: () => Promise<void>;
56
+ sessionCount: () => number;
57
+ }
58
+ /** Builds the one request handler that answers both the MCP endpoint and the
59
+ * viewer/`/api/*` surface (REP-17 requirement: one process, one graph).
60
+ *
61
+ * URL layout:
62
+ * POST/GET/DELETE `/mcp` — MCP Streamable HTTP transport
63
+ * GET `/api/graph`, `/api/jsonl/*`, `/api/source`, `/api/temporal`
64
+ * — byte-identical to `reposkein-mcp view`, because
65
+ * it IS view.ts's handler, not a copy
66
+ * GET everything else — the prebuilt viewer SPA
67
+ *
68
+ * Auth applies to every route. `/mcp` accepts ONLY
69
+ * `Authorization: Bearer <token>`; the viewer routes additionally accept
70
+ * `?token=` (which is immediately traded for an HttpOnly cookie and
71
+ * redirected away, so it appears once) because a static SPA in a browser
72
+ * cannot attach an Authorization header to its own page load. */
73
+ export declare function createServeApp(opts: CreateServeAppOptions): ServeApp;
74
+ /** `git status --porcelain` for the served checkout, or null when git is
75
+ * unavailable / the path isn't a repo. Never throws. */
76
+ export declare function gitPorcelainStatus(repoPath: string): string[] | null;
77
+ /** The startup warning for serving a checkout with local modifications, or
78
+ * null when the tree is clean (or git can't tell us).
79
+ *
80
+ * Serving a dirty checkout is legal and sometimes exactly what an operator
81
+ * wants, so this WARNS and never refuses. But it is worth saying loudly:
82
+ * `serve`'s own re-index writes into `.reposkein/` (the committed summary
83
+ * shards absorb every `local/summaries-*.jsonl` sidecar), so a checkout that
84
+ * someone also works in will accumulate diffs that look like the server's
85
+ * fault — and a re-index landing on top of half-finished local edits indexes
86
+ * those edits. A dedicated deploy clone has neither problem. */
87
+ export declare function dirtyCheckoutWarning(repoPath: string, statusFn?: (p: string) => string[] | null): string | null;
88
+ /** `reposkein-mcp serve --http [path] [--port N] [--host H] [--watch-interval S]`.
89
+ *
90
+ * Strictly optional (REP-17 / adr:2026-08-21-optional-shared-remote-mcp-server-…):
91
+ * stdio is still the default transport and nothing binds a socket unless this
92
+ * runs. Refuses to start without at least one configured token — an
93
+ * unauthenticated remote MCP server would hand write access to the network. */
94
+ export declare function runServe(repoPath: string, repoId: string, opts: ServeOptions): Promise<number>;
95
+ export {};