@humain/terminal 0.0.14 → 0.0.15

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 +7 -0
  2. package/dist/bundle/chunks/{chunk-6TW5AYGH.js → chunk-QMTWJZBT.js} +251 -39
  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
@@ -3,6 +3,8 @@ import type { UiHostContext, UiResourceContent, UiResourceCsp } from "./types.ts
3
3
  // Use locally bundled AppBridge to avoid CDN Zod bundling issues
4
4
  const DEFAULT_APP_BRIDGE_MODULE_URL = "/app-bridge.bundle.js";
5
5
  const APP_SANDBOX = "allow-scripts allow-forms allow-modals allow-popups allow-downloads";
6
+ const APP_PROXY_SANDBOX = `${APP_SANDBOX} allow-same-origin`;
7
+ const APP_INNER_SANDBOX = APP_PROXY_SANDBOX;
6
8
 
7
9
  export interface HostHtmlTemplateInput {
8
10
  sessionToken: string;
@@ -16,6 +18,7 @@ export interface HostHtmlTemplateInput {
16
18
  cacheToolConsent: boolean;
17
19
  hostContext?: UiHostContext;
18
20
  appBridgeModuleUrl?: string;
21
+ sandboxProxyUrl: string;
19
22
  }
20
23
 
21
24
  export function buildHostHtmlTemplate(input: HostHtmlTemplateInput): string {
@@ -31,6 +34,9 @@ export function buildHostHtmlTemplate(input: HostHtmlTemplateInput): string {
31
34
  const requireToolConsent = safeInlineJSON(input.requireToolConsent);
32
35
  const cacheToolConsent = safeInlineJSON(input.cacheToolConsent);
33
36
  const moduleUrl = safeInlineJSON(input.appBridgeModuleUrl ?? DEFAULT_APP_BRIDGE_MODULE_URL);
37
+ const sandboxProxyUrl = safeInlineJSON(input.sandboxProxyUrl);
38
+ const resourceCsp = safeInlineJSON(input.resource.meta.csp);
39
+ const resourcePermissions = safeInlineJSON(input.resource.meta.permissions);
34
40
 
35
41
  return `<!doctype html>
36
42
  <html lang="en">
@@ -112,7 +118,7 @@ export function buildHostHtmlTemplate(input: HostHtmlTemplateInput): string {
112
118
  </div>
113
119
  </header>
114
120
  <main>
115
- <iframe id="mcp-app" sandbox="${APP_SANDBOX}" referrerpolicy="no-referrer"></iframe>
121
+ <iframe id="mcp-app" sandbox="${APP_PROXY_SANDBOX}" referrerpolicy="no-referrer"></iframe>
116
122
  </main>
117
123
  <div class="overlay" id="error-overlay">
118
124
  <div class="panel">
@@ -138,6 +144,10 @@ export function buildHostHtmlTemplate(input: HostHtmlTemplateInput): string {
138
144
  const ALLOW_ATTRIBUTE = ${allowAttribute};
139
145
  const REQUIRE_TOOL_CONSENT = ${requireToolConsent};
140
146
  const CACHE_TOOL_CONSENT = ${cacheToolConsent};
147
+ const SANDBOX_PROXY_URL = ${sandboxProxyUrl};
148
+ const RESOURCE_CSP = ${resourceCsp};
149
+ const RESOURCE_PERMISSIONS = ${resourcePermissions};
150
+ const INNER_SANDBOX = ${safeInlineJSON(APP_INNER_SANDBOX)};
141
151
  const STREAM_CONTEXT_KEY = "pi-mcp-adapter/stream";
142
152
  const STREAM_PATCH_METHOD = "notifications/pi-mcp-adapter/ui-result-patch";
143
153
 
@@ -148,6 +158,7 @@ export function buildHostHtmlTemplate(input: HostHtmlTemplateInput): string {
148
158
  const errorOverlay = document.getElementById("error-overlay");
149
159
  const completionOverlay = document.getElementById("completion-overlay");
150
160
  const errorMessage = document.getElementById("error-message");
161
+ const sandboxProxyOrigin = new URL(SANDBOX_PROXY_URL).origin;
151
162
 
152
163
  document.getElementById("server-name").textContent = SERVER_NAME;
153
164
  document.getElementById("tool-name").textContent = TOOL_NAME;
@@ -205,10 +216,41 @@ export function buildHostHtmlTemplate(input: HostHtmlTemplateInput): string {
205
216
  const bridge = new AppBridge(
206
217
  null,
207
218
  { name: "pi", version: "1.0.0" },
208
- { serverTools: {}, openLinks: {}, logging: {}, updateModelContext: {}, message: {} },
219
+ {
220
+ serverTools: {},
221
+ openLinks: {},
222
+ logging: {},
223
+ updateModelContext: {},
224
+ message: {},
225
+ sandbox: {
226
+ ...(RESOURCE_CSP ? { csp: RESOURCE_CSP } : {}),
227
+ ...(RESOURCE_PERMISSIONS ? { permissions: RESOURCE_PERMISSIONS } : {}),
228
+ },
229
+ },
209
230
  { hostContext: HOST_CONTEXT }
210
231
  );
211
232
 
233
+ let sandboxResourceSent = false;
234
+ bridge.onsandboxready = async () => {
235
+ if (sandboxResourceSent) return;
236
+ sandboxResourceSent = true;
237
+ try {
238
+ const response = await fetch("/ui-app?resource=" + encodeURIComponent(UI_RESOURCE_TOKEN), {
239
+ headers: { Accept: "text/html" },
240
+ });
241
+ if (!response.ok) throw new Error("UI resource request failed: HTTP " + response.status);
242
+ const html = await response.text();
243
+ await bridge.sendSandboxResourceReady({
244
+ html,
245
+ sandbox: INNER_SANDBOX,
246
+ ...(RESOURCE_CSP ? { csp: RESOURCE_CSP } : {}),
247
+ ...(RESOURCE_PERMISSIONS ? { permissions: RESOURCE_PERMISSIONS } : {}),
248
+ });
249
+ } catch (error) {
250
+ showError("Failed to load MCP App resource: " + String(error));
251
+ }
252
+ };
253
+
212
254
  bridge.oncalltool = async (params) => {
213
255
  if (!consentGranted) {
214
256
  const accepted = window.confirm("Allow this UI to call server tools for this session?");
@@ -240,7 +282,7 @@ export function buildHostHtmlTemplate(input: HostHtmlTemplateInput): string {
240
282
  // Also listen for raw postMessage events with custom types (notify, prompt, intent, etc.)
241
283
  // These bypass the AppBridge protocol but are used by some MCP UI implementations
242
284
  window.addEventListener("message", async (event) => {
243
- if (event.source !== iframe.contentWindow) return;
285
+ if (event.source !== iframe.contentWindow || event.origin !== sandboxProxyOrigin) return;
244
286
  const data = event.data;
245
287
  if (!data || typeof data !== "object") return;
246
288
 
@@ -304,6 +346,12 @@ export function buildHostHtmlTemplate(input: HostHtmlTemplateInput): string {
304
346
  }
305
347
 
306
348
  // Connect bridge BEFORE loading iframe to ensure we're listening when the app sends ui/initialize
349
+ const sandboxMessageGuard = (event) => {
350
+ if (event.source === iframe.contentWindow && event.origin !== sandboxProxyOrigin) {
351
+ event.stopImmediatePropagation();
352
+ }
353
+ };
354
+ window.addEventListener("message", sandboxMessageGuard, true);
307
355
  try {
308
356
  const transport = new PostMessageTransport(iframe.contentWindow, iframe.contentWindow);
309
357
  await bridge.connect(transport);
@@ -315,7 +363,7 @@ export function buildHostHtmlTemplate(input: HostHtmlTemplateInput): string {
315
363
  const iframeLoaded = new Promise((resolve) => {
316
364
  iframe.onload = resolve;
317
365
  });
318
- iframe.src = "/ui-app?resource=" + encodeURIComponent(UI_RESOURCE_TOKEN);
366
+ iframe.src = SANDBOX_PROXY_URL;
319
367
  await iframeLoaded;
320
368
 
321
369
  const eventSource = new EventSource("/events?session=" + encodeURIComponent(SESSION_TOKEN));
@@ -340,6 +388,9 @@ export function buildHostHtmlTemplate(input: HostHtmlTemplateInput): string {
340
388
  showError("Failed to forward cancellation: " + String(error));
341
389
  }
342
390
  });
391
+ eventSource.addEventListener("resource-updated", () => {
392
+ setStatus("Resource updated on the server. Reopen this UI to load the latest version.");
393
+ });
343
394
  eventSource.addEventListener("result-patch", async (event) => {
344
395
  try {
345
396
  await bridge.notification({
@@ -443,7 +494,9 @@ function sanitizeCspDomains(domains: unknown): string[] {
443
494
  }
444
495
 
445
496
  function safeInlineJSON(value: unknown): string {
446
- return JSON.stringify(value)
497
+ const json = JSON.stringify(value);
498
+ if (json === undefined) return "undefined";
499
+ return json
447
500
  .replace(/</g, "\\u003c")
448
501
  .replace(/>/g, "\\u003e")
449
502
  .replace(/&/g, "\\u0026")