dsh-plugin-capabilities 0.2.1 → 0.3.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 CHANGED
@@ -39,7 +39,7 @@ MCP 行的变更需要重启 dsh 才会进入组合。MCP 页头部有常驻的
39
39
 
40
40
  ![「MCP 市场」](docs/images/screenshot-market-mcp.png)
41
41
 
42
- 「市场」页分两栏:「技能市场」是精选的技能仓库(Anthropic 官方技能集、Superpowers 工作流集等),点「安装」走的就是上文 GitHub 仓库的下载解包流程,装完立即出现在「技能」页;「MCP 市场」是一份精选服务器列表(官方 filesystem/memory/git 等,加上 context7 这类常用第三方),点「添加」直接写入一条 profile 服务器行,和手工添加完全等价。列表数据来自[本插件仓库](https://github.com/qinyre/dsh-plugin-capabilities)的在线索引(`market/*.json`),离线时自动回退到包内快照;需要 API 密钥的服务器会在卡片上标出环境变量名,装好后到 MCP 列表里补填即可。已安装的条目可以直接卸载:技能仓库走仓库移除,MCP 行走服务器删除。
42
+ 「市场」页分两栏:「技能市场」是精选的技能仓库(Anthropic 官方技能集、Superpowers 工作流集等),点「安装」走的就是上文 GitHub 仓库的下载解包流程,装完立即出现在「技能」页;「MCP 市场」是一份精选服务器列表(官方 filesystem/memory/git 等,加上 context7 这类常用第三方),点「添加」直接写入一条 profile 服务器行,和手工添加完全等价。0.3.0 起点开条目可以看详情:技能仓库列出里面具体有哪些技能,MCP 服务器列出启动命令、需要的环境变量和提供的工具,不必再去 GitHub 主页。列表数据来自[本插件仓库](https://github.com/qinyre/dsh-plugin-capabilities)的在线索引(`market/*.json`),离线时自动回退到包内快照;需要 API 密钥的服务器会在卡片上标出环境变量名,装好后到 MCP 列表里补填即可。已安装的条目可以直接卸载:技能仓库走仓库移除,MCP 行走服务器删除。
43
43
 
44
44
  ## 安装
45
45
 
package/lib/client.js CHANGED
@@ -58,7 +58,7 @@ var CSS = `
58
58
  .dpc-refresh:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}
59
59
  .dpc-empty{margin:0;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}
60
60
  .dpc-cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));align-items:stretch;gap:10px;margin:0;padding:0;list-style:none}
61
- .dpc-card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-3);padding:12px 14px}
61
+ .dpc-card{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-3);padding:12px 14px;cursor:pointer}
62
62
  .dpc-card:hover{background:var(--dsw-alias-interactive-bg-hover)}
63
63
  .dpc-cardTop{display:flex;align-items:center;gap:8px}
64
64
  .dpc-cardTitle{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:20px;font-weight:600;font-family:var(--ds-font-family-code)}
@@ -140,6 +140,11 @@ var CSS = `
140
140
  .dpc-format .dpc-form{margin-top:8px}
141
141
  .dpc-formatHint{margin:2px 0 0;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary)}
142
142
  .dpc-code{margin:4px 0 8px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:8px 10px;overflow-x:auto;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font-family:var(--ds-font-family-code);font-size:11px;line-height:17px;white-space:pre}
143
+ /* Market detail modal. */
144
+ .dpc-detailDesc{margin:0;font-size:13px;line-height:20px}
145
+ .dpc-detailSection{margin-top:12px;display:flex;flex-direction:column;gap:6px}
146
+ .dpc-detailLabel{font-size:11px;line-height:16px;color:var(--dsw-alias-label-secondary)}
147
+ .dpc-detailTags{display:flex;flex-wrap:wrap;gap:4px}
143
148
  @media(max-width:680px){.dpc-cards{grid-template-columns:minmax(0,1fr)}}
144
149
  `;
145
150
 
@@ -157,6 +162,7 @@ function MarketTab(props) {
157
162
  const [busyId, setBusyId] = (0, import_react.useState)(null);
158
163
  const [outcome, setOutcome] = (0, import_react.useState)(null);
159
164
  const [confirmUninstall, setConfirmUninstall] = (0, import_react.useState)(null);
165
+ const [detail, setDetail] = (0, import_react.useState)(null);
160
166
  const [reload, setReload] = (0, import_react.useState)(0);
161
167
  const refreshSkills = (0, import_react.useCallback)(() => {
162
168
  setRepos(null);
@@ -240,6 +246,11 @@ function MarketTab(props) {
240
246
  const pick = (base, zh2) => zhUi() && zh2 !== void 0 ? zh2 : base;
241
247
  const title = (entry) => pick(entry.name, entry.nameZh);
242
248
  const desc = (entry) => pick(entry.description, entry.descriptionZh);
249
+ const cardStop = (event) => {
250
+ event.stopPropagation();
251
+ };
252
+ const detailRepo = detail !== null && detail.kind === "skills" && repos !== null ? repos.find((repo) => repo.id === detail.id) ?? null : null;
253
+ const detailServer = detail !== null && detail.kind === "mcp" && servers !== null ? servers.find((server) => server.id === detail.id) ?? null : null;
243
254
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dpc-section", children: [
244
255
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: CSS }),
245
256
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dpc-head", children: [
@@ -264,7 +275,7 @@ function MarketTab(props) {
264
275
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dpc-intro", children: t("marketSkillsIntro") }),
265
276
  repos === null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dpc-empty", children: t("loading") }),
266
277
  repos !== null && repos.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dpc-empty", children: t("marketEmpty") }),
267
- repos !== null && repos.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dpc-cards", children: repos.map((repo) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "dpc-card", children: [
278
+ repos !== null && repos.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dpc-cards", children: repos.map((repo) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "dpc-card", onClick: () => setDetail({ kind: "skills", id: repo.id }), children: [
268
279
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dpc-cardTop", children: [
269
280
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { className: "dpc-cardTitle", title: repo.url, children: title(repo) }),
270
281
  repo.skillCount !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dpc-tag", children: t("marketSkillCount").replace("{n}", String(repo.skillCount)) }),
@@ -272,9 +283,16 @@ function MarketTab(props) {
272
283
  ] }),
273
284
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dpc-cardDesc", children: desc(repo) }),
274
285
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dpc-cardRow", children: [
275
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { className: "dpc-link", href: repo.homepage ?? repo.url, target: "_blank", rel: "noreferrer", children: t("marketHome") }),
286
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "dpc-link", onClick: () => setDetail({ kind: "skills", id: repo.id }), children: t("marketDetail") }),
287
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { className: "dpc-link", href: repo.homepage ?? repo.url, target: "_blank", rel: "noreferrer", onClick: cardStop, children: t("marketHome") }),
276
288
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dpc-spacer" }),
277
- repo.installedId !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "ghost", size: "sm", disabled: busyId !== null, onClick: () => setConfirmUninstall({ kind: "root", id: repo.installedId, name: title(repo) }), children: t("marketUninstall") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "primary", size: "sm", disabled: busyId !== null, onClick: () => void doInstallRepo(repo), children: busyId === repo.id ? t("marketInstalling") : t("marketInstall") })
289
+ repo.installedId !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "ghost", size: "sm", disabled: busyId !== null, onClick: (event) => {
290
+ event.stopPropagation();
291
+ setConfirmUninstall({ kind: "root", id: repo.installedId, name: title(repo) });
292
+ }, children: t("marketUninstall") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "primary", size: "sm", disabled: busyId !== null, onClick: (event) => {
293
+ event.stopPropagation();
294
+ void doInstallRepo(repo);
295
+ }, children: busyId === repo.id ? t("marketInstalling") : t("marketInstall") })
278
296
  ] })
279
297
  ] }, repo.id)) })
280
298
  ] }),
@@ -282,7 +300,7 @@ function MarketTab(props) {
282
300
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dpc-intro", children: t("marketMcpIntro") }),
283
301
  servers === null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dpc-empty", children: t("loading") }),
284
302
  servers !== null && servers.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dpc-empty", children: t("marketEmpty") }),
285
- servers !== null && servers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dpc-cards", children: servers.map((server) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "dpc-card", children: [
303
+ servers !== null && servers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "dpc-cards", children: servers.map((server) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "dpc-card", onClick: () => setDetail({ kind: "mcp", id: server.id }), children: [
286
304
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dpc-cardTop", children: [
287
305
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { className: "dpc-cardTitle", title: server.id, children: title(server) }),
288
306
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dpc-tag", children: server.transport }),
@@ -296,18 +314,80 @@ function MarketTab(props) {
296
314
  server.envKeys.join(", ")
297
315
  ] }),
298
316
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dpc-cardRow", children: [
299
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { className: "dpc-link", href: server.homepage, target: "_blank", rel: "noreferrer", children: t("marketHome") }),
317
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "dpc-link", onClick: () => setDetail({ kind: "mcp", id: server.id }), children: t("marketDetail") }),
318
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { className: "dpc-link", href: server.homepage, target: "_blank", rel: "noreferrer", onClick: cardStop, children: t("marketHome") }),
300
319
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dpc-spacer" }),
301
- server.installed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "ghost", size: "sm", disabled: busyId !== null, onClick: () => void mcp.list().then(
302
- (body) => {
303
- const row = body.servers.find((item) => item.serverName === server.id);
304
- if (row !== void 0) setConfirmUninstall({ kind: "mcp", id: row.id, name: server.id });
305
- },
306
- (error) => setOutcome({ ok: false, text: `${t("failed")}: ${String(error.message ?? error)}` })
307
- ), children: t("marketUninstall") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "primary", size: "sm", disabled: busyId !== null, onClick: () => void doInstallMcp(server), children: busyId === server.id ? t("marketInstalling") : t("marketAdd") })
320
+ server.installed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "ghost", size: "sm", disabled: busyId !== null, onClick: (event) => {
321
+ event.stopPropagation();
322
+ void mcp.list().then(
323
+ (body) => {
324
+ const row = body.servers.find((item) => item.serverName === server.id);
325
+ if (row !== void 0) setConfirmUninstall({ kind: "mcp", id: row.id, name: server.id });
326
+ },
327
+ (error) => setOutcome({ ok: false, text: `${t("failed")}: ${String(error.message ?? error)}` })
328
+ );
329
+ }, children: t("marketUninstall") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "primary", size: "sm", disabled: busyId !== null, onClick: (event) => {
330
+ event.stopPropagation();
331
+ void doInstallMcp(server);
332
+ }, children: busyId === server.id ? t("marketInstalling") : t("marketAdd") })
308
333
  ] })
309
334
  ] }, server.id)) })
310
335
  ] }),
336
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
337
+ import_dsh_client_ui_primitives.Modal,
338
+ {
339
+ open: detailRepo !== null || detailServer !== null,
340
+ onClose: () => setDetail(null),
341
+ title: detailRepo !== null ? title(detailRepo) : detailServer !== null ? title(detailServer) : "",
342
+ footer: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
343
+ detailRepo !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { className: "dpc-link", href: detailRepo.homepage ?? detailRepo.url, target: "_blank", rel: "noreferrer", children: t("marketHome") }),
344
+ detailServer !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { className: "dpc-link", href: detailServer.homepage, target: "_blank", rel: "noreferrer", children: t("marketHome") }),
345
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dpc-spacer" }),
346
+ detailRepo !== null && (detailRepo.installedId !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "ghost", disabled: busyId !== null, onClick: () => {
347
+ setConfirmUninstall({ kind: "root", id: detailRepo.installedId, name: title(detailRepo) });
348
+ setDetail(null);
349
+ }, children: t("marketUninstall") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "primary", disabled: busyId !== null, onClick: () => void doInstallRepo(detailRepo), children: busyId === detailRepo.id ? t("marketInstalling") : t("marketInstall") })),
350
+ detailServer !== null && (detailServer.installed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "ghost", disabled: busyId !== null, onClick: () => void mcp.list().then(
351
+ (body) => {
352
+ const row = body.servers.find((item) => item.serverName === detailServer.id);
353
+ if (row !== void 0) {
354
+ setConfirmUninstall({ kind: "mcp", id: row.id, name: title(detailServer) });
355
+ setDetail(null);
356
+ }
357
+ },
358
+ (error) => setOutcome({ ok: false, text: `${t("failed")}: ${String(error.message ?? error)}` })
359
+ ), children: t("marketUninstall") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "primary", disabled: busyId !== null, onClick: () => void doInstallMcp(detailServer), children: busyId === detailServer.id ? t("marketInstalling") : t("marketAdd") }))
360
+ ] }),
361
+ children: [
362
+ detailRepo !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
363
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dpc-detailDesc", children: desc(detailRepo) }),
364
+ detailRepo.skills !== void 0 && detailRepo.skills.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dpc-detailSection", children: [
365
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dpc-detailLabel", children: t("marketSkillListLabel") }),
366
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dpc-detailTags", children: detailRepo.skills.map((name2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dpc-tag", children: name2 }, name2)) })
367
+ ] })
368
+ ] }),
369
+ detailServer !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
370
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dpc-detailDesc", children: desc(detailServer) }),
371
+ detailServer.command !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dpc-detailSection", children: [
372
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dpc-detailLabel", children: t("marketCommandLabel") }),
373
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: "dpc-code", children: [detailServer.command, ...detailServer.args ?? []].join(" ") })
374
+ ] }),
375
+ detailServer.transport === "streamable-http" && detailServer.url !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dpc-detailSection", children: [
376
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dpc-detailLabel", children: t("marketCommandLabel") }),
377
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: "dpc-code", children: detailServer.url })
378
+ ] }),
379
+ detailServer.envKeys !== void 0 && detailServer.envKeys.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dpc-detailSection", children: [
380
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dpc-detailLabel", children: t("marketNeedsEnv") }),
381
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dpc-detailTags", children: detailServer.envKeys.map((key) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dpc-tag", children: key }, key)) })
382
+ ] }),
383
+ detailServer.tools !== void 0 && detailServer.tools.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dpc-detailSection", children: [
384
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dpc-detailLabel", children: t("marketToolsLabel") }),
385
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dpc-detailTags", children: detailServer.tools.map((name2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dpc-tag", children: name2 }, name2)) })
386
+ ] })
387
+ ] })
388
+ ]
389
+ }
390
+ ),
311
391
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
312
392
  import_dsh_client_ui_primitives.Modal,
313
393
  {
@@ -1588,7 +1668,11 @@ var zh = {
1588
1668
  marketNeedsEnv: "\u9700\u8981\u73AF\u5883\u53D8\u91CF",
1589
1669
  marketRepoInstalled: "\u4ED3\u5E93\u5DF2\u5B89\u88C5\uFF0C\u6280\u80FD\u7A0D\u5019\u51FA\u73B0\u5728\u300C\u6280\u80FD\u300D\u9875\u5217\u8868\u3002",
1590
1670
  marketUninstallConfirm: "\u786E\u8BA4\u79FB\u9664\uFF1F",
1591
- marketUninstallRootWarn: "\u5C06\u53D6\u6D88\u626B\u63CF\u8BE5\u4ED3\u5E93\u5E76\u5220\u9664\u4E0B\u8F7D\u7684\u526F\u672C\uFF08\u79FB\u9664\u540E\u53EF\u91CD\u65B0\u5B89\u88C5\uFF09\u3002"
1671
+ marketUninstallRootWarn: "\u5C06\u53D6\u6D88\u626B\u63CF\u8BE5\u4ED3\u5E93\u5E76\u5220\u9664\u4E0B\u8F7D\u7684\u526F\u672C\uFF08\u79FB\u9664\u540E\u53EF\u91CD\u65B0\u5B89\u88C5\uFF09\u3002",
1672
+ marketDetail: "\u8BE6\u60C5",
1673
+ marketSkillListLabel: "\u6280\u80FD\u6E05\u5355",
1674
+ marketToolsLabel: "\u63D0\u4F9B\u5DE5\u5177",
1675
+ marketCommandLabel: "\u542F\u52A8\u547D\u4EE4"
1592
1676
  };
1593
1677
  var en = {
1594
1678
  sectionNav: "Skills & MCP",
@@ -1714,7 +1798,11 @@ var en = {
1714
1798
  marketNeedsEnv: "Needs environment variables",
1715
1799
  marketRepoInstalled: "Repository installed \u2014 its skills appear on the Skills tab shortly.",
1716
1800
  marketUninstallConfirm: "Uninstall?",
1717
- marketUninstallRootWarn: "Stops scanning the repository and deletes the downloaded copy (you can reinstall later)."
1801
+ marketUninstallRootWarn: "Stops scanning the repository and deletes the downloaded copy (you can reinstall later).",
1802
+ marketDetail: "Details",
1803
+ marketSkillListLabel: "Skills included",
1804
+ marketToolsLabel: "Tools provided",
1805
+ marketCommandLabel: "Launch command"
1718
1806
  };
1719
1807
 
1720
1808
  // src/client/index.ts