@sammorrowdrums/mcpi-ext 0.2.1 → 1.0.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/LICENSE +21 -0
- package/README.md +426 -151
- package/dist/code-mode/eligibility.d.ts +29 -4
- package/dist/code-mode/eligibility.js +56 -6
- package/dist/code-mode/executor.d.ts +19 -1
- package/dist/code-mode/executor.js +73 -8
- package/dist/code-mode/index.d.ts +54 -12
- package/dist/code-mode/index.js +157 -65
- package/dist/code-mode/isolated-vm.d.ts +65 -0
- package/dist/code-mode/isolated-vm.js +116 -0
- package/dist/code-mode/tools.d.ts +4 -1
- package/dist/code-mode/tools.js +7 -4
- package/dist/code-mode/type-hints.d.ts +2 -2
- package/dist/code-mode/type-hints.js +24 -8
- package/dist/docker-e2e.d.ts +0 -1
- package/dist/docker-e2e.js +0 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +146 -67
- package/dist/mcp/call-tool-result.d.ts +10 -0
- package/dist/mcp/call-tool-result.js +70 -0
- package/dist/mcp/client-factory.d.ts +59 -0
- package/dist/mcp/client-factory.js +76 -0
- package/dist/mcp/client-manager.d.ts +61 -19
- package/dist/mcp/client-manager.js +223 -64
- package/dist/mcp/config-loader.d.ts +0 -1
- package/dist/mcp/config-loader.js +0 -1
- package/dist/mcp/config.d.ts +11 -1
- package/dist/mcp/config.js +15 -1
- package/dist/mcp/gateway-defaults.d.ts +14 -0
- package/dist/mcp/gateway-defaults.js +21 -0
- package/dist/mcp/host-approval.d.ts +16 -0
- package/dist/mcp/host-approval.js +19 -0
- package/dist/mcp/host-elicitation.d.ts +19 -0
- package/dist/mcp/host-elicitation.js +94 -0
- package/dist/mcp/index.d.ts +4 -1
- package/dist/mcp/index.js +4 -1
- package/dist/mcp/policy.d.ts +314 -0
- package/dist/mcp/policy.js +848 -0
- package/dist/routing/facilities.d.ts +109 -0
- package/dist/routing/facilities.js +175 -0
- package/dist/routing/format.d.ts +24 -0
- package/dist/routing/format.js +64 -0
- package/dist/routing/index.d.ts +4 -0
- package/dist/routing/index.js +4 -0
- package/dist/routing/seam.d.ts +35 -0
- package/dist/routing/seam.js +28 -0
- package/dist/routing/tripwire.d.ts +42 -0
- package/dist/routing/tripwire.js +80 -0
- package/dist/skills/discover.d.ts +5 -3
- package/dist/skills/discover.js +37 -12
- package/dist/skills/format.d.ts +4 -1
- package/dist/skills/format.js +8 -4
- package/dist/skills/index.d.ts +2 -2
- package/dist/skills/index.js +1 -1
- package/dist/skills/load-skill-tool.d.ts +23 -7
- package/dist/skills/load-skill-tool.js +112 -33
- package/dist/skills/mcp-tool-proxy.d.ts +4 -8
- package/dist/skills/mcp-tool-proxy.js +22 -97
- package/dist/skills/sep2640/client.d.ts +91 -0
- package/dist/skills/sep2640/client.js +160 -0
- package/dist/skills/sep2640/discover.d.ts +33 -0
- package/dist/skills/sep2640/discover.js +82 -0
- package/dist/skills/sep2640/index.d.ts +13 -0
- package/dist/skills/sep2640/index.js +13 -0
- package/dist/skills/sep2640/integrity.d.ts +58 -0
- package/dist/skills/sep2640/integrity.js +185 -0
- package/dist/skills/sep2640/load.d.ts +61 -0
- package/dist/skills/sep2640/load.js +90 -0
- package/dist/skills/sep2640/protocol.d.ts +146 -0
- package/dist/skills/sep2640/protocol.js +214 -0
- package/dist/skills/sep2640/spec.d.ts +76 -0
- package/dist/skills/sep2640/spec.js +88 -0
- package/dist/skills/skill-registry.d.ts +48 -2
- package/dist/skills/skill-registry.js +40 -3
- package/dist/tool-cli/bridge.d.ts +14 -0
- package/dist/tool-cli/bridge.js +196 -0
- package/dist/tool-cli/format.d.ts +17 -5
- package/dist/tool-cli/format.js +36 -20
- package/dist/tool-cli/index.d.ts +5 -2
- package/dist/tool-cli/index.js +3 -1
- package/dist/tool-cli/provider.d.ts +21 -0
- package/dist/tool-cli/provider.js +114 -0
- package/dist/tool-cli/startup.d.ts +22 -0
- package/dist/tool-cli/startup.js +47 -0
- package/package.json +78 -30
- package/dist/code-mode/code-mode-integration.test.d.ts +0 -2
- package/dist/code-mode/code-mode-integration.test.d.ts.map +0 -1
- package/dist/code-mode/code-mode-integration.test.js +0 -116
- package/dist/code-mode/code-mode-integration.test.js.map +0 -1
- package/dist/code-mode/eligibility.d.ts.map +0 -1
- package/dist/code-mode/eligibility.js.map +0 -1
- package/dist/code-mode/eligibility.test.d.ts +0 -2
- package/dist/code-mode/eligibility.test.d.ts.map +0 -1
- package/dist/code-mode/eligibility.test.js +0 -53
- package/dist/code-mode/eligibility.test.js.map +0 -1
- package/dist/code-mode/executor.d.ts.map +0 -1
- package/dist/code-mode/executor.js.map +0 -1
- package/dist/code-mode/executor.test.d.ts +0 -2
- package/dist/code-mode/executor.test.d.ts.map +0 -1
- package/dist/code-mode/executor.test.js +0 -130
- package/dist/code-mode/executor.test.js.map +0 -1
- package/dist/code-mode/index.d.ts.map +0 -1
- package/dist/code-mode/index.js.map +0 -1
- package/dist/code-mode/tools.d.ts.map +0 -1
- package/dist/code-mode/tools.js.map +0 -1
- package/dist/code-mode/type-hints.d.ts.map +0 -1
- package/dist/code-mode/type-hints.js.map +0 -1
- package/dist/code-mode/type-hints.test.d.ts +0 -2
- package/dist/code-mode/type-hints.test.d.ts.map +0 -1
- package/dist/code-mode/type-hints.test.js +0 -157
- package/dist/code-mode/type-hints.test.js.map +0 -1
- package/dist/docker-e2e.d.ts.map +0 -1
- package/dist/docker-e2e.js.map +0 -1
- package/dist/docker-e2e.test.d.ts +0 -2
- package/dist/docker-e2e.test.d.ts.map +0 -1
- package/dist/docker-e2e.test.js +0 -176
- package/dist/docker-e2e.test.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -8
- package/dist/index.test.js.map +0 -1
- package/dist/mcp/client-manager.d.ts.map +0 -1
- package/dist/mcp/client-manager.js.map +0 -1
- package/dist/mcp/client-manager.test.d.ts +0 -2
- package/dist/mcp/client-manager.test.d.ts.map +0 -1
- package/dist/mcp/client-manager.test.js +0 -204
- package/dist/mcp/client-manager.test.js.map +0 -1
- package/dist/mcp/config-loader.d.ts.map +0 -1
- package/dist/mcp/config-loader.js.map +0 -1
- package/dist/mcp/config-loader.test.d.ts +0 -2
- package/dist/mcp/config-loader.test.d.ts.map +0 -1
- package/dist/mcp/config-loader.test.js +0 -93
- package/dist/mcp/config-loader.test.js.map +0 -1
- package/dist/mcp/config.d.ts.map +0 -1
- package/dist/mcp/config.js.map +0 -1
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/index.js.map +0 -1
- package/dist/skills/discover.d.ts.map +0 -1
- package/dist/skills/discover.js.map +0 -1
- package/dist/skills/format.d.ts.map +0 -1
- package/dist/skills/format.js.map +0 -1
- package/dist/skills/format.test.d.ts +0 -2
- package/dist/skills/format.test.d.ts.map +0 -1
- package/dist/skills/format.test.js +0 -63
- package/dist/skills/format.test.js.map +0 -1
- package/dist/skills/index.d.ts.map +0 -1
- package/dist/skills/index.js.map +0 -1
- package/dist/skills/load-skill-tool.d.ts.map +0 -1
- package/dist/skills/load-skill-tool.js.map +0 -1
- package/dist/skills/mcp-tool-proxy.d.ts.map +0 -1
- package/dist/skills/mcp-tool-proxy.js.map +0 -1
- package/dist/skills/skill-integration.test.d.ts +0 -2
- package/dist/skills/skill-integration.test.d.ts.map +0 -1
- package/dist/skills/skill-integration.test.js +0 -119
- package/dist/skills/skill-integration.test.js.map +0 -1
- package/dist/skills/skill-registry.d.ts.map +0 -1
- package/dist/skills/skill-registry.js.map +0 -1
- package/dist/skills/skill-registry.test.d.ts +0 -2
- package/dist/skills/skill-registry.test.d.ts.map +0 -1
- package/dist/skills/skill-registry.test.js +0 -67
- package/dist/skills/skill-registry.test.js.map +0 -1
- package/dist/test-servers/weather-server.d.ts +0 -12
- package/dist/test-servers/weather-server.d.ts.map +0 -1
- package/dist/test-servers/weather-server.js +0 -139
- package/dist/test-servers/weather-server.js.map +0 -1
- package/dist/test-servers/weather-stdio.d.ts +0 -2
- package/dist/test-servers/weather-stdio.d.ts.map +0 -1
- package/dist/test-servers/weather-stdio.js +0 -11
- package/dist/test-servers/weather-stdio.js.map +0 -1
- package/dist/tool-cli/cli.d.ts +0 -3
- package/dist/tool-cli/cli.d.ts.map +0 -1
- package/dist/tool-cli/cli.js +0 -179
- package/dist/tool-cli/cli.js.map +0 -1
- package/dist/tool-cli/constants.d.ts +0 -7
- package/dist/tool-cli/constants.d.ts.map +0 -1
- package/dist/tool-cli/constants.js +0 -15
- package/dist/tool-cli/constants.js.map +0 -1
- package/dist/tool-cli/format.d.ts.map +0 -1
- package/dist/tool-cli/format.js.map +0 -1
- package/dist/tool-cli/format.test.d.ts +0 -2
- package/dist/tool-cli/format.test.d.ts.map +0 -1
- package/dist/tool-cli/format.test.js +0 -30
- package/dist/tool-cli/format.test.js.map +0 -1
- package/dist/tool-cli/index.d.ts.map +0 -1
- package/dist/tool-cli/index.js.map +0 -1
- package/dist/tool-cli/rpc-client.d.ts +0 -6
- package/dist/tool-cli/rpc-client.d.ts.map +0 -1
- package/dist/tool-cli/rpc-client.js +0 -25
- package/dist/tool-cli/rpc-client.js.map +0 -1
- package/dist/tool-cli/rpc-server.d.ts +0 -48
- package/dist/tool-cli/rpc-server.d.ts.map +0 -1
- package/dist/tool-cli/rpc-server.js +0 -220
- package/dist/tool-cli/rpc-server.js.map +0 -1
- package/dist/tool-cli/rpc-server.test.d.ts +0 -2
- package/dist/tool-cli/rpc-server.test.d.ts.map +0 -1
- package/dist/tool-cli/rpc-server.test.js +0 -154
- package/dist/tool-cli/rpc-server.test.js.map +0 -1
package/dist/code-mode/index.js
CHANGED
|
@@ -1,35 +1,111 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { McpPolicyError } from "../mcp/policy.js";
|
|
2
|
+
import { getCodeModeDiagnostics, getCodeModeTools, } from "./eligibility.js";
|
|
3
|
+
import { CodeModeDispatchError, executeInSandbox } from "./executor.js";
|
|
4
|
+
import { loadIsolatedVm } from "./isolated-vm.js";
|
|
3
5
|
import { createCodeExecuteTool, createCodeSearchTool } from "./tools.js";
|
|
4
6
|
import { generateTypeHints } from "./type-hints.js";
|
|
5
|
-
export { getEligibleTools, isEligibleForCodeMode } from "./eligibility.js";
|
|
6
|
-
export { executeInSandbox, normalizeCode } from "./executor.js";
|
|
7
|
+
export { SYNTHESIZED_OUTPUT_SCHEMA, getCodeModeDiagnostics, getCodeModeTools, getEligibleTools, isEligibleForCodeMode, toCodeModeTool, } from "./eligibility.js";
|
|
8
|
+
export { SANDBOX_UNAVAILABLE_ERROR, executeInSandbox, normalizeCode } from "./executor.js";
|
|
9
|
+
export { loadIsolatedVm, peekIsolatedVm, resetIsolatedVmCacheForTests, setIsolatedVmForTests, } from "./isolated-vm.js";
|
|
7
10
|
export { createCodeExecuteTool, createCodeSearchTool } from "./tools.js";
|
|
8
11
|
export { generateTypeHints, jsonSchemaToTypeString, sanitizeToolName } from "./type-hints.js";
|
|
12
|
+
const NO_ELIGIBLE_TOOLS_ERROR = {
|
|
13
|
+
error: "no_eligible_tools",
|
|
14
|
+
message: "code_search has no callable read-only MCP tools to search.",
|
|
15
|
+
alternatives: ["code_execute", "tool-cli"],
|
|
16
|
+
};
|
|
17
|
+
const SANDBOX_UNPROBED = {
|
|
18
|
+
state: "unknown",
|
|
19
|
+
reason: "the isolated-vm native addon has not been probed yet",
|
|
20
|
+
};
|
|
21
|
+
const SANDBOX_INJECTED = {
|
|
22
|
+
state: "available",
|
|
23
|
+
reason: "a sandbox executor was supplied directly, bypassing the isolated-vm addon",
|
|
24
|
+
};
|
|
25
|
+
const SANDBOX_NATIVE = {
|
|
26
|
+
state: "available",
|
|
27
|
+
reason: "the isolated-vm native addon loaded",
|
|
28
|
+
};
|
|
9
29
|
/**
|
|
10
|
-
* Orchestrates code mode:
|
|
30
|
+
* Orchestrates code mode: catalogs tools, generates type hints,
|
|
11
31
|
* and executes model-generated code in a sandbox with tool dispatch.
|
|
12
32
|
*/
|
|
13
33
|
export class CodeModeManager {
|
|
14
34
|
mcpManager = null;
|
|
15
|
-
|
|
16
|
-
|
|
35
|
+
policy = null;
|
|
36
|
+
codeModeTools = [];
|
|
37
|
+
diagnostics = getCodeModeDiagnostics([]);
|
|
38
|
+
typeHints = generateTypeHints([]);
|
|
17
39
|
options;
|
|
40
|
+
sandboxExecutor;
|
|
41
|
+
log;
|
|
42
|
+
lastDiagnosticSummary = "";
|
|
43
|
+
sandbox;
|
|
44
|
+
sandboxProbe;
|
|
18
45
|
constructor(options = {}) {
|
|
19
46
|
this.options = options;
|
|
47
|
+
this.sandboxExecutor = options.sandboxExecutor ?? executeInSandbox;
|
|
48
|
+
this.log = options.log;
|
|
49
|
+
// An injected executor is the sandbox. Probing the native addon in that
|
|
50
|
+
// case would report on a backend this manager will never call.
|
|
51
|
+
this.sandbox = options.sandboxExecutor ? SANDBOX_INJECTED : SANDBOX_UNPROBED;
|
|
20
52
|
}
|
|
21
|
-
/**
|
|
22
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Whether code mode should be advertised to the model.
|
|
55
|
+
*
|
|
56
|
+
* Only a *proven* unavailable sandbox switches this off. An unprobed backend
|
|
57
|
+
* stays active because `code_execute` is registered synchronously at load and
|
|
58
|
+
* returns a structured `sandbox_unavailable` error if it turns out it cannot
|
|
59
|
+
* run — a truthful refusal at call time beats hiding a facility that works.
|
|
60
|
+
*/
|
|
61
|
+
get isActive() {
|
|
62
|
+
return this.sandbox.state !== "unavailable";
|
|
63
|
+
}
|
|
64
|
+
/** Current sandbox backend availability, without triggering a probe. */
|
|
65
|
+
getSandboxAvailability() {
|
|
66
|
+
return this.sandbox;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Load the optional native addon once and cache the verdict.
|
|
70
|
+
*
|
|
71
|
+
* Safe to call from any lifecycle hook; concurrent callers share one probe.
|
|
72
|
+
*/
|
|
73
|
+
async probeSandbox() {
|
|
74
|
+
if (this.sandbox.state !== "unknown")
|
|
75
|
+
return this.sandbox;
|
|
76
|
+
this.sandboxProbe ??= loadIsolatedVm().then((load) => {
|
|
77
|
+
this.sandbox = load.available
|
|
78
|
+
? SANDBOX_NATIVE
|
|
79
|
+
: { state: "unavailable", reason: load.reason };
|
|
80
|
+
if (!load.available) {
|
|
81
|
+
this.log?.(`[code-mode] disabled: ${load.reason}. Skills, tool-cli, and routing are unaffected.`);
|
|
82
|
+
}
|
|
83
|
+
return this.sandbox;
|
|
84
|
+
});
|
|
85
|
+
return this.sandboxProbe;
|
|
86
|
+
}
|
|
87
|
+
/** Initialize with MCP manager and policy, catalog tools, and generate type hints. */
|
|
88
|
+
initialize(mcpManager, policy, log) {
|
|
23
89
|
this.mcpManager = mcpManager;
|
|
90
|
+
this.policy = policy;
|
|
91
|
+
this.log = log ?? this.log;
|
|
24
92
|
this.refresh();
|
|
25
93
|
}
|
|
26
|
-
/** Refresh
|
|
94
|
+
/** Refresh the complete tool catalog and type hints (call on tools/list_changed). */
|
|
27
95
|
refresh() {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this.
|
|
31
|
-
|
|
32
|
-
|
|
96
|
+
this.codeModeTools = this.mcpManager ? getCodeModeTools(this.mcpManager) : [];
|
|
97
|
+
this.diagnostics = getCodeModeDiagnostics(this.codeModeTools);
|
|
98
|
+
this.typeHints = generateTypeHints(this.codeModeTools);
|
|
99
|
+
const summary = `[code-mode] ${this.diagnostics.totalTools} tool(s): ` +
|
|
100
|
+
`${this.diagnostics.callableTools} callable, ${this.diagnostics.refusedTools} dispatch-refused; ` +
|
|
101
|
+
`output schemas: ${this.diagnostics.declaredOutputSchemas} declared, ` +
|
|
102
|
+
`${this.diagnostics.synthesizedOutputSchemas} synthesized, ` +
|
|
103
|
+
`${this.diagnostics.unavailableOutputSchemas} unavailable; ` +
|
|
104
|
+
`${this.typeHints.length} chars of type hints`;
|
|
105
|
+
if (summary !== this.lastDiagnosticSummary) {
|
|
106
|
+
this.log?.(summary);
|
|
107
|
+
this.lastDiagnosticSummary = summary;
|
|
108
|
+
}
|
|
33
109
|
}
|
|
34
110
|
/** Get the type hints string for injection into system prompt. */
|
|
35
111
|
getTypeHints() {
|
|
@@ -37,18 +113,34 @@ export class CodeModeManager {
|
|
|
37
113
|
}
|
|
38
114
|
/** Get eligible tools. */
|
|
39
115
|
getEligibleTools() {
|
|
40
|
-
return this.
|
|
116
|
+
return this.codeModeTools.filter((entry) => entry.callable).map((entry) => entry.tool);
|
|
41
117
|
}
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
-
return this.
|
|
118
|
+
/** Get the complete client-internal catalog, including permission and schema provenance. */
|
|
119
|
+
getCatalogTools() {
|
|
120
|
+
return this.codeModeTools;
|
|
121
|
+
}
|
|
122
|
+
getDiagnostics() {
|
|
123
|
+
return this.diagnostics;
|
|
45
124
|
}
|
|
46
125
|
/** Execute code in search mode (tool catalog queries). */
|
|
47
126
|
async searchTools(code) {
|
|
127
|
+
this.refresh();
|
|
128
|
+
if (this.diagnostics.callableTools === 0) {
|
|
129
|
+
return {
|
|
130
|
+
result: undefined,
|
|
131
|
+
error: NO_ELIGIBLE_TOOLS_ERROR.message,
|
|
132
|
+
errorDetails: {
|
|
133
|
+
...NO_ELIGIBLE_TOOLS_ERROR,
|
|
134
|
+
alternatives: [...(NO_ELIGIBLE_TOOLS_ERROR.alternatives ?? [])],
|
|
135
|
+
},
|
|
136
|
+
logs: [],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
48
139
|
return this.execute(code);
|
|
49
140
|
}
|
|
50
141
|
/** Execute code that chains MCP tool calls. */
|
|
51
142
|
async executeCode(code) {
|
|
143
|
+
this.refresh();
|
|
52
144
|
return this.execute(code);
|
|
53
145
|
}
|
|
54
146
|
/** Create the Pi tool definitions for code_search and code_execute. */
|
|
@@ -60,14 +152,15 @@ export class CodeModeManager {
|
|
|
60
152
|
}
|
|
61
153
|
/** Format a system prompt section for code mode. */
|
|
62
154
|
formatSystemPromptSection() {
|
|
63
|
-
if (!this.isActive)
|
|
64
|
-
return "";
|
|
65
155
|
return [
|
|
66
156
|
"",
|
|
67
157
|
"<code_mode>",
|
|
68
158
|
"## Code mode",
|
|
69
159
|
"",
|
|
70
|
-
"
|
|
160
|
+
"Use when a task needs exact computation or control flow: math, aggregation, looping over",
|
|
161
|
+
"results, data transformation, or chaining several MCP tool calls with logic in between.",
|
|
162
|
+
"",
|
|
163
|
+
"`code_execute` runs vanilla JavaScript in a sandboxed V8 isolate. Concretely, that covers:",
|
|
71
164
|
"",
|
|
72
165
|
"1. **Arbitrary computation** — math, string manipulation, date arithmetic, data transformation,",
|
|
73
166
|
" or any calculation the user asks for. No MCP tools needed; plain JS works.",
|
|
@@ -75,21 +168,10 @@ export class CodeModeManager {
|
|
|
75
168
|
" many tool calls. Write a loop inside one `code_execute` instead of making many separate tool calls.",
|
|
76
169
|
"3. **Pagination** — fetch batches in a loop until exhausted, then compute over the full dataset.",
|
|
77
170
|
"",
|
|
78
|
-
"Use `code_search` first to discover
|
|
79
|
-
"",
|
|
80
|
-
"**Code mode tools are always available — you do not need to call `load_skill` first.**",
|
|
171
|
+
"Use `code_search` first to discover which MCP tools are reachable from inside the sandbox.",
|
|
81
172
|
"",
|
|
82
|
-
"
|
|
173
|
+
"`code_search` and `code_execute` are always registered and never gated.",
|
|
83
174
|
"",
|
|
84
|
-
"- **Skill** (`load_skill`) — a curated workflow exists for this domain task (e.g., a GitHub skill for PR management).",
|
|
85
|
-
"- **tool-cli** — you need to discover what tools exist, or make a quick ad-hoc tool call.",
|
|
86
|
-
"- **Code mode** (`code_execute`) — you need computation: math, aggregation, looping over results,",
|
|
87
|
-
" data transformation, or chaining multiple tool calls with logic in between.",
|
|
88
|
-
"",
|
|
89
|
-
"Pick based on what the task needs, not a fixed order. A calculation goes straight to code mode;",
|
|
90
|
-
"a single lookup goes to a skill or tool-cli; exploration starts with tool-cli or `code_search`.",
|
|
91
|
-
"",
|
|
92
|
-
"**If unsure what's available**, start with `code_search` or `tool-cli --help` to see what you have.",
|
|
93
175
|
"After producing a result, verify it makes sense — run a quick sanity check or spot-check values.",
|
|
94
176
|
"",
|
|
95
177
|
"### How to write code",
|
|
@@ -131,45 +213,55 @@ export class CodeModeManager {
|
|
|
131
213
|
].join("\n");
|
|
132
214
|
}
|
|
133
215
|
async execute(code) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
// Refresh eligible tools in case MCP servers changed since initialization
|
|
138
|
-
this.refresh();
|
|
139
|
-
const toolNames = this.eligibleTools.map((t) => t.name);
|
|
216
|
+
const policy = this.policy;
|
|
217
|
+
const toolNames = this.codeModeTools.map((entry) => entry.tool.name);
|
|
140
218
|
const dispatch = async (toolName, args) => {
|
|
141
|
-
const
|
|
142
|
-
if (!
|
|
219
|
+
const codeModeTool = this.codeModeTools.find((entry) => entry.tool.name === toolName);
|
|
220
|
+
if (!codeModeTool) {
|
|
143
221
|
throw new Error(`Tool "${toolName}" not found in code mode eligible tools`);
|
|
144
222
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
throw new Error(`MCP server "${tool.serverName}" is not connected`);
|
|
223
|
+
if (!policy) {
|
|
224
|
+
throw new Error("Code mode MCP policy is not initialized");
|
|
148
225
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
226
|
+
try {
|
|
227
|
+
const terminal = await policy.callTool({
|
|
228
|
+
source: "code-mode",
|
|
229
|
+
serverName: codeModeTool.tool.serverName,
|
|
230
|
+
toolName: codeModeTool.tool.name,
|
|
231
|
+
args,
|
|
232
|
+
});
|
|
233
|
+
return terminal.result;
|
|
153
234
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const textParts = result.content
|
|
157
|
-
.filter((c) => typeof c === "object" && c !== null && "text" in c)
|
|
158
|
-
.map((c) => c.text);
|
|
159
|
-
const combined = textParts.join("\n");
|
|
160
|
-
try {
|
|
161
|
-
return JSON.parse(combined);
|
|
162
|
-
}
|
|
163
|
-
catch {
|
|
164
|
-
return combined;
|
|
165
|
-
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
throw toCodeModeDispatchError(error, codeModeTool);
|
|
166
237
|
}
|
|
167
|
-
return result;
|
|
168
238
|
};
|
|
169
|
-
return
|
|
239
|
+
return this.sandboxExecutor(code, toolNames, dispatch, {
|
|
170
240
|
memoryLimit: this.options.memoryLimit,
|
|
171
241
|
timeoutMs: this.options.timeoutMs,
|
|
172
242
|
});
|
|
173
243
|
}
|
|
174
244
|
}
|
|
175
|
-
|
|
245
|
+
/**
|
|
246
|
+
* Translate a policy denial into Code Mode's structured dispatch error, keeping
|
|
247
|
+
* the catalog's refusal detail so the model learns why a tool was refused.
|
|
248
|
+
*/
|
|
249
|
+
function toCodeModeDispatchError(error, codeModeTool) {
|
|
250
|
+
if (!(error instanceof McpPolicyError))
|
|
251
|
+
return error;
|
|
252
|
+
const isPermission = error.reason === "permission_denied";
|
|
253
|
+
return new CodeModeDispatchError({
|
|
254
|
+
error: isPermission ? "permission_denied" : error.reason,
|
|
255
|
+
message: error.message,
|
|
256
|
+
alternatives: [...error.alternatives],
|
|
257
|
+
toolName: codeModeTool.tool.name,
|
|
258
|
+
...(isPermission ? { reason: formatRefusalReasons(codeModeTool) } : {}),
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function formatRefusalReasons(codeModeTool) {
|
|
262
|
+
return codeModeTool.refusalReasons
|
|
263
|
+
.map((reason) => reason === "destructive_hint"
|
|
264
|
+
? "annotations.destructiveHint is true"
|
|
265
|
+
: "annotations.readOnlyHint is not true")
|
|
266
|
+
.join("; ");
|
|
267
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy adapter for the optional `isolated-vm` native addon.
|
|
3
|
+
*
|
|
4
|
+
* Code Mode is the only feature that needs a real V8 isolate. `isolated-vm` is a
|
|
5
|
+
* native addon, so it can legitimately be absent: an unsupported platform, a
|
|
6
|
+
* missing prebuild with no toolchain to compile one, or a deliberate
|
|
7
|
+
* `--omit=optional` install. When that happens Code Mode must report itself
|
|
8
|
+
* unavailable and the rest of the extension — skills, tool-cli, routing — must
|
|
9
|
+
* keep working.
|
|
10
|
+
*
|
|
11
|
+
* Two rules govern this module:
|
|
12
|
+
*
|
|
13
|
+
* 1. **No top-level import.** The specifier is resolved through a dynamic
|
|
14
|
+
* `import()` behind a variable so neither Node nor TypeScript binds to the
|
|
15
|
+
* addon at module-evaluation time. Loading the extension never throws
|
|
16
|
+
* because a native addon is missing.
|
|
17
|
+
* 2. **Never fall back to Node's `vm`.** `node:vm` shares the host heap and
|
|
18
|
+
* realm; it is a code-organisation tool, not a security boundary. Silently
|
|
19
|
+
* downgrading to it would turn "sandboxed execution" into a false claim.
|
|
20
|
+
* If the addon is absent, Code Mode is unavailable — full stop.
|
|
21
|
+
*/
|
|
22
|
+
/** The subset of the `isolated-vm` surface Code Mode actually uses. */
|
|
23
|
+
export interface IsolatedVmContext {
|
|
24
|
+
readonly global: {
|
|
25
|
+
set(name: string, value: unknown): Promise<void>;
|
|
26
|
+
};
|
|
27
|
+
eval(code: string, options: {
|
|
28
|
+
promise: true;
|
|
29
|
+
copy: true;
|
|
30
|
+
timeout: number;
|
|
31
|
+
}): Promise<unknown>;
|
|
32
|
+
}
|
|
33
|
+
export interface IsolatedVmIsolate {
|
|
34
|
+
createContext(): Promise<IsolatedVmContext>;
|
|
35
|
+
dispose(): void;
|
|
36
|
+
}
|
|
37
|
+
export interface IsolatedVmModule {
|
|
38
|
+
Isolate: new (options: {
|
|
39
|
+
memoryLimit: number;
|
|
40
|
+
}) => IsolatedVmIsolate;
|
|
41
|
+
Callback: new (fn: (...args: never[]) => unknown) => unknown;
|
|
42
|
+
Reference: new (fn: (...args: never[]) => unknown) => unknown;
|
|
43
|
+
}
|
|
44
|
+
/** Outcome of attempting to load the native addon. */
|
|
45
|
+
export type IsolatedVmLoad = {
|
|
46
|
+
readonly available: true;
|
|
47
|
+
readonly module: IsolatedVmModule;
|
|
48
|
+
} | {
|
|
49
|
+
readonly available: false;
|
|
50
|
+
readonly reason: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Load the native addon at most once per process.
|
|
54
|
+
*
|
|
55
|
+
* The result — success *or* failure — is cached. A failed load is not retried:
|
|
56
|
+
* a missing or broken native addon does not become present later in the same
|
|
57
|
+
* process, and retrying would repeat the cost on every Code Mode call.
|
|
58
|
+
*/
|
|
59
|
+
export declare function loadIsolatedVm(): Promise<IsolatedVmLoad>;
|
|
60
|
+
/** Synchronously report a previously resolved load, if one has happened. */
|
|
61
|
+
export declare function peekIsolatedVm(): IsolatedVmLoad | undefined;
|
|
62
|
+
/** Reset the memoised state. Test-only. */
|
|
63
|
+
export declare function resetIsolatedVmCacheForTests(): void;
|
|
64
|
+
/** Seed the memoised state. Test-only — lets tests simulate an absent addon. */
|
|
65
|
+
export declare function setIsolatedVmForTests(load: IsolatedVmLoad): void;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lazy adapter for the optional `isolated-vm` native addon.
|
|
3
|
+
*
|
|
4
|
+
* Code Mode is the only feature that needs a real V8 isolate. `isolated-vm` is a
|
|
5
|
+
* native addon, so it can legitimately be absent: an unsupported platform, a
|
|
6
|
+
* missing prebuild with no toolchain to compile one, or a deliberate
|
|
7
|
+
* `--omit=optional` install. When that happens Code Mode must report itself
|
|
8
|
+
* unavailable and the rest of the extension — skills, tool-cli, routing — must
|
|
9
|
+
* keep working.
|
|
10
|
+
*
|
|
11
|
+
* Two rules govern this module:
|
|
12
|
+
*
|
|
13
|
+
* 1. **No top-level import.** The specifier is resolved through a dynamic
|
|
14
|
+
* `import()` behind a variable so neither Node nor TypeScript binds to the
|
|
15
|
+
* addon at module-evaluation time. Loading the extension never throws
|
|
16
|
+
* because a native addon is missing.
|
|
17
|
+
* 2. **Never fall back to Node's `vm`.** `node:vm` shares the host heap and
|
|
18
|
+
* realm; it is a code-organisation tool, not a security boundary. Silently
|
|
19
|
+
* downgrading to it would turn "sandboxed execution" into a false claim.
|
|
20
|
+
* If the addon is absent, Code Mode is unavailable — full stop.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Resolved through a variable rather than a string literal so that TypeScript
|
|
24
|
+
* does not require `isolated-vm` types to be present to build, and so no
|
|
25
|
+
* bundler or loader statically links the addon into the module graph.
|
|
26
|
+
*/
|
|
27
|
+
const ISOLATED_VM_SPECIFIER = "isolated-vm";
|
|
28
|
+
const MISSING_MODULE_CODES = new Set([
|
|
29
|
+
"ERR_MODULE_NOT_FOUND",
|
|
30
|
+
"MODULE_NOT_FOUND",
|
|
31
|
+
"ERR_DLOPEN_FAILED",
|
|
32
|
+
]);
|
|
33
|
+
let cached;
|
|
34
|
+
let inFlight;
|
|
35
|
+
/**
|
|
36
|
+
* Load the native addon at most once per process.
|
|
37
|
+
*
|
|
38
|
+
* The result — success *or* failure — is cached. A failed load is not retried:
|
|
39
|
+
* a missing or broken native addon does not become present later in the same
|
|
40
|
+
* process, and retrying would repeat the cost on every Code Mode call.
|
|
41
|
+
*/
|
|
42
|
+
export async function loadIsolatedVm() {
|
|
43
|
+
if (cached)
|
|
44
|
+
return cached;
|
|
45
|
+
inFlight ??= attemptLoad().then((result) => {
|
|
46
|
+
cached = result;
|
|
47
|
+
inFlight = undefined;
|
|
48
|
+
return result;
|
|
49
|
+
});
|
|
50
|
+
return inFlight;
|
|
51
|
+
}
|
|
52
|
+
/** Synchronously report a previously resolved load, if one has happened. */
|
|
53
|
+
export function peekIsolatedVm() {
|
|
54
|
+
return cached;
|
|
55
|
+
}
|
|
56
|
+
/** Reset the memoised state. Test-only. */
|
|
57
|
+
export function resetIsolatedVmCacheForTests() {
|
|
58
|
+
cached = undefined;
|
|
59
|
+
inFlight = undefined;
|
|
60
|
+
}
|
|
61
|
+
/** Seed the memoised state. Test-only — lets tests simulate an absent addon. */
|
|
62
|
+
export function setIsolatedVmForTests(load) {
|
|
63
|
+
cached = load;
|
|
64
|
+
inFlight = undefined;
|
|
65
|
+
}
|
|
66
|
+
async function attemptLoad() {
|
|
67
|
+
try {
|
|
68
|
+
const imported = await import(ISOLATED_VM_SPECIFIER);
|
|
69
|
+
const candidate = unwrapDefault(imported);
|
|
70
|
+
if (!isIsolatedVmModule(candidate)) {
|
|
71
|
+
return {
|
|
72
|
+
available: false,
|
|
73
|
+
reason: "the optional isolated-vm addon loaded but did not expose the expected Isolate/Callback/Reference API",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return { available: true, module: candidate };
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return { available: false, reason: describeLoadFailure(error) };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function unwrapDefault(imported) {
|
|
83
|
+
if (typeof imported !== "object" || imported === null)
|
|
84
|
+
return imported;
|
|
85
|
+
const namespace = imported;
|
|
86
|
+
return namespace.default ?? imported;
|
|
87
|
+
}
|
|
88
|
+
function isIsolatedVmModule(value) {
|
|
89
|
+
if (typeof value !== "object" || value === null)
|
|
90
|
+
return false;
|
|
91
|
+
const candidate = value;
|
|
92
|
+
return (typeof candidate.Isolate === "function" &&
|
|
93
|
+
typeof candidate.Callback === "function" &&
|
|
94
|
+
typeof candidate.Reference === "function");
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Turn a load failure into a reason a human can act on.
|
|
98
|
+
*
|
|
99
|
+
* The two failure shapes are meaningfully different: "not installed" is fixed
|
|
100
|
+
* by installing it, while "installed but failed to load" points at an ABI or
|
|
101
|
+
* platform mismatch and needs a rebuild.
|
|
102
|
+
*/
|
|
103
|
+
function describeLoadFailure(error) {
|
|
104
|
+
const code = getErrorCode(error);
|
|
105
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
106
|
+
if (code && MISSING_MODULE_CODES.has(code)) {
|
|
107
|
+
return `the optional isolated-vm native addon is not installed or failed to load (${code}: ${detail})`;
|
|
108
|
+
}
|
|
109
|
+
return `the optional isolated-vm native addon could not be loaded (${detail})`;
|
|
110
|
+
}
|
|
111
|
+
function getErrorCode(error) {
|
|
112
|
+
if (typeof error !== "object" || error === null)
|
|
113
|
+
return undefined;
|
|
114
|
+
const code = error.code;
|
|
115
|
+
return typeof code === "string" ? code : undefined;
|
|
116
|
+
}
|
|
@@ -9,6 +9,10 @@ export interface CodeModeToolDetails {
|
|
|
9
9
|
executionMs: number;
|
|
10
10
|
logs: string[];
|
|
11
11
|
error?: string;
|
|
12
|
+
message?: string;
|
|
13
|
+
alternatives?: string[];
|
|
14
|
+
toolName?: string;
|
|
15
|
+
reason?: string;
|
|
12
16
|
}
|
|
13
17
|
/**
|
|
14
18
|
* Create the `code_search` tool for querying the tool catalog.
|
|
@@ -42,4 +46,3 @@ export declare function createCodeExecuteTool(manager: CodeModeManager): {
|
|
|
42
46
|
execute(_toolCallId: string, params: CodeInputType, _signal: AbortSignal | undefined, _onUpdate: undefined, _ctx: ExtensionContext): Promise<AgentToolResult<CodeModeToolDetails>>;
|
|
43
47
|
};
|
|
44
48
|
export {};
|
|
45
|
-
//# sourceMappingURL=tools.d.ts.map
|
package/dist/code-mode/tools.js
CHANGED
|
@@ -7,13 +7,17 @@ const CodeInput = Type.Object({
|
|
|
7
7
|
/** Format an ExecuteResult into a tool response. Falls back to logs if result is undefined. */
|
|
8
8
|
function formatResult(result, executionMs, errorPrefix) {
|
|
9
9
|
if (result.error) {
|
|
10
|
+
const errorDetails = result.errorDetails ?? {
|
|
11
|
+
error: "execution_failed",
|
|
12
|
+
message: result.error,
|
|
13
|
+
};
|
|
10
14
|
return {
|
|
11
15
|
content: [{ type: "text", text: `${errorPrefix}: ${result.error}` }],
|
|
12
|
-
details: { executionMs, logs: result.logs,
|
|
16
|
+
details: { executionMs, logs: result.logs, ...errorDetails },
|
|
13
17
|
};
|
|
14
18
|
}
|
|
15
19
|
// If code didn't return a value, fall back to captured console output
|
|
16
|
-
const output = result.result !== undefined
|
|
20
|
+
const output = result.result !== undefined
|
|
17
21
|
? typeof result.result === "string"
|
|
18
22
|
? result.result
|
|
19
23
|
: JSON.stringify(result.result, null, 2)
|
|
@@ -38,7 +42,7 @@ export function createCodeSearchTool(manager) {
|
|
|
38
42
|
return {
|
|
39
43
|
name: "code_search",
|
|
40
44
|
label: "Code Search",
|
|
41
|
-
description: "Discover available
|
|
45
|
+
description: "Discover all available MCP tools by writing JavaScript. Use `codemode.listTools()` to list tools and `codemode.describeTools(names)` for type info. Type hints identify which tools Code Mode can call; non-read-only tools remain discovery-only.",
|
|
42
46
|
parameters: CodeInput,
|
|
43
47
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
44
48
|
const start = performance.now();
|
|
@@ -67,4 +71,3 @@ export function createCodeExecuteTool(manager) {
|
|
|
67
71
|
},
|
|
68
72
|
};
|
|
69
73
|
}
|
|
70
|
-
//# sourceMappingURL=tools.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { McpTool } from "../mcp/index.js";
|
|
2
|
+
import { type CodeModeTool } from "./eligibility.js";
|
|
2
3
|
type JsonSchema = Record<string, unknown>;
|
|
3
4
|
/**
|
|
4
5
|
* Convert a JSON Schema to a TypeScript type string.
|
|
@@ -15,6 +16,5 @@ export declare function sanitizeToolName(name: string): string;
|
|
|
15
16
|
* Produces a `declare const codemode: { ... }` block with type-safe
|
|
16
17
|
* method signatures the model can use when writing code.
|
|
17
18
|
*/
|
|
18
|
-
export declare function generateTypeHints(tools: McpTool[]): string;
|
|
19
|
+
export declare function generateTypeHints(tools: readonly (McpTool | CodeModeTool)[]): string;
|
|
19
20
|
export {};
|
|
20
|
-
//# sourceMappingURL=type-hints.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getCodeModeDiagnostics, toCodeModeTool } from "./eligibility.js";
|
|
1
2
|
/**
|
|
2
3
|
* Convert a JSON Schema to a TypeScript type string.
|
|
3
4
|
*
|
|
@@ -124,13 +125,14 @@ export function sanitizeToolName(name) {
|
|
|
124
125
|
* method signatures the model can use when writing code.
|
|
125
126
|
*/
|
|
126
127
|
export function generateTypeHints(tools) {
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
const codeModeTools = tools.map(normalizeCodeModeTool);
|
|
129
|
+
const diagnostics = getCodeModeDiagnostics(codeModeTools);
|
|
129
130
|
const methods = [];
|
|
130
|
-
for (const
|
|
131
|
+
for (const codeModeTool of codeModeTools) {
|
|
132
|
+
const tool = codeModeTool.tool;
|
|
131
133
|
const safeName = sanitizeToolName(tool.name);
|
|
132
134
|
const inputSchema = tool.inputSchema;
|
|
133
|
-
const outputSchema =
|
|
135
|
+
const outputSchema = codeModeTool.outputSchema;
|
|
134
136
|
const definitions = (inputSchema.$defs ??
|
|
135
137
|
inputSchema.definitions ??
|
|
136
138
|
outputSchema?.$defs ??
|
|
@@ -140,13 +142,17 @@ export function generateTypeHints(tools) {
|
|
|
140
142
|
// Build output type
|
|
141
143
|
const outputType = outputSchema ? jsonSchemaToTypeString(outputSchema, definitions) : "unknown";
|
|
142
144
|
// Build JSDoc
|
|
143
|
-
const jsdoc = buildJsDoc(
|
|
145
|
+
const jsdoc = buildJsDoc(codeModeTool, inputSchema);
|
|
144
146
|
methods.push(`${jsdoc} ${safeName}: (input: ${inputType}) => Promise<${outputType}>;`);
|
|
145
147
|
}
|
|
146
|
-
const toolListType =
|
|
148
|
+
const toolListType = codeModeTools.length > 0
|
|
149
|
+
? codeModeTools.map((entry) => `"${escapeStr(entry.tool.name)}"`).join(" | ")
|
|
150
|
+
: "never";
|
|
147
151
|
return [
|
|
148
152
|
"// Code mode type hints — auto-generated from MCP tool schemas",
|
|
149
153
|
"// Available tools are accessed via the `codemode` namespace",
|
|
154
|
+
`// MCP catalog: ${diagnostics.totalTools} tool(s); ${diagnostics.callableTools} callable, ${diagnostics.refusedTools} dispatch-refused`,
|
|
155
|
+
`// Output schemas: ${diagnostics.declaredOutputSchemas} declared, ${diagnostics.synthesizedOutputSchemas} synthesized, ${diagnostics.unavailableOutputSchemas} unavailable`,
|
|
150
156
|
"",
|
|
151
157
|
`declare const codemode: {`,
|
|
152
158
|
` /** List all available code mode tool names. */`,
|
|
@@ -166,11 +172,19 @@ function generateInputType(_toolSafeName, inputSchema, definitions) {
|
|
|
166
172
|
const typeStr = jsonSchemaToTypeString(inputSchema, definitions);
|
|
167
173
|
return typeStr;
|
|
168
174
|
}
|
|
169
|
-
function buildJsDoc(
|
|
175
|
+
function buildJsDoc(codeModeTool, inputSchema) {
|
|
176
|
+
const tool = codeModeTool.tool;
|
|
170
177
|
const lines = [" /**"];
|
|
171
178
|
if (tool.description) {
|
|
172
179
|
lines.push(` * ${tool.description}`);
|
|
173
180
|
}
|
|
181
|
+
if (codeModeTool.callable) {
|
|
182
|
+
lines.push(" * Code Mode dispatch: callable (explicitly read-only and non-destructive).");
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
lines.push(" * Code Mode dispatch: refused. Use a permission-aware non-Code-Mode path.");
|
|
186
|
+
}
|
|
187
|
+
lines.push(` * Output schema provenance: ${codeModeTool.outputSchemaProvenance}.`);
|
|
174
188
|
const properties = inputSchema.properties;
|
|
175
189
|
if (properties) {
|
|
176
190
|
for (const [key, propSchema] of Object.entries(properties)) {
|
|
@@ -186,4 +200,6 @@ function buildJsDoc(tool, inputSchema) {
|
|
|
186
200
|
function escapeStr(s) {
|
|
187
201
|
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, " ");
|
|
188
202
|
}
|
|
189
|
-
|
|
203
|
+
function normalizeCodeModeTool(tool) {
|
|
204
|
+
return "tool" in tool && "outputSchemaProvenance" in tool ? tool : toCodeModeTool(tool);
|
|
205
|
+
}
|
package/dist/docker-e2e.d.ts
CHANGED
|
@@ -52,4 +52,3 @@ export declare const dockerE2ETool: {
|
|
|
52
52
|
execute(_toolCallId: string, params: DockerE2EInput, signal: AbortSignal | undefined, onUpdate: AgentToolUpdateCallback<DockerE2EDetails> | undefined, _ctx: ExtensionContext): Promise<AgentToolResult<DockerE2EDetails>>;
|
|
53
53
|
};
|
|
54
54
|
export {};
|
|
55
|
-
//# sourceMappingURL=docker-e2e.d.ts.map
|
package/dist/docker-e2e.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@sammorrowdrums/mcpi";
|
|
2
|
+
import type { BashState } from "./routing/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Report whether the host currently exposes a shell tool to the agent.
|
|
5
|
+
*
|
|
6
|
+
* `getActiveTools` may be missing on an older host or throw if the runner context
|
|
7
|
+
* is not bound, and neither is evidence that bash is absent — so both collapse
|
|
8
|
+
* to `undiscoverable` rather than a false negative.
|
|
9
|
+
*/
|
|
10
|
+
export declare function detectBashState(pi: ExtensionAPI): BashState;
|
|
2
11
|
export default function (pi: ExtensionAPI): void;
|
|
3
|
-
//# sourceMappingURL=index.d.ts.map
|