dsh-memory-eternal 0.5.6 → 0.5.7

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
@@ -343,8 +343,81 @@ npm i -g github:EternalNight996/dsh-memory-eternal
343
343
  | activeVault | '' | 当前激活的 Vault(对应 vaultProfiles 中的 name) |
344
344
  | sessionBudgetChars | 80000 | 会话级 token 预算(字符数),供 harness 触发压缩 |
345
345
  | recallEmbedding | '' | 语义召回 provider(空=零依赖 bigram + LLM 判定兜底) |
346
- | autoMcpSetup | | 激活时自动把 MCP 挂到本机已装的 Claude Code/Codex/Cursor(幂等+备份) |
347
- | autoWeb | 开 | 激活时确保 Web server 常驻(UI 唯一真源,DSH 渲染走 iframe) |
346
+ | autoMcpSetup | **关** | 激活时自动把 MCP 挂到本机已装的 Claude Code/Codex/Cursor(幂等+备份)。**默认关闭**——不碰外部配置,按需开启 |
347
+ | autoWeb | 开 | 激活时拉起 web server(默认 init 模式拉一次)。配 autoWebMode 调保活强度 |
348
+ | autoWebMode | `init` | web server 保活模式:`init`(启动时拉一次)/ `interval`(DSH 进程内周期保活)/ `manual`(不自动拉起,仅 `dsh-memory open` ensure-alive) |
349
+ | webPort | `7999` | web server 端口 |
350
+ | webCheckIntervalMs | `5000` | interval 模式的探活间隔(最小 1000) |
351
+ | webMaxRestart | `10` | interval 模式连续失败超过此次数后停止保活(让人工排查) |
352
+ | watchdogAutoSpawn | **关** | 是否 spawn 一个与 DSH 解耦的独立 watchdog 进程(额外 ~47 MB 常驻)。**默认关闭**——DSH 进程内 setInterval 已够用 |
353
+
354
+ ---
355
+
356
+ ## 🌐 服务自管理 · Self-hosting
357
+
358
+ **v0.5.7 引入配置化部署强度**——从「自动启用一切」改为「默认保守、用户显式升级强度」。
359
+
360
+ ### 三种 web server 保活模式(autoWebMode)
361
+
362
+ | 模式 | 行为 | 适合 | 代价 |
363
+ |---|---|---|---|
364
+ | `init`(默认)| DSH 激活时拉一次;之后不管 | 常规用法(DSH 常开) | 47 MB web + 0 监控 |
365
+ | `interval` | DSH 进程内 `setInterval` 周期探活 + 自动拉起(web 死掉复活) | DSH 常开但 web 偶尔被外部 kill | 47 MB web + ~0 监控(DSH 进程内) |
366
+ | `manual` | 完全不自动拉起;只在 `dsh-memory open` 时 ensure-alive | 服务器/CI 想自己控制启停 | 47 MB web(手动起后) |
367
+
368
+ ### 看门狗进程(watchdogAutoSpawn)
369
+
370
+ DSH 死了也能保活 web 时使用:
371
+
372
+ ```bash
373
+ # 方式 1:UI 设置 → 服务自管理 → 开启 watchdogAutoSpawn
374
+ # DSH 重启后会自动 spawn 一个独立 node watchdog 进程
375
+
376
+ # 方式 2:手动跑(在另一个终端)
377
+ dsh-memory watchdog --port 7799 --interval 5000 --max-restart 10
378
+ ```
379
+
380
+ **资源**:47 MB(独立 node 进程)/ 0 MB(DSH 进程内 setInterval)。**默认不 spawn**,需要 7×24 保活才开。
381
+
382
+ ### MCP 自动挂载(autoMcpSetup)
383
+
384
+ **v0.5.7 起默认关闭**。需要时:
385
+ - 设置 → 记忆 → `autoMcpSetup = true` → 重启 DSH 自动写入各 agent 配置
386
+ - 或手动:`dsh-memory setup [--claude-only|--codex-only|--cursor-only] [--dry-run]`
387
+
388
+ ### MCP 配置状态查询
389
+
390
+ Web UI 顶部「外部 Agent MCP 挂载状态」面板(`GET /memory-eternal/api/setup-status` 只读):
391
+
392
+ - **claude-code**:检测 `~/.claude.json` 的 `mcpServers.memory` + `~/.claude/settings.json` 的 SessionEnd hook
393
+ - **codex**:检测 `~/.codex/config.toml` 的 `[mcp_servers.memory]` 段
394
+ - **cursor**:检测 `~/.cursor/mcp.json` 的 `mcpServers.memory`
395
+
396
+ 每项返回:`installed` / `mcpConfigured` / `mcpMatchesCurrentNode`(检测 node 路径是否与当前一致)/ `hook`(仅 claude-code)。**node 路径不一致** = ⚠ 警告(之前在 dsh-desktop 环境 setup 过、现在换 node),提示重跑 `dsh-memory setup` 修复。
397
+
398
+ ### 服务自管理 vs 7×24 部署
399
+
400
+ | 部署强度 | 配置 | 进程 | 开机自启 |
401
+ |---|---|---|---|
402
+ | 个人开发(默认)| `autoMcpSetup=false` + `autoWeb=true` + `autoWebMode=init` + `watchdogAutoSpawn=false` | web 47 MB | 否 |
403
+ | 常规 DSH 用户 | 加上 `autoWebMode=interval` | web 47 MB | 否 |
404
+ | 7×24 服务化 | + `watchdogAutoSpawn=true` | web 47 MB + watchdog 47 MB | DSH 启动时 spawn(**不是**开机自启——DSH 退出则失效) |
405
+ | 真正开机自启(无 DSH)| 跳过 DSH,走**系统级** watchdog:Windows Task Scheduler 计划任务跑 `dsh-memory watchdog --port 7799 --interval 5000 --max-restart 10` | web 47 MB + watchdog 47 MB | **是**(与 DSH 解耦)|
406
+
407
+ **关键事实**:**MCP server 不是 daemon**——它是 stdio 协议,agent 启动会话时 spawn、用完即退。**不存在「MCP 开机自启」**的概念。Claude Code / Codex CLI / Cursor 每次开会话就 spawn 一个 MCP 进程,session 结束就退出。
408
+
409
+ ### 进程依赖关系
410
+
411
+ ```
412
+ DSH 宿主 (Cordis 框架)
413
+ ├─ host plugin: index.js ← 自动沉淀 / memory_recall / JSON API / web-info
414
+ ├─ (可选) autoWeb 拉起的 detached node web.js ← detached, DSH 退出后仍活
415
+ └─ (可选) watchdogAutoSpawn 拉起的 detached node watchdog.js ← 同上
416
+ web server (lib/web.js)
417
+ └─ (被 agent 按需 spawn) stdio MCP server 进程 ← 短生命周期
418
+ ```
419
+
420
+ **所有「常驻」node 进程都依赖 Node 运行时**。**不依赖 Node** 的方案只有**系统级 watchdog**(Windows Task Scheduler 用 PowerShell 脚本)—— 但 web server 本身仍需 node。**Node 是硬依赖**。
348
421
 
349
422
  ---
350
423
 
@@ -403,8 +476,66 @@ dsh-memory-eternal/
403
476
 
404
477
  ---
405
478
 
479
+ ## 🆕 v0.5.x 改善项汇总 · Improvements in v0.5.x
480
+
481
+ > v0.5 是**多宿主化主版本**,自 v0.5.0 起本插件不再只属于 DSH——一个记忆库,所有 Agent 共享。下方按主题归纳 v0.5.0 → v0.5.6 的关键改进(中英对照)。
482
+ >
483
+ > **v0.5 is the multi-host milestone.** From v0.5.0 on, this plugin is no longer DSH-only — one memory vault shared by every Agent. The summary below groups v0.5.0 → v0.5.6 improvements by theme (Chinese / English side by side).
484
+
485
+ ### 🧠 多宿主架构 · Multi-host architecture
486
+
487
+ | 中文 | English |
488
+ |---|---|
489
+ | **MCP server** 零依赖 stdio(`memory_recall` / `memory_capture` / `memory_stats` 三工具) | Zero-dep **MCP server** on stdio: `memory_recall` / `memory_capture` / `memory_stats` |
490
+ | **CLI 入口 `dsh-memory`** 7 子命令(recall / capture / serve / open / mcp / setup / sweep) | New **CLI `dsh-memory`** with 7 subcommands |
491
+ | **Web 端常驻** 独立进程,DSH 渲染走 iframe = 单一 UI 真源 | **Web UI** runs as detached process; DSH renders via iframe — single source of truth |
492
+ | **自动挂载** 插件激活即检测 Claude Code / Codex / Cursor,幂等 + 备份写入 MCP 配置 | **Auto-mount** to installed agents (Claude Code / Codex / Cursor), idempotent + auto backup |
493
+ | **Claude Code SessionEnd hook** 会话结束 / 压缩前自动沉淀(Windows 友好纯 node 脚本) | **Claude Code SessionEnd hook** auto-captures before session end / pre-compact |
494
+ | **卡格式 `formatVersion` 守卫** 多副本共存 / 版本漂移时只向后兼容读,不会写坏库 | **Card `formatVersion` guard** — backward-compatible reads survive cross-version drift |
495
+
496
+ ### ⚡ 健壮性 · Robustness
497
+
498
+ | 中文 | English |
499
+ |---|---|
500
+ | **看门狗 `dsh-memory watchdog`** 独立进程保活 web server(不依赖 DSH 宿主),端口探活 + 失败自动拉起 + 重启计数 + SIGINT/SIGTERM 优雅退出。稳态内存 ~47 MB / CPU 接近 0 | **`dsh-memory watchdog`** standalone process keeps web alive — port probe + auto-restart + counter + graceful shutdown. Steady-state ~47 MB RAM / ~0% CPU |
501
+ | **`autoMcpSetup` 默认改 false + `autoWebMode` 三档(init/interval/manual)+ `watchdogAutoSpawn` 默认 false** ——v0.5.7 起部署强度配置化,默认最保守,零外部副作用;显式开启才动外部配置 / spawn watchdog | **`autoMcpSetup` defaults to false + `autoWebMode` (init/interval/manual) + `watchdogAutoSpawn` defaults to false** — v0.5.7 makes deployment intensity configurable, conservative defaults, no external side effects unless explicitly enabled |
502
+ | **`GET /memory-eternal/api/setup-status`** 只读查询各 agent MCP 配置 + hook + node 路径一致性;Web UI 顶部面板一图看清三个 agent 状态 | **`GET /memory-eternal/api/setup-status`** — read-only check of each agent's MCP config + hook + node path consistency; Web UI panel shows all three agents at a glance |
503
+ | **OpenAI 兼容 LLM 适配器** 自动蒸馏用外部端点可配(DeepSeek / Ollama / vLLM / LM Studio),无配置时降级为原文卡 | **OpenAI-compatible LLM adapter** for distillation — works with DeepSeek / Ollama / vLLM / LM Studio; graceful fallback to raw cards when unconfigured |
504
+ | **降级路径捕获** 独立进程(无 DSH 环境)import `@deepseek-ai/dsh-llm` 失败时本地 fallback shim | **DSH-free fallback shim** — independent processes no longer require `@deepseek-ai/dsh-llm` |
505
+ | **`api.js` 抽层** DSH 与独立 web server 共用同一份 API 实现 | **`api.js` extracted** — DSH and standalone web server share the exact same API layer |
506
+
507
+ ### 🛠 整理与工具 · Optimization & tooling
508
+
509
+ | 中文 | English |
510
+ |---|---|
511
+ | **「⚡ 一键优化」按钮** 整理建议面板顶部新增,可选 checkbox「同时清理陈旧卡」,调 `POST /memory-eternal/api/optimize-execute` | **"⚡ One-click optimize" button** on the Organize panel — optional "Also clean stale" checkbox, calls new `POST /memory-eternal/api/optimize-execute` |
512
+ | **记忆窗口控制条** 侧边栏「记忆」浮窗右上角新增全屏切换 + 关闭 × 按钮(半透明背景 + blur) | **Window controls** in DSH sidebar memory popup — fullscreen toggle + close × in top-right (translucent + blur) |
513
+ | **CLI stdin 流式读修复** Windows cmd 重定向下 `fs.readFileSync(0)` 偶发空字符串,已改为 data/end 流式收集 + readableEnded 兜底 | **CLI stdin stream fix** — replaces unreliable `fs.readFileSync(0)` on Windows with data/end + readableEnded fallback |
514
+
515
+ ### 🩺 质量 · Quality
516
+
517
+ - **40/40 单元测试全绿**(vault 19 + capture 13 + api 8)/ **All 40 unit tests green**(vault 19 + capture 13 + api 8)
518
+ - **`npm publish` 一键化**:commit → tag → npm → 双端 push → gh release 全自动 / **One-button publish**: commit → tag → npm → push to GitHub + Gitee → gh release
519
+ - **DSH Market 收录徽章** README 顶部,按官方 issue 反馈挂上 / **DSH Market listing badge** on README top, per official issue guidance
520
+
521
+ ### 🐛 v0.5.x bugfixes
522
+
523
+ | 版本 | 修复 | Version | Fix |
524
+ |---|---|---|---|
525
+ | v0.5.1 | `positional()` 修正 —— 任意 `--flag` 都跳过下一项 | v0.5.1 | `positional()` fix — any `--flag` skips next token |
526
+ | v0.5.2 | capture stdin `fs.readFileSync(0)` → 流式读 | v0.5.2 | stdin `fs.readFileSync(0)` → stream reader |
527
+ | v0.5.3 | capture stdin 流式读 Windows 重定向下偶发空 → `readableEnded` + setTimeout 兜底 | v0.5.3 | stdin stream Windows redirect edge case → `readableEnded` + setTimeout fallback |
528
+
529
+ ---
530
+
406
531
  ## 📦 发布记录
407
532
 
533
+ - **v0.5.7**:**服务自管理配置化**——`autoMcpSetup` 默认改 false(不碰外部配置);新增 `autoWebMode`(init/interval/manual)+ `webPort`/`webCheckIntervalMs`/`webMaxRestart`/`watchdogAutoSpawn` 字段;index.js 按模式分层启停(init 拉一次 / interval DSH 进程内 setInterval / manual 仅 ensure);新增 `GET /memory-eternal/api/setup-status` 只读路由;Web UI 顶部加「外部 Agent MCP 挂载状态」面板(claude-code/Codex/Cursor 配置 + hook + node 路径一致性)。
534
+ - **v0.5.5**:`dsh-memory watchdog` 子命令 + `lib/watchdog.js`(独立保活 web server,端到端验证:杀 web 子进程 4s 后 watchdog 自动复活)
535
+ - **v0.5.4**:README 顶部新增 DSH Market 收录徽章(按 [Issue #76](https://github.com/2BingLing/dsh-market/issues/76) 官方建议)
536
+ - **v0.5.3**:capture stdin 改回流式 data/end + `readableEnded` 兜底(Node 22/24 Windows cmd 重定向下 `fs.readFileSync(0)` 偶发空字符串)
537
+ - **v0.5.2**:capture stdin `fs.readFileSync(0)` 同步读修复
538
+ - **v0.5.1**:`positional()` 修正——所有 `--flag` 都跳过下一项,避免 stdin 路径下 `--source` 的 value 被误当作位置参数
408
539
  - **v0.5.0**:**多宿主化**——MCP server 零依赖 stdio(3 工具:recall/capture/stats),CLI 入口 `dsh-memory`(recall/capture/serve/open/mcp/setup/sweep),Web 端常驻(DSH 渲染走 iframe = 单一 UI 真源),自动挂载到 Claude Code/Codex/Cursor(幂等+备份),Claude Code SessionEnd hook 自动沉淀,卡格式 `formatVersion` 守卫,DSH 用户 / Claude Code 用户均「一条命令安装即用」。`api.js` 抽层 + `capture-run.js` 独立沉淀管线复用。
409
540
  - **v0.4.28**:侧边栏底部「记忆」按钮**独占一行**——不再与「主题」等 footer 按钮挤在同一行(`flex-wrap` 同时命中直接包含与中间隔 wrapper 两种情况)。
410
541
  - **v0.4.27**:新建卡片 kind 下拉可读背景色;图谱合并/删除节点后**即时联动整理建议**面板刷新。
package/index.js CHANGED
@@ -17,6 +17,10 @@
17
17
  import { promises as fs } from 'node:fs'
18
18
  import path from 'node:path'
19
19
  import os from 'node:os'
20
+ import { spawn } from 'node:child_process'
21
+ import { fileURLToPath } from 'node:url'
22
+ const __filename = fileURLToPath(import.meta.url)
23
+ const PACKAGE_ROOT = path.resolve(path.dirname(__filename))
20
24
  import z from '@deepseek-ai/schemastery'
21
25
  import { defineTool } from '@deepseek-ai/dsh-tools'
22
26
  import { ensureVault, search, generateDailyBrief } from './lib/vault.js'
@@ -47,9 +51,20 @@ export const Config = z.object({
47
51
  // 会话级 token 预算(字符),供 harness 触发压缩/轮换;记忆侧提供估算与阈值
48
52
  sessionBudgetChars: z.number().default(80000),
49
53
  // 多宿主:激活时自动把 MCP 挂载到本机已装的 Claude Code/Codex/Cursor(幂等,
50
- // MEMORY_ETERNAL_SKIP_AUTO=1 可完全禁用);web server 默认常驻(UI 唯一真源)。
51
- autoMcpSetup: z.boolean().default(true),
54
+ // MEMORY_ETERNAL_SKIP_AUTO=1 可完全禁用)。**默认 false**——不碰外部配置,需要时显式开启。
55
+ autoMcpSetup: z.boolean().default(false),
52
56
  autoWeb: z.boolean().default(true),
57
+ // web server 保活模式:
58
+ // init = DSH 激活时拉起一次(默认;最低开销,DSH 死后 web 仍活但无人看守)
59
+ // interval= DSH 进程内 setInterval 周期探活+自动拉起(额外 0 内存;DSH 死则停保活)
60
+ // manual = 完全不自动拉起;只在 `dsh-memory open` 时 ensure-alive(最保守)
61
+ autoWebMode: z.enum(['init', 'interval', 'manual']).default('init'),
62
+ webPort: z.number().min(1).max(65535).default(7999),
63
+ webCheckIntervalMs: z.number().min(1000).max(600000).default(5000),
64
+ webMaxRestart: z.number().min(1).max(1000).default(10),
65
+ // 是否 spawn 独立 watchdog 进程(与 DSH 解耦,7×24 保活;额外 ~47 MB 常驻)
66
+ // 默认 false——DSH 进程内 setInterval 已足够常规用法
67
+ watchdogAutoSpawn: z.boolean().default(false),
53
68
  })
54
69
 
55
70
  const API_PREFIX = '/memory-eternal/api'
@@ -279,22 +294,88 @@ export function apply(ctx, config) {
279
294
  })
280
295
  }
281
296
 
282
- // -- 4. 多宿主常驻:自动挂载 MCP + web server 保活 -------------------------
297
+ // -- 4. 多宿主常驻:MCP 挂载 + web server 保活(按设置项分层) -----------------
283
298
  // 全部后台异步、静默失败:插件激活不能被外部环境问题卡住。
299
+ let intervalTimer = null
300
+ let watchdogProc = null
284
301
  ctx.effect(() => {
285
302
  const cfg0 = settings.get() ?? {}
286
- if (cfg0.enabled !== false && cfg0.autoMcpSetup !== false && process.env.MEMORY_ETERNAL_SKIP_AUTO !== '1') {
303
+ if (cfg0.enabled === false) return () => {}
304
+
305
+ // (1) MCP 自动挂载:默认关闭;只有用户显式开启才动外部配置。
306
+ if (cfg0.autoMcpSetup === true && process.env.MEMORY_ETERNAL_SKIP_AUTO !== '1') {
287
307
  import('./lib/setup.js')
288
308
  .then((m) => m.runSetup({ log: () => {} }))
289
309
  .catch(() => {})
290
310
  }
291
- if (cfg0.enabled !== false && cfg0.autoWeb !== false) {
292
- import('./lib/web.js')
293
- .then((m) => m.ensureWebServer({ vaultRoot: vaultDir() }))
294
- .then(refreshWebInfo)
295
- .catch((error) => console.error('[memory-eternal] web server failed:', error?.message || error))
311
+
312
+ // (2) web server:根据 autoWeb + autoWebMode 决策
313
+ const mode = cfg0.autoWebMode || 'init'
314
+ const port = Number(cfg0.webPort) || 7999
315
+ const ensureOpts = { port, vaultRoot: vaultDir() }
316
+ const ensureWeb = () => import('./lib/web.js')
317
+ .then((m) => m.ensureWebServer(ensureOpts))
318
+ .then((info) => { refreshWebInfo(info); return info })
319
+ .catch((error) => console.error('[memory-eternal] web server failed:', error?.message || error))
320
+
321
+ if (cfg0.autoWeb === true) {
322
+ if (mode === 'manual') {
323
+ // manual:不自动拉起;只在 dsh-memory open / WebFrame 触发 ensure
324
+ import('./lib/web.js')
325
+ .then((m) => m.probeWebServer(port))
326
+ .then((alive) => { if (alive) refreshWebInfo({ url: `http://127.0.0.1:${port}`, port, spawned: false }) })
327
+ .catch(() => {})
328
+ } else if (mode === 'init') {
329
+ // init:拉起一次(首次);之后不管(用户已设了,那看门狗都不开)
330
+ ensureWeb()
331
+ } else if (mode === 'interval') {
332
+ // interval:DSH 进程内 setInterval 周期保活
333
+ const intervalMs = Number(cfg0.webCheckIntervalMs) || 5000
334
+ const maxRestart = Number(cfg0.webMaxRestart) || 10
335
+ let restartCount = 0
336
+ const tick = async () => {
337
+ if (restartCount >= maxRestart) {
338
+ console.error(`[memory-eternal] web 已连续重启 ${maxRestart} 次,停止保活`)
339
+ if (intervalTimer) { clearInterval(intervalTimer); intervalTimer = null }
340
+ return
341
+ }
342
+ const alive = await import('./lib/web.js').then((m) => m.probeWebServer(port)).catch(() => null)
343
+ if (!alive) {
344
+ restartCount++
345
+ console.error(`[memory-eternal] web 离线 → 第 ${restartCount}/${maxRestart} 次拉起`)
346
+ await ensureWeb()
347
+ } else {
348
+ // 探到活则重置计数
349
+ restartCount = 0
350
+ }
351
+ }
352
+ // 立即跑一次(首启 + 间隔循环)
353
+ ensureWeb()
354
+ intervalTimer = setInterval(tick, intervalMs)
355
+ }
356
+ }
357
+
358
+ // (3) 看门狗独立进程:默认不 spawn;开启时启动一个与 DSH 解耦的 node watchdog。
359
+ if (cfg0.watchdogAutoSpawn === true && cfg0.autoWeb !== false) {
360
+ import('./lib/watchdog.js')
361
+ .then((m) => {
362
+ const port = Number(cfg0.webPort) || 7999
363
+ const wd = spawn(
364
+ process.execPath,
365
+ [path.join(PACKAGE_ROOT, 'lib', 'watchdog.js'), '--port', String(port), '--interval', String(cfg0.webCheckIntervalMs || 5000), '--max-restart', String(cfg0.webMaxRestart || 10)],
366
+ { detached: true, stdio: 'ignore', env: { ...process.env, MEMORY_VAULT_DIR: vaultDir() }, windowsHide: true },
367
+ )
368
+ wd.unref()
369
+ watchdogProc = wd
370
+ console.error(`[memory-eternal] watchdog spawned pid=${wd.pid} port=${port}`)
371
+ })
372
+ .catch(() => {})
373
+ }
374
+
375
+ return () => {
376
+ if (intervalTimer) { clearInterval(intervalTimer); intervalTimer = null }
377
+ // 注意:watchdog 进程是独立的,故意不杀(7×24 用法)—— 配置改变由下次重启 DSH 时重新 spawn 替换
296
378
  }
297
- return () => {}
298
379
  }, 'memory-eternal: multi-host ensure')
299
380
 
300
381
  // 首次激活时确保 vault 目录存在。
package/lib/api.js CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  import { listCards, readCard, search, searchAll, graph, graphAll, overview, exportCards, deleteCard, writeCard, parseCard, stats, optimizeCandidates, optimizeApply, addFeedback, dailyBrief, dailyCounts, mergeCards, ensureVault } from './vault.js'
14
14
  import { compressExcerpt } from './capture.js'
15
+ import { getSetupStatus } from './setup.js'
15
16
 
16
17
  export const API_PREFIX = '/memory-eternal/api'
17
18
 
@@ -150,6 +151,12 @@ export function createApi(deps = {}) {
150
151
  json(res, 200, result)
151
152
  return
152
153
  }
154
+ case '/setup-status': {
155
+ // 只读查询各 agent MCP 配置状态,不写任何文件
156
+ const status = await getSetupStatus()
157
+ json(res, 200, status)
158
+ return
159
+ }
153
160
  case '/feedback': {
154
161
  let raw = ''
155
162
  for await (const chunk of req) raw += chunk