@humain/terminal 0.0.14 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/bundle/chunks/{chunk-6TW5AYGH.js → chunk-Z4RA2T5Q.js} +252 -40
  3. package/dist/bundle/cli.js +1 -1
  4. package/dist/bundle/index.js +1 -1
  5. package/dist/bundle/rpc-entry.js +1 -1
  6. package/dist/core/tools/subagent.d.ts.map +1 -1
  7. package/dist/core/tools/subagent.js +30 -9
  8. package/dist/core/tools/subagent.js.map +1 -1
  9. package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +27 -0
  10. package/dist/humain/mcp-adapter/vendor/README.md +13 -13
  11. package/dist/humain/mcp-adapter/vendor/commands.ts +58 -21
  12. package/dist/humain/mcp-adapter/vendor/config.ts +18 -4
  13. package/dist/humain/mcp-adapter/vendor/direct-tools.ts +26 -6
  14. package/dist/humain/mcp-adapter/vendor/dist/config.d.ts +4 -0
  15. package/dist/humain/mcp-adapter/vendor/dist/config.js +13 -4
  16. package/dist/humain/mcp-adapter/vendor/dist/config.js.map +1 -1
  17. package/dist/humain/mcp-adapter/vendor/dist/types.d.ts +11 -3
  18. package/dist/humain/mcp-adapter/vendor/dist/types.js.map +1 -1
  19. package/dist/humain/mcp-adapter/vendor/error-signal.ts +15 -4
  20. package/dist/humain/mcp-adapter/vendor/errors.ts +141 -0
  21. package/dist/humain/mcp-adapter/vendor/host-html-template.ts +58 -5
  22. package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +1017 -160
  23. package/dist/humain/mcp-adapter/vendor/index.ts +2 -3
  24. package/dist/humain/mcp-adapter/vendor/init.ts +5 -0
  25. package/dist/humain/mcp-adapter/vendor/mcp-panel.ts +30 -9
  26. package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +66 -28
  27. package/dist/humain/mcp-adapter/vendor/mcp-status.ts +2 -0
  28. package/dist/humain/mcp-adapter/vendor/package.json +3 -2
  29. package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +66 -13
  30. package/dist/humain/mcp-adapter/vendor/sandbox-proxy-template.ts +217 -0
  31. package/dist/humain/mcp-adapter/vendor/server-manager.ts +337 -6
  32. package/dist/humain/mcp-adapter/vendor/skills/mcp-scripting/SKILL.md +1 -0
  33. package/dist/humain/mcp-adapter/vendor/types.ts +18 -3
  34. package/dist/humain/mcp-adapter/vendor/ui-resource-handler.ts +18 -2
  35. package/dist/humain/mcp-adapter/vendor/ui-server.ts +179 -54
  36. package/dist/humain/mcp-adapter/vendor/ui-session.ts +28 -8
  37. package/npm-shrinkwrap.json +2 -2
  38. package/package.json +1 -1
  39. package/src/humain/mcp-adapter/UPSTREAM.md +1 -1
  40. package/src/humain/mcp-adapter/upstream.json +4 -4
  41. package/src/humain/mcp-adapter/vendor/CHANGELOG.md +27 -0
@@ -0,0 +1,217 @@
1
+ /**
2
+ * The proxy is served from a different loopback origin than the trusted host.
3
+ * `allow-same-origin` is safe here because this document never contains the
4
+ * host's session capability; provider HTML is loaded into the nested frame.
5
+ */
6
+ export const SANDBOX_PROXY_SANDBOX =
7
+ "allow-scripts allow-forms allow-modals allow-popups allow-downloads allow-same-origin";
8
+ export const SANDBOX_INNER_SANDBOX = SANDBOX_PROXY_SANDBOX;
9
+ export const SANDBOX_PROXY_PATH = "/sandbox";
10
+
11
+ export interface SandboxProxyTemplateInput {
12
+ parentOrigin: string;
13
+ }
14
+
15
+ /**
16
+ * Build the static document used by the trusted, second-origin sandbox proxy.
17
+ * The only per-session value is the exact origin of the parent host.
18
+ */
19
+ export function buildSandboxProxyHtml(input: SandboxProxyTemplateInput): string {
20
+ const parentOrigin = safeInlineJSON(input.parentOrigin);
21
+
22
+ return `<!doctype html>
23
+ <html lang="en">
24
+ <head>
25
+ <meta charset="utf-8" />
26
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
27
+ <title>MCP App Sandbox</title>
28
+ <style>
29
+ html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: transparent; }
30
+ iframe { display: block; width: 100%; height: 100%; border: 0; }
31
+ </style>
32
+ </head>
33
+ <body>
34
+ <iframe id="mcp-app" title="MCP App" sandbox="${SANDBOX_INNER_SANDBOX}" referrerpolicy="no-referrer"></iframe>
35
+ <script>
36
+ const EXPECTED_PARENT_ORIGIN = ${parentOrigin};
37
+ const SANDBOX_PROXY_READY_METHOD = "ui/notifications/sandbox-proxy-ready";
38
+ const SANDBOX_RESOURCE_READY_METHOD = "ui/notifications/sandbox-resource-ready";
39
+ const INNER_SANDBOX = ${safeInlineJSON(SANDBOX_INNER_SANDBOX)};
40
+ const MAX_PENDING_MESSAGES = 64;
41
+ const innerFrame = document.getElementById("mcp-app");
42
+ const pendingToInner = [];
43
+ let innerReady = false;
44
+
45
+ const isObject = (value) => value !== null && typeof value === "object";
46
+ const isMessageFromParent = (event) =>
47
+ event.source === window.parent && event.origin === EXPECTED_PARENT_ORIGIN;
48
+ const isMessageFromInner = (event) =>
49
+ event.source === innerFrame.contentWindow && event.origin === window.location.origin;
50
+
51
+ const postToParent = (data) => {
52
+ window.parent.postMessage(data, EXPECTED_PARENT_ORIGIN);
53
+ };
54
+
55
+ const postToInner = (data) => {
56
+ if (!innerReady || !innerFrame.contentWindow) {
57
+ if (pendingToInner.length < MAX_PENDING_MESSAGES) pendingToInner.push(data);
58
+ return;
59
+ }
60
+ innerFrame.contentWindow.postMessage(data, window.location.origin);
61
+ };
62
+
63
+ const flushPendingMessages = () => {
64
+ if (!innerFrame.contentWindow) return;
65
+ innerReady = true;
66
+ for (const data of pendingToInner.splice(0)) {
67
+ innerFrame.contentWindow.postMessage(data, window.location.origin);
68
+ }
69
+ };
70
+
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, "&amp;")
107
+ .replace(/\"/g, "&quot;")
108
+ .replace(/</g, "&lt;")
109
+ .replace(/>/g, "&gt;");
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
+ window.addEventListener("message", (event) => {
159
+ if (isMessageFromParent(event)) {
160
+ const data = event.data;
161
+ if (!isObject(data)) return;
162
+ if (data.method === SANDBOX_RESOURCE_READY_METHOD) {
163
+ loadResource(data.params);
164
+ return;
165
+ }
166
+ if (data.method === SANDBOX_PROXY_READY_METHOD) return;
167
+ if (typeof data.method === "string" && data.method.startsWith("ui/notifications/sandbox-")) return;
168
+ postToInner(data);
169
+ return;
170
+ }
171
+
172
+ if (!isMessageFromInner(event)) return;
173
+ const data = event.data;
174
+ if (!isObject(data)) return;
175
+ if (typeof data.method === "string" && data.method.startsWith("ui/notifications/sandbox-")) return;
176
+ postToParent(data);
177
+ });
178
+
179
+ postToParent({
180
+ jsonrpc: "2.0",
181
+ method: SANDBOX_PROXY_READY_METHOD,
182
+ params: {},
183
+ });
184
+ </script>
185
+ </body>
186
+ </html>`;
187
+ }
188
+
189
+ /**
190
+ * CSP for the proxy document itself. It contains only the inline relay script
191
+ * and a nested about:blank frame; provider policy is applied separately after
192
+ * the host sends the resource-ready notification.
193
+ */
194
+ export function buildSandboxProxyCsp(): string {
195
+ return [
196
+ "default-src 'none'",
197
+ "script-src 'unsafe-inline'",
198
+ "style-src 'unsafe-inline'",
199
+ "frame-src 'self'",
200
+ "connect-src 'none'",
201
+ "worker-src 'none'",
202
+ "object-src 'none'",
203
+ "base-uri 'none'",
204
+ `sandbox ${SANDBOX_PROXY_SANDBOX}`,
205
+ ].join("; ");
206
+ }
207
+
208
+ function safeInlineJSON(value: unknown): string {
209
+ const json = JSON.stringify(value);
210
+ if (json === undefined) return "undefined";
211
+ return json
212
+ .replace(/</g, "\\u003c")
213
+ .replace(/>/g, "\\u003e")
214
+ .replace(/&/g, "\\u0026")
215
+ .replace(/\u2028/g, "\\u2028")
216
+ .replace(/\u2029/g, "\\u2029");
217
+ }