@leeoohoo/ui-apps-devkit 0.1.5 → 0.1.6
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/package.json +1 -1
- package/src/sandbox/server.js +70 -34
package/package.json
CHANGED
package/src/sandbox/server.js
CHANGED
|
@@ -628,6 +628,16 @@ function htmlPage() {
|
|
|
628
628
|
}
|
|
629
629
|
#container { flex: 1 1 auto; min-height:0; overflow:hidden; }
|
|
630
630
|
#containerInner { height:100%; overflow:auto; }
|
|
631
|
+
body[data-surface='compact'] #headerSlot {
|
|
632
|
+
width: 50vw;
|
|
633
|
+
align-self: flex-end;
|
|
634
|
+
border-left: 1px solid var(--ds-panel-border);
|
|
635
|
+
}
|
|
636
|
+
body[data-surface='compact'] #container {
|
|
637
|
+
width: 50vw;
|
|
638
|
+
align-self: flex-end;
|
|
639
|
+
border-left: 1px solid var(--ds-panel-border);
|
|
640
|
+
}
|
|
631
641
|
.muted { opacity: 0.7; font-size: 12px; }
|
|
632
642
|
.bar { display:flex; gap:10px; align-items:center; justify-content:space-between; }
|
|
633
643
|
.btn {
|
|
@@ -739,16 +749,6 @@ function htmlPage() {
|
|
|
739
749
|
box-shadow: 0 14px 40px rgba(0,0,0,0.16);
|
|
740
750
|
z-index: 12;
|
|
741
751
|
}
|
|
742
|
-
#mcpPanel[data-mode='half'] {
|
|
743
|
-
right: 0;
|
|
744
|
-
top: 72px;
|
|
745
|
-
width: 50vw;
|
|
746
|
-
height: calc(100vh - 84px);
|
|
747
|
-
max-height: none;
|
|
748
|
-
border-right: none;
|
|
749
|
-
border-top-right-radius: 0;
|
|
750
|
-
border-bottom-right-radius: 0;
|
|
751
|
-
}
|
|
752
752
|
#mcpPanelHeader {
|
|
753
753
|
padding: 10px 12px;
|
|
754
754
|
display:flex;
|
|
@@ -805,7 +805,7 @@ function htmlPage() {
|
|
|
805
805
|
<div id="sandboxContext" class="muted"></div>
|
|
806
806
|
<button id="btnLlmConfig" class="btn" type="button">AI Config</button>
|
|
807
807
|
<button id="btnMcpTest" class="btn" type="button">MCP Test</button>
|
|
808
|
-
<button id="
|
|
808
|
+
<button id="btnHalfApp" class="btn" type="button">半屏</button>
|
|
809
809
|
<button id="btnInspectorToggle" class="btn" type="button">Inspect</button>
|
|
810
810
|
<button id="btnReload" class="btn" type="button">Reload</button>
|
|
811
811
|
</div>
|
|
@@ -961,7 +961,7 @@ const llmModelId = $('#llmModelId');
|
|
|
961
961
|
const llmStatus = $('#llmStatus');
|
|
962
962
|
const llmKeyStatus = $('#llmKeyStatus');
|
|
963
963
|
const btnMcpTest = $('#btnMcpTest');
|
|
964
|
-
const
|
|
964
|
+
const btnHalfApp = $('#btnHalfApp');
|
|
965
965
|
const mcpPanel = $('#mcpPanel');
|
|
966
966
|
const btnMcpClose = $('#btnMcpClose');
|
|
967
967
|
const btnMcpClear = $('#btnMcpClear');
|
|
@@ -1033,6 +1033,34 @@ const updateContextStatus = () => {
|
|
|
1033
1033
|
sandboxContext.textContent = __SANDBOX__.pluginId + ':' + __SANDBOX__.appId;
|
|
1034
1034
|
};
|
|
1035
1035
|
|
|
1036
|
+
const entryCompactUrl = __SANDBOX__.entryCompactUrl || '';
|
|
1037
|
+
const hasCompactEntry = Boolean(entryCompactUrl);
|
|
1038
|
+
let currentSurface = 'full';
|
|
1039
|
+
|
|
1040
|
+
const updateSurfaceState = (surface) => {
|
|
1041
|
+
currentSurface = surface === 'compact' ? 'compact' : 'full';
|
|
1042
|
+
document.body.dataset.surface = currentSurface;
|
|
1043
|
+
if (btnHalfApp) {
|
|
1044
|
+
if (!hasCompactEntry) {
|
|
1045
|
+
btnHalfApp.disabled = true;
|
|
1046
|
+
btnHalfApp.title = 'plugin.json 未配置 entry.compact.path';
|
|
1047
|
+
delete btnHalfApp.dataset.active;
|
|
1048
|
+
} else {
|
|
1049
|
+
btnHalfApp.disabled = false;
|
|
1050
|
+
btnHalfApp.title = '';
|
|
1051
|
+
btnHalfApp.dataset.active = currentSurface === 'compact' ? '1' : '0';
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
if (host?.ui) host.ui.surface = currentSurface;
|
|
1055
|
+
};
|
|
1056
|
+
|
|
1057
|
+
const toggleCompactSurface = () => {
|
|
1058
|
+
if (!hasCompactEntry) return;
|
|
1059
|
+
updateSurfaceState(currentSurface === 'compact' ? 'full' : 'compact');
|
|
1060
|
+
loadAndMount().catch(renderError);
|
|
1061
|
+
updateInspectorIfOpen();
|
|
1062
|
+
};
|
|
1063
|
+
|
|
1036
1064
|
const isInspectorOpen = () => sandboxInspector && sandboxInspector.style.display === 'flex';
|
|
1037
1065
|
const isLlmPanelOpen = () => llmPanel && llmPanel.style.display === 'flex';
|
|
1038
1066
|
const isMcpPanelOpen = () => mcpPanel && mcpPanel.style.display === 'flex';
|
|
@@ -1140,13 +1168,8 @@ const refreshMcpConfigHint = async () => {
|
|
|
1140
1168
|
}
|
|
1141
1169
|
};
|
|
1142
1170
|
|
|
1143
|
-
const setMcpPanelOpen = (open
|
|
1171
|
+
const setMcpPanelOpen = (open) => {
|
|
1144
1172
|
if (!mcpPanel) return;
|
|
1145
|
-
if (mode) {
|
|
1146
|
-
mcpPanel.dataset.mode = mode;
|
|
1147
|
-
} else {
|
|
1148
|
-
delete mcpPanel.dataset.mode;
|
|
1149
|
-
}
|
|
1150
1173
|
mcpPanel.style.display = open ? 'flex' : 'none';
|
|
1151
1174
|
mcpPanel.setAttribute('aria-hidden', open ? 'false' : 'true');
|
|
1152
1175
|
if (open) {
|
|
@@ -1155,16 +1178,6 @@ const setMcpPanelOpen = (open, mode) => {
|
|
|
1155
1178
|
}
|
|
1156
1179
|
};
|
|
1157
1180
|
|
|
1158
|
-
const toggleMcpPanel = (mode) => {
|
|
1159
|
-
if (!mcpPanel) return;
|
|
1160
|
-
const currentMode = mcpPanel.dataset.mode || 'panel';
|
|
1161
|
-
if (isMcpPanelOpen() && currentMode === mode) {
|
|
1162
|
-
setMcpPanelOpen(false);
|
|
1163
|
-
return;
|
|
1164
|
-
}
|
|
1165
|
-
setMcpPanelOpen(true, mode);
|
|
1166
|
-
};
|
|
1167
|
-
|
|
1168
1181
|
const runMcpTest = async () => {
|
|
1169
1182
|
const sendBtn = btnMcpSend;
|
|
1170
1183
|
try {
|
|
@@ -1226,7 +1239,13 @@ const collectTokens = () => {
|
|
|
1226
1239
|
const readHostContext = () => {
|
|
1227
1240
|
if (!inspectorEnabled) return null;
|
|
1228
1241
|
if (typeof host?.context?.get === 'function') return host.context.get();
|
|
1229
|
-
return {
|
|
1242
|
+
return {
|
|
1243
|
+
pluginId: __SANDBOX__.pluginId,
|
|
1244
|
+
appId: __SANDBOX__.appId,
|
|
1245
|
+
theme: currentTheme,
|
|
1246
|
+
surface: currentSurface,
|
|
1247
|
+
bridge: { enabled: true },
|
|
1248
|
+
};
|
|
1230
1249
|
};
|
|
1231
1250
|
|
|
1232
1251
|
const readThemeInfo = () => ({
|
|
@@ -1305,8 +1324,8 @@ if (btnLlmClose) btnLlmClose.addEventListener('click', () => setLlmPanelOpen(fal
|
|
|
1305
1324
|
if (btnLlmRefresh) btnLlmRefresh.addEventListener('click', () => refreshLlmConfig());
|
|
1306
1325
|
if (btnLlmSave) btnLlmSave.addEventListener('click', () => saveLlmConfig());
|
|
1307
1326
|
if (btnLlmClear) btnLlmClear.addEventListener('click', () => saveLlmConfig({ clearKey: true }));
|
|
1308
|
-
if (btnMcpTest) btnMcpTest.addEventListener('click', () =>
|
|
1309
|
-
if (
|
|
1327
|
+
if (btnMcpTest) btnMcpTest.addEventListener('click', () => setMcpPanelOpen(!isMcpPanelOpen()));
|
|
1328
|
+
if (btnHalfApp) btnHalfApp.addEventListener('click', () => toggleCompactSurface());
|
|
1310
1329
|
if (btnMcpClose) btnMcpClose.addEventListener('click', () => setMcpPanelOpen(false));
|
|
1311
1330
|
if (btnMcpClear)
|
|
1312
1331
|
btnMcpClear.addEventListener('click', () => {
|
|
@@ -1499,7 +1518,15 @@ const getTheme = () => currentTheme || resolveTheme();
|
|
|
1499
1518
|
|
|
1500
1519
|
const host = {
|
|
1501
1520
|
bridge: { enabled: true },
|
|
1502
|
-
context: {
|
|
1521
|
+
context: {
|
|
1522
|
+
get: () => ({
|
|
1523
|
+
pluginId: __SANDBOX__.pluginId,
|
|
1524
|
+
appId: __SANDBOX__.appId,
|
|
1525
|
+
theme: getTheme(),
|
|
1526
|
+
surface: currentSurface,
|
|
1527
|
+
bridge: { enabled: true },
|
|
1528
|
+
}),
|
|
1529
|
+
},
|
|
1503
1530
|
theme: {
|
|
1504
1531
|
get: getTheme,
|
|
1505
1532
|
onChange: (listener) => {
|
|
@@ -1552,7 +1579,7 @@ const host = {
|
|
|
1552
1579
|
close: () => (setPanelOpen(false), { ok: true }),
|
|
1553
1580
|
toggle: () => (setPanelOpen(panel.style.display !== 'flex'), { ok: true }),
|
|
1554
1581
|
},
|
|
1555
|
-
ui: { navigate: (menu) => ({ ok: true, menu }) },
|
|
1582
|
+
ui: { navigate: (menu) => ({ ok: true, menu }), surface: 'full' },
|
|
1556
1583
|
chat: (() => {
|
|
1557
1584
|
const clone = (v) => JSON.parse(JSON.stringify(v));
|
|
1558
1585
|
|
|
@@ -1807,6 +1834,8 @@ const host = {
|
|
|
1807
1834
|
})(),
|
|
1808
1835
|
};
|
|
1809
1836
|
|
|
1837
|
+
updateSurfaceState('full');
|
|
1838
|
+
|
|
1810
1839
|
inspectorEnabled = true;
|
|
1811
1840
|
updateInspector();
|
|
1812
1841
|
|
|
@@ -1816,7 +1845,7 @@ async function loadAndMount() {
|
|
|
1816
1845
|
if (typeof dispose === 'function') { try { await dispose(); } catch {} dispose = null; }
|
|
1817
1846
|
container.textContent = '';
|
|
1818
1847
|
|
|
1819
|
-
const entryUrl = __SANDBOX__.entryUrl;
|
|
1848
|
+
const entryUrl = currentSurface === 'compact' && entryCompactUrl ? entryCompactUrl : __SANDBOX__.entryUrl;
|
|
1820
1849
|
const mod = await import(entryUrl + (entryUrl.includes('?') ? '&' : '?') + 't=' + Date.now());
|
|
1821
1850
|
const mount = mod?.mount || mod?.default?.mount || (typeof mod?.default === 'function' ? mod.default : null);
|
|
1822
1851
|
if (typeof mount !== 'function') throw new Error('module entry must export mount()');
|
|
@@ -1879,7 +1908,13 @@ export async function startSandboxServer({ pluginDir, port = 4399, appId = '' })
|
|
|
1879
1908
|
const entryAbs = resolveInsideDir(pluginDir, entryRel);
|
|
1880
1909
|
if (!isFile(entryAbs)) throw new Error(`module entry not found: ${entryRel}`);
|
|
1881
1910
|
|
|
1911
|
+
const entryCompactRel = String(app?.entry?.compact?.path || '').trim();
|
|
1882
1912
|
const entryUrl = `/plugin/${encodeURIComponent(entryRel).replaceAll('%2F', '/')}`;
|
|
1913
|
+
const entryCompactAbs = entryCompactRel ? resolveInsideDir(pluginDir, entryCompactRel) : '';
|
|
1914
|
+
const entryCompactUrl =
|
|
1915
|
+
entryCompactAbs && isFile(entryCompactAbs)
|
|
1916
|
+
? `/plugin/${encodeURIComponent(entryCompactRel).replaceAll('%2F', '/')}`
|
|
1917
|
+
: '';
|
|
1883
1918
|
|
|
1884
1919
|
let backendInstance = null;
|
|
1885
1920
|
let backendFactory = null;
|
|
@@ -2193,6 +2228,7 @@ export async function startSandboxServer({ pluginDir, port = 4399, appId = '' })
|
|
|
2193
2228
|
.replaceAll('__SANDBOX__.pluginId', JSON.stringify(ctxBase.pluginId))
|
|
2194
2229
|
.replaceAll('__SANDBOX__.appId', JSON.stringify(effectiveAppId))
|
|
2195
2230
|
.replaceAll('__SANDBOX__.entryUrl', JSON.stringify(entryUrl))
|
|
2231
|
+
.replaceAll('__SANDBOX__.entryCompactUrl', JSON.stringify(entryCompactUrl))
|
|
2196
2232
|
.replaceAll('__SANDBOX__.registryApp', JSON.stringify({ plugin: { id: ctxBase.pluginId }, id: effectiveAppId, entry: { type: 'module', url: entryUrl } }))
|
|
2197
2233
|
.replaceAll('__SANDBOX__.tokenNames', JSON.stringify(tokenNames))
|
|
2198
2234
|
.replaceAll('__SANDBOX__.paths', JSON.stringify(sandboxPaths));
|