reasonix 0.26.1 → 0.27.0
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/README.md +8 -0
- package/README.zh-CN.md +8 -0
- package/dashboard/app.css +14 -3
- package/dashboard/dist/app.js +315 -21
- package/dashboard/dist/app.js.map +1 -1
- package/dist/cli/index.js +2187 -916
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -118,6 +118,14 @@ Scoped starter tickets — each with background, code pointers, acceptance crite
|
|
|
118
118
|
- [#21 · Dashboard design](https://github.com/esengine/reasonix/discussions/21) — react against the [proposed mockup](https://esengine.github.io/reasonix/design/agent-dashboard.html)
|
|
119
119
|
- [#22 · Future feature wishlist](https://github.com/esengine/reasonix/discussions/22) — what would you build into Reasonix next?
|
|
120
120
|
|
|
121
|
+
**Already using Reasonix and willing to help others discover it?** Publish blog posts, articles, screenshots, talks, or videos to [**Show and tell**](https://github.com/esengine/reasonix/discussions/categories/show-and-tell). The project has no marketing budget — community word of mouth is how new users find it. Sustained advocates earn the badge below, displayed next to the contributors wall once awarded:
|
|
122
|
+
|
|
123
|
+
<p align="center">
|
|
124
|
+
<a href="https://github.com/esengine/reasonix/discussions/categories/show-and-tell">
|
|
125
|
+
<img src="https://img.shields.io/badge/REASONIX-📣%20ADVOCATE-c4b5fd?style=for-the-badge&labelColor=0d1117" alt="Reasonix Advocate badge — earned by sustained advocates"/>
|
|
126
|
+
</a>
|
|
127
|
+
</p>
|
|
128
|
+
|
|
121
129
|
**Before your first PR**: read [`CONTRIBUTING.md`](./CONTRIBUTING.md) — short, strict rules (comments, errors, libraries-over-hand-rolled). `tests/comment-policy.test.ts` enforces the comment ones; `npm run verify` is the pre-push gate. By participating you agree to the [Code of Conduct](./CODE_OF_CONDUCT.md). Security issues → [SECURITY.md](./SECURITY.md).
|
|
122
130
|
|
|
123
131
|
<p align="center">
|
package/README.zh-CN.md
CHANGED
|
@@ -118,6 +118,14 @@ npx reasonix code # 首次运行粘贴 DeepSeek API Key,之后会记住
|
|
|
118
118
|
- [#21 · Dashboard 设计](https://github.com/esengine/reasonix/discussions/21) —— 对着[设计稿](https://esengine.github.io/reasonix/design/agent-dashboard.html)拍砖
|
|
119
119
|
- [#22 · 未来功能愿望单](https://github.com/esengine/reasonix/discussions/22) —— 你希望 Reasonix 长出什么功能?
|
|
120
120
|
|
|
121
|
+
**正在使用 Reasonix,愿意让更多人了解它?** 欢迎将相关博客、文章、截图、演讲或视频发布到 [**Show and tell**](https://github.com/esengine/reasonix/discussions/categories/show-and-tell)。项目没有营销预算,新用户主要通过社区口碑找到这里。持续参与传播的用户将获得下方这枚徽章,颁发后会展示在贡献者墙旁:
|
|
122
|
+
|
|
123
|
+
<p align="center">
|
|
124
|
+
<a href="https://github.com/esengine/reasonix/discussions/categories/show-and-tell">
|
|
125
|
+
<img src="https://img.shields.io/badge/REASONIX-📣%20ADVOCATE-c4b5fd?style=for-the-badge&labelColor=0d1117" alt="Reasonix Advocate 徽章 —— 授予持续参与传播的用户"/>
|
|
126
|
+
</a>
|
|
127
|
+
</p>
|
|
128
|
+
|
|
121
129
|
**第一次提 PR 之前**:先读 [`CONTRIBUTING.md`](./CONTRIBUTING.md) —— 短小、严格的项目规则(注释、错误处理、用现成库不手写)。`tests/comment-policy.test.ts` 静态强制执行注释那部分,`npm run verify` 是 push 前的闸。参与本项目即同意 [行为准则](./CODE_OF_CONDUCT.md)。安全相关问题请走 [SECURITY.md](./SECURITY.md)。
|
|
122
130
|
|
|
123
131
|
<p align="center">
|
package/dashboard/app.css
CHANGED
|
@@ -690,8 +690,19 @@ main { padding: 32px 40px 60px 32px; min-width: 0; }
|
|
|
690
690
|
.crumbs .sep { color: var(--fg-4); }
|
|
691
691
|
|
|
692
692
|
/* ── Sessions panel ──────────────────────────────────────────────────── */
|
|
693
|
-
.sessions-grid {
|
|
694
|
-
|
|
693
|
+
.sessions-grid {
|
|
694
|
+
display: grid;
|
|
695
|
+
grid-template-columns: 320px minmax(0, 1fr);
|
|
696
|
+
/* `minmax(0, 1fr)` on the row + `min-height: 0` on the children is the
|
|
697
|
+
standard recipe for "let the inner overflow:auto take effect" — without
|
|
698
|
+
it the grid items default to min-height: auto (= content size) and
|
|
699
|
+
grow past the parent's max-height, dragging .app-body along. */
|
|
700
|
+
grid-template-rows: minmax(0, 1fr);
|
|
701
|
+
gap: 14px;
|
|
702
|
+
min-height: 540px;
|
|
703
|
+
max-height: calc(100vh - 140px);
|
|
704
|
+
}
|
|
705
|
+
.sessions-list { background: var(--bg-elev); border: 1px solid var(--bd); border-radius: var(--r); display: flex; flex-direction: column; overflow: hidden; min-height: 0; min-width: 0; }
|
|
695
706
|
.sessions-list .ssl-h { padding: 10px 12px; border-bottom: 1px solid var(--bd); display: flex; align-items: center; gap: 8px; }
|
|
696
707
|
.sessions-list .ssl-h input {
|
|
697
708
|
flex: 1; background: var(--bg-input); border: 1px solid var(--bd); border-radius: var(--r);
|
|
@@ -710,7 +721,7 @@ main { padding: 32px 40px 60px 32px; min-width: 0; }
|
|
|
710
721
|
.ssl-row .meta { display: flex; gap: 10px; font-family: var(--font-mono); font-size: 10.5px; color: var(--fg-4); margin-top: 2px; }
|
|
711
722
|
.ssl-row .meta .v { color: var(--fg-2); }
|
|
712
723
|
|
|
713
|
-
.sessions-detail { background: var(--bg-elev); border: 1px solid var(--bd); border-radius: var(--r); padding: 14px 16px; overflow: auto; }
|
|
724
|
+
.sessions-detail { background: var(--bg-elev); border: 1px solid var(--bd); border-radius: var(--r); padding: 14px 16px; overflow: auto; min-height: 0; min-width: 0; }
|
|
714
725
|
.sessions-detail-h { display: flex; align-items: baseline; gap: 12px; margin-bottom: 12px; padding-bottom: 12px; border-bottom: 1px solid var(--bd); }
|
|
715
726
|
.sessions-detail-h .name { font-family: var(--font-mono); font-size: 14px; color: var(--fg-0); font-weight: 600; }
|
|
716
727
|
.sessions-detail-h .ws { font-family: var(--font-mono); font-size: 11px; color: var(--fg-3); }
|
package/dashboard/dist/app.js
CHANGED
|
@@ -19013,7 +19013,33 @@ var en = {
|
|
|
19013
19013
|
promptsTitle: "Prompts \xB7 {count}",
|
|
19014
19014
|
colName: "name",
|
|
19015
19015
|
colDesc: "description",
|
|
19016
|
-
colUri: "uri"
|
|
19016
|
+
colUri: "uri",
|
|
19017
|
+
marketplace: "marketplace",
|
|
19018
|
+
marketplaceSearch: "search the registry\u2026",
|
|
19019
|
+
marketplaceLoading: "loading registry\u2026",
|
|
19020
|
+
marketplaceMore: "load 5 more pages",
|
|
19021
|
+
marketplaceMoreLabel: "load 50 more \xB7 showing {shown} / {total}",
|
|
19022
|
+
marketplaceMoreHint: "fetches more pages from the registry",
|
|
19023
|
+
marketplaceMoreCachedHint: "more entries already cached locally",
|
|
19024
|
+
marketplaceExhausted: "all pages loaded",
|
|
19025
|
+
marketplaceExhaustedFull: "showing all {total} entries \u2014 registry exhausted",
|
|
19026
|
+
marketplaceCount: "{loaded} loaded \xB7 {matched} match \xB7 source: {source}{cached}",
|
|
19027
|
+
marketplaceCachedSuffix: " \xB7 cached",
|
|
19028
|
+
marketplaceNoMatches: "No matches. Try different terms or load more pages.",
|
|
19029
|
+
marketplaceInstall: "Install",
|
|
19030
|
+
marketplacePickHint: "Pick a server on the left, then Install.",
|
|
19031
|
+
marketplaceInstalled: "installed \u2192 {spec}",
|
|
19032
|
+
marketplaceInstalledBridged: "installed + bridged \u2192 {spec}",
|
|
19033
|
+
marketplaceAlready: "already installed",
|
|
19034
|
+
marketplaceNeedsEnv: "needs env: {names}",
|
|
19035
|
+
marketplaceSourceTag: "[{source}]",
|
|
19036
|
+
marketplaceNoInstall: "smithery listing \u2014 install metadata not exposed; use `npx -y @smithery/cli install {name}` directly",
|
|
19037
|
+
marketplaceFetchOnInstall: "Smithery listing \u2014 install detail fetched on Install. http servers map to streamable-http remotes; stdio servers run via @smithery/cli.",
|
|
19038
|
+
marketplaceInstalledBadge: "installed",
|
|
19039
|
+
marketplaceUninstall: "Uninstall",
|
|
19040
|
+
marketplaceEnvTitle: "Required environment variables",
|
|
19041
|
+
marketplaceEnvHint: "Set these in your shell before next `reasonix code` so the bridged server can authenticate.",
|
|
19042
|
+
marketplaceRestartHint: "Spec written to ~/.reasonix/config.json. Restart `reasonix code` to bridge the server (live hot-reload is on the roadmap)."
|
|
19017
19043
|
},
|
|
19018
19044
|
memory: {
|
|
19019
19045
|
loading: "loading memory\u2026",
|
|
@@ -19500,7 +19526,33 @@ var zhCN = {
|
|
|
19500
19526
|
promptsTitle: "\u63D0\u793A \xB7 {count}",
|
|
19501
19527
|
colName: "\u540D\u79F0",
|
|
19502
19528
|
colDesc: "\u63CF\u8FF0",
|
|
19503
|
-
colUri: "URI"
|
|
19529
|
+
colUri: "URI",
|
|
19530
|
+
marketplace: "\u5E02\u573A",
|
|
19531
|
+
marketplaceSearch: "\u641C\u7D22\u6CE8\u518C\u8868\u2026",
|
|
19532
|
+
marketplaceLoading: "\u52A0\u8F7D\u6CE8\u518C\u8868\u2026",
|
|
19533
|
+
marketplaceMore: "\u518D\u52A0\u8F7D 5 \u9875",
|
|
19534
|
+
marketplaceMoreLabel: "\u518D\u52A0\u8F7D 50 \u6761 \xB7 \u5F53\u524D {shown} / {total}",
|
|
19535
|
+
marketplaceMoreHint: "\u9700\u8981\u4ECE\u8FDC\u7AEF\u6CE8\u518C\u8868\u518D\u62C9\u51E0\u9875",
|
|
19536
|
+
marketplaceMoreCachedHint: "\u672C\u5730\u7F13\u5B58\u5DF2\u6709\u66F4\u591A\u6761\u76EE",
|
|
19537
|
+
marketplaceExhausted: "\u5DF2\u52A0\u8F7D\u5168\u90E8\u9875",
|
|
19538
|
+
marketplaceExhaustedFull: "\u5DF2\u5C55\u793A\u5168\u90E8 {total} \u6761 \u2014 \u6CE8\u518C\u8868\u8017\u5C3D",
|
|
19539
|
+
marketplaceCount: "\u5DF2\u8F7D\u5165 {loaded} \xB7 \u5339\u914D {matched} \xB7 \u6765\u6E90\uFF1A{source}{cached}",
|
|
19540
|
+
marketplaceCachedSuffix: " \xB7 \u7F13\u5B58\u4E2D",
|
|
19541
|
+
marketplaceNoMatches: "\u65E0\u5339\u914D\u7ED3\u679C\u3002\u6362\u5173\u952E\u8BCD\u6216\u52A0\u8F7D\u66F4\u591A\u9875\u3002",
|
|
19542
|
+
marketplaceInstall: "\u5B89\u88C5",
|
|
19543
|
+
marketplacePickHint: "\u5728\u5DE6\u4FA7\u9009\u62E9\u670D\u52A1\u5668\uFF0C\u7136\u540E\u70B9\u5B89\u88C5\u3002",
|
|
19544
|
+
marketplaceInstalled: "\u5DF2\u5B89\u88C5 \u2192 {spec}",
|
|
19545
|
+
marketplaceInstalledBridged: "\u5DF2\u5B89\u88C5\u5E76\u6865\u63A5 \u2192 {spec}",
|
|
19546
|
+
marketplaceAlready: "\u5DF2\u5B89\u88C5\u8FC7",
|
|
19547
|
+
marketplaceNeedsEnv: "\u9700\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF\uFF1A{names}",
|
|
19548
|
+
marketplaceSourceTag: "[{source}]",
|
|
19549
|
+
marketplaceNoInstall: "Smithery \u5217\u8868\u9879 \u2014 \u4E0D\u66B4\u9732\u5B89\u88C5\u5143\u6570\u636E\uFF1B\u8BF7\u76F4\u63A5 `npx -y @smithery/cli install {name}`",
|
|
19550
|
+
marketplaceFetchOnInstall: "Smithery \u5217\u8868 \u2014 \u5B89\u88C5\u65F6\u518D\u62C9\u8BE6\u60C5\u3002HTTP \u670D\u52A1\u6620\u5C04\u4E3A streamable-http \u8FDC\u7AEF\uFF1Bstdio \u670D\u52A1\u901A\u8FC7 @smithery/cli \u8FD0\u884C\u3002",
|
|
19551
|
+
marketplaceInstalledBadge: "\u5DF2\u5B89\u88C5",
|
|
19552
|
+
marketplaceUninstall: "\u5378\u8F7D",
|
|
19553
|
+
marketplaceEnvTitle: "\u5FC5\u9700\u7684\u73AF\u5883\u53D8\u91CF",
|
|
19554
|
+
marketplaceEnvHint: "\u4E0B\u6B21\u542F\u52A8 `reasonix code` \u4E4B\u524D\u5728 shell \u91CC\u8BBE\u597D\uFF0C\u6865\u63A5\u7684\u670D\u52A1\u5668\u624D\u80FD\u6B63\u5E38\u9274\u6743\u3002",
|
|
19555
|
+
marketplaceRestartHint: "\u5DF2\u5199\u5165 ~/.reasonix/config.json\u3002\u91CD\u542F `reasonix code` \u540E\u670D\u52A1\u5668\u624D\u4F1A\u771F\u6B63\u6865\u63A5\uFF08\u70ED\u91CD\u8F7D\u5728\u8DEF\u7EBF\u56FE\u4E0A\uFF09\u3002"
|
|
19504
19556
|
},
|
|
19505
19557
|
memory: {
|
|
19506
19558
|
loading: "\u52A0\u8F7D\u8BB0\u5FC6\u2026",
|
|
@@ -23432,6 +23484,24 @@ function HooksPanel() {
|
|
|
23432
23484
|
}
|
|
23433
23485
|
|
|
23434
23486
|
// dashboard/src/panels/mcp.ts
|
|
23487
|
+
function specForEntry(e3) {
|
|
23488
|
+
if (!e3.install) return null;
|
|
23489
|
+
const localName = e3.name.split("/").pop() ?? e3.name;
|
|
23490
|
+
const safe = localName.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/^-+|-+$/g, "") || "mcp";
|
|
23491
|
+
const trail = e3.install.extraArgs?.length ? ` ${e3.install.extraArgs.join(" ")}` : "";
|
|
23492
|
+
if (e3.install.runtime === "remote" && e3.install.url) {
|
|
23493
|
+
if (e3.install.transport === "streamable-http") return `${safe}=streamable+${e3.install.url}`;
|
|
23494
|
+
return `${safe}=${e3.install.url}`;
|
|
23495
|
+
}
|
|
23496
|
+
if (e3.install.runtime === "npm" && e3.install.packageId) {
|
|
23497
|
+
const pinned = e3.install.version ? `${e3.install.packageId}@${e3.install.version}` : e3.install.packageId;
|
|
23498
|
+
return `${safe}=npx -y ${pinned}${trail}`;
|
|
23499
|
+
}
|
|
23500
|
+
if (e3.install.runtime === "pypi" && e3.install.packageId) {
|
|
23501
|
+
return `${safe}=uvx ${e3.install.packageId}${trail}`;
|
|
23502
|
+
}
|
|
23503
|
+
return null;
|
|
23504
|
+
}
|
|
23435
23505
|
function specLabel(spec) {
|
|
23436
23506
|
const eq = spec.indexOf("=");
|
|
23437
23507
|
return eq > 0 ? spec.slice(0, eq) : spec;
|
|
@@ -23451,6 +23521,57 @@ function McpPanel() {
|
|
|
23451
23521
|
const [open, setOpen] = p2(null);
|
|
23452
23522
|
const [openUnbridged, setOpenUnbridged] = p2(null);
|
|
23453
23523
|
const [filter, setFilter] = p2("all");
|
|
23524
|
+
const [registry, setRegistry] = p2(null);
|
|
23525
|
+
const [registryQuery, setRegistryQuery] = p2("");
|
|
23526
|
+
const [registryLoading, setRegistryLoading] = p2(false);
|
|
23527
|
+
const [openRegistry, setOpenRegistry] = p2(null);
|
|
23528
|
+
const [displayLimit, setDisplayLimit] = p2(50);
|
|
23529
|
+
const loadRegistry = x2(async (q3, pages, limit) => {
|
|
23530
|
+
setRegistryLoading(true);
|
|
23531
|
+
try {
|
|
23532
|
+
const params = new URLSearchParams();
|
|
23533
|
+
if (q3.trim()) params.set("q", q3.trim());
|
|
23534
|
+
params.set("pages", String(pages));
|
|
23535
|
+
params.set("maxPages", String(Math.max(20, pages)));
|
|
23536
|
+
params.set("limit", String(limit));
|
|
23537
|
+
const r3 = await api(`/mcp/registry?${params.toString()}`);
|
|
23538
|
+
setRegistry(r3);
|
|
23539
|
+
} catch (err) {
|
|
23540
|
+
setError(err.message);
|
|
23541
|
+
} finally {
|
|
23542
|
+
setRegistryLoading(false);
|
|
23543
|
+
}
|
|
23544
|
+
}, []);
|
|
23545
|
+
_2(() => {
|
|
23546
|
+
if (filter !== "marketplace") return;
|
|
23547
|
+
if (registry) return;
|
|
23548
|
+
void loadRegistry("", 1, displayLimit);
|
|
23549
|
+
}, [filter, registry, loadRegistry, displayLimit]);
|
|
23550
|
+
_2(() => {
|
|
23551
|
+
if (filter !== "marketplace") return;
|
|
23552
|
+
setDisplayLimit(50);
|
|
23553
|
+
const handle = setTimeout(() => void loadRegistry(registryQuery, 1, 50), 300);
|
|
23554
|
+
return () => clearTimeout(handle);
|
|
23555
|
+
}, [registryQuery, filter, loadRegistry]);
|
|
23556
|
+
const installFromRegistry = x2(async (entry) => {
|
|
23557
|
+
setBusy(true);
|
|
23558
|
+
try {
|
|
23559
|
+
const r3 = await api("/mcp/registry/install", { method: "POST", body: { name: entry.name } });
|
|
23560
|
+
if (r3.alreadyPresent) {
|
|
23561
|
+
setInfo(t4("mcp.marketplaceAlready"));
|
|
23562
|
+
} else if (r3.bridged) {
|
|
23563
|
+
setInfo(t4("mcp.marketplaceInstalledBridged", { spec: r3.spec }));
|
|
23564
|
+
} else {
|
|
23565
|
+
setInfo(t4("mcp.marketplaceInstalled", { spec: r3.spec }));
|
|
23566
|
+
}
|
|
23567
|
+
setTimeout(() => setInfo(null), 5e3);
|
|
23568
|
+
await load();
|
|
23569
|
+
} catch (err) {
|
|
23570
|
+
setError(err.message);
|
|
23571
|
+
} finally {
|
|
23572
|
+
setBusy(false);
|
|
23573
|
+
}
|
|
23574
|
+
}, []);
|
|
23454
23575
|
const load = x2(async () => {
|
|
23455
23576
|
try {
|
|
23456
23577
|
setData(await api("/mcp"));
|
|
@@ -23470,9 +23591,7 @@ function McpPanel() {
|
|
|
23470
23591
|
method: "POST",
|
|
23471
23592
|
body: { spec: newSpec.trim() }
|
|
23472
23593
|
});
|
|
23473
|
-
setInfo(
|
|
23474
|
-
r3.requiresRestart ? t4("mcp.savedRestart") : t4("mcp.saved")
|
|
23475
|
-
);
|
|
23594
|
+
setInfo(r3.requiresRestart ? t4("mcp.savedRestart") : t4("mcp.saved"));
|
|
23476
23595
|
setTimeout(() => setInfo(null), 4e3);
|
|
23477
23596
|
setNewSpec("");
|
|
23478
23597
|
await load();
|
|
@@ -23499,14 +23618,16 @@ function McpPanel() {
|
|
|
23499
23618
|
},
|
|
23500
23619
|
[load]
|
|
23501
23620
|
);
|
|
23502
|
-
if (!data && !error)
|
|
23621
|
+
if (!data && !error)
|
|
23622
|
+
return html4`<div class="card" style="color:var(--fg-3)">${t4("mcp.loading")}</div>`;
|
|
23503
23623
|
if (error && !data) return html4`<div class="card accent-err">${error}</div>`;
|
|
23504
23624
|
if (!data) return null;
|
|
23505
23625
|
const liveCount = data.servers.length;
|
|
23506
23626
|
const unbridgedSpecs = (specs ?? []).filter((spec) => !data.servers.some((s3) => s3.spec === spec));
|
|
23507
23627
|
const unbridgedCount = unbridgedSpecs.length;
|
|
23508
|
-
const showLive = filter
|
|
23509
|
-
const showUnbridged = filter
|
|
23628
|
+
const showLive = filter === "all" || filter === "live";
|
|
23629
|
+
const showUnbridged = filter === "all" || filter === "unbridged";
|
|
23630
|
+
const showMarketplace = filter === "marketplace";
|
|
23510
23631
|
return html4`
|
|
23511
23632
|
<div class="sessions-grid">
|
|
23512
23633
|
<div class="sessions-list">
|
|
@@ -23518,25 +23639,63 @@ function McpPanel() {
|
|
|
23518
23639
|
<span class=${`chip-f ${filter === "all" ? "active" : ""}`} onClick=${() => setFilter("all")}>${t4("mcp.all")} <span class="ct">${liveCount + unbridgedCount}</span></span>
|
|
23519
23640
|
<span class=${`chip-f ${filter === "live" ? "active" : ""}`} onClick=${() => setFilter("live")}>${t4("mcp.live")} <span class="ct">${liveCount}</span></span>
|
|
23520
23641
|
<span class=${`chip-f ${filter === "unbridged" ? "active" : ""}`} onClick=${() => setFilter("unbridged")}>${t4("mcp.unbridged")} <span class="ct">${unbridgedCount}</span></span>
|
|
23642
|
+
<span class=${`chip-f ${filter === "marketplace" ? "active" : ""}`} onClick=${() => setFilter("marketplace")}>${t4("mcp.marketplace")}</span>
|
|
23521
23643
|
</div>
|
|
23522
23644
|
</div>
|
|
23523
|
-
|
|
23524
|
-
|
|
23525
|
-
|
|
23526
|
-
|
|
23527
|
-
|
|
23528
|
-
|
|
23529
|
-
|
|
23530
|
-
|
|
23531
|
-
|
|
23532
|
-
|
|
23645
|
+
${showMarketplace ? html4`
|
|
23646
|
+
<div style="padding:8px 12px;display:flex;gap:6px">
|
|
23647
|
+
<input
|
|
23648
|
+
type="text"
|
|
23649
|
+
placeholder=${t4("mcp.marketplaceSearch")}
|
|
23650
|
+
value=${registryQuery}
|
|
23651
|
+
onInput=${(e3) => setRegistryQuery(e3.target.value)}
|
|
23652
|
+
style="flex:1;font-size:11px"
|
|
23653
|
+
/>
|
|
23654
|
+
</div>
|
|
23655
|
+
${registry ? html4`<div style="padding:0 12px 6px;font-size:11px;color:var(--fg-3)">
|
|
23656
|
+
${t4("mcp.marketplaceCount", {
|
|
23657
|
+
loaded: registry.loaded,
|
|
23658
|
+
matched: registry.matched,
|
|
23659
|
+
source: registry.source,
|
|
23660
|
+
cached: registry.fromCache ? t4("mcp.marketplaceCachedSuffix") : ""
|
|
23661
|
+
})}
|
|
23662
|
+
</div>` : null}
|
|
23663
|
+
` : html4`
|
|
23664
|
+
<div style="padding:8px 12px;display:flex;gap:6px">
|
|
23665
|
+
<input
|
|
23666
|
+
type="text"
|
|
23667
|
+
placeholder=${t4("mcp.specPlaceholder")}
|
|
23668
|
+
value=${newSpec}
|
|
23669
|
+
onInput=${(e3) => setNewSpec(e3.target.value)}
|
|
23670
|
+
style="flex:1;font-size:11px"
|
|
23671
|
+
/>
|
|
23672
|
+
<button class="btn primary" disabled=${busy || !newSpec.trim()} onClick=${addSpec}>+</button>
|
|
23673
|
+
</div>
|
|
23674
|
+
`}
|
|
23533
23675
|
${info ? html4`<div style="padding:0 12px 8px"><span class="pill ok">${info}</span></div>` : null}
|
|
23534
23676
|
${error ? html4`<div class="card accent-err" style="margin:0 12px 8px">${error}</div>` : null}
|
|
23535
23677
|
|
|
23536
23678
|
<div class="ssl-rows">
|
|
23537
|
-
${liveCount === 0 && unbridgedCount === 0 ? html4`<div style="color:var(--fg-3);padding:14px;font-size:12px">
|
|
23679
|
+
${!showMarketplace && liveCount === 0 && unbridgedCount === 0 ? html4`<div style="color:var(--fg-3);padding:14px;font-size:12px">
|
|
23538
23680
|
${t4("mcp.noServers")}
|
|
23539
23681
|
</div>` : null}
|
|
23682
|
+
${showMarketplace ? renderMarketplaceRows({
|
|
23683
|
+
registry,
|
|
23684
|
+
registryLoading,
|
|
23685
|
+
openRegistry,
|
|
23686
|
+
setOpenRegistry: (e3) => {
|
|
23687
|
+
setOpenRegistry(e3);
|
|
23688
|
+
setOpen(null);
|
|
23689
|
+
setOpenUnbridged(null);
|
|
23690
|
+
},
|
|
23691
|
+
loadMore: () => {
|
|
23692
|
+
const nextLimit = displayLimit + 50;
|
|
23693
|
+
setDisplayLimit(nextLimit);
|
|
23694
|
+
const pagesNeeded = Math.ceil(nextLimit / 30) + 3;
|
|
23695
|
+
void loadRegistry(registryQuery, pagesNeeded, nextLimit);
|
|
23696
|
+
},
|
|
23697
|
+
installedSpecs: new Set(specs ?? [])
|
|
23698
|
+
}) : null}
|
|
23540
23699
|
${showLive ? data.servers.map(
|
|
23541
23700
|
(s3) => html4`
|
|
23542
23701
|
<div
|
|
@@ -23571,7 +23730,17 @@ function McpPanel() {
|
|
|
23571
23730
|
</div>
|
|
23572
23731
|
|
|
23573
23732
|
<div class="sessions-detail">
|
|
23574
|
-
${
|
|
23733
|
+
${openRegistry != null ? renderRegistryDetail({
|
|
23734
|
+
entry: openRegistry,
|
|
23735
|
+
busy,
|
|
23736
|
+
installedSpec: (() => {
|
|
23737
|
+
const spec = specForEntry(openRegistry);
|
|
23738
|
+
return spec && (specs ?? []).includes(spec) ? spec : null;
|
|
23739
|
+
})(),
|
|
23740
|
+
onInstall: () => installFromRegistry(openRegistry),
|
|
23741
|
+
onUninstall: (spec) => removeSpec(spec),
|
|
23742
|
+
onClose: () => setOpenRegistry(null)
|
|
23743
|
+
}) : openUnbridged != null ? html4`
|
|
23575
23744
|
<div class="sessions-detail-h">
|
|
23576
23745
|
<span class="name">${specLabel(openUnbridged)}</span>
|
|
23577
23746
|
<span class="ws"><span class="pill">${t4("mcp.unbridgedTitle")}</span></span>
|
|
@@ -23595,7 +23764,7 @@ function McpPanel() {
|
|
|
23595
23764
|
</div>
|
|
23596
23765
|
</div>
|
|
23597
23766
|
` : open == null ? html4`<div style="color:var(--fg-3);font-size:13px;text-align:center;padding:60px 20px">
|
|
23598
|
-
${t4("mcp.pickHint")}
|
|
23767
|
+
${showMarketplace ? t4("mcp.marketplacePickHint") : t4("mcp.pickHint")}
|
|
23599
23768
|
</div>` : html4`
|
|
23600
23769
|
<div class="sessions-detail-h">
|
|
23601
23770
|
<span class="name">${open.label}</span>
|
|
@@ -23664,6 +23833,131 @@ function McpPanel() {
|
|
|
23664
23833
|
</div>
|
|
23665
23834
|
`;
|
|
23666
23835
|
}
|
|
23836
|
+
function renderLoadMoreFooter({
|
|
23837
|
+
registry,
|
|
23838
|
+
registryLoading,
|
|
23839
|
+
loadMore
|
|
23840
|
+
}) {
|
|
23841
|
+
if (!registry) return null;
|
|
23842
|
+
const shown = registry.entries.length;
|
|
23843
|
+
const total = registry.matched;
|
|
23844
|
+
const moreCached = total > shown;
|
|
23845
|
+
const moreOnNetwork = registry.hasMore;
|
|
23846
|
+
const canDoSomething = moreCached || moreOnNetwork;
|
|
23847
|
+
if (canDoSomething) {
|
|
23848
|
+
const label = registryLoading ? t4("mcp.marketplaceLoading") : t4("mcp.marketplaceMoreLabel", {
|
|
23849
|
+
shown,
|
|
23850
|
+
total: moreOnNetwork ? `${total}+` : `${total}`
|
|
23851
|
+
});
|
|
23852
|
+
return html4`<div style="padding:10px 12px;display:flex;align-items:center;gap:10px">
|
|
23853
|
+
<button class="btn primary" disabled=${registryLoading} onClick=${loadMore}>${label}</button>
|
|
23854
|
+
<span style="font-size:11px;color:var(--fg-3)">
|
|
23855
|
+
${moreOnNetwork ? t4("mcp.marketplaceMoreHint") : t4("mcp.marketplaceMoreCachedHint")}
|
|
23856
|
+
</span>
|
|
23857
|
+
</div>`;
|
|
23858
|
+
}
|
|
23859
|
+
return html4`<div style="padding:12px;background:var(--bg-elev-2,rgba(36,143,242,0.07));border-top:1px solid var(--bd);display:flex;align-items:center;gap:8px;font-size:12px;color:var(--fg-2)">
|
|
23860
|
+
<span style="color:var(--c-ok)">✓</span>
|
|
23861
|
+
<span>${t4("mcp.marketplaceExhaustedFull", { total })}</span>
|
|
23862
|
+
</div>`;
|
|
23863
|
+
}
|
|
23864
|
+
function renderMarketplaceRows({
|
|
23865
|
+
registry,
|
|
23866
|
+
registryLoading,
|
|
23867
|
+
openRegistry,
|
|
23868
|
+
setOpenRegistry,
|
|
23869
|
+
loadMore,
|
|
23870
|
+
installedSpecs
|
|
23871
|
+
}) {
|
|
23872
|
+
if (!registry && registryLoading) {
|
|
23873
|
+
return html4`<div style="color:var(--fg-3);padding:14px;font-size:12px">${t4("mcp.marketplaceLoading")}</div>`;
|
|
23874
|
+
}
|
|
23875
|
+
if (!registry || registry.entries.length === 0) {
|
|
23876
|
+
return html4`<div style="color:var(--fg-3);padding:14px;font-size:12px">${t4("mcp.marketplaceNoMatches")}</div>`;
|
|
23877
|
+
}
|
|
23878
|
+
return html4`
|
|
23879
|
+
${registry.entries.map((e3) => {
|
|
23880
|
+
const sel = openRegistry?.name === e3.name;
|
|
23881
|
+
const tag2 = t4("mcp.marketplaceSourceTag", { source: e3.source });
|
|
23882
|
+
const spec = specForEntry(e3);
|
|
23883
|
+
const installed = spec !== null && installedSpecs.has(spec);
|
|
23884
|
+
const pop = e3.popularity !== void 0 ? html4` <span class="dim">· ${fmtNum(e3.popularity)}</span>` : null;
|
|
23885
|
+
const icon = e3.iconUrl ? html4`<img src=${e3.iconUrl} alt="" style="width:16px;height:16px;border-radius:3px;margin-right:6px;vertical-align:middle;object-fit:cover" loading="lazy" referrerpolicy="no-referrer" onError=${(ev) => ev.target.style.display = "none"} />` : null;
|
|
23886
|
+
return html4`
|
|
23887
|
+
<div class=${`ssl-row ${sel ? "sel" : ""}`} onClick=${() => setOpenRegistry(e3)}>
|
|
23888
|
+
<span class="name">${icon}${e3.name} <span class="pill">${tag2}</span>${installed ? html4` <span class="pill ok">${t4("mcp.marketplaceInstalledBadge")}</span>` : null}</span>
|
|
23889
|
+
<span class="preview">${e3.description}</span>
|
|
23890
|
+
<span class="meta">${pop}</span>
|
|
23891
|
+
</div>
|
|
23892
|
+
`;
|
|
23893
|
+
})}
|
|
23894
|
+
${renderLoadMoreFooter({ registry, registryLoading, loadMore })}
|
|
23895
|
+
`;
|
|
23896
|
+
}
|
|
23897
|
+
function renderRegistryDetail({
|
|
23898
|
+
entry,
|
|
23899
|
+
busy,
|
|
23900
|
+
installedSpec,
|
|
23901
|
+
onInstall,
|
|
23902
|
+
onUninstall,
|
|
23903
|
+
onClose
|
|
23904
|
+
}) {
|
|
23905
|
+
const installable = !!entry.install || entry.source === "smithery";
|
|
23906
|
+
const installed = installedSpec !== null;
|
|
23907
|
+
const specPreview = entry.install ? `${entry.install.runtime} \xB7 ${entry.install.transport}${entry.install.packageId ? ` \xB7 ${entry.install.packageId}` : entry.install.url ? ` \xB7 ${entry.install.url}` : ""}${entry.install.version ? `@${entry.install.version}` : ""}` : "";
|
|
23908
|
+
const icon = entry.iconUrl ? html4`<img src=${entry.iconUrl} alt="" style="width:24px;height:24px;border-radius:4px;margin-right:8px;vertical-align:middle;object-fit:cover" loading="lazy" referrerpolicy="no-referrer" onError=${(ev) => ev.target.style.display = "none"} />` : null;
|
|
23909
|
+
return html4`
|
|
23910
|
+
<div class="sessions-detail-h">
|
|
23911
|
+
<span class="name">${icon}${entry.name}${installed ? html4` <span class="pill ok">${t4("mcp.marketplaceInstalledBadge")}</span>` : null}</span>
|
|
23912
|
+
<span class="ws">${t4("mcp.marketplaceSourceTag", { source: entry.source })}${entry.popularity !== void 0 ? ` \xB7 ${fmtNum(entry.popularity)} uses` : ""}${entry.homepage ? html4` · <a href=${entry.homepage} target="_blank" rel="noopener noreferrer">homepage</a>` : ""}</span>
|
|
23913
|
+
<span class="actions">
|
|
23914
|
+
${installed ? html4`<button
|
|
23915
|
+
class="btn"
|
|
23916
|
+
disabled=${busy}
|
|
23917
|
+
onClick=${() => onUninstall(installedSpec)}
|
|
23918
|
+
style="border-color:var(--c-err);color:var(--c-err)"
|
|
23919
|
+
>${t4("mcp.marketplaceUninstall")}</button>` : html4`<button class="btn primary" disabled=${busy || !installable} onClick=${onInstall}>${t4("mcp.marketplaceInstall")}</button>`}
|
|
23920
|
+
<button class="btn ghost" onClick=${onClose}>${t4("common.back")}</button>
|
|
23921
|
+
</span>
|
|
23922
|
+
</div>
|
|
23923
|
+
|
|
23924
|
+
<div class="card" style="margin-bottom:12px">
|
|
23925
|
+
<div class="card-b" style="font-size:13px;line-height:1.6">${entry.description || "\u2014"}</div>
|
|
23926
|
+
</div>
|
|
23927
|
+
|
|
23928
|
+
${entry.install ? html4`<div class="card" style="margin-bottom:12px">
|
|
23929
|
+
<div class="card-h"><span class="title">${t4("mcp.spec")}</span></div>
|
|
23930
|
+
<div class="card-b">
|
|
23931
|
+
<code class="mono" style="font-size:11.5px;color:var(--fg-2);word-break:break-all;display:block">${specPreview}</code>
|
|
23932
|
+
${installedSpec ? html4`<div style="margin-top:8px;font-size:11px;color:var(--fg-3)">
|
|
23933
|
+
<span class="dim">on disk:</span> <code class="mono">${installedSpec}</code>
|
|
23934
|
+
</div>` : null}
|
|
23935
|
+
</div>
|
|
23936
|
+
</div>` : entry.source === "smithery" ? html4`<div class="card" style="margin-bottom:12px">
|
|
23937
|
+
<div class="card-b" style="font-size:13px;line-height:1.6;color:var(--fg-3)">
|
|
23938
|
+
${t4("mcp.marketplaceFetchOnInstall")}
|
|
23939
|
+
</div>
|
|
23940
|
+
</div>` : null}
|
|
23941
|
+
|
|
23942
|
+
${entry.install?.requiredEnv?.length ? html4`<div class="card accent-brand" style="margin-bottom:12px">
|
|
23943
|
+
<div class="card-h"><span class="title">${t4("mcp.marketplaceEnvTitle")}</span></div>
|
|
23944
|
+
<div class="card-b" style="font-size:13px">
|
|
23945
|
+
${entry.install.requiredEnv.map(
|
|
23946
|
+
(name) => html4`<div><code class="mono" style="color:var(--c-warn)">${name}</code></div>`
|
|
23947
|
+
)}
|
|
23948
|
+
<div style="margin-top:6px;color:var(--fg-3);font-size:12px">
|
|
23949
|
+
${t4("mcp.marketplaceEnvHint")}
|
|
23950
|
+
</div>
|
|
23951
|
+
</div>
|
|
23952
|
+
</div>` : null}
|
|
23953
|
+
|
|
23954
|
+
${installed ? html4`<div class="card accent-warn">
|
|
23955
|
+
<div class="card-b" style="font-size:12.5px;line-height:1.6">
|
|
23956
|
+
${t4("mcp.marketplaceRestartHint")}
|
|
23957
|
+
</div>
|
|
23958
|
+
</div>` : null}
|
|
23959
|
+
`;
|
|
23960
|
+
}
|
|
23667
23961
|
|
|
23668
23962
|
// dashboard/src/panels/memory.ts
|
|
23669
23963
|
function MemoryPanel() {
|