@humain/terminal 0.1.1 → 0.2.2
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/CHANGELOG.md +22 -0
- package/dist/bundle/chunks/{anthropic-messages-XULXUBIG.js → anthropic-messages-QFCEKGI3.js} +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-JEG2XOYC.js → azure-openai-responses-G4ZMHV37.js} +1 -1
- package/dist/bundle/chunks/chunk-7T6XCLJF.js +22 -0
- package/dist/bundle/chunks/{chunk-LYAMSPR2.js → chunk-ADQYVZ6A.js} +483 -506
- package/dist/bundle/chunks/chunk-D6HHRSB5.js +103 -0
- package/dist/bundle/chunks/{chunk-JUPSJTFQ.js → chunk-K4JAZYQH.js} +1 -1
- package/dist/bundle/chunks/{chunk-HPPQHK3J.js → chunk-KKIB2TVR.js} +1 -1
- package/dist/bundle/chunks/chunk-LI2YVPWP.js +2 -0
- package/dist/bundle/chunks/chunk-NMPIM7MN.js +2 -0
- package/dist/bundle/chunks/{chunk-BZQ53VGE.js → chunk-XSR434CO.js} +1 -1
- package/dist/bundle/chunks/compat-CN7WN6DA.js +2 -0
- package/dist/bundle/chunks/dist-PRPIUY3U.js +2 -0
- package/dist/bundle/chunks/esm-E7UVEYTO.js +4 -0
- package/dist/bundle/chunks/{extract-TRW5FBY6.js → extract-CTIFQZDJ.js} +15 -14
- package/dist/bundle/chunks/{google-generative-ai-OX6VSCA6.js → google-generative-ai-RSUU4MWO.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-GW76GSS2.js → google-vertex-CKQPOITO.js} +1 -1
- package/dist/bundle/chunks/host-WP3MVKS2.js +2 -0
- package/dist/bundle/chunks/{node-KOIP55YZ.js → node-NF43OPII.js} +1 -1
- package/dist/bundle/chunks/{node-XY3CBY3C.js → node-UMFM7CDZ.js} +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-NPLWP6ZC.js → openai-codex-responses-S34V5ZSD.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-OT2GTJKC.js → openai-completions-T2IGVUEI.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-5A6CR7GI.js → openai-responses-GYZODCT3.js} +1 -1
- package/dist/bundle/chunks/readability-LAGF34IB.js +3 -0
- package/dist/bundle/chunks/turndown.cjs-HRMZVRUL.js +2 -0
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/model-runtime.d.ts +21 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +34 -4
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +21 -8
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/subagent-env.d.ts +20 -0
- package/dist/core/tools/subagent-env.d.ts.map +1 -0
- package/dist/core/tools/subagent-env.js +47 -0
- package/dist/core/tools/subagent-env.js.map +1 -0
- package/dist/core/tools/subagent-scheduler.d.ts +36 -0
- package/dist/core/tools/subagent-scheduler.d.ts.map +1 -0
- package/dist/core/tools/subagent-scheduler.js +213 -0
- package/dist/core/tools/subagent-scheduler.js.map +1 -0
- package/dist/core/tools/subagent.d.ts +83 -3
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +215 -76
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +78 -0
- package/dist/humain/mcp-adapter/vendor/README.md +125 -19
- package/dist/humain/mcp-adapter/vendor/agent-plugin-loader.ts +69 -30
- package/dist/humain/mcp-adapter/vendor/agent-plugin-provenance.ts +36 -0
- package/dist/humain/mcp-adapter/vendor/claude-plugin-loader.ts +365 -0
- package/dist/humain/mcp-adapter/vendor/commands.ts +13 -15
- package/dist/humain/mcp-adapter/vendor/config.ts +198 -30
- package/dist/humain/mcp-adapter/vendor/consent-manager.ts +40 -9
- package/dist/humain/mcp-adapter/vendor/direct-tool-surface.ts +250 -0
- package/dist/humain/mcp-adapter/vendor/direct-tools.ts +9 -228
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.js +74 -32
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.d.ts +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.js +31 -0
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.d.ts +9 -0
- package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.js +362 -0
- package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/config.d.ts +3 -1
- package/dist/humain/mcp-adapter/vendor/dist/config.js +189 -27
- package/dist/humain/mcp-adapter/vendor/dist/config.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.js +7 -16
- package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.js +5 -17
- package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/types.d.ts +30 -4
- package/dist/humain/mcp-adapter/vendor/dist/types.js +26 -0
- package/dist/humain/mcp-adapter/vendor/dist/types.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/utils.d.ts +6 -0
- package/dist/humain/mcp-adapter/vendor/dist/utils.js +65 -6
- package/dist/humain/mcp-adapter/vendor/dist/utils.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/host-html-template.ts +20 -19
- package/dist/humain/mcp-adapter/vendor/http-ca.ts +84 -0
- package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +37102 -15103
- package/dist/humain/mcp-adapter/vendor/index.ts +828 -164
- package/dist/humain/mcp-adapter/vendor/init.ts +48 -10
- package/dist/humain/mcp-adapter/vendor/lazy-loader.ts +7 -0
- package/dist/humain/mcp-adapter/vendor/mcp-auth-fetch.ts +113 -0
- package/dist/humain/mcp-adapter/vendor/mcp-auth-flow.ts +256 -77
- package/dist/humain/mcp-adapter/vendor/mcp-auth.ts +316 -54
- package/dist/humain/mcp-adapter/vendor/mcp-code.ts +45 -18
- package/dist/humain/mcp-adapter/vendor/mcp-install.ts +60 -0
- package/dist/humain/mcp-adapter/vendor/mcp-oauth-provider.ts +70 -6
- package/dist/humain/mcp-adapter/vendor/mcp-output-guard.ts +53 -42
- package/dist/humain/mcp-adapter/vendor/mcp-panel-theme.ts +105 -0
- package/dist/humain/mcp-adapter/vendor/mcp-panel.ts +366 -331
- package/dist/humain/mcp-adapter/vendor/mcp-references.ts +9 -14
- package/dist/humain/mcp-adapter/vendor/mcp-script-worker.mjs +3 -1
- package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +383 -341
- package/dist/humain/mcp-adapter/vendor/mcp-status.ts +5 -0
- package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +7 -16
- package/dist/humain/mcp-adapter/vendor/namespace-tools.ts +61 -3
- package/dist/humain/mcp-adapter/vendor/oauth.ts +6 -2
- package/dist/humain/mcp-adapter/vendor/package-mcp-loader.ts +5 -17
- package/dist/humain/mcp-adapter/vendor/package.json +13 -3
- package/dist/humain/mcp-adapter/vendor/prompts.ts +35 -3
- package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +108 -7
- package/dist/humain/mcp-adapter/vendor/runtime-owner.ts +16 -1
- package/dist/humain/mcp-adapter/vendor/sampling-handler.ts +9 -32
- package/dist/humain/mcp-adapter/vendor/sandbox-proxy-template.ts +20 -93
- package/dist/humain/mcp-adapter/vendor/server-manager.ts +227 -40
- package/dist/humain/mcp-adapter/vendor/session-approvals.ts +187 -0
- package/dist/humain/mcp-adapter/vendor/skills/mcp-scripting/SKILL.md +9 -1
- package/dist/humain/mcp-adapter/vendor/state.ts +10 -1
- package/dist/humain/mcp-adapter/vendor/tool-approval.ts +10 -22
- package/dist/humain/mcp-adapter/vendor/tool-metadata.ts +14 -0
- package/dist/humain/mcp-adapter/vendor/types.ts +57 -4
- package/dist/humain/mcp-adapter/vendor/ui-server.ts +36 -28
- package/dist/humain/mcp-adapter/vendor/utils.ts +64 -6
- package/dist/humain/web-access/vendor/abortable.d.ts +3 -0
- package/dist/humain/web-access/vendor/abortable.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/abortable.js +22 -0
- package/dist/humain/web-access/vendor/abortable.js.map +1 -0
- package/dist/humain/web-access/vendor/crawl4ai.d.ts +9 -0
- package/dist/humain/web-access/vendor/crawl4ai.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/crawl4ai.js +187 -0
- package/dist/humain/web-access/vendor/crawl4ai.js.map +1 -0
- package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/credential-source.js +1 -0
- package/dist/humain/web-access/vendor/credential-source.js.map +1 -1
- package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/curator-page.js +20 -2
- package/dist/humain/web-access/vendor/curator-page.js.map +1 -1
- package/dist/humain/web-access/vendor/curator-run.d.ts +11 -0
- package/dist/humain/web-access/vendor/curator-run.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/curator-run.js +38 -0
- package/dist/humain/web-access/vendor/curator-run.js.map +1 -0
- package/dist/humain/web-access/vendor/curator-server.d.ts +1 -0
- package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/curator-server.js +2 -0
- package/dist/humain/web-access/vendor/curator-server.js.map +1 -1
- package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/duckduckgo.js +1 -1
- package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -1
- package/dist/humain/web-access/vendor/extract.d.ts +1 -1
- package/dist/humain/web-access/vendor/extract.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/extract.js +58 -11
- package/dist/humain/web-access/vendor/extract.js.map +1 -1
- package/dist/humain/web-access/vendor/fetch-params.js +1 -1
- package/dist/humain/web-access/vendor/fetch-params.js.map +1 -1
- package/dist/humain/web-access/vendor/gemini-search.d.ts +2 -2
- package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/gemini-search.js +12 -5
- package/dist/humain/web-access/vendor/gemini-search.js.map +1 -1
- package/dist/humain/web-access/vendor/index.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/index.js +23 -19
- package/dist/humain/web-access/vendor/index.js.map +1 -1
- package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/openai-search.js +40 -14
- package/dist/humain/web-access/vendor/openai-search.js.map +1 -1
- package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/page-query.js +6 -2
- package/dist/humain/web-access/vendor/page-query.js.map +1 -1
- package/dist/humain/web-access/vendor/query-rewrite.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/query-rewrite.js +6 -2
- package/dist/humain/web-access/vendor/query-rewrite.js.map +1 -1
- package/dist/humain/web-access/vendor/serpapi.d.ts +4 -0
- package/dist/humain/web-access/vendor/serpapi.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/serpapi.js +215 -0
- package/dist/humain/web-access/vendor/serpapi.js.map +1 -0
- package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/ssrf-protection.js +5 -1
- package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -1
- package/dist/humain/web-access/vendor/storage.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/storage.js +9 -0
- package/dist/humain/web-access/vendor/storage.js.map +1 -1
- package/dist/humain/web-access/vendor/summary-review.d.ts +1 -1
- package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/summary-review.js +35 -24
- package/dist/humain/web-access/vendor/summary-review.js.map +1 -1
- package/dist/humain/web-access/vendor/utils.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/utils.js +5 -3
- package/dist/humain/web-access/vendor/utils.js.map +1 -1
- package/dist/modes/json-event.d.ts +8 -0
- package/dist/modes/json-event.d.ts.map +1 -1
- package/dist/modes/json-event.js +17 -0
- package/dist/modes/json-event.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +3 -2
- package/dist/modes/print-mode.js.map +1 -1
- package/docs/environment-variables.md +9 -0
- package/docs/json.md +16 -0
- package/npm-shrinkwrap.json +6 -6
- package/package.json +2 -2
- package/src/humain/mcp-adapter/UPSTREAM.md +56 -7
- package/src/humain/mcp-adapter/upstream.json +6 -4
- package/src/humain/mcp-adapter/vendor/CHANGELOG.md +78 -0
- package/src/humain/web-access/UPSTREAM.md +18 -8
- package/src/humain/web-access/upstream.json +6 -5
- package/dist/bundle/chunks/chunk-2LC3S3VV.js +0 -105
|
@@ -52,7 +52,22 @@ export function combineAbortSignals(...signals: Array<AbortSignal | undefined>):
|
|
|
52
52
|
const active = signals.filter((signal): signal is AbortSignal => signal !== undefined);
|
|
53
53
|
if (active.length === 0) return undefined;
|
|
54
54
|
if (active.length === 1) return active[0];
|
|
55
|
-
return AbortSignal.any(active);
|
|
55
|
+
if (typeof AbortSignal.any === "function") return AbortSignal.any(active);
|
|
56
|
+
|
|
57
|
+
// AbortSignal.any was added after Node 20.0.0, our minimum supported version.
|
|
58
|
+
const controller = new AbortController();
|
|
59
|
+
const alreadyAborted = active.find(signal => signal.aborted);
|
|
60
|
+
if (alreadyAborted) {
|
|
61
|
+
controller.abort(alreadyAborted.reason);
|
|
62
|
+
return controller.signal;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const onAbort = (event: Event) => {
|
|
66
|
+
for (const signal of active) signal.removeEventListener("abort", onAbort);
|
|
67
|
+
controller.abort((event.target as AbortSignal).reason);
|
|
68
|
+
};
|
|
69
|
+
for (const signal of active) signal.addEventListener("abort", onAbort, { once: true });
|
|
70
|
+
return controller.signal;
|
|
56
71
|
}
|
|
57
72
|
|
|
58
73
|
/** Fence session-bound UI calls after the owning extension runtime stops. */
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Api, AssistantMessage, Message, Model, ProviderHeaders, TextContent } from "@earendil-works/pi-ai";
|
|
1
|
+
import type { Api, AssistantMessage, Message, Model, TextContent } from "@earendil-works/pi-ai";
|
|
3
2
|
import { truncateAtWord } from "./utils.ts";
|
|
4
3
|
import { throwIfAborted } from "./abort.ts";
|
|
5
4
|
import type { ExtensionUIContext, ModelRegistry } from "@earendil-works/pi-coding-agent";
|
|
@@ -13,7 +12,7 @@ import {
|
|
|
13
12
|
} from "@modelcontextprotocol/client";
|
|
14
13
|
|
|
15
14
|
export type SamplingUIContext = Pick<ExtensionUIContext, "confirm">;
|
|
16
|
-
export type SamplingModelRegistry = Pick<ModelRegistry, "getAvailable" | "
|
|
15
|
+
export type SamplingModelRegistry = Pick<ModelRegistry, "getAvailable" | "complete">;
|
|
17
16
|
|
|
18
17
|
export interface SamplingHandlerOptions {
|
|
19
18
|
serverName: string;
|
|
@@ -57,7 +56,7 @@ export async function handleSamplingRequest(
|
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
const messages = params.messages.map(convertSamplingMessage);
|
|
60
|
-
const
|
|
59
|
+
const model = resolveSamplingModel(options, params.modelPreferences);
|
|
61
60
|
throwIfAborted(signal);
|
|
62
61
|
await confirmSampling(
|
|
63
62
|
options,
|
|
@@ -66,15 +65,13 @@ export async function handleSamplingRequest(
|
|
|
66
65
|
);
|
|
67
66
|
throwIfAborted(signal);
|
|
68
67
|
|
|
69
|
-
const result = await complete(
|
|
68
|
+
const result = await options.modelRegistry.complete(
|
|
70
69
|
model,
|
|
71
70
|
{
|
|
72
71
|
...(params.systemPrompt !== undefined ? { systemPrompt: params.systemPrompt } : {}),
|
|
73
72
|
messages,
|
|
74
73
|
},
|
|
75
74
|
{
|
|
76
|
-
...(apiKey !== undefined ? { apiKey } : {}),
|
|
77
|
-
...(headers !== undefined ? { headers } : {}),
|
|
78
75
|
maxTokens: params.maxTokens,
|
|
79
76
|
...(params.temperature !== undefined ? { temperature: params.temperature } : {}),
|
|
80
77
|
...(params.metadata !== undefined ? { metadata: params.metadata as Record<string, unknown> } : {}),
|
|
@@ -124,14 +121,10 @@ function messageText(message: Message): string {
|
|
|
124
121
|
}).join("\n");
|
|
125
122
|
}
|
|
126
123
|
|
|
127
|
-
|
|
124
|
+
function resolveSamplingModel(
|
|
128
125
|
options: SamplingHandlerOptions,
|
|
129
126
|
modelPreferences: ModelPreferences | undefined,
|
|
130
|
-
):
|
|
131
|
-
model: Model<Api>;
|
|
132
|
-
apiKey?: string;
|
|
133
|
-
headers?: ProviderHeaders;
|
|
134
|
-
}> {
|
|
127
|
+
): Model<Api> {
|
|
135
128
|
const candidates: Model<Api>[] = [];
|
|
136
129
|
const availableModels = options.modelRegistry.getAvailable();
|
|
137
130
|
|
|
@@ -153,26 +146,10 @@ async function resolveSamplingModel(
|
|
|
153
146
|
addSamplingCandidate(candidates, model);
|
|
154
147
|
}
|
|
155
148
|
|
|
156
|
-
const errors: string[] = [];
|
|
157
149
|
const signal = options.getSignal();
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
throwIfAborted(signal);
|
|
162
|
-
if (auth.ok === false) {
|
|
163
|
-
errors.push(`${model.provider}/${model.id}: ${auth.error}`);
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
return {
|
|
167
|
-
model,
|
|
168
|
-
...(auth.apiKey !== undefined ? { apiKey: auth.apiKey } : {}),
|
|
169
|
-
...(auth.headers !== undefined ? { headers: auth.headers } : {}),
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (errors.length > 0) {
|
|
174
|
-
throw new Error(`No configured auth for MCP sampling model. ${errors.join("; ")}`);
|
|
175
|
-
}
|
|
150
|
+
throwIfAborted(signal);
|
|
151
|
+
const model = candidates[0];
|
|
152
|
+
if (model) return model;
|
|
176
153
|
throw new Error("No Pi model is available for MCP sampling");
|
|
177
154
|
}
|
|
178
155
|
|
|
@@ -7,17 +7,22 @@ export const SANDBOX_PROXY_SANDBOX =
|
|
|
7
7
|
"allow-scripts allow-forms allow-modals allow-popups allow-downloads allow-same-origin";
|
|
8
8
|
export const SANDBOX_INNER_SANDBOX = SANDBOX_PROXY_SANDBOX;
|
|
9
9
|
export const SANDBOX_PROXY_PATH = "/sandbox";
|
|
10
|
+
export const SANDBOX_RESOURCE_PATH_PREFIX = "/resource/";
|
|
10
11
|
|
|
11
12
|
export interface SandboxProxyTemplateInput {
|
|
12
13
|
parentOrigin: string;
|
|
14
|
+
resourcePath: string;
|
|
15
|
+
allowAttribute: string;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
19
|
* Build the static document used by the trusted, second-origin sandbox proxy.
|
|
17
|
-
* The
|
|
20
|
+
* The per-session values are the exact parent host origin and opaque resource path.
|
|
18
21
|
*/
|
|
19
22
|
export function buildSandboxProxyHtml(input: SandboxProxyTemplateInput): string {
|
|
20
23
|
const parentOrigin = safeInlineJSON(input.parentOrigin);
|
|
24
|
+
const resourcePath = safeInlineJSON(input.resourcePath);
|
|
25
|
+
const allowAttribute = escapeHtmlAttribute(input.allowAttribute);
|
|
21
26
|
|
|
22
27
|
return `<!doctype html>
|
|
23
28
|
<html lang="en">
|
|
@@ -31,17 +36,21 @@ export function buildSandboxProxyHtml(input: SandboxProxyTemplateInput): string
|
|
|
31
36
|
</style>
|
|
32
37
|
</head>
|
|
33
38
|
<body>
|
|
34
|
-
<iframe id="mcp-app" title="MCP App" sandbox="${SANDBOX_INNER_SANDBOX}" referrerpolicy="no-referrer"></iframe>
|
|
39
|
+
<iframe id="mcp-app" title="MCP App" sandbox="${SANDBOX_INNER_SANDBOX}" allow="${allowAttribute}" referrerpolicy="no-referrer"></iframe>
|
|
35
40
|
<script>
|
|
36
41
|
const EXPECTED_PARENT_ORIGIN = ${parentOrigin};
|
|
42
|
+
const RESOURCE_PATH = ${resourcePath};
|
|
37
43
|
const SANDBOX_PROXY_READY_METHOD = "ui/notifications/sandbox-proxy-ready";
|
|
38
44
|
const SANDBOX_RESOURCE_READY_METHOD = "ui/notifications/sandbox-resource-ready";
|
|
39
|
-
const INNER_SANDBOX = ${safeInlineJSON(SANDBOX_INNER_SANDBOX)};
|
|
40
45
|
const MAX_PENDING_MESSAGES = 64;
|
|
41
46
|
const innerFrame = document.getElementById("mcp-app");
|
|
42
47
|
const pendingToInner = [];
|
|
43
48
|
let innerReady = false;
|
|
44
49
|
|
|
50
|
+
innerFrame.addEventListener("load", () => {
|
|
51
|
+
if (innerFrame.getAttribute("src") === RESOURCE_PATH) flushPendingMessages();
|
|
52
|
+
});
|
|
53
|
+
|
|
45
54
|
const isObject = (value) => value !== null && typeof value === "object";
|
|
46
55
|
const isMessageFromParent = (event) =>
|
|
47
56
|
event.source === window.parent && event.origin === EXPECTED_PARENT_ORIGIN;
|
|
@@ -68,99 +77,13 @@ export function buildSandboxProxyHtml(input: SandboxProxyTemplateInput): string
|
|
|
68
77
|
}
|
|
69
78
|
};
|
|
70
79
|
|
|
71
|
-
const sanitizeDomains = (domains) => {
|
|
72
|
-
if (!Array.isArray(domains)) return [];
|
|
73
|
-
return [...new Set(domains.filter((domain) =>
|
|
74
|
-
typeof domain === "string" &&
|
|
75
|
-
domain.length > 0 &&
|
|
76
|
-
/^[\\x21-\\x7E]+$/.test(domain) &&
|
|
77
|
-
!/[;'\"]/.test(domain),
|
|
78
|
-
))];
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const toDirective = (name, trustedSources, domains) =>
|
|
82
|
-
name + " " + [...new Set([...trustedSources, ...domains])].join(" ");
|
|
83
|
-
|
|
84
|
-
const buildResourceCsp = (csp) => {
|
|
85
|
-
const resourceDomains = sanitizeDomains(csp?.resourceDomains);
|
|
86
|
-
const connectDomains = sanitizeDomains(csp?.connectDomains);
|
|
87
|
-
const frameDomains = sanitizeDomains(csp?.frameDomains);
|
|
88
|
-
const baseUriDomains = sanitizeDomains(csp?.baseUriDomains);
|
|
89
|
-
return [
|
|
90
|
-
"default-src 'none'",
|
|
91
|
-
"sandbox " + INNER_SANDBOX,
|
|
92
|
-
toDirective("script-src", ["'self'", "'unsafe-inline'"], resourceDomains),
|
|
93
|
-
toDirective("style-src", ["'self'", "'unsafe-inline'"], resourceDomains),
|
|
94
|
-
toDirective("font-src", ["'self'"], resourceDomains),
|
|
95
|
-
toDirective("img-src", ["'self'", "data:"], resourceDomains),
|
|
96
|
-
toDirective("media-src", ["'self'", "data:"], resourceDomains),
|
|
97
|
-
connectDomains.length > 0 ? "connect-src " + connectDomains.join(" ") : "connect-src 'none'",
|
|
98
|
-
frameDomains.length > 0 ? "frame-src " + frameDomains.join(" ") : "frame-src 'none'",
|
|
99
|
-
"worker-src 'none'",
|
|
100
|
-
"object-src 'none'",
|
|
101
|
-
baseUriDomains.length > 0 ? "base-uri " + baseUriDomains.join(" ") : "base-uri 'self'",
|
|
102
|
-
].join("; ");
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const escapeAttribute = (value) => value
|
|
106
|
-
.replace(/&/g, "&")
|
|
107
|
-
.replace(/\"/g, """)
|
|
108
|
-
.replace(/</g, "<")
|
|
109
|
-
.replace(/>/g, ">");
|
|
110
|
-
|
|
111
|
-
const injectCsp = (html, csp) => {
|
|
112
|
-
const meta = '<meta http-equiv="Content-Security-Policy" content="' + escapeAttribute(csp) + '">';
|
|
113
|
-
const head = html.match(/<head(?:\\s[^>]*)?>/i);
|
|
114
|
-
if (head && head.index !== undefined) {
|
|
115
|
-
const end = head.index + head[0].length;
|
|
116
|
-
return html.slice(0, end) + meta + html.slice(end);
|
|
117
|
-
}
|
|
118
|
-
return meta + html;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const safeSandbox = (requested) => {
|
|
122
|
-
const requestedTokens = typeof requested === "string" ? requested.split(/\\s+/) : [];
|
|
123
|
-
const allowedTokens = new Set(INNER_SANDBOX.split(" "));
|
|
124
|
-
const tokens = requestedTokens.filter((token) => allowedTokens.has(token));
|
|
125
|
-
// Provider HTML needs both script execution and a real proxy-origin
|
|
126
|
-
// storage context. Never accept popup escape or top-navigation tokens.
|
|
127
|
-
return [...new Set([
|
|
128
|
-
"allow-scripts",
|
|
129
|
-
"allow-same-origin",
|
|
130
|
-
...tokens,
|
|
131
|
-
])].filter((token) => allowedTokens.has(token)).join(" ");
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const buildAllowAttribute = (permissions) => {
|
|
135
|
-
if (!isObject(permissions) || Array.isArray(permissions)) return "";
|
|
136
|
-
const allowed = [];
|
|
137
|
-
if (permissions.camera) allowed.push("camera");
|
|
138
|
-
if (permissions.microphone) allowed.push("microphone");
|
|
139
|
-
if (permissions.geolocation) allowed.push("geolocation");
|
|
140
|
-
if (permissions.clipboardWrite) allowed.push("clipboard-write");
|
|
141
|
-
return allowed.join("; ");
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const loadResource = (params) => {
|
|
145
|
-
if (!isObject(params) || typeof params.html !== "string" || !innerFrame.contentDocument) return;
|
|
146
|
-
innerFrame.setAttribute("sandbox", safeSandbox(params.sandbox));
|
|
147
|
-
const allow = buildAllowAttribute(params.permissions);
|
|
148
|
-
if (allow) innerFrame.setAttribute("allow", allow);
|
|
149
|
-
else innerFrame.removeAttribute("allow");
|
|
150
|
-
innerReady = false;
|
|
151
|
-
const document = innerFrame.contentDocument;
|
|
152
|
-
document.open();
|
|
153
|
-
document.write(injectCsp(params.html, buildResourceCsp(params.csp)));
|
|
154
|
-
document.close();
|
|
155
|
-
flushPendingMessages();
|
|
156
|
-
};
|
|
157
|
-
|
|
158
80
|
window.addEventListener("message", (event) => {
|
|
159
81
|
if (isMessageFromParent(event)) {
|
|
160
82
|
const data = event.data;
|
|
161
83
|
if (!isObject(data)) return;
|
|
162
84
|
if (data.method === SANDBOX_RESOURCE_READY_METHOD) {
|
|
163
|
-
|
|
85
|
+
innerReady = false;
|
|
86
|
+
innerFrame.setAttribute("src", RESOURCE_PATH);
|
|
164
87
|
return;
|
|
165
88
|
}
|
|
166
89
|
if (data.method === SANDBOX_PROXY_READY_METHOD) return;
|
|
@@ -186,10 +109,14 @@ export function buildSandboxProxyHtml(input: SandboxProxyTemplateInput): string
|
|
|
186
109
|
</html>`;
|
|
187
110
|
}
|
|
188
111
|
|
|
112
|
+
function escapeHtmlAttribute(value: string): string {
|
|
113
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
114
|
+
}
|
|
115
|
+
|
|
189
116
|
/**
|
|
190
117
|
* CSP for the proxy document itself. It contains only the inline relay script
|
|
191
|
-
* and a nested
|
|
192
|
-
*
|
|
118
|
+
* and a same-origin nested frame. Provider policy is applied on the resource
|
|
119
|
+
* navigation response, not inherited from this relay document.
|
|
193
120
|
*/
|
|
194
121
|
export function buildSandboxProxyCsp(): string {
|
|
195
122
|
return [
|