@frontmcp/uipack 1.8.5 → 1.8.7
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/adapters/index.js +339 -35
- package/adapters/markdown.d.ts +9 -0
- package/adapters/markdown.d.ts.map +1 -0
- package/adapters/template-renderer.d.ts +8 -0
- package/adapters/template-renderer.d.ts.map +1 -1
- package/bridge-runtime/iife-generator.d.ts.map +1 -1
- package/bridge-runtime/index.js +169 -22
- package/component/index.js +223 -26
- package/component/loader.d.ts.map +1 -1
- package/component/transpiler.d.ts.map +1 -1
- package/esm/adapters/index.mjs +339 -35
- package/esm/bridge-runtime/index.mjs +169 -22
- package/esm/component/index.mjs +223 -26
- package/esm/index.mjs +339 -35
- package/esm/package.json +8 -2
- package/esm/shell/index.mjs +169 -22
- package/index.js +339 -35
- package/package.json +8 -2
- package/shell/index.js +169 -22
- package/types/ui-config.d.ts +5 -3
- package/types/ui-config.d.ts.map +1 -1
package/component/index.js
CHANGED
|
@@ -498,8 +498,24 @@ function isFrontmcpUiResolvable(...candidatePaths) {
|
|
|
498
498
|
}
|
|
499
499
|
|
|
500
500
|
// libs/uipack/src/component/transpiler.ts
|
|
501
|
+
function loadEsbuild(filename) {
|
|
502
|
+
try {
|
|
503
|
+
return require("esbuild");
|
|
504
|
+
} catch (err) {
|
|
505
|
+
if (!isMissingEsbuild(err)) throw err;
|
|
506
|
+
const subject = filename ? `FileSource widget "${filename}"` : "A FileSource widget";
|
|
507
|
+
throw new Error(
|
|
508
|
+
`${subject} needs esbuild, which is not installed. @frontmcp/uipack loads esbuild on demand to bundle FileSource widgets (.tsx/.jsx) when the tool is called, so it must be installed where the server runs: \`npm install esbuild\` (in "dependencies", not "devDependencies"). Projects created with \`frontmcp create\` already get it through the \`frontmcp\` package.`,
|
|
509
|
+
{ cause: err }
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function isMissingEsbuild(err) {
|
|
514
|
+
if (!(err instanceof Error)) return false;
|
|
515
|
+
return err.code === "MODULE_NOT_FOUND" && /Cannot find module ['"]esbuild['"]/.test(err.message);
|
|
516
|
+
}
|
|
501
517
|
function transpileReactSource(source, filename) {
|
|
502
|
-
const esbuild =
|
|
518
|
+
const esbuild = loadEsbuild(filename);
|
|
503
519
|
const loader = filename?.endsWith(".tsx") ? "tsx" : "jsx";
|
|
504
520
|
const result = esbuild.transformSync(source, {
|
|
505
521
|
loader,
|
|
@@ -518,7 +534,7 @@ function bundleFileSource(source, filename, resolveDir, componentName, options =
|
|
|
518
534
|
`FileSource widget "${filename}" requires the @frontmcp/ui package, which provides the React bridge mount that's injected at bundle time. Install it (e.g. \`npm install @frontmcp/ui\` or \`yarn add @frontmcp/ui\`) and try again.`
|
|
519
535
|
);
|
|
520
536
|
}
|
|
521
|
-
const esbuild =
|
|
537
|
+
const esbuild = loadEsbuild(filename);
|
|
522
538
|
const mountCode = `
|
|
523
539
|
// --- Auto-generated mount ---
|
|
524
540
|
import { createElement as __h } from 'react';
|
|
@@ -615,7 +631,8 @@ if (__root) {
|
|
|
615
631
|
} catch (err) {
|
|
616
632
|
const message = err instanceof Error ? err.message : String(err);
|
|
617
633
|
throw new Error(
|
|
618
|
-
`Failed to bundle FileSource "${filename}": ${message}. If the error mentions @frontmcp/ui or @frontmcp/uipack, ensure both packages are installed in the consuming project
|
|
634
|
+
`Failed to bundle FileSource "${filename}": ${message}. If the error mentions @frontmcp/ui or @frontmcp/uipack, ensure both packages are installed in the consuming project.`,
|
|
635
|
+
{ cause: err }
|
|
619
636
|
);
|
|
620
637
|
}
|
|
621
638
|
}
|
|
@@ -677,6 +694,37 @@ function resolveImportSource(source) {
|
|
|
677
694
|
peerDependencies: []
|
|
678
695
|
};
|
|
679
696
|
}
|
|
697
|
+
var BUILD_DIR_SEGMENTS = /* @__PURE__ */ new Set(["dist", "build", "out"]);
|
|
698
|
+
function missingWidgetError(filePath, cause) {
|
|
699
|
+
const sourceWidget = findSourceWidget(filePath);
|
|
700
|
+
const error = new Error(
|
|
701
|
+
`FileSource widget not found (ENOENT): no file at "${filePath}". The widget source is read from this path when the tool is called, so it has to exist where the compiled tool runs \u2014 a path built from \`__dirname\` or \`import.meta.url\` points into the build output once the tool is compiled. tsc does not copy \`*.widget.tsx\` / \`*.widget.jsx\` files into its output; \`frontmcp build\` does, and any other build needs a step that copies them next to the compiled tool.` + (sourceWidget ? ` The source widget exists at "${sourceWidget}" \u2014 copy it to "${filePath}", or build with \`frontmcp build\`.` : ""),
|
|
702
|
+
{ cause }
|
|
703
|
+
);
|
|
704
|
+
error.code = "ENOENT";
|
|
705
|
+
error.path = filePath;
|
|
706
|
+
return error;
|
|
707
|
+
}
|
|
708
|
+
function findSourceWidget(filePath) {
|
|
709
|
+
const path = require("path");
|
|
710
|
+
const fs = require("fs");
|
|
711
|
+
const parts = filePath.split(path.sep);
|
|
712
|
+
for (let i = parts.length - 2; i >= 0; i--) {
|
|
713
|
+
if (!BUILD_DIR_SEGMENTS.has(parts[i])) continue;
|
|
714
|
+
const candidates = [[...parts.slice(0, i), "src", ...parts.slice(i + 1)]];
|
|
715
|
+
if (parts.length - i > 2) candidates.push([...parts.slice(0, i), "src", ...parts.slice(i + 2)]);
|
|
716
|
+
candidates.push([...parts.slice(0, i), ...parts.slice(i + 1)]);
|
|
717
|
+
for (const candidate of candidates) {
|
|
718
|
+
const candidatePath = candidate.join(path.sep);
|
|
719
|
+
try {
|
|
720
|
+
if (fs.existsSync(candidatePath)) return candidatePath;
|
|
721
|
+
} catch {
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
return void 0;
|
|
725
|
+
}
|
|
726
|
+
return void 0;
|
|
727
|
+
}
|
|
680
728
|
function resolveFileSource(source, options = {}) {
|
|
681
729
|
const path = require("path");
|
|
682
730
|
const ext = path.extname(source.file).toLowerCase();
|
|
@@ -691,9 +739,11 @@ function resolveFileSource(source, options = {}) {
|
|
|
691
739
|
const isNotFound = err?.code === "ENOENT";
|
|
692
740
|
if (isNotFound && wasRelative) {
|
|
693
741
|
throw new Error(
|
|
694
|
-
`FileSource widget "${source.file}" not found at "${filePath}". Relative paths are resolved against process.cwd() ("${process.cwd()}"), not the tool file's directory. To anchor the path to the tool file, pass an absolute path \u2014 e.g. \`{ file: fileURLToPath(new URL('./widget.tsx', import.meta.url)) }\` from \`node:url\` (see issue #444)
|
|
742
|
+
`FileSource widget "${source.file}" not found at "${filePath}". Relative paths are resolved against process.cwd() ("${process.cwd()}"), not the tool file's directory. To anchor the path to the tool file, pass an absolute path \u2014 e.g. \`{ file: fileURLToPath(new URL('./widget.tsx', import.meta.url)) }\` from \`node:url\` (see issue #444).`,
|
|
743
|
+
{ cause: err }
|
|
695
744
|
);
|
|
696
745
|
}
|
|
746
|
+
if (isNotFound) throw missingWidgetError(filePath, err);
|
|
697
747
|
throw err;
|
|
698
748
|
}
|
|
699
749
|
const componentName = source.exportName || extractDefaultExportName(rawSource) || "Component";
|
|
@@ -911,6 +961,23 @@ function __applySizingCss(sizing) {
|
|
|
911
961
|
}
|
|
912
962
|
}
|
|
913
963
|
|
|
964
|
+
function __measureHeight() {
|
|
965
|
+
// <html> at fit-content includes body margins and collapsed child margins;
|
|
966
|
+
// content overflowing a fixed-height body is added; a px max-height clamps.
|
|
967
|
+
var de = document.documentElement;
|
|
968
|
+
var body = document.body;
|
|
969
|
+
if (!de || !body) return 0;
|
|
970
|
+
var prev = de.style.height;
|
|
971
|
+
de.style.height = 'fit-content';
|
|
972
|
+
var dr = de.getBoundingClientRect();
|
|
973
|
+
var br = body.getBoundingClientRect();
|
|
974
|
+
var h = Math.max(dr.height, br.top + body.scrollHeight + Math.max(0, dr.bottom - br.bottom) - dr.top);
|
|
975
|
+
de.style.height = prev;
|
|
976
|
+
var maxHeight = getComputedStyle(de).maxHeight;
|
|
977
|
+
var mx = maxHeight && maxHeight.slice(-2) === 'px' ? parseFloat(maxHeight) : NaN;
|
|
978
|
+
return Math.ceil(isNaN(mx) ? h : Math.min(h, mx));
|
|
979
|
+
}
|
|
980
|
+
|
|
914
981
|
function __initAutoResize() {
|
|
915
982
|
if (typeof window === 'undefined') return;
|
|
916
983
|
// Idempotent: a re-injected IIFE must not stack observers.
|
|
@@ -933,23 +1000,30 @@ function __initAutoResize() {
|
|
|
933
1000
|
if (typeof ResizeObserver === 'undefined') return;
|
|
934
1001
|
|
|
935
1002
|
function startObserving() {
|
|
936
|
-
|
|
937
|
-
|
|
1003
|
+
if (!document.body) return;
|
|
1004
|
+
var targets = [document.documentElement, document.body];
|
|
1005
|
+
var root = document.getElementById('root');
|
|
1006
|
+
if (root) targets.push(root);
|
|
938
1007
|
|
|
939
1008
|
var rafId = null;
|
|
940
1009
|
var lastReported = -1;
|
|
941
1010
|
function report() {
|
|
942
1011
|
rafId = null;
|
|
943
1012
|
try {
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1013
|
+
// Before the handshake an ext-apps host can't receive the report; the
|
|
1014
|
+
// bridge:ready listener below sends it once the bridge is up.
|
|
1015
|
+
if (window.FrontMcpBridge && window.FrontMcpBridge.initialized === false) return;
|
|
1016
|
+
var height = __measureHeight();
|
|
1017
|
+
var width = Math.ceil(document.documentElement.getBoundingClientRect().width);
|
|
947
1018
|
if (height === lastReported || height <= 0) return;
|
|
948
1019
|
lastReported = height;
|
|
949
1020
|
var payload = { height: height, width: width };
|
|
950
1021
|
if (sizing.aspectRatio != null) payload.aspectRatio = sizing.aspectRatio;
|
|
951
1022
|
if (window.FrontMcpBridge && typeof window.FrontMcpBridge.setSize === 'function') {
|
|
952
|
-
window.FrontMcpBridge.setSize(payload).catch(function() {
|
|
1023
|
+
window.FrontMcpBridge.setSize(payload).catch(function() {
|
|
1024
|
+
// Forget a rejected report so the same height is sent again.
|
|
1025
|
+
if (lastReported === height) lastReported = -1;
|
|
1026
|
+
});
|
|
953
1027
|
}
|
|
954
1028
|
window.dispatchEvent(new CustomEvent('widget:resize', { detail: payload }));
|
|
955
1029
|
} catch (e) {}
|
|
@@ -970,9 +1044,17 @@ function __initAutoResize() {
|
|
|
970
1044
|
window.__mcpResizeObserver.disconnect();
|
|
971
1045
|
}
|
|
972
1046
|
var ro = new ResizeObserver(function() { schedule(); });
|
|
973
|
-
ro.observe(
|
|
1047
|
+
for (var i = 0; i < targets.length; i++) ro.observe(targets[i]);
|
|
974
1048
|
window.__mcpResizeObserver = ro;
|
|
975
1049
|
} catch (e) {}
|
|
1050
|
+
// Report once the bridge is ready (the report scheduled below is skipped
|
|
1051
|
+
// while the handshake is still pending).
|
|
1052
|
+
var readySent = false;
|
|
1053
|
+
window.addEventListener('bridge:ready', function() {
|
|
1054
|
+
if (readySent) return;
|
|
1055
|
+
readySent = true;
|
|
1056
|
+
schedule();
|
|
1057
|
+
});
|
|
976
1058
|
// Report once on init so the host gets an initial measurement.
|
|
977
1059
|
schedule();
|
|
978
1060
|
}
|
|
@@ -1020,12 +1102,57 @@ function detectViewport() {
|
|
|
1020
1102
|
return undefined;
|
|
1021
1103
|
}
|
|
1022
1104
|
|
|
1105
|
+
function __applyHostTheme(theme) {
|
|
1106
|
+
// Follow a host-supplied theme: <meta name="color-scheme"> sets the frame's
|
|
1107
|
+
// canvas and form controls (a widget's own :root color-scheme still wins),
|
|
1108
|
+
// <html data-theme> is a styling hook. The OS fallback is never written.
|
|
1109
|
+
if (theme !== 'light' && theme !== 'dark') return;
|
|
1110
|
+
if (typeof document === 'undefined' || !document.documentElement) return;
|
|
1111
|
+
try {
|
|
1112
|
+
var meta = document.querySelector('meta[name="color-scheme"]');
|
|
1113
|
+
var head = document.head || document.getElementsByTagName('head')[0];
|
|
1114
|
+
if (!meta && head) {
|
|
1115
|
+
meta = document.createElement('meta');
|
|
1116
|
+
meta.setAttribute('name', 'color-scheme');
|
|
1117
|
+
head.appendChild(meta);
|
|
1118
|
+
}
|
|
1119
|
+
if (meta) meta.setAttribute('content', theme);
|
|
1120
|
+
document.documentElement.setAttribute('data-theme', theme);
|
|
1121
|
+
} catch (e) {}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
function extractToolOutput(params) {
|
|
1125
|
+
// A host sends a CallToolResult: prefer structuredContent, then parsed text, then the raw content.
|
|
1126
|
+
if (!params) return undefined;
|
|
1127
|
+
if (params.structuredContent !== undefined && params.structuredContent !== null) return params.structuredContent;
|
|
1128
|
+
var content = params.content;
|
|
1129
|
+
if (Array.isArray(content)) {
|
|
1130
|
+
for (var i = 0; i < content.length; i++) {
|
|
1131
|
+
var item = content[i];
|
|
1132
|
+
if (item && item.type === 'text' && typeof item.text === 'string') {
|
|
1133
|
+
try { return JSON.parse(item.text); } catch (e) { return item.text; }
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
return content;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1023
1140
|
function readInjectedData() {
|
|
1024
1141
|
var data = { toolInput: {}, toolOutput: undefined, structuredContent: undefined };
|
|
1025
1142
|
if (typeof window !== 'undefined') {
|
|
1026
1143
|
if (window.__mcpToolInput) data.toolInput = window.__mcpToolInput;
|
|
1027
1144
|
if (window.__mcpToolOutput) data.toolOutput = window.__mcpToolOutput;
|
|
1028
1145
|
if (window.__mcpStructuredContent) data.structuredContent = window.__mcpStructuredContent;
|
|
1146
|
+
// The OpenAI Apps SDK hands the widget its data as window.openai.toolInput / toolOutput
|
|
1147
|
+
// (toolOutput is the tool's structuredContent).
|
|
1148
|
+
var oa = window.openai;
|
|
1149
|
+
if (oa && typeof oa === 'object') {
|
|
1150
|
+
if (oa.toolInput && !window.__mcpToolInput) data.toolInput = oa.toolInput;
|
|
1151
|
+
if (oa.toolOutput !== undefined && oa.toolOutput !== null) {
|
|
1152
|
+
if (data.toolOutput === undefined) data.toolOutput = oa.toolOutput;
|
|
1153
|
+
if (data.structuredContent === undefined) data.structuredContent = oa.toolOutput;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1029
1156
|
}
|
|
1030
1157
|
return data;
|
|
1031
1158
|
}
|
|
@@ -1074,7 +1201,24 @@ var OpenAIAdapter = {
|
|
|
1074
1201
|
if (sdk.displayMode) {
|
|
1075
1202
|
context.hostContext.displayMode = sdk.displayMode;
|
|
1076
1203
|
}
|
|
1077
|
-
//
|
|
1204
|
+
// The Apps SDK re-dispatches the changed globals in an 'openai:set_globals' event.
|
|
1205
|
+
window.addEventListener('openai:set_globals', function(event) {
|
|
1206
|
+
var globals = (event && event.detail && event.detail.globals) || window.openai || {};
|
|
1207
|
+
if (globals.toolInput !== undefined && globals.toolInput !== null) {
|
|
1208
|
+
context.toolInput = globals.toolInput;
|
|
1209
|
+
window.dispatchEvent(new CustomEvent('tool:input', { detail: { arguments: context.toolInput } }));
|
|
1210
|
+
}
|
|
1211
|
+
if (globals.toolOutput !== undefined && globals.toolOutput !== null) {
|
|
1212
|
+
context.structuredContent = globals.toolOutput;
|
|
1213
|
+
context.notifyToolResult(globals.toolOutput);
|
|
1214
|
+
}
|
|
1215
|
+
if (globals.theme && globals.theme !== context.hostContext.theme) {
|
|
1216
|
+
context.notifyContextChange({ theme: globals.theme });
|
|
1217
|
+
}
|
|
1218
|
+
if (globals.displayMode && globals.displayMode !== context.hostContext.displayMode) {
|
|
1219
|
+
context.notifyContextChange({ displayMode: globals.displayMode });
|
|
1220
|
+
}
|
|
1221
|
+
});
|
|
1078
1222
|
return Promise.resolve();
|
|
1079
1223
|
},
|
|
1080
1224
|
callTool: function(context, name, args) {
|
|
@@ -1126,6 +1270,8 @@ var ExtAppsAdapter = {
|
|
|
1126
1270
|
pendingRequests: {},
|
|
1127
1271
|
requestId: 0,
|
|
1128
1272
|
hostCapabilities: {},
|
|
1273
|
+
handshakeSettled: false,
|
|
1274
|
+
pendingSize: null,
|
|
1129
1275
|
canHandle: function() {
|
|
1130
1276
|
if (typeof window === 'undefined') return false;
|
|
1131
1277
|
if (window.parent === window) return false;
|
|
@@ -1219,9 +1365,10 @@ var ExtAppsAdapter = {
|
|
|
1219
1365
|
window.dispatchEvent(new CustomEvent('tool:input-partial', { detail: { arguments: context.toolInput } }));
|
|
1220
1366
|
break;
|
|
1221
1367
|
case 'ui/notifications/tool-result':
|
|
1222
|
-
|
|
1368
|
+
var resultOutput = extractToolOutput(params);
|
|
1369
|
+
context.toolOutput = resultOutput;
|
|
1223
1370
|
context.structuredContent = params.structuredContent;
|
|
1224
|
-
context.notifyToolResult(
|
|
1371
|
+
context.notifyToolResult(resultOutput);
|
|
1225
1372
|
window.dispatchEvent(new CustomEvent('tool:result', { detail: params }));
|
|
1226
1373
|
break;
|
|
1227
1374
|
case 'ui/notifications/host-context-changed':
|
|
@@ -1275,6 +1422,15 @@ var ExtAppsAdapter = {
|
|
|
1275
1422
|
window.parent.postMessage({ jsonrpc: '2.0', id: id, method: method, params: params }, targetOrigin);
|
|
1276
1423
|
});
|
|
1277
1424
|
},
|
|
1425
|
+
sendNotification: function(method, params) {
|
|
1426
|
+
// JSON-RPC notification: no id, no response. Same origin rule as sendRequest.
|
|
1427
|
+
if (!this.trustedOrigin && this.trustedOrigins.length === 0) {
|
|
1428
|
+
return Promise.reject(new Error('Cannot send notification: no trusted origin established'));
|
|
1429
|
+
}
|
|
1430
|
+
var targetOrigin = this.trustedOrigin || this.trustedOrigins[0];
|
|
1431
|
+
window.parent.postMessage({ jsonrpc: '2.0', method: method, params: params }, targetOrigin);
|
|
1432
|
+
return Promise.resolve();
|
|
1433
|
+
},
|
|
1278
1434
|
sendHandshake: function(context) {
|
|
1279
1435
|
// Send ui/initialize using '*' as target origin since TOFU hasn't
|
|
1280
1436
|
// been established yet. The response from the host will establish
|
|
@@ -1291,6 +1447,7 @@ var ExtAppsAdapter = {
|
|
|
1291
1447
|
var timeout = setTimeout(function() {
|
|
1292
1448
|
delete self.pendingRequests[id];
|
|
1293
1449
|
// Handshake timeout is non-fatal \u2014 notifications may still arrive
|
|
1450
|
+
self.settleHandshake();
|
|
1294
1451
|
resolve();
|
|
1295
1452
|
}, 10000);
|
|
1296
1453
|
|
|
@@ -1304,7 +1461,9 @@ var ExtAppsAdapter = {
|
|
|
1304
1461
|
supportsDisplayModes: true
|
|
1305
1462
|
});
|
|
1306
1463
|
if (result.hostContext) {
|
|
1307
|
-
|
|
1464
|
+
// Notify (not a silent merge) so onContextChange listeners and the
|
|
1465
|
+
// host theme see the handshake's context.
|
|
1466
|
+
context.notifyContextChange(result.hostContext);
|
|
1308
1467
|
}
|
|
1309
1468
|
// Send ui/notifications/initialized to tell the host the view is ready.
|
|
1310
1469
|
// Per MCP Apps spec, the host waits for this before sending tool-result.
|
|
@@ -1314,9 +1473,10 @@ var ExtAppsAdapter = {
|
|
|
1314
1473
|
method: 'ui/notifications/initialized',
|
|
1315
1474
|
params: {}
|
|
1316
1475
|
}, targetOrigin);
|
|
1476
|
+
self.settleHandshake();
|
|
1317
1477
|
resolve();
|
|
1318
1478
|
},
|
|
1319
|
-
reject: function(err) { resolve(); }, // Non-fatal
|
|
1479
|
+
reject: function(err) { self.settleHandshake(); resolve(); }, // Non-fatal
|
|
1320
1480
|
timeout: timeout
|
|
1321
1481
|
};
|
|
1322
1482
|
|
|
@@ -1330,6 +1490,18 @@ var ExtAppsAdapter = {
|
|
|
1330
1490
|
performHandshake: function(context) {
|
|
1331
1491
|
return this.sendHandshake(context);
|
|
1332
1492
|
},
|
|
1493
|
+
settleHandshake: function() {
|
|
1494
|
+
// Deliver the latest size requested while no host origin was trusted.
|
|
1495
|
+
this.handshakeSettled = true;
|
|
1496
|
+
var pending = this.pendingSize;
|
|
1497
|
+
if (!pending) return;
|
|
1498
|
+
this.pendingSize = null;
|
|
1499
|
+
this.sendNotification('ui/notifications/size-changed', pending.params).then(function(result) {
|
|
1500
|
+
for (var i = 0; i < pending.waiters.length; i++) pending.waiters[i].resolve(result);
|
|
1501
|
+
}, function(err) {
|
|
1502
|
+
for (var i = 0; i < pending.waiters.length; i++) pending.waiters[i].reject(err);
|
|
1503
|
+
});
|
|
1504
|
+
},
|
|
1333
1505
|
callTool: function(context, name, args) {
|
|
1334
1506
|
if (!this.hostCapabilities.serverTools && !this.hostCapabilities.serverToolProxy) {
|
|
1335
1507
|
return Promise.reject(new Error('Server tool proxy not supported'));
|
|
@@ -1351,13 +1523,22 @@ var ExtAppsAdapter = {
|
|
|
1351
1523
|
return this.sendRequest('ui/setDisplayMode', { mode: mode });
|
|
1352
1524
|
},
|
|
1353
1525
|
setSize: function(context, size) {
|
|
1354
|
-
//
|
|
1355
|
-
//
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1526
|
+
// Standard ext-apps sizing: the view tells the host its dimensions with the
|
|
1527
|
+
// ui/notifications/size-changed notification ({ width?, height? } in px).
|
|
1528
|
+
var params = {};
|
|
1529
|
+
if (size && typeof size.width === 'number') params.width = size.width;
|
|
1530
|
+
if (size && typeof size.height === 'number') params.height = size.height;
|
|
1531
|
+
if (!this.handshakeSettled && !this.trustedOrigin && this.trustedOrigins.length === 0) {
|
|
1532
|
+
// No host origin yet: keep only the latest size and send it when the
|
|
1533
|
+
// handshake settles; every caller's promise follows that one request.
|
|
1534
|
+
var self = this;
|
|
1535
|
+
if (!this.pendingSize) this.pendingSize = { params: params, waiters: [] };
|
|
1536
|
+
this.pendingSize.params = params;
|
|
1537
|
+
return new Promise(function(resolve, reject) {
|
|
1538
|
+
self.pendingSize.waiters.push({ resolve: resolve, reject: reject });
|
|
1539
|
+
});
|
|
1540
|
+
}
|
|
1541
|
+
return this.sendNotification('ui/notifications/size-changed', params);
|
|
1361
1542
|
},
|
|
1362
1543
|
requestClose: function(context) {
|
|
1363
1544
|
return this.sendRequest('ui/close', {});
|
|
@@ -1603,6 +1784,7 @@ function FrontMcpBridge() {
|
|
|
1603
1784
|
toolResultListeners: [],
|
|
1604
1785
|
notifyContextChange: function(changes) {
|
|
1605
1786
|
Object.assign(this.hostContext, changes);
|
|
1787
|
+
if (changes && changes.theme) __applyHostTheme(changes.theme);
|
|
1606
1788
|
for (var i = 0; i < this.contextListeners.length; i++) {
|
|
1607
1789
|
try { this.contextListeners[i](changes); } catch(e) {}
|
|
1608
1790
|
}
|
|
@@ -1779,7 +1961,7 @@ FrontMcpBridge.prototype.requestDisplayMode = function(mode) {
|
|
|
1779
1961
|
|
|
1780
1962
|
// Report a desired widget size to the host. \`size\` is { height?, width?, aspectRatio? }.
|
|
1781
1963
|
// Per-adapter behaviour: Claude/generic no-op (host measures the DOM),
|
|
1782
|
-
// ext-apps sends ui/
|
|
1964
|
+
// ext-apps sends ui/notifications/size-changed, OpenAI forwards to its SDK when available.
|
|
1783
1965
|
FrontMcpBridge.prototype.setSize = function(size) {
|
|
1784
1966
|
if (!this._adapter) return Promise.reject(new Error('Not initialized'));
|
|
1785
1967
|
if (!this._adapter.setSize) return Promise.resolve();
|
|
@@ -1881,7 +2063,7 @@ FrontMcpBridge.prototype._setupDataToolCallHandler = function() {
|
|
|
1881
2063
|
target.classList.add('opacity-50', 'cursor-not-allowed');
|
|
1882
2064
|
|
|
1883
2065
|
// Add spinner for buttons
|
|
1884
|
-
var spinner = '<svg class="animate-spin -ml-1 mr-2 h-4 w-4 inline" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>';
|
|
2066
|
+
var spinner = '<svg class="animate-spin -ml-1 mr-2 h-4 w-4 inline" style="width:1em;height:1em;vertical-align:-0.125em" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>';
|
|
1885
2067
|
if (target.tagName === 'BUTTON') {
|
|
1886
2068
|
target.innerHTML = spinner + 'Loading...';
|
|
1887
2069
|
}
|
|
@@ -1962,7 +2144,22 @@ function minifyJS(code) {
|
|
|
1962
2144
|
if (code.length > MAX_MINIFY_CODE_LENGTH) {
|
|
1963
2145
|
return code;
|
|
1964
2146
|
}
|
|
1965
|
-
|
|
2147
|
+
const out = [];
|
|
2148
|
+
let inBlockComment = false;
|
|
2149
|
+
for (const raw of code.split("\n")) {
|
|
2150
|
+
const line = raw.trim();
|
|
2151
|
+
if (inBlockComment) {
|
|
2152
|
+
if (line.includes("*/")) inBlockComment = false;
|
|
2153
|
+
continue;
|
|
2154
|
+
}
|
|
2155
|
+
if (line === "" || line.startsWith("//")) continue;
|
|
2156
|
+
if (line.startsWith("/*")) {
|
|
2157
|
+
if (!line.includes("*/")) inBlockComment = true;
|
|
2158
|
+
continue;
|
|
2159
|
+
}
|
|
2160
|
+
out.push(line);
|
|
2161
|
+
}
|
|
2162
|
+
return out.join("\n");
|
|
1966
2163
|
}
|
|
1967
2164
|
function generatePlatformBundle(platform, options = {}) {
|
|
1968
2165
|
const platformAdapters = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/component/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,mBAAmB,CAAC;AAGxE,OAAO,EACL,iBAAiB,EAUjB,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACd,MAAM,SAAS,CAAC;AAOjB;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,QAAQ,EAChB,OAAO,CAAC,EAAE;IACR,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GACA,iBAAiB,CA2BnB;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/component/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,mBAAmB,CAAC;AAGxE,OAAO,EACL,iBAAiB,EAUjB,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACd,MAAM,SAAS,CAAC;AAOjB;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,QAAQ,EAChB,OAAO,CAAC,EAAE;IACR,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;;;;;;OAWG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GACA,iBAAiB,CA2BnB;AAsMD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CA6B9G;AAmBD;;GAEG;AACH,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transpiler.d.ts","sourceRoot":"","sources":["../../src/component/transpiler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"transpiler.d.ts","sourceRoot":"","sources":["../../src/component/transpiler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyCH;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAiB9E;AAED;;;;;;;;;;;;GAYG;AACH;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,uBAA4B,GACpC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CA8HlB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUpE"}
|