@opensip-cli/mcp 0.1.15

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 (188) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +33 -0
  4. package/dist/__tests__/command-transport.test.d.ts +13 -0
  5. package/dist/__tests__/command-transport.test.d.ts.map +1 -0
  6. package/dist/__tests__/command-transport.test.js +63 -0
  7. package/dist/__tests__/command-transport.test.js.map +1 -0
  8. package/dist/__tests__/e2e-stdio.test.d.ts +16 -0
  9. package/dist/__tests__/e2e-stdio.test.d.ts.map +1 -0
  10. package/dist/__tests__/e2e-stdio.test.js +271 -0
  11. package/dist/__tests__/e2e-stdio.test.js.map +1 -0
  12. package/dist/__tests__/freshness.test.d.ts +9 -0
  13. package/dist/__tests__/freshness.test.d.ts.map +1 -0
  14. package/dist/__tests__/freshness.test.js +78 -0
  15. package/dist/__tests__/freshness.test.js.map +1 -0
  16. package/dist/__tests__/integration.test.d.ts +20 -0
  17. package/dist/__tests__/integration.test.d.ts.map +1 -0
  18. package/dist/__tests__/integration.test.js +178 -0
  19. package/dist/__tests__/integration.test.js.map +1 -0
  20. package/dist/__tests__/register-mcp-graph-adapters.test.d.ts +12 -0
  21. package/dist/__tests__/register-mcp-graph-adapters.test.d.ts.map +1 -0
  22. package/dist/__tests__/register-mcp-graph-adapters.test.js +47 -0
  23. package/dist/__tests__/register-mcp-graph-adapters.test.js.map +1 -0
  24. package/dist/__tests__/session-results-read-port.test.d.ts +13 -0
  25. package/dist/__tests__/session-results-read-port.test.d.ts.map +1 -0
  26. package/dist/__tests__/session-results-read-port.test.js +151 -0
  27. package/dist/__tests__/session-results-read-port.test.js.map +1 -0
  28. package/dist/__tests__/sqlite-graph-read-port.test.d.ts +12 -0
  29. package/dist/__tests__/sqlite-graph-read-port.test.d.ts.map +1 -0
  30. package/dist/__tests__/sqlite-graph-read-port.test.js +322 -0
  31. package/dist/__tests__/sqlite-graph-read-port.test.js.map +1 -0
  32. package/dist/__tests__/tool-descriptor.test.d.ts +9 -0
  33. package/dist/__tests__/tool-descriptor.test.d.ts.map +1 -0
  34. package/dist/__tests__/tool-descriptor.test.js +55 -0
  35. package/dist/__tests__/tool-descriptor.test.js.map +1 -0
  36. package/dist/catalog-generation.d.ts +22 -0
  37. package/dist/catalog-generation.d.ts.map +1 -0
  38. package/dist/catalog-generation.js +21 -0
  39. package/dist/catalog-generation.js.map +1 -0
  40. package/dist/command.d.ts +3 -0
  41. package/dist/command.d.ts.map +1 -0
  42. package/dist/command.js +111 -0
  43. package/dist/command.js.map +1 -0
  44. package/dist/freshness.d.ts +50 -0
  45. package/dist/freshness.d.ts.map +1 -0
  46. package/dist/freshness.js +96 -0
  47. package/dist/freshness.js.map +1 -0
  48. package/dist/graph-read-port.d.ts +111 -0
  49. package/dist/graph-read-port.d.ts.map +1 -0
  50. package/dist/graph-read-port.js +16 -0
  51. package/dist/graph-read-port.js.map +1 -0
  52. package/dist/index.d.ts +9 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +9 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/mcp-error.d.ts +15 -0
  57. package/dist/mcp-error.d.ts.map +1 -0
  58. package/dist/mcp-error.js +5 -0
  59. package/dist/mcp-error.js.map +1 -0
  60. package/dist/register-mcp-graph-adapters.d.ts +3 -0
  61. package/dist/register-mcp-graph-adapters.d.ts.map +1 -0
  62. package/dist/register-mcp-graph-adapters.js +21 -0
  63. package/dist/register-mcp-graph-adapters.js.map +1 -0
  64. package/dist/result-dto.d.ts +63 -0
  65. package/dist/result-dto.d.ts.map +1 -0
  66. package/dist/result-dto.js +11 -0
  67. package/dist/result-dto.js.map +1 -0
  68. package/dist/results-read-port.d.ts +43 -0
  69. package/dist/results-read-port.d.ts.map +1 -0
  70. package/dist/results-read-port.js +13 -0
  71. package/dist/results-read-port.js.map +1 -0
  72. package/dist/server.d.ts +84 -0
  73. package/dist/server.d.ts.map +1 -0
  74. package/dist/server.js +153 -0
  75. package/dist/server.js.map +1 -0
  76. package/dist/session-results-read-port.d.ts +42 -0
  77. package/dist/session-results-read-port.d.ts.map +1 -0
  78. package/dist/session-results-read-port.js +147 -0
  79. package/dist/session-results-read-port.js.map +1 -0
  80. package/dist/sqlite-graph-read-port.d.ts +88 -0
  81. package/dist/sqlite-graph-read-port.d.ts.map +1 -0
  82. package/dist/sqlite-graph-read-port.js +304 -0
  83. package/dist/sqlite-graph-read-port.js.map +1 -0
  84. package/dist/symbol-dto.d.ts +58 -0
  85. package/dist/symbol-dto.d.ts.map +1 -0
  86. package/dist/symbol-dto.js +12 -0
  87. package/dist/symbol-dto.js.map +1 -0
  88. package/dist/tool.d.ts +6 -0
  89. package/dist/tool.d.ts.map +1 -0
  90. package/dist/tool.js +33 -0
  91. package/dist/tool.js.map +1 -0
  92. package/dist/tools/__tests__/graph-handlers.test.d.ts +11 -0
  93. package/dist/tools/__tests__/graph-handlers.test.d.ts.map +1 -0
  94. package/dist/tools/__tests__/graph-handlers.test.js +415 -0
  95. package/dist/tools/__tests__/graph-handlers.test.js.map +1 -0
  96. package/dist/tools/__tests__/graph-walk.test.d.ts +9 -0
  97. package/dist/tools/__tests__/graph-walk.test.d.ts.map +1 -0
  98. package/dist/tools/__tests__/graph-walk.test.js +72 -0
  99. package/dist/tools/__tests__/graph-walk.test.js.map +1 -0
  100. package/dist/tools/__tests__/refresh-graph.test.d.ts +11 -0
  101. package/dist/tools/__tests__/refresh-graph.test.d.ts.map +1 -0
  102. package/dist/tools/__tests__/refresh-graph.test.js +100 -0
  103. package/dist/tools/__tests__/refresh-graph.test.js.map +1 -0
  104. package/dist/tools/__tests__/result-handlers.test.d.ts +9 -0
  105. package/dist/tools/__tests__/result-handlers.test.d.ts.map +1 -0
  106. package/dist/tools/__tests__/result-handlers.test.js +194 -0
  107. package/dist/tools/__tests__/result-handlers.test.js.map +1 -0
  108. package/dist/tools/__tests__/schemas.test.d.ts +10 -0
  109. package/dist/tools/__tests__/schemas.test.d.ts.map +1 -0
  110. package/dist/tools/__tests__/schemas.test.js +73 -0
  111. package/dist/tools/__tests__/schemas.test.js.map +1 -0
  112. package/dist/tools/blast-radius.d.ts +12 -0
  113. package/dist/tools/blast-radius.d.ts.map +1 -0
  114. package/dist/tools/blast-radius.js +33 -0
  115. package/dist/tools/blast-radius.js.map +1 -0
  116. package/dist/tools/call-walk-tool.d.ts +17 -0
  117. package/dist/tools/call-walk-tool.d.ts.map +1 -0
  118. package/dist/tools/call-walk-tool.js +46 -0
  119. package/dist/tools/call-walk-tool.js.map +1 -0
  120. package/dist/tools/callees-of.d.ts +12 -0
  121. package/dist/tools/callees-of.d.ts.map +1 -0
  122. package/dist/tools/callees-of.js +20 -0
  123. package/dist/tools/callees-of.js.map +1 -0
  124. package/dist/tools/find-dead-code.d.ts +11 -0
  125. package/dist/tools/find-dead-code.d.ts.map +1 -0
  126. package/dist/tools/find-dead-code.js +26 -0
  127. package/dist/tools/find-dead-code.js.map +1 -0
  128. package/dist/tools/get-agent-catalog.d.ts +12 -0
  129. package/dist/tools/get-agent-catalog.d.ts.map +1 -0
  130. package/dist/tools/get-agent-catalog.js +23 -0
  131. package/dist/tools/get-agent-catalog.js.map +1 -0
  132. package/dist/tools/get-architecture.d.ts +11 -0
  133. package/dist/tools/get-architecture.d.ts.map +1 -0
  134. package/dist/tools/get-architecture.js +26 -0
  135. package/dist/tools/get-architecture.js.map +1 -0
  136. package/dist/tools/get-latest-findings.d.ts +13 -0
  137. package/dist/tools/get-latest-findings.d.ts.map +1 -0
  138. package/dist/tools/get-latest-findings.js +38 -0
  139. package/dist/tools/get-latest-findings.js.map +1 -0
  140. package/dist/tools/get-symbol.d.ts +18 -0
  141. package/dist/tools/get-symbol.d.ts.map +1 -0
  142. package/dist/tools/get-symbol.js +44 -0
  143. package/dist/tools/get-symbol.js.map +1 -0
  144. package/dist/tools/graph-walk.d.ts +50 -0
  145. package/dist/tools/graph-walk.d.ts.map +1 -0
  146. package/dist/tools/graph-walk.js +89 -0
  147. package/dist/tools/graph-walk.js.map +1 -0
  148. package/dist/tools/list-runs.d.ts +11 -0
  149. package/dist/tools/list-runs.d.ts.map +1 -0
  150. package/dist/tools/list-runs.js +37 -0
  151. package/dist/tools/list-runs.js.map +1 -0
  152. package/dist/tools/refresh-graph.d.ts +22 -0
  153. package/dist/tools/refresh-graph.d.ts.map +1 -0
  154. package/dist/tools/refresh-graph.js +75 -0
  155. package/dist/tools/refresh-graph.js.map +1 -0
  156. package/dist/tools/register.d.ts +13 -0
  157. package/dist/tools/register.d.ts.map +1 -0
  158. package/dist/tools/register.js +40 -0
  159. package/dist/tools/register.js.map +1 -0
  160. package/dist/tools/schemas.d.ts +54 -0
  161. package/dist/tools/schemas.d.ts.map +1 -0
  162. package/dist/tools/schemas.js +59 -0
  163. package/dist/tools/schemas.js.map +1 -0
  164. package/dist/tools/search-symbols.d.ts +12 -0
  165. package/dist/tools/search-symbols.d.ts.map +1 -0
  166. package/dist/tools/search-symbols.js +37 -0
  167. package/dist/tools/search-symbols.js.map +1 -0
  168. package/dist/tools/show-run.d.ts +12 -0
  169. package/dist/tools/show-run.d.ts.map +1 -0
  170. package/dist/tools/show-run.js +40 -0
  171. package/dist/tools/show-run.js.map +1 -0
  172. package/dist/tools/tool-result.d.ts +29 -0
  173. package/dist/tools/tool-result.d.ts.map +1 -0
  174. package/dist/tools/tool-result.js +39 -0
  175. package/dist/tools/tool-result.js.map +1 -0
  176. package/dist/tools/trace-path.d.ts +12 -0
  177. package/dist/tools/trace-path.d.ts.map +1 -0
  178. package/dist/tools/trace-path.js +57 -0
  179. package/dist/tools/trace-path.js.map +1 -0
  180. package/dist/tools/types.d.ts +20 -0
  181. package/dist/tools/types.d.ts.map +1 -0
  182. package/dist/tools/types.js +11 -0
  183. package/dist/tools/types.js.map +1 -0
  184. package/dist/tools/who-calls.d.ts +12 -0
  185. package/dist/tools/who-calls.d.ts.map +1 -0
  186. package/dist/tools/who-calls.js +21 -0
  187. package/dist/tools/who-calls.js.map +1 -0
  188. package/package.json +104 -0
package/dist/server.js ADDED
@@ -0,0 +1,153 @@
1
+ // @fitness-ignore-file missing-type-exports -- McpServer/StdioServerTransport/CallToolResult exist ONLY at the SDK's deep paths (no @modelcontextprotocol/sdk barrel surfaces them); they are public, runtime-resolvable entries declared via the SDK's "./*" exports wildcard.
2
+ /**
3
+ * The stdio MCP server (ADR-0084).
4
+ *
5
+ * `opensip mcp` is the first long-lived, BLOCKING command in opensip-cli. Two
6
+ * properties make its construction unusual and are the whole point of this file:
7
+ *
8
+ * 1. **Scope captured, never ambient.** The MCP SDK dispatches tool handlers
9
+ * off an internal EventEmitter, so `currentScope()` (AsyncLocalStorage) does
10
+ * NOT propagate into them — a handler that read `currentScope()` would find
11
+ * `undefined` and silently degrade (no datastore, no logger runId). The fix
12
+ * is to capture the `RunScope` at construction and re-enter it per call via
13
+ * `runWithScope(capturedScope, …)` (see {@link McpStdioServer.register}). The
14
+ * ports are likewise PRE-BUILT and injected; handlers never reach for scope.
15
+ *
16
+ * 2. **stdout is JSON-RPC only.** The stdio transport owns stdout for the
17
+ * protocol frames. Every diagnostic must go to stderr. The `@opensip-cli/core`
18
+ * structured logger never writes stdout (it writes the per-project log file
19
+ * and — in debug mode — stderr), so we route its sink to stderr for the serve
20
+ * lifetime via the `configureLogger` seam and emit only at decision points
21
+ * (`mcp.server.start|stop`, `mcp.tool.dispatch[.ok|.error]`). No `console.*`
22
+ * / `process.stdout.write` for diagnostics anywhere in the serve path.
23
+ *
24
+ * No tools are registered here yet — Phase 4 mounts the catalog onto this server
25
+ * through the {@link McpStdioServer.register} seam (which guarantees the
26
+ * scope-wrap for every handler). The server resolves its lifetime promise on
27
+ * stdin EOF (or a SIGINT-driven graceful close); it never calls `process.exit`,
28
+ * leaving the final exit code to the host command handler.
29
+ */
30
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
31
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
32
+ import { configureLogger, logger, runWithScope } from '@opensip-cli/core';
33
+ /** Server identity advertised in the MCP `initialize` handshake. */
34
+ const SERVER_NAME = 'opensip-cli-mcp';
35
+ /** `module` field stamped on every structured logger event from this file. */
36
+ const LOG_MODULE = 'mcp:server';
37
+ /**
38
+ * A long-lived stdio MCP server bound to one captured {@link RunScope}.
39
+ *
40
+ * Construct with pre-built ports + the captured scope, register tools through
41
+ * {@link register} (Phase 4), then `await serve()` — the promise resolves when
42
+ * the transport closes (stdin EOF / graceful SIGINT).
43
+ */
44
+ export class McpStdioServer {
45
+ mcp;
46
+ transport;
47
+ scope;
48
+ version;
49
+ /** The graph read port handlers close over (Phase 4 reads it). */
50
+ graph;
51
+ /** The results read port handlers close over (Phase 4 reads it). */
52
+ results;
53
+ constructor(deps) {
54
+ this.scope = deps.scope;
55
+ this.graph = deps.graph;
56
+ this.results = deps.results;
57
+ this.version = deps.version;
58
+ this.mcp = new McpServer({ name: SERVER_NAME, version: deps.version });
59
+ // Default stdin/stdout; the transport owns stdout for JSON-RPC frames.
60
+ this.transport = new StdioServerTransport();
61
+ }
62
+ /**
63
+ * Register a tool, wrapping its handler so EVERY dispatch re-enters the
64
+ * captured scope (`runWithScope`) and is bracketed by `mcp.tool.dispatch`
65
+ * decision-point logging. The public signature is exactly the SDK's
66
+ * `registerTool` (full generic fidelity for the Phase-4 call sites); the thin
67
+ * forwarder casts internally because it is scope-/schema-agnostic.
68
+ */
69
+ register = (name, config, cb) => {
70
+ const handler = cb;
71
+ const wrapped = (...args) => this.dispatch(name, () => handler(...args));
72
+ // Forward the scope-wrapping handler back through the SDK's generic seam.
73
+ // The forwarder is schema-agnostic, so the broad→narrow assignment is widened
74
+ // through `unknown` (the public `register` signature stays the SDK's exact
75
+ // generic for the Phase-4 call sites).
76
+ return this.mcp.registerTool(name, config, wrapped);
77
+ };
78
+ /** Run one wrapped handler inside the captured scope, with decision logging. */
79
+ dispatch(name, run) {
80
+ return runWithScope(this.scope, async () => {
81
+ logger.info({ evt: 'mcp.tool.dispatch', module: LOG_MODULE, tool: name });
82
+ try {
83
+ const result = await run();
84
+ logger.info({ evt: 'mcp.tool.dispatch.ok', module: LOG_MODULE, tool: name });
85
+ return result;
86
+ }
87
+ catch (error) {
88
+ // The SDK converts a thrown handler into a JSON-RPC error frame; we log
89
+ // the decision point (stderr sink) and re-throw at this infra boundary.
90
+ logger.error({
91
+ evt: 'mcp.tool.dispatch.error',
92
+ module: LOG_MODULE,
93
+ tool: name,
94
+ error: errorMessage(error),
95
+ });
96
+ throw error;
97
+ }
98
+ });
99
+ }
100
+ /**
101
+ * Serve until the stdio transport closes. Resolves on stdin EOF (or a
102
+ * SIGINT-driven graceful close). Never calls `process.exit` — the host command
103
+ * handler resolves cleanly and owns the final exit code (ADR-0084).
104
+ */
105
+ async serve() {
106
+ // Route the structured logger sink to stderr for the serve lifetime: stdout
107
+ // is reserved for JSON-RPC frames. The logger never writes stdout; its only
108
+ // non-file destination is stderr, gated behind debug — so we enable it here
109
+ // (the documented `configureLogger` sink seam) and keep stdout pristine.
110
+ configureLogger({ silent: false, debugMode: true });
111
+ logger.info({
112
+ evt: 'mcp.server.start',
113
+ module: LOG_MODULE,
114
+ server: SERVER_NAME,
115
+ version: this.version,
116
+ });
117
+ const closed = new Promise((resolve) => {
118
+ // The underlying protocol invokes `onclose` when the transport closes
119
+ // (via an explicit `close()`); resolving here ends `serve()`.
120
+ // eslint-disable-next-line unicorn/prefer-add-event-listener -- the SDK's `Server`/`Protocol` exposes a plain `onclose` callback property, NOT a DOM EventTarget; there is no `addEventListener` to prefer.
121
+ this.mcp.server.onclose = resolve;
122
+ });
123
+ // `StdioServerTransport` only listens for stdin `data`/`error` — it does NOT
124
+ // close on EOF. So we own the graceful-shutdown triggers and translate each
125
+ // into a single `close()` (which drives the protocol `onclose` above):
126
+ // - stdin EOF (`end`/`close`): the client hung up the transport.
127
+ // - SIGINT: Ctrl-C. No `process.exit` here — the command handler resolves
128
+ // cleanly and the host sets the final exit code (ADR-0084 §shutdown).
129
+ const shutdown = () => {
130
+ void this.mcp.close();
131
+ };
132
+ process.stdin.once('end', shutdown);
133
+ process.stdin.once('close', shutdown);
134
+ process.once('SIGINT', shutdown);
135
+ try {
136
+ // `connect` starts the transport and begins reading stdin; it throws only
137
+ // at the genuine stdio infra boundary (the transport failing to start).
138
+ await this.mcp.connect(this.transport);
139
+ await closed;
140
+ }
141
+ finally {
142
+ process.stdin.removeListener('end', shutdown);
143
+ process.stdin.removeListener('close', shutdown);
144
+ process.removeListener('SIGINT', shutdown);
145
+ logger.info({ evt: 'mcp.server.stop', module: LOG_MODULE, server: SERVER_NAME });
146
+ }
147
+ }
148
+ }
149
+ /** Bounded, secret-free message extraction for the stderr error log. */
150
+ function errorMessage(error) {
151
+ return error instanceof Error ? error.message : String(error);
152
+ }
153
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Session-backed {@link ResultsReadPort} (ADR-0084).
3
+ *
4
+ * Implements the result/history reads over the `@opensip-cli/session-store`
5
+ * read API (`listSessionSummaries` / `resolveAndReplaySession` / the bundled
6
+ * replay resolver) and the `@opensip-cli/contracts` `buildAgentCatalog`. It is
7
+ * constructed from an injected `DataStore` (+ the live `ToolRegistry`) captured
8
+ * once — it NEVER calls `currentScope()` inside a method (the long-lived server
9
+ * captures scope at construction; Phase 3). It NEVER names `SessionRepo`, never
10
+ * raw-queries the datastore, and never re-runs the underlying tool — replay only
11
+ * (the `mcp-results-no-rerun` invariant). Every method returns `Result<T, E>`.
12
+ */
13
+ import { type SessionReplayFn } from '@opensip-cli/session-store';
14
+ import type { McpReadError } from './mcp-error.js';
15
+ import type { LatestFindingsOptions, McpFinding, McpResultReplay, RunSummary, ShowRunData } from './result-dto.js';
16
+ import type { ListRunsOptions, ResultsReadPort, ShowRunOptions } from './results-read-port.js';
17
+ import type { AgentCatalog } from '@opensip-cli/contracts';
18
+ import type { Result, ToolRegistry, ToolShortId } from '@opensip-cli/core';
19
+ import type { DataStore } from '@opensip-cli/datastore';
20
+ /** Construction deps — all captured once (no ambient scope reads). */
21
+ export interface SessionResultsReadPortDeps {
22
+ /** The datastore handle the long-lived server captured at construction. */
23
+ readonly store: DataStore;
24
+ /** Live tool registry — for the agent catalog + the bundled replay resolver. */
25
+ readonly tools?: ToolRegistry;
26
+ /** Override the per-tool replay resolver (defaults to the bundled in-host one). */
27
+ readonly replayFor?: (tool: ToolShortId) => SessionReplayFn | undefined;
28
+ /** Tier-3 internal command names excluded from the agent catalog. */
29
+ readonly internalCommands?: ReadonlySet<string>;
30
+ }
31
+ export declare class SessionResultsReadPort implements ResultsReadPort {
32
+ private readonly store;
33
+ private readonly tools?;
34
+ private readonly replayFor;
35
+ private readonly internalCommands?;
36
+ constructor(deps: SessionResultsReadPortDeps);
37
+ agentCatalog(): Result<AgentCatalog, McpReadError>;
38
+ listRuns(opts?: ListRunsOptions): Result<readonly RunSummary[], McpReadError>;
39
+ showRun(opts: ShowRunOptions): Promise<Result<McpResultReplay<ShowRunData>, McpReadError>>;
40
+ latestFindings(opts: LatestFindingsOptions): Promise<Result<McpResultReplay<readonly McpFinding[]>, McpReadError>>;
41
+ }
42
+ //# sourceMappingURL=session-results-read-port.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-results-read-port.d.ts","sourceRoot":"","sources":["../src/session-results-read-port.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,4BAA4B,CAAC;AAIpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EACV,qBAAqB,EACrB,UAAU,EACV,eAAe,EACf,UAAU,EACV,WAAW,EACZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC/F,OAAO,KAAK,EACV,YAAY,EAIb,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,MAAM,EAAU,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAKxD,sEAAsE;AACtE,MAAM,WAAW,0BAA0B;IACzC,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B,mFAAmF;IACnF,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,eAAe,GAAG,SAAS,CAAC;IACxE,qEAAqE;IACrE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACjD;AAED,qBAAa,sBAAuB,YAAW,eAAe;IAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqD;IAC/E,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAsB;gBAE5C,IAAI,EAAE,0BAA0B;IAO5C,YAAY,IAAI,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC;IASlD,QAAQ,CAAC,IAAI,GAAE,eAAoB,GAAG,MAAM,CAAC,SAAS,UAAU,EAAE,EAAE,YAAY,CAAC;IAW3E,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,WAAW,CAAC,EAAE,YAAY,CAAC,CAAC;IAiB1F,cAAc,CAClB,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,SAAS,UAAU,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;CAkBzE"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Session-backed {@link ResultsReadPort} (ADR-0084).
3
+ *
4
+ * Implements the result/history reads over the `@opensip-cli/session-store`
5
+ * read API (`listSessionSummaries` / `resolveAndReplaySession` / the bundled
6
+ * replay resolver) and the `@opensip-cli/contracts` `buildAgentCatalog`. It is
7
+ * constructed from an injected `DataStore` (+ the live `ToolRegistry`) captured
8
+ * once — it NEVER calls `currentScope()` inside a method (the long-lived server
9
+ * captures scope at construction; Phase 3). It NEVER names `SessionRepo`, never
10
+ * raw-queries the datastore, and never re-runs the underlying tool — replay only
11
+ * (the `mcp-results-no-rerun` invariant). Every method returns `Result<T, E>`.
12
+ */
13
+ import { buildAgentCatalog } from '@opensip-cli/contracts';
14
+ import { err, ok } from '@opensip-cli/core';
15
+ import { bundledReplayResolver, listSessionSummaries, resolveAndReplaySession, } from '@opensip-cli/session-store';
16
+ import { readError } from './mcp-error.js';
17
+ /** The no-op replay resolver used when no tool registry was supplied. */
18
+ const noReplay = () => undefined;
19
+ export class SessionResultsReadPort {
20
+ store;
21
+ tools;
22
+ replayFor;
23
+ internalCommands;
24
+ constructor(deps) {
25
+ this.store = deps.store;
26
+ this.tools = deps.tools;
27
+ this.replayFor = deps.replayFor ?? (deps.tools ? bundledReplayResolver(deps.tools) : noReplay);
28
+ this.internalCommands = deps.internalCommands;
29
+ }
30
+ agentCatalog() {
31
+ return ok(buildAgentCatalog({
32
+ ...(this.tools ? { tools: this.tools } : {}),
33
+ ...(this.internalCommands ? { internalCommands: this.internalCommands } : {}),
34
+ }));
35
+ }
36
+ listRuns(opts = {}) {
37
+ const history = listSessionSummaries(this.store, {
38
+ ...(opts.tool ? { tool: opts.tool } : {}),
39
+ ...(opts.limit === undefined ? {} : { limit: opts.limit }),
40
+ // Default to the lean projection — agents want pointers, not heavy payloads.
41
+ summaryOnly: opts.summaryOnly ?? true,
42
+ ...(this.tools ? { registry: this.tools } : {}),
43
+ });
44
+ return ok(history.sessions.map(toRunSummary));
45
+ }
46
+ async showRun(opts) {
47
+ const outcome = await resolveAndReplaySession(this.store, {
48
+ ref: opts.ref,
49
+ ...(opts.tool ? { tool: opts.tool } : {}),
50
+ replayFor: this.replayFor,
51
+ ...(opts.filters?.length ? { filters: opts.filters } : {}),
52
+ });
53
+ if (!outcome.ok)
54
+ return err(readError(outcome.reason, outcome.detail));
55
+ const { session, replay, originalSignalCount } = outcome;
56
+ return ok({
57
+ data: { fidelity: replay.fidelity, envelope: replay.envelope },
58
+ session: runSummaryFromReplay(session, replay.envelope),
59
+ ...filterMeta(opts.filters, originalSignalCount, replay.envelope.signals.length),
60
+ recommendedNext: recommendedNext(session),
61
+ });
62
+ }
63
+ async latestFindings(opts) {
64
+ const filters = severityFilters(opts);
65
+ const outcome = await resolveAndReplaySession(this.store, {
66
+ ref: 'latest',
67
+ tool: opts.tool,
68
+ replayFor: this.replayFor,
69
+ ...(filters.length > 0 ? { filters } : {}),
70
+ });
71
+ if (!outcome.ok)
72
+ return err(readError(outcome.reason, outcome.detail));
73
+ const { session, replay, originalSignalCount } = outcome;
74
+ const findings = replay.envelope.signals.map(toMcpFinding);
75
+ return ok({
76
+ data: findings,
77
+ session: runSummaryFromReplay(session, replay.envelope),
78
+ ...filterMeta(filters, originalSignalCount, findings.length),
79
+ recommendedNext: recommendedNext(session),
80
+ });
81
+ }
82
+ }
83
+ /** Map a `sessions list` row to the lean {@link RunSummary} agent shape. */
84
+ function toRunSummary(s) {
85
+ return {
86
+ id: s.id,
87
+ tool: s.tool,
88
+ startedAt: s.startedAt,
89
+ completedAt: s.completedAt,
90
+ score: s.score,
91
+ passed: s.passed,
92
+ showCommand: s.showCommand,
93
+ ...(s.summary ? { summary: s.summary } : {}),
94
+ };
95
+ }
96
+ /** Build a {@link RunSummary} for a replayed run (summary from the envelope verdict). */
97
+ function runSummaryFromReplay(session, envelope) {
98
+ return {
99
+ id: session.id,
100
+ tool: session.tool,
101
+ startedAt: session.startedAt,
102
+ completedAt: session.completedAt,
103
+ score: session.score,
104
+ passed: session.passed,
105
+ showCommand: `opensip sessions show ${session.id} --json`,
106
+ summary: envelope.verdict.summary,
107
+ };
108
+ }
109
+ /** Project a replayed envelope signal to a compact {@link McpFinding}. */
110
+ function toMcpFinding(signal) {
111
+ return {
112
+ ruleId: signal.ruleId,
113
+ message: signal.message,
114
+ severity: signal.severity,
115
+ ...(signal.filePath ? { filePath: signal.filePath } : {}),
116
+ ...(signal.line === undefined ? {} : { line: signal.line }),
117
+ ...(signal.column === undefined ? {} : { column: signal.column }),
118
+ };
119
+ }
120
+ /** The `--filter` vocabulary for a {@link LatestFindingsOptions} request. */
121
+ function severityFilters(opts) {
122
+ const filters = [];
123
+ if (opts.severity === 'errors')
124
+ filters.push('errors-only');
125
+ else if (opts.severity === 'warnings')
126
+ filters.push('warnings-only');
127
+ if (opts.limit !== undefined)
128
+ filters.push(`top:${String(opts.limit)}`);
129
+ return filters;
130
+ }
131
+ /** Agent filter metadata, present only when a filter actually narrowed the set. */
132
+ function filterMeta(filters, originalSignalCount, returnedSignalCount) {
133
+ if (!filters?.length)
134
+ return {};
135
+ return { filtersApplied: filters, originalSignalCount, returnedSignalCount };
136
+ }
137
+ /** Follow-up commands an agent should prefer over re-running the tool. */
138
+ function recommendedNext(session) {
139
+ const tool = session.tool;
140
+ return {
141
+ showLatestErrorsCommand: `opensip sessions show latest --tool ${tool} --json --filter errors-only`,
142
+ showLatestWarningsCommand: `opensip sessions show latest --tool ${tool} --json --filter warnings-only`,
143
+ showRawEnvelopeCommand: `opensip sessions show ${session.id} --json --raw`,
144
+ rerunCommand: `opensip ${tool}`,
145
+ };
146
+ }
147
+ //# sourceMappingURL=session-results-read-port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-results-read-port.js","sourceRoot":"","sources":["../src/session-results-read-port.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * SQLite-backed {@link GraphReadPort} (ADR-0084).
3
+ *
4
+ * Reads the persisted catalog through the graph engine's `CatalogRepo`
5
+ * (internal surface) and derives adjacency via `buildIndexes` — it NEVER invents
6
+ * a parallel catalog table or raw-queries `DataStore.db`. Freshness reuses
7
+ * `classifyCatalog`; dead code reuses `orphanSubtreeRule`; blast reuses the
8
+ * single canonical `buildFeatures(['blast'])` scoring site (no ad-hoc BFS). The
9
+ * generic bounded adjacency walks for callers/callees/trace are MCP-local.
10
+ *
11
+ * Constructed from an injected `DataStore` (+ optional freshness-context and
12
+ * rebuild providers, wired in Phases 3/4) — it NEVER reads `currentScope()`.
13
+ * Reads return `Result<McpToolResult<T>, McpReadError>`; a missing catalog is
14
+ * NOT an error — it surfaces as `freshness.fresh === false` with empty data and
15
+ * no auto-build. `throw` is reserved for the SQLite/Drizzle boundary (a failing
16
+ * `CatalogRepo.loadFullCatalog`) and the `runGraph` rebuild.
17
+ */
18
+ import type { AdjacencySnapshot, ArchitectureSummaryDto, BlastDto, DeadCodeDto, GraphGeneration, GraphReadPort, SearchSymbolsOptions } from './graph-read-port.js';
19
+ import type { McpReadError } from './mcp-error.js';
20
+ import type { Freshness, McpToolResult, SymbolRef } from './symbol-dto.js';
21
+ import type { Result } from '@opensip-cli/core';
22
+ import type { DataStore } from '@opensip-cli/datastore';
23
+ import type { Catalog } from '@opensip-cli/graph';
24
+ import type { GraphConfig, ValidationContext } from '@opensip-cli/graph/internal';
25
+ /** Construction deps — all captured once (no ambient scope reads). */
26
+ export interface SqliteGraphReadPortDeps {
27
+ /** The datastore handle the long-lived server captured at construction. */
28
+ readonly store: DataStore;
29
+ /**
30
+ * Build the working-tree {@link ValidationContext} for freshness, given the
31
+ * served generation's catalog (file set + language + adapter cache key). Wired
32
+ * in Phase 4 (`workingTreeContextFromCatalog`); absent ⇒ a loaded catalog is
33
+ * reported `fresh: true` (unverified, matching `graph lookup`).
34
+ */
35
+ readonly freshnessContext?: (catalog: Catalog) => ValidationContext | undefined;
36
+ /**
37
+ * Rebuild the catalog (the `refresh` op) and return the new {@link Catalog}.
38
+ * Wired in Phase 4; absent ⇒ `refresh()` returns a structured error.
39
+ */
40
+ readonly rebuild?: () => Promise<Catalog>;
41
+ /** Graph config used by dead-code / feature evaluation (defaults to `{}`). */
42
+ readonly config?: GraphConfig;
43
+ }
44
+ export declare class SqliteGraphReadPort implements GraphReadPort {
45
+ private readonly deps;
46
+ private readonly store;
47
+ private readonly config;
48
+ private generation;
49
+ private loaded;
50
+ private blastCache;
51
+ /** In-flight rebuild — serializes concurrent `refresh()` to a single build. */
52
+ private inFlightRefresh;
53
+ constructor(deps: SqliteGraphReadPortDeps);
54
+ /** Lazily load + pin the current generation from the persisted catalog. */
55
+ private current;
56
+ private invalidateDerived;
57
+ freshness(): Freshness;
58
+ private classify;
59
+ /** Wrap data in the shared `{ data, freshness, truncated? }` envelope. */
60
+ private wrap;
61
+ /** The empty (no-data) envelope for an absent catalog / unresolved symbol. */
62
+ private empty;
63
+ getGeneration(): Result<McpToolResult<GraphGeneration | undefined>, McpReadError>;
64
+ resolveSymbolId(symbolId: string): Result<McpToolResult<SymbolRef | undefined>, McpReadError>;
65
+ searchSymbols(query: string, opts?: SearchSymbolsOptions): Result<McpToolResult<readonly SymbolRef[]>, McpReadError>;
66
+ findBySpan(file: string, line: number): Result<McpToolResult<readonly SymbolRef[]>, McpReadError>;
67
+ callerGraph(): Result<McpToolResult<AdjacencySnapshot>, McpReadError>;
68
+ calleeGraph(): Result<McpToolResult<AdjacencySnapshot>, McpReadError>;
69
+ /**
70
+ * Project one direction's body-hash adjacency into a walkable
71
+ * {@link AdjacencySnapshot}. The map IS the engine's `Indexes.callers`/
72
+ * `callees` (no copy); the resolver closes over `byBodyHash`. The bounded
73
+ * walk itself lives in MCP's `boundedBfs` (rule of three) — the port never
74
+ * re-implements a BFS.
75
+ */
76
+ private adjacency;
77
+ blast(symbolId: string): Result<McpToolResult<BlastDto | undefined>, McpReadError>;
78
+ /** Memoized blast table — the canonical `buildFeatures(['blast'])` scoring. */
79
+ private blastScores;
80
+ deadCode(limit?: number): Result<McpToolResult<readonly DeadCodeDto[]>, McpReadError>;
81
+ architectureSummary(limit?: number): Result<McpToolResult<ArchitectureSummaryDto>, McpReadError>;
82
+ /** The `cap` highest-blast symbols (graph's canonical scoring; reused, not reinvented). */
83
+ private topHotspots;
84
+ refresh(): Promise<Result<McpToolResult<GraphGeneration>, McpReadError>>;
85
+ /** One rebuild: runs the provider, then swaps the generation atomically on success. */
86
+ private runRebuild;
87
+ }
88
+ //# sourceMappingURL=sqlite-graph-read-port.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-graph-read-port.d.ts","sourceRoot":"","sources":["../src/sqlite-graph-read-port.ts"],"names":[],"mappings":"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"}