@dsh-sup/dsh-core-linux-x64 0.1.6-BETA.1 → 0.1.6-BETA.2

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.
Files changed (2) hide show
  1. package/core.cjs +333 -550
  2. package/package.json +1 -1
package/core.cjs CHANGED
@@ -15,10 +15,10 @@ var require_exec = __commonJS({
15
15
  function options(opts) {
16
16
  const o = opts || {};
17
17
  return {
18
- // timeout 是历史别名:service.js 曾传 { timeout } 而被静默忽略,所有超时回落默认值(N1)。
18
+ // timeout 是历史别名(兼容旧调用点拼写,若不与 timeoutMs 归一会被静默忽略):
19
19
  // 两种拼写都收,timeoutMs 优先;新调用一律用 timeoutMs。
20
20
  timeout: o.timeoutMs || o.timeout || DEFAULT_TIMEOUT_MS,
21
- // 必须 SIGKILL:SIGTERM 对挂起或被停住的进程可能无效,否则有超时等于没超时。
21
+ // 必须 SIGKILL:SIGTERM 对挂起或被停住的进程可能无效。
22
22
  killSignal: o.killSignal || "SIGKILL",
23
23
  maxBuffer: o.maxBuffer || DEFAULT_MAX_BUFFER,
24
24
  stdio: o.stdio || ["ignore", "pipe", "pipe"],
@@ -195,9 +195,8 @@ var require_config = __commonJS({
195
195
  }
196
196
  var BASE_DEFAULTS = {
197
197
  probeIntervalMs: 5e3,
198
- // 健康探测(三层):L0 进程存活 + L1 端口监听 + L2 HTTP GET healthUrl。probeTimeoutMs = 单次
199
- // HTTP 探测超时;failThreshold = 连续失败次数判故障(防抖动);httpProbeEnabled=false 时
200
- // 退化为端口在线即健康。
198
+ // 健康探测三层:L0 进程存活 + L1 端口监听 + L2 HTTP GET healthUrl。probeTimeoutMs = 单次探测超时;
199
+ // failThreshold = 连续失败判故障(防抖动);httpProbeEnabled=false 退化为端口在线即健康。
201
200
  probeTimeoutMs: 3e3,
202
201
  failThreshold: 2,
203
202
  httpProbeEnabled: true,
@@ -208,18 +207,14 @@ var require_config = __commonJS({
208
207
  crashBurst: 5,
209
208
  backoff: [3e4, 6e4, 12e4, 3e5, 6e5],
210
209
  apiHost: "127.0.0.1",
211
- // API 端口:高位不常用段起始(3100 常用端口易冲突)。守卫启动被占则自动顺延并持久化。
210
+ // API 端口:高位不常用段起始(常用端口段易冲突);守卫启动被占则自动顺延并持久化。
212
211
  apiPort: 36360,
213
- // 注意:daemon 控制通道端口(43107/43108)属业务域知识,已反转至 app/settings/domain-config.js,
214
- // 经 normalize/buildDefaults 的第二参注入;原键名与值逐字保留,消费方零改动。
215
- // 动态端口池(范围是配置项,非编译期常量)。默认避开 OS 动态端口范围
216
- // (Linux ip_local_port_range=32768-60999),落在 IANA User 段低位供监听池使用。
217
- // managed = relay/proxyInstance/oauthCallback 共享池;providerApi = 智能路由供应商独立端点池。
218
- // null = 内置默认池。
212
+ // 注意:daemon 控制通道端口属业务域知识,经注入声明提供(同上),原键名与值逐字保留。
213
+ // 动态端口池(范围是配置项,非编译期常量):null = 内置默认池,默认避开 OS 动态端口范围
214
+ // (Linux ip_local_port_range=32768-60999),落在 IANA User 段低位。额外池由域装配期申报(DS-G4)。
219
215
  portPools: null,
220
216
  stateFile: path2.join(SUP, "state.json"),
221
- // 日志目录布局:log/ 与 events/ 分目录;守卫事件在 events/guard.events.log、分级日志在 log/guard.log。
222
- // 显式配置(既有 config.json / 测试)仍尊重用户给定路径,不强行改写。
217
+ // 日志目录布局:事件在 events/guard.events.log,分级日志在 log/;显式配置的路径尊重用户给定值,不强改。
223
218
  logFile: path2.join(SUP, "events", "guard.events.log"),
224
219
  eventsMaxBytes: 5 * 1024 * 1024,
225
220
  supervisorLogFile: path2.join(SUP, "log", "guard.log"),
@@ -228,22 +223,17 @@ var require_config = __commonJS({
228
223
  logLevel: "info",
229
224
  logMaxBytes: 5 * 1024 * 1024,
230
225
  notifyEnabled: true,
231
- // 注意:routerAutostart(智能路由启动开关)同属业务域知识,经注入声明提供。
232
- // 内核更新单写入者 = 桌面壳:corePackageName 为内核自身 npm 子包名,守卫只读它查询版本状态,
233
- // 安装/升级由桌面壳执行(见 RELEASE-AND-UPDATE-MECHANISM.md)。
226
+ // 内核更新单写入者 = 桌面壳:corePackageName 仅为内核自身 npm 子包名,守卫只读它查版本状态,
227
+ // 安装/升级由壳执行。不得再引入 manifest 更新通道(残留键已删,config.json 中未知键加载时忽略)。
234
228
  corePackageName: null,
235
- // 旧 manifest 模式的残留键 selfUpdateManifestUrl / selfUpdateDir 已删除(全仓无赋值点)。
236
- // 既有用户 config.json 若仍含这两键,加载时忽略即可(未知键不报错);新代码不得再引入 manifest 更新通道。
237
229
  pluginsProfileName: "web",
238
230
  packageName: "@deepseek-ai/dsh",
239
- // 灰度名单(RELEASE-CHANNEL-CONTRACT):本机配置 canary:true 即视为灰度机,仅对我们的内核包生效,
240
- // 对第三方包(packageName)无效;名单否定优先:未置真即非灰度。
231
+ // 灰度名单(RELEASE-CHANNEL-CONTRACT):本机 canary:true 即灰度机,仅对内核包生效,对第三方包
232
+ // (packageName)无效;未置真即非灰度。
241
233
  canary: false,
242
- // 最小兜底镜像源。完整目录与探测规格是壳的产物:用户在装壳那刻机器上
243
- // 没有内核,壳必须先完成镜像选择才能装内核,故镜像源管理所有权在壳,经
244
- // <产品状态根>/supervisor/registry.json 投放,内核由 platform/distribution 读取
245
- // (见 platform/contract/registry.js)。此处仅保留官方源(能上网)+ npmmirror(中国网络)两条,
246
- // 覆盖契约不可用时也能跑这一底线(不变量 C2)。
234
+ // 最小兜底镜像源(不变量 C2):完整目录归壳管理,经 <产品状态根>/supervisor/registry.json 投放,
235
+ // 内核由 platform/distribution 读取(契约见 platform/contract/registry.js);
236
+ // 此处官方源 + npmmirror 两条兜底,保证契约不可用时仍可安装。
247
237
  registries: [
248
238
  "https://registry.npmjs.org",
249
239
  "https://registry.npmmirror.com"
@@ -253,12 +243,11 @@ var require_config = __commonJS({
253
243
  initialCheckDelayMs: 2e4,
254
244
  upgradeTimeoutMs: 6e5,
255
245
  installCommandTemplate: ["npm", "install", "-g", "{pkg}@{version}"],
256
- // apiAccessKey(可选):出回环访问密钥。仅当配置了该键时,0.0.0.0(局域网)与 FRP 公网通道
257
- // 的 API 请求必须携带 Authorization: Bearer <key> 或 ?access_key=<key>,否则 401;
258
- // 本地回环豁免。不配置 = 维持现状(LAN 受 RFC1918 白名单约束,FRP 暴露仍强制 remoteToken)。
246
+ // apiAccessKey(可选)出回环访问密钥:配置后,0.0.0.0(局域网)与 FRP 公网通道的 API 请求必须携带
247
+ // Authorization: Bearer <key> 或 ?access_key=<key>,否则 401;回环豁免。
248
+ // 不配置 = LAN 受 RFC1918 白名单约束,FRP 暴露仍强制 remoteToken。
259
249
  apiAccessKey: null,
260
- // 关闭窗口行为(系统级):'hide' = 隐藏至系统托盘(默认,服务继续常驻);
261
- // 'exit' = 退出管家,结束壳并停止全部服务链。
250
+ // 关闭窗口行为(系统级):'hide' = 隐藏至托盘、服务常驻(默认);'exit' = 退出管家并停全部服务链。
262
251
  closeAction: "hide"
263
252
  };
264
253
  function buildDefaults2(ext) {
@@ -337,7 +326,7 @@ var require_domain_config = __commonJS({
337
326
  var defaults = [
338
327
  {
339
328
  at: "portPools",
340
- // daemon 控制通道端口(router/lan 独立进程 ctl):集中定义,杜绝散落硬编码。
329
+ // daemon 控制通道端口:集中定义,杜绝散落硬编码。
341
330
  // 这两个值同时是 app/ctl/client.js 与两个 daemon 的兜底端口,不得单独改动
342
331
  // (改动即需同步 8 处 43107/43108 兜底常量)。
343
332
  values: {
@@ -347,7 +336,7 @@ var require_domain_config = __commonJS({
347
336
  },
348
337
  {
349
338
  at: "corePackageName",
350
- // 智能路由启动开关(别名见下方 aliases)。
339
+ // 智能路由启动开关。
351
340
  values: {
352
341
  routerAutostart: false
353
342
  }
@@ -373,7 +362,7 @@ var require_version = __commonJS({
373
362
  var fs2 = require("node:fs");
374
363
  var path2 = require("node:path");
375
364
  function guardVersion() {
376
- if (true) return String("0.1.6-BETA.1");
365
+ if (true) return String("0.1.6-BETA.2");
377
366
  try {
378
367
  return JSON.parse(fs2.readFileSync(path2.join(__dirname, "..", "..", "package.json"), "utf8")).version || "unknown";
379
368
  } catch {
@@ -2248,7 +2237,7 @@ var require_events = __commonJS({
2248
2237
  }
2249
2238
  return max;
2250
2239
  }
2251
- // 条 13):文件实际最大 seq —— 只读尾部(append-only + seq 单调 => 末行即最大)。
2240
+ // 文件实际最大 seq —— 只读尾部(append-only + seq 单调,末行即最大)。
2252
2241
  // 末行不可解析(截断起点落在行中 / 崩溃残留半行)时从后往前找首条完整记录;
2253
2242
  // 整段都解析不出(文件为空/刚轮转走)才回退 _maxSeq() 全扫描,含 .1 防与旧代重号。
2254
2243
  _fileMaxSeq() {
@@ -2708,8 +2697,8 @@ var require_hub = __commonJS({
2708
2697
  var { loadWatermark, saveWatermark } = require_watermark();
2709
2698
  var EventHub = class {
2710
2699
  // opts: stateDir 守卫状态目录(聚合流/水位落此);guardEvents 守卫 Events 实例(源之一);
2711
- // guardLogFile / dshLogFile / upgradeLogFile 守卫侧运行日志(/logs/tail 用);
2712
- // daemonLogs / ctlPorts 按装配短键索引的 daemon 日志与 ctl 端口;logger 可选。
2700
+ // guardLogFile/dshLogFile/upgradeLogFile 守卫侧运行日志(/logs/tail 用);
2701
+ // daemonLogs/ctlPorts 按装配短键索引;logger 可选。
2713
2702
  constructor(opts) {
2714
2703
  this.stateDir = opts.stateDir;
2715
2704
  this.aggBase = opts.aggBase || "state";
@@ -2738,7 +2727,7 @@ var require_hub = __commonJS({
2738
2727
  if (this.watermark[this._localSource] == null && this.guardEvents) this.watermark[this._localSource] = this.guardEvents.seq;
2739
2728
  this._tickSeq = 0;
2740
2729
  }
2741
- // 内部告警出口:可选 logger + 绝不抛(失败路径上的最后一环)。
2730
+ // 内部告警出口:经可选 logger,绝不抛(失败路径上的最后一环)。
2742
2731
  _log(level, msg) {
2743
2732
  try {
2744
2733
  const lg = this.logger;
@@ -2787,7 +2776,7 @@ var require_hub = __commonJS({
2787
2776
  }
2788
2777
  return lastOkSeq;
2789
2778
  }
2790
- // 守卫事件推模式:守卫 Events.append 已同步调此,守卫事件零延迟入聚合流。
2779
+ // 推模式:守卫 Events.append 已同步调此,守卫事件零延迟入聚合流。
2791
2780
  pushGuard(rec) {
2792
2781
  if (!rec || typeof rec.seq !== "number") return;
2793
2782
  if (rec.source === "guard-hub") return;
@@ -2878,7 +2867,7 @@ var require_hub = __commonJS({
2878
2867
  get seq() {
2879
2868
  return this.writer.seq;
2880
2869
  }
2881
- // /logs/tail:读各运行日志尾部。
2870
+ // /logs/tail:dsh/upgrade 为预设流;守卫与业务流按注册源装配短键解析。
2882
2871
  tailLog(stream, n) {
2883
2872
  const fixed = { dsh: this.dshLogFile, upgrade: this.upgradeLogFile };
2884
2873
  if (stream in fixed) return tailFile(fixed[stream], n);
@@ -3466,9 +3455,9 @@ var require_alloc = __commonJS({
3466
3455
  }
3467
3456
  }
3468
3457
  }
3469
- /** 跨进程分配锁(best-effort,B14)。返回释放函数;获取超时返回 null 并**继续**
3470
- * (fail-open 有界:登记后的「二次确认、被抢即撤销」复检是第二层防线,且 ports.json
3471
- * 读路径 reload 使外部分配可见 —— 宁可退化到复检层,也不让锁 IO 故障冻结分配)。 */
3458
+ /** 跨进程分配锁(best-effort)。返回释放函数;获取超时返回 null 并继续(fail-open 有界:
3459
+ * 登记后的「二次确认、被抢即撤销」复检是第二层防线,且 ports.json 读路径 reload 使外部
3460
+ * 分配可见 —— 宁可退化到复检层,也不让锁 IO 故障冻结分配)。 */
3472
3461
  async _acquireXLock() {
3473
3462
  const f = String(this._registry._file || "") + ".alloc.lock";
3474
3463
  const deadline = Date.now() + XLOCK_TIMEOUT_MS;
@@ -3511,7 +3500,7 @@ var require_alloc = __commonJS({
3511
3500
  }
3512
3501
  }
3513
3502
  }
3514
- /** 登记 + 有界复检(B14 TOCTOU):登记后端口若立刻被外部占用(bind 探测与登记间隙被抢),
3503
+ /** 登记 + 有界复检(TOCTOU):登记后端口若立刻被外部占用(bind 探测与登记间隙被抢),
3515
3504
  * 撤销登记并返回 false —— 宁可让调用方换下一个端口,也不留下必然失败的占用登记。
3516
3505
  * self-listening 等「自己就在监听」的登记走 _register,不经本复检。 */
3517
3506
  async _confirmRegister(port, rangeKey, owner) {
@@ -3684,7 +3673,7 @@ var require_pool = __commonJS({
3684
3673
  if (pools && typeof pools === "object") this._pools = Object.assign({}, core.DEFAULT_POOLS, pools);
3685
3674
  return this._pools;
3686
3675
  }
3687
- /** 实例侧注册接口(委托模块级函数;段名/池名同样是域知识)。 */
3676
+ /** 实例侧注册接口(委托 core 模块级函数);段名/池名是域知识,不在本平台模块硬编码(DS-G4)。 */
3688
3677
  registerSegment(role, pool) {
3689
3678
  core.registerSegment(role, pool);
3690
3679
  return this;
@@ -3759,8 +3748,7 @@ var require_pool = __commonJS({
3759
3748
  }
3760
3749
  if (removed) this._save();
3761
3750
  }
3762
- /** 释放端口:不传 ownerId 按端口号;传了则仅当登记 owner 匹配才释放。
3763
- * 注意空值检查必须在 owner 比较之前(旧实现顺序反了会抛 TypeError)。
3751
+ /** 释放端口:不传 ownerId 按端口号;传了则仅当登记 owner 匹配才释放。空值检查必须先于 owner 比较。
3764
3752
  * @returns {boolean} 是否真的释放了一条记录 */
3765
3753
  release(port, ownerId) {
3766
3754
  const p = Number(port);
@@ -3787,8 +3775,8 @@ var require_pool = __commonJS({
3787
3775
  for (const r of this._records.values()) if (r.owner === owner) return r.port;
3788
3776
  return null;
3789
3777
  }
3790
- /** 端口是否被占用:已登记 交 本机实际监听;excludeOwner 仅豁免 registry 登记。
3791
- * 监听探测为**双栈回环**(127.0.0.1 并::1),不再漏 IPv6-only 监听者。 */
3778
+ /** 端口是否被占用:已登记 或 本机实际监听;excludeOwner 仅豁免 registry 登记。
3779
+ * 监听探测为双栈回环(127.0.0.1 并 ::1),不漏 IPv6-only 监听者。 */
3792
3780
  async isTaken(port, excludeOwner) {
3793
3781
  const rec = this._records.get(Number(port));
3794
3782
  if (rec && (!excludeOwner || rec.owner !== excludeOwner)) return true;
@@ -4548,7 +4536,7 @@ var require_watchdog = __commonJS({
4548
4536
  const r = await shell.restartShell({
4549
4537
  exePath: exe,
4550
4538
  procPattern,
4551
- // 在飞复判(K4):杀旧壳与 spawn 之间有 ~8s 窗口,退出请求可能在窗口内到达。
4539
+ // 在飞复判:杀旧壳与 spawn 之间有 ~8s 窗口,退出请求可能在窗口内到达。
4552
4540
  shouldAbort: typeof o.halted === "function" ? () => o.halted() : void 0
4553
4541
  });
4554
4542
  if (r && r.ok) {
@@ -4599,10 +4587,9 @@ var require_capability_profile = __commonJS({
4599
4587
  "src/platform/os/capability-profile.js"(exports2, module2) {
4600
4588
  "use strict";
4601
4589
  var linux = {
4602
- // 沙箱舱拆两字段(multiInstance 一字段混装「能否跑舱」与「有无 cgroup」,掩盖降级形状):
4603
- // sandboxLaunch=能否运行实例舱;sandboxEnforcement=限额由谁执行(cgroup|supervise|none)。
4590
+ // 两维拆分声明:sandboxLaunch = 能否运行实例舱;sandboxEnforcement = 限额由谁执行(cgroup|supervise|none)。
4604
4591
  sandboxLaunch: true,
4605
- // W3 起恒可跑舱:有 systemd-run 走 cgroup 硬档,无则落 portable 软档(容器/WSL1 解锁)
4592
+ // W3:恒可跑舱;有 systemd-run 走 cgroup 硬档,无则落 portable 软档(容器/WSL1)
4606
4593
  sandboxEnforcement: "cgroup",
4607
4594
  // 期望 cgroup 硬限额;无 systemd-run 实测降 'supervise'(采样式,无内核强制)
4608
4595
  pidAdoption: true,
@@ -4640,8 +4627,8 @@ var require_capability_profile = __commonJS({
4640
4627
  // LaunchAgent RunAtLoad + KeepAlive
4641
4628
  guardSelfHeal: true,
4642
4629
  // KeepAlive
4643
- // 独立 LaunchAgent com.dsh.supervisor.gui(RunAtLoad);守卫 plist 归桌面壳建立,
4644
- // 内核只 enable/disable(见 autostart.js 头注的所有权矩阵)。
4630
+ // 壳自启 = 独立 LaunchAgent com.dsh.supervisor.gui(RunAtLoad),内核创建/删除;
4631
+ // 守卫 plist 归桌面壳建立,内核只 enable/disable + bootstrap/bootout。
4645
4632
  shellAutostart: true,
4646
4633
  shellSelfHeal: true
4647
4634
  // 守卫看护(三平台一套机制)
@@ -4653,9 +4640,8 @@ var require_capability_profile = __commonJS({
4653
4640
  // 采样式限额;Job Object 硬档一期不做不预留(届时以真机数据另立项)
4654
4641
  pidAdoption: true,
4655
4642
  // netstat
4656
- // processTreeKill 已接入 _killTree(supervisor 的 SIGKILL 升级路径 + 接管实例路径),
4657
4643
  processTreeKill: true,
4658
- // taskkill /PID /T /F(由 hasTool 覆写;使用点见 main-process._killTree)
4644
+ // taskkill /PID /T /F(hasTool 覆写;使用点见 app/main/signals.js 的 _killTree)
4659
4645
  desktopNotify: true,
4660
4646
  // 期望 powershell(实测覆写)
4661
4647
  autostart: true,
@@ -4663,13 +4649,12 @@ var require_capability_profile = __commonJS({
4663
4649
  frpExpose: true,
4664
4650
  hostService: "windows-service",
4665
4651
  guardAutostart: true,
4666
- // schtasks DSH-Supervisor(ONLOGON)
4652
+ // schtasks DSH-Supervisor(ONLOGON,由壳建立)
4667
4653
  guardSelfHeal: true,
4668
- // schtasks DSH-Supervisor-Watchdog 每 5 分钟
4654
+ // schtasks DSH-Supervisor-Watchdog 每 5 分钟(同样归壳,内核只查询存在性)
4669
4655
  shellAutostart: true,
4670
- // schtasks DSH-Supervisor-GUI(ONLOGON,由 setAutostart 建立)
4671
- // watchdog 的壳检查不再限定在守卫也挂的块内 —— 壳崩而守卫活正是唯一需要它的场景。
4672
- // 前置条件:登录自启已启用(watchdog 任务由 setAutostart 建立),与 guardSelfHeal 同前提。
4656
+ // schtasks DSH-Supervisor-GUI(ONLOGON,内核 setAutostart 创建)
4657
+ // 壳的自愈依赖那条 watchdog 任务,故与 guardSelfHeal 同前提:登录自启未启用时无从检查。
4673
4658
  shellSelfHeal: true
4674
4659
  };
4675
4660
  var unknown = {
@@ -5003,8 +4988,8 @@ var require_portable = __commonJS({
5003
4988
  return true;
5004
4989
  },
5005
4990
  /** 拉起:spawn(detached)——POSIX 自成进程组(kill(-pid) 语义的前提)、win32 windowsHide +
5006
- * CREATE_NEW_PROCESS_GROUP(统一经 platform/os/spawn.js,NO-CONSOLE-WINDOW 纪律收口在那)。
5007
- * props(cgroup 语义)在此被如实忽略——无内核强制可施加,处置归 governor 采样违规链。
4991
+ * CREATE_NEW_PROCESS_GROUP(NO-CONSOLE-WINDOW 纪律收口在 platform/os/spawn.js)。
4992
+ * 调用方传来的 props(cgroup 语义)在此如实忽略:本档无内核强制可施加。
5008
4993
  * @param {{cmd:string[], env?:object, workingDir?:string, pidFile?:string, port?:number, anchors?:string[]}} o */
5009
4994
  startTransient(o) {
5010
4995
  const opts = o || {};
@@ -5069,12 +5054,10 @@ var require_portable = __commonJS({
5069
5054
  }
5070
5055
  return false;
5071
5056
  },
5072
- /** 活跃判定(三态):见文件头契约。无任何锚点(port 与 pidFile 都缺)= 无从查询 -> null,
5073
- * 绝不被删除保护路径当成「已停止」。
5074
- * anchors 为空时降级为与 monitor.probeInstance 同一口径「端口有监听即活跃」(该调用方本就以此
5075
- * 判在线,如 waitPortHealthy);杀进程(stopUnit)仍要求锚点命中,二者宽严不同是有意的:
5076
- * 判定可宽,动手必严。存活 pid 的 cmdline 读取失败 = 无法区分「他人复用」与「查询失败」
5077
- * -> null(与 FIX-5 同一保守方向)。 */
5057
+ /** 活跃判定(三态):port 与 pidFile 都缺 = 无从查询 -> null,删除保护路径不得把它当「已停止」。
5058
+ * anchors 为空时降级为「端口有监听即活跃」(monitor.probeInstance 同口径,该调用方本就以此判在线);
5059
+ * 杀进程(stopUnit)仍要求锚点命中 —— 判定可宽,动手必严。
5060
+ * 存活 pid 的 cmdline 读不到 = 分不清「他人复用」与「查询失败」-> null。 */
5078
5061
  isUnitActive(unit, o) {
5079
5062
  const opts = o || {};
5080
5063
  if (findOurs(opts)) return true;
@@ -5101,8 +5084,7 @@ var require_portable = __commonJS({
5101
5084
  transientUnitFile() {
5102
5085
  return null;
5103
5086
  },
5104
- /** 清理同名残留:先停掉仍活着的旧进程(重启自愈路径:旧进程未监听端口时端口探测拦不住),
5105
- * 再清 run.pid。返回形态与 systemd 档一致({ok, errors}),调用方无需分支。 */
5087
+ /** 清理同名残留:先停掉仍活着的旧进程(重启自愈路径:旧进程未监听端口时端口探测拦不住),再清 run.pid。 */
5106
5088
  cleanTransient(unit, o) {
5107
5089
  const opts = o || {};
5108
5090
  const errors = [];
@@ -5110,8 +5092,7 @@ var require_portable = __commonJS({
5110
5092
  removePidFile(opts);
5111
5093
  return { ok: errors.length === 0, errors };
5112
5094
  },
5113
- /** 运行期限额下发:portable 档恒 false(档位声明)。true/false 只表示「是否改动了内核强制」,
5114
- * governor 不因 false 走任何降级分支——违规处置链本就平台无关。 */
5095
+ /** 返回值只表示「是否改动了内核强制」;governor 不因 false 走降级分支 —— 违规处置链本就平台无关。 */
5115
5096
  setLimits() {
5116
5097
  return false;
5117
5098
  }
@@ -5166,15 +5147,14 @@ var require_service = __commonJS({
5166
5147
  return false;
5167
5148
  }
5168
5149
  },
5169
- // run() 失败返回 null 而不抛,故原 try/catch 是死代码、恒返回 true(N5)。如实回传成败。
5150
+ // run() 失败返回 null 而不抛,try/catch 包裹会恒返回 true;如实回传成败。
5170
5151
  resetFailed(unit) {
5171
5152
  if (unitNameViolation(unit)) return false;
5172
5153
  return run("systemctl", ["--user", "reset-failed", unit], { timeoutMs: 1e4 }) !== null;
5173
5154
  },
5174
5155
  /** 单元活跃判定(三态):确认 active -> true;确认不活跃 -> false;查询未完成 -> null(未知)。
5175
- * 旧实现把「查询未完成」折成 false,而 run() 失败只返回 null,于是
5176
- * instance/ops.js 删除数据目录前的 null 保护成了不可达死分支,is-active 超时时仍会 rmSync
5177
- * 沙箱数据(FIX-5 A 的根因)。调用方按「!== false 才放行删除」消费本函数。 */
5156
+ * run() 失败只返回 null,「查询未完成」不可折成 false:instance/ops.js 删除数据目录前
5157
+ * 按「!== false 才放行删除」消费本函数,折假即超时窗口内误删沙箱数据。 */
5178
5158
  isUnitActive(unit) {
5179
5159
  if (!unit) return true;
5180
5160
  if (unitNameViolation(unit)) return false;
@@ -5201,9 +5181,8 @@ var require_service = __commonJS({
5201
5181
  },
5202
5182
  /** 清理 stale transient 单元:stop/reset-failed/删单元文件/daemon-reload。
5203
5183
  * 必须 reload:删除文件后 systemd 仍缓存该单元为 loaded,否则 systemd-run 拒绝重建同名单元。
5204
- * 返回 {ok, errors}:原实现四步全由 try/catch 包裹,而 run() 失败只返回 null 不抛 —— 四步
5205
- * 全部静默,调用方无条件记「cleaned」日志(N5)。stop/reset-failed 对「从未加载的单元」非零
5206
- * 退出属正常,不计入 ok;真正的硬失败只有删单元文件与 daemon-reload。 */
5184
+ * 返回 {ok, errors}:stop/reset-failed 对「从未加载的单元」非零退出属正常,不计入 ok;
5185
+ * 硬失败只有删单元文件与 daemon-reload(run() 失败返回 null 不抛,成败须如实回传)。 */
5207
5186
  cleanTransient(unit) {
5208
5187
  const errors = [];
5209
5188
  const bad = unitNameViolation(unit);
@@ -5239,8 +5218,7 @@ var require_service = __commonJS({
5239
5218
  return true;
5240
5219
  },
5241
5220
  /** 运行期改限额(W3 动态化):systemctl --user set-property 立即生效,无需重启单元。
5242
- * 必带 --runtime:transient 单元本不落盘,不带它会把 drop-in 写进用户配置目录,
5243
- * 与「每次启动按当时拓扑重算」的 governor 语义失同步(陈旧下限永久黏住)。
5221
+ * 必带 --runtime:transient 单元本不落盘,不带它会把 drop-in 写进用户配置目录,陈旧下限永久黏住。
5244
5222
  * 值只来自 sandbox.unitProps 同源的 alloc(平台层翻译语义、不决定数额)。 */
5245
5223
  setLimits(unit, alloc) {
5246
5224
  if (unitNameViolation(unit)) return false;
@@ -5277,7 +5255,7 @@ var require_service = __commonJS({
5277
5255
  transientUnitFile() {
5278
5256
  return null;
5279
5257
  },
5280
- // 无 transient 单元可清 = 成功;返回形态与 systemd 一致,调用方无需分支(N5)。
5258
+ // 无 transient 单元可清 = 成功;返回形态与 systemd 一致,调用方无需分支。
5281
5259
  cleanTransient() {
5282
5260
  return { ok: true, errors: [] };
5283
5261
  },
@@ -6108,17 +6086,17 @@ var require_os = __commonJS({
6108
6086
  processControl: require_process(),
6109
6087
  pidlookup: require_pidlookup(),
6110
6088
  execPath,
6111
- // 跨平台可执行解析(扩展名/PATHEXT/标准目录;hasTool 亦复用)
6089
+ // 跨平台可执行解析
6112
6090
  fileProtect: require_file_protect(),
6113
6091
  // 跨平台文件保护(Unix chmod / Windows icacls)
6114
6092
  service: require_service(),
6115
6093
  // 服务管理器抽象(Provider 分派)
6116
- // notify 必须是直接可调函数:supervisor 按 platform.notify(title, body, onError) 调用,
6117
- // 导出模块对象会报 platform.notify is not a function,升级终态被误判为失败。
6094
+ // notify 必须是直接可调函数:调用方按 platform.notify(title, body, onError) 用,
6095
+ // 导出模块对象会抛 platform.notify is not a function,把升级终态误判成失败。
6118
6096
  notify: require_notify().notify,
6119
6097
  browser: require_browser(),
6120
6098
  desktop: require_desktop(),
6121
- // 图形会话可用性(Linux 需真判定,见 desktop.js)
6099
+ // 图形会话可用性(Linux 需实测 socket)
6122
6100
  autostart: require_autostart()
6123
6101
  };
6124
6102
  }
@@ -6274,14 +6252,12 @@ var require_bootstrap = __commonJS({
6274
6252
  logger: host2.logger,
6275
6253
  events: host2.events,
6276
6254
  config: host2.config,
6277
- // 门**下沉到看护域**:tick() 的一切调用者都受同一门约束。
6278
- // 合取式收敛为单源谓词 host._shellExitIntended()
6279
- // (通用退出 或 持久 _shellHalted)。壳看护是**桌面壳域**自愈,须含 shellHalted
6280
- // (9-18:退出管家后守卫重启不得把壳拉回);主 DSH 收敛用不含 shellHalted 的 _exitIntended。
6255
+ // 退出门下沉到看护域:tick() 的一切调用者受同一门约束,合取式收敛为单源谓词
6256
+ // host._shellExitIntended()(通用退出 或 持久 _shellHalted)。壳看护属桌面壳域,
6257
+ // 须含 shellHalted(退出管家后守卫重启不得把壳拉回);主 DSH 收敛用 _exitIntended。
6281
6258
  halted: () => host2._shellExitIntended(),
6282
6259
  // 壳已在线 = 用户重新打开了壳 -> 清除持久退出标记(否则自愈被永久抑制)。
6283
- // 只在**非退出中**才清:退出握手期间壳还会存活数百 ms,若此时误清,
6284
- // 持久标记被写成 false,守卫重启后看护又把壳拉回(本修的核心场景)。
6260
+ // 只在非退出中清:退出握手期间壳还会存活数百 ms,此时误清会让守卫重启后又把壳拉回。
6285
6261
  onShellAlive: () => {
6286
6262
  if (!host2._shellHalted) return;
6287
6263
  if (host2._stopping) return;
@@ -7118,7 +7094,7 @@ var require_runtime = __commonJS({
7118
7094
  npmPath: j.npmPath || npm.path || null,
7119
7095
  // 外壳可只提供包内 JS(npmPath=node,npmArgs=[npm-cli.js]),消费者必须带上 args。
7120
7096
  npmArgs: Array.isArray(j.npmArgs) ? j.npmArgs : Array.isArray(npm.args) ? npm.args : [],
7121
- // npm 版本由壳**真实执行** npm --version 得到;旧壳没有这个键时为 null(未知就是未知)。
7097
+ // npm 版本由壳真实执行 npm --version 得到;旧壳无此键时为 null(未知就是未知)。
7122
7098
  npmVersion: typeof npm.version === "string" && npm.version || null,
7123
7099
  minNode: j.minNode || null,
7124
7100
  writtenBy: j.writtenBy || null,
@@ -7483,15 +7459,14 @@ var require_distribution = __commonJS({
7483
7459
  DistributionManager,
7484
7460
  semverCompare,
7485
7461
  VERSION_RE,
7486
- // 选版算法(release.js 唯一实现)+ 包归属判定 + rollback 防降级下限常量(RC-7 / A3-b)
7462
+ // 选版算法(release.js 唯一实现)+ 包归属判定 + rollback 防降级下限常量(RC-7)
7487
7463
  pickReleaseVersion: release.pickReleaseVersion,
7488
7464
  isOurReleasePackage: release.isOurReleasePackage,
7489
7465
  OUR_RELEASE_SCOPE: release.OUR_RELEASE_SCOPE,
7490
7466
  ROLLBACK_FLOOR_VERSION: release.ROLLBACK_FLOOR_VERSION,
7491
7467
  ROLLBACK_MAX_AGE_DAYS: release.ROLLBACK_MAX_AGE_DAYS,
7492
- // 在途 npm 中止出口(D-10):句柄登记在 install.js 的模块级集合(跨实例,覆盖全部调用路径),
7493
- // 故门面按**静态**导出,不挂 DistributionManager 实例方法——挂实例会漏掉直接 require('./install')
7494
- // 的调用方(app/native/installer.js 经 host.dist 走门面,但测试与未来 daemon 可直用)。
7468
+ // 在途 npm 中止出口(D-10):句柄登记在 install.js 的模块级集合(跨实例、覆盖全部调用路径),
7469
+ // 故门面按静态导出而非实例方法——挂实例会漏掉直接 require('./install') 的调用方。
7495
7470
  killInflightNpm: install.killInflightNpm,
7496
7471
  inflightNpmCount: install.inflightNpmCount
7497
7472
  };
@@ -7728,9 +7703,9 @@ var require_scheduler = __commonJS({
7728
7703
  }
7729
7704
  module2.exports = {
7730
7705
  methods: {
7731
- /** tick 保留为 _dshConverge 别名(C3-3b G3):外部收敛触发点(start 首拍 / setDesired /
7732
- * requestRestart / _exitUpgradeHold)调用;shadow 模式下定时器也驱动此别名。
7733
- * on 模式下 main 每拍收敛由 heartbeat 的 dsh supervise 调用 _dshConverge(无独立 tick 定时器)。 */
7706
+ /** tick 保留为 _dshConverge 别名:外部收敛触发点(start 首拍 / setDesired / requestRestart /
7707
+ * _exitUpgradeHold)调用;shadow 模式的定时器也驱动此别名。on 模式下 main 每拍收敛由
7708
+ * heartbeat 的 dsh supervise 直接调 _dshConverge(无独立 tick 定时器)。 */
7734
7709
  async tick() {
7735
7710
  const d = depsOf(this);
7736
7711
  return d.main().converge();
@@ -7791,7 +7766,7 @@ var require_instance_adapter = __commonJS({
7791
7766
  logger: () => host2.logger,
7792
7767
  control: () => host2.control,
7793
7768
  managedObjects: () => host2.managedObjects,
7794
- // 同模块兄弟方法经 host 上的既有安装转发(等价于原经 this 的调用)。
7769
+ // 同模块兄弟方法经 host 上的既有安装转发(等价于原经 this 的调用)
7795
7770
  syncSandboxRegistryEntry: (entry) => host2._syncSandboxRegistryEntry(entry)
7796
7771
  };
7797
7772
  DEPS.set(host2, d);
@@ -7800,11 +7775,10 @@ var require_instance_adapter = __commonJS({
7800
7775
  }
7801
7776
  module2.exports = {
7802
7777
  methods: {
7803
- /** 沙箱实例监督单拍(v3 R3 C3-4a observe -> C3-4b supervise 接管):heartbeat 经 adapter
7804
- * 对每个沙箱实例执行监督收敛(InstanceManager.supervise 单实例状态机,语义=旧 tick per-instance),
7805
- * 并把目录项与实例域状态对齐(desired/phase/guardian——目录=真实视图,防 ghost/死登记)。
7806
- * 域业务 CRUD/安装/装配/systemd/持久化保留 InstanceManager;本方法只做心跳驱动 + 目录同步。
7807
- * @returns {ok:boolean} 实例当前在线(heartbeat 统一写目录 lastObserved) */
7778
+ /** 沙箱实例监督单拍:heartbeat 经 adapter 对每个沙箱实例跑 InstanceManager.supervise
7779
+ * (单实例状态机)并把目录项与实例域状态对齐(目录=真实视图,防 ghost/死登记)。
7780
+ * 域业务 CRUD/安装/装配/systemd/持久化保留在 InstanceManager,本方法只做心跳驱动+目录同步;
7781
+ * 返回 ok=实例当前在线(heartbeat 统一写目录 lastObserved)。 */
7808
7782
  async _sandboxSuperviseOnce(entry) {
7809
7783
  const d = depsOf(this);
7810
7784
  if (d.stopping()) return { ok: false, error: "guard stopping" };
@@ -7832,10 +7806,9 @@ var require_instance_adapter = __commonJS({
7832
7806
  }
7833
7807
  return { ok: running, error: running ? null : "\u6C99\u7BB1\u5B9E\u4F8B\u672A\u8FD0\u884C" };
7834
7808
  },
7835
- /** 目录项 <- 实例域状态对齐(heartbeat 监督拍后调用):实例已删 -> 注销(防死登记);
7836
- * 实例存在 -> name/guardian/ownership 经 _managedSandboxSpec 申报,phase 落目录唯一词表。
7837
- * **desired 不同步**(D-8/铁律 1):观测推导的应然写回目录会让「崩溃进 BACKOFF」被
7838
- * 误判成「用户想停它」。意图只由 entry 的 start()/stop() 与动作路径改。 */
7809
+ /** 目录项 <- 实例域状态对齐(监督拍后调用):实例已删 -> 注销(防死登记);存在 -> 经
7810
+ * sandboxSpec 同步 name/guardian/ownership + phase 落目录词表。desired 不同步(keepDesired,
7811
+ * 契约 M-1:观测推导不得写回应然,崩溃进 BACKOFF 不等于「用户想停」)。 */
7839
7812
  _syncSandboxRegistryEntry(entry) {
7840
7813
  const d = depsOf(this);
7841
7814
  if (!entry || !d.managedObjects() || !d.instances()) return;
@@ -7888,7 +7861,7 @@ var require_decide = __commonJS({
7888
7861
  crashHalted() {
7889
7862
  return host2._crashHalted;
7890
7863
  },
7891
- // 字段 helper 与状态读取经 host 上的既有安装转发(等价于原经 this 的调用)。
7864
+ // 字段 helper 与状态读取经 host 既有安装转发。
7892
7865
  mLastProbeOk() {
7893
7866
  return host2._mLastProbeOk();
7894
7867
  },
@@ -8169,7 +8142,7 @@ var require_controller = __commonJS({
8169
8142
  sessionState() {
8170
8143
  return host2._sessionState;
8171
8144
  },
8172
- // 字段 helper 经 host 上的既有安装转发(等价于原经 this 的调用)。
8145
+ // 字段 helper 经 host 既有安装转发。
8173
8146
  mChild() {
8174
8147
  return host2._mChild();
8175
8148
  },
@@ -8225,8 +8198,8 @@ var require_controller = __commonJS({
8225
8198
  }
8226
8199
  module2.exports = {
8227
8200
  methods: {
8228
- // 主循环收敛段(唯一心跳驱动;外部操作仍可即时触发)。单一状态机:
8229
- // STOPPED/STARTING/RUNNING/RESTARTING/BACKOFF。systemd 托管已废弃,main 由守卫 spawn/观测统一管理。
8201
+ // 唯一心跳驱动的收敛段(外部操作仍可即时触发);单一状态机 STOPPED/STARTING/RUNNING/RESTARTING/BACKOFF。
8202
+ // main 由守卫统一 spawn/观测管理(不经 systemd 托管)。
8230
8203
  async _dshConverge() {
8231
8204
  const d = depsOf(this);
8232
8205
  if (d.readTicking() || d.stopping()) return;
@@ -8444,7 +8417,7 @@ var require_shadow = __commonJS({
8444
8417
  stopping() {
8445
8418
  return host2._stopping;
8446
8419
  },
8447
- // 兄弟方法/字段 helper 经 host 上的既有安装转发(等价于原经 this 的调用)。
8420
+ // 兄弟方法/字段 helper 经 host 既有安装转发。
8448
8421
  mAdopted() {
8449
8422
  return host2._mAdopted();
8450
8423
  },
@@ -8673,7 +8646,7 @@ var require_log = __commonJS({
8673
8646
  return 0;
8674
8647
  }
8675
8648
  }
8676
- // 读取日志尾部至多 n 行(空行省略;供测试/调试读已落盘内容)。文件不存在返回空数组。
8649
+ // 读取日志尾部至多 n 行(空行省略;文件不存在返回空数组)。
8677
8650
  tail(n) {
8678
8651
  if (!this.file) return [];
8679
8652
  try {
@@ -9157,7 +9130,7 @@ var require_signals = __commonJS({
9157
9130
  logger() {
9158
9131
  return host2.logger;
9159
9132
  },
9160
- // 兄弟方法经 host 上的既有安装转发(等价于原经 this 的调用)。
9133
+ // 兄弟方法经 host 既有安装转发。
9161
9134
  mainOwnerFile() {
9162
9135
  return host2._mainOwnerFile();
9163
9136
  },
@@ -9195,10 +9168,8 @@ var require_signals = __commonJS({
9195
9168
  }
9196
9169
  module2.exports = {
9197
9170
  methods: {
9198
- /** 主 DSH 的**归属凭据**文件:与 lan/router daemon 的
9199
- * `*-daemon.identity.json` 同范式、同址(stateFile 所在目录)。此前接管只凭 cmdline 子串
9200
- * 相似(`_isManagedProcess`),于是**两个守卫会认领同一个 DSH**——彼此 stop/kill 对方刚
9201
- * 接管的进程(审计原述「疑似双管家互杀」)。 */
9171
+ /** 主 DSH 归属凭据文件:与 lan/router daemon 的 *-daemon.identity.json 同范式、同址(stateFile 目录)。
9172
+ * 接管只凭 cmdline 子串相似会让两个守卫认领同一个 DSH、互 stop/kill 对方刚接管的进程,故落凭据声明归属。 */
9202
9173
  _mainOwnerFile() {
9203
9174
  const d = depsOf(this);
9204
9175
  try {
@@ -9207,7 +9178,7 @@ var require_signals = __commonJS({
9207
9178
  return null;
9208
9179
  }
9209
9180
  },
9210
- /** 读归属凭据;缺失/损坏一律 null(**绝不**因读失败而接管或否决——判定回落 cmdline)。 */
9181
+ /** 读归属凭据;缺失/损坏一律 null(绝不因读失败而接管或否决,判定回落 cmdline)。 */
9211
9182
  _readMainOwner() {
9212
9183
  const d = depsOf(this);
9213
9184
  try {
@@ -9219,10 +9190,8 @@ var require_signals = __commonJS({
9219
9190
  return null;
9220
9191
  }
9221
9192
  },
9222
- /** 落归属凭据:声明「pid=<dshPid> 的主 DSH 由本守卫(guardPid)负责」。
9223
- * spawn 与 adopt 两条取得所有权的路线都要写。落盘走 E-1 原子写单源(platform/util/fs 的
9224
- * writeAtomic:tmp 名含 pid+时间戳,多实例并发不互相覆盖,rename 原子替换)+ 0600
9225
- * ——与 daemon 身份文件同法。 */
9193
+ /** 落归属凭据:声明 pid=<dshPid> 的主 DSH 由本守卫(guardPid)负责;spawn 与 adopt 两条取得所有权的路线都要写。
9194
+ * 落盘走 writeAtomic 单源(tmp 名含 pid+时间戳,多实例并发不互相覆盖)+ 0600,与 daemon 身份文件同法。 */
9226
9195
  _writeMainOwner(dshPid, port) {
9227
9196
  const d = depsOf(this);
9228
9197
  try {
@@ -9238,12 +9207,9 @@ var require_signals = __commonJS({
9238
9207
  d.logger() && d.logger().warn && d.logger().warn("writeMainOwner: " + (e && e.message || e));
9239
9208
  }
9240
9209
  },
9241
- /** 校验 pid 进程是否属于本守卫管理:cmdline 含配置的启动 bin,或符合 DSH 特征(兼容外部手动起的标准 DSH)。
9242
- * 精确匹配避免"路径碰巧含 dsh 就误接管"与"安装路径不含 dsh 就漏接管"。
9243
- *
9244
- * 先看**归属凭据**——但凭据只做**否决**(别的守卫活着且明确拥有这个 pid 时不接管),
9245
- * 不单独放行:放行权威仍是 cmdline 特征。理由——陈旧凭据(pid 已被内核复用)若可单独放行,
9246
- * 会把无关进程接管进来,那是比原缺陷更糟的失败方向。 */
9210
+ /** 校验 pid 是否属本守卫:cmdline 含配置启动 bin 或符合 DSH 特征(兼容外部手动起的标准 DSH);
9211
+ * 精确匹配避免"路径碰巧含 dsh 误接管"与"安装路径不含 dsh 漏接管"。
9212
+ * 归属凭据只做否决(别的存活守卫拥有此 pid 时不接管),不单独放行:陈旧凭据的 pid 可能已被内核复用,单独放行会误接管无关进程。 */
9247
9213
  _isManagedProcess(pid) {
9248
9214
  const d = depsOf(this);
9249
9215
  const own = d.readMainOwner();
@@ -9259,22 +9225,14 @@ var require_signals = __commonJS({
9259
9225
  if (typeof bin === "string" && bin && cmd2.includes(bin)) return true;
9260
9226
  return pidlook.isDshCmdline(pid);
9261
9227
  },
9262
- /** 向进程组发信号(detached spawn 的子进程是组长);组信号失败退回单进程(平台层封装:
9263
- * POSIX 组信号;Windows 无组语义则单进程信号,树语义由 `killTree` 提供)。 */
9228
+ /** 向进程组发信号(detached spawn 的子进程是组长);组信号失败退回单进程。平台层封装:
9229
+ * POSIX 组信号;Windows 无组语义则单进程信号,树语义由 killTree 提供。 */
9264
9230
  _signalChild(child, sig) {
9265
9231
  platform.processControl.signalProcess(child.pid, sig);
9266
9232
  },
9267
- /** 整树终止。
9268
- *
9269
- * 为什么必须单独有这个方法:
9270
- * 平台层提供 `killTree`(Windows = `taskkill /PID <pid> /T /F`,POSIX = 进程组信号),
9271
- * 实际停止路径若只用 `signalProcess`,它在 Windows 上只 `process.kill(pid, sig)`(单进程语义由平台层注释自己写明)。
9272
- * 于是 Windows 上停止 DSH 只杀父进程:其派生的子进程(node / 浏览器 / 子命令)成为**孤儿**,
9273
- * 继续占端口、持文件锁;守卫重启后 adopt 复用即被楔死。
9274
- *
9275
- * POSIX 上 `killTree` 退化为组信号,与 `_signalChild` 等价(幂等,无害)。
9276
- * child 一律是本守卫 detached 拉起(组长),显式 ownGroup:true 保留组信号。
9277
- */
9233
+ /** 整树终止:必须单独存在。平台层 killTree(Windows taskkill /PID <pid> /T /F,POSIX 进程组信号)
9234
+ * 与 signalProcess 不同,后者在 Windows 只杀单进程——停止 DSH 会遗留子进程成孤儿、继续占端口与文件锁,守卫重启 adopt 即被楔死。
9235
+ * child 恒为本守卫 detached 拉起的组长,故显式 ownGroup:true 走组信号(POSIX 退化为组信号,幂等无害)。 */
9278
9236
  _killTree(child, sig) {
9279
9237
  const d = depsOf(this);
9280
9238
  const pc = platform.processControl;
@@ -9297,16 +9255,10 @@ var require_signals = __commonJS({
9297
9255
  }
9298
9256
  }, d.config().stopGraceMs));
9299
9257
  },
9300
- /** 杀无句柄的接管实例(仅知 pid)。
9301
- *
9302
- * 失败不再静默(D12):SIGKILL 投递后另给一次复核窗口,仍存活才判定「停止落空」,
9303
- * 发 stop_failed + warn —— 原实现只 append sigkill_sent 就算完,kill 失败与成功无法区分。
9304
- *
9305
- * 代际(gen):本文件只有一个 _adoptKillTimer 槽位,后一次 kill 会覆盖前一次的句柄。
9306
- * 故每次调用自增 _adoptKillGen,定时器只在「本代仍是当前代」时才把槽位置回 null,
9307
- * 防止旧 timer 清掉新一次操作的句柄(清掉后 shutdown 就漏清它)。
9308
- * 注意代际只保护共享槽位:每个 timer 仍按自己的 pid 完成升级与复核,
9309
- * 不因换代而跳过,否则前一个 pid 的 SIGKILL 升级会被吞掉。 */
9258
+ /** 杀无句柄的接管实例(仅知 pid)。失败不再静默:SIGKILL 后另给复核窗口,仍存活才判「停止落空」发 stop_failed + warn。
9259
+ * 代际 gen:本文件只有一个 _adoptKillTimer 槽位,后一次 kill 会覆盖前一次句柄;故每次自增 _adoptKillGen,
9260
+ * 定时器只在「本代仍是当前代」时置空槽位,防旧 timer 清掉新句柄。
9261
+ * 代际只保护共享槽位:每个 timer 仍按自己的 pid 完成升级与复核,不因换代跳过(否则前一个 pid 的 SIGKILL 升级被吞)。 */
9310
9262
  _killAdopted(pid) {
9311
9263
  const d = depsOf(this);
9312
9264
  const gen = (d.readAdoptKillGen() || 0) + 1;
@@ -9409,7 +9361,7 @@ var require_health_gate = __commonJS({
9409
9361
  ui() {
9410
9362
  return host2.ui;
9411
9363
  },
9412
- // 字段 helper 经 host 上的既有安装转发(等价于原经 this 的调用)。
9364
+ // 字段 helper 经 host 既有安装转发。
9413
9365
  mCrashWindowStart() {
9414
9366
  return host2._mCrashWindowStart();
9415
9367
  },
@@ -9466,13 +9418,9 @@ var require_health_gate = __commonJS({
9466
9418
  d.ui().notify("DSH \u53CD\u590D\u5D29\u6E83", "\u5DF2\u8FDB\u5165\u7B2C " + dec.backoffLevel + " \u7EA7\u9000\u907F\uFF08" + Math.round(d.config().backoff[dec.backoffLevel] / 1e3) + "s\uFF09\uFF0C\u8BF7\u67E5\u770B dsh-supervisor \u9762\u677F");
9467
9419
  }
9468
9420
  },
9469
- /** 假死识别(健康维度判定):进程/端口在但 HTTP 不健康时连续 failThreshold 次判故障重启。
9470
- * 单次抖动不清零(failStreak 单调累积直到达到阈值或恢复健康),达到阈值即触发。
9421
+ /** 假死识别(健康维度):进程/端口在但 HTTP 连续 failThreshold 次不健康才判故障重启;单次抖动不清零(failStreak 单调累积至阈值或恢复)。
9471
9422
  * httpProbeEnabled=false 时 healthOk 恒为 true(monitor.probe 已退化),此处天然不触发。
9472
- *
9473
- * 本方法只记账 + 返回决策,不直接调 main.beginRestart()(否则造成
9474
- * health-gate -> process 反向边);执行由收敛器(main/controller.js)承担。
9475
- * 依赖单向:controller/process -> health-gate。 */
9423
+ * 只记账 + 返回决策,不直接调 main.beginRestart(避免 health-gate -> process 反向边);执行由收敛器 controller 承担。 */
9476
9424
  _applyHealthCheck(healthOk) {
9477
9425
  const d = depsOf(this);
9478
9426
  if (healthOk) {
@@ -9521,12 +9469,10 @@ var require_supervise = __commonJS({
9521
9469
  }
9522
9470
  module2.exports = {
9523
9471
  methods: {
9524
- /** 唯一心跳驱动的 daemon 保活单拍:
9525
- * router/lan-daemon 的「业务需要它 + 失联即拉起」,由 ManagedRegistry.heartbeat 经 adapter 调用
9526
- * (节流约 30s)。守卫重启不影响 daemon(进程独立)。
9527
- * 契约 域 B:这两个 daemon 是基础设施(能力自愈),本方法是保活,不是「用户意图被守护触发」,
9528
- * 故两分支均不写 guardian_action / restartCount(G-1/G-2)。
9529
- * @returns {ok:boolean} daemon 当前在线(heartbeat 统一写入目录实然)。 */
9472
+ /** 唯一心跳驱动的 daemon 保活单拍:router/lan-daemon「业务需要它 + 失联即拉起」,由 ManagedRegistry.heartbeat
9473
+ * 经 adapter 调用(节流约 30s);守卫重启不影响 daemon(进程独立)。
9474
+ * 契约 域 B:两 daemon 是基础设施(能力自愈),本方法是保活而非守护触发用户意图,两分支均不写
9475
+ * guardian_action / restartCount(G-1/G-2)。@returns {ok:boolean} daemon 当前在线(heartbeat 统一写入目录实然)。 */
9530
9476
  async _daemonSuperviseOnce(kind) {
9531
9477
  const d = depsOf(this);
9532
9478
  if (d.stopping()) return { ok: false };
@@ -9685,16 +9631,9 @@ var require_process3 = __commonJS({
9685
9631
  var { waitProcessExit, waitPortFree } = require_process_wait();
9686
9632
  var { deriveCmdMarks } = require_process_marks();
9687
9633
  var DaemonLifecycle = class {
9688
- /**
9689
- * @param {object} o
9690
- * - name: 标识('router' | 'lan')
9691
- * - script / args: spawn 命令
9692
- * - ctlPort: 就绪/换代仲裁端口
9693
- * - cmdMark: cmdline 识别子串(防误接管异主)
9694
- * - identityFile: JSON {guardPid, daemonPid, startedAt}
9695
- * - spawnEnv(extra) / logger / events
9696
- * - readyTimeoutMs / stopGraceMs / portReleaseTimeoutMs / spawnWindowMs
9697
- */
9634
+ /** @param o 配置:name('router' | 'lan')、script/args(spawn 命令)、ctlPort(就绪/换代仲裁端口)、
9635
+ * cmdMark(cmdline 识别子串,防误接管异主)、identityFile(JSON {guardPid, daemonPid, startedAt})、
9636
+ * spawnEnv(extra) / logger / events、readyTimeoutMs / stopGraceMs / portReleaseTimeoutMs / spawnWindowMs。 */
9698
9637
  constructor(o) {
9699
9638
  this.name = o.name;
9700
9639
  this.script = o.script;
@@ -9768,9 +9707,9 @@ var require_process3 = __commonJS({
9768
9707
  const id = this._readIdentity();
9769
9708
  return id && id.daemonPid ? id.daemonPid : null;
9770
9709
  }
9771
- /** 回收非当前受管代际的旧代进程:YAMA 下 /proc fd 对非祖先不可读,socket 到 pid 无法映射,
9772
- * 故改用 pgrep -af 读 cmdline(跨平台/YAMA 免疫)。凡 cmdline 命中本 daemon(script+configPath 特征)
9773
- * 且 pid 非当前身份 pid/自己/ctl 属主,一律视为旧代残留 TERM 回收。@returns 回收数 */
9710
+ /** 回收非当前受管代际的旧代进程:YAMA 下 /proc fd 对非祖先不可读、socket 到 pid 无法映射,
9711
+ * 故用 pgrep -af 读 cmdline(跨平台/YAMA 免疫)。命中本 daemon 特征且 pid 非当前身份 pid/自己/
9712
+ * ctl 属主者一律视为旧代残留,TERM 回收。@returns 回收数 */
9774
9713
  reclaimOrphans() {
9775
9714
  const args = this.args || [];
9776
9715
  let cfg = "";
@@ -9820,11 +9759,8 @@ var require_process3 = __commonJS({
9820
9759
  }
9821
9760
  return killed;
9822
9761
  }
9823
- /** 换代/启动仲裁总入口:
9824
- * - 期望 pid 活且 ctl 就绪 -> {mode:'adopted', pid}
9825
- * - 无进程 -> spawn(latch)-> {mode:'started', pid}
9826
- * - 期望 pid 死或失联 -> reclaiming(停残留,短 latch 后下一轮 spawn)
9827
- * - spawn latch 窗口内 -> {mode:'barrier'} */
9762
+ /** 换代/启动仲裁总入口:期望 pid 活 -> {mode:'adopted', pid};无进程 -> spawn(latch)-> {mode:'started', pid};
9763
+ * 期望 pid 死或失联 -> reclaiming(停残留,短 latch 后下一轮 spawn);spawn latch 窗口内 -> {mode:'barrier'}。 */
9828
9764
  ensureRunning() {
9829
9765
  if (this._stopping) return { mode: "stopping" };
9830
9766
  try {
@@ -9880,16 +9816,9 @@ var require_process3 = __commonJS({
9880
9816
  if (this.logger && this.logger.info) this.logger.info("[" + this.name + "] \u5DF2\u62C9\u8D77\u72EC\u7ACB daemon pid=" + child.pid + "\uFF08spawn \u7A97\u53E3\u81F3 " + new Date(this._spawnWindowUntil).toISOString() + "\uFF09");
9881
9817
  return { mode: "started", pid: child.pid };
9882
9818
  }
9883
- /** 无副作用分类(供监督/审计共用):当前受管代际与 ctl 属主的真实状态。**绝不 spawn/stop**。
9884
- * @returns {{mode:'running'|'external'|'reclaiming'|'barrier'|'absent'|'stopping', pid?, owner?, stale?}}
9885
- * - running: 期望代际存活(ctl 属主=期望 pid,或 ctl 尚未起)
9886
- * - external: ctl 被「异 cmdMark/异代际」进程占用(外部抢占,绝不接管)
9887
- * - reclaiming: 期望代际已死但同 cmdMark 残留仍占 ctl(需换代)
9888
- * - barrier: spawn latch 窗口内(等旧代退出)
9889
- * - absent: 无进程、无残留(可 spawn)
9890
- * - stopping: 已进入停止流程
9891
- * 这是生产监督路径(_orphanAudit / _daemonSuperviseOnce)识别「异主 daemon」的唯一判据——
9892
- * ensureRunning 只按 cmdline 判 active,无法区分「本守卫的 daemon」与「外部同名 daemon」。 */
9819
+ /** 无副作用分类(供监督/审计共用,绝不 spawn/stop):running 期望代际存活 / external ctl 被异 cmdMark 进程
9820
+ * 占用(绝不接管)/ reclaiming 期望已死且同 cmdMark 残留占 ctl / barrier latch 窗口内 / absent 可 spawn /
9821
+ * stopping 停止中。监督与停止路径据此识别「异主 daemon」——ensureRunning 只按 cmdline 判 active,分不清两者。 */
9893
9822
  classify() {
9894
9823
  if (this._stopping) return { mode: "stopping" };
9895
9824
  const exp = this.expectedPid();
@@ -9903,8 +9832,8 @@ var require_process3 = __commonJS({
9903
9832
  if (stale) return { mode: "reclaiming", stale };
9904
9833
  return { mode: "absent" };
9905
9834
  }
9906
- /** 周期监督:期望进程失联则先验证死透再 replace(死透由 ensureRunning 的 stale/死pid 分支处理)。
9907
- * 基于 classify() 分类后施加副作用(reclaim/spawn);分类能力本身无副作用、供审计复用。 */
9835
+ /** 周期监督:classify() 分类(无副作用)后再施加副作用(reclaim/spawn);期望进程失联则先验证
9836
+ * 死透再 replace(死透由 ensureRunning 的 stale/死 pid 分支处理)。 */
9908
9837
  async superviseOnce() {
9909
9838
  if (!this.expectedPid()) {
9910
9839
  try {
@@ -10021,7 +9950,7 @@ var require_runtime2 = __commonJS({
10021
9950
  router() {
10022
9951
  return host2.router;
10023
9952
  },
10024
- // 同模块兄弟方法经 host 上的既有安装转发(等价于原经 this 的调用;外部覆写 host 方法仍生效)。
9953
+ // 同模块兄弟方法经 host 上的既有安装转发(外部覆写 host 方法仍生效)。
10025
9954
  dshMainView() {
10026
9955
  return host2.dshMainView();
10027
9956
  },
@@ -10061,7 +9990,7 @@ var require_runtime2 = __commonJS({
10061
9990
  module2.exports = {
10062
9991
  methods: {
10063
9992
  /** 统一受管进程生命周期实例(懒加载单例;lan/router 共用 DaemonLifecycle 核心)。
10064
- * 身份文件(owner 连续:守卫重启=接管既有 daemon)+ spawn latch + 换代停旧/等死/等端口释放 全在核心内。 */
9993
+ * 身份文件(owner 连续:守卫重启=接管既有 daemon)、spawn latch、换代停旧/等死/等端口释放都在核心内。 */
10065
9994
  _daemonLifecycle(kind) {
10066
9995
  const d = depsOf(this);
10067
9996
  if (!d.configPath()) return null;
@@ -10331,7 +10260,7 @@ var require_identity = __commonJS({
10331
10260
  config() {
10332
10261
  return host2.config;
10333
10262
  },
10334
- // 同模块兄弟方法经 host 上的既有安装转发(等价于原经 this 的调用)。
10263
+ // 同模块兄弟方法经 host 上的既有安装转发。
10335
10264
  lanLockPath() {
10336
10265
  return host2._lanLockPath();
10337
10266
  },
@@ -10344,7 +10273,7 @@ var require_identity = __commonJS({
10344
10273
  return d;
10345
10274
  }
10346
10275
  module2.exports = {
10347
- // D-12 测试缝:锁的取/放/读主是纯 fs + kill(0) 语义,直接导出给回归用(不改行为)。
10276
+ // 测试缝:锁的取/放/读主是纯 fs + kill(0) 语义,直接导出给回归用。
10348
10277
  _lockPrimitives: { acquireLock: acquireLock2, releaseLock: releaseLock2, lockPid, pidAlive },
10349
10278
  methods: {
10350
10279
  _lanLockPath() {
@@ -10434,9 +10363,7 @@ var require_probe4 = __commonJS({
10434
10363
  }
10435
10364
  module2.exports = {
10436
10365
  methods: {
10437
- /** 独立 router-daemon 是否在运行(探测 ctl 端口监听者 cmdline 是否 router-daemon)。
10438
- * 守卫探测到 daemon 在跑就不再内嵌启动 router(避免双占 ctl 口),只做监督
10439
- * (lifecycleManager 周期探活 ctl 口,异常时拉起 daemon)。 */
10366
+ /** 独立 router-daemon 是否在运行(探测 ctl 端口监听者 cmdline)。 */
10440
10367
  _routerDaemonActive() {
10441
10368
  const d = depsOf(this);
10442
10369
  try {
@@ -10448,9 +10375,8 @@ var require_probe4 = __commonJS({
10448
10375
  return false;
10449
10376
  }
10450
10377
  },
10451
- /** lan-daemon 模式是否启用(结构性部署选择,非用户意图开关)。
10452
- * config.lanDaemon === true 时 lan 由独立 daemon 承载(ctl 通道),
10453
- * 否则内嵌 LanManager。这是部署形态选择(壳写配置),不对用户暴露。 */
10378
+ /** lan-daemon 模式是否启用:config.lanDaemon 是结构性部署选择(壳写配置,无面板入口、不对用户
10379
+ * 暴露)——true 时 lan 由独立 daemon 承载(ctl 通道),否则内嵌 LanManager。 */
10454
10380
  lanDaemonEnabled() {
10455
10381
  const d = depsOf(this);
10456
10382
  const cfg = d.config();
@@ -10499,7 +10425,7 @@ var require_router = __commonJS({
10499
10425
  ctl() {
10500
10426
  return host2.ctl;
10501
10427
  },
10502
- // 同模块兄弟方法经 host 上的既有安装转发(等价于原经 this 的调用;外部覆写 host 方法仍生效)。
10428
+ // 同模块兄弟方法经 host 上的既有安装转发(外部覆写 host 方法仍生效)。
10503
10429
  routerDaemonActive() {
10504
10430
  return host2.routerDaemonActive();
10505
10431
  },
@@ -10584,12 +10510,10 @@ var require_router = __commonJS({
10584
10510
  return { ok: false, source: "embedded", error: e2 && e2.message || String(e2) };
10585
10511
  }
10586
10512
  },
10587
- // L3 监督模式:router 控制通道(daemon 唯一事实源)。
10588
- // 本方法上移至此以打断 facade/router 与 ctl/facades 的 this 调用环:ctl/facades 不再
10589
- // 调用本文件的 routerDaemonActive;本文件对 ctl 的依赖单向(经 this._makeRouterFacade)。
10590
- // 守卫 API/视图统一从 routerApi() 取 router 门面:daemon 在跑则转发 ctl
10591
- // (POST /ctl {method,args},见 src/platform/ctl/server.js)——写即 daemon 生效、读即
10592
- // daemon 最新;daemon 未跑则走守卫本地实例(内嵌回退路径)。
10513
+ // router 控制通道门面:守卫 API/视图统一从这里取。
10514
+ // 本方法在此文件以保证对 ctl 的依赖单向(ctl/facades 不调本文件的 routerDaemonActive)。
10515
+ // daemon 在跑则转发 ctl(POST /ctl {method,args})——写即 daemon 生效、读即 daemon 最新;
10516
+ // daemon 未跑则走守卫本地实例(内嵌回退路径)。
10593
10517
  routerApi() {
10594
10518
  const d = depsOf(this);
10595
10519
  if (d.routerDaemonActive()) {
@@ -10616,12 +10540,9 @@ var require_lan = __commonJS({
10616
10540
  return d;
10617
10541
  }
10618
10542
  module2.exports = { methods: {
10619
- // 远程控制委托:全部转发给 LanManager。
10620
- // daemon 监督模式经 43108 ctl 委托(异步);本地模式走 LanManager(同步)。
10621
- // 令牌收敛:listLan 输出剔除 token/dshToken——/lan-access 允许 LAN/私网 Host 访问,
10622
- // 直出 dshToken 会把 DSH 会话令牌泄漏给局域网;权威仍在 DshTokenService(relay 经
10623
- // tokenOf 内部读取,无需经此透传)。remote(projectRemoteView 产物)为后端单一推导
10624
- // 视图 {mode,ready,accessUrl,reasons},不含机密,整段放行给 UI 消费。返回形如 {items,addresses}。
10543
+ // 远程控制委托:全部转发给 LanManager;daemon 监督模式经 43108 ctl 委托(异步),本地模式走 LanManager(同步)。
10544
+ // 令牌收敛:listLan 输出必须剔除 token/dshToken —— /lan-access 允许 LAN/私网 Host 访问,直出会把 DSH 会话令牌泄漏给局域网,权威仍在 DshTokenService。
10545
+ // remote(projectRemoteView 产物)为后端单一推导视图 {mode,ready,accessUrl,reasons},不含机密,整段放行给 UI。返回形如 {items,addresses}。
10625
10546
  listLan() {
10626
10547
  const d = depsOf(this);
10627
10548
  const sanitize = (r) => {
@@ -10680,7 +10601,6 @@ var require_ports2 = __commonJS({
10680
10601
  logger() {
10681
10602
  return host2.logger;
10682
10603
  },
10683
- // 同模块兄弟方法经 host 上的既有安装转发(等价于原经 this 的调用)。
10684
10604
  portActives(list) {
10685
10605
  return host2._portActives(list);
10686
10606
  },
@@ -10696,8 +10616,8 @@ var require_ports2 = __commonJS({
10696
10616
  return d;
10697
10617
  }
10698
10618
  module2.exports = { methods: {
10699
- // 端口管理门面:统一端口 registry 清单经 sup 接口暴露(presentation 不直连 infra)。
10700
- // 每条记录必须补 active(端口当前真实监听中),否则前端「状态」列全部显示停用。
10619
+ // 端口清单经 sup 接口暴露(presentation 不直连 infra)。每条记录必须补 active
10620
+ // (端口当前真实监听中),否则前端「状态」列全部显示停用。
10701
10621
  // 探测按端口集合整批缓存 3s TTL,避免前端 2s 心跳每次触发全量同步扫 /proc 挤占事件循环。
10702
10622
  async listPorts() {
10703
10623
  const d = depsOf(this);
@@ -10736,11 +10656,9 @@ var require_ports2 = __commonJS({
10736
10656
  }
10737
10657
  return { records: out, snapshot: snap, capacity };
10738
10658
  },
10739
- /** 端口集合激活探测。active=true 表示该端口当前有进程在监听。
10740
- * 用纯 TCP connect(probe.portListening)判定:findListeningPid 需读 /proc/<pid>/fd 反查
10741
- * socket->pid,对守卫管理树外的孙进程(router-daemon 的反代子进程)常因读取权限返回 null,
10742
- * 导致端口在监听却恒报 inactive。TCP connect 与端口是否被监听直接等价(同 isTaken 判占用
10743
- * 语义),无需 /proc 权限,三平台一致。 */
10659
+ /** 端口集合激活探测,active=true 表示该端口当前有进程在监听。判定用纯 TCP connect(probe.portListening):
10660
+ * findListeningPid 要读 /proc/<pid>/fd 反查 socket->pid,对守卫管理树外的孙进程(router-daemon 的反代子进程)
10661
+ * 常因读取权限返回 null,端口在监听却恒报 inactive;TCP connect 无需 /proc 权限、三平台一致。 */
10744
10662
  async _portActives(portsList) {
10745
10663
  const d = depsOf(this);
10746
10664
  const now = Date.now();
@@ -10893,7 +10811,7 @@ var require_status = __commonJS({
10893
10811
  return {
10894
10812
  desired: host2._mDesired(),
10895
10813
  phase: host2._mPhase(),
10896
- // 会话生命周期(契约 ,INV-S4):与 phase 正交——phase 是 main 状态机相位,
10814
+ // 会话生命周期(INV-S4):与 phase 正交——phase 是 main 状态机相位,
10897
10815
  // sessionState 是整个服务链的运行相位(前端/壳据此表达「退出中/已退出」)。
10898
10816
  sessionState: host2._sessionState,
10899
10817
  // 数据目录保护状态(Windows 无 icacls 时可观测降级)。
@@ -10938,7 +10856,6 @@ var require_router2 = __commonJS({
10938
10856
  function createRouterActions(deps) {
10939
10857
  const g = deps || {};
10940
10858
  return {
10941
- // 智能路由开关管理
10942
10859
  async setRouterRunning(on) {
10943
10860
  const lifecycleManager = g.getLifecycleManager();
10944
10861
  const daemons = g.getDaemons();
@@ -11094,7 +11011,7 @@ var require_core4 = __commonJS({
11094
11011
  return {
11095
11012
  ok: false,
11096
11013
  redirect: url.pathname,
11097
- // 令牌条 5:种的是派生会话值,绝不是门卫令牌原文。
11014
+ // 令牌条 5:种派生会话值,绝不是门卫令牌原文。
11098
11015
  cookie: "dsh_lan_token=" + lanGateCookieValue(token, salt) + "; Path=/; HttpOnly; SameSite=Lax"
11099
11016
  };
11100
11017
  }
@@ -11436,10 +11353,9 @@ var require_env_catalog = __commonJS({
11436
11353
  constructor(config) {
11437
11354
  this.config = config || {};
11438
11355
  }
11439
- /** 系统二进制条目探测:{ id: { label, required, state, detail } }。
11440
- * state 三态:ok = 存在且满足门槛(Node 需 >= 壳投放的 minNode);outdated = 存在但低于门槛
11441
- * (旧实现会误报 ok,面板谎报环境就绪);missing = 不存在。
11442
- * 兼容:detail 保持字符串,新增字段放 detail 之外(version/min/meets),不破坏既有契约。 */
11356
+ /** 系统二进制条目探测:{ id: { label, required, state, detail } }。state 三态:
11357
+ * ok = 存在且满足门槛(Node 需 >= 壳投放的 minNode);outdated = 存在但低于门槛;missing = 不存在。
11358
+ * 兼容:detail 保持字符串,新增字段(version/min/meets)放 detail 之外,不破坏既有契约。 */
11443
11359
  probe() {
11444
11360
  const out = {};
11445
11361
  for (const [id, e] of Object.entries(SYSTEM_ENTRIES)) {
@@ -11460,9 +11376,8 @@ var require_env_catalog = __commonJS({
11460
11376
  }
11461
11377
  return out;
11462
11378
  }
11463
- /** 内核更新依赖条目(单写入者契约:安装/重启归桌面壳)。守卫不再自更新,corePackageName 只用于
11464
- * 查询内核版本状态,本条目只报告壳执行内核更新所需的包名是否就位。id 仍为 selfUpdate 以兼容
11465
- * 既有 /env/status 消费方。 */
11379
+ /** 内核更新依赖条目(单写入者契约:安装/重启归桌面壳,守卫只读 corePackageName 查版本状态)。
11380
+ * id 仍为 selfUpdate 以兼容既有 /env/status 消费方。 */
11466
11381
  selfUpdateEntry() {
11467
11382
  const pkg = this.config.corePackageName;
11468
11383
  if (!pkg) {
@@ -11484,8 +11399,7 @@ var require_env_catalog = __commonJS({
11484
11399
  detail: binOk ? installed || "\u5DF2\u88C5" : "bin \u4E0D\u5B58\u5728: " + (bin || "?")
11485
11400
  };
11486
11401
  }
11487
- /** 汇总:全部必填项状态(供面板/守卫快速判定环境就绪)。
11488
- * 无 sys 时探测一次(有 10s TTL 缓存)。 */
11402
+ /** 汇总:全部必填项状态(供面板/守卫快速判定环境就绪);无 sys 时探测一次(有 10s TTL 缓存)。 */
11489
11403
  summary(extra, sys) {
11490
11404
  const s = sys || this.probe();
11491
11405
  const items = { ...s, ...extra || {} };
@@ -11587,7 +11501,7 @@ var require_node_lts = __commonJS({
11587
11501
  var path2 = require("node:path");
11588
11502
  module2.exports = {
11589
11503
  methods: {
11590
- /** 6h 缓存 + 失败降级:不做远端查询(避免守卫启动依赖网络),本地判定 + 可刷新缓存;
11504
+ /** Node LTS 状态:本地判定 + 6h 可刷新缓存,不做远端查询(避免守卫启动依赖网络)。
11591
11505
  * 失败返回 { ok:false, error } 由前端降级展示,绝不抛异常。 */
11592
11506
  async nodeLtsStatus() {
11593
11507
  try {
@@ -11713,7 +11627,6 @@ var require_versions = __commonJS({
11713
11627
  dist: () => host2.dist,
11714
11628
  events: () => host2.events,
11715
11629
  guardVersion: () => host2.guardVersion,
11716
- // 同模块兄弟方法经 host 上的既有安装转发(等价于原经 this 的调用)。
11717
11630
  guardCorePkg: () => host2.guardCorePkg(),
11718
11631
  readBinarySelfVersion: () => host2._readBinarySelfVersion(),
11719
11632
  vcsRoot: () => host2._vcsRoot(),
@@ -11725,20 +11638,18 @@ var require_versions = __commonJS({
11725
11638
  }
11726
11639
  module2.exports = {
11727
11640
  methods: {
11728
- // ---- 内核更新(单写入者契约:安装/重启归桌面壳)----
11729
- // 内核 npm 包的唯一写入者是桌面壳(见 RELEASE-AND-UPDATE-MECHANISM.md);
11641
+ // ---- 内核更新(单写入者契约):内核 npm 包的唯一写入者是桌面壳;
11730
11642
  // 守卫只保留只读的 guardSelfUpdateStatus,接口 /self-update/apply|restart-guard 返回 410。
11731
- /** 内核 npm 子包名(按当前平台/架构)。corePackageName 可为显式常量或含 {os}/{arch} 占位的模板。 */
11643
+ /** 内核 npm 子包名:corePackageName 可为显式常量或含 {os}/{arch} 占位的模板。 */
11732
11644
  guardCorePkg() {
11733
11645
  const d = depsOf(this);
11734
11646
  const raw = d.config().corePackageName;
11735
11647
  if (!raw) return null;
11736
11648
  return String(raw).replace(/{os}/g, matrix.osTag()).replace(/{arch}/g, matrix.current().arch) || null;
11737
11649
  },
11738
- /** 内核更新状态(只读;安装/重启归桌面壳,单写入者契约)。
11739
- * 查 @dsh-sup/dsh-core-<os>-<arch> 的通道版本(RELEASE-CHANNEL-CONTRACT:
11740
- * rollback -> canary -> latest;latest 缺失才回落最高),与本机 guardVersion 比较。
11741
- * 本方法不写任何东西:面板据此显示可更新,实际安装由桌面壳 kernel_update_apply 执行。 */
11650
+ /** 内核更新状态(只读,本方法不写任何东西;实际安装由桌面壳 kernel_update_apply 执行)。
11651
+ * 查内核子包在发布通道(RELEASE-CHANNEL-CONTRACT:rollback -> canary -> latest,
11652
+ * latest 缺失才回落最高)的版本,与本机 guardVersion 比较。 */
11742
11653
  async guardSelfUpdateStatus() {
11743
11654
  const d = depsOf(this);
11744
11655
  const pkg = d.guardCorePkg();
@@ -11759,14 +11670,10 @@ var require_versions = __commonJS({
11759
11670
  return { ok: false, error: e.message };
11760
11671
  }
11761
11672
  },
11762
- /** 读磁盘上运行位的自报版本(A1 校验用):spawn --version,解析 guardVersion= 行。
11763
- *
11764
- * 条件为「可更新的标准形态」(updatable === true,即 sea-binary 或 launcher):
11765
- * 发布形态已弃 SEA 改为文本 launcher,launcher 的 <pkg>/bin/dsh-supervisor 同样是可执行入口
11766
- * (require('../../core.cjs')),spawn 它能得到同样的 --version 输出。若只认 sea-binary,
11767
- * 真实用户永远读不到磁盘实况版本,updatePending 恒 false(「已装好待重启」永不显示)。
11768
- * source-shell(源码形态)不支持:其 --version 报的是开发目录版本,与 npm 安装无关。
11769
- */
11673
+ /** 读磁盘上运行位的自报版本:spawn --version,解析版本行。
11674
+ * 条件是 updatable(sea-binary 或 launcher):launcher 的 bin 入口同样可执行,
11675
+ * 若只认 sea-binary 则发布态永远读不到磁盘实况,updatePending 恒 false。
11676
+ * source-shell 不支持:其 --version 报的是开发目录版本,与 npm 安装无关。 */
11770
11677
  _readBinarySelfVersion() {
11771
11678
  const dep = deploy.detect();
11772
11679
  if (!dep.updatable || !dep.runningTarget) return null;
@@ -11779,9 +11686,9 @@ var require_versions = __commonJS({
11779
11686
  }
11780
11687
  },
11781
11688
  // 管家自身版本检查(与 DSH 更新解耦):本地仓库 git 视角,配了远程才 fetch 比对。
11782
- /** VCS 根解析:从包根上溯找最近的外层 .git(排除自身嵌套仓)。
11783
- * 命中嵌套仓会使其 HEAD 与真实外层仓脱节,导致 UI 版本/commit 失真;找不到外层仓时回退包根。
11784
- * 包根用 srcpath.resolvePackageRoot()(按 package.json 上溯),不能靠 __dirname 相对路径。 */
11689
+ /** VCS 根:从包根上溯找最近的外层 .git(排除自身嵌套仓——嵌套仓 HEAD 与外层仓脱节,
11690
+ * 会导致 UI 版本/commit 失真);找不到时回退包根。
11691
+ * 包根必须用 srcpath.resolvePackageRoot()(按 package.json 上溯),不能靠 __dirname 相对层数。 */
11785
11692
  _vcsRoot() {
11786
11693
  const dir = srcpath.resolvePackageRoot() || path2.resolve(__dirname, "..");
11787
11694
  const innerGit = path2.join(dir, ".git");
@@ -11807,11 +11714,9 @@ var require_versions = __commonJS({
11807
11714
  }
11808
11715
  return { version: d.guardVersion(), runningVersion: d.guardVersion(), commit, updateAvailable: false, upstream, latest: d.guardVersion() };
11809
11716
  },
11810
- /**
11811
- * 完整版本检查(async):本地 commit + 远端 fetch 比对。
11812
- * 关键架构约束:git fetch 是网络 I/O,绝不能同步执行(会冻结整个事件循环,守卫假死且无法自愈)。
11813
- * 这里用 exec.runOutAsync(异步)+ 10s 超时;fetch 失败/超时只降级为「本地视图」,不抛错。
11814
- */
11717
+ /** 完整版本检查(async):本地 commit + 远端 fetch 比对。
11718
+ * git fetch 是网络 I/O,绝不能同步执行(会冻结事件循环,守卫假死且无法自愈);
11719
+ * fetch 失败/超时只降级为「本地视图」,不抛错。 */
11815
11720
  async guardVersionCheck() {
11816
11721
  const d = depsOf(this);
11817
11722
  const base = d.guardVersionLocal();
@@ -11861,10 +11766,10 @@ var require_access = __commonJS({
11861
11766
  const cfg = this.config || {};
11862
11767
  return { configured: !!cfg.apiAccessKey, host: cfg.apiHost || void 0 };
11863
11768
  },
11864
- /** 设置/清除出回环访问密钥(空串=清除)。原子持久化到守卫 config。
11865
- * 清空密钥必须**同时回关 LAN**(apiHost -> 127.0.0.1 并持久化):lan-panel 的开 LAN 前置条件是
11866
- * 「已有 apiAccessKey」,若只清 key 不动 apiHost,就会留下「绑定 0.0.0.0 且零认证」的暴露窗口。
11867
- * 监听 socket 的即时生效由 api 层的 fail-closed 兜底(本层只负责让配置事实自洽,不在此重绑)。 */
11769
+ /** 设置/清除出回环访问密钥(空串=清除)。
11770
+ * 清空密钥必须同时回关 LAN(apiHost -> 127.0.0.1 并持久化):lan-panel 的开 LAN
11771
+ * 前置条件是「已有 apiAccessKey」,只清 key 不动 apiHost 会留下「绑定 0.0.0.0 且零认证」
11772
+ * 的暴露窗口。监听 socket 的即时生效由 api 层 fail-closed 兜底,本层只保证配置自洽。 */
11868
11773
  setAccessKey(key) {
11869
11774
  try {
11870
11775
  const cfg = this.config || {};
@@ -12031,7 +11936,6 @@ var require_lan_panel = __commonJS({
12031
11936
  events: () => host2.events,
12032
11937
  configPath: () => host2.configPath,
12033
11938
  api: () => host2.api,
12034
- // 同模块兄弟方法经 host 上的既有安装转发(等价于原经 this 的调用)。
12035
11939
  lanPanelStatus: () => host2.lanPanelStatus(),
12036
11940
  apiRebind: () => host2._apiRebind()
12037
11941
  };
@@ -12104,9 +12008,7 @@ var require_facets = __commonJS({
12104
12008
  var FACETS = [
12105
12009
  { name: "assembly/bootstrap", mod: require_bootstrap(), hostFirst: true },
12106
12010
  { name: "assembly/api-rebind", mod: require_api_rebind(), apiRebind: true },
12107
- // 级 2:session/machine + state/{store,fields,desired,upgrade-hold,main-store}
12108
- // + control/{projection,specs} 已改为**真 ctor 工厂**,经 assembly/collaborators.js 装配,
12109
- // 不再在此以 { methods }/{ hostFirst } 形态安装(见 collaborators.js)。
12011
+ // session/state/control 不在本清单:它们是真 ctor 工厂,由 assembly/collaborators.js 装配。
12110
12012
  { name: "session/shutdown", mod: require_shutdown(), hostFirst: true },
12111
12013
  { name: "self/notify", mod: require_notify2(), hostFirst: true },
12112
12014
  { name: "control/scheduler", mod: require_scheduler() },
@@ -12115,7 +12017,6 @@ var require_facets = __commonJS({
12115
12017
  { name: "main/controller", mod: require_controller() },
12116
12018
  { name: "main/shadow", mod: require_shadow() },
12117
12019
  { name: "main/process", mod: require_process2() },
12118
- // R3 严值 DF-2:端口运行时再推导从 main/process.js 拆为独立切面(_findManagedDshPort/_applyMainPort)。
12119
12020
  { name: "main/port-rederive", mod: require_port_rederive() },
12120
12021
  { name: "main/signals", mod: require_signals() },
12121
12022
  { name: "main/health-gate", mod: require_health_gate() },
@@ -12130,10 +12031,9 @@ var require_facets = __commonJS({
12130
12031
  { name: "facade/ports", mod: require_ports2() },
12131
12032
  { name: "facade/main", mod: require_main() },
12132
12033
  { name: "facade/status", mod: require_status(), hostFirst: true },
12133
- // 域写动作下沉 app/domain-actions/(facade 只读),同一装配契约。
12134
- // P6-B:三者已改为**真 ctor 工厂**(实现体经显式 deps 取事实,不再直连 this),
12135
- // 故不再走 `f.mod.methods` 分支 —— 用 factory 名在装配期构造,并把产物**平铺安装**到 host,
12136
- // 保证 api 消费面(sup.setRouterRunning / patchDshMain / setRemoteMode …)名字逐个不变。
12034
+ // 域写动作在 app/domain-actions/(facade 侧只读):三者是真 ctor 工厂,实现体经显式 deps
12035
+ // 取事实、不直连 this;按 factory 名在装配期构造后把产物平铺安装到 host,
12036
+ // 平铺名必须与 api 消费面(setRouterRunning / patchDshMain / setRemoteMode 等)逐个一致。
12137
12037
  { name: "domain-actions/router", mod: require_router2(), factory: "createRouterActions" },
12138
12038
  { name: "domain-actions/lan", mod: require_lan2(), factory: "createLanActions" },
12139
12039
  { name: "domain-actions/main", mod: require_main2(), factory: "createMainActions" },
@@ -12706,9 +12606,8 @@ var require_pool2 = __commonJS({
12706
12606
  this._loaded = false;
12707
12607
  }
12708
12608
  /* 来源登记 */
12709
- /** 登记或更新目标的令牌来源,同一目标重复 attach 幂等并保留已推送的 stdout 行。
12710
- * id 为目标标识('main' 或实例 id);src 形如 { kind?, unit?, file? },kind 缺省时按源形态强推断。
12711
- * 返回是否完成登记;kind 完全无法判定时返回 false。 */
12609
+ /** 登记或更新目标的令牌来源,重复 attach 幂等并保留已推送的 stdout 行;kind 缺省时按源形态推断(infer.js)。
12610
+ * kind 必须在 kinds.js 登记(契约1),完全无法判定时返回 false,避免幽灵令牌入池。 */
12712
12611
  attach(id, src) {
12713
12612
  if (!id) return false;
12714
12613
  const s = src || {};
@@ -12739,9 +12638,8 @@ var require_pool2 = __commonJS({
12739
12638
  this.clear(id);
12740
12639
  }
12741
12640
  /* 统一捕获(源无关) */
12742
- /** 主动捕捉一次:按源顺序取“最新一条”URL 行的令牌,有变化则入库并广播。
12743
- *:stdout/文件档同步返回;journal 档**非阻塞**发射(resolve 后照常 _commit+广播),
12744
- * 因为同步 journalctl 在守卫生命周期 tick 里会冻结事件循环最长 5s(心跳停摆)。 */
12641
+ /** 主动捕捉一次:按源优先级取“最新一条”URL 行的令牌,有变化则入库并广播。
12642
+ * stdout/文件档同步返回;journal 档非阻塞发射:同步 journalctl 在生命周期 tick 里会冻结事件循环(见 capture.js)。 */
12745
12643
  capture(id) {
12746
12644
  const src = this._sources.get(id);
12747
12645
  if (!src) return null;
@@ -12813,9 +12711,9 @@ var require_pool2 = __commonJS({
12813
12711
  this.capture(id);
12814
12712
  }
12815
12713
  /* 生命周期 */
12816
- /** 清空某目标的令牌与调度;TK-8:必须广播 null(消费方据此立刻丢弃旧代令牌)。
12817
- * stdout 行缓冲同属旧代状态——不清则 ensureCaptured 下一拍从残留行再“捕获”已死令牌,
12818
- * 以新 gen 追加进恢复文件(回灌死令牌,relay 恒 401)。 */
12714
+ /** 清空某目标的令牌与调度;TK-8:必须广播 null(消费方立刻丢弃旧代令牌)。
12715
+ * stdout 行缓冲同属旧代状态必须一并清:残留行会被 ensureCaptured 再“捕获”,
12716
+ * 以新 gen 把已死令牌回灌进恢复文件。 */
12819
12717
  clear(id) {
12820
12718
  this._cancelSchedule(id);
12821
12719
  this._backfillAt.delete(id);
@@ -12882,7 +12780,6 @@ var require_pool2 = __commonJS({
12882
12780
  const rec = {
12883
12781
  value,
12884
12782
  gen: (prev ? prev.gen : 0) + 1,
12885
- // 每次值变化加一,代号解决无版本问题
12886
12783
  source: source || "unknown",
12887
12784
  at: Date.now(),
12888
12785
  kind: src && src.kind || prev && prev.kind || null
@@ -12899,7 +12796,7 @@ var require_pool2 = __commonJS({
12899
12796
  this._bus.emit(id, rec.value, { value: rec.value, gen: rec.gen, source: rec.source, at: rec.at });
12900
12797
  return value;
12901
12798
  }
12902
- /** 把命中令牌的原文行持久化到恢复文件(统一经 persist:脱敏 + 0600 + 超限轮转)。 */
12799
+ /** 把命中令牌的原文行写入恢复文件(统一经 persist:脱敏 + 0600 + 轮转)。 */
12903
12800
  _persistLine(id, file, line) {
12904
12801
  const r = persist.appendByRotation(file, line, { maxBytes: persist.PERSIST_LIMITS.MAX_BYTES });
12905
12802
  if (!r.ok) this.logger.warn && this.logger.warn("[token] persist file(" + id + ") failed: " + (r.reason || "unknown"));
@@ -12938,7 +12835,6 @@ var require_pool2 = __commonJS({
12938
12835
  this._records.set(e.id, { value: e.value, gen: e.gen, source: e.source, at: e.at, kind: e.kind });
12939
12836
  }
12940
12837
  }
12941
- // 兼容层已移除:TK-4 要求令牌池是唯一事实源,任何指向内部 Map 的旧访问器都会让消费方绕开 get/getRecord,成为各自缓存令牌的温床。
12942
12838
  };
12943
12839
  module2.exports = {
12944
12840
  TokenPool,
@@ -12962,7 +12858,6 @@ var require_token = __commonJS({
12962
12858
  this.events = o.events || null;
12963
12859
  this.pool = new TokenPool({ logger: this.logger, events: this.events, poolFile: o.poolFile || null });
12964
12860
  }
12965
- /* 来源登记 */
12966
12861
  /** 登记源。kind 必填(契约1);缺省时按源形态强推断(见 pool.inferKind)。 */
12967
12862
  attach(id, src) {
12968
12863
  return this.pool.attach(id, src);
@@ -12971,7 +12866,6 @@ var require_token = __commonJS({
12971
12866
  detach(id) {
12972
12867
  return this.pool.detach(id);
12973
12868
  }
12974
- /* 捕捉 */
12975
12869
  /** 主动捕捉一次(journal 源)。返回当前令牌或 null。 */
12976
12870
  capture(id) {
12977
12871
  return this.pool.capture(id);
@@ -12988,7 +12882,6 @@ var require_token = __commonJS({
12988
12882
  ensureCaptured(id) {
12989
12883
  return this.pool.ensureCaptured(id);
12990
12884
  }
12991
- /* 变更 */
12992
12885
  /** 清令牌,广播 null(TK-8)。 */
12993
12886
  clear(id) {
12994
12887
  return this.pool.clear(id);
@@ -13377,11 +13270,8 @@ var require_tasks = __commonJS({
13377
13270
  this._log("info", "task " + task.id + " created (" + kind + "/" + action + " " + task.target.id + ")");
13378
13271
  return task;
13379
13272
  }
13380
- /**
13381
- * 统一作业执行器:提供 begin->start->fn->succeed/fail 的封装(作业体异常自动落 failed)。
13382
- * 内建契约:finally 清 _current 索引;fn 内的任何异常都不再逃逸为 unhandledRejection /
13383
- * 任务永久 running。
13384
- */
13273
+ /** 统一作业执行器:begin->start->fn->succeed/fail 封装,作业体异常一律落 failed;
13274
+ * finally 清 _current 索引,任务绝不永久占用。 */
13385
13275
  async run(kind, targetId, action, opts, fn) {
13386
13276
  if (this.isBusy(kind, targetId)) {
13387
13277
  const cur = this.current(kind, targetId);
@@ -13421,7 +13311,6 @@ var require_tasks = __commonJS({
13421
13311
  const t = this.tasks.find((x) => x.id === id);
13422
13312
  return t && (t.state === "running" || t.state === "pending") ? t : null;
13423
13313
  }
13424
- /** 按 id 查任务。 */
13425
13314
  get(taskId2) {
13426
13315
  return this.tasks.find((t) => t.id === taskId2) || null;
13427
13316
  }
@@ -13435,7 +13324,6 @@ var require_tasks = __commonJS({
13435
13324
  return this.tasks.filter((t) => t.state === "running" || t.state === "pending");
13436
13325
  }
13437
13326
  /* 任务推进 */
13438
- /** 标记任务运行中(从 pending 进入 running;首个 step 前调用)。 */
13439
13327
  start(taskId2) {
13440
13328
  const t = this.get(taskId2);
13441
13329
  if (!t || t.state !== "pending") return null;
@@ -13444,7 +13332,6 @@ var require_tasks = __commonJS({
13444
13332
  this._emit("task_state", { id: taskId2, state: "running" });
13445
13333
  return t;
13446
13334
  }
13447
- /** 添加一个 step(追加到 steps 尾部)。 */
13448
13335
  step(taskId2, name) {
13449
13336
  const t = this.get(taskId2);
13450
13337
  if (!t) return null;
@@ -13453,7 +13340,6 @@ var require_tasks = __commonJS({
13453
13340
  this._save();
13454
13341
  return s;
13455
13342
  }
13456
- /** 推进某 step 状态。 */
13457
13343
  stepState(taskId2, index, state, extra) {
13458
13344
  const t = this.get(taskId2);
13459
13345
  if (!t || !t.steps[index]) return null;
@@ -13468,7 +13354,6 @@ var require_tasks = __commonJS({
13468
13354
  this._emit("task_step", { id: taskId2, index, name: s.name, state });
13469
13355
  return s;
13470
13356
  }
13471
- /** 记录任务日志(有界尾部)。 */
13472
13357
  log(taskId2, line) {
13473
13358
  const t = this.get(taskId2);
13474
13359
  if (!t) return;
@@ -13477,11 +13362,9 @@ var require_tasks = __commonJS({
13477
13362
  if (t.log.length > MAX_LOG_LINES) t.log.splice(0, t.log.length - MAX_LOG_LINES);
13478
13363
  this._save();
13479
13364
  }
13480
- /** 任务成功。 */
13481
13365
  succeed(taskId2, extra) {
13482
13366
  return this._finish(taskId2, "succeeded", null, extra);
13483
13367
  }
13484
- /** 任务失败。 */
13485
13368
  fail(taskId2, error, extra) {
13486
13369
  return this._finish(taskId2, "failed", error, extra);
13487
13370
  }
@@ -13588,7 +13471,7 @@ var require_token_kinds = __commonJS({
13588
13471
  var kinds = require_kinds();
13589
13472
  var pool = require_pool2();
13590
13473
  var KINDS = {
13591
- // 1) 原生 main 会话令牌:DSH 进程自己生成,我方只能捕捉;每次 DSH 重启轮换。
13474
+ // 原生令牌:DSH 进程生成、我方只能捕捉;每次 DSH 重启轮换。main 与实例同策略、仅源不同。
13592
13475
  "dsh-main": {
13593
13476
  side: "dsh",
13594
13477
  strategy: "capture+persist",
@@ -13598,7 +13481,7 @@ var require_token_kinds = __commonJS({
13598
13481
  unitBacked: false,
13599
13482
  desc: "\u539F\u751F main \u4F1A\u8BDD\u4EE4\u724C\uFF08DSH \u8FDB\u7A0B\u751F\u6210\uFF1B\u6355\u6349+\u6301\u4E45\u5316+\u8DDF\u968F\uFF09"
13600
13483
  },
13601
- // 2) 沙箱实例会话令牌:与 main 同策略、只是源不同(systemd 单元 journald)。
13484
+ // 沙箱实例会话令牌:源为 systemd 单元 journald。
13602
13485
  "dsh-instance": {
13603
13486
  side: "dsh",
13604
13487
  strategy: "capture+persist",
@@ -13608,8 +13491,8 @@ var require_token_kinds = __commonJS({
13608
13491
  unitBacked: true,
13609
13492
  desc: "\u6C99\u7BB1\u5B9E\u4F8B\u4F1A\u8BDD\u4EE4\u724C\uFF08DSH \u8FDB\u7A0B\u751F\u6210\uFF1B\u6E90\u4E3A dsh-web@<id> \u5355\u5143\uFF09"
13610
13493
  },
13611
- // 3) 浏览器会话 cookie:由 1/2 经 HTTP 303 换取,随 dshToken 轮换重换。
13612
- // 刻意为 persistent:false —— cookie 是**派生缓存**,落盘等于多一份会话凭据副本。
13494
+ // 浏览器会话 cookie:由上面两种经 HTTP 303 换取,随 dshToken 轮换重换。
13495
+ // 刻意为 persistent:false —— cookie 是派生缓存,落盘等于多一份会话凭据副本。
13613
13496
  "dsh-auth": {
13614
13497
  side: "dsh-derived",
13615
13498
  strategy: "exchange",
@@ -13619,7 +13502,7 @@ var require_token_kinds = __commonJS({
13619
13502
  unitBacked: false,
13620
13503
  desc: "\u6D4F\u89C8\u5668\u4F1A\u8BDD cookie\uFF08dsh-auth-*\uFF0C\u7531 dsh-main/dsh-instance \u6362\u53D6\uFF1B\u53EA\u5B58\u8FDB\u7A0B\u5185\u5B58\uFF09"
13621
13504
  },
13622
- // 4-6) 用户配置类:不是 DSH 令牌。不捕捉、不进令牌池展示、不随 DSH 轮换。
13505
+ // 用户配置类:不是 DSH 令牌。不捕捉、不进令牌池展示、不随 DSH 轮换。
13623
13506
  "remote-token": {
13624
13507
  side: "user",
13625
13508
  strategy: "config",
@@ -13647,7 +13530,7 @@ var require_token_kinds = __commonJS({
13647
13530
  unitBacked: false,
13648
13531
  desc: "FRP \u8BA4\u8BC1\u4EE4\u724C\uFF08\u7528\u6237\u5728 UI \u586B\u5199\uFF0C\u900F\u4F20\u7ED9 frpc\uFF09"
13649
13532
  },
13650
- // 7) 我方签发的门卫会话 cookie。
13533
+ // 我方签发的门卫会话 cookie。
13651
13534
  "lan-gate": {
13652
13535
  side: "self",
13653
13536
  strategy: "issue+verify",
@@ -13819,7 +13702,7 @@ var require_core5 = __commonJS({
13819
13702
  registryFile: path2.join(swDir, "registry.json"),
13820
13703
  events: host2.events,
13821
13704
  logger: host2.logger,
13822
- // 灰度名单事实:本机配置 canary:true。仅对 @dsh-sup/* 生效。
13705
+ // 灰度事实由本机配置注入(canary:true);仅 @dsh-sup/* 包消费该开关。
13823
13706
  canary: host2.config.canary === true
13824
13707
  });
13825
13708
  host2.shellDomain = shellDomain;
@@ -13840,7 +13723,7 @@ var require_port_segments = __commonJS({
13840
13723
  var ports = require_ports();
13841
13724
  var POOLS = {
13842
13725
  providerApi: { base: 24e3, count: 2e3 }
13843
- // 智能路由每供应商独立 API 端点(24000-25999,可容 2000 供应商)
13726
+ // 每供应商独立 API 端点段(24000-25999)
13844
13727
  };
13845
13728
  var SEGMENTS = {
13846
13729
  proxyInstance: { pool: "managed", anchor: 1e3 },
@@ -13966,7 +13849,6 @@ var require_store3 = __commonJS({
13966
13849
  canPersist() {
13967
13850
  return this._canPersist ? this._canPersist() !== false : true;
13968
13851
  }
13969
- /** 触发一次落盘(经统一写权闸)。 */
13970
13852
  persist() {
13971
13853
  if (!this._persistFn) return;
13972
13854
  if (!this.canPersist()) return;
@@ -14399,12 +14281,9 @@ var require_base = __commonJS({
14399
14281
  async detectAccount(acc) {
14400
14282
  throw new Error("detectAccount must be implemented by subclass");
14401
14283
  }
14402
- // 能力契约声明(PG-1)。process-pool 能力面(startInstance/stopInstance/restartInstance/
14403
- // _waitHealthy/instanceOf/ensureServable/reclaimAccount/markRequestOk/markInstanceNetFail/
14404
- // _retryPendingStop/flushRestartPending/reconcileInstances 及其 this 图所需的
14405
- // accountOf/markInstanceProblem/_doStart)
14406
- // 由 providers/process-pool.js 的 mixin 实现并并入 supports 词表——契约在能力方声明,
14407
- // 基座不再携带实现不了的抛错占位;调用方一律以 supports(cap) 守卫。
14284
+ // 能力契约声明(PG-1):process-pool 能力面由 providers/process-pool.js 的 mixin 实现并
14285
+ // 并入 supports 词表——契约在能力方声明,基座不携带实现不了的抛错占位;
14286
+ // 调用方一律以 supports(cap) 守卫。
14408
14287
  /** 本 provider 是否具备某项能力;缺省为无 process 能力(最保守)。 */
14409
14288
  supports(_cap) {
14410
14289
  return false;
@@ -14460,7 +14339,7 @@ var require_base = __commonJS({
14460
14339
  classifyResponse(status, headers, bodyText) {
14461
14340
  return quota.classifyUpstreamLimited(status, bodyText);
14462
14341
  }
14463
- /** 账号处置副作用(M3 契约):router 只发 signal,具体冻结/停实例/封号由 provider 执行。 */
14342
+ /** 账号处置副作用契约:router 只发 signal,具体冻结/停实例/封号由 provider 执行。 */
14464
14343
  effect(signal, acc, ctx) {
14465
14344
  const c = ctx || {};
14466
14345
  if (signal === "credits") {
@@ -14477,7 +14356,7 @@ var require_base = __commonJS({
14477
14356
  }
14478
14357
  return false;
14479
14358
  }
14480
- /** 唯一「时间窗额度用尽」判定(M4)。 */
14359
+ /** 唯一「时间窗额度用尽」判定。 */
14481
14360
  _windowExhausted(acc) {
14482
14361
  return quota.windowExhausted(acc);
14483
14362
  }
@@ -14487,7 +14366,7 @@ var require_base = __commonJS({
14487
14366
  _creditsRefilled(acc) {
14488
14367
  return quota.creditsRefilled(acc);
14489
14368
  }
14490
- /** 账号可用性判定(唯一事实,M4):ready 且未「预付余额不足」且窗口未满。 */
14369
+ /** 账号可用性判定(唯一事实):ready 且未「预付余额不足」且窗口未满。 */
14491
14370
  isAccountUsable(acc, opts) {
14492
14371
  if (!acc || acc.status !== "ready") return false;
14493
14372
  if (this._isCreditsLow(acc)) return false;
@@ -14501,7 +14380,7 @@ var require_base = __commonJS({
14501
14380
  _ensureLimit(acc) {
14502
14381
  return freeze.ensureLimit(acc);
14503
14382
  }
14504
- /** limit 纯只读预览(#20;不赋值、不写盘):只读视图唯一入口。写版 _ensureLimit 保留(门禁/测试消费)。 */
14383
+ /** limit 纯只读预览(不赋值、不写盘):只读视图唯一入口。写版 _ensureLimit 保留(门禁/测试消费)。 */
14505
14384
  _previewLimit(acc) {
14506
14385
  return freeze.previewLimit(acc);
14507
14386
  }
@@ -14520,7 +14399,7 @@ var require_base = __commonJS({
14520
14399
  markBanned(acc, error) {
14521
14400
  return freeze.markBanned(acc, error, this);
14522
14401
  }
14523
- // 状态投影完成处补齐 limit(写版 ensureLimit 从只读视图移到此)。唯一投影入口,覆盖全部 applyDetection 调用方。
14402
+ // applyDetection 是唯一状态投影入口(覆盖全部调用方):投影完成后补齐 limit(写版 ensureLimit)。
14524
14403
  applyDetection(acc, det) {
14525
14404
  const r = freeze.applyDetection(acc, det, this);
14526
14405
  freeze.ensureLimit(acc);
@@ -14715,7 +14594,7 @@ var require_direct = __commonJS({
14715
14594
  this.presetId = opts.presetId || null;
14716
14595
  this.officialPricing = {};
14717
14596
  }
14718
- /** 能力声明:key-pool 无实例能力。显式声明「不支持」,使转发层不再靠 typeof 猜测,差异可静态校验。 */
14597
+ /** 能力声明:key-pool 无实例能力,显式声明「不支持」供调用方 supports() 守卫,差异可静态校验。 */
14719
14598
  supports(_cap) {
14720
14599
  return false;
14721
14600
  }
@@ -14798,15 +14677,13 @@ var require_model2 = __commonJS({
14798
14677
  toJSON() {
14799
14678
  return serializeInstance(this);
14800
14679
  }
14801
- /** 实例是否可立即服务(切换策略唯一需要问的问题,见双预算切换)。 */
14680
+ /** 实例是否可立即服务(切换策略唯一需要问的问题)。 */
14802
14681
  isServable() {
14803
14682
  return isServable(this);
14804
14683
  }
14805
- /** 实例是否占用资源(WARM/HOT/DEAD 都有进程)。 */
14806
14684
  occupiesSlot() {
14807
14685
  return occupiesSlot(this);
14808
14686
  }
14809
- /** 反序列化:进程态(pid)不落盘 -> 一律回到 COLD,由 reconcile 按期望集重新拉起。 */
14810
14687
  static fromJSON(o) {
14811
14688
  return deserializeInstance(o);
14812
14689
  }
@@ -15727,11 +15604,10 @@ var require_process_pool = __commonJS({
15727
15604
  }
15728
15605
  };
15729
15606
  }
15730
- /** 能力声明 = 基座能力与 process-pool 能力的并集。 */
15731
15607
  supports(cap) {
15732
15608
  return POOL_CAPS.includes(cap) || super.supports(cap);
15733
15609
  }
15734
- /** 使用状态在基座(in-use/idle)上派生 warming:实例在场是池能力,覆写归 mixin。 */
15610
+ /** 实例在场是池能力:在基座使用状态(in-use/idle)上覆写派生 warming。 */
15735
15611
  usageOf(acc) {
15736
15612
  const r = super.usageOf(acc);
15737
15613
  if (r !== "idle") return r;
@@ -15741,7 +15617,7 @@ var require_process_pool = __commonJS({
15741
15617
  accountOf(inst) {
15742
15618
  return this.accounts.find((a) => a.key === inst.key) || null;
15743
15619
  }
15744
- /** 账号 -> 实例映射(一账号一实例):usageOf 派生 warming 的依据。 */
15620
+ /** 账号 -> 实例映射(一账号一实例硬规则)。 */
15745
15621
  instanceOf(acc) {
15746
15622
  if (!acc) return null;
15747
15623
  return (this.instances || []).find((i) => i.keyId === acc.keyId) || acc.instance || null;
@@ -15769,19 +15645,17 @@ var require_process_pool = __commonJS({
15769
15645
  })();
15770
15646
  return inst.startingPromise;
15771
15647
  }
15772
- /** 启动实例底层治理(spawn/探活在 probe.js)。方法在能力面上保持原型可覆写,
15773
- * 测试以 _doStart 打桩替换 spawn;留在 mixin 侧是为了 this 图单向(mixin 不回调消费方方法)。 */
15648
+ /** 启动实例底层治理(spawn/探活在 probe.js)。测试以 _doStart 打桩替换 spawn;留在 mixin 侧是为 this 图单向。 */
15774
15649
  async _doStart(inst) {
15775
15650
  return probe.spawnInstance(this, inst);
15776
15651
  }
15777
- /** 请求成功后清零失败计数(时机是熔断可达的全部要害)。不触碰健康监测的 _monitorFails。 */
15652
+ /** 请求级熔断计数清零;独立于健康监测的 _monitorFails。 */
15778
15653
  markRequestOk(inst) {
15779
15654
  if (!inst) return;
15780
15655
  inst._unhealthyCount = 0;
15781
15656
  }
15782
- /** 统一可服务化门面(LC 核心-1:请求路径/显式切换经此驱动进程,不裸调 start/kill):
15783
- * 幂等启动(startingPromise 去重)+ 预算内同步等待。opts.budgetMs=null 表示等满探活周期
15784
- * (显式切换的启动预算,裁决 1:超时诚实报错,绝不静默换号)。 */
15657
+ /** 统一可服务化门面(LC 核心-1):幂等启动 + 预算内同步等待,外部不裸调 start/kill。
15658
+ * budgetMs=null 表示等满探活周期(显式切换预算);超时诚实报错,绝不静默换号。 */
15785
15659
  async ensureServable(acc, opts) {
15786
15660
  const inst = this.instanceOf(acc);
15787
15661
  if (!inst) return { ok: false, error: "\u5B9E\u4F8B\u4E0D\u5B58\u5728" };
@@ -15795,12 +15669,12 @@ var require_process_pool = __commonJS({
15795
15669
  return { ok: false, warming: !!inst.pid, error: "\u5B9E\u4F8B\u672A\u5728\u7B49\u5F85\u671F\u5185\u5C31\u7EEA" };
15796
15670
  }
15797
15671
  /** 等待区回收唯一入口(LC 核心-3):force 终止 + 释放端口,账号进程层面同一轮零存在。
15798
- * 丢弃在途属预期语义——发不出请求的账号不该继续占进程(裁决:冻结零宽限)。幂等。 */
15672
+ * 冻结零宽限:发不出请求的账号不该继续占进程;丢弃在途属预期语义。幂等。 */
15799
15673
  reclaimAccount(acc) {
15800
15674
  return life.reclaimAccount(this, acc);
15801
15675
  }
15802
- /** 状态迁移事件表接线(freeze.js setStatus 回调):进入等待区(frozen/banned/discarded)
15803
- * 立即回收;恢复回可用池(status 回到 ready)立即重算期望集补缺口(LC 核心-5,不等周期对账的运气)。 */
15676
+ /** 状态迁移事件表的进程侧接线(freeze.js setStatus 调用):进等待区立即回收;
15677
+ * 回 ready 立即重算期望集补缺口(LC 核心-5),不等周期对账。 */
15804
15678
  _onStatusTransition(acc, prev, status) {
15805
15679
  if (status === "frozen" || status === "banned" || status === "discarded") {
15806
15680
  try {
@@ -15811,11 +15685,10 @@ var require_process_pool = __commonJS({
15811
15685
  this.reconcileNow();
15812
15686
  }
15813
15687
  }
15814
- /** 实例停止(幂等):在途/在用 -> 标记待停;force 跳过仲裁(委托 instance-lifecycle.js)。 */
15688
+ /** 实例停止仲裁(在途/在用延后、force 跳过的语义在 instance-lifecycle.js)。 */
15815
15689
  stopInstance(inst, force) {
15816
15690
  return life.arbitrateStop(this, inst, force);
15817
15691
  }
15818
- /** 请求结束补刀(委托 instance-lifecycle.js)。 */
15819
15692
  _retryPendingStop(acc) {
15820
15693
  return life.retryPendingStop(this, acc);
15821
15694
  }
@@ -15874,11 +15747,11 @@ var require_process_pool = __commonJS({
15874
15747
  } catch {
15875
15748
  }
15876
15749
  }
15877
- /** 兼容旧名(保持对外调用不破)。 */
15750
+ /** 兼容旧名别名。 */
15878
15751
  markInstanceNetFail(instOrAcc) {
15879
15752
  this.markInstanceProblem(instOrAcc, "net-error");
15880
15753
  }
15881
- /** 实例空闲后补做「被延后的重启」(_restartPending 的消费点,不再只写不读)。 */
15754
+ /** 实例空闲后补做被延后的重启(_restartPending 的唯一消费点)。 */
15882
15755
  flushRestartPending(inst) {
15883
15756
  if (!inst || !inst._restartPending) return;
15884
15757
  const acc = this.accountOf(inst);
@@ -15976,7 +15849,6 @@ var require_proxy = __commonJS({
15976
15849
  this._stopping = false;
15977
15850
  this._terminatingPids = /* @__PURE__ */ new Set();
15978
15851
  }
15979
- /** 能力声明:基座与 process-pool 的并集在 withProcessPool mixin 完成(process-pool.js)。 */
15980
15852
  async ensureInstance(key) {
15981
15853
  let inst = this.instances.find((i) => i.key === key);
15982
15854
  if (inst) return inst;
@@ -15984,7 +15856,7 @@ var require_proxy = __commonJS({
15984
15856
  this.instances.push(inst);
15985
15857
  return inst;
15986
15858
  }
15987
- /** 解析启动命令(缓存优先 + fallback npx):纯拼装委托 command.js,凭证剔除留在本层(纪律)。 */
15859
+ /** 解析启动命令(缓存优先 + fallback npx):拼装委托 command.js;凭证剔除留在本层(纪律)。 */
15988
15860
  async _resolveLaunchCommand(app, port, key) {
15989
15861
  const registry = this.dist ? await this.dist.selectRegistry(false).catch(() => null) : null;
15990
15862
  const cachedBin = this._cachedPkgBin(app.pkg);
@@ -16008,23 +15880,18 @@ var require_proxy = __commonJS({
16008
15880
  _ensurePkgCached(app) {
16009
15881
  return probe.ensurePkgCached(this, app);
16010
15882
  }
16011
- /** 实例停止仲裁(委托 instance-lifecycle.js)。 */
16012
15883
  _canStopInstance(acc) {
16013
15884
  return life.canStopInstance(this, acc);
16014
15885
  }
16015
- /** 等待全部 SIGTERM 在途子进程真正退出(实现与 zombie 判定在 probe.js)。 */
16016
15886
  async waitAllStopped(timeoutMs) {
16017
15887
  return probe.waitAllStopped(this, timeoutMs);
16018
15888
  }
16019
- /** 实例探活(探活实现与计数分层在 probe.js,计数各归其主)。 */
16020
15889
  async healthInstance(inst) {
16021
15890
  return probe.healthInstance(this, inst);
16022
15891
  }
16023
- /** 实例生命周期监控(进程/端口/HTTP 卡死检测)。 */
16024
15892
  async monitorLifecycle() {
16025
15893
  return probe.monitorLifecycle(this);
16026
15894
  }
16027
- /** 模式级配额检测(策略注册与解析在 probe.js + quota-strategies.js)。 */
16028
15895
  async detectInstanceQuota(inst) {
16029
15896
  return probe.detectInstanceQuota(this, inst);
16030
15897
  }
@@ -16034,14 +15901,14 @@ var require_proxy = __commonJS({
16034
15901
  isAccountUsable(acc, opts) {
16035
15902
  return life.isAccountUsable(this, acc, opts);
16036
15903
  }
16037
- /** 429/403 配额触发冻结:立即回收进等待区(force + 释放端口,零宽限),再状态机,再对账补槽。 */
15904
+ /** 429/403 配额冻结:先立即回收进等待区(force + 释放端口,零宽限),再状态机,再对账补槽。 */
16038
15905
  markQuotaExhausted(acc, cooldownMs) {
16039
15906
  this.reclaimAccount(acc);
16040
15907
  super.markQuotaExhausted(acc, cooldownMs);
16041
15908
  this.reconcileNow();
16042
15909
  this._probeAfterResponseFreeze(acc);
16043
15910
  }
16044
- /** credits 余额不足:与窗口同一处置(立即回收 + 冻结 + 对账补槽)。 */
15911
+ /** credits 余额不足:与窗口同一处置(回收 + 冻结 + 补槽)。 */
16045
15912
  markCreditsExhausted(acc) {
16046
15913
  this.reclaimAccount(acc);
16047
15914
  super.markCreditsExhausted(acc);
@@ -16072,7 +15939,7 @@ var require_proxy = __commonJS({
16072
15939
  reconcileNow() {
16073
15940
  return restart.reconcileNow(this);
16074
15941
  }
16075
- /** 封号:立即回收进等待区,再更新状态机。 */
15942
+ /** 封号:与配额冻结同一处置(先回收再走状态机)。 */
16076
15943
  markBanned(acc, error) {
16077
15944
  this.reclaimAccount(acc);
16078
15945
  super.markBanned(acc, error);
@@ -16185,8 +16052,7 @@ var require_switch2 = __commonJS({
16185
16052
  this.events = opts.events || null;
16186
16053
  this.onPersist = opts.onPersist || null;
16187
16054
  }
16188
- /** 在指定供应商的账号池内选择(供应商独立端点语义):绝不跨供应商 failover,本池无可用返回 null。
16189
- * opts.excludeKeys=Set 时把本请求内瞬时故障(5xx/net-error)账号直接排除,强制轮换不粘滞。 */
16055
+ /** 在指定供应商池内选号(不跨池,见文件头)。opts.excludeKeys=Set 时排除本请求内瞬时故障账号,强制轮换不粘滞。 */
16190
16056
  pickFor(provider, opts) {
16191
16057
  if (!provider) return null;
16192
16058
  return this._pickIn(provider, opts);
@@ -16223,11 +16089,8 @@ var require_switch2 = __commonJS({
16223
16089
  if (this.events) this.events.append("router_pick", { provider: p.name, key: picked.maskedKey });
16224
16090
  return picked;
16225
16091
  }
16226
- /** 上游失败反应(唯一编排点)。ctx = { status, headers, body, attempt, attempts, error? }:
16227
- * 1) provider.classifyResponse 给出 signal;
16228
- * 2) provider.effect 执行账号副作用(credits/window 冻结,proxy 会停实例并预热;banned 封号);
16229
- * 3) 返回 action:'retry'(credits/window/transient,带 transient 标记供调用方定退避)或
16230
- * 'passthrough'(banned/none/unknown 原样回状态/头/体,绝不误切)。 */
16092
+ /** 上游失败反应(唯一编排点)。ctx = { status, headers, body, attempt, attempts, error? };
16093
+ * action/retry 语义见 policies/failure.js decideFailure 契约。 */
16231
16094
  reactToFailure(provider, acc, ctx) {
16232
16095
  const c = ctx || {};
16233
16096
  const status = c.status;
@@ -16296,7 +16159,7 @@ var require_store4 = __commonJS({
16296
16159
  canPersist() {
16297
16160
  return this._writable !== false && this.loadedOk === true;
16298
16161
  }
16299
- /** L3:设置状态文件写开关(true=本实例写;false=只读,由外部 router-daemon 独占写)。 */
16162
+ /** 设置状态文件写开关(true=本实例写;false=只读,由外部 router-daemon 独占写)。 */
16300
16163
  setPersistEnabled(v) {
16301
16164
  this._writable = v !== false;
16302
16165
  }
@@ -16361,8 +16224,7 @@ var require_store4 = __commonJS({
16361
16224
  key: a.key || null,
16362
16225
  keyId: a.keyId,
16363
16226
  maskedKey: a.maskedKey,
16364
- // 单事实源:只读 status;
16365
- // usage 不反序列化(纯派生,由 usageOf 从 activeAccount/实例实况算)。
16227
+ // 单事实源:只读 status;usage 不反序列化(纯派生,由 usageOf 计算)。
16366
16228
  status: a.status || a.validity || "registered",
16367
16229
  quota: a.quota || null,
16368
16230
  registeredAt: a.registeredAt || Date.now(),
@@ -16398,32 +16260,27 @@ var require_proxy_apps = __commonJS({
16398
16260
  id: "commandcode",
16399
16261
  name: "Command Code Proxy",
16400
16262
  pkg: "commandcode-api-proxy",
16401
- // 官方运行方式(npx 一键)—— 完整独立发行版
16402
16263
  command: ["npx", "--yes", "commandcode-api-proxy", "--host", "127.0.0.1", "--port", "{{port}}", "--api-key", "{{key}}"],
16403
16264
  healthPath: "/health",
16404
16265
  modelPath: "/v1/models",
16405
16266
  upstream: "https://api.commandcode.ai",
16406
- // 实例环境契约:keyEnv=账号密钥注入的 env 名(只经 env 传递,绝不进 cmdline);app.env/超时等
16407
- // 一律不注入,commandcode-api-proxy 跑完全默认配置(idle 120s / upstream 600s,作者设计值)——
16408
- // 加 CC_IDLE_TIMEOUT_MS=0 等自我干预曾导致回归,故保持纯净注入。
16267
+ // 实例环境契约:keyEnv 是密钥注入的唯一 env 名(绝不进 cmdline);app.env/超时等一律不注入,
16268
+ // 跑上游完全默认配置(作者设计值)——自我干预(如 CC_IDLE_TIMEOUT_MS=0)曾导致回归,保持纯净注入。
16409
16269
  keyEnv: "CC_API_KEY",
16410
16270
  repo: "thaolaptrinh/commandcode-api-proxy",
16411
16271
  // 自动更新:最新版本从 npm registry 查(同一 package 名)。空则跳过版本检查。
16412
16272
  registry: "commandcode-api-proxy",
16413
16273
  versionRefreshMs: 6 * 3600 * 1e3,
16414
- // 默认 6h 查一次 npm
16415
- // 每账号配额来源:Command Code 官方 /alpha/billing/credits(Bearer 各账号 key;窗口 5h/weekly +
16416
- // credits 池,无 period 字段),以及 /alpha/billing/subscriptions 的 currentPeriodEnd(月额度随订阅
16417
- // 续期重置的精确时刻;仅 credits-limited 账号按 6h 缓存低频取,防风控)。
16418
- // windowMap: rolling=5h、weekly=周;monthly 由订阅面推导(见 quota-strategies 的 monthlyCapUsd)。
16274
+ // 每账号配额来源:官方 billing 面(解析逻辑见 quota-strategies.js detectCommandCodeBilling)。
16275
+ // windowMap 指 rolling/weekly 字段;monthly 由订阅面推导。
16419
16276
  quota: {
16420
16277
  type: "commandcode-billing",
16421
16278
  apiBase: "https://api.commandcode.ai",
16422
16279
  creditsPath: "/alpha/billing/credits",
16423
16280
  subscriptionsPath: "/alpha/billing/subscriptions",
16424
16281
  windowMap: { rolling: "fiveHour", weekly: "weekly", monthly: null },
16425
- // 月度配额上限($/月):Command 订阅含 $10/月总配额池,周窗口从池内扣(weekly.used +
16426
- // monthlyCredits.remaining = 10),解析层据此推导 monthly.percent,前端每月格子显示真实百分比。
16282
+ // 月度配额上限($/月):订阅含 $10/月总池,周窗口从池内扣(weekly.used + monthlyRemaining = 10),
16283
+ // 解析层据此推导 monthly.percent。
16427
16284
  monthlyCapUsd: 10
16428
16285
  },
16429
16286
  real: true
@@ -17053,11 +16910,8 @@ var require_usage = __commonJS({
17053
16910
  this._timer = null;
17054
16911
  this._dirty = false;
17055
16912
  }
17056
- /** 归一 model 键:E-4 单源字符集闸(platform/util/input.ledgerKey)。
17057
- * 旧实现只做「字符串化 + 截断」,于是客户端 body 里的 model 名可以就是
17058
- * `__proto__` / `constructor` —— `t.byModel[key] = {...}` 走的是原型赋值,
17059
- * 账本静默失真且污染面在 Object.prototype 上(空白/控制符键同理,面板也没法看)。
17060
- * 违规值**折进 (other) 桶**而不是丢弃:B19 的上限语义与「不丢计数」都保持不变。 */
16913
+ /** model 键归一走 platform/util/input.ledgerKey(外部输入字符集单源闸):
16914
+ * __proto__/constructor/空白/控制符等违规值折进 (other) 桶——不丢计数,也不做对象键(防原型污染)。 */
17061
16915
  _modelKey(model) {
17062
16916
  return input.ledgerKey(model, { max: 128, empty: "unknown", unsafe: "(other)" });
17063
16917
  }
@@ -17074,7 +16928,6 @@ var require_usage = __commonJS({
17074
16928
  }
17075
16929
  return bm;
17076
16930
  }
17077
- /** 记账:累计总量 + byModel + byKey,按快照单价估算费用,节流落盘。 */
17078
16931
  recordUsage(entry) {
17079
16932
  const t = this.load();
17080
16933
  t.requests += 1;
@@ -17104,14 +16957,13 @@ var require_usage = __commonJS({
17104
16957
  if (this.events) this.events.append("router_usage", { model: entry.model, tokens: entry.totalTokens });
17105
16958
  return t;
17106
16959
  }
17107
- /** 错误计数(持久化)。 */
17108
16960
  recordError() {
17109
16961
  const t = this.load();
17110
16962
  t.errors = (t.errors || 0) + 1;
17111
16963
  this._scheduleWrite();
17112
16964
  return t.errors;
17113
16965
  }
17114
- /** 脏标记 + 尾部定时器合并落盘(delay=0 时保持每调用同步写,兼容既有测试语义)。 */
16966
+ /** 脏标记 + 尾部定时器合并落盘;delay=0 时每调用同步写(兼容既有测试语义)。 */
17115
16967
  _scheduleWrite() {
17116
16968
  this._dirty = true;
17117
16969
  if (this._writeDelayMs <= 0) return this._writeTotals();
@@ -17131,9 +16983,8 @@ var require_usage = __commonJS({
17131
16983
  if (!this._dirty) return;
17132
16984
  this._writeTotals();
17133
16985
  }
17134
- /** 读盘。读源纪律:写者以内存为准(节流窗口内盘落后于内存,重读会丢在途账);
17135
- * 只读实例(守卫/内嵌,无写权)从不记账,盘上是别人的活账,必须每次新鲜读盘——
17136
- * 永久缓存会让面板冻结在进程启动时的旧快照。兼容旧格式补默认字段,防 undefined 崩溃。 */
16986
+ /** 读源纪律:写者以内存为准(节流窗口内盘落后于内存,重读丢在途账);
16987
+ * 只读实例(无写权)从不记账、盘上是别人的活账,必须每次新鲜读盘——永久缓存会冻结面板。 */
17137
16988
  load() {
17138
16989
  if (this.totals && this._canPersist()) return this.totals;
17139
16990
  let t;
@@ -17145,13 +16996,12 @@ var require_usage = __commonJS({
17145
16996
  this.totals = defaults(t);
17146
16997
  return this.totals;
17147
16998
  }
17148
- /** 汇总视图(byModel 取 token 前 12)。 */
17149
16999
  getUsage() {
17150
17000
  const t = this.load();
17151
17001
  const byModel = Object.entries(t.byModel || {}).map(([model, v]) => ({ model, ...v })).sort((a, b) => b.totalTokens - a.totalTokens).slice(0, 12);
17152
17002
  return { requests: t.requests, promptTokens: t.promptTokens, completionTokens: t.completionTokens, totalTokens: t.totalTokens, costUsd: t.costUsd, errors: t.errors || 0, byModel, byKey: t.byKey || {} };
17153
17003
  }
17154
- /** 原子落盘(tmp+rename 防崩溃/断电损坏高频用量文件);写权单闸。 */
17004
+ /** 原子落盘:tmp+rename 防崩溃/断电损坏高频用量文件;写权单闸。 */
17155
17005
  _writeTotals() {
17156
17006
  try {
17157
17007
  if (typeof this._canPersist === "function" && !this._canPersist()) return;
@@ -17183,13 +17033,10 @@ var require_inflight = __commonJS({
17183
17033
  acc.inflight = (acc.inflight || 0) + 1;
17184
17034
  return acc.inflight;
17185
17035
  },
17186
- /**
17187
- * 唯一在途递减入口。
17188
- * @param {object} acc 账号(在途计数挂在账号对象上)
17189
- * @param {{prov?:object, inst?:object, lifecycle?:boolean}} [ctx]
17190
- * @returns {{ zero:boolean, effects:Array<{kind:string,acc:object,prov:object,inst:object}> }}
17191
- * effects 仅为**描述**,由调用方执行——两条结束路径共用此结果。
17192
- */
17036
+ /** 唯一在途递减入口。@param {object} acc 账号(在途计数挂在账号对象上)
17037
+ * @param {{prov?:object, inst?:object, lifecycle?:boolean}} [ctx]
17038
+ * @returns {{ zero:boolean, effects:Array<{kind:string,acc:object,prov:object,inst:object}> }}
17039
+ * effects 仅为描述,由调用方在所有结束路径统一执行。 */
17193
17040
  end(acc, ctx) {
17194
17041
  if (!acc) return { zero: false, effects: [] };
17195
17042
  ended += 1;
@@ -18090,7 +17937,7 @@ var require_views = __commonJS({
18090
17937
  });
18091
17938
  return {
18092
17939
  running: state.running === true,
18093
- // 中转服务逻辑开关(无公用入口;启用即提供已激活供应商的独立端点)
17940
+ // 服务运行标志(由 RouterService start/stop 翻转,不在 ctl 方法白名单内)
18094
17941
  activatedProviders: (state.providers || []).filter((x) => x.activated).length,
18095
17942
  // 已激活供应商数(独立端点在线数)
18096
17943
  providers: provs,
@@ -18142,14 +17989,13 @@ var require_views = __commonJS({
18142
17989
  keyId: a.keyId,
18143
17990
  maskedKey: a.maskedKey,
18144
17991
  status: a.status,
18145
- // 单事实源
18146
17992
  validity: a.status,
18147
17993
  // 兼容字段(=status,避免旧前端读 undefined)
18148
17994
  usage: usageOf,
18149
17995
  // 纯派生(activeAccount/实例实况)
18150
17996
  quota: a.quota || null,
18151
17997
  limit: (p._previewLimit ? p._previewLimit(a) : a.limit) || null,
18152
- // limitKind+recovery(#20 纯只读预览,无写副作用)
17998
+ // limitKind+recovery(只读预览,无写副作用)
18153
17999
  nextResetAt: a.nextResetAt || null,
18154
18000
  registeredAt: a.registeredAt,
18155
18001
  detectError: a.detectError || null,
@@ -18964,7 +18810,6 @@ var require_router3 = __commonJS({
18964
18810
  _startActivatedProviders() {
18965
18811
  return this._endpoint.startActivatedProviders();
18966
18812
  }
18967
- /* Q9 转发 */
18968
18813
  proxyFor(prov, req, res) {
18969
18814
  return this._forward.proxyFor(prov, req, res);
18970
18815
  }
@@ -18977,7 +18822,7 @@ var require_router3 = __commonJS({
18977
18822
  recordError() {
18978
18823
  return this._forward.recordError();
18979
18824
  }
18980
- /* Q7 注册表 + Q12 生命周期 */
18825
+ /* 注册表 + 生命周期 */
18981
18826
  addDirectProvider(o) {
18982
18827
  return this._ops.addDirectProvider(o);
18983
18828
  }
@@ -18999,7 +18844,7 @@ var require_router3 = __commonJS({
18999
18844
  stopAllInstances() {
19000
18845
  return this._ops.stopAllInstances();
19001
18846
  }
19002
- /* Q10/Q11 调度 */
18847
+ /* 调度 */
19003
18848
  _startMaintenance() {
19004
18849
  return this._scheduler.start();
19005
18850
  }
@@ -19400,7 +19245,6 @@ var require_model3 = __commonJS({
19400
19245
  id,
19401
19246
  name: String(payload.name || "\u5B9E\u4F8B:" + port).slice(0, 40),
19402
19247
  port,
19403
- // 新增实例:默认沙箱域(绝对隔离、与原生/彼此互不干扰)
19404
19248
  domain: "sandbox",
19405
19249
  kind: "sandbox",
19406
19250
  autoRegistered: false,
@@ -19415,7 +19259,7 @@ var require_model3 = __commonJS({
19415
19259
  privateTmp: true,
19416
19260
  // node/dsh 位于 /home(nvm),ProtectHome=yes 会使其 exec 失败(203/EXEC);默认关闭,可用 payload.protectHome 覆盖
19417
19261
  protectHome: payload.protectHome === void 0 ? false : !!payload.protectHome
19418
- // 资源配额不接收户输入:启动时由 governor 按机器预算与活跃实例数推导(见 ARCHITECTURE-PLAN-instance-sandbox-governor)。
19262
+ // 资源配额不接收户输入:启动时由 governor 按机器预算与活跃实例数推导。
19419
19263
  },
19420
19264
  state: { phase: "STOPPED", restartCount: 0, backoffLevel: 0, lastProbeOk: null },
19421
19265
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -19509,16 +19353,13 @@ var require_store5 = __commonJS({
19509
19353
  this.syncPorts();
19510
19354
  return this.instances;
19511
19355
  }
19512
- /** 清历史遗留的未声明 state 字段。**只在内存删、本方法不写盘**;下次 save(5s tick 或任意内容变化)
19513
- * 由 save() 全量序列化内存数组而自然落地,故幂等:文件既已无该键,再 load 即无键可删。
19514
- * state.version:阶段五已停止写入(upgrade.js 的两处赋值删除),且内核/测试/壳仓**零消费者**、
19515
- * createRecord 声明的 state 形状不含它(version 显示走 readInstalledVersion 实时读盘)。
19516
- * 同型先例:model.normalizeInstance 同样在加载期删遗留键 dshToken(有测试断言该行为)。 */
19356
+ /** 清历史遗留的未声明 state 字段。只在内存删、本方法不写盘;下次 save() 全量序列化自然落地,故幂等。
19357
+ * state.version:内核/测试/壳仓零消费者,版本显示走 readInstalledVersion 实时读盘,已从记录形状声明中移除。 */
19517
19358
  _stripLegacyStateKeys(inst) {
19518
19359
  if (inst.state && Object.prototype.hasOwnProperty.call(inst.state, "version")) delete inst.state.version;
19519
19360
  }
19520
- /** 损坏现场隔离:先告警,再把损坏文件改名为 .corrupt-<ts> 保留现场,最后清空内存。
19521
- * rename 先于清空(后续 save 会覆盖原文件);rename 后原文件不再被覆盖。 */
19361
+ /** 损坏现场隔离:先告警,再把损坏文件改名为 .corrupt-<ts> 保留现场,最后清空内存——
19362
+ * rename 必须先于清空,后续 save 才不会覆盖原损坏文件。 */
19522
19363
  _quarantineCorrupt(err) {
19523
19364
  const bak = this.instancesFile + ".corrupt-" + Date.now();
19524
19365
  this.logger && this.logger.warn && this.logger.warn("instances.json \u8BFB\u53D6/\u89E3\u6790\u5931\u8D25\uFF0C\u5907\u4EFD\u540E\u6E05\u7A7A: " + (err && err.message) + " -> " + bak);
@@ -19529,7 +19370,7 @@ var require_store5 = __commonJS({
19529
19370
  }
19530
19371
  this._replace([]);
19531
19372
  }
19532
- /** 原地替换数组内容(**保持数组对象身份**,外部引用不失效)。 */
19373
+ /** 原地替换数组内容(保持数组对象身份,外部引用不失效)。 */
19533
19374
  _replace(list) {
19534
19375
  if (list === this.instances) return;
19535
19376
  this.instances.length = 0;
@@ -19549,11 +19390,10 @@ var require_store5 = __commonJS({
19549
19390
  this.logger && this.logger.error && this.logger.error("instances.json \u6301\u4E45\u5316\u5931\u8D25: " + (e && e.message));
19550
19391
  }
19551
19392
  }
19552
- /** 实例端口注册表派生同步:端口真源是 instances.json(内存数组,用户配置值);registry 的 inst:*
19553
- * 记录是派生投影,把配置端口纳入全局冲突视图(防动态分配段撞实例端口),非记忆绑定。
19554
- * 全量对账:内存有而 registry 缺则 registerUser;registry 有 inst:* 而内存无对应实例则 unregister。
19555
- * 同 owner 已登记端口与当前配置端口不一致(端口已变)时,先 unregister 旧登记再按新端口
19556
- * registerUser——否则旧 inst:* 记录因「该 id 仍存在」而永久泄漏。 */
19393
+ /** 端口登记派生同步:真源是 instances.json 内存数组(用户配置值),registry 的 inst:* 记录只是派生投影,
19394
+ * 把配置端口纳入全局冲突视图(防动态分配段撞实例端口)。全量对账:内存有而 registry 缺则 registerUser,
19395
+ * registry 有 inst:* 而内存无该实例则 unregister;端口变更时先卸旧登记再按新端口注册,
19396
+ * 否则旧 inst:* 记录因「该 id 仍存在」永久泄漏。 */
19557
19397
  syncPorts() {
19558
19398
  for (const inst of this.instances) {
19559
19399
  const id = String(inst.id || "");
@@ -19582,7 +19422,7 @@ var require_store5 = __commonJS({
19582
19422
  }
19583
19423
  }
19584
19424
  /** 为沙箱实例建独立目录(根 + 数据 + 依赖 + 临时)。实例根一次性收紧权限:
19585
- * 同机他用户的跨舱互读是隔离清单里唯一没被目录布局本身挡住的一格。 */
19425
+ * 同机他用户的跨舱互读是隔离清单里唯一未被目录布局本身挡住的一格。 */
19586
19426
  ensureDirs(inst) {
19587
19427
  const r = fileProtect.ensurePrivateDir(sandbox.root(this.instancesRoot, inst));
19588
19428
  if (r && r.ok === false) this.logger && this.logger.warn && this.logger.warn("\u5B9E\u4F8B\u6839\u6743\u9650\u6536\u7D27\u5931\u8D25 " + r.mode + ": " + r.reason);
@@ -21275,14 +21115,10 @@ var require_market = __commonJS({
21275
21115
  if (this._inFlight) return this._inFlight;
21276
21116
  return this._startBuild();
21277
21117
  }
21278
- /** 启动一次构建并登记为并发去重引用,返回**原始** promise。
21279
- * 两条不变量必须同时成立:
21280
- * (a) 无消费者的后台刷新失败不得成为进程级 unhandledRejection —— 靠给 raw **挂一个
21281
- * no-op handler「标记已处理」**实现,而不是把 promise 消化掉;
21282
- * (b) 被消费者取走时仍须如实失败 —— raw 的 reject 语义不变(api/domains/plugins.js 的
21283
- * GET /plugins/market 分支据此回答 500)。
21284
- * 若改成「消化后存回 _inFlight」,则并发的 force 请求会取到这个已消化的 promise,
21285
- * 失败时 resolve 成 undefined -> 200 + 空体,正是本仓最忌讳的「假成功」。 */
21118
+ /** 启动一次构建并登记为并发去重引用,返回原始 promise。两条不变量必须同时成立:
21119
+ * (a) 无消费者的后台刷新失败不得成为进程级 unhandledRejection —— 靠给 raw 挂 no-op handler「标记已处理」实现,而不是把 promise 消化掉;
21120
+ * (b) 被消费者取走时仍须如实失败 —— raw 的 reject 语义不变(api/domains/plugins.js 的 GET /plugins/market 据此回答 500)。
21121
+ * 若改成「消化后存回 _inFlight」,force 请求会取到它并在失败时 resolve 成 undefined -> 200 + 空体。 */
21286
21122
  _startBuild() {
21287
21123
  const raw = this.buildIndex();
21288
21124
  raw.catch(() => {
@@ -21425,7 +21261,7 @@ var require_market = __commonJS({
21425
21261
  }
21426
21262
  return (origin || REGISTRY).replace(/\/+$/, "");
21427
21263
  }
21428
- /** npm 最新版元数据查询:走 dist 统一镜像源(国内可达性/手动固定与全系统一致)。 */
21264
+ /** npm 最新版元数据查询(镜像源选择见 _npmOrigin)。 */
21429
21265
  async safeFetchLatest(name) {
21430
21266
  return fetchLatest(await this._npmOrigin(), name);
21431
21267
  }
@@ -22718,27 +22554,20 @@ var require_managed_object = __commonJS({
22718
22554
  kind: o.kind,
22719
22555
  id: o.id,
22720
22556
  name: String(o.name || o.id),
22721
- // 应然(业务申报 / 用户操作;唯一持久意图)
22722
- // desired:两域共用同一字段名,但语义不同——
22723
- // 域 A = 用户意图;域 B = 「当前业务是否需要它」的条件。
22557
+ // desired 两域共用字段名但语义不同:域 A=用户意图;域 B=「当前业务是否需要它」的条件
22724
22558
  desired: o.desired === "stopped" ? "stopped" : "running",
22725
- // guardian:域 A 专有字段(契约 G-1)。域 B 基础设施不物化它——
22726
- // 不是「置 false」,是「不存在」,这样旧残留才清得掉。
22559
+ // guardian 域 A 专有(见上);域 B 不物化,旧残留才清得掉
22727
22560
  ...isDomainA(o.kind) ? { guardian: o.guardian === true } : {},
22728
- // 所有权(注册时申报;持久)
22729
22561
  ownership: normalizeOwnership(o.ownership),
22730
- // phase(调谐循环 R3 驱动;初始 stopped。业务不得直接改)
22562
+ // 初始 stopped;业务不得直接改,由 heartbeat 调谐循环写入
22731
22563
  phase: "stopped",
22732
- // 观测缓存(实然;不持久化,由 heartbeat/adapter 写入)
22733
22564
  lastObserved: null,
22734
- // { ok, error, at }
22735
- // 进程句柄/运行期引用(C3-3b G2:main 状态机句柄挂目录,不持久化——
22736
- // 形如 { child?, adoptedPid?, adopted, observedOnly, startDeadline?, spawnBlockedUntil? })
22565
+ // 实然缓存 { ok, error, at };不持久化,由 heartbeat/adapter 写入
22566
+ // 运行期引用(不持久化):main 状态机句柄,形如 { child?, adoptedPid?, adopted, observedOnly, startDeadline?, spawnBlockedUntil? }
22737
22567
  process: null,
22738
- // 域摘要引用(R4:daemon 类黑盒经 ctl 向目录呈报的紧凑摘要,只存引用/只读缓存,不持久化;
22739
- // 形如 { runState, providers, accounts, proxyInstances, resourcePorts, fetchedAt })
22568
+ // daemon 类黑盒经 ctl 呈报的紧凑摘要,只读缓存不持久化(形如 { runState, providers, accounts, proxyInstances, resourcePorts, fetchedAt })
22740
22569
  domainSummary: null,
22741
- // 退避(调谐用;崩溃窗口)随目录持久化(见 _load/_save)。
22570
+ // 退避与崩溃窗口计数随目录持久化(见 registry _load/_save)
22742
22571
  backoffLevel: 0,
22743
22572
  backoffUntil: null,
22744
22573
  crashWindowStart: null,
@@ -22940,8 +22769,8 @@ var require_registry3 = __commonJS({
22940
22769
  this._log("warn", "managed-objects \u6301\u4E45\u5316\u5931\u8D25: " + (e && e.message));
22941
22770
  }
22942
22771
  }
22943
- /** 崩溃/退避字段变化时的持久化入口:防抖 50ms 合并同拍多次变更,避免写放大。
22944
- * 仅落盘目录文件;由 supervisor._persistCrashField 在字段变更后调用。 */
22772
+ /** 崩溃/退避字段变化的持久化入口:防抖 50ms 合并同拍多次变更避免写放大;
22773
+ * 由 supervisor._persistCrashField 在字段变更后调用。 */
22945
22774
  persistCrashState() {
22946
22775
  if (this._crashSaveTimer) return;
22947
22776
  this._crashSaveTimer = setTimeout(() => {
@@ -22971,7 +22800,7 @@ var require_registry3 = __commonJS({
22971
22800
  const i = this._objects.indexOf(e);
22972
22801
  if (i >= 0) this._objects.splice(i, 1);
22973
22802
  }
22974
- /** 注册新类型能力(未来扩展;显式声明,非 CRD)。委托纯模型 managed-object。 */
22803
+ /** 注册新类型能力(显式声明,非通用 CRD;实现与判据见 managed-object.js)。 */
22975
22804
  registerKind(kind, meta) {
22976
22805
  registerManagedKind(kind, meta);
22977
22806
  return this;
@@ -22995,8 +22824,8 @@ var require_registry3 = __commonJS({
22995
22824
  this._event("managed_object_registered", { kind: e.kind, id: e.id, name: e.name });
22996
22825
  return e;
22997
22826
  }
22998
- /** 对象变更申报(desired/guardian/ownership/name)。
22999
- * `guardian` 是域 A 专有:域 B 基础设施忽略它并清除历史残留。 */
22827
+ /** 对象变更申报(desired/guardian/ownership/name)。guardian 是域 A 专有:
22828
+ * 域 B 基础设施既不写入,还主动删键清除早期版本残留(下一次 update 即归一)。 */
23000
22829
  update(id, patch) {
23001
22830
  const e = this.get(id);
23002
22831
  if (!e) return { ok: false, error: "\u672A\u6CE8\u518C: " + id };
@@ -23043,10 +22872,8 @@ var require_registry3 = __commonJS({
23043
22872
  this._event("managed_object_removed", { kind: e.kind, id: e.id });
23044
22873
  return { ok: true };
23045
22874
  }
23046
- /** 释放本对象持有的端口(按 owner)。
23047
- * `PortRegistry.release(port, ownerId)` 的 owner 校验不可绕过:这里绝不回退成无 owner 的释放
23048
- * (那会误删他人端口登记)。返回值仅用于日志——不匹配即 no-op 是期望行为,不是错误。
23049
- */
22875
+ /** 释放本对象持有的端口(按 owner)。绝不回退成无 owner 的释放——那会误删他人登记;
22876
+ * owner 不匹配时 release 返回失败是期望行为,不视为错误,仅日志。 */
23050
22877
  _releasePort(port, ownerId) {
23051
22878
  if (!this.ports || typeof this.ports.release !== "function") return;
23052
22879
  try {
@@ -23077,11 +22904,8 @@ var require_registry3 = __commonJS({
23077
22904
  count() {
23078
22905
  return this._objects.length;
23079
22906
  }
23080
- /** 唯一心跳:薄委托 runHeartbeat(单拍调度、节流、单对象超时隔离在 control/heartbeat.js)。
23081
- * 观测写入口仍是本实例的 applyObservation/setPhase。
23082
- * @param {number} [intervalMs] 心跳拍宽(默认 5000)
23083
- * @returns {Promise<{ observed: string[], errors: string[] }>}
23084
- */
22907
+ /** 唯一心跳:薄委托 runHeartbeat(单拍调度、节流、单对象超时隔离在 control/heartbeat.js);
22908
+ * 观测写入口仍是本实例的 applyObservation/setPhase。 */
23085
22909
  heartbeat(intervalMs) {
23086
22910
  return runHeartbeat(this, intervalMs);
23087
22911
  }
@@ -24157,16 +23981,6 @@ var require_entry = __commonJS({
24157
23981
  "use strict";
24158
23982
  var { PHASES } = require_registry3();
24159
23983
  var ManagedLifecycle = class {
24160
- /**
24161
- * @param {object} opts
24162
- * - id: 模块唯一标识(如 'dsh' / 'router' / 'router.proxy.<keyId>' / 'inst.<id>' / 'lan')
24163
- * - kind: 模块类别('dsh' | 'router' | 'proxy-instance' | 'instance' | 'lan' | 'plugin')
24164
- * - name: 显示名
24165
- * - logger / events:可选(日志与事件总线)
24166
- * - start(ctx):async —— 启动该模块(由生命周期管理器调用)
24167
- * - stop(ctx):async —— 停止该模块(守卫 shutdown 或用户启停时调用)
24168
- * - status():返回模块自身细节状态(供面板展示,可选)
24169
- */
24170
23984
  constructor(opts) {
24171
23985
  this.id = opts.id || "lc-" + Math.random().toString(36).slice(2, 8);
24172
23986
  this.kind = opts.kind || "module";
@@ -24202,19 +24016,16 @@ var require_entry = __commonJS({
24202
24016
  lastProbeAt: this.lastProbeAt,
24203
24017
  lastTransitionAt: this.lastTransitionAt,
24204
24018
  error: this.error,
24205
- // 无 restartCount(域 A 计数不在本对象上)
24206
24019
  guardian: this.guardian === true,
24207
24020
  startable: this.startable,
24208
- // 能力声明可视化(UI 据此灰化启停入口)
24021
+ // UI 据此灰化启停入口
24209
24022
  guardable: this.guardable,
24210
24023
  monitoring: this._monitoring,
24211
24024
  detail: this._status ? this._status() || null : null
24212
24025
  };
24213
24026
  }
24214
- /* 内部状态迁移(由 LifecycleManager 驱动,模块不直接改 phase) */
24215
- /** 状态迁移。非白名单值静默丢弃(是执法,不是 bug):
24216
- * phase 只能取 canonical 词表内的值,防止写入手写字符串造成新的分叉;
24217
- * 代价是写错值时不报错,故词表必须引用唯一源,否则合法值会被无声拒绝。 */
24027
+ /** 状态迁移。非白名单值静默丢弃是执法不是 bug:phase 只取 canonical 词表,
24028
+ * 防止手写字符串造成分叉;代价是写错不报错,故词表必须引用唯一源。 */
24218
24029
  _setPhase(p) {
24219
24030
  if (!PHASES.includes(p)) return;
24220
24031
  if (this.phase !== p) {
@@ -24223,23 +24034,16 @@ var require_entry = __commonJS({
24223
24034
  }
24224
24035
  }
24225
24036
  /* 供 LifecycleManager 调用的统一操作 */
24226
- /** 期望保持运行。 */
24227
24037
  wantRunning() {
24228
24038
  this.desired = "running";
24229
24039
  this.error = null;
24230
24040
  }
24231
- /** 期望停止。 */
24232
24041
  wantStopped() {
24233
24042
  this.desired = "stopped";
24234
24043
  }
24235
- /** 启动模块(幂等:已在运行则 no-op)。
24236
- *
24237
- * 必须尊重回调的显式失败:适配器的 start 可能返回 `{ok:false, error}`
24238
- * (如 daemon 拉不起来时)。若不看 `r.ok` 就置 running/healthy,
24239
- * 会让 `/lifecycle/status` 谎报成功,而模块实际没起来。
24240
- *
24241
- * 兼容性:`r.ok !== false` 视为成功,保留「回调只返回 undefined / 无 ok 字段」的既有语义。
24242
- */
24044
+ /** 启动(幂等:已在运行则 no-op)。必须尊重回调的显式失败:适配器 start 可能返回
24045
+ * {ok:false}(如 daemon 拉不起来),不看 r.ok 就置 running/healthy 会让
24046
+ * /lifecycle/status 谎报成功。r.ok !== false 视为成功(允许回调返回 undefined)。 */
24243
24047
  async start() {
24244
24048
  if (this.phase === "running" || this.phase === "starting") return { ok: true, already: true };
24245
24049
  this.error = null;
@@ -24266,12 +24070,8 @@ var require_entry = __commonJS({
24266
24070
  return { ok: false, error: this.error };
24267
24071
  }
24268
24072
  }
24269
- /** 停止模块(守卫 shutdown 或用户显式停)。
24270
- *
24271
- * 同样必须尊重回调的显式失败:stop 回调返回 `{ok:false}` 时不得置
24272
- * phase=stopped/desired=stopped,否则面板显示「已停止」而进程可能还在跑;
24273
- * 显式失败时保持运行态(与异常分支同一语义)并如实上报错误。
24274
- */
24073
+ /** 停止(守卫 shutdown 或用户显式停)。同样必须尊重回调显式失败:ok:false 时
24074
+ * 不得置 stopped,否则面板显示「已停止」而进程可能还在跑。 */
24275
24075
  async stop(reason) {
24276
24076
  if (this.phase === "stopped") {
24277
24077
  this.desired = "stopped";
@@ -24298,12 +24098,8 @@ var require_entry = __commonJS({
24298
24098
  return { ok: false, error: this.error };
24299
24099
  }
24300
24100
  }
24301
- /** 重启(无 _restart 回调时退化为 stop -> start)。
24302
- *
24303
- * 回退路径必须尊重 stop/start 的显式失败:两个返回值都不可丢弃,
24304
- * 否则「停不掉」或「起不来」时仍报成功,面板显示「已重启」而模块实际是死的。
24305
- * 语义:stop 失败则模块仍在跑,重启未发生;start 失败则已停但未起。
24306
- */
24101
+ /** 重启(无 _restart 回调时退化为 stop -> start)。两步返回值都不得丢弃显式失败:
24102
+ * stop 失败=模块仍在跑、重启未发生;start 失败=已停但未起。 */
24307
24103
  async restart() {
24308
24104
  if (this._restart) {
24309
24105
  const r = await this._restart();
@@ -24380,7 +24176,9 @@ var require_manager = __commonJS({
24380
24176
  this._emit("lifecycle_stopped", { id: lc.id, kind: lc.kind, ok: r.ok, reason });
24381
24177
  return { ok: r.ok !== false, error: r.error, already: r.already, ...lc.snapshot() };
24382
24178
  }
24383
- /** 重启模块(保持 desired 语义)。 */
24179
+ /** 重启(保持 desired 语义)。委托 lc.restart():_restart 回调优先(如 dsh 经 requestRestart
24180
+ * 停旧拉新),无回调才退化为 stop -> start;该回退逻辑由 ManagedLifecycle.restart() 唯一承担
24181
+ * (契约测试锁定),此处不留副本。 */
24384
24182
  async restart(id) {
24385
24183
  const lc = this.registrations.get(id);
24386
24184
  if (!lc) return { ok: false, error: "\u672A\u6CE8\u518C\u6A21\u5757: " + id };
@@ -24392,12 +24190,9 @@ var require_manager = __commonJS({
24392
24190
  statusAll() {
24393
24191
  return this.all().map((l) => lc_status(l));
24394
24192
  }
24395
- /**
24396
- * 守卫 shutdown:停全部 monitoring 的模块。
24397
- * 契约(RC2):本管理器不内置 dsh 特例——stopAll 会停掉所有纳管/期望运行项。
24398
- * 「守卫退出不动 DSH」由调用方以 exclude:['dsh'] 保证(见 supervisor.js 的 stopAll 调用)。
24399
- * @param {object} opts { exclude?: string[] } 额外豁免的模块 id(如独立 daemon 型 router)
24400
- */
24193
+ /** 守卫 shutdown:停全部 monitoring 的模块。契约 RC2:本管理器不内置 dsh 特例——
24194
+ * stopAll 会停掉所有纳管/期望运行项,「守卫退出不动 DSH」由调用方以 exclude:['dsh'] 保证
24195
+ * (见 supervisor.js 的调用)。exclude = 额外豁免的模块 id(如独立 daemon 型 router)。 */
24401
24196
  async stopAll(reason, opts) {
24402
24197
  const exclude = new Set(opts && opts.exclude || []);
24403
24198
  for (const lc of this.all()) {
@@ -24581,13 +24376,12 @@ var require_adapters = __commonJS({
24581
24376
  name: "\u667A\u80FD\u8DEF\u7531",
24582
24377
  logger,
24583
24378
  start: async () => sup && typeof sup.setRouterRunning === "function" ? sup.setRouterRunning(true) : router.start(),
24584
- // 守卫自身 shutdown(_stopping=true)时 stopAll 不得停独立 router-daemon:
24585
- // 守卫退出不影响被管模块(daemon 独立生命周期继续服务);仅显式用户停止才停 daemon。
24379
+ // 守卫自身 shutdown(_stopping=true)不得停独立 daemon:守卫退出不影响被管模块,仅显式用户停止才停。
24586
24380
  stop: async () => {
24587
24381
  if (sup && sup._stopping) return { ok: true, already: true, reason: "guard-shutdown \u4E0D\u505C daemon" };
24588
24382
  return sup && typeof sup.setRouterRunning === "function" ? sup.setRouterRunning(false) : router.stop();
24589
24383
  },
24590
- // detail 走守卫真实 router 状态视图(daemon 模式经 ctl 取 daemon 实时态)。
24384
+ // detail 走守卫真实 router 状态视图(daemon 模式经 ctl 取实时态)
24591
24385
  status: () => sup && typeof sup.routerStatus === "function" ? sup.routerStatus() : router.status ? router.status() : null
24592
24386
  });
24593
24387
  mgr.register(rlc);
@@ -24609,7 +24403,7 @@ var require_adapters = __commonJS({
24609
24403
  return { ok: false, error: e.message };
24610
24404
  }
24611
24405
  },
24612
- // 守卫 shutdown 时同样不停 LAN(L3b:relay 由独立 lan-daemon 承载;守卫内 LanManager 为 dry/门面)
24406
+ // 守卫 shutdown 同样不停 lan(relay 由独立 lan-daemon 承载;守卫内 LanManager 为门面)
24613
24407
  stop: async () => {
24614
24408
  if (deps && deps.supervisor && deps.supervisor._stopping) return { ok: true, already: true, reason: "guard-shutdown \u4E0D\u505C lan" };
24615
24409
  try {
@@ -24628,16 +24422,14 @@ var require_adapters = __commonJS({
24628
24422
  id: "instances",
24629
24423
  kind: "instances",
24630
24424
  name: "\u5B9E\u4F8B\u7BA1\u7406",
24631
- // 聚合单元:无全局进程(start/stop 为 no-op)——声明不可启停,避免「返回 ok 但无动作」的假成功。
24632
- // 单个实例的启停走 /instances/{start|stop}(各自独立生命周期)。
24425
+ // 聚合单元无全局进程:声明不可启停,避免「返回 ok 但无动作」的假成功;
24426
+ // 单个实例的启停走 /instances/{start|stop}。
24633
24427
  startable: false,
24634
24428
  guardable: false,
24635
24429
  logger,
24636
24430
  start: async () => ({ ok: true }),
24637
- // 实例无全局进程;单个实例由各自启停
24638
24431
  stop: async () => ({ ok: true }),
24639
- // detail 用实例集真实统计(曾引用不存在的 instances.summary——死回调恒 null);
24640
- // phase/healthy 视图由守卫 _syncInstancesLifecycleView 每心跳真实刷新。
24432
+ // detail 用实例集真实统计;phase/healthy 视图由守卫 _syncInstancesLifecycleView 每心跳刷新。
24641
24433
  status: () => {
24642
24434
  try {
24643
24435
  const arr = instances && typeof instances.all === "function" && instances.all() || [];
@@ -25780,8 +25572,7 @@ var require_instances = __commonJS({
25780
25572
  return bootstrapDshCookie("127.0.0.1", it.port, tok).then((cookie) => {
25781
25573
  if (!cookie) return deny(400, "\u4EE4\u724C\u6362\u53D6\u5931\u8D25");
25782
25574
  res.writeHead(303, {
25783
- // SameSite=Strict——cookie 跨端口共享是本设计意图(回环同源,
25784
- // 端口不参与 site 判定),但必须杜绝跨站导航/子资源携带(旧值缺省=Lax)。
25575
+ // 跨端口共享 cookie 是设计意图(回环同源,端口不参与 site 判定),故须 Strict 杜绝跨站携带。
25785
25576
  "Set-Cookie": cookie + "; Path=/; HttpOnly; SameSite=Strict",
25786
25577
  "Location": "http://127.0.0.1:" + it.port + "/"
25787
25578
  });
@@ -26095,7 +25886,7 @@ var require_router_table = __commonJS({
26095
25886
  require_instances(),
26096
25887
  require_relay(),
26097
25888
  require_shell2()
26098
- // 桌面壳更新安全网(/shell/*)——内核仅做安全网,非更新源
25889
+ // 桌面壳更新安全网(/shell/*)
26099
25890
  ];
26100
25891
  module2.exports = { API_DOMAINS };
26101
25892
  }
@@ -26995,8 +26786,8 @@ var require_ports3 = __commonJS({
26995
26786
  bindingPreferred: !!o.bindingPreferred,
26996
26787
  onBindingLost: o.onBindingLost,
26997
26788
  reclaimCmdMark: "lan-daemon.js",
26998
- // configPath 为空时 reclaimCfg='',probe.reclaimByCmdMark 按
26999
- // fail-closed 不回收(宁可留占用走冲突分支,也不按 cmdMark 全量误杀同名进程)。
26789
+ // configPath 为空时 reclaimCfg='',probe.reclaimByCmdMark 按 fail-closed 不回收:
26790
+ // 宁可留占用走冲突分支,也不按 cmdMark 全量误杀同名进程。
27000
26791
  reclaimCfg: o.configPath || "",
27001
26792
  waitMs: 8e3
27002
26793
  });
@@ -27217,8 +27008,8 @@ var require_frp = __commonJS({
27217
27008
  this._sumCache = null;
27218
27009
  this._hardenPermissions();
27219
27010
  }
27220
- /** 敏感文件权限加固:frpc.toml 含 auth.token 明文、frp.json 同含 token;
27221
- * 新写入已用 0600,但历史遗留文件可能是早期版本以默认 umask 写出的 0644/0664。 */
27011
+ /** frpc.toml 含 auth.token 明文、frp.json 同含 token:新写入已用 0600,
27012
+ * 但历史遗留文件可能是早期以默认 umask 写出的 0644/0664,故启动时补加固。 */
27222
27013
  _hardenPermissions() {
27223
27014
  try {
27224
27015
  const fp = platform.fileProtect;
@@ -27254,19 +27045,18 @@ var require_frp = __commonJS({
27254
27045
  installed: fs2.existsSync(this.binPath),
27255
27046
  running: !!(this.child && this.child.pid),
27256
27047
  pid: this.child ? this.child.pid : null,
27257
- // API 面绝不回显 authToken 明文(与 access.js「只报 configured」同规)。
27258
- // UI 需要改动令牌时显式提交新值;normalizeFrpSettings 是 patch 归并——
27259
- // **字段缺省(undefined)= 保留现值**,显式提交 '' = 清除(UI 留空时必须省略字段)。
27048
+ // API 面绝不回显 authToken 明文,只报 authTokenSet(与 access.js「只报 configured」同规)。
27049
+ // normalizeFrpSettings 是 patch 归并:字段缺省(undefined)= 保留现值,显式 '' = 清除;
27050
+ // 故 UI 想保留现值必须省略字段而不是留空。
27260
27051
  settings: { serverAddr: s.serverAddr, serverPort: s.serverPort, user: s.user, authTokenSet: !!s.authToken },
27261
27052
  logTail: this.logTail.slice(-20)
27262
27053
  };
27263
27054
  }
27264
- /** instances 里 remoteMode==='wan' 的映射到远程端口(纯文本生成委托 core.buildFrpcToml)。 */
27055
+ /** wan 实例映射为远程端口;文本生成委托纯函数 core.buildFrpcToml。 */
27265
27056
  buildConfig(settings, instances) {
27266
27057
  return buildFrpcToml(settings, instances);
27267
27058
  }
27268
- /** 由受管清单变化时调用:重写配置并在运行中时平滑重启。
27269
- * frpc 生命周期单一条件 = 是否存在 wan 隧道(count>0);无全局总闸。 */
27059
+ /** 受管清单变化时调用:重写配置,运行中则平滑重启(生命周期条件见类头:是否存在 wan 隧道)。 */
27270
27060
  syncFromInstances(instances) {
27271
27061
  const settings = this.loadSettings();
27272
27062
  const { text, count } = this.buildConfig(settings, instances);
@@ -27335,7 +27125,6 @@ var require_frp = __commonJS({
27335
27125
  this.logger.info && this.logger.info("frpc started pid=" + child.pid);
27336
27126
  return { ok: true, pid: child.pid };
27337
27127
  }
27338
- /** 非预期退出后的有界退避重启。 */
27339
27128
  _scheduleRestart() {
27340
27129
  if (this._restartTimer) return;
27341
27130
  if (!this._lastCount) return;
@@ -27419,7 +27208,6 @@ var require_frp = __commonJS({
27419
27208
  _download(url, report) {
27420
27209
  return download(url, report);
27421
27210
  }
27422
- /** 安装 frpc(下载 + 完整性校验 + 解压)。 */
27423
27211
  async install(onProgress) {
27424
27212
  const cache = this._sumCache || (this._sumCache = {});
27425
27213
  return installFrpc({
@@ -27682,7 +27470,7 @@ var require_ops5 = __commonJS({
27682
27470
  localAddresses() {
27683
27471
  return managed.localAddresses();
27684
27472
  }
27685
- /** 持久化:优先注入的路由(persist),否则回退沙箱实例 save。 */
27473
+ /** 持久化:优先注入的 persist 路由,否则回退沙箱 instances.save()。 */
27686
27474
  _saveAll() {
27687
27475
  if (typeof this.persist === "function") {
27688
27476
  try {
@@ -27699,15 +27487,15 @@ var require_ops5 = __commonJS({
27699
27487
  }
27700
27488
  }
27701
27489
  }
27702
- /** 受管 DSH 合成清单:沙箱实例 + 原生主干 main。 */
27490
+ /** 受管 DSH 合成清单(沙箱 + 原生主干 main)。 */
27703
27491
  _allManaged() {
27704
27492
  return managed.allManaged({ instances: this.instances, mainOf: this.mainOf });
27705
27493
  }
27706
- /** 合成查找:按 id 取首个匹配(清单无同 id 项,见 managed.js#allManaged)。 */
27494
+ /** 合成查找:按 id 取首个匹配。 */
27707
27495
  _findManaged(id) {
27708
27496
  return managed.findManaged(this._allManaged(), id);
27709
27497
  }
27710
- /** frpc 子进程句柄只读访问器(daemon 优雅停机等待其退出;不暴露内部 frp 私有对象)。 */
27498
+ /** frpc 子进程句柄只读访问器:不暴露 frp 私有对象,供 daemon 优雅停机等待其退出。 */
27711
27499
  frpChild() {
27712
27500
  return this.frp && this.frp.child || null;
27713
27501
  }
@@ -27751,7 +27539,7 @@ var require_ops5 = __commonJS({
27751
27539
  wanPort: proxy ? proxy.wanPort : null,
27752
27540
  token: inst.remoteToken || "",
27753
27541
  dshToken: this.tokenOf(inst.id) || "",
27754
- // 令牌一律按需从令牌池读取
27542
+ // 令牌按需从令牌池读取
27755
27543
  running: !!this._lanServers && !!this._lanServers[inst.id],
27756
27544
  inject,
27757
27545
  remote
@@ -27768,7 +27556,7 @@ var require_ops5 = __commonJS({
27768
27556
  });
27769
27557
  return st;
27770
27558
  }
27771
- /** frpc 操作门面(settings/install 统一入口;总闸已随三态模型废止)。 */
27559
+ /** frpc 操作门面(settings/install 统一入口)。 */
27772
27560
  async frpAction(action, body) {
27773
27561
  const j = body || {};
27774
27562
  if (action === "settings") {
@@ -27792,14 +27580,13 @@ var require_ops5 = __commonJS({
27792
27580
  }
27793
27581
  return { ok: false, error: "\u672A\u77E5 frp \u64CD\u4F5C: " + action };
27794
27582
  }
27795
- /** 受管清单是否存在 wan 意图(配置闸用:含尚未建立代理的实例,磁盘态即算)。 */
27583
+ /** 受管清单是否有 wan 意图:含尚未建立代理的实例(磁盘态即算)。 */
27796
27584
  _hasWanIntent() {
27797
27585
  return this._allManaged().some((x) => normalizeRemoteMode(x.remoteMode) === "wan");
27798
27586
  }
27799
27587
  /** 实例变化后同步 frpc 配置与进程(尽力而为,不抛异常影响主流程)。
27800
- * 执行边界复校 wan 闸:写入口(setRemoteMode 动作)已过 core.validateWanAccess,但冷启动
27801
- * 是直接按磁盘态组装隧道 —— 历史遗留的「wan 态但远程令牌为空」会绕开写侧闸,在网络
27802
- * 边界重现公网零认证暴露。故建隧道前对每个 wan 项复用同一事实源复校,不过闸即跳过该隧道。 */
27588
+ * 建隧道前复校 wan 闸(core.validateWanAccess,与写入口同一实现):冷启动直接按磁盘态组装隧道,
27589
+ * 历史遗留「wan 态但令牌为空」会绕开写侧闸,在网络边界重现公网零认证暴露——不过闸即跳过该隧道。 */
27803
27590
  syncFrpc() {
27804
27591
  if (!this.frp) return;
27805
27592
  try {
@@ -27821,9 +27608,8 @@ var require_ops5 = __commonJS({
27821
27608
  }
27822
27609
  }
27823
27610
  /** 远程代理对账:注册只与「remoteMode!=off」绑定;relay 运行 = 目标存活;孤儿注册移除。
27824
- * 单飞:对账内含逐实例串行 await targetReachable(每个最多 600ms),而被 2 秒级节拍多次触发;
27825
- * 同刻只允许一轮在跑,后续调用复用同一在途 Promise。
27826
- * 刻意不加 async:async 会把返回值包一层新 Promise,单飞身份丢失。 */
27611
+ * 单飞:内部逐实例串行 await targetReachable(每个最多 600ms)而被 2s 节拍反复触发,
27612
+ * 同刻只允许一轮在跑,后续调用复用同一在途 Promise。刻意不加 async——包一层 Promise 会丢单飞身份。 */
27827
27613
  reconcile() {
27828
27614
  if (this._reconcileInFlight) return this._reconcileInFlight;
27829
27615
  this._reconcileInFlight = this._reconcileOnce().catch((e) => {
@@ -27833,25 +27619,23 @@ var require_ops5 = __commonJS({
27833
27619
  });
27834
27620
  return this._reconcileInFlight;
27835
27621
  }
27836
- /** 对账主体(委托 ops/reconcile.js;具名保留:单飞包装与门禁按此名调用)。 */
27622
+ /** 对账主体(委托 ops/reconcile.js);方法名不可改:单飞包装与门禁按此名调用。 */
27837
27623
  async _reconcileOnce() {
27838
27624
  return reconcile.reconcileOnce(this);
27839
27625
  }
27840
- /** 目标实例是否可达(委托 ops/reconcile.js)。 */
27841
27626
  targetReachable(inst) {
27842
27627
  return reconcile.targetReachable(inst);
27843
27628
  }
27844
- /** 串行执行 syncProxy(队列)。 */
27845
27629
  _syncProxyQueued(inst) {
27846
27630
  return reconcile.syncProxyQueued(this, inst);
27847
27631
  }
27848
- /** 删除某实例关联的局域网代理(实例被删除时调用)。 */
27632
+ /** 实例被删除时移除其局域网代理。 */
27849
27633
  async removeProxyForInstance(instId) {
27850
27634
  return reconcile.removeProxyForInstance(this, instId);
27851
27635
  }
27852
27636
  /** 同步某实例的远程访问代理:remoteMode!=off 且目标在监听时创建 relay,off 拆除。
27853
- * wan 不引入第二监听/第二端口:隧道口与 relay 口恒同号(core.buildFrpcToml)。
27854
- * 端口绑定唯一权威是 relay 槽位注册表(byOwner 复用);实例记录不存 wanPort 镜像。 */
27637
+ * wan 不引入第二监听/第二端口(隧道口与 relay 口恒同号,见 core.buildFrpcToml);
27638
+ * 端口绑定唯一权威是 relay 槽位注册表,实例记录不存 wanPort 镜像。 */
27855
27639
  async syncProxy(inst) {
27856
27640
  if (!inst) return;
27857
27641
  const mode = normalizeRemoteMode(inst.remoteMode);
@@ -27915,11 +27699,10 @@ var require_ops5 = __commonJS({
27915
27699
  }
27916
27700
  }
27917
27701
  }
27918
- /** 实例启动时联动远程代理(委托 ops/reconcile.js)。 */
27702
+ /** 实例启动/停止时联动远程代理(委托 ops/reconcile.js:停止只停 relay,保留注册)。 */
27919
27703
  async instanceStart(inst) {
27920
27704
  return reconcile.instanceStart(this, inst);
27921
27705
  }
27922
- /** 实例停止时联动远程代理(委托 ops/reconcile.js)。 */
27923
27706
  instanceStop(inst) {
27924
27707
  return reconcile.instanceStop(this, inst);
27925
27708
  }
@@ -27929,11 +27712,11 @@ var require_ops5 = __commonJS({
27929
27712
  _stopLanServer(id) {
27930
27713
  return lanServers.stopLanServer(this, id);
27931
27714
  }
27932
- /** 守卫优雅退出时调用(委托 ops/lan-servers.js)。 */
27715
+ /** 守卫优雅退出:停全部 relay 与 frpc。 */
27933
27716
  shutdown() {
27934
27717
  return lanServers.shutdown(this);
27935
27718
  }
27936
- /** 令牌变化经 onChange 下发(委托 ops/lan-servers.js)。 */
27719
+ /** 令牌变化下发到既有 relay(热换 DSH 会话 cookie);本域不持久化令牌。 */
27937
27720
  applyToken(instId) {
27938
27721
  return lanServers.applyToken(this, instId);
27939
27722
  }