@dsh-sup/dsh-core-linux-x64 0.1.6-BETA.5 → 0.1.6-BETA.6

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 +397 -276
  2. package/package.json +1 -1
package/core.cjs CHANGED
@@ -60,11 +60,7 @@ var require_exec = __commonJS({
60
60
  function runAsync(bin, args, opts) {
61
61
  const o = opts || {};
62
62
  return new Promise((resolve) => {
63
- execFile(bin, args, Object.assign({}, options(o), { encoding: "utf8" }), (err, stdout, stderr) => {
64
- if (!err) {
65
- resolve({ ok: true, code: "0", stdout: String(stdout == null ? "" : stdout), stderr: String(stderr == null ? "" : stderr), timedOut: false, error: null });
66
- return;
67
- }
63
+ const fail = (err) => {
68
64
  if (o.logger && o.logger.warn) {
69
65
  try {
70
66
  o.logger.warn("[exec] (async) " + bin + " " + (args || []).join(" ").slice(0, 80) + " failed: " + (err && err.message || err));
@@ -75,12 +71,25 @@ var require_exec = __commonJS({
75
71
  resolve({
76
72
  ok: false,
77
73
  code: err.status != null ? String(err.status) : null,
78
- stdout: String(stdout == null ? err.stdout || "" : stdout),
79
- stderr: String(stderr == null ? err.stderr || "" : stderr),
74
+ stdout: String(err.stdout || ""),
75
+ stderr: String(err.stderr || ""),
80
76
  timedOut,
81
77
  error: err && err.message ? String(err.message) : String(err)
82
78
  });
83
- });
79
+ };
80
+ try {
81
+ execFile(bin, args, Object.assign({}, options(o), { encoding: "utf8" }), (err, stdout, stderr) => {
82
+ if (!err) {
83
+ resolve({ ok: true, code: "0", stdout: String(stdout == null ? "" : stdout), stderr: String(stderr == null ? "" : stderr), timedOut: false, error: null });
84
+ return;
85
+ }
86
+ err.stdout = stdout;
87
+ err.stderr = stderr;
88
+ fail(err);
89
+ });
90
+ } catch (e) {
91
+ fail(e);
92
+ }
84
93
  });
85
94
  }
86
95
  function runOutAsync(bin, args, opts) {
@@ -503,15 +512,21 @@ var require_probe = __commonJS({
503
512
  }
504
513
  return null;
505
514
  }
506
- function isAlive(pid) {
507
- if (!Number.isInteger(pid) || pid <= 0) return false;
515
+ function probeAlive(pid) {
516
+ if (!Number.isInteger(pid) || pid <= 0) return "dead";
508
517
  try {
509
518
  process.kill(pid, 0);
510
- return true;
519
+ return "alive";
511
520
  } catch (e) {
512
- return !!e && e.code === "EPERM";
521
+ const code = e && e.code;
522
+ if (code === "EPERM") return "alive";
523
+ if (code === "ESRCH") return "dead";
524
+ return "unknown";
513
525
  }
514
526
  }
527
+ function isAlive(pid) {
528
+ return probeAlive(pid) === "alive";
529
+ }
515
530
  function isZombie(pid) {
516
531
  if (!Number.isInteger(pid) || pid <= 0 || isWindows) return false;
517
532
  if (isLinux) {
@@ -611,6 +626,7 @@ var require_probe = __commonJS({
611
626
  readCmdline: readCmdline2,
612
627
  pgrepList,
613
628
  isAlive,
629
+ probeAlive,
614
630
  isZombie
615
631
  };
616
632
  }
@@ -637,6 +653,7 @@ var require_pidlookup = __commonJS({
637
653
  readCmdline: readCmdline2,
638
654
  pgrepList,
639
655
  isAlive,
656
+ probeAlive,
640
657
  isZombie
641
658
  } = require_probe();
642
659
  var isLinux = process.platform === "linux";
@@ -659,6 +676,7 @@ var require_pidlookup = __commonJS({
659
676
  module2.exports = {
660
677
  findListeningPid,
661
678
  isAlive,
679
+ probeAlive,
662
680
  isZombie,
663
681
  readCmdline: readCmdline2,
664
682
  normCmdline,
@@ -929,7 +947,7 @@ var require_version = __commonJS({
929
947
  var fs2 = require("node:fs");
930
948
  var path2 = require("node:path");
931
949
  function guardVersion() {
932
- if (true) return String("0.1.6-BETA.5");
950
+ if (true) return String("0.1.6-BETA.6");
933
951
  try {
934
952
  return JSON.parse(fs2.readFileSync(path2.join(__dirname, "..", "..", "package.json"), "utf8")).version || "unknown";
935
953
  } catch {
@@ -949,6 +967,8 @@ var require_main_record = __commonJS({
949
967
  const reg = () => typeof g.getManagedObjects === "function" ? g.getManagedObjects() : null;
950
968
  const logger = () => typeof g.getLogger === "function" ? g.getLogger() : null;
951
969
  let fallback = null;
970
+ const DEFAULTS = { restartCount: 0, backoffLevel: 0, backoffUntil: null, crashWindowStart: null, crashWindowRestarts: 0 };
971
+ const buffered = /* @__PURE__ */ new Map();
952
972
  function entryOf() {
953
973
  const m = reg();
954
974
  if (!m || typeof m.get !== "function") return null;
@@ -964,8 +984,8 @@ var require_main_record = __commonJS({
964
984
  kind: "dsh",
965
985
  id: "main",
966
986
  name: "\u4E3B\u5B9E\u4F8B",
987
+ // 不带 guardian(B2-2/B2-3):目录 entry 形态已无该键,守护开关权威在 dsh-main.json。
967
988
  desired: "running",
968
- guardian: true,
969
989
  ownership: { ports: [], rootPath: null, unit: null, daemonScript: null, processMode: "spawn", meta: null },
970
990
  phase: "stopped",
971
991
  lastObserved: null,
@@ -994,11 +1014,26 @@ var require_main_record = __commonJS({
994
1014
  }
995
1015
  }
996
1016
  function storeOf() {
997
- return entryOf() || fallbackEntryOf();
1017
+ const e = entryOf();
1018
+ if (!e) return fallbackEntryOf();
1019
+ if (buffered.size) flushBuffered(e);
1020
+ return e;
1021
+ }
1022
+ function flushBuffered(e) {
1023
+ let changed = false;
1024
+ for (const [k, v] of buffered) {
1025
+ if (k in DEFAULTS && e[k] === DEFAULTS[k] && e[k] !== v) {
1026
+ e[k] = v;
1027
+ changed = true;
1028
+ }
1029
+ }
1030
+ buffered.clear();
1031
+ if (changed) persistCrashField();
998
1032
  }
999
1033
  function fieldOf(name, v, write) {
1000
1034
  const e = storeOf();
1001
1035
  if (write) {
1036
+ if (e === fallback && name in DEFAULTS) buffered.set(name, v);
1002
1037
  if (e[name] !== v) {
1003
1038
  e[name] = v;
1004
1039
  persistCrashField();
@@ -1280,8 +1315,8 @@ var require_fields = __commonJS({
1280
1315
  try {
1281
1316
  if (m && typeof m.setPhase === "function" && record.entryOf() === e) {
1282
1317
  if (e.phase !== ph) m.setPhase("main", ph);
1283
- } else if (e.phase !== ph) {
1284
- e.phase = ph;
1318
+ } else {
1319
+ record.fieldOf("phase", ph, true);
1285
1320
  }
1286
1321
  } catch (e2) {
1287
1322
  const l = logger();
@@ -1308,8 +1343,8 @@ var require_fields = __commonJS({
1308
1343
  try {
1309
1344
  if (m && typeof m.update === "function" && record.entryOf() === e) {
1310
1345
  if (e.desired !== want) m.update("main", { desired: want });
1311
- } else if (e.desired !== want) {
1312
- e.desired = want;
1346
+ } else {
1347
+ record.fieldOf("desired", want, true);
1313
1348
  }
1314
1349
  } catch (e2) {
1315
1350
  const l = logger();
@@ -1511,6 +1546,7 @@ var require_desired = __commonJS({
1511
1546
  const intents = () => typeof g.getIntents === "function" ? g.getIntents() : null;
1512
1547
  const events = () => typeof g.getEvents === "function" ? g.getEvents() : null;
1513
1548
  const configPath = () => typeof g.getConfigPath === "function" ? g.getConfigPath() : null;
1549
+ const configAliases = () => typeof g.getConfigAliases === "function" ? g.getConfigAliases() || [] : [];
1514
1550
  const logger = () => typeof g.getLogger === "function" ? g.getLogger() : null;
1515
1551
  const setCrashHalted = typeof g.setCrashHalted === "function" ? g.setCrashHalted : () => {
1516
1552
  };
@@ -1592,7 +1628,9 @@ var require_desired = __commonJS({
1592
1628
  }
1593
1629
  }
1594
1630
  Object.assign(cur, patch);
1595
- delete cur.switcherAutoStart;
1631
+ for (const [from, to] of configAliases()) {
1632
+ if (cur[from] !== void 0 && cur[to] !== void 0) delete cur[from];
1633
+ }
1596
1634
  writeAtomic(p, JSON.stringify(cur, null, 2), { mode: 384 });
1597
1635
  return true;
1598
1636
  } catch (e) {
@@ -1741,6 +1779,7 @@ var require_collaborator = __commonJS({
1741
1779
  getIntents: g.getIntents,
1742
1780
  getEvents: g.getEvents,
1743
1781
  getConfigPath: g.getConfigPath,
1782
+ getConfigAliases: g.getConfigAliases,
1744
1783
  getLogger: logger,
1745
1784
  setCrashHalted: g.setCrashHalted,
1746
1785
  setManualRestart: g.setManualRestart,
@@ -2022,13 +2061,11 @@ var require_specs = __commonJS({
2022
2061
  const daemons = () => typeof g.getDaemons === "function" ? g.getDaemons() : null;
2023
2062
  const logger = () => typeof g.getLogger === "function" ? g.getLogger() : null;
2024
2063
  function mainSpec() {
2025
- const m = state().readMainMeta();
2026
2064
  return {
2027
2065
  kind: "dsh",
2028
2066
  id: "main",
2029
2067
  name: "\u4E3B\u5B9E\u4F8B",
2030
2068
  desired: state().desired() === "stopped" ? "stopped" : "running",
2031
- guardian: m.guardian === true,
2032
2069
  ownership: {
2033
2070
  ports: [{ role: "dsh-main", port: Number(config().targetPort || 3080) }],
2034
2071
  rootPath: path2.join(os2.homedir(), ".dsh"),
@@ -2048,8 +2085,6 @@ var require_specs = __commonJS({
2048
2085
  kind: "sandbox-instance",
2049
2086
  id: inst.id,
2050
2087
  name: String(inst.name || inst.id),
2051
- desired: inst.state && inst.state.desired === "stopped" ? "stopped" : "running",
2052
- guardian: inst.guardian === true,
2053
2088
  ownership: {
2054
2089
  ports: [{ role: "inst", port: Number(inst.port) }],
2055
2090
  rootPath,
@@ -2063,7 +2098,7 @@ var require_specs = __commonJS({
2063
2098
  if (!m || !spec) return;
2064
2099
  try {
2065
2100
  const existing = m.get(spec.id);
2066
- if (existing) m.update(spec.id, { desired: spec.desired, guardian: spec.guardian, name: spec.name, ownership: spec.ownership });
2101
+ if (existing) m.update(spec.id, { desired: spec.desired, name: spec.name, ownership: spec.ownership });
2067
2102
  else m.register(spec);
2068
2103
  } catch (e) {
2069
2104
  const l = logger();
@@ -3172,6 +3207,14 @@ var require_store2 = __commonJS({
3172
3207
  }
3173
3208
  return out;
3174
3209
  }
3210
+ function fileStamp(file) {
3211
+ try {
3212
+ const st = fs2.statSync(file);
3213
+ return st.mtimeMs + ":" + st.size;
3214
+ } catch {
3215
+ return "0";
3216
+ }
3217
+ }
3175
3218
  function saveRecords(file, records) {
3176
3219
  try {
3177
3220
  fs2.mkdirSync(path2.dirname(file), { recursive: true });
@@ -3197,7 +3240,7 @@ var require_store2 = __commonJS({
3197
3240
  }
3198
3241
  return out;
3199
3242
  }
3200
- module2.exports = { loadRecords, saveRecords, extraRecords };
3243
+ module2.exports = { loadRecords, saveRecords, extraRecords, fileStamp };
3201
3244
  }
3202
3245
  });
3203
3246
 
@@ -3440,6 +3483,7 @@ var require_alloc = __commonJS({
3440
3483
  }
3441
3484
  r._allocLock = true;
3442
3485
  this._xrel = await this._acquireXLock();
3486
+ r._syncFromDisk();
3443
3487
  }
3444
3488
  _releaseAlloc() {
3445
3489
  this._registry._allocLock = false;
@@ -3694,6 +3738,14 @@ var require_pool = __commonJS({
3694
3738
  _load() {
3695
3739
  this._records = /* @__PURE__ */ new Map();
3696
3740
  for (const r of store.loadRecords(this._file)) this._records.set(r.port, r);
3741
+ this._diskStamp = store.fileStamp(this._file);
3742
+ }
3743
+ /** 跨进程对时(B2-5):ports.json 是多进程(守卫 + lan-daemon)共享事实源,各方全量
3744
+ * read-modify-write,陈旧内存快照会在 _save 时把他人新增整段覆盖丢失、或让分配器抢注
3745
+ * 他进程已登记的端口。指纹(mtime+size)变化即重载——所有写口与冲突判读口的入口。
3746
+ * 不动 _allocLock(复位会击穿本进程在飞分配的互斥)。 */
3747
+ _syncFromDisk() {
3748
+ if (store.fileStamp(this._file) !== this._diskStamp) this._load();
3697
3749
  }
3698
3750
  /** 重新从文件加载(读路径先 reload,以权威文件为准)。 */
3699
3751
  reload() {
@@ -3703,6 +3755,7 @@ var require_pool = __commonJS({
3703
3755
  }
3704
3756
  _save() {
3705
3757
  store.saveRecords(this._file, [...this._records.values()]);
3758
+ this._diskStamp = store.fileStamp(this._file);
3706
3759
  }
3707
3760
  /** 通用记录迁移:owner 命中任一前缀的记录 oldFile 到 newFile,并从旧文件清除。 */
3708
3761
  migrateByOwnerPrefix(oldFile, newFile, prefixes) {
@@ -3711,6 +3764,7 @@ var require_pool = __commonJS({
3711
3764
  /* 登记(固定 / 用户 / 动态) */
3712
3765
  /** 登记固定端口;同端口已被其它固定角色占用则报错;user/动态记录由固定权威覆盖。 */
3713
3766
  register(role, port) {
3767
+ this._syncFromDisk();
3714
3768
  const p = Number(port);
3715
3769
  if (!Number.isInteger(p) || p <= 0 || p > 65535) throw new Error("ports.register: \u975E\u6CD5\u7AEF\u53E3 " + port);
3716
3770
  const existing = this._records.get(p);
@@ -3737,6 +3791,7 @@ var require_pool = __commonJS({
3737
3791
  }
3738
3792
  /** 登记用户配置端口(实例内部端口等);冲突(固定/保留池/已占)抛错。 */
3739
3793
  registerUser(port, owner) {
3794
+ this._syncFromDisk();
3740
3795
  const p = Number(port);
3741
3796
  if (!Number.isInteger(p) || p <= 0 || p > 65535) throw new Error("ports.registerUser: \u975E\u6CD5\u7AEF\u53E3 " + port);
3742
3797
  if (this._records.has(p)) throw new Error("\u7AEF\u53E3 " + p + " \u5DF2\u88AB [" + this._records.get(p).role + "] \u5360\u7528");
@@ -3748,6 +3803,7 @@ var require_pool = __commonJS({
3748
3803
  }
3749
3804
  /** 按 owner 释放端口(对象删除/关闭时调用)。 */
3750
3805
  unregister(owner) {
3806
+ this._syncFromDisk();
3751
3807
  let removed = false;
3752
3808
  for (const [p, r] of this._records) {
3753
3809
  if (r.owner === owner) {
@@ -3760,6 +3816,7 @@ var require_pool = __commonJS({
3760
3816
  /** 释放端口:不传 ownerId 按端口号;传了则仅当登记 owner 匹配才释放。空值检查必须先于 owner 比较。
3761
3817
  * @returns {boolean} 是否真的释放了一条记录 */
3762
3818
  release(port, ownerId) {
3819
+ this._syncFromDisk();
3763
3820
  const p = Number(port);
3764
3821
  const rec = this._records.get(p);
3765
3822
  if (!rec) return false;
@@ -3772,6 +3829,7 @@ var require_pool = __commonJS({
3772
3829
  /** 按 role 取端口(固定端口)。同 role 有多条(老版本避让留下的残留记录)时取**最新登记**:
3773
3830
  * 桌面壳读 ports.json 用的是同一判据,两侧不许对「哪个端口是当前的」给出不同答案。 */
3774
3831
  get(role) {
3832
+ this._syncFromDisk();
3775
3833
  let best = null;
3776
3834
  for (const r of this._records.values()) {
3777
3835
  if (r.role !== role) continue;
@@ -3780,12 +3838,15 @@ var require_pool = __commonJS({
3780
3838
  return best ? best.port : null;
3781
3839
  }
3782
3840
  isRegistered(port) {
3841
+ this._syncFromDisk();
3783
3842
  return this._records.has(Number(port));
3784
3843
  }
3785
3844
  recordOf(port) {
3845
+ this._syncFromDisk();
3786
3846
  return this._records.get(Number(port)) || null;
3787
3847
  }
3788
3848
  byOwner(owner) {
3849
+ this._syncFromDisk();
3789
3850
  for (const r of this._records.values()) if (r.owner === owner) return r.port;
3790
3851
  return null;
3791
3852
  }
@@ -3798,6 +3859,7 @@ var require_pool = __commonJS({
3798
3859
  }
3799
3860
  /** 全部端口清单(按端口升序)。 */
3800
3861
  list() {
3862
+ this._syncFromDisk();
3801
3863
  return [...this._records.values()].sort((a, b) => a.port - b.port);
3802
3864
  }
3803
3865
  /** 只读聚合:本注册表 + 同目录下其它注册表文件(去重,本表优先)。
@@ -3822,6 +3884,7 @@ var require_pool = __commonJS({
3822
3884
  }
3823
3885
  /** 显式登记已分配端口(复用持久化端口时调用)。 */
3824
3886
  allocateMark(port, role, owner) {
3887
+ this._syncFromDisk();
3825
3888
  const p = Number(port);
3826
3889
  if (!this._records.has(p)) {
3827
3890
  this._records.set(p, { port: p, role: role || "dynamic", owner: owner || "dynamic", createdAt: Date.now() });
@@ -4016,6 +4079,7 @@ var require_collaborators = __commonJS({
4016
4079
  var { createCtl } = require_collaborator3();
4017
4080
  var { createOrphanScan } = require_collaborator4();
4018
4081
  var { ENTRY_FIELDS, PROC_FIELDS } = require_field_tables();
4082
+ var { aliases: CONFIG_ALIASES } = require_domain_config();
4019
4083
  var THIN_SPEC = {
4020
4084
  ctl: {
4021
4085
  call: "_ctlCall",
@@ -4105,6 +4169,7 @@ var require_collaborators = __commonJS({
4105
4169
  const state = createStateStore({
4106
4170
  getConfig: () => host2.config,
4107
4171
  getConfigPath: () => host2.configPath,
4172
+ getConfigAliases: () => CONFIG_ALIASES,
4108
4173
  getLogger: () => host2.logger,
4109
4174
  getEvents: () => host2.events,
4110
4175
  getManagedObjects: () => host2.managedObjects,
@@ -4150,7 +4215,6 @@ var require_collaborators = __commonJS({
4150
4215
  return host2;
4151
4216
  };
4152
4217
  host2._dshEntry = () => state.dshEntry();
4153
- host2._mainFallbackEntry = () => state.fallbackEntry();
4154
4218
  host2._persistCrashField = () => state.persistCrashField();
4155
4219
  host2._mStore = () => state.store();
4156
4220
  host2._mField = function(name, v) {
@@ -7817,8 +7881,8 @@ var require_instance_adapter = __commonJS({
7817
7881
  return { ok: running, error: running ? null : "\u6C99\u7BB1\u5B9E\u4F8B\u672A\u8FD0\u884C" };
7818
7882
  },
7819
7883
  /** 目录项 <- 实例域状态对齐(监督拍后调用):实例已删 -> 注销(防死登记);存在 -> 经
7820
- * sandboxSpec 同步 name/guardian/ownership + phase 落目录词表。desired 走的是实例意图字段的
7821
- * 投影(不是 phase 推导),所以观测路径写它不会改写任何意图(契约 M-1)。 */
7884
+ * sandboxSpec 同步 name/guardian/ownership + phase 落目录词表。沙箱不申报 desired
7885
+ * (运行意图无第二落点,B2-1),观测路径因此不可能改写任何意图。 */
7822
7886
  _syncSandboxRegistryEntry(entry) {
7823
7887
  const d = depsOf(this);
7824
7888
  if (!entry || !d.managedObjects() || !d.instances()) return;
@@ -7851,6 +7915,9 @@ var require_decide = __commonJS({
7851
7915
  "src/app/main/decide.js"(exports2, module2) {
7852
7916
  "use strict";
7853
7917
  var pidlook = require_pidlookup();
7918
+ function startDeadlinePassed(deadline, now) {
7919
+ return !!(deadline && now > deadline);
7920
+ }
7854
7921
  var DEPS = /* @__PURE__ */ new WeakMap();
7855
7922
  function depsOf(host2) {
7856
7923
  let d = DEPS.get(host2);
@@ -7938,7 +8005,7 @@ var require_decide = __commonJS({
7938
8005
  upgradeHold: d.upgradeHold() === true,
7939
8006
  manualRestart: d.manualRestart() === true,
7940
8007
  spawnBlocked: !!(d.mSpawnBlockedUntil() && now < d.mSpawnBlockedUntil()),
7941
- startDeadlinePassed: !!(d.mStartDeadline() && now > d.mStartDeadline()),
8008
+ startDeadlinePassed: startDeadlinePassed(d.mStartDeadline(), now),
7942
8009
  restartDue: d.mRestartAt() === null || now >= d.mRestartAt(),
7943
8010
  backoffDue: d.mBackoffUntil() === null || now >= d.mBackoffUntil(),
7944
8011
  // `_shouldRun()` 有两个否决位,快照必须建模(crashHalted/sessionHalting),否则影子每拍
@@ -8013,7 +8080,9 @@ var require_decide = __commonJS({
8013
8080
  _decideCrashRestart(reason) {
8014
8081
  return decideCrashRestart(reason);
8015
8082
  }
8016
- }
8083
+ },
8084
+ // 非 host 方法:纯谓词导出,controller 与本文件快照判据共用(facets 只安装 methods)。
8085
+ startDeadlinePassed
8017
8086
  };
8018
8087
  }
8019
8088
  });
@@ -8064,6 +8133,7 @@ var require_controller = __commonJS({
8064
8133
  "use strict";
8065
8134
  var pidlook = require_pidlookup();
8066
8135
  var monitor = require_monitor();
8136
+ var { startDeadlinePassed } = require_decide();
8067
8137
  var DEPS = /* @__PURE__ */ new WeakMap();
8068
8138
  function depsOf(host2) {
8069
8139
  let d = DEPS.get(host2);
@@ -8168,6 +8238,9 @@ var require_controller = __commonJS({
8168
8238
  mStartDeadline() {
8169
8239
  return host2._mStartDeadline();
8170
8240
  },
8241
+ mSetStartDeadline(v) {
8242
+ return host2._mSetStartDeadline(v);
8243
+ },
8171
8244
  mRestartAt() {
8172
8245
  return host2._mRestartAt();
8173
8246
  },
@@ -8315,7 +8388,9 @@ var require_controller = __commonJS({
8315
8388
  }
8316
8389
  case "STARTING": {
8317
8390
  if (portUp && healthOk) d.main().enterRunning();
8318
- else if (Date.now() > d.mStartDeadline()) d.main().beginRestart("start_timeout", { countCrash: true });
8391
+ else if (d.mStartDeadline() === null) {
8392
+ d.mSetStartDeadline(Date.now() + d.config().startTimeoutMs);
8393
+ } else if (startDeadlinePassed(d.mStartDeadline(), Date.now())) d.main().beginRestart("start_timeout", { countCrash: true });
8319
8394
  break;
8320
8395
  }
8321
8396
  case "RUNNING": {
@@ -9569,13 +9644,7 @@ var require_process_wait = __commonJS({
9569
9644
  async function waitProcessExit(pid, timeoutMs) {
9570
9645
  const deadline = Date.now() + timeoutMs;
9571
9646
  while (Date.now() < deadline) {
9572
- let alive = false;
9573
- try {
9574
- alive = pidlook.isAlive ? pidlook.isAlive(pid) : true;
9575
- } catch {
9576
- alive = false;
9577
- }
9578
- if (!alive) return true;
9647
+ if (!pidlook.isAlive(pid)) return true;
9579
9648
  await new Promise((r) => setTimeout(r, 200));
9580
9649
  }
9581
9650
  return false;
@@ -9693,13 +9762,15 @@ var require_process3 = __commonJS({
9693
9762
  } catch {
9694
9763
  }
9695
9764
  }
9765
+ /** 判活(platform/pidlookup.probeAlive 单源):unknown 不 fail-open——必须有第二条证据
9766
+ * (ctl 端口属主正是该 pid 且 cmdline 匹配本服务)才认活,否则按死走 reclaim/spawn。
9767
+ * fail-open 会让已死 daemon 被判活,此后既不接管也不拉起,永不自愈。 */
9696
9768
  _pidAlive(pid) {
9697
9769
  if (!pid) return false;
9698
- try {
9699
- return pidlook.isAlive ? !!pidlook.isAlive(pid) : true;
9700
- } catch {
9701
- return true;
9702
- }
9770
+ const st = pidlook.probeAlive(pid);
9771
+ if (st === "alive") return true;
9772
+ if (st === "dead") return false;
9773
+ return this._ctlOwnerPid() === pid;
9703
9774
  }
9704
9775
  /** ctl 端口的监听者是否就是本服务进程(cmdline 匹配)。 */
9705
9776
  _ctlOwnerPid() {
@@ -10205,6 +10276,7 @@ var require_identity = __commonJS({
10205
10276
  "use strict";
10206
10277
  var fs2 = require("node:fs");
10207
10278
  var path2 = require("node:path");
10279
+ var { isAlive } = require_pidlookup();
10208
10280
  function lockPid(p) {
10209
10281
  if (!p) return null;
10210
10282
  try {
@@ -10215,13 +10287,7 @@ var require_identity = __commonJS({
10215
10287
  }
10216
10288
  }
10217
10289
  function pidAlive2(pid) {
10218
- if (!Number.isInteger(pid) || pid <= 0) return false;
10219
- try {
10220
- process.kill(pid, 0);
10221
- return true;
10222
- } catch (e) {
10223
- return !!(e && e.code === "EPERM");
10224
- }
10290
+ return isAlive(pid);
10225
10291
  }
10226
10292
  function acquireLock2(p, onErr) {
10227
10293
  if (!p) return false;
@@ -10602,7 +10668,7 @@ var require_ports2 = __commonJS({
10602
10668
  "use strict";
10603
10669
  var probe = require_probe2();
10604
10670
  var ports = require_ports().shared;
10605
- var SIBLING_REGISTRIES = ["ports-lan.json", "ports-router.json"];
10671
+ var SIBLING_REGISTRIES = ["ports-router.json"];
10606
10672
  var DEPS = /* @__PURE__ */ new WeakMap();
10607
10673
  function depsOf(host2) {
10608
10674
  let d = DEPS.get(host2);
@@ -11198,24 +11264,32 @@ var require_lan2 = __commonJS({
11198
11264
  }
11199
11265
  }
11200
11266
  return {
11201
- /** 远程控制模式唯一写入口(off|lan|wan)。wan 前置闸:必须先有合规访问令牌。 */
11267
+ /** 远程控制模式唯一写入口(off|lan|wan)。mode 必须显式给出——缺省归 'off' 会让
11268
+ * 漏字段的请求静默关闭远程控制。wan 前置闸:必须先有合规访问令牌。 */
11202
11269
  setRemoteMode(id, mode) {
11203
- const want = mode === "lan" || mode === "wan" ? mode : "off";
11270
+ if (mode !== "off" && mode !== "lan" && mode !== "wan") {
11271
+ return { ok: false, error: "mode \u5FC5\u987B\u663E\u5F0F\u7ED9\u51FA\uFF08off|lan|wan\uFF09" };
11272
+ }
11204
11273
  const target = resolveTarget(id);
11205
11274
  if (!target) return { ok: false, error: "\u5B9E\u4F8B\u4E0D\u5B58\u5728" };
11206
- if (want === "wan") {
11275
+ if (mode === "wan") {
11207
11276
  const v = validateWanAccess({ remoteToken: target.remoteToken });
11208
11277
  if (!v.ok) return { ok: false, error: v.error };
11209
11278
  }
11210
11279
  if (target.kind === "main") {
11211
- if (target.mode !== want) applyMainIntent({ remoteMode: want }, { id: "main", name: "\u539F\u751F DSH", mode: want });
11280
+ if (target.mode !== mode) applyMainIntent({ remoteMode: mode }, { id: "main", name: "\u539F\u751F DSH", mode });
11212
11281
  return { ok: true };
11213
11282
  }
11214
- return g.getInstances().updateInstance(id, { remoteMode: want });
11283
+ return g.getInstances().updateInstance(id, { remoteMode: mode });
11215
11284
  },
11216
- /** 访问令牌唯一写入口(空串=清除;lan 模式可无令牌,wan 模式的守门由执行边界闸兜住)。 */
11285
+ /** 访问令牌唯一写入口。token 必须是字符串:空串=显式清除;缺字段/非字符串=请求方缺陷,
11286
+ * 拒绝而非当作清除(漏 token 字段清掉访问凭据是事故,不是语义)。lan 模式可无令牌,
11287
+ * wan 模式的守门由执行边界闸兜住。 */
11217
11288
  setRemoteToken(id, token) {
11218
- const next = String(token || "");
11289
+ if (typeof token !== "string") {
11290
+ return { ok: false, error: "token \u5FC5\u987B\u663E\u5F0F\u7ED9\u51FA\uFF08\u7A7A\u4E32=\u6E05\u9664\uFF09" };
11291
+ }
11292
+ const next = token;
11219
11293
  if (next && !remoteTokenStrength(next).ok) {
11220
11294
  return { ok: false, error: "\u8FDC\u7A0B\u8BBF\u95EE\u4EE4\u724C\uFF08remoteToken\uFF09\u81F3\u5C11 8 \u4F4D" };
11221
11295
  }
@@ -11299,16 +11373,17 @@ var require_env_catalog = __commonJS({
11299
11373
  const v = ex2.runOut(bin, (Array.isArray(args) ? args : []).concat(["--version"]), { timeoutMs: 3e3 });
11300
11374
  return v ? v.trim() || null : null;
11301
11375
  }
11376
+ function whichVersionAsync(bin, args) {
11377
+ return ex2.runOutAsync(bin, (Array.isArray(args) ? args : []).concat(["--version"]), { timeoutMs: 3e3 }).then((v) => v ? v.trim() || null : null);
11378
+ }
11302
11379
  var _verCache = /* @__PURE__ */ new Map();
11303
11380
  var CACHE_TTL = 1e4;
11304
- function cachedWhichVersion(bin, args) {
11381
+ function cacheKey(bin, args) {
11305
11382
  const a = Array.isArray(args) ? args : [];
11306
- const key = bin + "\0" + a.join("\0");
11307
- const hit = _verCache.get(key);
11308
- const now = Date.now();
11309
- if (hit && now - hit.at < CACHE_TTL) return hit.v;
11310
- const v = whichVersion(bin, a);
11311
- _verCache.set(key, { at: now, v });
11383
+ return bin + "\0" + a.join("\0");
11384
+ }
11385
+ function cacheSet(key, v) {
11386
+ _verCache.set(key, { at: Date.now(), v });
11312
11387
  if (_verCache.size > 16) {
11313
11388
  let oldest = null;
11314
11389
  for (const [k, e] of _verCache) if (!oldest || e.at < oldest.at) oldest = { k, at: e.at };
@@ -11316,6 +11391,19 @@ var require_env_catalog = __commonJS({
11316
11391
  }
11317
11392
  return v;
11318
11393
  }
11394
+ function cachedWhichVersion(bin, args) {
11395
+ const key = cacheKey(bin, args);
11396
+ const hit = _verCache.get(key);
11397
+ const now = Date.now();
11398
+ if (hit && now - hit.at < CACHE_TTL) return hit.v;
11399
+ return cacheSet(key, whichVersion(bin, args));
11400
+ }
11401
+ function cachedWhichVersionAsync(bin, args) {
11402
+ const key = cacheKey(bin, args);
11403
+ const hit = _verCache.get(key);
11404
+ if (hit && Date.now() - hit.at < CACHE_TTL) return Promise.resolve(hit.v);
11405
+ return whichVersionAsync(bin, args).then((v) => cacheSet(key, v));
11406
+ }
11319
11407
  var MIN_NODE_DEFAULT = "v22.12.0";
11320
11408
  var _runtimeMetaCache = null;
11321
11409
  var _runtimeMetaAt = 0;
@@ -11342,50 +11430,68 @@ var require_env_catalog = __commonJS({
11342
11430
  }
11343
11431
  return true;
11344
11432
  }
11345
- function probeNode() {
11346
- const v = cachedWhichVersion("node");
11433
+ function nodeVerdict(v) {
11347
11434
  if (!v) return null;
11348
11435
  const m = /v?(\d+\.\d+\.\d+)/.exec(String(v));
11349
11436
  const ver = m ? m[1] : String(v).trim();
11350
11437
  const min = String(runtimeMeta().minNode || MIN_NODE_DEFAULT);
11351
11438
  return { version: "v" + ver, min, meets: verAtLeast(ver, min) };
11352
11439
  }
11440
+ function probeNode() {
11441
+ return nodeVerdict(cachedWhichVersion("node"));
11442
+ }
11443
+ function probeNodeAsync() {
11444
+ return cachedWhichVersionAsync("node").then(nodeVerdict);
11445
+ }
11353
11446
  function probeNpm() {
11354
11447
  const l = runtime.npmLauncher();
11355
11448
  return cachedWhichVersion(l.program, l.args);
11356
11449
  }
11450
+ function probeNpmAsync() {
11451
+ const l = runtime.npmLauncher();
11452
+ return cachedWhichVersionAsync(l.program, l.args);
11453
+ }
11357
11454
  var SYSTEM_ENTRIES = {
11358
- node: { label: "Node.js", required: true, probe: probeNode },
11359
- npm: { label: "npm", required: true, probe: probeNpm },
11360
- git: { label: "git", required: false, probe: () => cachedWhichVersion("git") }
11455
+ node: { label: "Node.js", required: true, probe: probeNode, probeAsync: probeNodeAsync },
11456
+ npm: { label: "npm", required: true, probe: probeNpm, probeAsync: probeNpmAsync },
11457
+ git: { label: "git", required: false, probe: () => cachedWhichVersion("git"), probeAsync: () => cachedWhichVersionAsync("git") }
11361
11458
  };
11459
+ function entryView(id, e, v) {
11460
+ if (v && typeof v === "object" && typeof v.meets === "boolean") {
11461
+ return {
11462
+ label: e.label,
11463
+ required: e.required,
11464
+ state: v.meets ? "ok" : "outdated",
11465
+ version: v.version,
11466
+ min: v.min,
11467
+ meets: v.meets,
11468
+ detail: v.meets ? v.version : v.version + "\uFF08\u4F4E\u4E8E\u6700\u4F4E\u8981\u6C42 " + v.min + "\uFF09"
11469
+ };
11470
+ }
11471
+ return { label: e.label, required: e.required, state: v ? "ok" : "missing", detail: v };
11472
+ }
11362
11473
  var EnvCatalog = class {
11363
11474
  constructor(config) {
11364
11475
  this.config = config || {};
11365
11476
  }
11366
- /** 系统二进制条目探测:{ id: { label, required, state, detail } }。state 三态:
11367
- * ok = 存在且满足门槛(Node 需 >= 壳投放的 minNode);outdated = 存在但低于门槛;missing = 不存在。
11368
- * 兼容:detail 保持字符串,新增字段(version/min/meets)放 detail 之外,不破坏既有契约。 */
11477
+ /** 系统二进制条目探测(同步口径):{ id: 条目视图 }。仅限启动早期/CLI;HTTP 路径用 probeAsync。 */
11369
11478
  probe() {
11370
11479
  const out = {};
11371
11480
  for (const [id, e] of Object.entries(SYSTEM_ENTRIES)) {
11372
- const v = e.probe() || null;
11373
- if (v && typeof v === "object" && typeof v.meets === "boolean") {
11374
- out[id] = {
11375
- label: e.label,
11376
- required: e.required,
11377
- state: v.meets ? "ok" : "outdated",
11378
- version: v.version,
11379
- min: v.min,
11380
- meets: v.meets,
11381
- detail: v.meets ? v.version : v.version + "\uFF08\u4F4E\u4E8E\u6700\u4F4E\u8981\u6C42 " + v.min + "\uFF09"
11382
- };
11383
- } else {
11384
- out[id] = { label: e.label, required: e.required, state: v ? "ok" : "missing", detail: v };
11385
- }
11481
+ out[id] = entryView(id, e, e.probe() || null);
11386
11482
  }
11387
11483
  return out;
11388
11484
  }
11485
+ /** 异步口径:条目并行探测(最坏 3s x N 的串行冻结 -> 全程不阻塞事件循环)。 */
11486
+ async probeAsync() {
11487
+ const entries = Object.entries(SYSTEM_ENTRIES);
11488
+ const vals = await Promise.all(entries.map(([, e]) => e.probeAsync()));
11489
+ const out = {};
11490
+ entries.forEach(([id, e], i) => {
11491
+ out[id] = entryView(id, e, vals[i] || null);
11492
+ });
11493
+ return out;
11494
+ }
11389
11495
  /** 内核更新依赖条目(单写入者契约:安装/重启归桌面壳,守卫只读 corePackageName 查版本状态)。
11390
11496
  * id 仍为 selfUpdate 以兼容既有 /env/status 消费方。 */
11391
11497
  selfUpdateEntry() {
@@ -11429,20 +11535,22 @@ var require_env = __commonJS({
11429
11535
  var fs2 = require("node:fs");
11430
11536
  var { EnvCatalog } = require_env_catalog();
11431
11537
  var runtimeContract = require_runtime();
11432
- function envCatalogSummary(that) {
11538
+ async function envCatalogSummary(that) {
11433
11539
  const cat = new EnvCatalog(that.config);
11434
11540
  const extra = {};
11435
11541
  const d = that.dshenvStatus();
11436
11542
  extra.dsh = cat.dshEntry(d.binOk, d.installed, d.bin);
11437
11543
  extra.selfUpdate = cat.selfUpdateEntry();
11438
- return cat.summary(extra);
11544
+ return cat.summary(extra, await cat.probeAsync());
11439
11545
  }
11440
11546
  module2.exports = {
11441
11547
  methods: {
11442
- envStatus() {
11548
+ // 异步:全部子进程探测(EnvCatalog/契约回读)走异步口径——本方法挂在 /env/status 上,
11549
+ // 同步 execFileSync 会把守卫事件循环冻结在探测超时上(心跳/自愈停摆,B1-6 收口)。
11550
+ async envStatus() {
11443
11551
  const c = runtimeContract.read() || {};
11444
- const cat = new EnvCatalog(this.config).probe();
11445
- const en = this.nativeManager && typeof this.nativeManager.checkEnvironment === "function" ? this.nativeManager.checkEnvironment() : null;
11552
+ const cat = await new EnvCatalog(this.config).probeAsync();
11553
+ const en = this.nativeManager && typeof this.nativeManager.checkEnvironment === "function" ? await this.nativeManager.checkEnvironment() : null;
11446
11554
  return {
11447
11555
  node: { detected: cat.node.detail || null, runtime: c.nodeVersion || null, path: c.nodePath || null },
11448
11556
  // npm 与 node 同构三段:detected = 本机实跑版本;runtime = 壳实跑后投放的版本
@@ -11454,7 +11562,7 @@ var require_env = __commonJS({
11454
11562
  ok: cat.node.state === "ok" && cat.npm.state === "ok",
11455
11563
  npmRoot: en ? en.npmRoot : null,
11456
11564
  // EnvCatalog 声明式视图(面板环境卡用)
11457
- catalog: envCatalogSummary(this),
11565
+ catalog: await envCatalogSummary(this),
11458
11566
  // 平台能力矩阵:三平台静态档位 x 实际工具探测;前端据此做能力感知呈现与降级提示。
11459
11567
  capabilities: (() => {
11460
11568
  try {
@@ -11680,15 +11788,16 @@ var require_versions = __commonJS({
11680
11788
  return { ok: false, error: e.message };
11681
11789
  }
11682
11790
  },
11683
- /** 读磁盘上运行位的自报版本:spawn --version,解析版本行。
11791
+ /** 读磁盘上运行位的自报版本:spawn --version,解析版本行(异步:20s 上限的同步 exec
11792
+ * 在 HTTP 路径上会冻结守卫整条事件循环,判据不变)。
11684
11793
  * 条件是 updatable(sea-binary 或 launcher):launcher 的 bin 入口同样可执行,
11685
11794
  * 若只认 sea-binary 则发布态永远读不到磁盘实况,updatePending 恒 false。
11686
11795
  * source-shell 不支持:其 --version 报的是开发目录版本,与 npm 安装无关。 */
11687
- _readBinarySelfVersion() {
11796
+ async _readBinarySelfVersion() {
11688
11797
  const dep = deploy.detect();
11689
11798
  if (!dep.updatable || !dep.runningTarget) return null;
11690
11799
  try {
11691
- const out = ex2.runOut(dep.runningTarget, ["--version"], { timeoutMs: 2e4 });
11800
+ const out = await ex2.runOutAsync(dep.runningTarget, ["--version"], { timeoutMs: 2e4 });
11692
11801
  const m = /dsh-supervisor v([^\s]+)/.exec(out);
11693
11802
  return m ? m[1] : null;
11694
11803
  } catch {
@@ -11710,18 +11819,18 @@ var require_versions = __commonJS({
11710
11819
  }
11711
11820
  return dir;
11712
11821
  },
11713
- /** 本地视角(无网络 I/O,同步安全):commit + 是否配了 upstream。 */
11714
- guardVersionLocal() {
11822
+ /** 本地视角(无网络 I/O;git 子进程异步执行——同步 spawn 会冻结事件循环,
11823
+ * 消费方含 HTTP 路径,见 exec.js 同步仅限启动早期/CLI 的纪律)。 */
11824
+ async guardVersionLocal() {
11715
11825
  const d = depsOf(this);
11716
11826
  const root = d.vcsRoot();
11717
- let commit = null;
11718
- commit = (ex2.runOut("git", ["-C", root, "rev-parse", "--short", "HEAD"]) || "").trim() || null;
11827
+ const [rawCommit, rawUp] = await Promise.all([
11828
+ ex2.runOutAsync("git", ["-C", root, "rev-parse", "--short", "HEAD"]),
11829
+ ex2.runOutAsync("git", ["-C", root, "rev-parse", "--abbrev-ref", "@{u}"])
11830
+ ]);
11831
+ const commit = (rawCommit || "").trim() || null;
11719
11832
  let upstream = "local";
11720
- try {
11721
- const up = (ex2.runOut("git", ["-C", root, "rev-parse", "--abbrev-ref", "@{u}"]) || "").trim();
11722
- if (up) upstream = "git-repo";
11723
- } catch {
11724
- }
11833
+ if ((rawUp || "").trim()) upstream = "git-repo";
11725
11834
  return { version: d.guardVersion(), runningVersion: d.guardVersion(), commit, updateAvailable: false, upstream, latest: d.guardVersion() };
11726
11835
  },
11727
11836
  /** 完整版本检查(async):本地 commit + 远端 fetch 比对。
@@ -11729,20 +11838,17 @@ var require_versions = __commonJS({
11729
11838
  * fetch 失败/超时只降级为「本地视图」,不抛错。 */
11730
11839
  async guardVersionCheck() {
11731
11840
  const d = depsOf(this);
11732
- const base = d.guardVersionLocal();
11841
+ const base = await d.guardVersionLocal();
11733
11842
  if (base.upstream !== "git-repo") return base;
11734
11843
  const root = d.vcsRoot();
11735
11844
  const fetchOk = await ex2.runOutAsync("git", ["-C", root, "fetch", "--quiet"], { timeoutMs: 1e4 }) !== null;
11736
11845
  if (!fetchOk) return base;
11737
11846
  let updateAvailable = false;
11738
- try {
11739
- const ahead = (ex2.runOut("git", ["-C", root, "rev-list", "--count", "HEAD..@{u}"]) || "").trim();
11740
- updateAvailable = parseInt(ahead, 10) > 0;
11741
- } catch {
11742
- }
11847
+ const ahead = (await ex2.runOutAsync("git", ["-C", root, "rev-list", "--count", "HEAD..@{u}"], { timeoutMs: 1e4 }) || "").trim();
11848
+ updateAvailable = parseInt(ahead, 10) > 0;
11743
11849
  const dep = deploy.detect();
11744
11850
  let diskVersion = null;
11745
- if (dep.updatable) diskVersion = d.readBinarySelfVersion();
11851
+ if (dep.updatable) diskVersion = await d.readBinarySelfVersion();
11746
11852
  const updatePending = !!(diskVersion && diskVersion !== d.guardVersion());
11747
11853
  return { ...base, diskVersion, updatePending };
11748
11854
  }
@@ -11826,7 +11932,9 @@ var require_access = __commonJS({
11826
11932
  return { ok: false, error: e.message };
11827
11933
  }
11828
11934
  }
11829
- }
11935
+ },
11936
+ // settings 门面的写口核验件(B2-4):lan-panel 共用同一「写后读回」口径,不各写各的。
11937
+ verifyPersisted
11830
11938
  };
11831
11939
  }
11832
11940
  });
@@ -11933,9 +12041,8 @@ var require_netinfo = __commonJS({
11933
12041
  var require_lan_panel = __commonJS({
11934
12042
  "src/app/settings/lan-panel.js"(exports2, module2) {
11935
12043
  "use strict";
11936
- var fs2 = require("node:fs");
11937
12044
  var netInfo = require_netinfo();
11938
- var { writeAtomic } = require_fs();
12045
+ var { verifyPersisted } = require_access();
11939
12046
  var DEPS = /* @__PURE__ */ new WeakMap();
11940
12047
  function depsOf(host2) {
11941
12048
  let d = DEPS.get(host2);
@@ -11945,6 +12052,7 @@ var require_lan_panel = __commonJS({
11945
12052
  logger: () => host2.logger,
11946
12053
  events: () => host2.events,
11947
12054
  configPath: () => host2.configPath,
12055
+ state: () => host2.state,
11948
12056
  api: () => host2.api,
11949
12057
  lanPanelStatus: () => host2.lanPanelStatus(),
11950
12058
  apiRebind: () => host2._apiRebind()
@@ -11986,14 +12094,9 @@ var require_lan_panel = __commonJS({
11986
12094
  d.config().apiHost = host2;
11987
12095
  let persistError = null;
11988
12096
  if (d.configPath()) {
11989
- try {
11990
- const doc = JSON.parse(fs2.readFileSync(d.configPath(), "utf8"));
11991
- doc.apiHost = host2;
11992
- writeAtomic(d.configPath(), JSON.stringify(doc, null, 2), { mode: 384 });
11993
- } catch (e) {
11994
- persistError = "persist apiHost: " + e.message;
11995
- d.logger().error(persistError);
11996
- }
12097
+ d.state().persistConfigPatch({ apiHost: host2 });
12098
+ persistError = verifyPersisted(d.configPath(), { apiHost: host2 });
12099
+ if (persistError) d.logger().error(persistError);
11997
12100
  }
11998
12101
  if (changed && d.api() && typeof d.api().close === "function") d.apiRebind();
11999
12102
  if (d.events()) d.events().append("lan_panel_changed", { enabled: on });
@@ -12611,6 +12714,8 @@ var require_pool2 = __commonJS({
12611
12714
  this._bus = new FollowBus({ logger: this.logger });
12612
12715
  this._schedules = /* @__PURE__ */ new Map();
12613
12716
  this._seq = 0;
12717
+ this._attachGen = /* @__PURE__ */ new Map();
12718
+ this._journalFn = o.journal || capture.captureJournal;
12614
12719
  this._backfillAt = /* @__PURE__ */ new Map();
12615
12720
  this._poolFile = o.poolFile ? path2.resolve(o.poolFile) : null;
12616
12721
  this._loaded = false;
@@ -12635,6 +12740,7 @@ var require_pool2 = __commonJS({
12635
12740
  const unit = s.unit || prev && prev.unit || null;
12636
12741
  const file = s.file || prev && prev.file || null;
12637
12742
  this._sources.set(id, { kind, unit, file, lines: prev && prev.lines || [] });
12743
+ this._attachGen.set(id, (this._attachGen.get(id) || 0) + 1);
12638
12744
  const rec = this._records.get(id);
12639
12745
  if (rec) rec.kind = kind;
12640
12746
  return true;
@@ -12659,9 +12765,16 @@ var require_pool2 = __commonJS({
12659
12765
  return this._commit(id, hit.token, hit.source);
12660
12766
  }
12661
12767
  if (src.unit && kinds.isCaptured(src.kind)) {
12662
- Promise.resolve().then(() => capture.captureJournal(src.unit, { logger: this.logger })).then((j) => {
12768
+ const gen = this._attachGen.get(id) || 0;
12769
+ const fresh = () => (this._attachGen.get(id) || 0) === gen ? this._sources.get(id) : null;
12770
+ Promise.resolve().then(() => {
12771
+ const cur = fresh();
12772
+ return cur ? this._journalFn(cur.unit, { logger: this.logger }) : null;
12773
+ }).then((j) => {
12663
12774
  if (!j) return;
12664
- if (src.file) this._persistLine(id, src.file, j.line);
12775
+ const cur = fresh();
12776
+ if (!cur) return;
12777
+ if (cur.file) this._persistLine(id, cur.file, j.line);
12665
12778
  this._commit(id, j.token, j.source);
12666
12779
  }).catch(() => {
12667
12780
  });
@@ -12729,6 +12842,7 @@ var require_pool2 = __commonJS({
12729
12842
  this._backfillAt.delete(id);
12730
12843
  const src = this._sources.get(id);
12731
12844
  if (src && src.lines && src.lines.length) src.lines.length = 0;
12845
+ this._attachGen.set(id, (this._attachGen.get(id) || 0) + 1);
12732
12846
  this._records.delete(id);
12733
12847
  this._persistPool();
12734
12848
  this._bus.emit(id, null, null);
@@ -13659,7 +13773,6 @@ var require_core5 = __commonJS({
13659
13773
  host2._routerFacade = null;
13660
13774
  host2._lc = null;
13661
13775
  host2._dshMainLive = null;
13662
- host2._fallbackEntry = null;
13663
13776
  host2._lastStateBody = null;
13664
13777
  host2._shadowSeq = 0;
13665
13778
  host2._shadowConsistentBeats = 0;
@@ -17206,10 +17319,11 @@ var require_oauth = __commonJS({
17206
17319
  const d = deps || {};
17207
17320
  const ports = d.ports;
17208
17321
  const openInBrowser = d.openInBrowser;
17209
- const st = { _ccLogin: null, _ccLoginPromise: null, _ccLoginResolve: null, _ccLoginReject: null };
17322
+ const st = { _ccLogin: null, _ccLoginPromise: null, _ccLoginResolve: null, _ccLoginReject: null, _ccLoginRound: 0 };
17210
17323
  async function commandcodeLoginStart() {
17211
17324
  const STUDIO_BASE = "https://commandcode.ai";
17212
17325
  const state = crypto.randomBytes(32).toString("base64url");
17326
+ const roundId = ++st._ccLoginRound;
17213
17327
  if (st._ccLogin && st._ccLogin.server) {
17214
17328
  const oldState = st._ccLogin.state;
17215
17329
  try {
@@ -17271,6 +17385,11 @@ var require_oauth = __commonJS({
17271
17385
  if (b.length > 1e4) req.destroy();
17272
17386
  });
17273
17387
  req.on("end", () => {
17388
+ if (st._ccLoginRound !== roundId) {
17389
+ res.writeHead(410);
17390
+ res.end(callbackJson({ success: false, error: "Stale login round" }));
17391
+ return;
17392
+ }
17274
17393
  try {
17275
17394
  const j = JSON.parse(b || "{}");
17276
17395
  if (j && typeof j === "object" && "error" in j) {
@@ -17361,6 +17480,7 @@ var require_oauth = __commonJS({
17361
17480
  });
17362
17481
  st._ccLoginPromise = promise;
17363
17482
  const tmpProfile = openInBrowser(authUrl, () => {
17483
+ if (st._ccLoginRound !== roundId) return;
17364
17484
  if (st._ccLoginReject) {
17365
17485
  const r = st._ccLoginReject;
17366
17486
  st._ccLoginReject = null;
@@ -19247,10 +19367,7 @@ var require_model3 = __commonJS({
19247
19367
  inst.state.lastError = null;
19248
19368
  }
19249
19369
  if (inst.state) inst.state.phase = inst.state.phase || "STOPPED";
19250
- if (inst.state && inst.state.desired === void 0) {
19251
- const p = inst.state.phase;
19252
- inst.state.desired = p === "RUNNING" || p === "STARTING" || p === "INSTALLING" ? "running" : "stopped";
19253
- }
19370
+ if (inst.state) delete inst.state.desired;
19254
19371
  return inst;
19255
19372
  }
19256
19373
  function createRecord(payload, id) {
@@ -19275,7 +19392,7 @@ var require_model3 = __commonJS({
19275
19392
  protectHome: payload.protectHome === void 0 ? false : !!payload.protectHome
19276
19393
  // 资源配额不接收户输入:启动时由 governor 按机器预算与活跃实例数推导。
19277
19394
  },
19278
- state: { phase: "STOPPED", desired: "stopped", restartCount: 0, backoffLevel: 0, lastProbeOk: null },
19395
+ state: { phase: "STOPPED", restartCount: 0, backoffLevel: 0, lastProbeOk: null },
19279
19396
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
19280
19397
  };
19281
19398
  }
@@ -19515,6 +19632,7 @@ var require_lifecycle = __commonJS({
19515
19632
  "use strict";
19516
19633
  var fs2 = require("node:fs");
19517
19634
  var monitor = require_monitor();
19635
+ var ports = require_ports().shared;
19518
19636
  var guardian = require_guardian();
19519
19637
  var sandbox = require_sandbox();
19520
19638
  var governor = require_governor();
@@ -19557,7 +19675,7 @@ var require_lifecycle = __commonJS({
19557
19675
  logger.info && logger.info("cleaned stale transient unit: " + unit);
19558
19676
  }
19559
19677
  }
19560
- function _systemdStart(inst) {
19678
+ function _systemdStart(inst, opts) {
19561
19679
  try {
19562
19680
  const cmdArr = sandbox.effectiveCommand(instancesRoot, deps.dshBin, inst);
19563
19681
  if (!cmdArr || !cmdArr.length) return { ok: false, error: "\u5B9E\u4F8B\u672A\u914D\u7F6E\u542F\u52A8\u547D\u4EE4" };
@@ -19573,6 +19691,15 @@ var require_lifecycle = __commonJS({
19573
19691
  logger.warn && logger.warn("[" + inst.id + "] " + msg);
19574
19692
  return { ok: false, error: msg };
19575
19693
  }
19694
+ const takenBy = ports.recordOf(inst.port);
19695
+ if (takenBy && takenBy.owner !== "inst:" + inst.id) {
19696
+ const msg = "PORT_TAKEN:" + (takenBy.owner || takenBy.role);
19697
+ inst.state.lastError = msg;
19698
+ store.save();
19699
+ if (events) events.append("inst_start_refused", { id: inst.id, name: inst.name, error: msg });
19700
+ logger.warn && logger.warn("[" + inst.id + "] " + msg);
19701
+ return { ok: false, error: msg };
19702
+ }
19576
19703
  if (probe(inst).running) return { ok: false, error: "\u7AEF\u53E3 " + inst.port + " \u5DF2\u88AB\u5360\u7528" };
19577
19704
  const alloc = governor.currentAllocation(store.instances, inst.id, machineFactsNow());
19578
19705
  inst.state.allocation = alloc;
@@ -19592,6 +19719,12 @@ var require_lifecycle = __commonJS({
19592
19719
  inst.state.phase = "STARTING";
19593
19720
  inst.state.startAt = Date.now();
19594
19721
  inst.state.lastError = null;
19722
+ if (opts && opts.manual) {
19723
+ inst.state.restartCount = 0;
19724
+ inst.state.backoffLevel = 0;
19725
+ inst.state.backoffUntil = null;
19726
+ inst.state.lastFailAt = null;
19727
+ }
19595
19728
  store.save();
19596
19729
  if (inst.port && hooks.onInstanceStart) hooks.onInstanceStart(inst);
19597
19730
  if (events) events.append("inst_started", { id: inst.id, port: inst.port });
@@ -19617,10 +19750,6 @@ var require_lifecycle = __commonJS({
19617
19750
  return { ok: false, error: adm.error };
19618
19751
  }
19619
19752
  }
19620
- if (inst.state.desired !== "running") {
19621
- inst.state.desired = "running";
19622
- store.save();
19623
- }
19624
19753
  store.ensureDirs(inst);
19625
19754
  const dshEntry = sandbox.dshEntry(instancesRoot, inst);
19626
19755
  if (!fs2.existsSync(dshEntry)) {
@@ -19629,10 +19758,9 @@ var require_lifecycle = __commonJS({
19629
19758
  return { ok: true, installing: true };
19630
19759
  }
19631
19760
  }
19632
- return _systemdStart(inst);
19761
+ return _systemdStart(inst, opts);
19633
19762
  }
19634
- function stop(id, opts) {
19635
- const transient = !!(opts && opts.intent === "transient");
19763
+ function stop(id) {
19636
19764
  const inst = store.instances.find((i) => i.id === id);
19637
19765
  if (!inst) return { ok: false, error: "\u5B9E\u4F8B\u4E0D\u5B58\u5728" };
19638
19766
  if (!isSandboxSupported()) return { ok: false, error: "\u5F53\u524D\u5E73\u53F0\u4E0D\u652F\u6301\u6C99\u7BB1\u5B9E\u4F8B\uFF08\u80FD\u529B\u77E9\u9635\u89C1 GET /env/status \u7684 capabilities.sandboxLaunch\uFF1B\u9650\u989D\u6267\u884C\u6863\u4F4D\u89C1 capabilities.sandboxEnforcement\uFF09" };
@@ -19654,7 +19782,6 @@ var require_lifecycle = __commonJS({
19654
19782
  }
19655
19783
  inst.state.phase = "STOPPED";
19656
19784
  inst.state.usage = null;
19657
- if (!transient) inst.state.desired = "stopped";
19658
19785
  runtime.delete(inst.id);
19659
19786
  store.save();
19660
19787
  if (inst.port && hooks.onInstanceStop) hooks.onInstanceStop(inst);
@@ -19710,15 +19837,17 @@ var require_lifecycle = __commonJS({
19710
19837
  }).catch(() => {
19711
19838
  });
19712
19839
  }
19840
+ }
19841
+ function governSweep() {
19713
19842
  const roster = _sandboxRoster();
19714
- if (!roster.length) return;
19843
+ if (!roster.length) return { ok: true, entries: 0 };
19715
19844
  let plan;
19716
19845
  try {
19717
19846
  const f = machineFactsNow();
19718
19847
  plan = governor.decide({ totalMemBytes: f.totalMemBytes, cpuCount: f.cpuCount, roster });
19719
19848
  } catch (e) {
19720
- logger.warn && logger.warn("[" + inst.id + "] govern decide \u5931\u8D25: " + (e && e.message));
19721
- return;
19849
+ logger.warn && logger.warn("govern decide \u5931\u8D25: " + (e && e.message));
19850
+ return { ok: false, error: e && e.message || String(e) };
19722
19851
  }
19723
19852
  const now = Date.now();
19724
19853
  for (const entry of plan.entries) {
@@ -19743,19 +19872,21 @@ var require_lifecycle = __commonJS({
19743
19872
  }
19744
19873
  }
19745
19874
  }
19746
- if (!entry.violation || entry.id !== inst.id) continue;
19875
+ if (!entry.violation) continue;
19747
19876
  const v = entry.violation;
19748
19877
  const kindLabel = v.kind === "memory" ? "\u5185\u5B58" : "CPU";
19749
19878
  const reason = "\u8D44\u6E90\u8FDD\u89C4:" + kindLabel + "\u6301\u7EED\u8D85\u9650(\u5B9E\u9645 " + v.actual + "/\u9650\u989D " + v.target + ")";
19750
- if (events) events.append("inst_resource_violation", { id: inst.id, name: inst.name, kind: v.kind, actual: v.actual, target: v.target });
19751
- logger.warn && logger.warn("[" + inst.id + "] " + reason);
19879
+ if (events) events.append("inst_resource_violation", { id: target.id, name: target.name, kind: v.kind, actual: v.actual, target: v.target });
19880
+ logger.warn && logger.warn("[" + target.id + "] " + reason);
19752
19881
  try {
19753
- service.stopUnit("dsh-web@" + inst.id, Object.assign({ timeoutMs: 2e4 }, sandbox.launchCtx(instancesRoot, deps.dshBin, inst)));
19882
+ service.stopUnit("dsh-web@" + target.id, Object.assign({ timeoutMs: 2e4 }, sandbox.launchCtx(instancesRoot, deps.dshBin, target)));
19754
19883
  } catch (e) {
19755
- logger.warn && logger.warn("[" + inst.id + "] \u8FDD\u89C4\u505C\u5355\u5143\u5F02\u5E38: " + (e && e.message));
19884
+ logger.warn && logger.warn("[" + target.id + "] \u8FDD\u89C4\u505C\u5355\u5143\u5F02\u5E38: " + (e && e.message));
19756
19885
  }
19757
- stateMachine.restart(stateDeps(), inst, reason);
19886
+ stateMachine.restart(stateDeps(), target, reason);
19758
19887
  }
19888
+ store.save();
19889
+ return { ok: true, entries: plan.entries.length };
19759
19890
  }
19760
19891
  function supervise(id) {
19761
19892
  const inst = store.instances.find((i) => i.id === id);
@@ -19849,7 +19980,7 @@ var require_lifecycle = __commonJS({
19849
19980
  }
19850
19981
  return { ok: true };
19851
19982
  }
19852
- return { _prepareSystemd, start, stop, probe, probeInstance, supervise };
19983
+ return { _prepareSystemd, start, stop, probe, probeInstance, supervise, governSweep };
19853
19984
  }
19854
19985
  module2.exports = { createLifecycle };
19855
19986
  }
@@ -20158,7 +20289,7 @@ var require_upgrade = __commonJS({
20158
20289
  tasks.stepState(task.id, tasks.get(task.id).steps.indexOf(s), "running");
20159
20290
  }
20160
20291
  try {
20161
- await lifecycle.stop(id, { intent: "transient" });
20292
+ await lifecycle.stop(id);
20162
20293
  } catch {
20163
20294
  }
20164
20295
  if (task) {
@@ -20206,7 +20337,7 @@ var require_upgrade = __commonJS({
20206
20337
  tasks.log(task.id, "\u81EA\u52A8\u56DE\u6EDA\u5230 " + oldVersion + "\u2026");
20207
20338
  }
20208
20339
  try {
20209
- const rs = await lifecycle.stop(id, { intent: "transient" });
20340
+ const rs = await lifecycle.stop(id);
20210
20341
  if (rs && rs.ok === false && task) tasks.log(task.id, "\u56DE\u6EDA\u524D\u505C\u6B62\u5931\u8D25\uFF08\u7EE7\u7EED\u56DE\u88C5\u65E7\u7248\uFF09\uFF1A" + (rs.error || ""));
20211
20342
  } catch (e) {
20212
20343
  if (task) tasks.log(task.id, "\u56DE\u6EDA\u524D\u505C\u6B62\u5F02\u5E38\uFF08\u7EE7\u7EED\u56DE\u88C5\u65E7\u7248\uFF09\uFF1A" + (e && e.message || e));
@@ -20493,6 +20624,11 @@ var require_ops2 = __commonJS({
20493
20624
  } catch {
20494
20625
  }
20495
20626
  }
20627
+ try {
20628
+ lifecycle.governSweep();
20629
+ } catch (e) {
20630
+ logger.warn && logger.warn("governSweep: " + (e && e.message));
20631
+ }
20496
20632
  }, intervalMs || 5e3);
20497
20633
  }
20498
20634
  return { list, addInstance, removeInstance, updateInstance, startTimer };
@@ -20785,12 +20921,16 @@ var require_instance = __commonJS({
20785
20921
  startInstance(id, opts) {
20786
20922
  return this._lifecycle.start(id, opts);
20787
20923
  }
20788
- stopInstance(id, opts) {
20789
- return this._lifecycle.stop(id, opts);
20924
+ stopInstance(id) {
20925
+ return this._lifecycle.stop(id);
20790
20926
  }
20791
20927
  supervise(id) {
20792
20928
  return this._lifecycle.supervise(id);
20793
20929
  }
20930
+ /** 治理单拍(B2-6e):心跳拍末由 onBeatDone 调一次,全花名册 decide+下发+违规处置。 */
20931
+ governSweep() {
20932
+ return this._lifecycle.governSweep();
20933
+ }
20794
20934
  probeInstance(id) {
20795
20935
  return this._lifecycle.probeInstance(id);
20796
20936
  }
@@ -21112,8 +21252,6 @@ var require_market = __commonJS({
21112
21252
  this._ts = 0;
21113
21253
  this._inFlight = null;
21114
21254
  this.buildBudgetMs = opts.buildBudgetMs || 24e4;
21115
- this._deadline = 0;
21116
- this._truncatedSources = /* @__PURE__ */ new Set();
21117
21255
  this.loadFromDisk();
21118
21256
  }
21119
21257
  loadFromDisk() {
@@ -21160,19 +21298,18 @@ var require_market = __commonJS({
21160
21298
  }
21161
21299
  async buildIndex() {
21162
21300
  const start = Date.now();
21163
- this._deadline = Date.now() + this.buildBudgetMs;
21164
- this._truncatedSources = /* @__PURE__ */ new Set();
21301
+ const bctx = { deadline: start + this.buildBudgetMs, truncated: /* @__PURE__ */ new Set() };
21165
21302
  try {
21166
- return await this._buildIndexInner(start);
21303
+ return await this._buildIndexInner(start, bctx);
21167
21304
  } finally {
21168
- this._deadline = 0;
21305
+ bctx.deadline = 0;
21169
21306
  }
21170
21307
  }
21171
- /** 预算是否已耗尽(供各源的批次循环调用)。 */
21172
- _budgetExhausted() {
21173
- return this._deadline > 0 && Date.now() >= this._deadline;
21308
+ /** 预算是否已耗尽(供各源的批次循环调用;无 ctx = 单源直调,不设预算)。 */
21309
+ _budgetExhausted(bctx) {
21310
+ return !!bctx && bctx.deadline > 0 && Date.now() >= bctx.deadline;
21174
21311
  }
21175
- async _buildIndexInner(start) {
21312
+ async _buildIndexInner(start, bctx) {
21176
21313
  const plugins = [];
21177
21314
  const seen = /* @__PURE__ */ new Set();
21178
21315
  const add = (p) => {
@@ -21180,11 +21317,11 @@ var require_market = __commonJS({
21180
21317
  seen.add(p.name);
21181
21318
  plugins.push(p);
21182
21319
  };
21183
- const npm = await this.indexNpm();
21320
+ const npm = await this.indexNpm(bctx);
21184
21321
  npm.forEach(add);
21185
- const gh = await this.indexGithub();
21322
+ const gh = await this.indexGithub(bctx);
21186
21323
  gh.forEach(add);
21187
- const community = await this.indexCommunity();
21324
+ const community = await this.indexCommunity(bctx);
21188
21325
  community.forEach(add);
21189
21326
  for (const p of plugins) {
21190
21327
  p.category = p.category || classify(p);
@@ -21192,7 +21329,7 @@ var require_market = __commonJS({
21192
21329
  }
21193
21330
  plugins.sort((a, b) => (b.stars || 0) - (a.stars || 0));
21194
21331
  const prev = this._cache;
21195
- const truncated = this._truncatedSources || /* @__PURE__ */ new Set();
21332
+ const truncated = bctx.truncated;
21196
21333
  if (prev && prev.plugins && prev.plugins.length > 0 && truncated.size > 0) {
21197
21334
  const freshNames = new Set(plugins.map((pp) => pp.name));
21198
21335
  const kept = prev.plugins.filter((pp) => truncated.has(pp.source) && !freshNames.has(pp.name));
@@ -21227,8 +21364,8 @@ var require_market = __commonJS({
21227
21364
  this.logger.info && this.logger.info("market index built in " + (Date.now() - start) + "ms: " + plugins.length + " plugins (npm=" + npm.length + ", gh=" + gh.length + ", community=" + community.length + ")");
21228
21365
  return this._cache;
21229
21366
  }
21230
- /** npm 源:搜 deepseek-harness 受限 dsh,逐个检测 dsh.bundle。 */
21231
- async indexNpm() {
21367
+ /** npm 源:搜 deepseek-harness 受限 dsh,逐个检测 dsh.bundle。bctx 为本次构建的预算上下文(见 buildIndex)。 */
21368
+ async indexNpm(bctx) {
21232
21369
  const out = [];
21233
21370
  const queries = ["keywords:deepseek-harness", "keywords:dsh-bundle", "keywords:dsh-plugin"];
21234
21371
  const allNames = /* @__PURE__ */ new Set();
@@ -21255,8 +21392,8 @@ var require_market = __commonJS({
21255
21392
  this.logger.info && this.logger.info("npm candidates: " + names.length);
21256
21393
  const batch = 8;
21257
21394
  for (let i = 0; i < names.length; i += batch) {
21258
- if (this._budgetExhausted()) {
21259
- this._truncatedSources.add("npm");
21395
+ if (this._budgetExhausted(bctx)) {
21396
+ bctx.truncated.add("npm");
21260
21397
  this.logger.warn && this.logger.warn("market: npm \u6E90\u9884\u7B97\u8017\u5C3D\uFF0C\u5DF2\u5904\u7406 " + i + "/" + names.length + " \u4E2A\u5019\u9009");
21261
21398
  break;
21262
21399
  }
@@ -21286,7 +21423,7 @@ var require_market = __commonJS({
21286
21423
  return fetchLatest(await this._npmOrigin(), name);
21287
21424
  }
21288
21425
  /** GitHub 源:搜 topic:dsh-plugin + deepseek-harness,逐个验证 dsh.bundle。 */
21289
- async indexGithub() {
21426
+ async indexGithub(bctx) {
21290
21427
  const out = [];
21291
21428
  const topics = ["dsh-plugin", "deepseek-harness"];
21292
21429
  const seen = /* @__PURE__ */ new Set();
@@ -21316,7 +21453,7 @@ var require_market = __commonJS({
21316
21453
  return repoPkg(fullName);
21317
21454
  }
21318
21455
  /** 社区列表:抓 awesome-dsh-plugin README 白名单(官方社区维护的精选)。 */
21319
- async indexCommunity() {
21456
+ async indexCommunity(bctx) {
21320
21457
  const out = [];
21321
21458
  try {
21322
21459
  const md = await rawGet("awesome-dsh-plugin/awesome-dsh-plugin/main/README.md", false, 3e4);
@@ -21328,8 +21465,8 @@ var require_market = __commonJS({
21328
21465
  }
21329
21466
  const seenName = /* @__PURE__ */ new Set();
21330
21467
  for (let i = 0; i < links.length; i += 8) {
21331
- if (this._budgetExhausted()) {
21332
- this._truncatedSources.add("community");
21468
+ if (this._budgetExhausted(bctx)) {
21469
+ bctx.truncated.add("community");
21333
21470
  this.logger.warn && this.logger.warn("market: community \u6E90\u9884\u7B97\u8017\u5C3D\uFF0C\u5DF2\u5904\u7406 " + i + "/" + links.length + " \u4E2A\u5019\u9009");
21334
21471
  break;
21335
21472
  }
@@ -21851,7 +21988,7 @@ var require_restart3 = __commonJS({
21851
21988
  log("\u91CD\u542F\u5B9E\u4F8B\u300C" + (target.name || target.id) + "\u300D\u4F7F\u63D2\u4EF6\u53D8\u66F4\u751F\u6548\u2026");
21852
21989
  if (ctx.events) ctx.events.append("plugin_restart_started", { name: target.name || target.id, target: target.id, kind });
21853
21990
  try {
21854
- ctx.instances.stopInstance(target.id, { intent: "transient" });
21991
+ ctx.instances.stopInstance(target.id);
21855
21992
  } catch (e) {
21856
21993
  log("\u505C\u6B62\u5B9E\u4F8B\u5931\u8D25: " + e.message);
21857
21994
  }
@@ -22562,10 +22699,6 @@ var require_managed_object = __commonJS({
22562
22699
  function registerKind(kind, meta) {
22563
22700
  _customKinds[kind] = Object.assign({ label: kind, startable: false, guardable: false }, meta || {});
22564
22701
  }
22565
- var DOMAIN_A_KINDS = /* @__PURE__ */ new Set(["dsh", "sandbox-instance"]);
22566
- function isDomainA(kind) {
22567
- return DOMAIN_A_KINDS.has(kind);
22568
- }
22569
22702
  function createEntry(o) {
22570
22703
  const meta = kindMeta(o.kind);
22571
22704
  if (!meta) throw new Error("\u672A\u77E5\u53D7\u7BA1\u5BF9\u8C61\u7C7B\u578B: " + o.kind + "\uFF08\u5148 registerKind \u58F0\u660E\uFF09");
@@ -22576,8 +22709,9 @@ var require_managed_object = __commonJS({
22576
22709
  name: String(o.name || o.id),
22577
22710
  // desired 两域共用字段名但语义不同:域 A=用户意图;域 B=「当前业务是否需要它」的条件
22578
22711
  desired: o.desired === "stopped" ? "stopped" : "running",
22579
- // guardian 域 A 专有(见上);域 B 不物化,旧残留才清得掉
22580
- ...isDomainA(o.kind) ? { guardian: o.guardian === true } : {},
22712
+ // guardian 开关的权威在域记录本身(dsh-main.json / inst.guardian),消费者全部直读源;
22713
+ // 目录曾在域 A entry 上物化该字段但零读者(B2-2 收口)。createEntry 永不物化 guardian 键
22714
+ // = 老库残留的天然一次性清理口(load 经本函数重建即消失),无需迁移脚本。
22581
22715
  ownership: normalizeOwnership(o.ownership),
22582
22716
  // 初始 stopped;业务不得直接改,由 heartbeat 调谐循环写入
22583
22717
  phase: "stopped",
@@ -22612,7 +22746,7 @@ var require_managed_object = __commonJS({
22612
22746
  // 域备注(只读参考)
22613
22747
  };
22614
22748
  }
22615
- module2.exports = { DESIRED, MANAGED_KINDS, kindMeta, registerKind, isDomainA, createEntry, normalizeOwnership };
22749
+ module2.exports = { DESIRED, MANAGED_KINDS, kindMeta, registerKind, createEntry, normalizeOwnership };
22616
22750
  }
22617
22751
  });
22618
22752
 
@@ -22679,6 +22813,13 @@ var require_heartbeat = __commonJS({
22679
22813
  registry._log("warn", "heartbeat " + (ad.supervise ? "supervise" : "observe") + "(" + e.kind + ":" + e.id + "): " + (err && err.message || err));
22680
22814
  }
22681
22815
  }
22816
+ if (typeof registry.onBeatDone === "function") {
22817
+ try {
22818
+ await registry.onBeatDone({ observed, errors });
22819
+ } catch (err) {
22820
+ registry._log("warn", "heartbeat onBeatDone: " + (err && err.message || err));
22821
+ }
22822
+ }
22682
22823
  return { observed, errors };
22683
22824
  }
22684
22825
  module2.exports = { runHeartbeat, withTimeout, ADAPTER_TIMEOUT_TICKS };
@@ -22692,7 +22833,7 @@ var require_registry3 = __commonJS({
22692
22833
  var fs2 = require("node:fs");
22693
22834
  var path2 = require("node:path");
22694
22835
  var { writeAtomic } = require_fs();
22695
- var { DESIRED, MANAGED_KINDS, kindMeta, registerKind: registerManagedKind, isDomainA, createEntry, normalizeOwnership } = require_managed_object();
22836
+ var { DESIRED, MANAGED_KINDS, kindMeta, registerKind: registerManagedKind, createEntry, normalizeOwnership } = require_managed_object();
22696
22837
  var PHASES = ["stopped", "installing", "starting", "running", "draining", "backoff", "failed", "restarting"];
22697
22838
  var { runHeartbeat } = require_heartbeat();
22698
22839
  var ManagedRegistry = class {
@@ -22743,7 +22884,7 @@ var require_registry3 = __commonJS({
22743
22884
  for (const o of arr) {
22744
22885
  try {
22745
22886
  if (!o || !kindMeta(o.kind)) continue;
22746
- const e = createEntry({ kind: o.kind, id: o.id, name: o.name, desired: o.desired, guardian: isDomainA(o.kind) ? o.guardian : void 0, ownership: o.ownership });
22887
+ const e = createEntry({ kind: o.kind, id: o.id, name: o.name, desired: o.desired, ownership: o.ownership });
22747
22888
  if (PHASES.includes(o.phase)) e.phase = o.phase;
22748
22889
  if (Number.isInteger(o.backoffLevel)) e.backoffLevel = o.backoffLevel;
22749
22890
  if (typeof o.backoffUntil === "number" && o.backoffUntil > Date.now()) e.backoffUntil = o.backoffUntil;
@@ -22770,7 +22911,7 @@ var require_registry3 = __commonJS({
22770
22911
  kind: o.kind,
22771
22912
  id: o.id,
22772
22913
  name: o.name,
22773
- // desired 两域共用(语义不同,见 createEntry);guardian 仅域 A 落盘。
22914
+ // desired 两域共用(语义不同,见 createEntry);guardian 不落盘(B2-2,权威在域记录)。
22774
22915
  desired: o.desired,
22775
22916
  ownership: o.ownership,
22776
22917
  phase: o.phase,
@@ -22782,7 +22923,7 @@ var require_registry3 = __commonJS({
22782
22923
  startedAt: o.startedAt,
22783
22924
  createdAt: o.createdAt,
22784
22925
  updatedAt: o.updatedAt
22785
- }, isDomainA(o.kind) ? { guardian: o.guardian === true } : {}))
22926
+ }))
22786
22927
  }, null, 2);
22787
22928
  writeAtomic(this.file, body, { mode: 384 });
22788
22929
  } catch (e) {
@@ -22844,8 +22985,8 @@ var require_registry3 = __commonJS({
22844
22985
  this._event("managed_object_registered", { kind: e.kind, id: e.id, name: e.name });
22845
22986
  return e;
22846
22987
  }
22847
- /** 对象变更申报(desired/guardian/ownership/name)。guardian 是域 A 专有:
22848
- * 域 B 基础设施既不写入,还主动删键清除早期版本残留(下一次 update 即归一)。 */
22988
+ /** 对象变更申报(desired/ownership/name)。guardian 不接受申报(B2-2):createEntry 永不
22989
+ * 物化该键,patch 里带 guardian 一律忽略,老库残留由 load 重建时清理。 */
22849
22990
  update(id, patch) {
22850
22991
  const e = this.get(id);
22851
22992
  if (!e) return { ok: false, error: "\u672A\u6CE8\u518C: " + id };
@@ -22854,11 +22995,6 @@ var require_registry3 = __commonJS({
22854
22995
  if (!DESIRED.includes(p.desired)) return { ok: false, error: "\u975E\u6CD5 desired: " + p.desired };
22855
22996
  e.desired = p.desired;
22856
22997
  }
22857
- if (isDomainA(e.kind)) {
22858
- if (p.guardian !== void 0) e.guardian = p.guardian === true;
22859
- } else if ("guardian" in e) {
22860
- delete e.guardian;
22861
- }
22862
22998
  if (p.name !== void 0) e.name = String(p.name || e.id);
22863
22999
  if (p.ownership !== void 0) {
22864
23000
  const old = e.ownership.ports;
@@ -23276,20 +23412,23 @@ var require_npm = __commonJS({
23276
23412
  const l = runtimeContract.npmLauncher();
23277
23413
  return { program: l.program, args: l.args };
23278
23414
  }
23279
- function resolveNpmRoot(host2) {
23415
+ async function resolveNpmRoot(host2) {
23280
23416
  if (host2.npmRoot) return host2.npmRoot;
23281
23417
  const l = npmLaunch(host2);
23282
- const r = ex2.runOut(l.program, l.args.concat(["root", "-g"]));
23418
+ const r = await ex2.runOutAsync(l.program, l.args.concat(["root", "-g"]));
23283
23419
  return r ? r.trim() : null;
23284
23420
  }
23285
- function checkEnvironment(host2) {
23421
+ async function checkEnvironment(host2) {
23286
23422
  const errors = [];
23287
- const nv = ex2.runOut("node", ["--version"]);
23288
- if (!nv || !nv.trim()) errors.push("node \u672A\u5B89\u88C5\u6216\u4E0D\u53EF\u6267\u884C");
23289
23423
  const l = npmLaunch(host2);
23290
- const npmv = ex2.runOut(l.program, l.args.concat(["--version"]));
23424
+ const [nv, npmv, npmRoot] = await Promise.all([
23425
+ ex2.runOutAsync("node", ["--version"]),
23426
+ ex2.runOutAsync(l.program, l.args.concat(["--version"])),
23427
+ resolveNpmRoot(host2)
23428
+ ]);
23429
+ if (!nv || !nv.trim()) errors.push("node \u672A\u5B89\u88C5\u6216\u4E0D\u53EF\u6267\u884C");
23291
23430
  if (!npmv || !npmv.trim()) errors.push("npm \u672A\u5B89\u88C5\u6216\u4E0D\u53EF\u6267\u884C");
23292
- return { ok: errors.length === 0, errors, npmRoot: resolveNpmRoot(host2) };
23431
+ return { ok: errors.length === 0, errors, npmRoot };
23293
23432
  }
23294
23433
  async function latestVersion(host2) {
23295
23434
  if (!host2.dist || !host2.config.packageName) throw new Error("\u5206\u53D1\u670D\u52A1\u672A\u521D\u59CB\u5316\uFF0C\u65E0\u6CD5\u67E5\u8BE2\u6700\u65B0\u7248\u672C");
@@ -23388,13 +23527,14 @@ var require_ops4 = __commonJS({
23388
23527
  }
23389
23528
  async function install(host2, version) {
23390
23529
  if (!policies.isValidVersion(version)) return { ok: false, error: "\u975E\u6CD5\u7248\u672C\u53F7: " + version };
23391
- const env = host2.checkEnvironment();
23392
- if (!env.ok) return { ok: false, error: "\u73AF\u5883\u68C0\u67E5\u5931\u8D25: " + env.errors.join("; ") };
23393
23530
  host2.installing = true;
23394
23531
  host2.installLog = [];
23395
- const task = beginTask(host2, "install", { to: version || null, createdBy: "user" });
23396
- let target = version;
23532
+ let task = null;
23397
23533
  try {
23534
+ const env = await host2.checkEnvironment();
23535
+ if (!env.ok) return { ok: false, error: "\u73AF\u5883\u68C0\u67E5\u5931\u8D25: " + env.errors.join("; ") };
23536
+ task = beginTask(host2, "install", { to: version || null, createdBy: "user" });
23537
+ let target = version;
23398
23538
  if (!target) {
23399
23539
  target = await host2._latestVersion().catch(() => null);
23400
23540
  if (!target) {
@@ -23417,7 +23557,7 @@ var require_ops4 = __commonJS({
23417
23557
  return { ok: false, error: res.error, output: res.output };
23418
23558
  }
23419
23559
  const isFirstInstall = !host2._manifest();
23420
- host2._recordManifest(target, isFirstInstall ? host2._claimDataPaths() : void 0);
23560
+ await host2._recordManifest(target, isFirstInstall ? host2._claimDataPaths() : void 0);
23421
23561
  try {
23422
23562
  if (typeof host2._bindNativeDshCommand === "function") host2._bindNativeDshCommand();
23423
23563
  } catch (e) {
@@ -23442,8 +23582,6 @@ var require_ops4 = __commonJS({
23442
23582
  if (host2.uninstalling) return { ok: false, error: "\u5378\u8F7D\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u518D\u88C5" };
23443
23583
  if (policies.busy(host2)) return { ok: false, error: "\u5347\u7EA7\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u518D\u88C5\uFF08state=" + host2.upgradeState + "\uFF09" };
23444
23584
  if (!policies.isValidVersion(version)) return { ok: false, error: "\u975E\u6CD5\u7248\u672C\u53F7: " + version };
23445
- const env = host2.checkEnvironment();
23446
- if (!env.ok) return { ok: false, error: "\u73AF\u5883\u68C0\u67E5\u5931\u8D25: " + env.errors.join("; ") };
23447
23585
  install(host2, version).then(() => {
23448
23586
  }).catch((e) => {
23449
23587
  host2.installing = null;
@@ -23636,7 +23774,7 @@ var require_upgrade2 = __commonJS({
23636
23774
  if (!res.ok) throw new Error(res.error || "install failed");
23637
23775
  const newV = host2.installedVersion();
23638
23776
  if (newV !== target) throw new Error("\u5B89\u88C5\u540E\u7248\u672C\u6821\u9A8C\u5931\u8D25\uFF1A\u671F\u671B " + target + "\uFF0C\u5B9E\u9645 " + newV);
23639
- host2._recordManifest(newV || target);
23777
+ await host2._recordManifest(newV || target);
23640
23778
  if (host2.events) host2.events.append("upgrade_installed", { from: oldV, to: target });
23641
23779
  log(host2, "\u5B89\u88C5\u5B8C\u6210\uFF0C\u78C1\u76D8\u7248\u672C " + newV);
23642
23780
  if (task) {
@@ -23706,9 +23844,9 @@ var require_upgrade2 = __commonJS({
23706
23844
  async function rollbackAfterFailedVerify(host2, oldV, task, healthy) {
23707
23845
  log(host2, "\u5065\u5EB7\u9A8C\u8BC1\u5931\u8D25\uFF08" + healthy.reason + "\uFF09");
23708
23846
  if (task) host2.tasks.log(task.id, "\u5065\u5EB7\u9A8C\u8BC1\u5931\u8D25\uFF08" + healthy.reason + "\uFF09");
23709
- host2.rolledBack = true;
23710
23847
  host2.upgradeState = "rolling_back";
23711
23848
  const rb = await rollbackNative(host2, oldV, task);
23849
+ host2.rolledBack = rb.ok === true;
23712
23850
  host2.upgradeError = rb.ok ? "\u5347\u7EA7\u5931\u8D25\uFF0C\u5DF2\u56DE\u6EDA\u5230 " + oldV : "\u5347\u7EA7\u5931\u8D25\u4E14\u56DE\u6EDA\u5931\u8D25\uFF1A" + (rb.error || "");
23713
23851
  host2.upgradeState = "failed";
23714
23852
  host2.upgradeFinishedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -23740,7 +23878,7 @@ var require_upgrade2 = __commonJS({
23740
23878
  }
23741
23879
  tlog("\u56DE\u6EDA\u5B8C\u6210\uFF0C\u78C1\u76D8\u7248\u672C " + oldVersion);
23742
23880
  try {
23743
- host2._recordManifest(oldVersion);
23881
+ await host2._recordManifest(oldVersion);
23744
23882
  } catch (e2) {
23745
23883
  tlog("manifest \u66F4\u65B0\u5931\u8D25: " + e2.message);
23746
23884
  }
@@ -23755,7 +23893,6 @@ var require_upgrade2 = __commonJS({
23755
23893
  }
23756
23894
  async function rollbackAfterFailure(host2) {
23757
23895
  host2.upgradeState = "rolling_back";
23758
- host2.rolledBack = true;
23759
23896
  if (host2.events) host2.events.append("upgrade_rollback_started", { to: host2.oldVersion });
23760
23897
  log(host2, "\u56DE\u6EDA\u5230 " + host2.oldVersion + "\u2026");
23761
23898
  const registry = await host2._selectRegistry();
@@ -23776,8 +23913,9 @@ var require_upgrade2 = __commonJS({
23776
23913
  return { ok: false };
23777
23914
  }
23778
23915
  log(host2, "\u56DE\u6EDA\u5B8C\u6210\u3002");
23916
+ host2.rolledBack = true;
23779
23917
  try {
23780
- host2._recordManifest(host2.oldVersion);
23918
+ await host2._recordManifest(host2.oldVersion);
23781
23919
  } catch (e2) {
23782
23920
  log(host2, "manifest \u66F4\u65B0\u5931\u8D25: " + e2.message);
23783
23921
  }
@@ -23927,8 +24065,8 @@ var require_installer = __commonJS({
23927
24065
  _saveManifest(m) {
23928
24066
  return manifest.save(this, m);
23929
24067
  }
23930
- _recordManifest(version, dataPaths) {
23931
- return manifest.record(this, version, dataPaths, this.npmRoot || npm.resolveNpmRoot(this));
24068
+ async _recordManifest(version, dataPaths) {
24069
+ return manifest.record(this, version, dataPaths, this.npmRoot || await npm.resolveNpmRoot(this));
23932
24070
  }
23933
24071
  _claimDataPaths() {
23934
24072
  return manifest.claimDataPaths(this);
@@ -24310,6 +24448,7 @@ var require_domains = __commonJS({
24310
24448
  host2.managedObjects.registerAdapter("dsh", { supervise: () => host2._dshSuperviseOnce(), tickEvery: 1 });
24311
24449
  host2.managedObjects.registerAdapter("sandbox-instance", { supervise: (entry) => host2._sandboxSuperviseOnce(entry), tickEvery: 1 });
24312
24450
  }
24451
+ if (host2.managedObjects) host2.managedObjects.onBeatDone = () => host2.instances.governSweep();
24313
24452
  } catch (e) {
24314
24453
  host2.logger && host2.logger.warn && host2.logger.warn("managed registry init: " + (e && e.message));
24315
24454
  }
@@ -24904,7 +25043,7 @@ var require_guard = __commonJS({
24904
25043
  }
24905
25044
  }
24906
25045
  if (req.method === "GET" && pathname === "/guard/version") {
24907
- return send(200, sup.guardVersionLocal());
25046
+ return Promise.resolve(sup.guardVersionLocal()).then((r) => send(200, r)).catch((e) => send(500, { ok: false, error: e.message }));
24908
25047
  }
24909
25048
  if (req.method === "POST" && pathname === "/guard/version/check") {
24910
25049
  req.resume();
@@ -25049,7 +25188,7 @@ var require_guard = __commonJS({
25049
25188
  req.resume();
25050
25189
  return send(403, {});
25051
25190
  }
25052
- return send(200, sup.envStatus());
25191
+ return Promise.resolve(sup.envStatus()).then((r) => send(200, r)).catch((e) => send(500, { ok: false, error: e.message }));
25053
25192
  }
25054
25193
  if (req.method === "GET" && pathname === "/env/node-lts") {
25055
25194
  return sup.nodeLtsStatus().then((r) => send(200, r)).catch((e) => send(500, { ok: false, error: e.message }));
@@ -25704,7 +25843,7 @@ var require_instances = __commonJS({
25704
25843
  const r = sup.instances.updateInstance(j.id, j);
25705
25844
  return send(r && r.ok ? 200 : 400, r);
25706
25845
  }
25707
- if (act === "start" && j.id) return Promise.resolve(sup.instances.startInstance(j.id)).then((r) => send(r && r.ok ? 200 : 400, r)).catch((e) => send(500, { ok: false, error: e.message }));
25846
+ if (act === "start" && j.id) return Promise.resolve(sup.instances.startInstance(j.id, { manual: true })).then((r) => send(r && r.ok ? 200 : 400, r)).catch((e) => send(500, { ok: false, error: e.message }));
25708
25847
  if (act === "stop" && j.id) {
25709
25848
  const r = sup.instances.stopInstance(j.id);
25710
25849
  return send(r && r.ok ? 200 : 400, r);
@@ -27918,28 +28057,45 @@ function printSelfVersion() {
27918
28057
  const { guardVersion } = require_version();
27919
28058
  console.log("dsh-supervisor v" + guardVersion());
27920
28059
  }
27921
- function apiRequest(method, apiPath) {
28060
+ function apiRaw(method, apiPath, body) {
27922
28061
  return new Promise((resolve) => {
27923
28062
  const addr = readApiAddress();
27924
28063
  const req = http.request(
27925
- { hostname: addr.host, port: addr.port, path: apiPath, method, timeout: 5e3 },
28064
+ {
28065
+ hostname: addr.host,
28066
+ port: addr.port,
28067
+ path: apiPath,
28068
+ method,
28069
+ timeout: 5e3,
28070
+ headers: body ? { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(body) } : {}
28071
+ },
27926
28072
  (res) => {
27927
- let body = "";
27928
- res.on("data", (d) => body += d);
27929
- res.on("end", () => {
27930
- try {
27931
- resolve(JSON.parse(body));
27932
- } catch {
27933
- resolve({ error: "parse error", raw: body });
27934
- }
27935
- });
27936
- res.on("error", () => resolve({ error: "response error" }));
28073
+ let text = "";
28074
+ res.setEncoding("utf8");
28075
+ res.on("data", (d) => text += d);
28076
+ res.on("end", () => resolve({ status: res.statusCode, text }));
28077
+ res.on("error", (e) => resolve({ status: 0, text: "", error: e.message }));
27937
28078
  }
27938
28079
  );
27939
- req.on("error", () => resolve({ error: "daemon \u672A\u8FD0\u884C\u6216\u8FDE\u63A5\u5931\u8D25" }));
28080
+ req.on("timeout", () => req.destroy(new Error("api-timeout")));
28081
+ req.on(
28082
+ "error",
28083
+ (e) => resolve({ status: 0, text: "", error: e && e.message === "api-timeout" ? "daemon \u54CD\u5E94\u8D85\u65F6\uFF085s\uFF09" : "daemon \u672A\u8FD0\u884C\u6216\u8FDE\u63A5\u5931\u8D25" })
28084
+ );
28085
+ if (body) req.write(body);
27940
28086
  req.end();
27941
28087
  });
27942
28088
  }
28089
+ function apiRequest(method, apiPath) {
28090
+ return apiRaw(method, apiPath).then(({ status, text, error }) => {
28091
+ if (error) return { error };
28092
+ try {
28093
+ return JSON.parse(text);
28094
+ } catch {
28095
+ return { error: "parse error", raw: text };
28096
+ }
28097
+ });
28098
+ }
27943
28099
  var LOCK_FILE = process.env.DSH_SUPERVISOR_LOCK_FILE || path.join(SUPERVISOR_DIR, "guard.lock");
27944
28100
  var LOCK_OWNER = { pid: process.pid, started: Date.now(), entry: process.argv[1] || "" };
27945
28101
  function readLock() {
@@ -28258,26 +28414,9 @@ function cmdVersion() {
28258
28414
  });
28259
28415
  }
28260
28416
  function cmdSelfUpdate(action) {
28261
- const addr = readApiAddress();
28262
- const apiOne = (method, p, body) => new Promise((resolve) => {
28263
- const req = http.request({ hostname: addr.host, port: addr.port, path: p, method, timeout: 5e3, headers: body ? { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(body) } : {} }, (res) => {
28264
- let b = "";
28265
- res.on("data", (d) => b += d);
28266
- res.on("end", () => {
28267
- try {
28268
- resolve(JSON.parse(b));
28269
- } catch {
28270
- resolve({ error: "parse error", raw: b });
28271
- }
28272
- });
28273
- });
28274
- req.on("error", () => resolve({ error: "daemon \u672A\u8FD0\u884C\u6216\u8FDE\u63A5\u5931\u8D25" }));
28275
- if (body) req.write(body);
28276
- req.end();
28277
- });
28278
28417
  (async () => {
28279
28418
  if (action === "check" || !action) {
28280
- const s = await apiOne("GET", "/self-update/status");
28419
+ const s = await apiRequest("GET", "/self-update/status");
28281
28420
  if (s.error) return console.log("\u68C0\u67E5\u5931\u8D25: " + s.error);
28282
28421
  if (s.ok) {
28283
28422
  console.log("\u5B88\u536B\u5F53\u524D\u7248\u672C: " + s.installed);
@@ -28295,31 +28434,13 @@ function cmdSelfUpdate(action) {
28295
28434
  })();
28296
28435
  }
28297
28436
  function cmdUpgrade(requested) {
28298
- const post = () => new Promise((resolve) => {
28299
- const addr = readApiAddress();
28300
- const body = requested ? JSON.stringify({ version: requested }) : void 0;
28301
- const req = http.request(
28302
- {
28303
- hostname: addr.host,
28304
- port: addr.port,
28305
- path: "/native/upgrade",
28306
- method: "POST",
28307
- timeout: 5e3,
28308
- headers: body ? { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(body) } : {}
28309
- },
28310
- (res) => {
28311
- let b = "";
28312
- res.on("data", (d) => b += d);
28313
- res.on("end", () => resolve({ code: res.statusCode, body: b }));
28314
- }
28315
- );
28316
- req.on("error", () => resolve({ code: 0, body: "" }));
28317
- if (body) req.write(body);
28318
- req.end();
28319
- });
28320
- post().then(({ code, body }) => {
28437
+ const body = requested ? JSON.stringify({ version: requested }) : void 0;
28438
+ const post = () => apiRaw("POST", "/native/upgrade", body);
28439
+ post().then(({ status, text, error }) => {
28440
+ const code = error ? 0 : status;
28441
+ const outText = error ? "" : text;
28321
28442
  if (code !== 202) {
28322
- console.log("\u5347\u7EA7\u672A\u88AB\u63A5\u53D7:", body || "HTTP " + code);
28443
+ console.log("\u5347\u7EA7\u672A\u88AB\u63A5\u53D7:", outText || "HTTP " + code);
28323
28444
  process.exit(1);
28324
28445
  }
28325
28446
  console.log("\u5347\u7EA7\u5DF2\u5F00\u59CB\uFF0C\u8DDF\u8E2A\u8FDB\u5EA6\uFF08\u5148\u505C DSH \u2192 \u5B89\u88C5 \u2192 \u81EA\u52A8\u62C9\u8D77\uFF0C\u9700\u6570\u5206\u949F\uFF09\u2026");