skillscript-runtime 0.3.4 → 0.4.1
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/ARCHITECTURE.md +3 -1
- package/README.md +26 -0
- package/dist/bootstrap.d.ts +15 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +33 -0
- package/dist/bootstrap.js.map +1 -1
- package/dist/compile.d.ts +9 -0
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +1 -0
- package/dist/compile.js.map +1 -1
- package/dist/connectors/config.d.ts +94 -0
- package/dist/connectors/config.d.ts.map +1 -0
- package/dist/connectors/config.js +276 -0
- package/dist/connectors/config.js.map +1 -0
- package/dist/connectors/mcp-remote.d.ts +79 -0
- package/dist/connectors/mcp-remote.d.ts.map +1 -0
- package/dist/connectors/mcp-remote.js +342 -0
- package/dist/connectors/mcp-remote.js.map +1 -0
- package/dist/connectors/registry.d.ts +10 -1
- package/dist/connectors/registry.d.ts.map +1 -1
- package/dist/connectors/registry.js +33 -3
- package/dist/connectors/registry.js.map +1 -1
- package/dist/help-content.d.ts.map +1 -1
- package/dist/help-content.js +1 -0
- package/dist/help-content.js.map +1 -1
- package/dist/lint.d.ts +28 -0
- package/dist/lint.d.ts.map +1 -1
- package/dist/lint.js +125 -0
- package/dist/lint.js.map +1 -1
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +26 -3
- package/dist/mcp-server.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +80 -2
- package/dist/runtime.js.map +1 -1
- package/examples/hello.skill.provenance.json +1 -1
- package/examples/youtrack-morning-sweep.skill.md +17 -0
- package/package.json +1 -1
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
// v0.4.0 — `connectors.json` loader. Reads + validates the per-host
|
|
2
|
+
// connector configuration file at runtime startup and wires the
|
|
3
|
+
// declared instances into the Registry.
|
|
4
|
+
//
|
|
5
|
+
// Spec: ERD §3 + Perry's v0.4.0 kickoff (b3f6c5ed) + amendment (58a9d3d3).
|
|
6
|
+
//
|
|
7
|
+
// Surface shape (matches Claude Desktop's `mcp.json` convention so authors
|
|
8
|
+
// don't carry two mental models):
|
|
9
|
+
//
|
|
10
|
+
// {
|
|
11
|
+
// "youtrack": {
|
|
12
|
+
// "class": "RemoteMcpConnector",
|
|
13
|
+
// "config": {
|
|
14
|
+
// "command": "npx",
|
|
15
|
+
// "args": ["mcp-remote", "https://...", "--header", "Authorization:${AUTH_HEADER}"],
|
|
16
|
+
// "env": { "AUTH_HEADER": "Bearer ${YOUTRACK_TOKEN}" }
|
|
17
|
+
// }
|
|
18
|
+
// }
|
|
19
|
+
// }
|
|
20
|
+
//
|
|
21
|
+
// **Credential discipline (v0.4.0 hard requirement, Perry's amendment):**
|
|
22
|
+
// `connectors.json` is secret-bearing. Default `.gitignore` excludes it;
|
|
23
|
+
// `connectors.json.example` ships at repo root as the template. See README.
|
|
24
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
25
|
+
import { dirname, basename, resolve } from "node:path";
|
|
26
|
+
import { CallbackMcpConnector } from "./mcp.js";
|
|
27
|
+
import { RemoteMcpConnector } from "./mcp-remote.js";
|
|
28
|
+
export const KNOWN_CONNECTOR_CLASSES = new Map([
|
|
29
|
+
["CallbackMcpConnector", { ctor: CallbackMcpConnector }],
|
|
30
|
+
[
|
|
31
|
+
"RemoteMcpConnector",
|
|
32
|
+
{
|
|
33
|
+
ctor: RemoteMcpConnector,
|
|
34
|
+
fromConfig: (config) => RemoteMcpConnector.fromConfig(config),
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
]);
|
|
38
|
+
/** Listable for error messages + runtime_capabilities discovery. */
|
|
39
|
+
export function listKnownConnectorClasses() {
|
|
40
|
+
return [...KNOWN_CONNECTOR_CLASSES.keys()];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* v0.4.1 — credential-discipline backstop. Walk up from `connectors.json`'s
|
|
44
|
+
* dir looking for `.git/`. If found, check whether any `.gitignore` between
|
|
45
|
+
* the file and the git root excludes `connectors.json`. Returns a warning
|
|
46
|
+
* string when the file appears to be in a git repo BUT not gitignored.
|
|
47
|
+
* `null` means either (a) not in a git repo, or (b) gitignored cleanly.
|
|
48
|
+
*
|
|
49
|
+
* Heuristic — not a full gitignore parser. Recognizes the canonical
|
|
50
|
+
* exclusion patterns: `connectors.json`, `/connectors.json`, `*.json`
|
|
51
|
+
* (broad), and anchored ancestor-dir matches. False negatives (warning
|
|
52
|
+
* fires on a gitignored file) are possible with exotic gitignore shapes;
|
|
53
|
+
* those are operator-fixable. False positives (warning suppressed on a
|
|
54
|
+
* tracked file) are the worse outcome and the heuristic biases against.
|
|
55
|
+
*/
|
|
56
|
+
export function detectGitignoreRisk(configPath) {
|
|
57
|
+
let dir = dirname(resolve(configPath));
|
|
58
|
+
const filename = basename(configPath);
|
|
59
|
+
const gitignorePaths = [];
|
|
60
|
+
let gitRoot = null;
|
|
61
|
+
// Walk up looking for .git/ and collecting any .gitignore files along the way.
|
|
62
|
+
while (true) {
|
|
63
|
+
if (existsSync(`${dir}/.git`)) {
|
|
64
|
+
gitRoot = dir;
|
|
65
|
+
const rootGitignore = `${dir}/.gitignore`;
|
|
66
|
+
if (existsSync(rootGitignore))
|
|
67
|
+
gitignorePaths.push(rootGitignore);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
const localGitignore = `${dir}/.gitignore`;
|
|
71
|
+
if (existsSync(localGitignore))
|
|
72
|
+
gitignorePaths.push(localGitignore);
|
|
73
|
+
const parent = dirname(dir);
|
|
74
|
+
if (parent === dir)
|
|
75
|
+
break; // hit filesystem root
|
|
76
|
+
dir = parent;
|
|
77
|
+
}
|
|
78
|
+
if (gitRoot === null)
|
|
79
|
+
return null; // not in a git repo
|
|
80
|
+
// Scan all collected .gitignore files for any line that would exclude
|
|
81
|
+
// the connectors.json filename. Patterns recognized: bare name, anchored
|
|
82
|
+
// `/<name>`, anchored to subdir, or wildcard `*.json` (rare but valid).
|
|
83
|
+
const patterns = [filename, `/${filename}`];
|
|
84
|
+
for (const giPath of gitignorePaths) {
|
|
85
|
+
let raw;
|
|
86
|
+
try {
|
|
87
|
+
raw = readFileSync(giPath, "utf8");
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const lines = raw.split("\n").map((l) => l.trim()).filter((l) => l !== "" && !l.startsWith("#"));
|
|
93
|
+
for (const line of lines) {
|
|
94
|
+
if (patterns.includes(line))
|
|
95
|
+
return null; // explicitly ignored
|
|
96
|
+
// Wildcard match: `*.json` or `*` — broad, assume covers the file.
|
|
97
|
+
if (line === "*" || line === "*.json")
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// In a git repo, but no .gitignore entry seems to cover connectors.json.
|
|
102
|
+
// Warn (informational; not blocking).
|
|
103
|
+
return `connectors.json appears to be in a git-tracked directory (${gitRoot}) without a .gitignore entry. Credentials in this file may end up committed. Add '/connectors.json' to your .gitignore — or use the bundled \`connectors.json.example\` template + \${ENV} substitution pattern instead.`;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Resolve `${NAME}` patterns in a string against the provided env.
|
|
107
|
+
* Missing var → throws (clear error rather than silent empty string).
|
|
108
|
+
* Used by the loader on every string value in the `config` block.
|
|
109
|
+
*/
|
|
110
|
+
export function resolveEnvSubstitution(value, env) {
|
|
111
|
+
return value.replace(/\$\{([A-Z_][A-Z0-9_]*)\}/g, (_match, name) => {
|
|
112
|
+
const v = env[name];
|
|
113
|
+
if (v === undefined) {
|
|
114
|
+
throw new Error(`Environment variable '\${${name}}' referenced in connectors.json is not set.`);
|
|
115
|
+
}
|
|
116
|
+
return v;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/** Walk a config tree and resolve `${NAME}` substitutions on every string leaf. */
|
|
120
|
+
function resolveConfigEnv(value, env) {
|
|
121
|
+
if (typeof value === "string")
|
|
122
|
+
return resolveEnvSubstitution(value, env);
|
|
123
|
+
if (Array.isArray(value))
|
|
124
|
+
return value.map((v) => resolveConfigEnv(v, env));
|
|
125
|
+
if (value !== null && typeof value === "object") {
|
|
126
|
+
const out = {};
|
|
127
|
+
for (const [k, v] of Object.entries(value))
|
|
128
|
+
out[k] = resolveConfigEnv(v, env);
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Read + parse `connectors.json` at the given path. Validate the top-
|
|
135
|
+
* level shape. Resolve `${VAR}` substitutions. Instantiate each entry
|
|
136
|
+
* via the closed-set class registry's `fromConfig` factory (when
|
|
137
|
+
* present; entries pointing at classes without one get a clear error
|
|
138
|
+
* and a `null` instance, surfaced via `errors`).
|
|
139
|
+
*
|
|
140
|
+
* Missing file → returns `{connectors: [], errors: []}` (graceful: not
|
|
141
|
+
* every deployment uses external connectors). Malformed JSON or
|
|
142
|
+
* structural errors → returned in `errors[]` for the bootstrap caller
|
|
143
|
+
* to log and refuse to start, or for the lint surface to consume.
|
|
144
|
+
*/
|
|
145
|
+
export function loadConnectorsConfig(opts) {
|
|
146
|
+
const env = opts.env ?? process.env;
|
|
147
|
+
let raw;
|
|
148
|
+
try {
|
|
149
|
+
raw = readFileSync(opts.path, "utf8");
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
const code = err.code;
|
|
153
|
+
if (code === "ENOENT")
|
|
154
|
+
return { connectors: [], errors: [] };
|
|
155
|
+
return { connectors: [], errors: [`connectors.json: failed to read '${opts.path}': ${err.message}`] };
|
|
156
|
+
}
|
|
157
|
+
let parsed;
|
|
158
|
+
try {
|
|
159
|
+
parsed = JSON.parse(raw);
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
return { connectors: [], errors: [`connectors.json: malformed JSON in '${opts.path}': ${err.message}`] };
|
|
163
|
+
}
|
|
164
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
165
|
+
return { connectors: [], errors: [`connectors.json: top-level must be an object mapping connector names to {class, config}. Got: ${Array.isArray(parsed) ? "array" : typeof parsed}.`] };
|
|
166
|
+
}
|
|
167
|
+
const connectors = [];
|
|
168
|
+
const errors = [];
|
|
169
|
+
for (const [name, entry] of Object.entries(parsed)) {
|
|
170
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) {
|
|
171
|
+
errors.push(`connectors.json: entry '${name}' must be an object with {class, config}. Got: ${Array.isArray(entry) ? "array" : entry === null ? "null" : typeof entry}.`);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
const obj = entry;
|
|
175
|
+
const className = obj["class"];
|
|
176
|
+
if (typeof className !== "string" || className === "") {
|
|
177
|
+
errors.push(`connectors.json: entry '${name}' is missing required string field 'class'.`);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const rawConfig = obj["config"] ?? {};
|
|
181
|
+
if (rawConfig === null || typeof rawConfig !== "object" || Array.isArray(rawConfig)) {
|
|
182
|
+
errors.push(`connectors.json: entry '${name}' field 'config' must be an object. Got: ${Array.isArray(rawConfig) ? "array" : typeof rawConfig}.`);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
// v0.4.1 env-block-as-scope: resolve `config.env` against process.env
|
|
186
|
+
// FIRST, then merge into the substitution scope for the rest of the
|
|
187
|
+
// config. Lets authors compose values like:
|
|
188
|
+
// env: { AUTH_HEADER: "Bearer ${YOUTRACK_TOKEN}" }
|
|
189
|
+
// args: ["--header", "Authorization:${AUTH_HEADER}"]
|
|
190
|
+
// Matches Claude Desktop's `mcp.json` convention.
|
|
191
|
+
let resolvedConfig;
|
|
192
|
+
try {
|
|
193
|
+
const cfgObj = rawConfig;
|
|
194
|
+
const rawEnv = cfgObj["env"];
|
|
195
|
+
let resolvedEnv;
|
|
196
|
+
let scopedEnv = env;
|
|
197
|
+
if (rawEnv !== undefined) {
|
|
198
|
+
if (rawEnv === null || typeof rawEnv !== "object" || Array.isArray(rawEnv)) {
|
|
199
|
+
errors.push(`connectors.json: entry '${name}' field 'config.env' must be an object of string values.`);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
resolvedEnv = {};
|
|
203
|
+
for (const [k, v] of Object.entries(rawEnv)) {
|
|
204
|
+
if (typeof v !== "string") {
|
|
205
|
+
errors.push(`connectors.json: entry '${name}': config.env['${k}'] must be a string (got ${typeof v}).`);
|
|
206
|
+
resolvedEnv = undefined;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
resolvedEnv[k] = resolveEnvSubstitution(v, env);
|
|
210
|
+
}
|
|
211
|
+
if (resolvedEnv === undefined)
|
|
212
|
+
continue;
|
|
213
|
+
scopedEnv = { ...env, ...resolvedEnv };
|
|
214
|
+
}
|
|
215
|
+
// Resolve the rest of the config using the scoped env (process.env
|
|
216
|
+
// plus the just-resolved env block). The env block itself goes in
|
|
217
|
+
// pre-resolved to skip a redundant second pass.
|
|
218
|
+
const restConfig = {};
|
|
219
|
+
for (const [k, v] of Object.entries(cfgObj)) {
|
|
220
|
+
if (k === "env") {
|
|
221
|
+
if (resolvedEnv !== undefined)
|
|
222
|
+
restConfig["env"] = resolvedEnv;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
restConfig[k] = resolveConfigEnv(v, scopedEnv);
|
|
226
|
+
}
|
|
227
|
+
resolvedConfig = restConfig;
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
errors.push(`connectors.json: entry '${name}': ${err.message}`);
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
const classEntry = KNOWN_CONNECTOR_CLASSES.get(className);
|
|
234
|
+
if (classEntry === undefined) {
|
|
235
|
+
errors.push(`connectors.json: entry '${name}' references unknown connector class '${className}'. Known classes: ${listKnownConnectorClasses().join(", ")}.`);
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
let instance;
|
|
239
|
+
if (classEntry.fromConfig !== undefined) {
|
|
240
|
+
try {
|
|
241
|
+
instance = classEntry.fromConfig(resolvedConfig);
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
errors.push(`connectors.json: entry '${name}' failed to instantiate '${className}': ${err.message}`);
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
// No fromConfig means the class can't be JSON-instantiated. v0.4.0
|
|
250
|
+
// ships with CallbackMcpConnector in this state — wire it via
|
|
251
|
+
// embedder code. v0.4.1 adds RemoteMcpConnector with a fromConfig.
|
|
252
|
+
errors.push(`connectors.json: entry '${name}' uses class '${className}' which doesn't support configuration via connectors.json. Wire this connector via embedder code instead, or use a JSON-instantiable class.`);
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
// v0.4.1 — `allowed_tools` allowlist. Optional. Undefined = allow-all;
|
|
256
|
+
// [] = allow-none (staging disable); listed = exactly-these.
|
|
257
|
+
let allowedTools;
|
|
258
|
+
const rawAllowed = obj["allowed_tools"];
|
|
259
|
+
if (rawAllowed !== undefined) {
|
|
260
|
+
if (!Array.isArray(rawAllowed) || !rawAllowed.every((t) => typeof t === "string")) {
|
|
261
|
+
errors.push(`connectors.json: entry '${name}' field 'allowed_tools' must be an array of strings (got ${Array.isArray(rawAllowed) ? "array with non-string element" : typeof rawAllowed}).`);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
allowedTools = rawAllowed;
|
|
265
|
+
}
|
|
266
|
+
connectors.push({
|
|
267
|
+
name,
|
|
268
|
+
className,
|
|
269
|
+
config: resolvedConfig,
|
|
270
|
+
instance,
|
|
271
|
+
...(allowedTools !== undefined ? { allowedTools } : {}),
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
return { connectors, errors };
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/connectors/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { McpConnector, McpDispatchCtx, StaticCapabilities, ManifestInfo } from "./types.js";
|
|
2
|
+
/** Wire-format options for stdio framing between this process and the spawned MCP child. */
|
|
3
|
+
export type RemoteMcpFraming = "lsp" | "newline";
|
|
4
|
+
/**
|
|
5
|
+
* Configuration shape for a `RemoteMcpConnector` in `connectors.json`.
|
|
6
|
+
* `${VAR}` substitutions are resolved at config-load time (v0.4.0); the
|
|
7
|
+
* resolved values arrive here verbatim. Extra fields (e.g. v0.4.x+
|
|
8
|
+
* `allowed_tools`) flow through the loader's permissive-field handling
|
|
9
|
+
* and are not validated by this constructor — they're handled at
|
|
10
|
+
* dispatch-policy layers above.
|
|
11
|
+
*/
|
|
12
|
+
export interface RemoteMcpConfig {
|
|
13
|
+
/** Executable to spawn. Typically `"npx"`, `"node"`, or a binary path. */
|
|
14
|
+
command: string;
|
|
15
|
+
/** Argument list for the spawned process. */
|
|
16
|
+
args: string[];
|
|
17
|
+
/** Environment variables for the spawned child. Merged with parent env. */
|
|
18
|
+
env?: Record<string, string>;
|
|
19
|
+
/** Stdio framing convention. Default: `"lsp"`. */
|
|
20
|
+
framing?: RemoteMcpFraming;
|
|
21
|
+
/** Maximum time (ms) to wait for the `initialize` response. Default: 10000. */
|
|
22
|
+
initTimeoutMs?: number;
|
|
23
|
+
/** Maximum time (ms) to wait for a `tools/call` response. Default: 30000. */
|
|
24
|
+
callTimeoutMs?: number;
|
|
25
|
+
/** Maximum time (ms) to wait for graceful shutdown before SIGKILL. Default: 2000. */
|
|
26
|
+
shutdownTimeoutMs?: number;
|
|
27
|
+
}
|
|
28
|
+
/** Connector dispatch error — bridge-side failures surface to skill via this. */
|
|
29
|
+
export declare class RemoteMcpDispatchError extends Error {
|
|
30
|
+
readonly bridgeCause: unknown;
|
|
31
|
+
constructor(message: string, bridgeCause?: unknown);
|
|
32
|
+
}
|
|
33
|
+
export declare class RemoteMcpConnector implements McpConnector {
|
|
34
|
+
private readonly config;
|
|
35
|
+
static staticCapabilities(): StaticCapabilities;
|
|
36
|
+
/**
|
|
37
|
+
* Closed-set registry factory. Validates config shape, constructs the
|
|
38
|
+
* instance. The spawn + handshake are deferred to first dispatch (or
|
|
39
|
+
* an explicit `start()` call) so config validation can happen
|
|
40
|
+
* synchronously at load time.
|
|
41
|
+
*/
|
|
42
|
+
static fromConfig(config: Record<string, unknown>): RemoteMcpConnector;
|
|
43
|
+
private child;
|
|
44
|
+
private nextRequestId;
|
|
45
|
+
private pending;
|
|
46
|
+
private inboundBuffer;
|
|
47
|
+
private initializePromise;
|
|
48
|
+
private toolsAvailable;
|
|
49
|
+
private errorState;
|
|
50
|
+
private readonly framing;
|
|
51
|
+
private readonly initTimeoutMs;
|
|
52
|
+
private readonly callTimeoutMs;
|
|
53
|
+
private readonly shutdownTimeoutMs;
|
|
54
|
+
constructor(config: RemoteMcpConfig);
|
|
55
|
+
/**
|
|
56
|
+
* Spawn the child + run the `initialize` handshake. Idempotent;
|
|
57
|
+
* subsequent calls return the same in-flight or completed promise.
|
|
58
|
+
* Called lazily by `call()` on first dispatch.
|
|
59
|
+
*/
|
|
60
|
+
start(): Promise<unknown>;
|
|
61
|
+
private doStart;
|
|
62
|
+
call(toolName: string, args: Record<string, unknown>, _ctxOverrides?: McpDispatchCtx): Promise<unknown>;
|
|
63
|
+
manifest(): Promise<ManifestInfo>;
|
|
64
|
+
/**
|
|
65
|
+
* Graceful shutdown. Best-effort `shutdown` JSON-RPC request, then
|
|
66
|
+
* SIGTERM, then SIGKILL fallback after `shutdownTimeoutMs`. Idempotent.
|
|
67
|
+
*/
|
|
68
|
+
dispose(): Promise<void>;
|
|
69
|
+
/** For tests + observability — names of tools surfaced by the initialize handshake. */
|
|
70
|
+
getToolsAvailable(): readonly string[];
|
|
71
|
+
private sendRequest;
|
|
72
|
+
private encodeFrame;
|
|
73
|
+
private drainInbound;
|
|
74
|
+
private drainLsp;
|
|
75
|
+
private drainNewline;
|
|
76
|
+
private handleInboundMessage;
|
|
77
|
+
private rejectAllPending;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=mcp-remote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-remote.d.ts","sourceRoot":"","sources":["../../src/connectors/mcp-remote.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,YAAY,EACb,MAAM,YAAY,CAAC;AAIpB,4FAA4F;AAC5F,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,SAAS,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,kDAAkD;IAClD,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAsBD,iFAAiF;AACjF,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,SAAgB,WAAW,EAAE,OAAO,CAAC;gBACzB,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,OAAO;CAKnD;AAED,qBAAa,kBAAmB,YAAW,YAAY;IAgEzC,OAAO,CAAC,QAAQ,CAAC,MAAM;IA/DnC,MAAM,CAAC,kBAAkB,IAAI,kBAAkB;IAa/C;;;;;OAKG;IACH,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB;IAgCtE,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,OAAO,CAA2C;IAC1D,OAAO,CAAC,aAAa,CAAmB;IACxC,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;gBAEd,MAAM,EAAE,eAAe;IAOpD;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;YAMX,OAAO;IAoDf,IAAI,CACR,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,aAAa,CAAC,EAAE,cAAc,GAC7B,OAAO,CAAC,OAAO,CAAC;IA2Bb,QAAQ,IAAI,OAAO,CAAC,YAAY,CAAC;IAcvC;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA0B9B,uFAAuF;IACvF,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAMtC,OAAO,CAAC,WAAW;IA+BnB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,QAAQ;IAoBhB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,gBAAgB;CAOzB"}
|