@theruansilva/omp-web 2.0.1 → 2.2.1
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/dist/cli.js +83 -3
- package/dist/cli.js.map +1 -1
- package/dist/client/assets/CodeViewer-B61IQaP0.js +4 -0
- package/dist/client/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/client/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/client/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/client/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/client/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/client/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/client/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/client/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/client/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/client/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/client/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/client/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/client/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/client/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/client/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/client/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/client/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/client/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/client/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/client/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/client/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/client/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/client/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/client/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/client/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/client/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/client/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/client/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/client/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/client/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/client/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/client/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/client/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/client/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/client/assets/{TerminalPanel-Cb2CgFtQ.js → TerminalPanel-BcxMZQKk.js} +8 -8
- package/dist/client/assets/{UnifiedDiffViewer-Db5Yxwri.js → UnifiedDiffViewer-BnFQlZDg.js} +2 -2
- package/dist/client/assets/abnfDiagram-O67JEVCF-BCWHgm_-.js +1 -0
- package/dist/client/assets/arc-BUpZciy9.js +1 -0
- package/dist/client/assets/architectureDiagram-NJMV4G6O-CVWCwiqh.js +36 -0
- package/dist/client/assets/blockDiagram-BEXU5L5S-W5WSJa_J.js +140 -0
- package/dist/client/assets/c4Diagram-YGBWAQC7-BWpacECA.js +38 -0
- package/dist/client/assets/channel-ChkqWR3Z.js +1 -0
- package/dist/client/assets/chunk-2Q5K7J3B-D0TV4T28.js +1 -0
- package/dist/client/assets/chunk-3FUC2YCW-BlkJ2B9v.js +2 -0
- package/dist/client/assets/chunk-5VM5RSS4-LRh3HbZr.js +15 -0
- package/dist/client/assets/chunk-GTNCS2PH-CBiTovUf.js +88 -0
- package/dist/client/assets/chunk-GWA4HPMP-Dnu3R9yI.js +1 -0
- package/dist/client/assets/chunk-JWPE2WC7-C2yjQs6c.js +1 -0
- package/dist/client/assets/chunk-NETBCI7D-Dxos4L3P.js +1 -0
- package/dist/client/assets/chunk-WEXAMYUT-DrLvxPom.js +1 -0
- package/dist/client/assets/chunk-XXDRQBXY-Cub_nego.js +1 -0
- package/dist/client/assets/classDiagram-v2-NBCMYWYE-CIe2lhk7.js +217 -0
- package/dist/client/assets/cose-bilkent-JH36ORCC-DOGZoTZg.js +1 -0
- package/dist/client/assets/cynefin-OW5HDTMX-DXF0a63d.js +166 -0
- package/dist/client/assets/cynefinDiagram-VND7K2PF-C_Qmhc8V.js +62 -0
- package/dist/client/assets/cytoscape.esm-BB4DxJjf.js +321 -0
- package/dist/client/assets/dagre-6A5THRUB-CEhDrD4X.js +4 -0
- package/dist/client/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/client/assets/diagram-22UHCM2B-CgN81sDZ.js +200 -0
- package/dist/client/assets/diagram-3UASUU5V-Dk1gOSew.js +24 -0
- package/dist/client/assets/diagram-ATOU4E4O-C_tcqhr3.js +3 -0
- package/dist/client/assets/diagram-CDSNMT55-Dj-WM3vk.js +30 -0
- package/dist/client/assets/diagram-MLGK6HIB-CDowox_d.js +24 -0
- package/dist/client/assets/diagram-MPIPVDR6-CaThzNCZ.js +41 -0
- package/dist/client/assets/ebnfDiagram-ZINNZB2B-BZbLdwcz.js +1 -0
- package/dist/client/assets/elk-276RUBZZ-DGku1nk-.js +27 -0
- package/dist/client/assets/erDiagram-OPXOYQCR-D0nJ53i7.js +99 -0
- package/dist/client/assets/flowDiagram-KWPJA3E3-DeB8-O7Y.js +213 -0
- package/dist/client/assets/ganttDiagram-FUAMR5RP-CBcW8sXy.js +292 -0
- package/dist/client/assets/gitGraphDiagram-X574FWY7-CC-b8FLq.js +106 -0
- package/dist/client/assets/graph-D8UmR1vK.js +1 -0
- package/dist/client/assets/index-CyN73uMY.js +5664 -0
- package/dist/client/assets/{index-DGBYb2j9.css → index-DSGiUJZL.css} +1 -1
- package/dist/client/assets/infoDiagram-VRGFBTTK-DL3QMN01.js +2 -0
- package/dist/client/assets/init-Gi6I4Gst.js +1 -0
- package/dist/client/assets/ishikawaDiagram-OU5B5YK6-Brt56LtP.js +70 -0
- package/dist/client/assets/journeyDiagram-ZHPQQLJL-Df8VwbDr.js +139 -0
- package/dist/client/assets/kanban-definition-PNTS6WVX-cVbdWfVg.js +89 -0
- package/dist/client/assets/katex-HP8lGamR.js +257 -0
- package/dist/client/assets/linear-DugbH7BO.js +1 -0
- package/dist/client/assets/mindmap-definition-NLK3R4M7-BDqwqJMJ.js +96 -0
- package/dist/client/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/client/assets/pegDiagram-GJSIUBJH-w6CrSKt0.js +1 -0
- package/dist/client/assets/pieDiagram-5QR66LMP-D0utByOI.js +39 -0
- package/dist/client/assets/quadrantDiagram-O4NWA36T-DIAIplx2.js +7 -0
- package/dist/client/assets/railroadDiagram-XR7U4H2S-BX9P-jy7.js +1 -0
- package/dist/client/assets/requirementDiagram-PLB6GJNP-C55JlmRI.js +84 -0
- package/dist/client/assets/sankeyDiagram-IPEJSGJF-VeHnKI-a.js +40 -0
- package/dist/client/assets/sequenceDiagram-PO4LG4MO-CTUoXviF.js +169 -0
- package/dist/client/assets/sizeCapture-INFHLROL-DBKjJDUZ.js +1 -0
- package/dist/client/assets/stateDiagram-v2-GCMORJYK-DzonJh3D.js +291 -0
- package/dist/client/assets/swimlanes-2SLR337P-Cnsd5mvJ.js +1 -0
- package/dist/client/assets/swimlanesDiagram-TC7HE7FX-iyBCc4Xc.js +8 -0
- package/dist/client/assets/timeline-definition-EJHVYXUP-C9nhaxck.js +120 -0
- package/dist/client/assets/usecaseDiagram-POWQR4AR-jfXBWSzR.js +370 -0
- package/dist/client/assets/vendor-editor-core-D-5q2tVX.js +49 -0
- package/dist/client/assets/vendor-editor-languages-B6WRt0aC.js +26 -0
- package/dist/client/assets/vennDiagram-UO4OBE2U-BigR6haV.js +34 -0
- package/dist/client/assets/wardleyDiagram-VNRHLVJA-BXJexKTM.js +78 -0
- package/dist/client/assets/xychartDiagram-PMCCYNJV-HL5cuxsZ.js +7 -0
- package/dist/client/index.html +4 -4
- package/dist/config.js +11 -12
- package/dist/config.js.map +1 -1
- package/dist/omp-web-plugins/mcps/mcpsLogic.js +78 -0
- package/dist/omp-web-plugins/mcps/mcpsPanelElement.js +417 -0
- package/dist/omp-web-plugins/mcps/omp-web-plugin.js +45 -0
- package/dist/omp-web-plugins/mcps/package.json +9 -0
- package/dist/omp-web-plugins/mcps/types.js +2 -0
- package/dist/plugin-api.d.ts +1 -0
- package/dist/server/app.js +24 -1
- package/dist/server/app.js.map +1 -1
- package/dist/server/configRoutes.js +6 -0
- package/dist/server/configRoutes.js.map +1 -1
- package/dist/server/index.js +0 -0
- package/dist/server/machines/machineService.js +3 -0
- package/dist/server/machines/machineService.js.map +1 -1
- package/dist/server/mcpRoutes.js +73 -0
- package/dist/server/mcpRoutes.js.map +1 -0
- package/dist/server/push/PushNotificationService.js +16 -3
- package/dist/server/push/PushNotificationService.js.map +1 -1
- package/dist/server/security.js +172 -0
- package/dist/server/security.js.map +1 -0
- package/dist/server/sessiond/sessionProxyRoutes.js +11 -5
- package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
- package/dist/server/sessiond.js +28 -1
- package/dist/server/sessiond.js.map +1 -1
- package/dist/server/sessions/piAgentSession.js +2 -1
- package/dist/server/sessions/piAgentSession.js.map +1 -1
- package/dist/server/sessions/piSessionService.js +168 -16
- package/dist/server/sessions/piSessionService.js.map +1 -1
- package/dist/server/sessions/schedulePrompt/scheduler.js +17 -13
- package/dist/server/sessions/schedulePrompt/scheduler.js.map +1 -1
- package/dist/server/sessions/schedulePrompt/tool.js +13 -1
- package/dist/server/sessions/schedulePrompt/tool.js.map +1 -1
- package/dist/server/sessions/sessionEventMapper.js +36 -2
- package/dist/server/sessions/sessionEventMapper.js.map +1 -1
- package/dist/server/sessions/sessionRoutes.js +3 -0
- package/dist/server/sessions/sessionRoutes.js.map +1 -1
- package/dist/server/workspaceExplorerRoutes.js +16 -9
- package/dist/server/workspaceExplorerRoutes.js.map +1 -1
- package/dist/server/workspaces/fileContentService.js +9 -4
- package/dist/server/workspaces/fileContentService.js.map +1 -1
- package/dist/server/workspaces/imagePreviewService.js +63 -13
- package/dist/server/workspaces/imagePreviewService.js.map +1 -1
- package/dist/shared/apiTypes.d.ts +18 -1
- package/dist/shared/federatedRoutes.js +2 -0
- package/dist/shared/federatedRoutes.js.map +1 -1
- package/docs/config.md +16 -1
- package/package.json +5 -1
- package/dist/client/assets/CodeViewer-Mp4aTsTY.js +0 -4
- package/dist/client/assets/index-Df4Ex27j.js +0 -4427
- package/dist/client/assets/vendor-editor-core-D9EJm1dE.js +0 -10
- package/dist/client/assets/vendor-editor-languages-N6dcxgRO.js +0 -26
- package/dist/client-react/assets/index-BQ6zLLfz.js +0 -51
- package/dist/client-react/assets/index-Befs78HG.css +0 -1
- package/dist/client-react/index.html +0 -16
- package/dist/docker/piWebDockerCommandPlan.js +0 -211
- package/dist/docker/piWebDockerCommandPlan.js.map +0 -1
- package/dist/pi-web-plugins/info/package.json +0 -9
- package/dist/pi-web-plugins/info/pi-web-plugin.js +0 -51
- package/dist/pi-web-plugins/schedule-prompts/package.json +0 -9
- package/dist/pi-web-plugins/schedule-prompts/pi-web-plugin.js +0 -43
- package/dist/pi-web-plugins/schedule-prompts/schedulePromptsPanelElement.js +0 -226
- package/dist/pi-web-plugins/schedule-prompts/types.js +0 -2
- package/dist/pi-web-plugins/updates/package.json +0 -9
- package/dist/pi-web-plugins/updates/pi-web-plugin.js +0 -173
- package/dist/pi-web-plugins/updates/updatesLogic.js +0 -97
- package/dist/piWebVersionReport.js +0 -225
- package/dist/piWebVersionReport.js.map +0 -1
- package/dist/server/diagnostics/nodePtySpawnHelper.js +0 -130
- package/dist/server/diagnostics/nodePtySpawnHelper.js.map +0 -1
- package/dist/server/piWebPluginService.js +0 -283
- package/dist/server/piWebPluginService.js.map +0 -1
- package/dist/server/piWebStatus.js +0 -602
- package/dist/server/piWebStatus.js.map +0 -1
- package/dist/server/piWebStatusCache.js +0 -32
- package/dist/server/piWebStatusCache.js.map +0 -1
- package/dist/server/workspaces/projectPiWebConfig.js +0 -61
- package/dist/server/workspaces/projectPiWebConfig.js.map +0 -1
- package/dist/shared/piWebStatusParsing.js +0 -102
- package/dist/shared/piWebStatusParsing.js.map +0 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Generated from omp-web-plugins/mcps/mcpsLogic.ts. Do not edit directly.
|
|
2
|
+
export const PROJECT_MCP_FILES = [".mcp.json", "mcp.json", ".omp/mcp.json"];
|
|
3
|
+
export function isMcpConfigFile(value) {
|
|
4
|
+
return (typeof value === "object" &&
|
|
5
|
+
value !== null &&
|
|
6
|
+
"mcpServers" in value &&
|
|
7
|
+
typeof value.mcpServers === "object" &&
|
|
8
|
+
value.mcpServers !== null);
|
|
9
|
+
}
|
|
10
|
+
export function parseMcpConfigFile(raw) {
|
|
11
|
+
try {
|
|
12
|
+
const parsed = JSON.parse(raw);
|
|
13
|
+
if (isMcpConfigFile(parsed)) {
|
|
14
|
+
return parsed;
|
|
15
|
+
}
|
|
16
|
+
return { mcpServers: {} };
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return { mcpServers: {} };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function formatTransport(config) {
|
|
23
|
+
if (config.type !== undefined)
|
|
24
|
+
return config.type;
|
|
25
|
+
if (config.url !== undefined)
|
|
26
|
+
return "http";
|
|
27
|
+
return "stdio";
|
|
28
|
+
}
|
|
29
|
+
export function formatCommandOrUrl(config) {
|
|
30
|
+
if (config.url !== undefined && config.url !== "") {
|
|
31
|
+
return config.url;
|
|
32
|
+
}
|
|
33
|
+
const cmd = config.command ?? "";
|
|
34
|
+
const args = config.args?.join(" ") ?? "";
|
|
35
|
+
return [cmd, args].filter(Boolean).join(" ");
|
|
36
|
+
}
|
|
37
|
+
export function isServerEnabled(config) {
|
|
38
|
+
return config.enabled !== false;
|
|
39
|
+
}
|
|
40
|
+
export function countActiveServers(state) {
|
|
41
|
+
let count = 0;
|
|
42
|
+
for (const server of Object.values(state.projectServers)) {
|
|
43
|
+
if (isServerEnabled(server))
|
|
44
|
+
count++;
|
|
45
|
+
}
|
|
46
|
+
for (const server of Object.values(state.globalServers)) {
|
|
47
|
+
if (isServerEnabled(server))
|
|
48
|
+
count++;
|
|
49
|
+
}
|
|
50
|
+
return count;
|
|
51
|
+
}
|
|
52
|
+
export function countFailedServers(state) {
|
|
53
|
+
if (!state.checkResults)
|
|
54
|
+
return 0;
|
|
55
|
+
let count = 0;
|
|
56
|
+
for (const check of Object.values(state.checkResults)) {
|
|
57
|
+
if (check.status === "failed")
|
|
58
|
+
count++;
|
|
59
|
+
}
|
|
60
|
+
return count;
|
|
61
|
+
}
|
|
62
|
+
export function toggleServerInConfig(raw, serverName) {
|
|
63
|
+
try {
|
|
64
|
+
const parsed = JSON.parse(raw);
|
|
65
|
+
if (isMcpConfigFile(parsed) && parsed.mcpServers !== undefined) {
|
|
66
|
+
const servers = parsed.mcpServers;
|
|
67
|
+
const target = servers[serverName];
|
|
68
|
+
if (target !== undefined) {
|
|
69
|
+
target.enabled = !isServerEnabled(target);
|
|
70
|
+
return JSON.stringify(parsed, null, 2) + "\n";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Return original on parse error
|
|
76
|
+
}
|
|
77
|
+
return raw;
|
|
78
|
+
}
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
// Generated from omp-web-plugins/mcps/mcpsPanelElement.ts. Do not edit directly.
|
|
2
|
+
import { countActiveServers, countFailedServers, formatCommandOrUrl, formatTransport, isServerEnabled, parseMcpConfigFile, PROJECT_MCP_FILES, toggleServerInConfig, } from "./mcpsLogic.js";
|
|
3
|
+
export const mcpsPanelTagName = "omp-web-mcps-panel";
|
|
4
|
+
const panelCache = new Map();
|
|
5
|
+
export function defineMcpsPanelElement() {
|
|
6
|
+
if (!customElements.get(mcpsPanelTagName)) {
|
|
7
|
+
customElements.define(mcpsPanelTagName, OmpWebMcpsPanel);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export function mcpsBadge(context) {
|
|
11
|
+
const cached = panelCache.get(cacheKeyForContext(context));
|
|
12
|
+
if (cached === undefined || "kind" in cached)
|
|
13
|
+
return undefined;
|
|
14
|
+
const count = countActiveServers(cached);
|
|
15
|
+
return count > 0 ? String(count) : undefined;
|
|
16
|
+
}
|
|
17
|
+
class OmpWebMcpsPanel extends HTMLElement {
|
|
18
|
+
contextValue;
|
|
19
|
+
root;
|
|
20
|
+
pollTimer;
|
|
21
|
+
currentKey;
|
|
22
|
+
isChecking = false;
|
|
23
|
+
constructor() {
|
|
24
|
+
super();
|
|
25
|
+
this.root = this.attachShadow({ mode: "open" });
|
|
26
|
+
}
|
|
27
|
+
set context(value) {
|
|
28
|
+
const prevKey = this.currentKey;
|
|
29
|
+
const newKey = value ? cacheKeyForContext(value) : undefined;
|
|
30
|
+
this.contextValue = value;
|
|
31
|
+
this.currentKey = newKey;
|
|
32
|
+
if (value && newKey !== prevKey) {
|
|
33
|
+
void this.loadServers(value);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
this.render();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
connectedCallback() {
|
|
40
|
+
this.render();
|
|
41
|
+
this.pollTimer = setInterval(() => {
|
|
42
|
+
if (this.contextValue)
|
|
43
|
+
void this.loadServers(this.contextValue, false);
|
|
44
|
+
}, 60000);
|
|
45
|
+
}
|
|
46
|
+
disconnectedCallback() {
|
|
47
|
+
if (this.pollTimer !== undefined) {
|
|
48
|
+
clearInterval(this.pollTimer);
|
|
49
|
+
this.pollTimer = undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async loadServers(context, forceCheck = false) {
|
|
53
|
+
const key = cacheKeyForContext(context);
|
|
54
|
+
if (this.isChecking)
|
|
55
|
+
return;
|
|
56
|
+
let projectFile;
|
|
57
|
+
let projectServers = {};
|
|
58
|
+
for (const fileName of PROJECT_MCP_FILES) {
|
|
59
|
+
try {
|
|
60
|
+
const response = await context.files.readFile(fileName);
|
|
61
|
+
const content = typeof response.content === "string"
|
|
62
|
+
? response.content
|
|
63
|
+
: new TextDecoder().decode(response.content);
|
|
64
|
+
const parsed = parseMcpConfigFile(content);
|
|
65
|
+
if (parsed.mcpServers !== undefined) {
|
|
66
|
+
projectFile = fileName;
|
|
67
|
+
projectServers = parsed.mcpServers;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Continue checking next candidate file
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
let globalPath;
|
|
76
|
+
let globalServers = {};
|
|
77
|
+
try {
|
|
78
|
+
const response = await context.apiFetch("/mcps");
|
|
79
|
+
if (response.ok) {
|
|
80
|
+
const data = (await response.json());
|
|
81
|
+
if (data.servers) {
|
|
82
|
+
globalServers = data.servers;
|
|
83
|
+
globalPath = data.path;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Ignore network errors fetching global servers
|
|
89
|
+
}
|
|
90
|
+
const cached = panelCache.get(key);
|
|
91
|
+
const prevCheckResults = cached && !("kind" in cached) ? cached.checkResults : undefined;
|
|
92
|
+
const shouldCheck = forceCheck || prevCheckResults === undefined;
|
|
93
|
+
const state = {
|
|
94
|
+
projectFile,
|
|
95
|
+
projectServers,
|
|
96
|
+
globalPath,
|
|
97
|
+
globalServers,
|
|
98
|
+
checkResults: prevCheckResults,
|
|
99
|
+
isChecking: shouldCheck,
|
|
100
|
+
lastLoaded: new Date().toISOString(),
|
|
101
|
+
};
|
|
102
|
+
panelCache.set(key, state);
|
|
103
|
+
this.render();
|
|
104
|
+
if (!shouldCheck)
|
|
105
|
+
return;
|
|
106
|
+
// Probe server connection status
|
|
107
|
+
const allServers = {};
|
|
108
|
+
for (const [name, config] of Object.entries(projectServers)) {
|
|
109
|
+
if (isServerEnabled(config))
|
|
110
|
+
allServers[name] = config;
|
|
111
|
+
}
|
|
112
|
+
for (const [name, config] of Object.entries(globalServers)) {
|
|
113
|
+
if (isServerEnabled(config))
|
|
114
|
+
allServers[name] = config;
|
|
115
|
+
}
|
|
116
|
+
if (Object.keys(allServers).length > 0) {
|
|
117
|
+
this.isChecking = true;
|
|
118
|
+
try {
|
|
119
|
+
const checkRes = await context.apiFetch("/mcps/check", {
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: { "content-type": "application/json" },
|
|
122
|
+
body: JSON.stringify({ servers: allServers }),
|
|
123
|
+
});
|
|
124
|
+
if (checkRes.ok) {
|
|
125
|
+
const checkData = (await checkRes.json());
|
|
126
|
+
state.checkResults = checkData.results;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Ignore check probe errors
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
this.isChecking = false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
state.isChecking = false;
|
|
137
|
+
panelCache.set(key, state);
|
|
138
|
+
this.render();
|
|
139
|
+
}
|
|
140
|
+
render() {
|
|
141
|
+
const context = this.contextValue;
|
|
142
|
+
if (context === undefined) {
|
|
143
|
+
this.root.innerHTML = `${panelStyles()}<section class="empty">Select a workspace.</section>`;
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const key = cacheKeyForContext(context);
|
|
147
|
+
const cached = panelCache.get(key);
|
|
148
|
+
const state = cached ?? { kind: "loading" };
|
|
149
|
+
const isLoading = "kind" in state && state.kind === "loading";
|
|
150
|
+
let activeCount = 0;
|
|
151
|
+
let failedCount = 0;
|
|
152
|
+
if (!("kind" in state)) {
|
|
153
|
+
activeCount = countActiveServers(state);
|
|
154
|
+
failedCount = countFailedServers(state);
|
|
155
|
+
}
|
|
156
|
+
this.root.innerHTML = `
|
|
157
|
+
${panelStyles()}
|
|
158
|
+
<section class="toolbar">
|
|
159
|
+
<div class="toolbar-title">
|
|
160
|
+
<strong>MCP Servers</strong>
|
|
161
|
+
${!isLoading ? `
|
|
162
|
+
<span class="badge ${activeCount > 0 ? "active" : ""}">
|
|
163
|
+
${activeCount} active
|
|
164
|
+
${failedCount > 0 ? `<span class="badge-failed">· ${failedCount} failed</span>` : ""}
|
|
165
|
+
</span>
|
|
166
|
+
` : ""}
|
|
167
|
+
</div>
|
|
168
|
+
<button class="secondary" data-refresh ${isLoading || this.isChecking ? "disabled" : ""}>Refresh</button>
|
|
169
|
+
</section>
|
|
170
|
+
<section class="viewer">
|
|
171
|
+
${this.renderContent(state)}
|
|
172
|
+
</section>
|
|
173
|
+
`;
|
|
174
|
+
this.attachEventListeners(context, state);
|
|
175
|
+
}
|
|
176
|
+
renderContent(state) {
|
|
177
|
+
if ("kind" in state) {
|
|
178
|
+
if (state.kind === "loading") {
|
|
179
|
+
return `<p class="muted">Loading MCP configuration…</p>`;
|
|
180
|
+
}
|
|
181
|
+
return `<div class="status error">${escapeHtml(state.message)}</div>`;
|
|
182
|
+
}
|
|
183
|
+
const hasProjectServers = Object.keys(state.projectServers).length > 0;
|
|
184
|
+
let html = "";
|
|
185
|
+
// Project Section
|
|
186
|
+
html += `
|
|
187
|
+
<section class="server-group">
|
|
188
|
+
<div class="group-header">
|
|
189
|
+
<span class="group-title">Workspace Servers</span>
|
|
190
|
+
${state.projectFile !== undefined ? `<span class="group-path">${escapeHtml(state.projectFile)}</span>` : ""}
|
|
191
|
+
</div>
|
|
192
|
+
`;
|
|
193
|
+
if (hasProjectServers) {
|
|
194
|
+
html += `<div class="servers-list">`;
|
|
195
|
+
for (const [name, config] of Object.entries(state.projectServers)) {
|
|
196
|
+
html += this.renderServerRow(name, config, "project", state);
|
|
197
|
+
}
|
|
198
|
+
html += `</div>`;
|
|
199
|
+
}
|
|
200
|
+
else if (state.projectFile !== undefined) {
|
|
201
|
+
html += `<p class="muted"><code>${escapeHtml(state.projectFile)}</code> exists but defines no servers.</p>`;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
html += `
|
|
205
|
+
<div class="no-file-box">
|
|
206
|
+
<p class="muted">No project MCP configuration found (.mcp.json).</p>
|
|
207
|
+
<button data-create-project-file class="secondary">+ Create .mcp.json</button>
|
|
208
|
+
</div>
|
|
209
|
+
`;
|
|
210
|
+
}
|
|
211
|
+
html += `</section>`;
|
|
212
|
+
// Global Section
|
|
213
|
+
const hasGlobalServers = Object.keys(state.globalServers).length > 0;
|
|
214
|
+
html += `
|
|
215
|
+
<section class="server-group">
|
|
216
|
+
<div class="group-header">
|
|
217
|
+
<span class="group-title">Global Servers</span>
|
|
218
|
+
${state.globalPath !== undefined ? `<span class="group-path">${escapeHtml(state.globalPath)}</span>` : ""}
|
|
219
|
+
</div>
|
|
220
|
+
`;
|
|
221
|
+
if (hasGlobalServers) {
|
|
222
|
+
html += `<div class="servers-list">`;
|
|
223
|
+
for (const [name, config] of Object.entries(state.globalServers)) {
|
|
224
|
+
html += this.renderServerRow(name, config, "global", state);
|
|
225
|
+
}
|
|
226
|
+
html += `</div>`;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
html += `<p class="muted">No global MCP servers configured.</p>`;
|
|
230
|
+
}
|
|
231
|
+
html += `</section>`;
|
|
232
|
+
// Quick Command Shortcuts
|
|
233
|
+
html += `
|
|
234
|
+
<section class="shortcuts-group">
|
|
235
|
+
<span class="group-title">Oh My Pi Commands</span>
|
|
236
|
+
<div class="shortcut-buttons">
|
|
237
|
+
<button data-prompt="/mcp list" class="secondary">/mcp list</button>
|
|
238
|
+
<button data-prompt="/mcp reload" class="secondary">/mcp reload</button>
|
|
239
|
+
<button data-prompt="/mcp add " class="secondary">+ /mcp add</button>
|
|
240
|
+
</div>
|
|
241
|
+
</section>
|
|
242
|
+
`;
|
|
243
|
+
return html;
|
|
244
|
+
}
|
|
245
|
+
renderServerRow(name, config, scope, state) {
|
|
246
|
+
const enabled = isServerEnabled(config);
|
|
247
|
+
const transport = formatTransport(config);
|
|
248
|
+
const target = formatCommandOrUrl(config);
|
|
249
|
+
const check = state.checkResults?.[name];
|
|
250
|
+
const isChecking = state.isChecking === true && enabled && check === undefined;
|
|
251
|
+
let statusDotClass = enabled ? "active" : "disabled";
|
|
252
|
+
let statusText = enabled ? "Active" : "Disabled";
|
|
253
|
+
let statusTextClass = enabled ? "" : "disabled";
|
|
254
|
+
if (!enabled) {
|
|
255
|
+
statusDotClass = "disabled";
|
|
256
|
+
statusText = "Disabled";
|
|
257
|
+
statusTextClass = "disabled";
|
|
258
|
+
}
|
|
259
|
+
else if (isChecking) {
|
|
260
|
+
statusDotClass = "checking";
|
|
261
|
+
statusText = "Connecting…";
|
|
262
|
+
statusTextClass = "checking";
|
|
263
|
+
}
|
|
264
|
+
else if (check?.status === "connected") {
|
|
265
|
+
statusDotClass = "connected";
|
|
266
|
+
statusText = check.serverInfo?.version ? `Connected (v${check.serverInfo.version})` : "Connected";
|
|
267
|
+
statusTextClass = "connected";
|
|
268
|
+
}
|
|
269
|
+
else if (check?.status === "failed") {
|
|
270
|
+
statusDotClass = "failed";
|
|
271
|
+
statusText = "Connection failed";
|
|
272
|
+
statusTextClass = "failed";
|
|
273
|
+
}
|
|
274
|
+
return `
|
|
275
|
+
<article class="server-row ${enabled ? "enabled" : "disabled"} ${check?.status === "failed" ? "server-failed" : ""}">
|
|
276
|
+
<div class="server-main">
|
|
277
|
+
<div class="server-header">
|
|
278
|
+
<span class="status-dot ${statusDotClass}"></span>
|
|
279
|
+
<strong class="server-name">${escapeHtml(name)}</strong>
|
|
280
|
+
<span class="tag transport">${escapeHtml(transport)}</span>
|
|
281
|
+
<span class="status-text ${statusTextClass}">${escapeHtml(statusText)}</span>
|
|
282
|
+
</div>
|
|
283
|
+
${target !== "" ? `<div class="server-target"><code>${escapeHtml(target)}</code></div>` : ""}
|
|
284
|
+
${config.description !== undefined ? `<div class="server-desc">${escapeHtml(config.description)}</div>` : ""}
|
|
285
|
+
${check?.status === "failed" && check.error ? `
|
|
286
|
+
<div class="server-error-banner">
|
|
287
|
+
<span class="error-icon">⚠️</span>
|
|
288
|
+
<span class="error-msg">${escapeHtml(check.error)}</span>
|
|
289
|
+
</div>
|
|
290
|
+
` : ""}
|
|
291
|
+
</div>
|
|
292
|
+
<div class="server-actions">
|
|
293
|
+
${scope === "project" ? `
|
|
294
|
+
<button
|
|
295
|
+
data-toggle-server="${escapeAttr(name)}"
|
|
296
|
+
class="${enabled ? "secondary" : "accent"}"
|
|
297
|
+
>
|
|
298
|
+
${enabled ? "Disable" : "Enable"}
|
|
299
|
+
</button>
|
|
300
|
+
` : `
|
|
301
|
+
<span class="badge-readonly">Global</span>
|
|
302
|
+
`}
|
|
303
|
+
</div>
|
|
304
|
+
</article>
|
|
305
|
+
`;
|
|
306
|
+
}
|
|
307
|
+
attachEventListeners(context, state) {
|
|
308
|
+
this.root.querySelector("button[data-refresh]")?.addEventListener("click", () => {
|
|
309
|
+
void this.loadServers(context, true);
|
|
310
|
+
});
|
|
311
|
+
this.root.querySelector("button[data-create-project-file]")?.addEventListener("click", async () => {
|
|
312
|
+
const initial = {
|
|
313
|
+
$schema: "https://raw.githubusercontent.com/can1357/oh-my-pi/main/packages/coding-agent/src/config/mcp-schema.json",
|
|
314
|
+
mcpServers: {},
|
|
315
|
+
};
|
|
316
|
+
await context.files.writeFile(".mcp.json", JSON.stringify(initial, null, 2) + "\n");
|
|
317
|
+
void this.loadServers(context, true);
|
|
318
|
+
});
|
|
319
|
+
this.root.querySelectorAll("button[data-toggle-server]").forEach((btn) => {
|
|
320
|
+
btn.addEventListener("click", async () => {
|
|
321
|
+
const serverName = btn.getAttribute("data-toggle-server");
|
|
322
|
+
if (!serverName || "kind" in state || !state.projectFile)
|
|
323
|
+
return;
|
|
324
|
+
try {
|
|
325
|
+
const res = await context.files.readFile(state.projectFile);
|
|
326
|
+
const currentContent = typeof res.content === "string"
|
|
327
|
+
? res.content
|
|
328
|
+
: new TextDecoder().decode(res.content);
|
|
329
|
+
const updatedContent = toggleServerInConfig(currentContent, serverName);
|
|
330
|
+
await context.files.writeFile(state.projectFile, updatedContent);
|
|
331
|
+
void this.loadServers(context, true);
|
|
332
|
+
}
|
|
333
|
+
catch (err) {
|
|
334
|
+
console.error("Failed to toggle MCP server in configuration:", err);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
this.root.querySelectorAll("button[data-prompt]").forEach((btn) => {
|
|
339
|
+
btn.addEventListener("click", () => {
|
|
340
|
+
const promptText = btn.getAttribute("data-prompt");
|
|
341
|
+
if (promptText) {
|
|
342
|
+
context.prompt.insertText(promptText);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
function cacheKeyForContext(context) {
|
|
349
|
+
return `${context.machine.id}:${context.workspace.projectId}:${context.workspace.id}`;
|
|
350
|
+
}
|
|
351
|
+
function escapeHtml(value) {
|
|
352
|
+
return String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
353
|
+
}
|
|
354
|
+
function escapeAttr(value) {
|
|
355
|
+
return escapeHtml(value).replaceAll('"', """);
|
|
356
|
+
}
|
|
357
|
+
function panelStyles() {
|
|
358
|
+
return `
|
|
359
|
+
<style>
|
|
360
|
+
:host { display: contents; }
|
|
361
|
+
.toolbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 12px; border-bottom: 1px solid var(--pi-border-muted); }
|
|
362
|
+
.toolbar-title { display: flex; align-items: center; gap: 8px; }
|
|
363
|
+
.viewer { box-sizing: border-box; min-height: 0; overflow: auto; padding: 12px; display: flex; flex-direction: column; gap: 16px; }
|
|
364
|
+
.server-group { display: flex; flex-direction: column; gap: 8px; }
|
|
365
|
+
.group-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
366
|
+
.group-title { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--pi-muted); }
|
|
367
|
+
.group-path { font-size: 11px; color: var(--pi-muted); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
368
|
+
.servers-list { display: grid; gap: 8px; }
|
|
369
|
+
.server-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; border: 1px solid var(--pi-border); border-radius: 8px; background: var(--pi-surface); padding: 10px 12px; }
|
|
370
|
+
.server-row.disabled { opacity: 0.65; }
|
|
371
|
+
.server-row.server-failed { border-color: rgba(239, 68, 68, 0.4); background: rgba(239, 68, 68, 0.04); }
|
|
372
|
+
.server-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1; }
|
|
373
|
+
.server-header { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
|
|
374
|
+
.server-name { font-size: 13px; color: var(--pi-text); }
|
|
375
|
+
.status-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--pi-muted); flex-shrink: 0; }
|
|
376
|
+
.status-dot.active { background: #22c55e; }
|
|
377
|
+
.status-dot.connected { background: #22c55e; }
|
|
378
|
+
.status-dot.checking { background: #eab308; animation: pulse 1.5s infinite; }
|
|
379
|
+
.status-dot.failed { background: #ef4444; }
|
|
380
|
+
.status-dot.disabled { background: var(--pi-muted); opacity: 0.5; }
|
|
381
|
+
.status-text { font-size: 11px; color: var(--pi-muted); }
|
|
382
|
+
.status-text.connected { color: #22c55e; }
|
|
383
|
+
.status-text.checking { color: #eab308; }
|
|
384
|
+
.status-text.failed { color: #ef4444; font-weight: 500; }
|
|
385
|
+
.status-text.disabled { color: var(--pi-muted); opacity: 0.7; }
|
|
386
|
+
.tag { font-size: 10px; padding: 1px 5px; border-radius: 4px; border: 1px solid var(--pi-border-muted); color: var(--pi-muted); font-family: ui-monospace, monospace; }
|
|
387
|
+
.tag.transport { color: var(--pi-accent); border-color: var(--pi-accent-border); }
|
|
388
|
+
.server-target { font-size: 11px; color: var(--pi-text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
389
|
+
.server-target code { border: none; background: transparent; padding: 0; color: inherit; }
|
|
390
|
+
.server-desc { font-size: 11px; color: var(--pi-muted); }
|
|
391
|
+
.server-error-banner { display: flex; align-items: flex-start; gap: 6px; margin-top: 6px; padding: 6px 10px; border-radius: 6px; background: rgba(239, 68, 68, 0.08); border: 1px solid rgba(239, 68, 68, 0.25); font-size: 11px; color: #f87171; line-height: 1.4; word-break: break-word; }
|
|
392
|
+
.error-icon { flex-shrink: 0; font-size: 12px; line-height: 1; }
|
|
393
|
+
.error-msg { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
394
|
+
.server-actions { display: flex; align-items: center; gap: 6px; }
|
|
395
|
+
.badge { font-size: 11px; padding: 2px 7px; border-radius: 10px; background: var(--pi-surface); border: 1px solid var(--pi-border); color: var(--pi-muted); }
|
|
396
|
+
.badge.active { border-color: #22c55e44; color: #22c55e; }
|
|
397
|
+
.badge-failed { color: #ef4444; font-weight: 600; }
|
|
398
|
+
.badge-readonly { font-size: 11px; padding: 2px 7px; border-radius: 6px; background: var(--pi-border-muted); color: var(--pi-muted); }
|
|
399
|
+
.no-file-box { display: flex; flex-direction: column; gap: 8px; padding: 12px; border: 1px dashed var(--pi-border); border-radius: 8px; background: var(--pi-surface); align-items: flex-start; }
|
|
400
|
+
.shortcuts-group { display: flex; flex-direction: column; gap: 8px; padding-top: 8px; border-top: 1px solid var(--pi-border-muted); }
|
|
401
|
+
.shortcut-buttons { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
402
|
+
button { border: 1px solid var(--pi-accent-border); border-radius: 6px; background: var(--pi-accent); color: var(--pi-bg); cursor: pointer; padding: 5px 9px; font: inherit; font-size: 12px; }
|
|
403
|
+
button.secondary { border-color: var(--pi-border); background: var(--pi-surface); color: var(--pi-text); }
|
|
404
|
+
button.accent { border-color: var(--pi-accent-border); background: var(--pi-accent); color: var(--pi-bg); }
|
|
405
|
+
button:disabled { cursor: wait; opacity: 0.65; }
|
|
406
|
+
.muted { color: var(--pi-muted); font-size: 12px; margin: 0; }
|
|
407
|
+
.status { border: 1px solid var(--pi-border); border-radius: 8px; padding: 10px; color: var(--pi-muted); font-size: 12px; }
|
|
408
|
+
.status.error { border-color: var(--pi-danger); color: var(--pi-danger); }
|
|
409
|
+
.empty { padding: 16px; color: var(--pi-muted); font-size: 12px; }
|
|
410
|
+
code { border: 1px solid var(--pi-border-muted); border-radius: 4px; background: var(--pi-bg); color: var(--pi-text-secondary); font: 11px ui-monospace, SFMono-Regular, Menlo, monospace; padding: 1px 4px; }
|
|
411
|
+
@keyframes pulse {
|
|
412
|
+
0%, 100% { opacity: 1; transform: scale(1); }
|
|
413
|
+
50% { opacity: 0.4; transform: scale(0.85); }
|
|
414
|
+
}
|
|
415
|
+
</style>
|
|
416
|
+
`;
|
|
417
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Generated from omp-web-plugins/mcps/omp-web-plugin.ts. Do not edit directly.
|
|
2
|
+
import { defineMcpsPanelElement, mcpsBadge } from "./mcpsPanelElement.js";
|
|
3
|
+
const plugin = {
|
|
4
|
+
apiVersion: 1,
|
|
5
|
+
name: "MCP Servers",
|
|
6
|
+
activate: ({ pluginId, html, svg }) => {
|
|
7
|
+
defineMcpsPanelElement();
|
|
8
|
+
return {
|
|
9
|
+
contributions: {
|
|
10
|
+
actions: [
|
|
11
|
+
{
|
|
12
|
+
id: "workspace.open-mcps",
|
|
13
|
+
title: "Open MCP Servers",
|
|
14
|
+
description: "Open the MCP Servers panel.",
|
|
15
|
+
group: "Workspace",
|
|
16
|
+
enabled: (context) => context.state.selectedWorkspace !== undefined,
|
|
17
|
+
run: (context) => {
|
|
18
|
+
if (context.state.selectedWorkspace === undefined)
|
|
19
|
+
return;
|
|
20
|
+
context.selectWorkspaceTool(`${pluginId}:workspace.mcps`);
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
workspacePanels: [
|
|
25
|
+
{
|
|
26
|
+
id: "workspace.mcps",
|
|
27
|
+
title: "MCPs",
|
|
28
|
+
icon: svg `
|
|
29
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
30
|
+
<rect x="2" y="2" width="20" height="8" rx="2" ry="2"></rect>
|
|
31
|
+
<rect x="2" y="14" width="20" height="8" rx="2" ry="2"></rect>
|
|
32
|
+
<line x1="6" y1="6" x2="6.01" y2="6"></line>
|
|
33
|
+
<line x1="6" y1="18" x2="6.01" y2="18"></line>
|
|
34
|
+
</svg>
|
|
35
|
+
`,
|
|
36
|
+
order: 55,
|
|
37
|
+
badge: (context) => mcpsBadge(context),
|
|
38
|
+
render: (context) => html `<omp-web-mcps-panel .context=${context}></omp-web-mcps-panel>`,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
export default plugin;
|
package/dist/plugin-api.d.ts
CHANGED
|
@@ -120,6 +120,7 @@ export interface WorkspaceContext {
|
|
|
120
120
|
state?: PluginRuntimeState;
|
|
121
121
|
files: WorkspaceFiles;
|
|
122
122
|
host: WorkspaceHost;
|
|
123
|
+
apiFetch(path: string, init?: RequestInit): Promise<Response>;
|
|
123
124
|
}
|
|
124
125
|
export interface WorkspaceTerminalCommandInput {
|
|
125
126
|
title: string;
|
package/dist/server/app.js
CHANGED
|
@@ -2,6 +2,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { Hono } from "hono";
|
|
5
|
+
import { createSecurityMiddleware } from "./security.js";
|
|
5
6
|
import { createBunWebSocket } from "hono/bun";
|
|
6
7
|
import { serveStatic } from "hono/bun";
|
|
7
8
|
import { ProjectStore } from "./storage/projectStore.js";
|
|
@@ -30,6 +31,7 @@ import { registerMachineProxyRoutes } from "./machines/machineProxyRoutes.js";
|
|
|
30
31
|
import { proxyMachinePluginAsset, registerMachinePluginProxyRoutes } from "./machines/machinePluginProxyRoutes.js";
|
|
31
32
|
import { PushNotificationService } from "./push/PushNotificationService.js";
|
|
32
33
|
import { registerPushRoutes } from "./push/pushRoutes.js";
|
|
34
|
+
import { registerMcpRoutes } from "./mcpRoutes.js";
|
|
33
35
|
function registerLocalProjectRoutes(app, projects, workspaces, prefix, options = {}) {
|
|
34
36
|
app.get(`${prefix}/projects`, async (c) => c.json(await projects.list()));
|
|
35
37
|
app.post(`${prefix}/projects`, async (c) => {
|
|
@@ -105,12 +107,31 @@ function registerLocalFileSuggestionRoutes(app, projects, workspaces, prefix, op
|
|
|
105
107
|
}
|
|
106
108
|
export async function buildApp(deps = {}) {
|
|
107
109
|
const app = new Hono();
|
|
110
|
+
const configService = deps.config ?? createFileOmpWebConfigService();
|
|
111
|
+
const effectiveConfig = (await configService.read()).effectiveConfig;
|
|
112
|
+
let cachedAllowedHosts = effectiveConfig.allowedHosts;
|
|
113
|
+
let lastCheck = 0;
|
|
114
|
+
const getAllowedHosts = async () => {
|
|
115
|
+
const now = Date.now();
|
|
116
|
+
if (now - lastCheck < 1000)
|
|
117
|
+
return cachedAllowedHosts;
|
|
118
|
+
lastCheck = now;
|
|
119
|
+
try {
|
|
120
|
+
cachedAllowedHosts = (await configService.read()).effectiveConfig.allowedHosts;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// keep cached
|
|
124
|
+
}
|
|
125
|
+
return cachedAllowedHosts;
|
|
126
|
+
};
|
|
127
|
+
app.use("*", createSecurityMiddleware({
|
|
128
|
+
allowedHosts: getAllowedHosts,
|
|
129
|
+
}));
|
|
108
130
|
const { upgradeWebSocket, websocket } = createBunWebSocket();
|
|
109
131
|
const projects = deps.projects ?? new ProjectService(new ProjectStore());
|
|
110
132
|
const workspaces = deps.workspaces ?? new WorkspaceService();
|
|
111
133
|
const ompWebPlugins = deps.ompWebPlugins ?? new OmpWebPluginService();
|
|
112
134
|
const piPackages = deps.piPackages ?? createDefaultPiPackageService();
|
|
113
|
-
const configService = deps.config ?? createFileOmpWebConfigService();
|
|
114
135
|
const sessionDaemon = deps.sessionDaemon ?? new SessionDaemonClient();
|
|
115
136
|
const ompWebStatusCache = createOmpWebStatusCache(() => getOmpWebStatus(sessionDaemon), {
|
|
116
137
|
onError: (error) => { console.warn("failed to refresh PI WEB status cache", error); },
|
|
@@ -157,6 +178,8 @@ export async function buildApp(deps = {}) {
|
|
|
157
178
|
registerWorkspaceDeletionRoutes(app, projects, workspaces, sessionDaemon, "/api/machines/local");
|
|
158
179
|
registerLocalFileSuggestionRoutes(app, projects, workspaces, "/api", { config: configService });
|
|
159
180
|
registerLocalFileSuggestionRoutes(app, projects, workspaces, "/api/machines/local", { config: configService });
|
|
181
|
+
registerMcpRoutes(app, "/api");
|
|
182
|
+
registerMcpRoutes(app, "/api/machines/local");
|
|
160
183
|
registerMachineProxyRoutes(app, machines, upgradeWebSocket);
|
|
161
184
|
const pushService = new PushNotificationService((msg) => { console.warn("[push]", msg); });
|
|
162
185
|
registerPushRoutes(app, pushService);
|