@descryy/mcp 0.1.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/LICENSE +21 -0
- package/dist/action-handshake.d.ts +86 -0
- package/dist/action-handshake.d.ts.map +1 -0
- package/dist/action-handshake.js +144 -0
- package/dist/action-handshake.js.map +1 -0
- package/dist/bin/descry-mcp.d.ts +18 -0
- package/dist/bin/descry-mcp.d.ts.map +1 -0
- package/dist/bin/descry-mcp.js +54 -0
- package/dist/bin/descry-mcp.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/language-guess.d.ts +17 -0
- package/dist/language-guess.d.ts.map +1 -0
- package/dist/language-guess.js +43 -0
- package/dist/language-guess.js.map +1 -0
- package/dist/protocol.d.ts +91 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +127 -0
- package/dist/protocol.js.map +1 -0
- package/dist/registry.d.ts +72 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +136 -0
- package/dist/registry.js.map +1 -0
- package/dist/render.d.ts +275 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +333 -0
- package/dist/render.js.map +1 -0
- package/dist/server.d.ts +42 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +263 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +164 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +302 -0
- package/dist/session.js.map +1 -0
- package/dist/tools/analyze.d.ts +124 -0
- package/dist/tools/analyze.d.ts.map +1 -0
- package/dist/tools/analyze.js +411 -0
- package/dist/tools/analyze.js.map +1 -0
- package/dist/tools/contracts.d.ts +105 -0
- package/dist/tools/contracts.d.ts.map +1 -0
- package/dist/tools/contracts.js +141 -0
- package/dist/tools/contracts.js.map +1 -0
- package/dist/tools/cross-pr.d.ts +137 -0
- package/dist/tools/cross-pr.d.ts.map +1 -0
- package/dist/tools/cross-pr.js +216 -0
- package/dist/tools/cross-pr.js.map +1 -0
- package/dist/tools/git-diff.d.ts +29 -0
- package/dist/tools/git-diff.d.ts.map +1 -0
- package/dist/tools/git-diff.js +117 -0
- package/dist/tools/git-diff.js.map +1 -0
- package/dist/tools/git-history.d.ts +27 -0
- package/dist/tools/git-history.d.ts.map +1 -0
- package/dist/tools/git-history.js +91 -0
- package/dist/tools/git-history.js.map +1 -0
- package/dist/tools/history.d.ts +63 -0
- package/dist/tools/history.d.ts.map +1 -0
- package/dist/tools/history.js +114 -0
- package/dist/tools/history.js.map +1 -0
- package/dist/tools/impact.d.ts +81 -0
- package/dist/tools/impact.d.ts.map +1 -0
- package/dist/tools/impact.js +229 -0
- package/dist/tools/impact.js.map +1 -0
- package/dist/tools/index.d.ts +33 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +47 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/kit.d.ts +183 -0
- package/dist/tools/kit.d.ts.map +1 -0
- package/dist/tools/kit.js +117 -0
- package/dist/tools/kit.js.map +1 -0
- package/dist/tools/link-workspace.d.ts +62 -0
- package/dist/tools/link-workspace.d.ts.map +1 -0
- package/dist/tools/link-workspace.js +156 -0
- package/dist/tools/link-workspace.js.map +1 -0
- package/dist/tools/lookup.d.ts +29 -0
- package/dist/tools/lookup.d.ts.map +1 -0
- package/dist/tools/lookup.js +73 -0
- package/dist/tools/lookup.js.map +1 -0
- package/dist/tools/pr-analysis.d.ts +89 -0
- package/dist/tools/pr-analysis.d.ts.map +1 -0
- package/dist/tools/pr-analysis.js +169 -0
- package/dist/tools/pr-analysis.js.map +1 -0
- package/dist/tools/propagation.d.ts +74 -0
- package/dist/tools/propagation.d.ts.map +1 -0
- package/dist/tools/propagation.js +194 -0
- package/dist/tools/propagation.js.map +1 -0
- package/dist/tools/questions.d.ts +80 -0
- package/dist/tools/questions.d.ts.map +1 -0
- package/dist/tools/questions.js +213 -0
- package/dist/tools/questions.js.map +1 -0
- package/dist/tools/refusal-fetch.d.ts +71 -0
- package/dist/tools/refusal-fetch.d.ts.map +1 -0
- package/dist/tools/refusal-fetch.js +137 -0
- package/dist/tools/refusal-fetch.js.map +1 -0
- package/dist/tools/scope.d.ts +60 -0
- package/dist/tools/scope.d.ts.map +1 -0
- package/dist/tools/scope.js +160 -0
- package/dist/tools/scope.js.map +1 -0
- package/dist/tools/similar-incidents.d.ts +105 -0
- package/dist/tools/similar-incidents.d.ts.map +1 -0
- package/dist/tools/similar-incidents.js +228 -0
- package/dist/tools/similar-incidents.js.map +1 -0
- package/dist/tools/validate.d.ts +103 -0
- package/dist/tools/validate.d.ts.map +1 -0
- package/dist/tools/validate.js +176 -0
- package/dist/tools/validate.js.map +1 -0
- package/dist/tools/verification-status.d.ts +68 -0
- package/dist/tools/verification-status.d.ts.map +1 -0
- package/dist/tools/verification-status.js +179 -0
- package/dist/tools/verification-status.js.map +1 -0
- package/dist/transport.d.ts +58 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +115 -0
- package/dist/transport.js.map +1 -0
- package/package.json +33 -0
package/dist/protocol.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 and the slice of MCP this server speaks.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this is hand-written
|
|
5
|
+
*
|
|
6
|
+
* `@modelcontextprotocol/sdk` is the obvious answer and the blueprint's
|
|
7
|
+
* dependency table names it. It was measured rather than assumed: version 1.30.0
|
|
8
|
+
* declares **seventeen direct dependencies** — `express`, `hono`,
|
|
9
|
+
* `@hono/node-server`, `cors`, `express-rate-limit`, `jose`, `pkce-challenge`,
|
|
10
|
+
* `eventsource`, `ajv`, `zod` — essentially all of which exist to serve the HTTP
|
|
11
|
+
* and OAuth transports. This server speaks stdio to a coding agent on the same
|
|
12
|
+
* machine. It will never open a socket.
|
|
13
|
+
*
|
|
14
|
+
* The rest of this project has made the same call four times — `node:sqlite`
|
|
15
|
+
* over `better-sqlite3`, `node --test` over a test runner, `tsc` over a bundler,
|
|
16
|
+
* `git` invoked directly over a git library — every time on the same grounds:
|
|
17
|
+
* this is a **locally installed developer tool**, and a dependency tree is a
|
|
18
|
+
* distribution problem before it is anything else. Both shipped packages have
|
|
19
|
+
* zero runtime dependencies today. Seventeen transitively-hundreds is a large
|
|
20
|
+
* price for newline-delimited JSON.
|
|
21
|
+
*
|
|
22
|
+
* **The cost is named, not waved away.** Hand-rolling means spec drift is
|
|
23
|
+
* silent: the wire format changes, the client stops working, and nothing in this
|
|
24
|
+
* repository fails. Two things pay it down. `PROTOCOL_VERSION` is pinned and
|
|
25
|
+
* `SUPPORTED_PROTOCOL_VERSIONS` is explicit, so an unknown version is negotiated
|
|
26
|
+
* rather than assumed compatible; and the handshake is covered by tests that
|
|
27
|
+
* assert the exact frames, so a change to the shape is a red test rather than a
|
|
28
|
+
* user-visible mystery. If the protocol moves past what is here, the fix is to
|
|
29
|
+
* add a version to the list — not to discover it from a bug report.
|
|
30
|
+
*/
|
|
31
|
+
/** Standard JSON-RPC codes. MCP adds none of its own at this layer. */
|
|
32
|
+
export const RPC_PARSE_ERROR = -32700;
|
|
33
|
+
export const RPC_INVALID_REQUEST = -32600;
|
|
34
|
+
export const RPC_METHOD_NOT_FOUND = -32601;
|
|
35
|
+
export const RPC_INVALID_PARAMS = -32602;
|
|
36
|
+
export const RPC_INTERNAL_ERROR = -32603;
|
|
37
|
+
/**
|
|
38
|
+
* The version this server implements.
|
|
39
|
+
*
|
|
40
|
+
* Newest first. Negotiation echoes the client's version when it is on this list
|
|
41
|
+
* and otherwise answers with `PROTOCOL_VERSION`, which is what the spec asks for
|
|
42
|
+
* — the client then decides whether it can proceed. Answering with the client's
|
|
43
|
+
* unknown version instead would be a claim of compatibility nobody has checked.
|
|
44
|
+
*/
|
|
45
|
+
export const PROTOCOL_VERSION = "2025-06-18";
|
|
46
|
+
export const SUPPORTED_PROTOCOL_VERSIONS = [
|
|
47
|
+
"2025-06-18",
|
|
48
|
+
"2025-03-26",
|
|
49
|
+
"2024-11-05",
|
|
50
|
+
];
|
|
51
|
+
export function negotiateVersion(requested) {
|
|
52
|
+
return typeof requested === "string" && SUPPORTED_PROTOCOL_VERSIONS.includes(requested)
|
|
53
|
+
? requested
|
|
54
|
+
: PROTOCOL_VERSION;
|
|
55
|
+
}
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Parsing
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
/**
|
|
60
|
+
* A frame that could not be understood well enough to answer.
|
|
61
|
+
*
|
|
62
|
+
* Distinguished from a request that is merely wrong, because JSON-RPC says a
|
|
63
|
+
* message with no usable id gets no response at all — replying to it with a
|
|
64
|
+
* fabricated id would put a frame on the wire the client cannot correlate.
|
|
65
|
+
*/
|
|
66
|
+
export class ProtocolError extends Error {
|
|
67
|
+
code;
|
|
68
|
+
/** Null when the frame carried no usable id and must therefore go unanswered. */
|
|
69
|
+
id;
|
|
70
|
+
constructor(code, message, id) {
|
|
71
|
+
super(message);
|
|
72
|
+
this.name = "ProtocolError";
|
|
73
|
+
this.code = code;
|
|
74
|
+
this.id = id;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function isRecord(value) {
|
|
78
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
79
|
+
}
|
|
80
|
+
/** Parse one line into a request or notification, or throw `ProtocolError`. */
|
|
81
|
+
export function parseMessage(line) {
|
|
82
|
+
let raw;
|
|
83
|
+
try {
|
|
84
|
+
raw = JSON.parse(line);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
throw new ProtocolError(RPC_PARSE_ERROR, "not valid JSON", null);
|
|
88
|
+
}
|
|
89
|
+
if (!isRecord(raw)) {
|
|
90
|
+
throw new ProtocolError(RPC_INVALID_REQUEST, "message must be a JSON object", null);
|
|
91
|
+
}
|
|
92
|
+
// Batch requests were removed from MCP in 2025-06-18 and this server never
|
|
93
|
+
// supported them; an array reaches the same branch as any other non-object.
|
|
94
|
+
const id = raw["id"];
|
|
95
|
+
const usableId = typeof id === "string" || typeof id === "number" ? id : null;
|
|
96
|
+
if (raw["jsonrpc"] !== "2.0") {
|
|
97
|
+
throw new ProtocolError(RPC_INVALID_REQUEST, "jsonrpc must be \"2.0\"", usableId);
|
|
98
|
+
}
|
|
99
|
+
if (typeof raw["method"] !== "string") {
|
|
100
|
+
throw new ProtocolError(RPC_INVALID_REQUEST, "method must be a string", usableId);
|
|
101
|
+
}
|
|
102
|
+
const params = raw["params"];
|
|
103
|
+
if (params !== undefined && !isRecord(params)) {
|
|
104
|
+
// Positional params are legal JSON-RPC and illegal MCP. Rejected rather than
|
|
105
|
+
// coerced: an array silently read as an object is a wrong answer, not an error.
|
|
106
|
+
throw new ProtocolError(RPC_INVALID_PARAMS, "params must be an object", usableId);
|
|
107
|
+
}
|
|
108
|
+
const method = raw["method"];
|
|
109
|
+
const base = params === undefined ? {} : { params };
|
|
110
|
+
return usableId === null
|
|
111
|
+
? { jsonrpc: "2.0", method, ...base }
|
|
112
|
+
: { jsonrpc: "2.0", id: usableId, method, ...base };
|
|
113
|
+
}
|
|
114
|
+
export function isRequest(message) {
|
|
115
|
+
return "id" in message;
|
|
116
|
+
}
|
|
117
|
+
export function ok(id, result) {
|
|
118
|
+
return { jsonrpc: "2.0", id, result };
|
|
119
|
+
}
|
|
120
|
+
export function fail(id, code, message, data) {
|
|
121
|
+
return {
|
|
122
|
+
jsonrpc: "2.0",
|
|
123
|
+
id,
|
|
124
|
+
error: { code, message, ...(data === undefined ? {} : { data }) },
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the server reaches adapters without this repository depending on them.
|
|
3
|
+
*
|
|
4
|
+
* `descry-core` must not import `descry-adapters`: the IR boundary is a
|
|
5
|
+
* dependency-direction fact, and an import here would invert it in the one place
|
|
6
|
+
* where it matters most — the process that runs everything. So sources are named
|
|
7
|
+
* in configuration as module specifiers and loaded at runtime. The engine knows
|
|
8
|
+
* `IRSource`; it never knows the word "python".
|
|
9
|
+
*
|
|
10
|
+
* ## The factory convention, and why it is a convention rather than an interface
|
|
11
|
+
*
|
|
12
|
+
* Every adapter in `descry-adapters` exports `ADAPTER_ID`, `ADAPTER_VERSION` and
|
|
13
|
+
* a factory named `create<Something>Adapter` — `createGoAdapter`,
|
|
14
|
+
* `createTypeScriptAdapter`, `createOpenApiAdapter`. There is no uniform name,
|
|
15
|
+
* and inventing one now would be a breaking change across twelve packages to
|
|
16
|
+
* save a regular expression. So: an explicit `export` in config wins; failing
|
|
17
|
+
* that, the single export matching `create*Adapter` is used; **two matches is an
|
|
18
|
+
* error, not a coin toss.**
|
|
19
|
+
*
|
|
20
|
+
* ## Failing to load a source is a disclosure, never a shrug
|
|
21
|
+
*
|
|
22
|
+
* An adapter that will not import is the difference between "we found no problem
|
|
23
|
+
* in your Python service" and "we could not read your Python service" — §20.2
|
|
24
|
+
* keeps those in different categories, and a registry that quietly skipped a
|
|
25
|
+
* broken specifier would collapse them at the very bottom of the stack, where no
|
|
26
|
+
* layer above could ever recover the distinction. Every failure comes back as a
|
|
27
|
+
* `SourceLoadFailure` carrying the specifier and the reason, and the caller is
|
|
28
|
+
* structurally unable to take the loaded sources without also taking the list of
|
|
29
|
+
* ones that are missing.
|
|
30
|
+
*/
|
|
31
|
+
import type { IRSource, LanguageAdapter, RepoRoot } from "@descryy/ir";
|
|
32
|
+
/** One entry in the configured source list. A bare string is `{ module }`. */
|
|
33
|
+
export interface SourceSpec {
|
|
34
|
+
readonly module: string;
|
|
35
|
+
/** Named export to call. Defaults to the `create*Adapter` convention. */
|
|
36
|
+
readonly export?: string;
|
|
37
|
+
/** Passed to the factory. Adapter-specific and opaque here. */
|
|
38
|
+
readonly options?: Record<string, unknown>;
|
|
39
|
+
}
|
|
40
|
+
export interface LoadedSource {
|
|
41
|
+
readonly spec: SourceSpec;
|
|
42
|
+
readonly source: IRSource;
|
|
43
|
+
/** Present when the source implements `LanguageAdapter`, so `detect` can run. */
|
|
44
|
+
readonly adapter: LanguageAdapter | null;
|
|
45
|
+
}
|
|
46
|
+
export interface SourceLoadFailure {
|
|
47
|
+
readonly spec: SourceSpec;
|
|
48
|
+
readonly reason: string;
|
|
49
|
+
}
|
|
50
|
+
export interface RegistryResult {
|
|
51
|
+
readonly loaded: readonly LoadedSource[];
|
|
52
|
+
readonly failed: readonly SourceLoadFailure[];
|
|
53
|
+
}
|
|
54
|
+
export declare function normaliseSpec(entry: string | SourceSpec): SourceSpec;
|
|
55
|
+
export declare function loadSources(entries: readonly (string | SourceSpec)[]): Promise<RegistryResult>;
|
|
56
|
+
/**
|
|
57
|
+
* Ask each loaded adapter whether it claims this repository.
|
|
58
|
+
*
|
|
59
|
+
* A source that is not a `LanguageAdapter` — the git history reader is the
|
|
60
|
+
* standing example — has nothing to detect and always runs. A `detect` that
|
|
61
|
+
* throws is treated as "did not detect", **with the reason recorded**: a broken
|
|
62
|
+
* detector must not be able to fail the whole run, and must not be able to hide
|
|
63
|
+
* either.
|
|
64
|
+
*/
|
|
65
|
+
export declare function detectSources(sources: readonly LoadedSource[], root: RepoRoot): Promise<{
|
|
66
|
+
readonly applicable: readonly LoadedSource[];
|
|
67
|
+
readonly skipped: readonly {
|
|
68
|
+
source: LoadedSource;
|
|
69
|
+
reason: string;
|
|
70
|
+
}[];
|
|
71
|
+
}>;
|
|
72
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvE,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;CAC1C;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAC/C;AAID,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAEpE;AAyBD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,SAAS,CAAC,MAAM,GAAG,UAAU,CAAC,EAAE,GACxC,OAAO,CAAC,cAAc,CAAC,CAczB;AAsCD;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC;IACT,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,MAAM,EAAE,YAAY,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACvE,CAAC,CAuBD"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the server reaches adapters without this repository depending on them.
|
|
3
|
+
*
|
|
4
|
+
* `descry-core` must not import `descry-adapters`: the IR boundary is a
|
|
5
|
+
* dependency-direction fact, and an import here would invert it in the one place
|
|
6
|
+
* where it matters most — the process that runs everything. So sources are named
|
|
7
|
+
* in configuration as module specifiers and loaded at runtime. The engine knows
|
|
8
|
+
* `IRSource`; it never knows the word "python".
|
|
9
|
+
*
|
|
10
|
+
* ## The factory convention, and why it is a convention rather than an interface
|
|
11
|
+
*
|
|
12
|
+
* Every adapter in `descry-adapters` exports `ADAPTER_ID`, `ADAPTER_VERSION` and
|
|
13
|
+
* a factory named `create<Something>Adapter` — `createGoAdapter`,
|
|
14
|
+
* `createTypeScriptAdapter`, `createOpenApiAdapter`. There is no uniform name,
|
|
15
|
+
* and inventing one now would be a breaking change across twelve packages to
|
|
16
|
+
* save a regular expression. So: an explicit `export` in config wins; failing
|
|
17
|
+
* that, the single export matching `create*Adapter` is used; **two matches is an
|
|
18
|
+
* error, not a coin toss.**
|
|
19
|
+
*
|
|
20
|
+
* ## Failing to load a source is a disclosure, never a shrug
|
|
21
|
+
*
|
|
22
|
+
* An adapter that will not import is the difference between "we found no problem
|
|
23
|
+
* in your Python service" and "we could not read your Python service" — §20.2
|
|
24
|
+
* keeps those in different categories, and a registry that quietly skipped a
|
|
25
|
+
* broken specifier would collapse them at the very bottom of the stack, where no
|
|
26
|
+
* layer above could ever recover the distinction. Every failure comes back as a
|
|
27
|
+
* `SourceLoadFailure` carrying the specifier and the reason, and the caller is
|
|
28
|
+
* structurally unable to take the loaded sources without also taking the list of
|
|
29
|
+
* ones that are missing.
|
|
30
|
+
*/
|
|
31
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
32
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
33
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
34
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return path;
|
|
38
|
+
};
|
|
39
|
+
const FACTORY_PATTERN = /^create[A-Za-z0-9]*Adapter$/;
|
|
40
|
+
export function normaliseSpec(entry) {
|
|
41
|
+
return typeof entry === "string" ? { module: entry } : entry;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A loaded module is a `LanguageAdapter` when it can be asked what it supports.
|
|
45
|
+
*
|
|
46
|
+
* Duck-typed on the two methods that matter rather than on a marker, because the
|
|
47
|
+
* adapters are compiled separately and `instanceof` across package boundaries is
|
|
48
|
+
* a well-known way to be wrong. `detect` and `capabilities` are the two the
|
|
49
|
+
* server actually calls; a source with both is one it can treat as an adapter.
|
|
50
|
+
*/
|
|
51
|
+
function asAdapter(source) {
|
|
52
|
+
const candidate = source;
|
|
53
|
+
return typeof candidate.detect === "function" && typeof candidate.capabilities === "function"
|
|
54
|
+
? source
|
|
55
|
+
: null;
|
|
56
|
+
}
|
|
57
|
+
function describe(error) {
|
|
58
|
+
if (error instanceof Error) {
|
|
59
|
+
const code = error.code;
|
|
60
|
+
return code === undefined ? error.message : `${code}: ${error.message}`;
|
|
61
|
+
}
|
|
62
|
+
return String(error);
|
|
63
|
+
}
|
|
64
|
+
export async function loadSources(entries) {
|
|
65
|
+
const loaded = [];
|
|
66
|
+
const failed = [];
|
|
67
|
+
for (const entry of entries) {
|
|
68
|
+
const spec = normaliseSpec(entry);
|
|
69
|
+
try {
|
|
70
|
+
loaded.push({ ...(await instantiate(spec)), spec });
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
failed.push({ spec, reason: describe(error) });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return { loaded, failed };
|
|
77
|
+
}
|
|
78
|
+
async function instantiate(spec) {
|
|
79
|
+
const module = (await import(__rewriteRelativeImportExtension(spec.module)));
|
|
80
|
+
let factoryName = spec.export;
|
|
81
|
+
if (factoryName === undefined) {
|
|
82
|
+
const candidates = Object.keys(module).filter((key) => FACTORY_PATTERN.test(key) && typeof module[key] === "function");
|
|
83
|
+
if (candidates.length === 0) {
|
|
84
|
+
throw new Error(`no export matching create*Adapter. Name one explicitly with ` +
|
|
85
|
+
`{ "module": "${spec.module}", "export": "..." }.`);
|
|
86
|
+
}
|
|
87
|
+
if (candidates.length > 1) {
|
|
88
|
+
throw new Error(`${candidates.length} exports match create*Adapter (${candidates.sort().join(", ")}). ` +
|
|
89
|
+
"Name the one to use explicitly rather than letting the choice depend on export order.");
|
|
90
|
+
}
|
|
91
|
+
factoryName = candidates[0];
|
|
92
|
+
}
|
|
93
|
+
const factory = module[factoryName];
|
|
94
|
+
if (typeof factory !== "function") {
|
|
95
|
+
throw new Error(`export "${factoryName}" is not a function`);
|
|
96
|
+
}
|
|
97
|
+
const source = factory(spec.options);
|
|
98
|
+
if (typeof source?.emit !== "function" || typeof source.id !== "string") {
|
|
99
|
+
throw new Error(`"${factoryName}" did not return an IRSource (needs \`id\` and \`emit\`)`);
|
|
100
|
+
}
|
|
101
|
+
return { source, adapter: asAdapter(source) };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Ask each loaded adapter whether it claims this repository.
|
|
105
|
+
*
|
|
106
|
+
* A source that is not a `LanguageAdapter` — the git history reader is the
|
|
107
|
+
* standing example — has nothing to detect and always runs. A `detect` that
|
|
108
|
+
* throws is treated as "did not detect", **with the reason recorded**: a broken
|
|
109
|
+
* detector must not be able to fail the whole run, and must not be able to hide
|
|
110
|
+
* either.
|
|
111
|
+
*/
|
|
112
|
+
export async function detectSources(sources, root) {
|
|
113
|
+
const applicable = [];
|
|
114
|
+
const skipped = [];
|
|
115
|
+
for (const entry of sources) {
|
|
116
|
+
if (entry.adapter === null) {
|
|
117
|
+
applicable.push(entry);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const detection = await entry.adapter.detect(root);
|
|
122
|
+
if (detection.detected)
|
|
123
|
+
applicable.push(entry);
|
|
124
|
+
else
|
|
125
|
+
skipped.push({
|
|
126
|
+
source: entry,
|
|
127
|
+
reason: "found nothing it recognises in this repository",
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
skipped.push({ source: entry, reason: `detection failed — ${describe(error)}` });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return { applicable, skipped };
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one way an engine answer becomes an MCP tool result.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this file exists rather than each tool formatting its own reply
|
|
5
|
+
*
|
|
6
|
+
* `QueryResult` carries three things a caller would rather not think about: a
|
|
7
|
+
* staleness stamp (§27.3), a `truncated` flag, and `notes` — the plain-words
|
|
8
|
+
* disclosures that populate the five result states' `refused`/`empty`/`failed`/
|
|
9
|
+
* `timed_out` cases. The engine computes all three correctly today. Every one of
|
|
10
|
+
* them is one careless `return result.data` away from never reaching a user.
|
|
11
|
+
*
|
|
12
|
+
* So the tool handler's return type is `QueryResult`, not content. A handler
|
|
13
|
+
* *cannot* build a reply; it can only produce an answer, and this module is the
|
|
14
|
+
* only thing that turns an answer into frames. Rule 7 — honest degradation, no
|
|
15
|
+
* silent doing-less — becomes a property of the type system rather than of
|
|
16
|
+
* whoever writes the next tool.
|
|
17
|
+
*
|
|
18
|
+
* ## `ai-tool-contract.md` §2 — the frozen envelope
|
|
19
|
+
*
|
|
20
|
+
* This module used to ship a two-value `status: "ok" | "not_analysable"`. The
|
|
21
|
+
* contract froze five: `ok` / `empty` / `refused` / `failed` / `timed_out`
|
|
22
|
+
* (§1), plus `class`, `toolVersion`, `budget` and a structured `truncated`
|
|
23
|
+
* object (§2). `AnswerStatus`/`renderAnswer`'s old two-state shape is gone
|
|
24
|
+
* rather than kept alongside the new one — two envelope shapes on the wire is
|
|
25
|
+
* the thing DEC-277's "one process mints" reasoning exists to avoid one layer
|
|
26
|
+
* up, applied here to a type rather than a decision number.
|
|
27
|
+
*
|
|
28
|
+
* ## Four invariants, asserted rather than documented (§2.1)
|
|
29
|
+
*
|
|
30
|
+
* `render.ts` already enforced the first two; the other two are new.
|
|
31
|
+
*
|
|
32
|
+
* 1. `truncated != null` with empty `disclosures` → throw.
|
|
33
|
+
* 2. `state` in `{refused, failed, timed_out}` with empty `disclosures` → throw.
|
|
34
|
+
* 3. `state == "refused"` with no verbatim reason in `disclosures` → throw (§4).
|
|
35
|
+
* 4. `class == "action"` returning anything other than a handshake envelope on
|
|
36
|
+
* the first call → throw (§7) — enforced in `action-handshake.ts` and
|
|
37
|
+
* `server.ts`, not here: this module never sees a mint, only a redeemed run.
|
|
38
|
+
*/
|
|
39
|
+
import { type ReliabilityClass, type ReportCategory } from "@descryy/ir";
|
|
40
|
+
import type { ResultState, ToolClass } from "@descryy/ir";
|
|
41
|
+
import type { QueryResult } from "@descryy/core";
|
|
42
|
+
export type { ResultState } from "@descryy/ir";
|
|
43
|
+
/**
|
|
44
|
+
* MK-5 — which of the sixteen tools states a conclusion about the user's code
|
|
45
|
+
* versus which reports a fact about the graph.
|
|
46
|
+
*
|
|
47
|
+
* Lives here rather than in `@descryy/ir`: `tool-surface.ts`'s own header
|
|
48
|
+
* scopes that file to exactly `ResultState` and `ToolClass` ("and nothing
|
|
49
|
+
* else"), because those two cross into the pipeline and the desktop surface.
|
|
50
|
+
* This distinction is agent-mode-only (`plugin-and-mcp-surface.md` §3 PL-1),
|
|
51
|
+
* so a third shared union there would be scope creep the file's own doc
|
|
52
|
+
* disclaims. `kit.ts` imports it from here rather than the reverse, because
|
|
53
|
+
* `kit.ts` already depends on this module for `ToolAnswer`/`TruncationDetail`
|
|
54
|
+
* — defining it in `kit.ts` instead would make this module import back from
|
|
55
|
+
* `kit.ts` and cycle.
|
|
56
|
+
*
|
|
57
|
+
* - `conclusion` — the output is a statement about the user's code
|
|
58
|
+
* (`validate`, `contracts`, `cross_pr`). Never raw candidates: an
|
|
59
|
+
* already-adjudicated result carrying the category and the disclosure
|
|
60
|
+
* sentence as one payload.
|
|
61
|
+
* - `evidence` — the output is a fact the graph computed, already carrying
|
|
62
|
+
* its own resolution and qualification. The other thirteen.
|
|
63
|
+
*/
|
|
64
|
+
export declare const TOOL_TIERS: readonly ["conclusion", "evidence"];
|
|
65
|
+
export type ToolTier = (typeof TOOL_TIERS)[number];
|
|
66
|
+
/**
|
|
67
|
+
* MK-6 — a conclusion produced through this server must not carry the same
|
|
68
|
+
* badge as one produced by the app's full governance pipeline
|
|
69
|
+
* (`plugin-and-mcp-surface.md` §3 PL-4). Every value here is a fact about
|
|
70
|
+
* *this server*, not about any one call, so it is one constant reused on
|
|
71
|
+
* every envelope rather than a per-tool computation.
|
|
72
|
+
*/
|
|
73
|
+
export interface Provenance {
|
|
74
|
+
readonly surface: "mcp";
|
|
75
|
+
readonly adjudicatedBy: "descry";
|
|
76
|
+
readonly presentedBy: "host-agent";
|
|
77
|
+
/** MK-11: the G1–G5 governance pipeline does not run in this surface. */
|
|
78
|
+
readonly governancePipeline: false;
|
|
79
|
+
}
|
|
80
|
+
export interface TruncationDetail {
|
|
81
|
+
/** How many of the primary collection are in this reply. */
|
|
82
|
+
readonly shown: number;
|
|
83
|
+
/** The count before the cap — §5.5: "the count before the cap". */
|
|
84
|
+
readonly total: number;
|
|
85
|
+
/** A cursor to fetch the rest. `null` until pagination exists to redeem one. */
|
|
86
|
+
readonly more: string | null;
|
|
87
|
+
}
|
|
88
|
+
export interface ToolAnswer<T> {
|
|
89
|
+
readonly result: QueryResult<T>;
|
|
90
|
+
/**
|
|
91
|
+
* One of the five result states (§1). Omitted means `"ok"` — the common
|
|
92
|
+
* case, and the one that needs no tool-author ceremony.
|
|
93
|
+
*
|
|
94
|
+
* `"empty"` is a claim a tool must *earn* (§1.3b): reach for it only when
|
|
95
|
+
* the search ran against a population known to be real (an `analysed`/`ran`
|
|
96
|
+
* flag already true, a resolved node, a read that completed). Default to
|
|
97
|
+
* `"refused"` when that is not established — never to `"ok"` with a quietly
|
|
98
|
+
* empty collection, which is the exact defect §1 exists to close.
|
|
99
|
+
*/
|
|
100
|
+
readonly state?: ResultState;
|
|
101
|
+
/**
|
|
102
|
+
* Is this a claim about a *name* or about a *shape*? §11A.5 gives R2 two
|
|
103
|
+
* different caps depending on the answer, so it is required rather than
|
|
104
|
+
* defaulted — see `reliabilityCap`.
|
|
105
|
+
*/
|
|
106
|
+
readonly nameLevel: boolean;
|
|
107
|
+
/** One line the agent reads first. The payload is underneath it. */
|
|
108
|
+
readonly headline: string;
|
|
109
|
+
/**
|
|
110
|
+
* Present only when the tool already computed `shown`/`total` for its
|
|
111
|
+
* primary list at the return site (most do, for the "N further… capped at
|
|
112
|
+
* limit" note). `null` falls back to a bare boolean-shaped truncation with
|
|
113
|
+
* no counts — still non-null per invariant 1, just less informative.
|
|
114
|
+
*/
|
|
115
|
+
readonly truncatedDetail?: TruncationDetail;
|
|
116
|
+
/**
|
|
117
|
+
* §5.4's `refusals` field, populated by a tool whose *own call* produced a
|
|
118
|
+
* fresh population of `UnresolvedRef` rows to summarise — as opposed to
|
|
119
|
+
* `refusal_fetch`, which pages the whole graph's stored ledger. `analyze`
|
|
120
|
+
* is the one tool that fits today: a run reads sources and the refs it
|
|
121
|
+
* could not resolve are this call's own result, not a read of prior state.
|
|
122
|
+
* Omit when the tool has no such population, or when it summarised zero
|
|
123
|
+
* rows — an empty summary carries no exemplar or handle to show.
|
|
124
|
+
*/
|
|
125
|
+
readonly refusalSummary?: {
|
|
126
|
+
readonly count: number;
|
|
127
|
+
readonly exemplar: string;
|
|
128
|
+
readonly handle: string;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
export interface McpContent {
|
|
132
|
+
readonly type: "text";
|
|
133
|
+
readonly text: string;
|
|
134
|
+
}
|
|
135
|
+
export interface CallToolResult {
|
|
136
|
+
readonly content: readonly McpContent[];
|
|
137
|
+
readonly structuredContent: Record<string, unknown>;
|
|
138
|
+
readonly isError?: boolean;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The machine-readable envelope. Shape is stable across every tool.
|
|
142
|
+
*
|
|
143
|
+
* `T` is the tool's own `data` type — every tool exports one (`ImpactData`,
|
|
144
|
+
* `ScopeData`, …) and types its handler against it, so `tsc` rejects a handler
|
|
145
|
+
* that returns a shape the declaration does not name. The parameter defaults
|
|
146
|
+
* to `unknown` so a caller handling any tool's reply generically still type
|
|
147
|
+
* checks; a caller that knows which tool it called writes
|
|
148
|
+
* `AnswerEnvelope<ImpactData>` and gets the shape.
|
|
149
|
+
*/
|
|
150
|
+
export interface AnswerEnvelope<T = unknown> {
|
|
151
|
+
readonly tool: string;
|
|
152
|
+
/** Contract §6, rule 8. A behaviour change is a version bump; recorded with the run. */
|
|
153
|
+
readonly toolVersion: string;
|
|
154
|
+
readonly state: ResultState;
|
|
155
|
+
/** DEC-278's three classes — §6's retry table reads this. */
|
|
156
|
+
readonly class: ToolClass;
|
|
157
|
+
readonly headline: string;
|
|
158
|
+
/** `null` on `failed` (§2.2: always). May carry disambiguation, never an answer, on `refused`. */
|
|
159
|
+
readonly data: T | null;
|
|
160
|
+
readonly graph: {
|
|
161
|
+
readonly commitSha: string | null;
|
|
162
|
+
readonly builtAt: string | null;
|
|
163
|
+
readonly irSchemaVersion: number;
|
|
164
|
+
/** `null` — never absent — when the graph was not consulted at all (§3). */
|
|
165
|
+
readonly resolutionFloor: number | null;
|
|
166
|
+
readonly reliabilityCap: ReliabilityClass;
|
|
167
|
+
};
|
|
168
|
+
readonly truncated: TruncationDetail | null;
|
|
169
|
+
/**
|
|
170
|
+
* §5.4. `null` unless the answering tool supplied `refusalSummary` — see
|
|
171
|
+
* that field's own doc for which tools have a population to summarise.
|
|
172
|
+
*/
|
|
173
|
+
readonly refusals: {
|
|
174
|
+
readonly count: number;
|
|
175
|
+
readonly exemplar: string;
|
|
176
|
+
readonly handle: string;
|
|
177
|
+
} | null;
|
|
178
|
+
readonly budget: {
|
|
179
|
+
readonly elapsedMs: number;
|
|
180
|
+
readonly limitMs: number;
|
|
181
|
+
};
|
|
182
|
+
/** Never empty when the answer is degraded, truncated or refused/failed/timed-out. */
|
|
183
|
+
readonly disclosures: readonly string[];
|
|
184
|
+
/**
|
|
185
|
+
* MK-8/MK-11 — §19's five categories, settled for this surface: a
|
|
186
|
+
* `conclusion`-tier tool states its verdict in `headline`'s own plain words
|
|
187
|
+
* rather than through this apparatus (it is a fact, not a hypothesis), so
|
|
188
|
+
* this is `null` there. An `evidence`-tier tool never carries runtime
|
|
189
|
+
* evidence in this surface — descry-runtime's loop does not run inside an
|
|
190
|
+
* MCP call — so G3 always short-circuits: `refused` maps to the direct
|
|
191
|
+
* equivalent, `not analysable` ("could not look" vs. "cannot establish
|
|
192
|
+
* this here" are the same statement); `ok`/`empty` map to `unconfirmed`,
|
|
193
|
+
* since a graph fact with no runtime corroboration is never `confirmed` by
|
|
194
|
+
* construction; `failed`/`timed_out` carry no claim at all, so `null`.
|
|
195
|
+
* `confirmed` stays reserved for the app's full pipeline and is therefore
|
|
196
|
+
* unreachable from here — the honest outcome MK-11 ruled on, not a gap.
|
|
197
|
+
*/
|
|
198
|
+
readonly reportCategory: ReportCategory | null;
|
|
199
|
+
/** MK-6. Constant for this server — see `Provenance`'s own doc. */
|
|
200
|
+
readonly provenance: Provenance;
|
|
201
|
+
}
|
|
202
|
+
export declare class DisclosureError extends Error {
|
|
203
|
+
constructor(message: string);
|
|
204
|
+
}
|
|
205
|
+
export interface RenderOptions {
|
|
206
|
+
readonly toolVersion: string;
|
|
207
|
+
readonly toolClass: ToolClass;
|
|
208
|
+
/** MK-5/MK-8 — which report-category rule applies. See `ToolTier`. */
|
|
209
|
+
readonly toolTier: ToolTier;
|
|
210
|
+
readonly elapsedMs: number;
|
|
211
|
+
readonly limitMs: number;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* A refusal's reason must be the specific, verbatim thing that blocked it —
|
|
215
|
+
* never just the state name. This is a heuristic proxy for that rule (§4):
|
|
216
|
+
* `disclosures` must contain something a template did not produce, which we
|
|
217
|
+
* cannot verify from here, but we CAN verify the weaker, structurally
|
|
218
|
+
* checkable half — that at least one disclosure exists and it is not empty
|
|
219
|
+
* text — the same shape invariant 2 already asserts. The stronger claim (the
|
|
220
|
+
* reason is *this* refusal's actual cause, not a generic string) is a
|
|
221
|
+
* per-tool authoring discipline this function cannot see into; it is checked
|
|
222
|
+
* by `tool-contract-gate.mjs`'s exemplar reading instead.
|
|
223
|
+
*/
|
|
224
|
+
export declare function renderAnswer<T>(tool: string, answer: ToolAnswer<T>, options: RenderOptions): CallToolResult;
|
|
225
|
+
/**
|
|
226
|
+
* A failure that is the caller's to fix — a bad argument, a missing graph.
|
|
227
|
+
*
|
|
228
|
+
* Returned as a tool result with `isError`, not as a JSON-RPC error, which is
|
|
229
|
+
* what the MCP spec asks for: protocol errors are for malformed protocol, tool
|
|
230
|
+
* errors are for tools, and an agent can act on the second only if it arrives as
|
|
231
|
+
* content it can read.
|
|
232
|
+
*
|
|
233
|
+
* Deliberately outside the five-state envelope: a bad argument is not a
|
|
234
|
+
* statement about what Descry found or could not find, it is "fix your call
|
|
235
|
+
* and retry" — a different kind of thing than `refused`/`failed`.
|
|
236
|
+
*/
|
|
237
|
+
export declare function renderToolError(tool: string, message: string): CallToolResult;
|
|
238
|
+
/**
|
|
239
|
+
* `state: "failed"` — §1.1: "promoted from a transport error to a result."
|
|
240
|
+
*
|
|
241
|
+
* An unexpected/internal error, not a bad argument (`renderToolError` still
|
|
242
|
+
* handles those). `data` is always `null` here (§2.2): the tool does not know
|
|
243
|
+
* what happened, and anything it returned would be a guess about its own
|
|
244
|
+
* fault. `isError` stays `true` so a generic MCP client that only reads the
|
|
245
|
+
* transport-level signal still treats this as a failure; an AI-layer-aware
|
|
246
|
+
* caller additionally gets `state: "failed"` in `structuredContent` to reason
|
|
247
|
+
* about rather than a bare `{tool, status, message}` shape.
|
|
248
|
+
*/
|
|
249
|
+
export declare function renderFailed(tool: string, message: string, options: RenderOptions): CallToolResult;
|
|
250
|
+
/**
|
|
251
|
+
* The one legitimate producer of a pending-handshake payload — §7's mint call.
|
|
252
|
+
*
|
|
253
|
+
* `class == "action"` returning anything other than this shape on an
|
|
254
|
+
* unconfirmed first call is invariant 4 (§2.1): "throw." This function is
|
|
255
|
+
* where that shape is produced, so the throw lives at the one call site that
|
|
256
|
+
* builds anything else for an action tool's first call — `server.ts`'s
|
|
257
|
+
* dispatch loop calls this and only this when `resolveActionDispatch` returns
|
|
258
|
+
* `{kind: "handshake"}`, never `tool.run`.
|
|
259
|
+
*
|
|
260
|
+
* `state: "ok"` deliberately: a mint is not a refusal, a failure or an empty
|
|
261
|
+
* result — it is a successful "here is what I would do", and the *pending*
|
|
262
|
+
* flag inside `data` is what tells a caller nothing was performed yet.
|
|
263
|
+
*/
|
|
264
|
+
export declare function renderHandshake(tool: string, token: string, willDo: string, options: RenderOptions): CallToolResult;
|
|
265
|
+
/**
|
|
266
|
+
* `state: "timed_out"` — the call ran out of its declared budget.
|
|
267
|
+
*
|
|
268
|
+
* §6: "not a silent truncation and never a `failed`". `data` is `null` here
|
|
269
|
+
* because none of the registered tools currently produce genuine partial
|
|
270
|
+
* results mid-run (none checks `ctx.signal` internally yet — a disclosed gap,
|
|
271
|
+
* not a silent one, named in the returned disclosure); the envelope shape
|
|
272
|
+
* supports a populated partial `data` the day a tool does.
|
|
273
|
+
*/
|
|
274
|
+
export declare function renderTimedOut(tool: string, options: RenderOptions): CallToolResult;
|
|
275
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|