@reposkein/mcp 0.4.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 (45) hide show
  1. package/README.md +3 -0
  2. package/binary-digests.json +4 -4
  3. package/dist/cli/view.js +27 -6
  4. package/dist/cli/view.js.map +1 -1
  5. package/dist/index.d.ts +8 -56
  6. package/dist/index.js +38 -402
  7. package/dist/index.js.map +1 -1
  8. package/dist/indexer/indexLock.d.ts +13 -0
  9. package/dist/indexer/indexLock.js +66 -0
  10. package/dist/indexer/indexLock.js.map +1 -0
  11. package/dist/indexer/runIndexer.d.ts +8 -0
  12. package/dist/indexer/runIndexer.js +12 -0
  13. package/dist/indexer/runIndexer.js.map +1 -1
  14. package/dist/serve/serve.d.ts +95 -0
  15. package/dist/serve/serve.js +581 -0
  16. package/dist/serve/serve.js.map +1 -0
  17. package/dist/serve/tokens.d.ts +49 -0
  18. package/dist/serve/tokens.js +108 -0
  19. package/dist/serve/tokens.js.map +1 -0
  20. package/dist/serve/watch.d.ts +73 -0
  21. package/dist/serve/watch.js +135 -0
  22. package/dist/serve/watch.js.map +1 -0
  23. package/dist/server/createMcpServer.d.ts +129 -0
  24. package/dist/server/createMcpServer.js +464 -0
  25. package/dist/server/createMcpServer.js.map +1 -0
  26. package/dist/store/JsonlGraphStore.d.ts +5 -1
  27. package/dist/store/JsonlGraphStore.js +6 -2
  28. package/dist/store/JsonlGraphStore.js.map +1 -1
  29. package/dist/store/teamConfig.d.ts +10 -6
  30. package/dist/store/teamConfig.js +23 -17
  31. package/dist/store/teamConfig.js.map +1 -1
  32. package/dist/tools/recordDecision.d.ts +3 -0
  33. package/dist/tools/recordDecision.js +1 -1
  34. package/dist/tools/recordDecision.js.map +1 -1
  35. package/dist/tools/writeSemanticSummary.d.ts +4 -1
  36. package/dist/tools/writeSemanticSummary.js +5 -2
  37. package/dist/tools/writeSemanticSummary.js.map +1 -1
  38. package/dist/viz/assets/index-BnqIVYFE.css +1 -0
  39. package/dist/viz/assets/index-IhtszTp0.js +5 -0
  40. package/dist/viz/assets/{r3f-BZY3QR6_.js → r3f-Bn9htB92.js} +1 -1
  41. package/dist/viz/assets/{tanstack-CjXr-L-s.js → tanstack-CSzx6NDA.js} +7 -7
  42. package/dist/viz/index.html +4 -4
  43. package/package.json +1 -1
  44. package/dist/viz/assets/index-CxqeGuRS.css +0 -1
  45. package/dist/viz/assets/index-DiNZyrXx.js +0 -9
@@ -3,6 +3,14 @@ export interface SpawnResult {
3
3
  stdout: string;
4
4
  stderr: string;
5
5
  }
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`. */
6
14
  export declare function spawnIndexer(bin: string, args: string[]): Promise<SpawnResult>;
7
15
  export interface IndexJsonStats {
8
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;
@@ -21,7 +22,18 @@ function buildChildEnv() {
21
22
  // sourced from mcp/src/store/repoSession.ts. Don't reintroduce an
22
23
  // env/cwd-based resolver here — see mcp/src/store/resolveRepoPath.ts for the
23
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`. */
24
33
  export function spawnIndexer(bin, args) {
34
+ return withIndexLock(() => spawnIndexerUnlocked(bin, args));
35
+ }
36
+ function spawnIndexerUnlocked(bin, args) {
25
37
  return new Promise((resolve, reject) => {
26
38
  const child = spawn(bin, args, { env: buildChildEnv() });
27
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 {};