dsh-as-mcp 0.1.4 → 0.1.5

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
@@ -160,6 +160,9 @@ introduces.
160
160
  }
161
161
  ```
162
162
 
163
+ The settings panel builds exactly this snippet with the token already filled in, so prefer its
164
+ **Copy** button over editing `<token>` by hand.
165
+
163
166
  **stdio-only client** — use the bundled bridge, which forwards each JSON-RPC message to the
164
167
  endpoint over HTTP:
165
168
 
@@ -381,6 +384,15 @@ Then **restart DSH Desktop** to mount the plugin.
381
384
  > row, so the composed result carries **two rows sharing one id** (`dsh --profile <name>
382
385
  > --dump-config` shows both). Use the patch layer or the bundle list, never both. Switch to the
383
386
  > bundle route via `dsh plugin add` when you want it to persist across restarts.
387
+ >
388
+ > This is worse than a duplicated row: **every write from the settings panel is refused**, with
389
+ > `Configuration for "dsh-as-mcp" is overridden by a home patch or command-line overlay`. DSH's
390
+ > config editor validates an edit against the *first* composed row while the Loader applies the
391
+ > *last*, so with two rows they never agree and nothing is ever persisted. The panel only says
392
+ > `Write failed; the host state was re-read. Please retry.` — which reads like a transient
393
+ > failure, not a composition mistake. If you are on the bundle route, delete the hand-written
394
+ > `- insert:` row; if you are on the patch route, remove `dsh-as-mcp` from
395
+ > `dsh.profile.bundles`.
384
396
 
385
397
  ### 3. Smoke-test it
386
398
 
@@ -466,23 +478,32 @@ Changing the port is the case worth stating plainly: the plugin stops the old li
466
478
  starts the new one, so the endpoint really does move. If the new port is taken, the bind error
467
479
  is shown in the panel and in `dsh_info` rather than being swallowed.
468
480
 
469
- The token is rendered **write-only**. Its literal never leaves the host process, so the panel
470
- shows only whether one is set, and a "clear" button. The copyable client configuration uses a
471
- `<token>` placeholder and points at the token file. Live endpoint state (listening, bind error,
472
- enabled tool groups) is served by a read-only route on DSH's connection layer — inside that
473
- layer's Host/Origin and browser-cookie fence, so it inherits DSH's own authorization and is
474
- never exposed on a bare port.
475
-
476
- The panel needs `@deepseek-ai/schemastery` to register a settings namespace; there is no
477
- schemastery-free path in DSH. It is declared as an **optional** peer and loaded by dynamic
478
- import, so a host that cannot supply it loses the section and nothing else — the endpoint keeps
479
- running from the configuration file. `dsh_info` and the smoke script both report which of the
480
- two you have.
481
+ The token is rendered **write-only in the form**: its literal never reaches the settings form, so
482
+ the input only writes, and a "clear" button removes the override this panel wrote (a token the
483
+ composition config supplies is not affected by it and stays in force). Whether one is pinned is
484
+ reported by the host, not guessed by the page: `auth.token` deliberately carries no schema
485
+ default, because the settings service answers "is this secret set?" with `value !== undefined`
486
+ and a default would make every panel claim a token was pinned from the moment the plugin loaded.
487
+
488
+ The panel's **copyable client configuration** is the one place the literal is deliberately handed
489
+ out. The **Copy** button writes the snippet with the real effective token in it, so pasting it
490
+ just works; the text on screen is masked (with a "Show token" button) so a screenshot or a shared
491
+ screen does not leak it. Both come from the same read-only status route, on DSH's connection
492
+ layer — inside that layer's Host/Origin and browser-cookie fence, so it inherits DSH's own
493
+ authorization and is never exposed on a bare port. `dsh_info` still reports only the token's
494
+ source: a caller that authenticated with the token does not need it echoed into its transcript.
495
+
496
+ The panel is a `settings.section` page the browser half registers through
497
+ `ctx.configForms.whileServed`, so it appears only while the host actually serves this entry's
498
+ form. That needs `@deepseek-ai/schemastery`: DSH 0.2.0-rc.2 projects a form only for an entry
499
+ whose `Config` carries a `toJSON()`, and it keeps only fields marked `meta.volatile`. There is
500
+ no schemastery-free path to a panel, so the module is a declared peer and imported directly —
501
+ without it the plugin cannot be imported at all, which is why the compatibility range below is
502
+ what protects a host that cannot supply it.
481
503
 
482
504
  ## Compatibility
483
505
 
484
- - **Harness** ≥ `0.1.5-rc.1` (developed and verified against `dsh-v0.1.5-rc.1`, the version
485
- bundled with DSH Desktop 2.0.9), declared as `peerDependencies["@deepseek-ai/dsh"]:
506
+ - **Harness** ≥ `0.1.5-rc.1`, declared as `peerDependencies["@deepseek-ai/dsh"]:
486
507
  ">=0.1.5-rc.1"` with no upper bound. DSH's plugin loader reads that range straight from the
487
508
  manifest and semver-checks it against the single running runtime version (prereleases
488
509
  included) *before* the plugin is imported; an incompatible install is refused unless the host
@@ -492,14 +513,19 @@ two you have.
492
513
  a full harness install into every profile just to satisfy it. Optional only changes
493
514
  installation — DSH's compatibility gate reads `peerDependencies` regardless of
494
515
  `peerDependenciesMeta`, so the version check above still applies in full.
516
+ - **Settings model.** Verified against `dsh 0.2.0-rc.2`, whose settings service replaced the
517
+ 0.1.x API this plugin first shipped against: `settings.installSection` is gone, a namespace is
518
+ projected from the entry's own `Config` keyed by the Loader row id, and only `meta.volatile`
519
+ fields are editable — a volatile write is committed into the running reference without a
520
+ remount. The host half therefore declares no registration at all and reads its configuration
521
+ through `plainConfig()` on every access, and the only settings call it still makes is
522
+ `configure({ auto: false }, ctx.fiber)` (it ships its own page). **The panel needs the 0.2
523
+ settings model**; on a 0.1.x runtime the endpoint still runs from the configuration file, but
524
+ there is no panel, because that runtime only projects a form for a namespace a plugin
525
+ registered through the removed call.
495
526
  - **No other hard `@deepseek-ai/*` dependency.** This package resolves every other capability
496
- structurally through `ctx.get(name)`, and its config schema is a hand-written
497
- [Standard Schema](https://standardschema.dev) rather than a schemastery schema — which is all
498
- Cordis's `resolveConfig` actually consumes. The one exception is `@deepseek-ai/schemastery`,
499
- also declared as an **optional** peer: DSH offers no schemastery-free path to registering a
500
- settings namespace, so wanting the panel means declaring it — but optional means a host
501
- without it loses only the panel. This is the same stance the installed third-party
502
- `dsh-tokenledger` takes.
527
+ structurally through `ctx.get(name)`. The one exception is `@deepseek-ai/schemastery`, a
528
+ declared peer imported directly: DSH offers no schemastery-free path to a settings form.
503
529
 
504
530
  ## Design notes
505
531
 
package/README.zh.md CHANGED
@@ -153,6 +153,9 @@ dsh --profile <名称> --dump-config | grep -A 30 '# == dsh-as-mcp'
153
153
  }
154
154
  ```
155
155
 
156
+ 配置面板会生成一段一模一样的配置,并且已经填好当前令牌,所以直接用面板上的**复制**按钮,
157
+ 不必手工替换 `<token>`。
158
+
156
159
  **只支持 stdio 的客户端** —— 用随包提供的桥接脚本,它把每条 JSON-RPC 消息通过 HTTP 转给
157
160
  端点:
158
161
 
@@ -349,6 +352,13 @@ cd ~/.dsh/profiles/desktop && pnpm add /tmp/dsh-as-mcp-0.1.0.tgz
349
352
  > ⚠️ **不要同时把 `dsh-as-mcp` 加进 `dsh.profile.bundles`。** bundle 会贡献它自己的行,于是最终
350
353
  > 组合里会出现**两行同 id**(`dsh --profile <name> --dump-config` 会直接显示出 2 行)。用 patch
351
354
  > 层就只走 patch 层。反过来说,想让它跨重启常驻时,才改用 `dsh plugin add` 走 bundle 路线。
355
+ >
356
+ > 后果比"多一行"严重得多:**设置面板的每一次写入都会被拒绝**,错误是
357
+ > `Configuration for "dsh-as-mcp" is overridden by a home patch or command-line overlay`。DSH 的
358
+ > config editor 拿**第一行**组合结果校验编辑,而 Loader 生效的是**最后一行**,两行同 id 时永远
359
+ > 对不上,于是什么也存不下去。面板只会显示"写入失败,已重新读取。请重试。",看起来像偶发故障,
360
+ > 而不是组合写错了。走 bundle 路线就删掉手写的 `- insert:` 那一行;走 patch 路线就把
361
+ > `dsh-as-mcp` 从 `dsh.profile.bundles` 里去掉。
352
362
 
353
363
  ### 3. 冒烟验证
354
364
 
@@ -433,33 +443,43 @@ node ~/.dsh/profiles/desktop/node_modules/dsh-as-mcp/scripts/smoke.mjs \
433
443
  最值得说清的是改端口:插件会先停掉旧监听再起新的,所以端点是真的搬了。如果新端口被占用,
434
444
  绑定错误会显示在面板和 `dsh_info` 里,而不是被吞掉。
435
445
 
436
- 令牌是**只写**的。它的明文从不离开宿主进程,所以面板只能显示“是否已设置”和一个清除按钮;
437
- 可复制的客户端配置用 `<token>` 占位,并指向令牌文件。实时端点状态(是否在监听、绑定错误、
438
- 已启用的工具组)由 DSH connection 层上的一条只读路由提供——它在该层的 Host/Origin 与浏览器
439
- cookie 围栏**之内**,因此自动继承 DSH 自己的鉴权,绝不会暴露在一个裸端口上。
446
+ 令牌在表单里是**只写**的:明文不会进入设置表单,所以输入框只负责写入,另有一个清除按钮用来撤销
447
+ 面板自己写的那一层(如果令牌来自组合配置,清除它不影响该令牌,它仍然生效)。“是否已固定令牌”由
448
+ 宿主回答,而不是页面自己猜——`auth.token` 特意不设 schema 默认值,因为设置服务判断“这个 secret
449
+ 是否已设置”用的是 `value !== undefined`,一旦有默认值,插件一加载面板就会声称令牌已固定。
450
+
451
+ 面板里**可复制的客户端配置**是唯一一处有意交出明文的地方。**复制**按钮写入的片段里是当前真实
452
+ 生效的令牌,粘贴即可用;屏幕上显示的那份则打了掩码(另有一个“显示令牌”按钮),这样截图或共享
453
+ 屏幕都不会泄露它。两者都来自同一条只读状态路由,位于 DSH connection 层——在该层的 Host/Origin
454
+ 与浏览器 cookie 围栏**之内**,因此自动继承 DSH 自己的鉴权,绝不会暴露在一个裸端口上。`dsh_info`
455
+ 仍然只报告令牌来源:已经用这个令牌通过鉴权的调用方,没必要让它再被回显进对话记录里。
440
456
 
441
- 注册 settings 命名空间需要 `@deepseek-ai/schemastery`,DSH 里没有绕开它的路径。本包把它声明为
442
- **可选** peer 并用动态导入加载:宿主提供不了时,只失去这个分组,其他能力一个不少——端点继续
443
- 按配置文件运行。`dsh_info` 和冒烟脚本都会告诉你当前是哪种情况。
457
+ 面板是浏览器半边通过 `ctx.configForms.whileServed` 注册进 `settings.section` 的一页,因此只有宿主
458
+ 确实在提供这一项的配置表单时才会出现。这需要 `@deepseek-ai/schemastery`:DSH 0.2.0-rc.2 只给
459
+ `Config` 上带 `toJSON()` 的 entry 投影表单,而且只保留标了 `meta.volatile` 的字段。DSH 里没有
460
+ 免 schemastery 的面板路径,所以它作为 peer 直接 import——拿不到它插件根本无法被 import,这正是
461
+ 下面那条兼容范围要挡住的情况。
444
462
 
445
463
  ## 兼容性
446
464
 
447
- - **Harness** ≥ `0.1.5-rc.1`(开发与验证基于 `dsh-v0.1.5-rc.1`,即 DSH Desktop 2.0.9 内置
448
- 的版本),声明为 `peerDependencies["@deepseek-ai/dsh"]: ">=0.1.5-rc.1"`,不封顶。DSH 的插件
449
- 加载器会直接从 manifest 里读出这个范围,在插件被 import **之前**就拿它和唯一那个运行时版本做
450
- semver 比对(预发布版也参与比对);不兼容的安装会被拒载,除非宿主显式给出精确版本豁免
451
- (`dsh plugin allow-version`)。
465
+ - **Harness** ≥ `0.1.5-rc.1`,声明为 `peerDependencies["@deepseek-ai/dsh"]: ">=0.1.5-rc.1"`,
466
+ 不封顶。DSH 的插件加载器会直接从 manifest 里读出这个范围,在插件被 import **之前**就拿它和
467
+ 唯一那个运行时版本做 semver 比对(预发布版也参与比对);不兼容的安装会被拒载,除非宿主显式
468
+ 给出精确版本豁免(`dsh plugin allow-version`)。
452
469
  - **Node** `^22.19.0 || >=24.0.0`。
453
470
  - `@deepseek-ai/dsh` 这个 peer 声明为**可选**,纯粹是为了不让 `dsh plugin add` 为了满足它就把
454
471
  一整个 harness 装进每个 profile。可选只影响安装行为——DSH 的兼容性检查不看
455
472
  `peerDependenciesMeta`,只读 `peerDependencies`,所以上面那条版本校验照样生效,一条都不少。
456
- - **没有其它硬 `@deepseek-ai/*` 依赖。** 除了上面这个版本闸门,本包的其它能力都通过
457
- `ctx.get(name)` 做结构化解析,配置 schema 也是手写的
458
- [Standard Schema](https://standardschema.dev) 而不是 schemastery schema——而 Cordis 的
459
- `resolveConfig` 实际消费的就是 Standard Schema。唯一的例外是 `@deepseek-ai/schemastery`,同样
460
- 声明为**可选** peer:DSH 里没有免 schemastery 的 settings 注册路径,所以想要设置面板就必须
461
- 声明它——但声明为可选意味着没装上也只失去面板,核心功能不受影响。这与生态里已有的第三方插件
462
- (`dsh-tokenledger`)做法一致。
473
+ - **设置模型。** 已针对 `dsh 0.2.0-rc.2` 验证:它的 settings 服务换掉了本插件最初面向的 0.1.x
474
+ API——`settings.installSection` 已不存在,命名空间改由 entry 自己的 `Config` 按 Loader 行 id
475
+ 投影,且只有 `meta.volatile` 字段可编辑;volatile 写入直接提交进运行中的引用,不重挂载。因此
476
+ 宿主半边不再做任何注册,每次读取都通过 `plainConfig()` 解出实时值,唯一保留的 settings 调用是
477
+ `configure({ auto: false }, ctx.fiber)`(本插件自带页面)。**面板需要 0.2 的设置模型**;在
478
+ 0.1.x 运行时上端点仍按配置文件正常运行,但没有面板——那种运行时只会为「插件通过已移除的那个
479
+ 调用注册过的命名空间」投影表单。
480
+ - **没有其它硬 `@deepseek-ai/*` 依赖。** 除上面这个版本闸门,本包的其它能力都通过
481
+ `ctx.get(name)` 做结构化解析。唯一的例外是 `@deepseek-ai/schemastery`,作为 peer 直接 import:
482
+ DSH 里没有免 schemastery 的设置表单路径。
463
483
 
464
484
  ## 设计说明
465
485
 
package/cordis.patch.yml CHANGED
@@ -12,6 +12,12 @@
12
12
  # what is tunable at a glance. A profile's own `cordis.patch.yml` overrides this
13
13
  # row by `id`, and a patch replaces a row's entire `config` object rather than
14
14
  # deep-merging it — restate every key you still want.
15
+ #
16
+ # Do NOT insert this row a second time from a profile patch. DSH's settings
17
+ # editor refuses to write a configuration whose id composes twice (it compares
18
+ # the edit against the *first* composed row, while the Loader applies the last),
19
+ # and the only symptom is a panel that reports every write as failed. Listing
20
+ # `dsh-as-mcp` in `dsh.profile.bundles` is the whole install.
15
21
  - insert:
16
22
  - id: dsh-as-mcp
17
23
  name: dsh-as-mcp
@@ -27,10 +33,14 @@
27
33
  # reachable at http://127.0.0.1:<dsh port>/mcp. Off by default because
28
34
  # that server is part of the browser-facing composition.
29
35
  mountOnWebServer: false
30
- auth:
31
- # Empty means: read $DSH_HOME/dsh-as-mcp/token, and generate + persist
32
- # a fresh token when that file does not exist yet.
33
- token: ''
36
+ # `auth.token` is deliberately NOT restated here. Leaving it absent means
37
+ # "read $DSH_HOME/dsh-as-mcp/token, and generate + persist a fresh token
38
+ # when that file does not exist yet" — the same meaning an empty string
39
+ # has for this plugin. But an explicitly empty string is a *present*
40
+ # value, and the settings panel answers "is a token pinned?" with
41
+ # `value !== undefined`, so shipping `token: ''` made every panel claim a
42
+ # token was pinned from the moment the plugin loaded. Set it here only to
43
+ # pin a real secret.
34
44
  tools:
35
45
  workspace: true
36
46
  session: true
package/lib/client.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // This file is generated by `node scripts/build-client.mjs` (esbuild). Do not edit directly.
2
2
  window.__ModuleLoader__.load({ id: "dsh-as-mcp", factory: (require) => {
3
3
  var module = { exports: {} }; var exports = module.exports;
4
- "use strict";var w=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var I=Object.getOwnPropertyNames;var B=Object.prototype.hasOwnProperty;var G=(e,t)=>{for(var n in t)w(e,n,{get:t[n],enumerable:!0})},K=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of I(t))!B.call(e,s)&&s!==n&&w(e,s,{get:()=>t[s],enumerable:!(o=j(t,s))||o.enumerable});return e};var U=e=>K(w({},"__esModule",{value:!0}),e);var ie={};G(ie,{apply:()=>te,inject:()=>X});module.exports=U(ie);var N="/api/dsh-as-mcp/status";var m="dsh-as-mcp",M={nav:"MCP \u670D\u52A1",intro:"\u628A\u5F53\u524D DSH \u5B9E\u4F8B\u4F5C\u4E3A MCP \u670D\u52A1\u91CA\u653E\u51FA\u53BB\uFF0C\u4F9B\u5176\u4ED6 agent \u521B\u5EFA\u5DE5\u4F5C\u533A\u3001\u65B0\u5EFA\u4F1A\u8BDD\u3001\u8BFB\u5199\u6587\u4EF6\u4E0E\u6267\u884C\u547D\u4EE4\u3002\u4FEE\u6539\u5373\u65F6\u751F\u6548\uFF0C\u65E0\u9700\u91CD\u542F\u3002","group.endpoint.title":"\u7AEF\u70B9","group.endpoint.description":"\u5176\u4ED6 agent \u8FDE\u63A5\u8FD9\u4E2A\u5730\u5740\u6765\u8C03\u7528 DSH\u3002","group.tools.title":"\u5DE5\u5177\u5F00\u5173","group.tools.description":"\u5173\u95ED\u7684\u7EC4\u4E0D\u4F1A\u51FA\u73B0\u5728 tools/list \u4E2D\uFF0C\u8C03\u7528\u5B83\u4F1A\u5F97\u5230\u201C\u672A\u77E5\u5DE5\u5177\u201D\uFF0C\u800C\u4E0D\u662F\u6267\u884C\u540E\u88AB\u62D2\u7EDD\u3002","group.session.title":"\u4F1A\u8BDD\u9ED8\u8BA4\u503C","group.session.description":"\u901A\u8FC7 MCP \u65B0\u5EFA\u4F1A\u8BDD\u65F6\u4F7F\u7528\u7684\u9ED8\u8BA4\u9884\u8BBE\u4E0E\u6A21\u578B\u3002","group.limits.title":"\u4E0A\u9650","group.limits.description":"\u5355\u6B21\u8BF7\u6C42\u53EF\u4EE5\u6D88\u8017\u7684\u6700\u5927\u8D44\u6E90\u3002","group.approval.title":"\u5BA1\u6279","group.approval.description":"\u63A7\u5236 MCP \u521B\u5EFA\u7684\u4F1A\u8BDD\u5728\u9700\u8981\u6388\u6743\u65F6\u5982\u4F55\u5904\u7406\u3002","group.auth.title":"\u8BBF\u95EE\u4EE4\u724C","group.auth.description":"\u6240\u6709\u8BF7\u6C42\u90FD\u5FC5\u987B\u643A\u5E26\u8FD9\u4E2A\u4EE4\u724C\u3002","field.http.enabled":"\u542F\u7528 HTTP \u7AEF\u70B9","field.http.enabled.hint":"\u5173\u95ED\u540E\u4E0D\u518D\u76D1\u542C\u7AEF\u53E3\uFF1B\u82E5\u540C\u65F6\u6302\u8F7D\u5728 DSH Web \u670D\u52A1\u5668\u4E0A\uFF0C\u4ECD\u53EF\u901A\u8FC7\u8BE5\u8DEF\u5F84\u8BBF\u95EE\u3002","field.http.host":"\u76D1\u542C\u5730\u5740","field.http.host.hint":"127.0.0.1 \u53EA\u5141\u8BB8\u672C\u673A\u8BBF\u95EE\u30020.0.0.0 \u4F1A\u628A\u7AEF\u70B9\u66B4\u9732\u5230\u5C40\u57DF\u7F51\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u8BBE\u7F6E\u4EE4\u724C\u3002","field.http.port":"\u7AEF\u53E3","field.http.port.hint":"\u88AB\u5360\u7528\u65F6\u7AEF\u70B9\u65E0\u6CD5\u542F\u52A8\uFF0C\u9519\u8BEF\u4F1A\u663E\u793A\u5728\u4E0B\u65B9\u72B6\u6001\u91CC\u3002","field.http.path":"\u8DEF\u5F84","field.http.path.hint":"MCP \u5BA2\u6237\u7AEF\u5E94\u8BBF\u95EE\u7684\u8DEF\u5F84\uFF0C\u9ED8\u8BA4 /mcp\u3002","field.http.mountOnWebServer":"\u540C\u65F6\u6302\u8F7D\u5230 DSH Web \u670D\u52A1\u5668","field.http.mountOnWebServer.hint":"\u901A\u8FC7 DSH \u81EA\u5DF1\u7684\u670D\u52A1\u5668\u540C\u6E90\u63D0\u4F9B\uFF0C\u6D4F\u89C8\u5668\u5BA2\u6237\u7AEF\u56E0\u6B64\u4E0D\u53D7\u8DE8\u57DF\u9650\u5236\u3002","field.tools.workspace":"\u5DE5\u4F5C\u533A","field.tools.workspace.hint":"workspace_create / workspace_list","field.tools.session":"\u4F1A\u8BDD","field.tools.session.hint":"session_create / session_prompt / session_cancel \u7B49","field.tools.files":"\u6587\u4EF6","field.tools.files.hint":"file_read / file_write / file_list","field.tools.shell":"\u547D\u4EE4","field.tools.agentTools":"agent \u5DE5\u5177","field.tools.agentTools.hint":"dsh_tool_list / dsh_tool_call\uFF1A\u76F4\u63A5\u8C03\u7528\u672C\u673A agent \u7684\u5DE5\u5177\uFF0C\u4E0D\u6D88\u8017\u4E00\u8F6E\u6A21\u578B\u3002","group.agentTools.title":"agent \u5DE5\u5177\u767D\u540D\u5355","group.agentTools.description":"dsh_tool_call \u53EF\u4EE5\u89E6\u8FBE\u54EA\u4E9B\u5DE5\u5177\u3002\u8FD9\u662F\u767D\u540D\u5355\uFF1A\u4E0D\u5728\u540D\u5355\u91CC\u7684\u4E00\u5F8B\u62D2\u7EDD\uFF0C\u4E14\u4E0D\u4F1A\u51FA\u73B0\u5728 dsh_tool_list \u4E2D\u3002","field.agentTools.allow":"\u5141\u8BB8\u7684\u5DE5\u5177","field.agentTools.allow.hint":"\u9017\u53F7\u5206\u9694\u3002\u7559\u7A7A\u5219\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4\u96C6\u5408\uFF1B\u4E00\u65E6\u586B\u5199\u5C31\u5B8C\u5168\u53D6\u4EE3\u9ED8\u8BA4\uFF0C\u6240\u4EE5\u653E\u5BBD\u5FC5\u987B\u662F\u6709\u610F\u7684\u3002","field.agentTools.deny":"\u989D\u5916\u6392\u9664\u7684\u5DE5\u5177","field.agentTools.deny.hint":"\u9017\u53F7\u5206\u9694\uFF0C\u4ECE\u4E0A\u9762\u7684\u7ED3\u679C\u91CC\u51CF\u53BB\uFF0C\u7528\u4E8E\u53EA\u505A\u51CF\u6CD5\u800C\u4E0D\u5FC5\u91CD\u6284\u6574\u4EFD\u540D\u5355\u3002","field.tools.shell.hint":"shell_run","field.session.agentPreset":"Agent \u9884\u8BBE","field.session.agentPreset.hint":"\u7559\u7A7A\u8868\u793A\u4F7F\u7528 DSH \u7684\u9ED8\u8BA4\u9884\u8BBE\u3002","field.session.provider":"\u63D0\u4F9B\u65B9","field.session.provider.hint":"\u7559\u7A7A\u8868\u793A\u4F7F\u7528 DSH \u7684\u9ED8\u8BA4\u63D0\u4F9B\u65B9\u3002","field.session.model":"\u6A21\u578B","field.session.model.hint":"\u7559\u7A7A\u8868\u793A\u4F7F\u7528 DSH \u7684\u9ED8\u8BA4\u6A21\u578B\u3002","field.session.promptTimeoutMs":"\u7B49\u5F85\u56DE\u590D\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09","field.session.promptTimeoutMs.hint":"session_prompt \u7B49\u5F85\u4E00\u8F6E\u7ED3\u675F\u7684\u6700\u957F\u65F6\u95F4\uFF0C\u8D85\u65F6\u4E0D\u4EE3\u8868\u4F1A\u8BDD\u88AB\u53D6\u6D88\u3002","field.limits.maxReadBytes":"\u5355\u6B21\u8BFB\u53D6\u4E0A\u9650\uFF08\u5B57\u8282\uFF09","field.limits.maxReadBytes.hint":"\u8D85\u8FC7\u4E0A\u9650\u7684\u5185\u5BB9\u4F1A\u88AB\u622A\u65AD\u3002","field.limits.shellTimeoutMs":"\u547D\u4EE4\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09","field.limits.shellTimeoutMs.hint":"shell_run \u7684\u9ED8\u8BA4\u8D85\u65F6\uFF0C\u5355\u6B21\u8C03\u7528\u53EF\u4EE5\u8986\u76D6\u3002","field.limits.agentToolTimeoutMs":"\u5DE5\u5177\u8C03\u7528\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09","field.limits.agentToolTimeoutMs.hint":"dsh_tool_call \u7684\u9ED8\u8BA4\u8D85\u65F6\uFF0C\u5355\u6B21\u8C03\u7528\u53EF\u4EE5\u8986\u76D6\u3002","field.approval.policy":"\u5BA1\u6279\u7B56\u7565","field.approval.policy.hint":"\u9ED8\u8BA4\u53EA\u5BF9\u672C\u63D2\u4EF6\u521B\u5EFA\u7684\u4F1A\u8BDD\u751F\u6548\uFF0C\u4E0D\u5F71\u54CD DSH \u91CC\u7684\u5176\u4ED6\u4F1A\u8BDD\u3002","field.approval.policy.inherit":"\u7EE7\u627F DSH \u6743\u9650\u8BBE\u7F6E","field.approval.policy.allow":"\u81EA\u52A8\u6279\u51C6\u672C\u63D2\u4EF6\u521B\u5EFA\u7684\u4F1A\u8BDD","field.approval.policy.allow.hint":"\u5371\u9669\uFF1A\u8FD9\u4E9B\u4F1A\u8BDD\u4E0D\u518D\u8BE2\u95EE\uFF0C\u4F1A\u76F4\u63A5\u6267\u884C\u9700\u8981\u6388\u6743\u7684\u64CD\u4F5C\u3002","field.auth.token":"\u4EE4\u724C","field.auth.token.hint":"\u7559\u7A7A\u8868\u793A\u7EE7\u627F\u914D\u7F6E\u5C42\uFF1B\u914D\u7F6E\u5C42\u4E5F\u4E3A\u7A7A\u65F6\u4F7F\u7528 DSH \u751F\u6210\u7684\u4EE4\u724C\u6587\u4EF6\u3002","field.auth.token.set":"\u5DF2\u8BBE\u7F6E","field.auth.token.unset":"\u672A\u8BBE\u7F6E\uFF08\u4F7F\u7528\u751F\u6210\u7684\u4EE4\u724C\uFF09","field.auth.token.replace":"\u66FF\u6362\u4EE4\u724C","field.auth.token.clear":"\u6E05\u9664","field.auth.token.placeholder":"\u7C98\u8D34\u4E00\u4E2A\u4EE4\u724C\u4EE5\u56FA\u5B9A\u5B83","client.title":"\u5BA2\u6237\u7AEF\u914D\u7F6E","client.description":"\u628A\u4E0B\u9762\u8FD9\u6BB5\u7C98\u8D34\u5230 MCP \u5BA2\u6237\u7AEF\u914D\u7F6E\u91CC\u5373\u53EF\u8FDE\u63A5\u3002\u4EE4\u724C\u4E3A\u654F\u611F\u4FE1\u606F\uFF0C\u8BF7\u52FF\u63D0\u4EA4\u5230\u7248\u672C\u5E93\u3002","client.copy":"\u590D\u5236","client.copied":"\u5DF2\u590D\u5236","client.copyFailed":"\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u62E9","client.tokenHidden":"\u4EE4\u724C\u5DF2\u9690\u85CF","client.tokenSource.settings":"\u6765\u81EA\u672C\u9762\u677F","client.tokenSource.config":"\u6765\u81EA\u63D2\u4EF6\u914D\u7F6E","client.tokenSource.file":"\u6765\u81EA\u4EE4\u724C\u6587\u4EF6","client.tokenSource.generated":"\u7531 DSH \u751F\u6210","client.tokenSource.ephemeral":"\u4E34\u65F6\u4EE4\u724C\uFF08\u65E0\u6CD5\u5199\u5165\u78C1\u76D8\uFF09","client.tokenSourceLabel":"\u4EE4\u724C\u6765\u6E90\uFF1A","client.toolsLabel":"\u5DF2\u542F\u7528\u7684\u5DE5\u5177\u7EC4\uFF1A","client.statusLabel":"\u72B6\u6001\uFF1A","client.listening":"\u76D1\u542C\u4E2D","client.notListening":"\u672A\u76D1\u542C","client.mounted":"\u5DF2\u6302\u8F7D\u5230 Web \u670D\u52A1\u5668","client.errorLabel":"\u7ED1\u5B9A\u5931\u8D25\uFF1A","state.loading":"\u6B63\u5728\u8BFB\u53D6\u914D\u7F6E\u2026","state.unavailable":"\u8BBE\u7F6E\u670D\u52A1\u4E0D\u53EF\u7528\uFF0C\u65E0\u6CD5\u4ECE\u9762\u677F\u4FEE\u6539\u914D\u7F6E\u3002","state.readonly":"\u5F53\u524D\u9875\u9762\u65E0\u6CD5\u5199\u5165\u8BBE\u7F6E\uFF08\u975E\u672C\u673A\u8BBF\u95EE\uFF09\u3002","state.writeFailed":"\u5199\u5165\u5931\u8D25\uFF0C\u5DF2\u91CD\u65B0\u8BFB\u53D6\u3002\u8BF7\u91CD\u8BD5\u3002"},P={nav:"MCP server",intro:"Expose this DSH instance as an MCP server, so other agents can create workspaces, start sessions, read and write files, and run commands. Changes apply immediately; no restart.","group.endpoint.title":"Endpoint","group.endpoint.description":"Where other agents connect to reach DSH.","group.tools.title":"Tool groups","group.tools.description":"A disabled group is absent from tools/list, so calling it reports an unknown tool rather than running and being refused.","group.session.title":"Session defaults","group.session.description":"The preset and model used when a session is created over MCP.","group.limits.title":"Limits","group.limits.description":"The most a single request may consume.","group.approval.title":"Approval","group.approval.description":"How sessions created over MCP handle authorization.","group.auth.title":"Access token","group.auth.description":"Every request must carry this token.","field.http.enabled":"Serve the HTTP endpoint","field.http.enabled.hint":"When off, nothing is listening on the port. A mount on the DSH web server, if enabled, stays reachable.","field.http.host":"Bind address","field.http.host.hint":"127.0.0.1 admits only this machine. 0.0.0.0 exposes the endpoint to your network \u2014 make sure a token is set.","field.http.port":"Port","field.http.port.hint":"If the port is taken the endpoint cannot start; the error appears in the status below.","field.http.path":"Path","field.http.path.hint":"The path an MCP client should POST to. Default /mcp.","field.http.mountOnWebServer":"Also mount on the DSH web server","field.http.mountOnWebServer.hint":"Served same-origin through DSH\u2019s own server, so a browser client is not blocked by cross-origin rules.","field.tools.workspace":"Workspaces","field.tools.workspace.hint":"workspace_create / workspace_list","field.tools.session":"Sessions","field.tools.session.hint":"session_create / session_prompt / session_cancel and friends","field.tools.files":"Files","field.tools.files.hint":"file_read / file_write / file_list","field.tools.shell":"Shell","field.tools.agentTools":"Agent tools","field.tools.agentTools.hint":"dsh_tool_list / dsh_tool_call: run this instance's own tools without spending a model turn.","group.agentTools.title":"Agent tool allow-list","group.agentTools.description":"Which tools dsh_tool_call may reach. This is an allow-list: anything absent is refused and hidden from dsh_tool_list.","field.agentTools.allow":"Permitted tools","field.agentTools.allow.hint":"Comma separated. Empty uses the built-in default; any entry replaces that default entirely, so widening is always deliberate.","field.agentTools.deny":"Additionally excluded","field.agentTools.deny.hint":"Comma separated, subtracted from the result above, for narrowing without restating the whole list.","field.tools.shell.hint":"shell_run","field.session.agentPreset":"Agent preset","field.session.agentPreset.hint":"Empty uses DSH\u2019s default preset.","field.session.provider":"Provider","field.session.provider.hint":"Empty uses DSH\u2019s default provider.","field.session.model":"Model","field.session.model.hint":"Empty uses DSH\u2019s default model.","field.session.promptTimeoutMs":"Reply timeout (ms)","field.session.promptTimeoutMs.hint":"How long session_prompt waits for a turn to settle. A timeout does not cancel the session.","field.limits.maxReadBytes":"Read limit (bytes)","field.limits.maxReadBytes.hint":"Content past the limit is truncated.","field.limits.shellTimeoutMs":"Command timeout (ms)","field.limits.shellTimeoutMs.hint":"The default shell_run timeout; a single call may override it.","field.limits.agentToolTimeoutMs":"Tool call timeout (ms)","field.limits.agentToolTimeoutMs.hint":"The default dsh_tool_call timeout; a single call may override it.","field.approval.policy":"Approval policy","field.approval.policy.hint":"Either way this only affects sessions this plugin created, never the rest of DSH.","field.approval.policy.inherit":"Inherit DSH permissions","field.approval.policy.allow":"Auto-approve this plugin\u2019s sessions","field.approval.policy.allow.hint":"Dangerous: those sessions stop asking and will perform operations that need authorization.","field.auth.token":"Token","field.auth.token.hint":"Empty inherits the composition value; if that is empty too, the generated token file is used.","field.auth.token.set":"Set","field.auth.token.unset":"Not set (using the generated token)","field.auth.token.replace":"Replace token","field.auth.token.clear":"Clear","field.auth.token.placeholder":"Paste a token to pin it","client.title":"Client configuration","client.description":"Paste this into your MCP client configuration. The token is a secret \u2014 do not commit it.","client.copy":"Copy","client.copied":"Copied","client.copyFailed":"Copy failed; select it manually","client.tokenHidden":"token hidden","client.tokenSource.settings":"this panel","client.tokenSource.config":"plugin configuration","client.tokenSource.file":"the token file","client.tokenSource.generated":"generated by DSH","client.tokenSource.ephemeral":"ephemeral (could not write to disk)","client.tokenSourceLabel":"Token source: ","client.toolsLabel":"Enabled tool groups: ","client.statusLabel":"Status: ","client.listening":"listening","client.notListening":"not listening","client.mounted":"mounted on the web server","client.errorLabel":"Bind failed: ","state.loading":"Reading configuration\u2026","state.unavailable":"The settings service is unavailable, so this panel cannot change the configuration.","state.readonly":"This page cannot write settings (it is not a loopback page).","state.writeFailed":"Write failed; the host state was re-read. Please retry."};var d=require("react");var D=[{id:"endpoint",title:"group.endpoint.title",description:"group.endpoint.description",fields:[{kind:"toggle",path:["http","enabled"],label:"field.http.enabled",hint:"field.http.enabled.hint"},{kind:"text",path:["http","host"],label:"field.http.host",hint:"field.http.host.hint"},{kind:"number",path:["http","port"],label:"field.http.port",hint:"field.http.port.hint",min:0,max:65535},{kind:"text",path:["http","path"],label:"field.http.path",hint:"field.http.path.hint"},{kind:"toggle",path:["http","mountOnWebServer"],label:"field.http.mountOnWebServer",hint:"field.http.mountOnWebServer.hint"}]},{id:"tools",title:"group.tools.title",description:"group.tools.description",fields:[{kind:"toggle",path:["tools","workspace"],label:"field.tools.workspace",hint:"field.tools.workspace.hint"},{kind:"toggle",path:["tools","session"],label:"field.tools.session",hint:"field.tools.session.hint"},{kind:"toggle",path:["tools","files"],label:"field.tools.files",hint:"field.tools.files.hint"},{kind:"toggle",path:["tools","shell"],label:"field.tools.shell",hint:"field.tools.shell.hint"},{kind:"toggle",path:["tools","agentTools"],label:"field.tools.agentTools",hint:"field.tools.agentTools.hint"}]},{id:"agentTools",title:"group.agentTools.title",description:"group.agentTools.description",fields:[{kind:"list",path:["agentTools","allow"],label:"field.agentTools.allow",hint:"field.agentTools.allow.hint",placeholder:"read, write, bash"},{kind:"list",path:["agentTools","deny"],label:"field.agentTools.deny",hint:"field.agentTools.deny.hint",placeholder:"bash, pwsh"}]},{id:"session",title:"group.session.title",description:"group.session.description",fields:[{kind:"text",path:["session","agentPreset"],label:"field.session.agentPreset",hint:"field.session.agentPreset.hint"},{kind:"text",path:["session","provider"],label:"field.session.provider",hint:"field.session.provider.hint"},{kind:"text",path:["session","model"],label:"field.session.model",hint:"field.session.model.hint"},{kind:"number",path:["session","promptTimeoutMs"],label:"field.session.promptTimeoutMs",hint:"field.session.promptTimeoutMs.hint",min:0}]},{id:"limits",title:"group.limits.title",description:"group.limits.description",fields:[{kind:"number",path:["limits","maxReadBytes"],label:"field.limits.maxReadBytes",hint:"field.limits.maxReadBytes.hint",min:1},{kind:"number",path:["limits","shellTimeoutMs"],label:"field.limits.shellTimeoutMs",hint:"field.limits.shellTimeoutMs.hint",min:0},{kind:"number",path:["limits","agentToolTimeoutMs"],label:"field.limits.agentToolTimeoutMs",hint:"field.limits.agentToolTimeoutMs.hint",min:0}]},{id:"approval",title:"group.approval.title",description:"group.approval.description",fields:[{kind:"select",path:["approval","policy"],label:"field.approval.policy",hint:"field.approval.policy.hint",options:[{value:"inherit",label:"field.approval.policy.inherit"},{value:"allow",label:"field.approval.policy.allow"}]}]}];function f(e,t){let n=e;for(let o of t){if(n===null||typeof n!="object")return;n=n[o]}return n}function S(e){return e.join(".")}function E(e){return Array.isArray(e)?e.map(t=>String(t)).join(", "):""}function H(e){return e.split(/[,\n]/).map(t=>t.trim()).filter(t=>t!=="")}var i=require("react/jsx-runtime");function R({value:e,disabled:t,placeholder:n,type:o,min:s,max:a,onCommit:l}){let[r,h]=(0,d.useState)(e),u=(0,d.useRef)(!1);return(0,d.useEffect)(()=>{u.current||h(e)},[e]),(0,i.jsx)("input",{className:"dshmcp_input",type:o,value:r,disabled:t,...n===void 0?{}:{placeholder:n},...s===void 0?{}:{min:s},...a===void 0?{}:{max:a},onFocus:()=>{u.current=!0},onChange:p=>{h(p.target.value)},onBlur:()=>{u.current=!1,r!==e&&l(r)},onKeyDown:p=>{p.key==="Enter"&&p.target.blur(),p.key==="Escape"&&u.current&&(u.current=!1,h(e),p.target.blur())}})}function $({t:e,field:t,value:n,disabled:o,onWrite:s}){let a=t.kind==="text"||t.kind==="number"||t.kind==="list";return(0,i.jsxs)("label",{className:`dshmcp_row${a?" dshmcp_rowStack":""}`,"data-field":S(t.path),children:[(0,i.jsxs)("span",{className:"dshmcp_rowMain",children:[(0,i.jsx)("span",{className:"dshmcp_label",children:e(t.label)}),t.hint!==void 0&&(0,i.jsx)("span",{className:"dshmcp_hint",children:e(t.hint)})]}),(0,i.jsxs)("span",{className:"dshmcp_control",children:[t.kind==="toggle"&&(0,i.jsx)("input",{className:"dshmcp_check",type:"checkbox",checked:n===!0,disabled:o,onChange:l=>{s(l.target.checked)}}),t.kind==="list"&&(0,i.jsx)(R,{type:"text",value:E(n),disabled:o,...t.placeholder===void 0?{}:{placeholder:t.placeholder},onCommit:l=>{s(H(l))}}),(t.kind==="text"||t.kind==="number")&&(0,i.jsx)(R,{type:t.kind==="number"?"number":"text",value:n==null?"":String(n),disabled:o,...t.placeholder===void 0?{}:{placeholder:t.placeholder},...t.min===void 0?{}:{min:t.min},...t.max===void 0?{}:{max:t.max},onCommit:l=>{if(t.kind==="text"){s(l);return}let r=Number(l);l.trim()===""||!Number.isFinite(r)||t.min!==void 0&&r<t.min||t.max!==void 0&&r>t.max||s(r)}}),t.kind==="select"&&(0,i.jsx)("select",{className:"dshmcp_input",value:n==null?"":String(n),disabled:o,onChange:l=>{s(l.target.value)},children:(t.options??[]).map(l=>(0,i.jsx)("option",{value:l.value,children:e(l.label)},l.value))})]})]})}function q({t:e,group:t,value:n,disabled:o,onWrite:s}){return(0,i.jsxs)("section",{className:"dshmcp_group",children:[(0,i.jsx)("h3",{className:"dshmcp_groupTitle",children:e(t.title)}),(0,i.jsx)("p",{className:"dshmcp_groupDesc",children:e(t.description)}),(0,i.jsx)("div",{className:"dshmcp_rows",children:t.fields.map(a=>(0,i.jsx)($,{t:e,field:a,value:f(n,a.path),disabled:o,onWrite:l=>{s(a,l)}},S(a.path)))})]})}function J({t:e,isSet:t,disabled:n,onWrite:o,onClear:s}){let[a,l]=(0,d.useState)("");return(0,i.jsxs)("label",{className:"dshmcp_row dshmcp_rowStack","data-field":"auth.token",children:[(0,i.jsxs)("span",{className:"dshmcp_rowMain",children:[(0,i.jsxs)("span",{className:"dshmcp_label",children:[e("field.auth.token")," ",(0,i.jsx)("span",{className:`dshmcp_badge${t?" dshmcp_badgeOk":""}`,children:e(t?"field.auth.token.set":"field.auth.token.unset")})]}),(0,i.jsx)("span",{className:"dshmcp_hint",children:e("field.auth.token.hint")})]}),(0,i.jsxs)("span",{className:"dshmcp_control",children:[(0,i.jsx)("input",{className:"dshmcp_input",type:"password",value:a,disabled:n,placeholder:e("field.auth.token.placeholder"),autoComplete:"off",onChange:r=>{l(r.target.value)},onBlur:()=>{a!==""&&(o(a),l(""))},onKeyDown:r=>{r.key==="Enter"&&r.target.blur()}}),t&&(0,i.jsx)("button",{className:"dshmcp_btn",type:"button",disabled:n,onClick:s,children:e("field.auth.token.clear")})]})]})}function Z({t:e,url:t,mounted:n,tokenFile:o,status:s,statusRead:a}){let[l,r]=(0,d.useState)("idle"),h=JSON.stringify({mcpServers:{dsh:{type:"http",url:t,headers:{Authorization:"Bearer <token>"}}}},null,2);return(0,i.jsxs)("section",{className:"dshmcp_group",children:[(0,i.jsx)("h3",{className:"dshmcp_groupTitle",children:e("client.title")}),(0,i.jsx)("p",{className:"dshmcp_groupDesc",children:e("client.description")}),(0,i.jsx)("pre",{className:"dshmcp_code",children:h}),(0,i.jsxs)("div",{className:"dshmcp_control",children:[(0,i.jsx)("button",{className:"dshmcp_btn",type:"button",onClick:()=>{navigator.clipboard.writeText(h).then(()=>{r("ok")}).catch(()=>{r("failed")})},children:e(l==="ok"?"client.copied":l==="failed"?"client.copyFailed":"client.copy")}),a&&(0,i.jsx)("span",{className:`dshmcp_badge${s?.listening===!0?" dshmcp_badgeOk":""}`,children:s?.listening===!0?e("client.listening"):e("client.notListening")}),n&&(0,i.jsx)("span",{className:"dshmcp_badge",children:e("client.mounted")})]}),(0,i.jsxs)("p",{className:"dshmcp_note",children:[e("field.auth.token.hint")," \u2192 ",(0,i.jsx)("code",{children:o})]}),s!==void 0&&s.enabledToolGroups.length>0&&(0,i.jsxs)("p",{className:"dshmcp_note",children:[e("client.toolsLabel"),s.enabledToolGroups.join(", ")]}),s?.error!=null&&(0,i.jsxs)("p",{className:"dshmcp_error",children:[e("client.errorLabel"),s.error]})]})}function F({t:e,store:t,tokenFile:n}){let o=(0,d.useSyncExternalStore)(t.subscribe,t.getSnapshot),[s,a]=(0,d.useState)(!1),[l,r]=(0,d.useState)(),[h,u]=(0,d.useState)(!1),p=o.value,_=o.writable&&o.status==="ready"&&p!==void 0;(0,d.useEffect)(()=>{let c=!0,g=()=>{t.readStatus().then(W=>{c&&(u(!0),r(W))})};g();let v=setInterval(g,5e3);return()=>{c=!1,clearInterval(v)}},[t]);let T=(0,d.useCallback)((c,g)=>{a(!1),t.mutate([{op:"set",path:[...c],value:g}],o.revision).catch(()=>{a(!0)})},[t,o.revision]),L=(0,d.useCallback)(c=>{a(!1),t.mutate([{op:"unset",path:[...c]}],o.revision).catch(()=>{a(!0)})},[t,o.revision]),k=f(p,["http","host"]),O=f(p,["http","port"]),z=f(p,["http","path"]),C=typeof k=="string"&&k!==""?k:"127.0.0.1",A=`http://${C==="0.0.0.0"?"127.0.0.1":C}:${String(O??"")}${String(z??"")}`;return(0,i.jsxs)("div",{className:"dshmcp",children:[(0,i.jsx)("p",{className:"dshmcp_intro",children:e("intro")}),o.status==="loading"&&(0,i.jsx)("p",{className:"dshmcp_note",children:e("state.loading")}),o.status==="unavailable"&&(0,i.jsx)("p",{className:"dshmcp_error",children:e("state.unavailable")}),o.status==="ready"&&!o.writable&&(0,i.jsx)("p",{className:"dshmcp_note",children:e("state.readonly")}),s&&(0,i.jsx)("p",{className:"dshmcp_error",children:e("state.writeFailed")}),D.map(c=>(0,i.jsx)(q,{t:e,group:c,value:p,disabled:!_,onWrite:(g,v)=>{T(g.path,v)}},c.id)),(0,i.jsxs)("section",{className:"dshmcp_group",children:[(0,i.jsx)("h3",{className:"dshmcp_groupTitle",children:e("group.auth.title")}),(0,i.jsx)("p",{className:"dshmcp_groupDesc",children:e("group.auth.description")}),(0,i.jsx)("div",{className:"dshmcp_rows",children:(0,i.jsx)(J,{t:e,isSet:t.secretIsSet(),disabled:!_,onWrite:c=>{T(["auth","token"],c)},onClear:()=>{L(["auth","token"])}})})]}),(0,i.jsx)(Z,{t:e,url:A,mounted:f(p,["http","mountOnWebServer"])===!0,tokenFile:l?.tokenFile??n,status:l,statusRead:h})]})}var x="dsh-as-mcp",Q=`
4
+ "use strict";var T=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var Q=(e,t)=>{for(var o in t)T(e,o,{get:t[o],enumerable:!0})},V=(e,t,o,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let l of Y(t))!Z.call(e,l)&&l!==o&&T(e,l,{get:()=>t[l],enumerable:!(i=J(t,l))||i.enumerable});return e};var X=e=>V(T({},"__esModule",{value:!0}),e);var pe={};Q(pe,{apply:()=>de,inject:()=>le});module.exports=X(pe);var F="/api/dsh-as-mcp/status";var v="dsh-as-mcp",L={nav:"MCP \u670D\u52A1",intro:"\u628A\u5F53\u524D DSH \u5B9E\u4F8B\u4F5C\u4E3A MCP \u670D\u52A1\u91CA\u653E\u51FA\u53BB\uFF0C\u4F9B\u5176\u4ED6 agent \u521B\u5EFA\u5DE5\u4F5C\u533A\u3001\u65B0\u5EFA\u4F1A\u8BDD\u3001\u8BFB\u5199\u6587\u4EF6\u4E0E\u6267\u884C\u547D\u4EE4\u3002\u4FEE\u6539\u5373\u65F6\u751F\u6548\uFF0C\u65E0\u9700\u91CD\u542F\u3002","group.endpoint.title":"\u7AEF\u70B9","group.endpoint.description":"\u5176\u4ED6 agent \u8FDE\u63A5\u8FD9\u4E2A\u5730\u5740\u6765\u8C03\u7528 DSH\u3002","group.tools.title":"\u5DE5\u5177\u5F00\u5173","group.tools.description":"\u5173\u95ED\u7684\u7EC4\u4E0D\u4F1A\u51FA\u73B0\u5728 tools/list \u4E2D\uFF0C\u8C03\u7528\u5B83\u4F1A\u5F97\u5230\u201C\u672A\u77E5\u5DE5\u5177\u201D\uFF0C\u800C\u4E0D\u662F\u6267\u884C\u540E\u88AB\u62D2\u7EDD\u3002","group.session.title":"\u4F1A\u8BDD\u9ED8\u8BA4\u503C","group.session.description":"\u901A\u8FC7 MCP \u65B0\u5EFA\u4F1A\u8BDD\u65F6\u4F7F\u7528\u7684\u9ED8\u8BA4\u9884\u8BBE\u4E0E\u6A21\u578B\u3002","group.limits.title":"\u4E0A\u9650","group.limits.description":"\u5355\u6B21\u8BF7\u6C42\u53EF\u4EE5\u6D88\u8017\u7684\u6700\u5927\u8D44\u6E90\u3002","group.approval.title":"\u5BA1\u6279","group.approval.description":"\u63A7\u5236 MCP \u521B\u5EFA\u7684\u4F1A\u8BDD\u5728\u9700\u8981\u6388\u6743\u65F6\u5982\u4F55\u5904\u7406\u3002","group.auth.title":"\u8BBF\u95EE\u4EE4\u724C","group.auth.description":"\u6240\u6709\u8BF7\u6C42\u90FD\u5FC5\u987B\u643A\u5E26\u8FD9\u4E2A\u4EE4\u724C\u3002","field.http.enabled":"\u542F\u7528 HTTP \u7AEF\u70B9","field.http.enabled.hint":"\u5173\u95ED\u540E\u4E0D\u518D\u76D1\u542C\u7AEF\u53E3\uFF1B\u82E5\u540C\u65F6\u6302\u8F7D\u5728 DSH Web \u670D\u52A1\u5668\u4E0A\uFF0C\u4ECD\u53EF\u901A\u8FC7\u8BE5\u8DEF\u5F84\u8BBF\u95EE\u3002","field.http.host":"\u76D1\u542C\u5730\u5740","field.http.host.hint":"127.0.0.1 \u53EA\u5141\u8BB8\u672C\u673A\u8BBF\u95EE\u30020.0.0.0 \u4F1A\u628A\u7AEF\u70B9\u66B4\u9732\u5230\u5C40\u57DF\u7F51\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u8BBE\u7F6E\u4EE4\u724C\u3002","field.http.port":"\u7AEF\u53E3","field.http.port.hint":"\u88AB\u5360\u7528\u65F6\u7AEF\u70B9\u65E0\u6CD5\u542F\u52A8\uFF0C\u9519\u8BEF\u4F1A\u663E\u793A\u5728\u4E0B\u65B9\u72B6\u6001\u91CC\u3002","field.http.path":"\u8DEF\u5F84","field.http.path.hint":"MCP \u5BA2\u6237\u7AEF\u5E94\u8BBF\u95EE\u7684\u8DEF\u5F84\uFF0C\u9ED8\u8BA4 /mcp\u3002","field.http.mountOnWebServer":"\u540C\u65F6\u6302\u8F7D\u5230 DSH Web \u670D\u52A1\u5668","field.http.mountOnWebServer.hint":"\u901A\u8FC7 DSH \u81EA\u5DF1\u7684\u670D\u52A1\u5668\u540C\u6E90\u63D0\u4F9B\uFF0C\u6D4F\u89C8\u5668\u5BA2\u6237\u7AEF\u56E0\u6B64\u4E0D\u53D7\u8DE8\u57DF\u9650\u5236\u3002","field.tools.workspace":"\u5DE5\u4F5C\u533A","field.tools.workspace.hint":"workspace_create / workspace_list","field.tools.session":"\u4F1A\u8BDD","field.tools.session.hint":"session_create / session_prompt / session_cancel \u7B49","field.tools.files":"\u6587\u4EF6","field.tools.files.hint":"file_read / file_write / file_list","field.tools.shell":"\u547D\u4EE4","field.tools.agentTools":"agent \u5DE5\u5177","field.tools.agentTools.hint":"dsh_tool_list / dsh_tool_call\uFF1A\u76F4\u63A5\u8C03\u7528\u672C\u673A agent \u7684\u5DE5\u5177\uFF0C\u4E0D\u6D88\u8017\u4E00\u8F6E\u6A21\u578B\u3002","group.agentTools.title":"agent \u5DE5\u5177\u767D\u540D\u5355","group.agentTools.description":"dsh_tool_call \u53EF\u4EE5\u89E6\u8FBE\u54EA\u4E9B\u5DE5\u5177\u3002\u8FD9\u662F\u767D\u540D\u5355\uFF1A\u4E0D\u5728\u540D\u5355\u91CC\u7684\u4E00\u5F8B\u62D2\u7EDD\uFF0C\u4E14\u4E0D\u4F1A\u51FA\u73B0\u5728 dsh_tool_list \u4E2D\u3002","field.agentTools.allow":"\u5141\u8BB8\u7684\u5DE5\u5177","field.agentTools.allow.hint":"\u9017\u53F7\u5206\u9694\u3002\u7559\u7A7A\u5219\u4F7F\u7528\u5185\u7F6E\u9ED8\u8BA4\u96C6\u5408\uFF1B\u4E00\u65E6\u586B\u5199\u5C31\u5B8C\u5168\u53D6\u4EE3\u9ED8\u8BA4\uFF0C\u6240\u4EE5\u653E\u5BBD\u5FC5\u987B\u662F\u6709\u610F\u7684\u3002","field.agentTools.deny":"\u989D\u5916\u6392\u9664\u7684\u5DE5\u5177","field.agentTools.deny.hint":"\u9017\u53F7\u5206\u9694\uFF0C\u4ECE\u4E0A\u9762\u7684\u7ED3\u679C\u91CC\u51CF\u53BB\uFF0C\u7528\u4E8E\u53EA\u505A\u51CF\u6CD5\u800C\u4E0D\u5FC5\u91CD\u6284\u6574\u4EFD\u540D\u5355\u3002","field.tools.shell.hint":"shell_run","field.session.agentPreset":"Agent \u9884\u8BBE","field.session.agentPreset.hint":"\u7559\u7A7A\u8868\u793A\u4F7F\u7528 DSH \u7684\u9ED8\u8BA4\u9884\u8BBE\u3002","field.session.provider":"\u63D0\u4F9B\u65B9","field.session.provider.hint":"\u7559\u7A7A\u8868\u793A\u4F7F\u7528 DSH \u7684\u9ED8\u8BA4\u63D0\u4F9B\u65B9\u3002","field.session.model":"\u6A21\u578B","field.session.model.hint":"\u7559\u7A7A\u8868\u793A\u4F7F\u7528 DSH \u7684\u9ED8\u8BA4\u6A21\u578B\u3002","field.session.promptTimeoutMs":"\u7B49\u5F85\u56DE\u590D\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09","field.session.promptTimeoutMs.hint":"session_prompt \u7B49\u5F85\u4E00\u8F6E\u7ED3\u675F\u7684\u6700\u957F\u65F6\u95F4\uFF0C\u8D85\u65F6\u4E0D\u4EE3\u8868\u4F1A\u8BDD\u88AB\u53D6\u6D88\u3002","field.limits.maxReadBytes":"\u5355\u6B21\u8BFB\u53D6\u4E0A\u9650\uFF08\u5B57\u8282\uFF09","field.limits.maxReadBytes.hint":"\u8D85\u8FC7\u4E0A\u9650\u7684\u5185\u5BB9\u4F1A\u88AB\u622A\u65AD\u3002","field.limits.shellTimeoutMs":"\u547D\u4EE4\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09","field.limits.shellTimeoutMs.hint":"shell_run \u7684\u9ED8\u8BA4\u8D85\u65F6\uFF0C\u5355\u6B21\u8C03\u7528\u53EF\u4EE5\u8986\u76D6\u3002","field.limits.agentToolTimeoutMs":"\u5DE5\u5177\u8C03\u7528\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09","field.limits.agentToolTimeoutMs.hint":"dsh_tool_call \u7684\u9ED8\u8BA4\u8D85\u65F6\uFF0C\u5355\u6B21\u8C03\u7528\u53EF\u4EE5\u8986\u76D6\u3002","field.approval.policy":"\u5BA1\u6279\u7B56\u7565","field.approval.policy.hint":"\u9ED8\u8BA4\u53EA\u5BF9\u672C\u63D2\u4EF6\u521B\u5EFA\u7684\u4F1A\u8BDD\u751F\u6548\uFF0C\u4E0D\u5F71\u54CD DSH \u91CC\u7684\u5176\u4ED6\u4F1A\u8BDD\u3002","field.approval.policy.inherit":"\u7EE7\u627F DSH \u6743\u9650\u8BBE\u7F6E","field.approval.policy.allow":"\u81EA\u52A8\u6279\u51C6\u672C\u63D2\u4EF6\u521B\u5EFA\u7684\u4F1A\u8BDD","field.approval.policy.allow.hint":"\u5371\u9669\uFF1A\u8FD9\u4E9B\u4F1A\u8BDD\u4E0D\u518D\u8BE2\u95EE\uFF0C\u4F1A\u76F4\u63A5\u6267\u884C\u9700\u8981\u6388\u6743\u7684\u64CD\u4F5C\u3002","field.auth.token":"\u4EE4\u724C","field.auth.token.hint":"\u7559\u7A7A\u8868\u793A\u7EE7\u627F\u914D\u7F6E\u5C42\uFF1B\u914D\u7F6E\u5C42\u4E5F\u4E3A\u7A7A\u65F6\u4F7F\u7528 DSH \u751F\u6210\u7684\u4EE4\u724C\u6587\u4EF6\u3002","field.auth.token.set":"\u5DF2\u8BBE\u7F6E","field.auth.token.unset":"\u672A\u8BBE\u7F6E\uFF08\u4F7F\u7528\u751F\u6210\u7684\u4EE4\u724C\uFF09","field.auth.token.replace":"\u66FF\u6362\u4EE4\u724C","field.auth.token.clear":"\u6E05\u9664","field.auth.token.placeholder":"\u7C98\u8D34\u4E00\u4E2A\u4EE4\u724C\u4EE5\u56FA\u5B9A\u5B83","client.title":"\u5BA2\u6237\u7AEF\u914D\u7F6E","client.description":"\u628A\u4E0B\u9762\u8FD9\u6BB5\u7C98\u8D34\u5230 MCP \u5BA2\u6237\u7AEF\u914D\u7F6E\u91CC\u5373\u53EF\u8FDE\u63A5\u3002\u590D\u5236\u65F6\u4F1A\u586B\u5165\u5F53\u524D\u751F\u6548\u7684\u4EE4\u724C\uFF08\u754C\u9762\u4E0A\u53EA\u663E\u793A\u63A9\u7801\uFF0C\u53EF\u70B9\u201C\u663E\u793A\u4EE4\u724C\u201D\u6838\u5BF9\uFF09\u3002\u4EE4\u724C\u4E3A\u654F\u611F\u4FE1\u606F\uFF0C\u8BF7\u52FF\u63D0\u4EA4\u5230\u7248\u672C\u5E93\u3002","client.copy":"\u590D\u5236","client.copied":"\u5DF2\u590D\u5236","client.copyFailed":"\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u62E9","client.reveal":"\u663E\u793A\u4EE4\u724C","client.hide":"\u9690\u85CF\u4EE4\u724C","client.tokenSource.settings":"\u5DF2\u56FA\u5B9A\uFF0C\u53EF\u5728\u4E0A\u65B9\u66FF\u6362","client.tokenSource.config":"\u5DF2\u5728\u63D2\u4EF6\u914D\u7F6E\u91CC\u56FA\u5B9A","client.tokenSource.file":"\u6765\u81EA\u4EE4\u724C\u6587\u4EF6","client.tokenSource.generated":"\u7531 DSH \u751F\u6210","client.tokenSource.ephemeral":"\u4E34\u65F6\u4EE4\u724C\uFF08\u65E0\u6CD5\u5199\u5165\u78C1\u76D8\uFF09","client.tokenSourceLabel":"\u4EE4\u724C\uFF1A","client.tokenUnknown":"\u672A\u77E5\uFF08\u5BBF\u4E3B\u6CA1\u6709\u63D0\u4F9B\uFF09","client.tokenUnknownHint":"\u62FF\u4E0D\u5230\u5F53\u524D\u4EE4\u724C\uFF0C\u590D\u5236\u51FA\u7684\u914D\u7F6E\u91CC\u4ECD\u662F\u5360\u4F4D\u7B26\uFF1B\u53EF\u4EE5\u76F4\u63A5\u8BFB\u53D6\u8FD9\u4E2A\u6587\u4EF6\uFF1A","client.toolsLabel":"\u5DF2\u542F\u7528\u7684\u5DE5\u5177\u7EC4\uFF1A","client.statusLabel":"\u72B6\u6001\uFF1A","client.listening":"\u76D1\u542C\u4E2D","client.notListening":"\u672A\u76D1\u542C","client.mounted":"\u5DF2\u6302\u8F7D\u5230 Web \u670D\u52A1\u5668","client.errorLabel":"\u7ED1\u5B9A\u5931\u8D25\uFF1A","state.loading":"\u6B63\u5728\u8BFB\u53D6\u914D\u7F6E\u2026","state.unavailable":"\u8BBE\u7F6E\u670D\u52A1\u4E0D\u53EF\u7528\uFF0C\u65E0\u6CD5\u4ECE\u9762\u677F\u4FEE\u6539\u914D\u7F6E\u3002","state.readonly":"\u5F53\u524D\u9875\u9762\u65E0\u6CD5\u5199\u5165\u8BBE\u7F6E\uFF08\u975E\u672C\u673A\u8BBF\u95EE\uFF09\u3002","state.writeFailed":"\u5199\u5165\u5931\u8D25\uFF0C\u5DF2\u91CD\u65B0\u8BFB\u53D6\u3002\u8BF7\u91CD\u8BD5\u3002"},R={nav:"MCP server",intro:"Expose this DSH instance as an MCP server, so other agents can create workspaces, start sessions, read and write files, and run commands. Changes apply immediately; no restart.","group.endpoint.title":"Endpoint","group.endpoint.description":"Where other agents connect to reach DSH.","group.tools.title":"Tool groups","group.tools.description":"A disabled group is absent from tools/list, so calling it reports an unknown tool rather than running and being refused.","group.session.title":"Session defaults","group.session.description":"The preset and model used when a session is created over MCP.","group.limits.title":"Limits","group.limits.description":"The most a single request may consume.","group.approval.title":"Approval","group.approval.description":"How sessions created over MCP handle authorization.","group.auth.title":"Access token","group.auth.description":"Every request must carry this token.","field.http.enabled":"Serve the HTTP endpoint","field.http.enabled.hint":"When off, nothing is listening on the port. A mount on the DSH web server, if enabled, stays reachable.","field.http.host":"Bind address","field.http.host.hint":"127.0.0.1 admits only this machine. 0.0.0.0 exposes the endpoint to your network \u2014 make sure a token is set.","field.http.port":"Port","field.http.port.hint":"If the port is taken the endpoint cannot start; the error appears in the status below.","field.http.path":"Path","field.http.path.hint":"The path an MCP client should POST to. Default /mcp.","field.http.mountOnWebServer":"Also mount on the DSH web server","field.http.mountOnWebServer.hint":"Served same-origin through DSH\u2019s own server, so a browser client is not blocked by cross-origin rules.","field.tools.workspace":"Workspaces","field.tools.workspace.hint":"workspace_create / workspace_list","field.tools.session":"Sessions","field.tools.session.hint":"session_create / session_prompt / session_cancel and friends","field.tools.files":"Files","field.tools.files.hint":"file_read / file_write / file_list","field.tools.shell":"Shell","field.tools.agentTools":"Agent tools","field.tools.agentTools.hint":"dsh_tool_list / dsh_tool_call: run this instance's own tools without spending a model turn.","group.agentTools.title":"Agent tool allow-list","group.agentTools.description":"Which tools dsh_tool_call may reach. This is an allow-list: anything absent is refused and hidden from dsh_tool_list.","field.agentTools.allow":"Permitted tools","field.agentTools.allow.hint":"Comma separated. Empty uses the built-in default; any entry replaces that default entirely, so widening is always deliberate.","field.agentTools.deny":"Additionally excluded","field.agentTools.deny.hint":"Comma separated, subtracted from the result above, for narrowing without restating the whole list.","field.tools.shell.hint":"shell_run","field.session.agentPreset":"Agent preset","field.session.agentPreset.hint":"Empty uses DSH\u2019s default preset.","field.session.provider":"Provider","field.session.provider.hint":"Empty uses DSH\u2019s default provider.","field.session.model":"Model","field.session.model.hint":"Empty uses DSH\u2019s default model.","field.session.promptTimeoutMs":"Reply timeout (ms)","field.session.promptTimeoutMs.hint":"How long session_prompt waits for a turn to settle. A timeout does not cancel the session.","field.limits.maxReadBytes":"Read limit (bytes)","field.limits.maxReadBytes.hint":"Content past the limit is truncated.","field.limits.shellTimeoutMs":"Command timeout (ms)","field.limits.shellTimeoutMs.hint":"The default shell_run timeout; a single call may override it.","field.limits.agentToolTimeoutMs":"Tool call timeout (ms)","field.limits.agentToolTimeoutMs.hint":"The default dsh_tool_call timeout; a single call may override it.","field.approval.policy":"Approval policy","field.approval.policy.hint":"Either way this only affects sessions this plugin created, never the rest of DSH.","field.approval.policy.inherit":"Inherit DSH permissions","field.approval.policy.allow":"Auto-approve this plugin\u2019s sessions","field.approval.policy.allow.hint":"Dangerous: those sessions stop asking and will perform operations that need authorization.","field.auth.token":"Token","field.auth.token.hint":"Empty inherits the composition value; if that is empty too, the generated token file is used.","field.auth.token.set":"Set","field.auth.token.unset":"Not set (using the generated token)","field.auth.token.replace":"Replace token","field.auth.token.clear":"Clear","field.auth.token.placeholder":"Paste a token to pin it","client.title":"Client configuration","client.description":"Paste this into your MCP client configuration. The copy carries the token in force; the panel only shows a mask \u2014 use \u201CShow token\u201D to check it. The token is a secret, so do not commit it.","client.copy":"Copy","client.copied":"Copied","client.copyFailed":"Copy failed; select it manually","client.reveal":"Show token","client.hide":"Hide token","client.tokenSource.settings":"pinned; replace it above","client.tokenSource.config":"pinned in the plugin configuration","client.tokenSource.file":"from the token file","client.tokenSource.generated":"generated by DSH","client.tokenSource.ephemeral":"ephemeral (could not write to disk)","client.tokenSourceLabel":"Token: ","client.tokenUnknown":"unknown (the host did not report one)","client.tokenUnknownHint":"The copied configuration still carries the placeholder. Read the token from:","client.toolsLabel":"Enabled tool groups: ","client.statusLabel":"Status: ","client.listening":"listening","client.notListening":"not listening","client.mounted":"mounted on the web server","client.errorLabel":"Bind failed: ","state.loading":"Reading configuration\u2026","state.unavailable":"The settings service is unavailable, so this panel cannot change the configuration.","state.readonly":"This page cannot write settings (it is not a loopback page).","state.writeFailed":"Write failed; the host state was re-read. Please retry."};var r=require("react");var O=[{id:"endpoint",title:"group.endpoint.title",description:"group.endpoint.description",fields:[{kind:"toggle",path:["http","enabled"],label:"field.http.enabled",hint:"field.http.enabled.hint"},{kind:"text",path:["http","host"],label:"field.http.host",hint:"field.http.host.hint"},{kind:"number",path:["http","port"],label:"field.http.port",hint:"field.http.port.hint",min:0,max:65535},{kind:"text",path:["http","path"],label:"field.http.path",hint:"field.http.path.hint"},{kind:"toggle",path:["http","mountOnWebServer"],label:"field.http.mountOnWebServer",hint:"field.http.mountOnWebServer.hint"}]},{id:"tools",title:"group.tools.title",description:"group.tools.description",fields:[{kind:"toggle",path:["tools","workspace"],label:"field.tools.workspace",hint:"field.tools.workspace.hint"},{kind:"toggle",path:["tools","session"],label:"field.tools.session",hint:"field.tools.session.hint"},{kind:"toggle",path:["tools","files"],label:"field.tools.files",hint:"field.tools.files.hint"},{kind:"toggle",path:["tools","shell"],label:"field.tools.shell",hint:"field.tools.shell.hint"},{kind:"toggle",path:["tools","agentTools"],label:"field.tools.agentTools",hint:"field.tools.agentTools.hint"}]},{id:"agentTools",title:"group.agentTools.title",description:"group.agentTools.description",fields:[{kind:"list",path:["agentTools","allow"],label:"field.agentTools.allow",hint:"field.agentTools.allow.hint",placeholder:"read, write, bash"},{kind:"list",path:["agentTools","deny"],label:"field.agentTools.deny",hint:"field.agentTools.deny.hint",placeholder:"bash, pwsh"}]},{id:"session",title:"group.session.title",description:"group.session.description",fields:[{kind:"text",path:["session","agentPreset"],label:"field.session.agentPreset",hint:"field.session.agentPreset.hint"},{kind:"text",path:["session","provider"],label:"field.session.provider",hint:"field.session.provider.hint"},{kind:"text",path:["session","model"],label:"field.session.model",hint:"field.session.model.hint"},{kind:"number",path:["session","promptTimeoutMs"],label:"field.session.promptTimeoutMs",hint:"field.session.promptTimeoutMs.hint",min:0}]},{id:"limits",title:"group.limits.title",description:"group.limits.description",fields:[{kind:"number",path:["limits","maxReadBytes"],label:"field.limits.maxReadBytes",hint:"field.limits.maxReadBytes.hint",min:1},{kind:"number",path:["limits","shellTimeoutMs"],label:"field.limits.shellTimeoutMs",hint:"field.limits.shellTimeoutMs.hint",min:0},{kind:"number",path:["limits","agentToolTimeoutMs"],label:"field.limits.agentToolTimeoutMs",hint:"field.limits.agentToolTimeoutMs.hint",min:0}]},{id:"approval",title:"group.approval.title",description:"group.approval.description",fields:[{kind:"select",path:["approval","policy"],label:"field.approval.policy",hint:"field.approval.policy.hint",options:[{value:"inherit",label:"field.approval.policy.inherit"},{value:"allow",label:"field.approval.policy.allow"}]}]}];function k(e,t){let o=e;for(let i of t){if(o===null||typeof o!="object")return;o=o[i]}return o}function C(e){return e.join(".")}function A(e){return Array.isArray(e)?e.map(t=>String(t)).join(", "):""}function z(e){return e.split(/[,\n]/).map(t=>t.trim()).filter(t=>t!=="")}var N="<token>";function M(e,t){return JSON.stringify({mcpServers:{dsh:{type:"http",url:e,headers:{Authorization:`Bearer ${t}`}}}},null,2)}function W(e){return`${e.length>8?e.slice(0,4):""}${"\u2022".repeat(8)}`}function I(e,t){if(t===void 0)return;let o=`client.tokenSource.${t}`,i=e(o);return i===o?t:i}var n=require("react/jsx-runtime");function j({value:e,disabled:t,placeholder:o,type:i,min:l,max:a,onCommit:s}){let[d,u]=(0,r.useState)(e),h=(0,r.useRef)(!1);return(0,r.useEffect)(()=>{h.current||u(e)},[e]),(0,n.jsx)("input",{className:"dshmcp_input",type:i,value:d,disabled:t,...o===void 0?{}:{placeholder:o},...l===void 0?{}:{min:l},...a===void 0?{}:{max:a},onFocus:()=>{h.current=!0},onChange:p=>{u(p.target.value)},onBlur:()=>{h.current=!1,d!==e&&s(d)},onKeyDown:p=>{p.key==="Enter"&&p.target.blur(),p.key==="Escape"&&h.current&&(h.current=!1,u(e),p.target.blur())}})}function ee({t:e,field:t,value:o,disabled:i,onWrite:l}){let a=t.kind==="text"||t.kind==="number"||t.kind==="list";return(0,n.jsxs)("label",{className:`dshmcp_row${a?" dshmcp_rowStack":""}`,"data-field":C(t.path),children:[(0,n.jsxs)("span",{className:"dshmcp_rowMain",children:[(0,n.jsx)("span",{className:"dshmcp_label",children:e(t.label)}),t.hint!==void 0&&(0,n.jsx)("span",{className:"dshmcp_hint",children:e(t.hint)})]}),(0,n.jsxs)("span",{className:"dshmcp_control",children:[t.kind==="toggle"&&(0,n.jsx)("input",{className:"dshmcp_check",type:"checkbox",checked:o===!0,disabled:i,onChange:s=>{l(s.target.checked)}}),t.kind==="list"&&(0,n.jsx)(j,{type:"text",value:A(o),disabled:i,...t.placeholder===void 0?{}:{placeholder:t.placeholder},onCommit:s=>{l(z(s))}}),(t.kind==="text"||t.kind==="number")&&(0,n.jsx)(j,{type:t.kind==="number"?"number":"text",value:o==null?"":String(o),disabled:i,...t.placeholder===void 0?{}:{placeholder:t.placeholder},...t.min===void 0?{}:{min:t.min},...t.max===void 0?{}:{max:t.max},onCommit:s=>{if(t.kind==="text"){l(s);return}let d=Number(s);s.trim()===""||!Number.isFinite(d)||t.min!==void 0&&d<t.min||t.max!==void 0&&d>t.max||l(d)}}),t.kind==="select"&&(0,n.jsx)("select",{className:"dshmcp_input",value:o==null?"":String(o),disabled:i,onChange:s=>{l(s.target.value)},children:(t.options??[]).map(s=>(0,n.jsx)("option",{value:s.value,children:e(s.label)},s.value))})]})]})}function te({t:e,group:t,value:o,disabled:i,onWrite:l}){return(0,n.jsxs)("section",{className:"dshmcp_group",children:[(0,n.jsx)("h3",{className:"dshmcp_groupTitle",children:e(t.title)}),(0,n.jsx)("p",{className:"dshmcp_groupDesc",children:e(t.description)}),(0,n.jsx)("div",{className:"dshmcp_rows",children:t.fields.map(a=>(0,n.jsx)(ee,{t:e,field:a,value:k(o,a.path),disabled:i,onWrite:s=>{l(a,s)}},C(a.path)))})]})}function ne({t:e,isSet:t,disabled:o,onWrite:i,onClear:l}){let[a,s]=(0,r.useState)("");return(0,n.jsxs)("label",{className:"dshmcp_row dshmcp_rowStack","data-field":"auth.token",children:[(0,n.jsxs)("span",{className:"dshmcp_rowMain",children:[(0,n.jsxs)("span",{className:"dshmcp_label",children:[e("field.auth.token")," ",(0,n.jsx)("span",{className:`dshmcp_badge${t?" dshmcp_badgeOk":""}`,children:e(t?"field.auth.token.set":"field.auth.token.unset")})]}),(0,n.jsx)("span",{className:"dshmcp_hint",children:e("field.auth.token.hint")})]}),(0,n.jsxs)("span",{className:"dshmcp_control",children:[(0,n.jsx)("input",{className:"dshmcp_input",type:"password",value:a,disabled:o,placeholder:e("field.auth.token.placeholder"),autoComplete:"off",onChange:d=>{s(d.target.value)},onBlur:()=>{a!==""&&(i(a),s(""))},onKeyDown:d=>{d.key==="Enter"&&d.target.blur()}}),t&&(0,n.jsx)("button",{className:"dshmcp_btn",type:"button",disabled:o,onClick:l,children:e("field.auth.token.clear")})]})]})}function ie({t:e,url:t,mounted:o,token:i,tokenSource:l,tokenFile:a,status:s,statusRead:d}){let[u,h]=(0,r.useState)("idle"),[p,m]=(0,r.useState)(!1),f=i!==void 0&&i!=="",g=M(t,f?i:N),w=M(t,f?p?i:W(i):N),S=I(e,l);return(0,n.jsxs)("section",{className:"dshmcp_group",children:[(0,n.jsx)("h3",{className:"dshmcp_groupTitle",children:e("client.title")}),(0,n.jsx)("p",{className:"dshmcp_groupDesc",children:e("client.description")}),(0,n.jsx)("pre",{className:"dshmcp_code",children:w}),(0,n.jsxs)("div",{className:"dshmcp_control",children:[(0,n.jsx)("button",{className:"dshmcp_btn",type:"button",onClick:()=>{navigator.clipboard.writeText(g).then(()=>{h("ok")}).catch(()=>{h("failed")})},children:e(u==="ok"?"client.copied":u==="failed"?"client.copyFailed":"client.copy")}),f&&(0,n.jsx)("button",{className:"dshmcp_btn",type:"button",onClick:()=>{m(D=>!D)},children:e(p?"client.hide":"client.reveal")}),d&&(0,n.jsx)("span",{className:`dshmcp_badge${s?.listening===!0?" dshmcp_badgeOk":""}`,children:s?.listening===!0?e("client.listening"):e("client.notListening")}),o&&(0,n.jsx)("span",{className:"dshmcp_badge",children:e("client.mounted")})]}),(0,n.jsxs)("p",{className:"dshmcp_note",children:[e("client.tokenSourceLabel"),S??e("client.tokenUnknown")]}),!f&&(0,n.jsxs)("p",{className:"dshmcp_note",children:[e("client.tokenUnknownHint")," ",(0,n.jsx)("code",{children:a})]}),s!==void 0&&s.enabledToolGroups.length>0&&(0,n.jsxs)("p",{className:"dshmcp_note",children:[e("client.toolsLabel"),s.enabledToolGroups.join(", ")]}),s?.error!=null&&(0,n.jsxs)("p",{className:"dshmcp_error",children:[e("client.errorLabel"),s.error]})]})}function B({t:e,store:t,tokenFile:o}){let i=(0,r.useSyncExternalStore)(t.subscribe,t.getSnapshot),[l,a]=(0,r.useState)(!1),[s,d]=(0,r.useState)(),[u,h]=(0,r.useState)(!1),p=(0,r.useRef)(!0),m=i.value,f=i.writable&&i.status==="ready"&&m!==void 0,g=(0,r.useCallback)(()=>t.readStatus().then(c=>{p.current&&(h(!0),d(c))}),[t]);(0,r.useEffect)(()=>{p.current=!0,g();let c=setInterval(()=>{g()},5e3);return()=>{p.current=!1,clearInterval(c)}},[g]);let w=(0,r.useCallback)((c,_)=>(a(!1),t.mutate([{op:"set",path:[...c],value:_}],i.revision).catch(()=>{a(!0)})),[t,i.revision]),S=(0,r.useCallback)(c=>(a(!1),t.mutate([{op:"unset",path:[...c]}],i.revision).catch(()=>{a(!0)})),[t,i.revision]),U=(s===void 0?void 0:s.tokenSource==="settings"||s.tokenSource==="config")??t.secretIsSet(),x=k(m,["http","host"]),G=k(m,["http","port"]),K=k(m,["http","path"]),H=typeof x=="string"&&x!==""?x:"127.0.0.1",$=`http://${H==="0.0.0.0"?"127.0.0.1":H}:${String(G??"")}${String(K??"")}`;return(0,n.jsxs)("div",{className:"dshmcp",children:[(0,n.jsx)("p",{className:"dshmcp_intro",children:e("intro")}),i.status==="loading"&&(0,n.jsx)("p",{className:"dshmcp_note",children:e("state.loading")}),i.status==="unavailable"&&(0,n.jsx)("p",{className:"dshmcp_error",children:e("state.unavailable")}),i.status==="ready"&&!i.writable&&(0,n.jsx)("p",{className:"dshmcp_note",children:e("state.readonly")}),l&&(0,n.jsx)("p",{className:"dshmcp_error",children:e("state.writeFailed")}),O.map(c=>(0,n.jsx)(te,{t:e,group:c,value:m,disabled:!f,onWrite:(_,q)=>{w(_.path,q)}},c.id)),(0,n.jsxs)("section",{className:"dshmcp_group",children:[(0,n.jsx)("h3",{className:"dshmcp_groupTitle",children:e("group.auth.title")}),(0,n.jsx)("p",{className:"dshmcp_groupDesc",children:e("group.auth.description")}),(0,n.jsx)("div",{className:"dshmcp_rows",children:(0,n.jsx)(ne,{t:e,isSet:U,disabled:!f,onWrite:c=>{w(["auth","token"],c).then(()=>g())},onClear:()=>{S(["auth","token"]).then(()=>g())}})})]}),(0,n.jsx)(ie,{t:e,url:$,mounted:k(m,["http","mountOnWebServer"])===!0,token:s?.token,tokenSource:s?.tokenSource,tokenFile:s?.tokenFile??o,status:s,statusRead:u})]})}var E="dsh-as-mcp",oe=`
5
5
  .dshmcp{display:flex;flex-direction:column;gap:20px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:18px}
6
6
  .dshmcp_intro{margin:0;color:var(--dsw-alias-label-secondary)}
7
7
  .dshmcp_group{display:flex;flex-direction:column;gap:10px}
@@ -29,6 +29,6 @@ button.dshmcp_btn[disabled]{opacity:.5;cursor:default}
29
29
  .dshmcp_code{box-sizing:border-box;width:100%;margin:0;padding:10px 12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:17px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-l2,var(--dsw-alias-interactive-bg-hover));border:1px solid var(--dsw-alias-border-l1);border-radius:8px;white-space:pre;overflow-x:auto;resize:vertical}
30
30
  .dshmcp_error{margin:0;padding:8px 10px;font-size:12px;color:var(--dsw-alias-label-error,var(--dsw-alias-label-primary));background:var(--dsw-alias-bg-error,var(--dsw-alias-interactive-bg-hover));border-radius:8px}
31
31
  .dshmcp_note{margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:17px}
32
- `;function V(){if(typeof document>"u"||document.querySelector('style[data-plugin-css="'+x+'"]')!==null)return;let e=document.createElement("style");e.dataset.plugin=x,e.dataset.pluginCss=x,e.textContent=Q,document.head.appendChild(e)}V();var X=["slots","locale"],Y="~/.dsh/dsh-as-mcp/token";function ee(e){let t=e.get("settingsScope")?.bind({namespace:m});if(t===void 0)return;let n=e.get("settingsScope").describe();return{subscribe:o=>t.subscribe(o),getSnapshot:()=>t.getSnapshot(),mutate:(o,s)=>t.mutate(o,s),secretIsSet:()=>n.getSnapshot().view?.namespaces.find(a=>a.ns===m)?.secrets.some(a=>a.path.join(".")==="auth.token"&&a.set)??!1,readStatus:async()=>{try{let o=await fetch(N,{headers:{accept:"application/json"}});return o.ok?await o.json():void 0}catch{return}}}}function te(e){try{e.effect(()=>{let n=e.locale.register(m,"zh",M),o=e.locale.register(m,"en",P);return()=>{n(),o()}},"dsh-as-mcp: dictionaries")}catch(n){console.warn("[dsh-as-mcp] locale.register failed; falling back to built-in strings:",n)}let t;e.slots.inject("settings.section",()=>{if(t??=ee(e),t!==void 0)return e.slots.register({name:"settings.section",id:"mcp",order:40,label:()=>e.locale.bind(m)("nav"),locale:m,inject:()=>({store:t,tokenFile:Y})},F)})}
32
+ `;function se(){if(typeof document>"u"||document.querySelector('style[data-plugin-css="'+E+'"]')!==null)return;let e=document.createElement("style");e.dataset.plugin=E,e.dataset.pluginCss=E,e.textContent=oe,document.head.appendChild(e)}se();var le=["slots","locale","configForms"],P="dsh-as-mcp",ae="~/.dsh/dsh-as-mcp/token";function re(e){let t=e.configForms.get(P),o=e.configForms.describe();return{subscribe:i=>t.subscribe(i),getSnapshot:()=>t.getSnapshot(),mutate:async(i,l)=>{if(!await t.mutate(i,l))throw new Error("dsh-as-mcp: the host refused the settings write")},secretIsSet:()=>o.getSnapshot().view?.namespaces.find(a=>a.ns===P)?.secrets.some(a=>a.path.join(".")==="auth.token"&&a.set)??!1,readStatus:async()=>{try{let i=await fetch(F,{headers:{accept:"application/json"}});return i.ok?await i.json():void 0}catch{return}}}}function de(e){try{e.effect(()=>{let o=e.locale.register(v,"zh",L),i=e.locale.register(v,"en",R);return()=>{o(),i()}},"dsh-as-mcp: dictionaries")}catch(o){console.warn("[dsh-as-mcp] locale.register failed; falling back to built-in strings:",o)}let t=re(e);e.effect(()=>e.configForms.whileServed([P],()=>e.slots.inject("settings.section",()=>e.slots.register({name:"settings.section",id:"mcp",order:40,label:()=>e.locale.bind(v)("nav"),locale:v,inject:()=>({store:t,tokenFile:ae})},B))),"dsh-as-mcp: settings section")}
33
33
  return module.exports; } });
34
34
  //# sourceMappingURL=client.js.map