@dsh-sup/dsh-core-linux-x64 0.1.6-BETA.14 → 0.1.6-BETA.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core.cjs CHANGED
@@ -951,7 +951,7 @@ var require_version = __commonJS({
951
951
  var fs2 = require("node:fs");
952
952
  var path2 = require("node:path");
953
953
  function guardVersion() {
954
- if (true) return String("0.1.6-BETA.14");
954
+ if (true) return String("0.1.6-BETA.16");
955
955
  try {
956
956
  return JSON.parse(fs2.readFileSync(path2.join(__dirname, "..", "..", "package.json"), "utf8")).version || "unknown";
957
957
  } catch {
@@ -4855,6 +4855,106 @@ var require_capability_profile = __commonJS({
4855
4855
  }
4856
4856
  });
4857
4857
 
4858
+ // src/platform/util/redact.js
4859
+ var require_redact = __commonJS({
4860
+ "src/platform/util/redact.js"(exports2, module2) {
4861
+ "use strict";
4862
+ function maskProxyServer(server) {
4863
+ return server ? String(server).replace(/(\/\/)?([^\s/@:]+):([^\s/@]*)@/, "$1$2:***@") : null;
4864
+ }
4865
+ function maskProxySecrets(text) {
4866
+ return String(text == null ? "" : text).replace(/(\/\/)?([^\s/@:]+):([^\s/@]*)@/g, "$1$2:***@");
4867
+ }
4868
+ module2.exports = { maskProxyServer, maskProxySecrets };
4869
+ }
4870
+ });
4871
+
4872
+ // src/platform/os/registry.js
4873
+ var require_registry = __commonJS({
4874
+ "src/platform/os/registry.js"(exports2, module2) {
4875
+ "use strict";
4876
+ function regValueOf(out) {
4877
+ const m = String(out || "").match(/REG_(?:EXPAND_SZ|SZ)\s+(.*)/);
4878
+ if (!m) return null;
4879
+ return m[1].trim() || null;
4880
+ }
4881
+ function regDwordOf(out) {
4882
+ const m = String(out || "").match(/REG_DWORD\s+(0x[0-9a-fA-F]+|\d+)\b/);
4883
+ if (!m) return null;
4884
+ const n = Number.parseInt(m[1], m[1].startsWith("0x") ? 16 : 10);
4885
+ return Number.isNaN(n) ? null : n;
4886
+ }
4887
+ function expandEnvVars(value, env) {
4888
+ const e = env || process.env;
4889
+ return String(value).replace(/%([^%]+)%/g, (all, name) => e[name] === void 0 ? all : e[name]);
4890
+ }
4891
+ function safeRegKeyPart(s) {
4892
+ return typeof s === "string" && s.length > 0 && s.length <= 200 && /^[\x20-\x7e]+$/.test(s) && !/[;|&`$()<>^"'\r\n]/.test(s);
4893
+ }
4894
+ var REG_HIVE_ALIAS = { HKLM: "HKEY_LOCAL_MACHINE", HKCU: "HKEY_CURRENT_USER", HKCR: "HKEY_CLASSES_ROOT", HKU: "HKEY_USERS", HKCC: "HKEY_CURRENT_CONFIG" };
4895
+ function regKeyFull(key) {
4896
+ const s = String(key || "");
4897
+ const i = s.indexOf("\\");
4898
+ const root = i < 0 ? s : s.slice(0, i);
4899
+ return (REG_HIVE_ALIAS[root.toUpperCase()] || root) + (i < 0 ? "" : s.slice(i));
4900
+ }
4901
+ function regValue(runner, note, key, name) {
4902
+ const args = name ? ["query", key, "/v", name] : ["query", key, "/ve"];
4903
+ const out = runner("reg.exe", args);
4904
+ const v = regValueOf(out);
4905
+ note(name ? key + " /v " + name : key, v ? "ok" : "empty");
4906
+ return v;
4907
+ }
4908
+ function regSubkeys(runner, note, key) {
4909
+ const out = runner("reg.exe", ["query", key]);
4910
+ if (!out) {
4911
+ note(key, "unreadable");
4912
+ return [];
4913
+ }
4914
+ const prefix = regKeyFull(key) + "\\";
4915
+ const names = [];
4916
+ for (const line of String(out).split(/\r?\n/)) {
4917
+ const l = line.trim();
4918
+ if (!/^HKEY_/i.test(l) || l.length <= prefix.length) continue;
4919
+ if (l.slice(0, prefix.length).toUpperCase() !== prefix.toUpperCase()) continue;
4920
+ const rest = l.slice(prefix.length);
4921
+ if (rest && !rest.includes("\\") && safeRegKeyPart(rest)) names.push(rest);
4922
+ }
4923
+ note(key, names.length ? names.length + " \u9879" : "\u65E0\u5B50\u952E");
4924
+ return names;
4925
+ }
4926
+ function regValueTargets(runner, note, key) {
4927
+ const out = runner("reg.exe", ["query", key]);
4928
+ if (!out) {
4929
+ note(key, "unreadable");
4930
+ return [];
4931
+ }
4932
+ const paths = [];
4933
+ for (const line of String(out).split(/\r?\n/)) {
4934
+ const m = line.trim().match(/REG_SZ\s+(.*)/);
4935
+ if (!m) continue;
4936
+ const rel = m[1].trim();
4937
+ if (!safeRegKeyPart(rel)) continue;
4938
+ const root = key.slice(0, key.indexOf("\\"));
4939
+ paths.push(root + "\\" + rel);
4940
+ }
4941
+ note(key, paths.length ? paths.length + " \u4E2A\u80FD\u529B\u8DEF\u5F84" : "\u65E0\u503C");
4942
+ return paths;
4943
+ }
4944
+ module2.exports = {
4945
+ regValueOf,
4946
+ regDwordOf,
4947
+ expandEnvVars,
4948
+ safeRegKeyPart,
4949
+ REG_HIVE_ALIAS,
4950
+ regKeyFull,
4951
+ regValue,
4952
+ regSubkeys,
4953
+ regValueTargets
4954
+ };
4955
+ }
4956
+ });
4957
+
4858
4958
  // src/platform/os/browser-inventory.js
4859
4959
  var require_browser_inventory = __commonJS({
4860
4960
  "src/platform/os/browser-inventory.js"(exports2, module2) {
@@ -4864,6 +4964,8 @@ var require_browser_inventory = __commonJS({
4864
4964
  var os2 = require("node:os");
4865
4965
  var exec = require_exec();
4866
4966
  var { isExecutableFile } = require_exec_path();
4967
+ var registry = require_registry();
4968
+ var { expandEnvVars, safeRegKeyPart, regValue, regSubkeys, regValueTargets } = registry;
4867
4969
  var PROBE_TIMEOUT_MS = 1500;
4868
4970
  function engineOf(bin) {
4869
4971
  const base = String(bin || "").toLowerCase().split(/[\\/]/).pop();
@@ -4922,15 +5024,6 @@ var require_browser_inventory = __commonJS({
4922
5024
  if (!toks.length) return null;
4923
5025
  return { bin: toks[0], baseArgs: toks.slice(1) };
4924
5026
  }
4925
- function regValueOf(out) {
4926
- const m = String(out || "").match(/REG_(?:EXPAND_SZ|SZ)\s+(.*)/);
4927
- if (!m) return null;
4928
- return m[1].trim() || null;
4929
- }
4930
- function expandEnvVars(value, env) {
4931
- const e = env || process.env;
4932
- return String(value).replace(/%([^%]+)%/g, (all, name) => e[name] === void 0 ? all : e[name]);
4933
- }
4934
5027
  function exeFromCmdLine(cmdLine) {
4935
5028
  const s = String(cmdLine || "");
4936
5029
  let m = s.match(/^\s*"([^"]+\.exe)"/i);
@@ -4938,41 +5031,6 @@ var require_browser_inventory = __commonJS({
4938
5031
  m = s.match(/^\s*(.*?\.exe)/i);
4939
5032
  return m ? m[1] : null;
4940
5033
  }
4941
- function safeRegKeyPart(s) {
4942
- return typeof s === "string" && s.length > 0 && s.length <= 200 && /^[\x20-\x7e]+$/.test(s) && !/[;|&`$()<>^"'\r\n]/.test(s);
4943
- }
4944
- function regValue(runner, note, key, name) {
4945
- const args = name ? ["query", key, "/v", name] : ["query", key, "/ve"];
4946
- const out = runner("reg.exe", args);
4947
- const v = regValueOf(out);
4948
- note(name ? key + " /v " + name : key, v ? "ok" : "empty");
4949
- return v;
4950
- }
4951
- var REG_HIVE_ALIAS = { HKLM: "HKEY_LOCAL_MACHINE", HKCU: "HKEY_CURRENT_USER", HKCR: "HKEY_CLASSES_ROOT", HKU: "HKEY_USERS", HKCC: "HKEY_CURRENT_CONFIG" };
4952
- function regKeyFull(key) {
4953
- const s = String(key || "");
4954
- const i = s.indexOf("\\");
4955
- const root = i < 0 ? s : s.slice(0, i);
4956
- return (REG_HIVE_ALIAS[root.toUpperCase()] || root) + (i < 0 ? "" : s.slice(i));
4957
- }
4958
- function regSubkeys(runner, note, key) {
4959
- const out = runner("reg.exe", ["query", key]);
4960
- if (!out) {
4961
- note(key, "unreadable");
4962
- return [];
4963
- }
4964
- const prefix = regKeyFull(key) + "\\";
4965
- const names = [];
4966
- for (const line of String(out).split(/\r?\n/)) {
4967
- const l = line.trim();
4968
- if (!/^HKEY_/i.test(l) || l.length <= prefix.length) continue;
4969
- if (l.slice(0, prefix.length).toUpperCase() !== prefix.toUpperCase()) continue;
4970
- const rest = l.slice(prefix.length);
4971
- if (rest && !rest.includes("\\") && safeRegKeyPart(rest)) names.push(rest);
4972
- }
4973
- note(key, names.length ? names.length + " \u9879" : "\u65E0\u5B50\u952E");
4974
- return names;
4975
- }
4976
5034
  var WIN_APP_PATHS = ["msedge.exe", "chrome.exe", "firefox.exe", "brave.exe", "opera.exe", "vivaldi.exe", "chromium.exe", "thorium.exe", "librewolf.exe"];
4977
5035
  function winExeOfProgId(runner, note, progId, env) {
4978
5036
  if (!safeRegKeyPart(progId)) return null;
@@ -5068,24 +5126,6 @@ var require_browser_inventory = __commonJS({
5068
5126
  if (found.size === 1) setDefault([...found.values()][0], "only-installed");
5069
5127
  return { browsers: [...found.values()], defaultId, defaultSource, probed: notes };
5070
5128
  }
5071
- function regValueTargets(runOut, note, key) {
5072
- const out = runOut("reg.exe", ["query", key]);
5073
- if (!out) {
5074
- note(key, "unreadable");
5075
- return [];
5076
- }
5077
- const paths = [];
5078
- for (const line of String(out).split(/\r?\n/)) {
5079
- const m = line.trim().match(/REG_SZ\s+(.*)/);
5080
- if (!m) continue;
5081
- const rel = m[1].trim();
5082
- if (!safeRegKeyPart(rel)) continue;
5083
- const root = key.slice(0, key.indexOf("\\"));
5084
- paths.push(root + "\\" + rel);
5085
- }
5086
- note(key, paths.length ? paths.length + " \u4E2A\u80FD\u529B\u8DEF\u5F84" : "\u65E0\u503C");
5087
- return paths;
5088
- }
5089
5129
  var MAC_JXA_LIST = [
5090
5130
  "ObjC.import('Foundation');",
5091
5131
  "var ws=$.NSWorkspace.sharedWorkspace;",
@@ -5387,13 +5427,15 @@ var require_browser_inventory = __commonJS({
5387
5427
  engineOf,
5388
5428
  tokenizeExec,
5389
5429
  parseExecLine,
5390
- regValueOf,
5391
- expandEnvVars,
5392
5430
  exeFromCmdLine,
5431
+ // 注册表原语住在 ./registry.js(单一实现),此处原样转出:既有门禁与消费方的取用口不变。
5432
+ regValueOf: registry.regValueOf,
5433
+ expandEnvVars,
5434
+ safeRegKeyPart,
5435
+ regKeyFull: registry.regKeyFull,
5436
+ regValue,
5393
5437
  regSubkeys,
5394
- regKeyFull,
5395
5438
  regValueTargets,
5396
- safeRegKeyPart,
5397
5439
  browserFromDesktop,
5398
5440
  desktopDirs,
5399
5441
  resolveLinuxBin,
@@ -5405,6 +5447,317 @@ var require_browser_inventory = __commonJS({
5405
5447
  }
5406
5448
  });
5407
5449
 
5450
+ // src/platform/os/egress.js
5451
+ var require_egress = __commonJS({
5452
+ "src/platform/os/egress.js"(exports2, module2) {
5453
+ "use strict";
5454
+ var tls = require("node:tls");
5455
+ var dns = require("node:dns");
5456
+ var exec = require_exec();
5457
+ var registry = require_registry();
5458
+ var PROBE_TIMEOUT_MS = 2500;
5459
+ var READ_TTL_MS = 6e4;
5460
+ function hostOf(url) {
5461
+ try {
5462
+ return new URL(String(url)).hostname.toLowerCase() || null;
5463
+ } catch {
5464
+ return null;
5465
+ }
5466
+ }
5467
+ function proxyWin(runner, note) {
5468
+ const KEY = "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
5469
+ const read = (args) => Promise.resolve(runner("reg.exe", args));
5470
+ return Promise.all([
5471
+ read(["query", KEY, "/v", "ProxyEnable"]),
5472
+ read(["query", KEY, "/v", "ProxyServer"]),
5473
+ read(["query", KEY, "/v", "AutoConfigURL"])
5474
+ ]).then(([en, sv, pc]) => {
5475
+ const on = registry.regDwordOf(en);
5476
+ const server = registry.regValueOf(sv);
5477
+ const pac = registry.regValueOf(pc);
5478
+ const state = on === 1 ? "on" : on === 0 ? pac ? "on" : "off" : "unknown";
5479
+ note("registry:Internet Settings", "ProxyEnable=" + (on === null ? "unreadable" : on) + " server=" + (server || "-") + " pac=" + (pac ? "set" : "-"));
5480
+ return { state, server: server || null, pac: pac || null, source: "registry:Internet Settings" };
5481
+ });
5482
+ }
5483
+ function proxyMac(runOut, note) {
5484
+ return Promise.resolve(runOut("scutil", ["--proxy"])).then((out) => {
5485
+ if (!out) {
5486
+ note("scutil --proxy", "unreadable");
5487
+ return { state: "unknown", server: null, pac: null, source: "scutil" };
5488
+ }
5489
+ const kv = {};
5490
+ for (const line of String(out).split(/\r?\n/)) {
5491
+ const m = line.match(/^\s*([A-Za-z]+)\s*:\s*(.+?)\s*$/);
5492
+ if (m) kv[m[1]] = m[2];
5493
+ }
5494
+ const flagOn = (k) => kv[k] === "1";
5495
+ const anyManual = kv.HTTPEnable !== void 0 || kv.HTTPSEnable !== void 0 || kv.SOCKSEnable !== void 0 || kv.ProxyAutoConfigEnable !== void 0;
5496
+ const state = flagOn("HTTPEnable") || flagOn("HTTPSEnable") || flagOn("SOCKSEnable") || flagOn("ProxyAutoConfigEnable") ? "on" : anyManual ? "off" : "unknown";
5497
+ note("scutil --proxy", "state=" + state);
5498
+ return {
5499
+ state,
5500
+ server: kv.HTTPProxy || kv.HTTPSProxy || kv.SOCKSProxy || null,
5501
+ pac: kv.ProxyAutoConfigURLString || kv.ProxyAutoConfigURL || null,
5502
+ source: "scutil"
5503
+ };
5504
+ });
5505
+ }
5506
+ function proxyLinux(env, note) {
5507
+ const pick = (k) => typeof env[k] === "string" && env[k].trim() ? env[k].trim() : null;
5508
+ const server = pick("https_proxy") || pick("HTTPS_PROXY") || pick("http_proxy") || pick("HTTP_PROXY") || pick("ALL_PROXY") || pick("all_proxy");
5509
+ const noProxy = pick("no_proxy") || pick("NO_PROXY");
5510
+ const state = server ? "on" : "unknown";
5511
+ note("env proxy", "state=" + state);
5512
+ return { state, server, pac: pick("PAC_FILE") || null, noProxy, source: "env" };
5513
+ }
5514
+ function proxyUnknown(reason) {
5515
+ return { state: "unknown", server: null, pac: null, source: reason };
5516
+ }
5517
+ var _proxyCache = /* @__PURE__ */ new Map();
5518
+ function proxy(o) {
5519
+ const ov = o || {};
5520
+ const pl = ov.platform || process.platform;
5521
+ const now = typeof ov.now === "function" ? ov.now : Date.now;
5522
+ const ttl = ov.ttlMs === void 0 ? READ_TTL_MS : ov.ttlMs;
5523
+ const hit = _proxyCache.get(pl);
5524
+ if (!ov.force && ttl > 0 && hit && now() - hit.value.at < ttl) {
5525
+ return Promise.resolve(Object.assign({}, hit.value, { cached: true }));
5526
+ }
5527
+ const notes = [];
5528
+ const note = (source, detail) => {
5529
+ notes.push({ source, detail });
5530
+ };
5531
+ const runOut = ov.runOut || ((bin, args) => exec.runOutAsync(bin, args, { timeoutMs: PROBE_TIMEOUT_MS }));
5532
+ const out = Promise.resolve().then(() => {
5533
+ if (pl === "win32") return proxyWin(runOut, note);
5534
+ if (pl === "darwin") return proxyMac(runOut, note);
5535
+ if (pl === "linux") return proxyLinux(ov.env || process.env, note);
5536
+ return proxyUnknown("unsupported-platform");
5537
+ }).catch((e) => {
5538
+ note(pl + " proxy probe", "error: " + String(e && (e.code || e.message) || e));
5539
+ return proxyUnknown("probe-failed");
5540
+ }).then((v) => {
5541
+ const value = Object.assign({ platform: pl, at: now(), probed: notes }, v);
5542
+ _proxyCache.set(pl, { value });
5543
+ return value;
5544
+ });
5545
+ return out;
5546
+ }
5547
+ function proxyRead() {
5548
+ const hit = _proxyCache.get(process.platform);
5549
+ return hit ? hit.value : null;
5550
+ }
5551
+ function reachWith(deps, host2, port, timeoutMs) {
5552
+ const d = deps || {};
5553
+ const ms = timeoutMs || PROBE_TIMEOUT_MS;
5554
+ const lookup = d.lookup || ((h) => new Promise((resolve, reject) => dns.lookup(h, (err, addr) => err ? reject(err) : resolve(addr))));
5555
+ const connect = d.connect || ((opts) => new Promise((resolve, reject) => {
5556
+ let settled = false;
5557
+ const sock = tls.connect(opts);
5558
+ const fail = (e) => {
5559
+ if (settled) return;
5560
+ settled = true;
5561
+ try {
5562
+ sock.destroy();
5563
+ } catch {
5564
+ }
5565
+ reject(e);
5566
+ };
5567
+ sock.once("secureConnect", () => {
5568
+ if (settled) return;
5569
+ settled = true;
5570
+ try {
5571
+ sock.destroy();
5572
+ } catch {
5573
+ }
5574
+ resolve(true);
5575
+ });
5576
+ sock.once("error", fail);
5577
+ sock.setTimeout(ms, () => fail(Object.assign(new Error("tls-timeout"), { code: "ETIMEDOUT" })));
5578
+ }));
5579
+ const started = Date.now();
5580
+ const verdict = (ok, stage, detail) => ({ ok, stage, host: host2, port, detail, at: started });
5581
+ return lookup(host2).then((addr) => connect({ host: addr, port, servername: host2, timeout: ms })).then(() => verdict(true, "tls", "TLS \u63E1\u624B\u5B8C\u6210")).catch((e) => {
5582
+ const code = String(e && (e.code || e.message) || e);
5583
+ if (/ENOTFOUND/i.test(code)) return verdict(false, "dns", code);
5584
+ if (/ECONNREFUSED/i.test(code)) return verdict(false, "tcp", code);
5585
+ if (/EPROTO|handshake|ALPR|CERT|UNEXPECTED/i.test(code)) return verdict(false, "tls", code);
5586
+ if (/EAI_AGAIN|getaddrinfo|ESERVFAIL|ENODATA/i.test(code)) return verdict(null, "dns", code);
5587
+ if (/ETIMEDOUT|ECONNRESET|EHOSTUNREACH|ENETUNREACH|timeout/i.test(code)) return verdict(null, "tcp", code);
5588
+ return verdict(null, "tcp", code);
5589
+ });
5590
+ }
5591
+ var _reachCache = /* @__PURE__ */ new Map();
5592
+ function reach(host2, o) {
5593
+ const ov = o || {};
5594
+ const h = String(host2 || "").toLowerCase();
5595
+ if (!h) return Promise.resolve({ ok: null, stage: "not-attempted", host: host2 || null, port: null, detail: "\u6CA1\u6709\u53EF\u5224\u5B9A\u7684\u4E3B\u673A", at: Date.now() });
5596
+ const ttl = ov.ttlMs === void 0 ? READ_TTL_MS : ov.ttlMs;
5597
+ const hit = _reachCache.get(h);
5598
+ if (!ov.force && ttl > 0 && hit && Date.now() - hit.value.at < ttl) {
5599
+ return Promise.resolve(Object.assign({}, hit.value, { cached: true }));
5600
+ }
5601
+ const port = ov.port || 443;
5602
+ return reachWith(ov, h, port, ov.timeoutMs).then((v) => {
5603
+ _reachCache.set(h, { value: v });
5604
+ return v;
5605
+ });
5606
+ }
5607
+ function reachRead(host2) {
5608
+ const h = String(host2 || "").toLowerCase();
5609
+ const hit = _reachCache.get(h);
5610
+ return hit ? hit.value : null;
5611
+ }
5612
+ function hosts() {
5613
+ return [..._reachCache.keys()];
5614
+ }
5615
+ function invalidate(host2) {
5616
+ if (host2 === void 0 || host2 === null) {
5617
+ const n = _reachCache.size + _proxyCache.size;
5618
+ _reachCache.clear();
5619
+ _proxyCache.clear();
5620
+ return n;
5621
+ }
5622
+ return _reachCache.delete(String(host2).toLowerCase()) ? 1 : 0;
5623
+ }
5624
+ module2.exports = {
5625
+ PROBE_TIMEOUT_MS,
5626
+ READ_TTL_MS,
5627
+ hostOf,
5628
+ proxy,
5629
+ proxyRead,
5630
+ proxyWin,
5631
+ proxyMac,
5632
+ proxyLinux,
5633
+ reach,
5634
+ reachRead,
5635
+ reachWith,
5636
+ hosts,
5637
+ invalidate
5638
+ };
5639
+ }
5640
+ });
5641
+
5642
+ // src/platform/contract/shell-report.js
5643
+ var require_shell_report = __commonJS({
5644
+ "src/platform/contract/shell-report.js"(exports2, module2) {
5645
+ "use strict";
5646
+ var fs2 = require("node:fs");
5647
+ var path2 = require("node:path");
5648
+ var stateRoot2 = require_state_root();
5649
+ var { maskProxyServer, maskProxySecrets } = require_redact();
5650
+ var SUPPORTED_SCHEMA = 1;
5651
+ var FILE_NAME = "shell-report.json";
5652
+ var MAX_BYTES = 256 * 1024;
5653
+ var MAX_ROWS = 64;
5654
+ function file() {
5655
+ return path2.join(stateRoot2.supervisorDir(), FILE_NAME);
5656
+ }
5657
+ var str = (v) => typeof v === "string" && v.trim() ? maskProxySecrets(v.trim()) : null;
5658
+ var raw = (v) => typeof v === "string" && v.trim() ? v.trim() : null;
5659
+ var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
5660
+ var tri = (v) => v === true || v === false ? v : null;
5661
+ var list = (v) => Array.isArray(v) ? v : [];
5662
+ function nodeView(n) {
5663
+ const o = n && typeof n === "object" ? n : null;
5664
+ if (!o) return null;
5665
+ return { path: str(o.path), binDir: str(o.binDir), version: raw(o.version), min: raw(o.min), ok: tri(o.ok) };
5666
+ }
5667
+ function npmView(n) {
5668
+ const o = n && typeof n === "object" ? n : null;
5669
+ if (!o) return null;
5670
+ return { path: str(o.path), args: list(o.args).map(String), version: raw(o.version), ok: tri(o.ok) };
5671
+ }
5672
+ function prefixView(n) {
5673
+ const o = n && typeof n === "object" ? n : null;
5674
+ if (!o) return null;
5675
+ return { dir: str(o.dir), writable: tri(o.writable), why: str(o.why) };
5676
+ }
5677
+ function registryView(n) {
5678
+ const o = n && typeof n === "object" ? n : null;
5679
+ if (!o) return null;
5680
+ const rows = list(o.probes).slice(0, MAX_ROWS).map((p) => ({
5681
+ url: p && typeof p === "object" ? maskProxyServer(raw(p.url)) : null,
5682
+ ok: p && typeof p === "object" ? tri(p.ok) : null,
5683
+ latencyMs: p && typeof p === "object" ? num(p.latencyMs) : null
5684
+ }));
5685
+ return { best: maskProxyServer(raw(o.best)), latencyMs: num(o.latencyMs), probes: rows, probesTotal: list(o.probes).length };
5686
+ }
5687
+ function recordsView(recs) {
5688
+ const all = list(recs);
5689
+ const rows = all.slice(0, MAX_ROWS).map((r) => {
5690
+ const o = r && typeof r === "object" ? r : {};
5691
+ return {
5692
+ probe: raw(o.probe) || "unknown",
5693
+ source: str(o.source) || "",
5694
+ target: str(o.target) || "",
5695
+ ms: num(o.ms),
5696
+ ok: tri(o.ok),
5697
+ note: str(o.note) || ""
5698
+ };
5699
+ });
5700
+ return { rows, truncated: all.length > MAX_ROWS ? all.length - MAX_ROWS : 0 };
5701
+ }
5702
+ function bodyOf(j) {
5703
+ const recs = recordsView(j.records);
5704
+ const body = {
5705
+ writtenBy: raw(j.writtenBy),
5706
+ schema: num(j.schema),
5707
+ node: nodeView(j.node),
5708
+ npm: npmView(j.npm),
5709
+ prefix: prefixView(j.prefix),
5710
+ registry: registryView(j.registry),
5711
+ records: recs.rows,
5712
+ droppedRecords: recs.truncated
5713
+ };
5714
+ const seen = [body.node, body.npm, body.prefix, body.registry].some((x) => !!x) || body.records.length > 0;
5715
+ return seen ? body : null;
5716
+ }
5717
+ function envelope(p, at, ageMs, reason, body) {
5718
+ return Object.assign({ available: reason === "ok", path: p, at, ageMs, reason }, body || {
5719
+ writtenBy: null,
5720
+ schema: null,
5721
+ node: null,
5722
+ npm: null,
5723
+ prefix: null,
5724
+ registry: null,
5725
+ records: [],
5726
+ droppedRecords: 0
5727
+ });
5728
+ }
5729
+ function read(o) {
5730
+ const now = o && typeof o.now === "function" ? o.now : Date.now;
5731
+ const p = file();
5732
+ let text;
5733
+ try {
5734
+ const st = fs2.statSync(p);
5735
+ if (st.size > MAX_BYTES) return envelope(p, null, null, "unreadable-or-schema-mismatch", null);
5736
+ text = fs2.readFileSync(p, "utf8");
5737
+ } catch (e) {
5738
+ if (e && e.code === "ENOENT") return envelope(p, null, null, "never-written", null);
5739
+ return envelope(p, null, null, "unreadable-or-schema-mismatch", null);
5740
+ }
5741
+ let j;
5742
+ try {
5743
+ j = JSON.parse(text);
5744
+ } catch {
5745
+ return envelope(p, null, null, "unreadable-or-schema-mismatch", null);
5746
+ }
5747
+ if (!j || typeof j !== "object" || Array.isArray(j) || num(j.schema) !== SUPPORTED_SCHEMA) {
5748
+ return envelope(p, null, null, "unreadable-or-schema-mismatch", null);
5749
+ }
5750
+ const at = num(j.at);
5751
+ if (at === null) return envelope(p, null, null, "unreadable-or-schema-mismatch", null);
5752
+ const ageMs = Math.max(0, now() - at);
5753
+ const body = bodyOf(j);
5754
+ if (!body) return envelope(p, at, null, "unreadable-or-schema-mismatch", null);
5755
+ return envelope(p, at, ageMs, "ok", body);
5756
+ }
5757
+ module2.exports = { SUPPORTED_SCHEMA, FILE_NAME, MAX_BYTES, MAX_ROWS, file, read };
5758
+ }
5759
+ });
5760
+
5408
5761
  // src/platform/os/environment.js
5409
5762
  var require_environment = __commonJS({
5410
5763
  "src/platform/os/environment.js"(exports2, module2) {
@@ -5414,12 +5767,17 @@ var require_environment = __commonJS({
5414
5767
  var path2 = require("node:path");
5415
5768
  var stateRoot2 = require_state_root();
5416
5769
  var { writeAtomic } = require_fs();
5770
+ var { maskProxyServer, maskProxySecrets } = require_redact();
5417
5771
  var desktop = require_desktop();
5418
5772
  var detector = require_browser_inventory();
5773
+ var egress = require_egress();
5774
+ var shellReport = require_shell_report();
5419
5775
  var { engineOf } = detector;
5420
- var SCHEMA = 1;
5776
+ var SCHEMA = 2;
5421
5777
  var FILE_NAME = "environment.json";
5422
5778
  var FORM_TTL_MS = 6e4;
5779
+ var SECTION_TTL_MS = 6e4;
5780
+ var SHELL_REPORT_TTL_MS = 1e4;
5423
5781
  var _sources = {};
5424
5782
  function bind(sources) {
5425
5783
  _sources = Object.assign({}, _sources, sources || {});
@@ -5510,6 +5868,148 @@ var require_environment = __commonJS({
5510
5868
  if (list.length > 1) return out(rankCandidates(list)[0], "candidate-rank");
5511
5869
  return out(null, "none-found");
5512
5870
  }
5871
+ var _sections = /* @__PURE__ */ new Map();
5872
+ var _reads = /* @__PURE__ */ new Map();
5873
+ var SECTION_ORDER = ["runtime", "shell", "dsh", "browsers", "session", "egress", "capabilities", "preference", "pick", "startup"];
5874
+ var SYNC_DIMS = ["browsers", "session", "capabilities", "preference", "pick"];
5875
+ function registerSection(id, def) {
5876
+ if (!id || !def || typeof def.probe !== "function") throw new Error("registerSection(" + id + ") \u9700\u8981 probe \u51FD\u6570");
5877
+ if (SYNC_DIMS.includes(id)) throw new Error("\u7EF4\u5EA6 " + id + " \u7531\u8868\u5355\u6BCF\u62CD\u81EA\u88C5\uFF0C\u4E0D\u63A5\u6CE8\u518C");
5878
+ const d = { id, label: def.label || id, probe: def.probe, ttlMs: def.ttlMs === void 0 ? SECTION_TTL_MS : def.ttlMs, source: def.source || "registered" };
5879
+ _sections.set(id, d);
5880
+ _reads.delete(id);
5881
+ return d;
5882
+ }
5883
+ function unregisterSection(id) {
5884
+ _sections.delete(id);
5885
+ _reads.delete(id);
5886
+ }
5887
+ function section(id) {
5888
+ return _reads.get(id) || null;
5889
+ }
5890
+ function sectionData(id) {
5891
+ const r = _reads.get(id);
5892
+ return r ? r.data || null : null;
5893
+ }
5894
+ function proxyDataOf(p) {
5895
+ return p ? { state: p.state, server: maskProxyServer(p.server), pac: p.pac || null, source: p.source, cached: p.cached === true } : null;
5896
+ }
5897
+ function egressData(proxyReading) {
5898
+ const targets = {};
5899
+ for (const h of egress.hosts()) {
5900
+ const r = egress.reachRead(h);
5901
+ if (r) targets[h] = { ok: r.ok === null ? null : r.ok === true, stage: r.stage, detail: r.detail, at: r.at };
5902
+ }
5903
+ const p = proxyReading || egress.proxyRead();
5904
+ const probed = [];
5905
+ if (p) {
5906
+ for (const row of p.probed || []) probed.push({ source: row.source, detail: maskProxySecrets(String(row.detail || "")) });
5907
+ probed.push({ source: p.source, detail: "proxy=" + p.state + (p.server ? " (" + maskProxyServer(p.server) + ")" : "") + (p.cached ? " \u590D\u7528" : "") });
5908
+ } else {
5909
+ probed.push({ source: "egress", detail: "\u7CFB\u7EDF\u4EE3\u7406\u672A\u8BFB\uFF08\u672C\u7EF4\u5EA6\u5C1A\u672A\u5237\u65B0\uFF09" });
5910
+ }
5911
+ for (const h of Object.keys(targets)) {
5912
+ const t = targets[h];
5913
+ probed.push({ source: "reach:" + h, detail: (t.ok === null ? "unknown" : t.ok ? "ok" : "no-route") + "@" + t.stage + " " + t.detail });
5914
+ }
5915
+ return {
5916
+ at: p ? p.at : null,
5917
+ proxy: proxyDataOf(p),
5918
+ targets,
5919
+ probed
5920
+ };
5921
+ }
5922
+ registerSection("egress", {
5923
+ label: "\u51FA\u7F51\u6761\u4EF6",
5924
+ source: "self",
5925
+ probe: (o) => {
5926
+ const ov = o || {};
5927
+ const force = ov.force === true;
5928
+ const hosts = Array.isArray(ov.hosts) ? ov.hosts : egress.hosts();
5929
+ const reachOpts = { force, timeoutMs: ov.timeoutMs, lookup: ov.lookup, connect: ov.connect, ttlMs: ov.ttlMs };
5930
+ return Promise.all([egress.proxy(Object.assign({}, ov, { force }))].concat(hosts.map((h) => egress.reach(h, reachOpts)))).then(([p]) => egressData(p));
5931
+ }
5932
+ });
5933
+ registerSection("shell", {
5934
+ label: "\u684C\u9762\u58F3\u6240\u89C1\uFF08Node/npm/\u955C\u50CF\u6E90/\u5168\u5C40\u524D\u7F00\uFF09",
5935
+ source: "shell",
5936
+ ttlMs: SHELL_REPORT_TTL_MS,
5937
+ probe: () => shellReport.read()
5938
+ });
5939
+ async function probeSection(id, o) {
5940
+ const def = _sections.get(id);
5941
+ if (!def) return null;
5942
+ const ov = o || {};
5943
+ const now = typeof ov.now === "function" ? ov.now : Date.now;
5944
+ try {
5945
+ const data = await def.probe(ov);
5946
+ _reads.set(id, { at: now(), source: def.source, label: def.label, state: data ? "ok" : "empty", data: data || null, error: null });
5947
+ } catch (e) {
5948
+ _reads.set(id, { at: now(), source: def.source, label: def.label, state: "error", data: null, error: String(e && (e.code || e.message) || e) });
5949
+ }
5950
+ return _reads.get(id);
5951
+ }
5952
+ function staleOf(id, now, force) {
5953
+ if (force) return true;
5954
+ const def = _sections.get(id);
5955
+ const read = _reads.get(id);
5956
+ if (!def || !read) return true;
5957
+ return now - read.at >= def.ttlMs;
5958
+ }
5959
+ async function refresh(o) {
5960
+ const ov = o || {};
5961
+ const now = typeof ov.now === "function" ? ov.now : Date.now;
5962
+ const ids = Array.isArray(ov.only) && ov.only.length ? ov.only : [..._sections.keys()];
5963
+ await Promise.all(ids.filter((id) => _sections.has(id) && staleOf(id, now(), ov.force)).map((id) => probeSection(id, ov)));
5964
+ return form(Object.assign({}, ov, { force: true }));
5965
+ }
5966
+ async function checkEgress(url, o) {
5967
+ const ov = o || {};
5968
+ const host2 = egress.hostOf(url);
5969
+ let data = ov.egress === void 0 ? null : ov.egress;
5970
+ if (!data) {
5971
+ try {
5972
+ const hosts = new Set(egress.hosts());
5973
+ if (host2) {
5974
+ await egress.reach(host2, ov);
5975
+ hosts.add(host2);
5976
+ }
5977
+ const read = await probeSection("egress", Object.assign({}, ov, { hosts: [...hosts] }));
5978
+ data = read && read.data || sectionData("egress");
5979
+ } catch {
5980
+ data = sectionData("egress");
5981
+ }
5982
+ }
5983
+ const v = coldProfileViable(data, host2);
5984
+ return Object.assign({}, v, {
5985
+ host: host2,
5986
+ proxy: data && data.proxy ? data.proxy.state : "unknown",
5987
+ at: data ? data.at || null : null
5988
+ });
5989
+ }
5990
+ function coldProfileViable(eg, host2) {
5991
+ if (!eg) return { viable: null, basis: "egress-unprobed", detail: "\u51FA\u7F51\u6761\u4EF6\u5C1A\u672A\u63A2\u6D4B\uFF0C\u9694\u79BB\u7A97\u53E3\u6309\u539F\u6863\u6253\u5F00" };
5992
+ const t = host2 && eg.targets ? eg.targets[host2] : null;
5993
+ const reached = t ? t.ok : null;
5994
+ const proxyState = eg.proxy ? eg.proxy.state : "unknown";
5995
+ if (reached === true) {
5996
+ return { viable: true, basis: "target-reachable", detail: host2 + " \u76F4\u8FDE\u53EF\u8FBE\uFF08" + t.stage + "\uFF09" };
5997
+ }
5998
+ if (reached === null) {
5999
+ return { viable: null, basis: "egress-undetermined", detail: host2 + " \u7684\u901A\u8DEF\u5224\u5B9A\u6CA1\u6709\u7ED9\u51FA\u7B54\u6848\uFF08" + (t ? t.stage + " " + t.detail : "\u65E0\u8BFB\u6570") + "\uFF09" };
6000
+ }
6001
+ if (proxyState === "on") {
6002
+ return { viable: true, basis: "cold-profile-inherits-proxy", detail: host2 + " \u76F4\u8FDE\u4E0D\u901A\uFF08" + t.stage + "\uFF09\uFF0C\u7CFB\u7EDF\u7EA7\u4EE3\u7406\u5728\u7528\uFF0C\u51B7\u6863\u6848\u540C\u4E00\u6761\u8DEF" };
6003
+ }
6004
+ if (proxyState === "unknown") {
6005
+ return { viable: null, basis: "proxy-unreadable", detail: host2 + " \u76F4\u8FDE\u4E0D\u901A\uFF08" + t.stage + "\uFF09\uFF0C\u4F46\u4EE3\u7406\u8BFB\u6570\u53D6\u4E0D\u5230\uFF0C\u6309\u5224\u4E0D\u51FA\u5904\u7406" };
6006
+ }
6007
+ return {
6008
+ viable: false,
6009
+ basis: "cold-profile-blocked",
6010
+ detail: host2 + " \u76F4\u8FDE\u4E0D\u901A\uFF08" + t.stage + " " + t.detail + "\uFF09\u4E14\u7CFB\u7EDF\u6CA1\u6709\u5728\u7528\u4EE3\u7406\uFF0C\u51B7\u6863\u6848\u7A97\u53E3\u5FC5\u7136\u7A7A\u767D"
6011
+ };
6012
+ }
5513
6013
  function snapshotPath() {
5514
6014
  return path2.join(stateRoot2.supervisorDir(), FILE_NAME);
5515
6015
  }
@@ -5521,6 +6021,23 @@ var require_environment = __commonJS({
5521
6021
  return null;
5522
6022
  }
5523
6023
  }
6024
+ function lastSnapshot(o) {
6025
+ const now = o && typeof o.now === "function" ? o.now : Date.now;
6026
+ const p = snapshotPath();
6027
+ const doc = readSnapshot();
6028
+ if (doc) {
6029
+ const at = typeof doc.at === "number" ? doc.at : null;
6030
+ return { available: true, path: p, at, ageMs: at === null ? null : Math.max(0, now() - at), reason: "ok", data: doc };
6031
+ }
6032
+ return {
6033
+ available: false,
6034
+ path: p,
6035
+ at: null,
6036
+ ageMs: null,
6037
+ reason: fs2.existsSync(p) ? "unreadable-or-schema-mismatch" : "never-written",
6038
+ data: null
6039
+ };
6040
+ }
5524
6041
  var _formCache = null;
5525
6042
  function form(o) {
5526
6043
  const ov = o || {};
@@ -5560,6 +6077,45 @@ var require_environment = __commonJS({
5560
6077
  source: "form",
5561
6078
  detail: pick.how + (pick.browser ? "\uFF08" + pick.browser.name + "\uFF09" : "\uFF08\u65E0\u5019\u9009\uFF09") + (pick.stale ? "\uFF0C\u504F\u597D\u5DF2\u5931\u6548\u9700\u91CD\u9009" : "")
5562
6079
  });
6080
+ const sections = {};
6081
+ const syncDims = {
6082
+ browsers: { at: stamp, state: inv.browsers.length ? "ok" : "empty", count: inv.browsers.length, defaultSource: inv.defaultSource },
6083
+ session: { at: stamp, state: session.available ? "ok" : "missing", reason: session.reason },
6084
+ capabilities: { at: stamp, state: caps ? "ok" : "unbound", openBrowser: caps ? caps.openBrowser === true : null },
6085
+ preference: { at: stamp, state: preference.reason === "matched" ? "ok" : preference.configured ? "stale" : "unset", id: preference.id },
6086
+ pick: { at: stamp, state: pick.browser ? "ok" : "empty", how: pick.how, id: pick.browser ? pick.browser.id : null }
6087
+ };
6088
+ const dimOf = (id) => {
6089
+ const def = _sections.get(id);
6090
+ const read = _reads.get(id);
6091
+ if (read && !syncDims[id]) {
6092
+ return { label: def ? def.label : id, at: read.at, source: read.source, state: read.state, data: read.data, error: read.error || null };
6093
+ }
6094
+ const s = syncDims[id];
6095
+ if (s) return Object.assign({ label: id, source: "self" }, s);
6096
+ return { label: def ? def.label : id, at: null, source: def ? def.source : "registered", state: "pending", data: null, error: null };
6097
+ };
6098
+ const ids = SECTION_ORDER.concat([..._sections.keys()].filter((id) => !SECTION_ORDER.includes(id)));
6099
+ for (const id of ids) {
6100
+ if (sections[id]) continue;
6101
+ const entry = dimOf(id);
6102
+ sections[id] = entry;
6103
+ if (entry.state === "pending") {
6104
+ probed.push({ section: id, source: "form", detail: "\u672A\u5237\u65B0\uFF08\u7B49\u542F\u52A8\u88C5\u914D\u6216\u9762\u677F force \u5237\u65B0\u8865\u62CD\uFF09" });
6105
+ } else if (entry.state === "error") {
6106
+ probed.push({ section: id, source: "probe", detail: id + " \u63A2\u6D4B\u5931\u8D25: " + entry.error });
6107
+ }
6108
+ }
6109
+ const egressRows = ((sections.egress || {}).data || {}).probed || [];
6110
+ for (const row of egressRows) probed.push({ section: "egress", source: row.source, detail: row.detail });
6111
+ const sh = (sections.shell || {}).data;
6112
+ if (sh) {
6113
+ probed.push({
6114
+ section: "shell",
6115
+ source: "shell-report:" + (sh.reason || "?"),
6116
+ detail: sh.available === true ? "\u58F3\u5DF2\u4E0A\u62A5\uFF08\u5199\u5165\u8005 " + (sh.writtenBy || "\u672A\u7F72\u540D") + "\uFF0Cschema " + sh.schema + "\uFF0C\u8DDD\u4ECA " + (sh.ageMs === null ? "\u672A\u8BFB\u51FA" : sh.ageMs) + " \u6BEB\u79D2\uFF0C\u660E\u7EC6 " + (sh.records || []).length + " \u6761" + (sh.droppedRecords ? "\uFF0C\u622A\u65AD " + sh.droppedRecords + " \u6761" : "") + "\uFF09" : sh.reason === "never-written" ? "\u8FD9\u53F0\u673A\u5668\u7684\u58F3\u8FD8\u6CA1\u62A5\u8FC7\uFF08\u5185\u6838\u72EC\u7ACB\u8DD1\u6216\u8001\u7248\u672C\u58F3\u65F6\u662F\u5E38\u6001\uFF0C\u4E0D\u662F\u6545\u969C\uFF09" : "\u58F3\u62A5\u7684\u6587\u4EF6\u8BFB\u4E0D\u51FA\u6216\u7248\u672C\u4E0D\u7B26\uFF0C\u5F97\u67E5\uFF1A" + (sh.path || "?")
6117
+ });
6118
+ }
5563
6119
  const value = {
5564
6120
  schema: SCHEMA,
5565
6121
  at: stamp,
@@ -5572,6 +6128,7 @@ var require_environment = __commonJS({
5572
6128
  default: inv.defaultId ? { id: inv.defaultId, source: inv.defaultSource } : null,
5573
6129
  browsers: inv.browsers,
5574
6130
  pick: { how: pick.how, id: pick.browser ? pick.browser.id : null, name: pick.browser ? pick.browser.name : null, wanted: pick.wanted, stale: pick.stale },
6131
+ sections,
5575
6132
  probed
5576
6133
  };
5577
6134
  const snapshot = { path: snapshotPath(), written: false, error: null };
@@ -5592,8 +6149,14 @@ var require_environment = __commonJS({
5592
6149
  _formCache = { at: stamp, value };
5593
6150
  return Object.assign({ cached: false }, value);
5594
6151
  }
5595
- function invalidate(platform) {
6152
+ function invalidate(platform, only) {
5596
6153
  _formCache = null;
6154
+ const list = only === void 0 ? null : Array.isArray(only) ? only : [only];
6155
+ if (!list || list.includes("egress")) egress.invalidate();
6156
+ for (const id of list || [..._reads.keys()]) {
6157
+ const r = _reads.get(id);
6158
+ if (r) r.at = 0;
6159
+ }
5597
6160
  return detector.invalidate(platform);
5598
6161
  }
5599
6162
  function checkPreference(value, form2) {
@@ -5615,6 +6178,9 @@ var require_environment = __commonJS({
5615
6178
  SCHEMA,
5616
6179
  FILE_NAME,
5617
6180
  FORM_TTL_MS,
6181
+ SECTION_TTL_MS,
6182
+ SECTION_ORDER,
6183
+ SYNC_DIMS,
5618
6184
  bind,
5619
6185
  preferenceId,
5620
6186
  capabilities,
@@ -5625,9 +6191,17 @@ var require_environment = __commonJS({
5625
6191
  rankCandidates,
5626
6192
  pickLauncher,
5627
6193
  checkPreference,
6194
+ registerSection,
6195
+ unregisterSection,
6196
+ section,
6197
+ sectionData,
6198
+ refresh,
6199
+ coldProfileViable,
6200
+ checkEgress,
5628
6201
  form,
5629
6202
  snapshotPath,
5630
6203
  readSnapshot,
6204
+ lastSnapshot,
5631
6205
  invalidate
5632
6206
  };
5633
6207
  }
@@ -6513,9 +7087,7 @@ var require_browser = __commonJS({
6513
7087
  }));
6514
7088
  const pk = picked || {};
6515
7089
  return {
6516
- platform: inv && inv.platform || null,
6517
7090
  pick: pk.how || plan && plan.pick || "none",
6518
- bin: plan && plan.bin || null,
6519
7091
  default: inv && inv.defaultId ? { id: inv.defaultId, source: inv.defaultSource || null } : null,
6520
7092
  preference: pk.wanted ? { id: pk.wanted, matched: pk.stale !== true } : null,
6521
7093
  found,
@@ -6556,15 +7128,42 @@ var require_browser = __commonJS({
6556
7128
  if (bin.includes("/") || bin.includes("\\") || /^[A-Za-z]:[\\/]/.test(bin)) return isExecutableFile(bin);
6557
7129
  return resolveExecutable(bin) !== null;
6558
7130
  }
7131
+ function logOpen(lg, run, res) {
7132
+ const ev = res.evidence || {};
7133
+ const tier = res.ok ? res.confirmed ? "confirmed" : "handedOff" : "failed";
7134
+ const exit = ev.exitSignal ? " signal=" + ev.exitSignal : ev.exitCode === null || ev.exitCode === void 0 ? "" : " exit=" + ev.exitCode;
7135
+ const line = "[open] intent=" + run.intent + " via=" + (ev.via || "-") + " engine=" + (ev.engine || "-") + " bin=" + (ev.bin || "-") + " isolated=" + (ev.isolated === true) + " argv=" + (run.args || []).map(redactArg).join(" ") + " => " + tier + (res.reason ? " reason=" + res.reason : "") + exit + (ev.error ? " error=" + ev.error : "");
7136
+ const fn = lg.info || lg.warn;
7137
+ if (typeof fn !== "function") return;
7138
+ try {
7139
+ fn.call(lg, line);
7140
+ } catch {
7141
+ }
7142
+ }
7143
+ function redactArg(a) {
7144
+ const s = String(a);
7145
+ let cut = -1;
7146
+ for (const ch of ["?", "#"]) {
7147
+ const i = s.indexOf(ch);
7148
+ if (i >= 0 && (cut < 0 || i < cut)) cut = i;
7149
+ }
7150
+ return cut < 0 ? s : s.slice(0, cut) + "[trimmed]";
7151
+ }
6559
7152
  async function openBrowser(url, o) {
6560
7153
  const opts = o || {};
6561
7154
  const pl = opts.platform || process.platform;
6562
7155
  const intent = opts.intent === "isolated-login" ? "isolated-login" : "plain";
7156
+ const run = { intent, args: null };
7157
+ const out = (p) => {
7158
+ const res = outcome(p);
7159
+ if (opts.logger) logOpen(opts.logger, run, res);
7160
+ return res;
7161
+ };
6563
7162
  if (!isSafeHttpUrl(url)) {
6564
- return outcome({ ok: false, reason: "unsafe-url", url: String(url || ""), evidence: null });
7163
+ return out({ ok: false, reason: "unsafe-url", url: String(url || ""), evidence: null });
6565
7164
  }
6566
7165
  if (!SUPPORTED_OPEN_PLATFORMS.includes(pl)) {
6567
- return outcome({ ok: false, reason: "unsupported-platform", url, evidence: { platform: pl } });
7166
+ return out({ ok: false, reason: "unsupported-platform", url, evidence: { platform: pl } });
6568
7167
  }
6569
7168
  const observeMs = opts.observeMs === void 0 ? OPEN_OBSERVE_MS : opts.observeMs;
6570
7169
  const spawnWith = typeof opts.spawn === "function" ? opts.spawn : intent === "isolated-login" ? _spawnDetached : _spawnDetachedIgnored;
@@ -6577,8 +7176,10 @@ var require_browser = __commonJS({
6577
7176
  const picked = opts.pick || environment.pickLauncher(pl, inv, pref);
6578
7177
  const form = formOfBin(pl, picked.browser);
6579
7178
  const canIsolate = intent === "isolated-login" && form.direct && (form.engine === "chromium" || form.engine === "firefox");
7179
+ const cold = canIsolate ? await environment.checkEgress(url, opts) : null;
7180
+ const isolate = canIsolate && (!cold || cold.viable !== false);
6580
7181
  let profile = null;
6581
- if (canIsolate) {
7182
+ if (isolate) {
6582
7183
  const alloc = typeof opts.allocProfile === "function" ? opts.allocProfile : (() => allocTempDir("dsh-login-"));
6583
7184
  try {
6584
7185
  profile = opts.profileDir || alloc();
@@ -6587,6 +7188,7 @@ var require_browser = __commonJS({
6587
7188
  }
6588
7189
  }
6589
7190
  const plan = intent === "isolated-login" ? isolatedPlan(pl, url, { inventory: inv, pick: picked, profileDir: profile, size: login.size, lang: login.lang }) : openPlan(pl, url, { inventory: inv, pick: picked });
7191
+ run.args = plan.args;
6590
7192
  const diagnostics = launchDiagnostics(inv, plan, picked);
6591
7193
  const evidence = {
6592
7194
  bin: plan.bin,
@@ -6599,12 +7201,15 @@ var require_browser = __commonJS({
6599
7201
  exitCode: null,
6600
7202
  exitSignal: null,
6601
7203
  error: null,
6602
- diagnostics
7204
+ diagnostics,
7205
+ egress: cold
6603
7206
  };
7207
+ const downgraded = cold && cold.viable === false;
7208
+ const downgradeText = downgraded ? "\u672C\u673A\u76F4\u8FDE " + cold.host + " \u4E0D\u901A\u4E14\u6CA1\u6709\u5728\u7528\u7CFB\u7EDF\u4EE3\u7406\uFF0C\u9694\u79BB\u7A97\u53E3\u4F1A\u662F\u7A7A\u767D\u9875\uFF1B\u5DF2\u5728\u73B0\u6709\u6D4F\u89C8\u5668\u7A97\u53E3\u6253\u5F00\u8BE5\u5730\u5740\uFF08\u767B\u5F55\u5B8C\u6210\u540E\u8BF7\u624B\u52A8\u6E05\u7406\u8D26\u53F7\uFF0C\u6216\u5148\u5728\u7CFB\u7EDF\u91CC\u914D\u597D\u4EE3\u7406\uFF09" : null;
6604
7209
  const deferredRemove = typeof opts.rmTree === "function" ? opts.rmTree : removeTreeDeferred;
6605
7210
  const fail = (reason, patch) => {
6606
7211
  if (profile) deferredRemove(profile, 0);
6607
- return outcome(Object.assign({ ok: false, reason, url, evidence }, patch));
7212
+ return out(Object.assign({ ok: false, reason, url, evidence }, patch));
6608
7213
  };
6609
7214
  const desktopAvailable = typeof opts.desktopAvailable === "function" ? opts.desktopAvailable : desktop.sessionAvailable;
6610
7215
  if (pl === "linux" && !desktopAvailable()) {
@@ -6612,7 +7217,7 @@ var require_browser = __commonJS({
6612
7217
  }
6613
7218
  if (!plan.bin) return fail("no-launcher");
6614
7219
  if (!avail(plan.bin)) return fail("no-launcher");
6615
- if (canIsolate && !profile) {
7220
+ if (isolate && !profile) {
6616
7221
  evidence.error = "\u4E34\u65F6 profile \u76EE\u5F55\u5206\u914D\u5931\u8D25";
6617
7222
  return fail("spawn-failed");
6618
7223
  }
@@ -6629,10 +7234,10 @@ var require_browser = __commonJS({
6629
7234
  evidence.error = seen.stage === "error" ? String(seen.code) : null;
6630
7235
  evidence.exitCode = seen.code === void 0 ? null : seen.code;
6631
7236
  evidence.exitSignal = seen.signal === void 0 ? null : seen.signal;
6632
- if (seen.stage === "error") return outcome({ ok: false, reason: "spawn-failed", url, evidence });
7237
+ if (seen.stage === "error") return out({ ok: false, reason: "spawn-failed", url, evidence });
6633
7238
  const exitDecides = seen.stage === "exit" && plan.exitIsEvidence === true;
6634
7239
  if (exitDecides && (seen.code !== 0 || seen.signal)) {
6635
- return outcome({
7240
+ return out({
6636
7241
  ok: false,
6637
7242
  reason: seen.signal ? "killed-by-signal" : "exit-nonzero",
6638
7243
  url,
@@ -6640,7 +7245,14 @@ var require_browser = __commonJS({
6640
7245
  error: FAILURE_TEXT[seen.signal ? "killed-by-signal" : "exit-nonzero"] + "\uFF08" + (seen.signal || seen.code) + "\uFF09"
6641
7246
  });
6642
7247
  }
6643
- return outcome({ ok: true, confirmed: exitDecides, handedOff: !exitDecides, url, evidence });
7248
+ return out({
7249
+ ok: true,
7250
+ confirmed: exitDecides,
7251
+ handedOff: !exitDecides,
7252
+ url,
7253
+ evidence,
7254
+ message: downgradeText || void 0
7255
+ });
6644
7256
  }
6645
7257
  module2.exports = {
6646
7258
  openBrowser,
@@ -7108,6 +7720,7 @@ var require_bootstrap = __commonJS({
7108
7720
  var { createShellWatchdog } = require_watchdog();
7109
7721
  var pidlook = require_pidlookup();
7110
7722
  var platform = require_os();
7723
+ var ENV_FORM_STARTUP_DELAY_MS = 3e3;
7111
7724
  function _bootstrap(host2) {
7112
7725
  try {
7113
7726
  host2.events.append("guard_started", {
@@ -7123,6 +7736,15 @@ var require_bootstrap = __commonJS({
7123
7736
  } catch {
7124
7737
  }
7125
7738
  host2.logger.info("guard started v" + host2.guardVersion + " pid=" + process.pid);
7739
+ host2._startupFacts = {
7740
+ bootAt: Date.now(),
7741
+ envDelayMs: ENV_FORM_STARTUP_DELAY_MS,
7742
+ routerAutostart: host2.config.routerAutostart === true,
7743
+ routerMode: null,
7744
+ updateCheck: null,
7745
+ shellWatchdog: null,
7746
+ lastRefresh: null
7747
+ };
7126
7748
  host2.tick();
7127
7749
  host2._timer = host2.managedObjects ? null : setInterval(() => host2.tick(), host2.config.probeIntervalMs);
7128
7750
  host2._lastHeartbeatAt = Date.now();
@@ -7178,6 +7800,7 @@ var require_bootstrap = __commonJS({
7178
7800
  }
7179
7801
  if (host2._routerDaemonActive()) host2._writeRouterDaemonLock();
7180
7802
  const rt = host2._ensureRouterRuntime(true);
7803
+ host2._startupFacts.routerMode = rt.mode;
7181
7804
  if (rt.mode === "daemon") {
7182
7805
  host2._disableRouterPersist();
7183
7806
  if (rt.spawned) {
@@ -7218,13 +7841,20 @@ var require_bootstrap = __commonJS({
7218
7841
  rlc._monitoring = false;
7219
7842
  }
7220
7843
  }
7844
+ const checkDelayMs = host2.config.initialCheckDelayMs || 2e4;
7845
+ const checkIntervalMs = host2.config.updateCheckIntervalMs || 36e5;
7846
+ host2._startupFacts.updateCheck = {
7847
+ enabled: host2.config.updateCheckEnabled !== false,
7848
+ initialDelayMs: checkDelayMs,
7849
+ intervalMs: checkIntervalMs
7850
+ };
7221
7851
  if (host2.config.updateCheckEnabled !== false) {
7222
7852
  host2._initialCheckTimer = setTimeout(() => {
7223
7853
  host2.nativeManager.checkUpdate();
7224
- }, host2.config.initialCheckDelayMs || 2e4);
7854
+ }, checkDelayMs);
7225
7855
  host2._upgradeTimer = setInterval(() => {
7226
7856
  host2.nativeManager.checkUpdate();
7227
- }, host2.config.updateCheckIntervalMs || 36e5);
7857
+ }, checkIntervalMs);
7228
7858
  }
7229
7859
  try {
7230
7860
  host2._startShellWatchdog();
@@ -7233,6 +7863,50 @@ var require_bootstrap = __commonJS({
7233
7863
  host2.logger.warn("[shell-watchdog] \u542F\u52A8\u5F02\u5E38\uFF08\u4E0D\u5F71\u54CD\u5B88\u536B\u4E3B\u5FAA\u73AF\uFF09: " + (e && e.message || e));
7234
7864
  }
7235
7865
  }
7866
+ host2._startupFacts.shellWatchdog = !!host2.shellWatchdog;
7867
+ const envTimer = setTimeout(() => {
7868
+ try {
7869
+ host2._refreshEnvironmentForm();
7870
+ } catch (e) {
7871
+ host2.logger.warn && host2.logger.warn("[environment] \u542F\u52A8\u5237\u65B0\u5F02\u5E38\uFF08\u4E0D\u5F71\u54CD\u5B88\u536B\u4E3B\u5FAA\u73AF\uFF09: " + (e && e.message || e));
7872
+ }
7873
+ }, ENV_FORM_STARTUP_DELAY_MS);
7874
+ if (envTimer && envTimer.unref) envTimer.unref();
7875
+ }
7876
+ function _refreshEnvironmentForm(host2) {
7877
+ const startedAt = Date.now();
7878
+ return platform.environment.refresh({ persist: true }).then((f) => {
7879
+ const secs = f && f.sections || {};
7880
+ const pending = Object.keys(secs).filter((id) => secs[id] && secs[id].state === "pending");
7881
+ const failed = Object.keys(secs).filter((id) => secs[id] && secs[id].state === "error");
7882
+ const snap = f && f.snapshot ? f.snapshot : {};
7883
+ if (host2._startupFacts) {
7884
+ const states = {};
7885
+ for (const id of Object.keys(secs)) states[id] = secs[id] ? secs[id].state : "missing";
7886
+ host2._startupFacts.lastRefresh = {
7887
+ at: f && f.at || null,
7888
+ tookMs: Date.now() - startedAt,
7889
+ dims: states,
7890
+ browsers: f && f.browsers && f.browsers.length || 0,
7891
+ pick: f && f.pick && f.pick.how || null,
7892
+ snapshotWritten: snap.written === true
7893
+ };
7894
+ }
7895
+ if (snap.written === false && snap.error) {
7896
+ host2.logger.warn && host2.logger.warn("[environment] \u5FEB\u7167\u672A\u843D\u76D8: " + snap.error);
7897
+ }
7898
+ if (failed.length) {
7899
+ host2.logger.warn && host2.logger.warn("[environment] \u7EF4\u5EA6\u63A2\u6D4B\u5931\u8D25: " + failed.map((id) => id + "(" + secs[id].error + ")").join("; "));
7900
+ }
7901
+ if (pending.length) {
7902
+ host2.logger.warn && host2.logger.warn("[environment] \u7EF4\u5EA6\u65E0\u63A2\u9488\uFF0C\u672C\u673A\u8BE5\u9879\u4E0D\u53EF\u5224: " + pending.join(","));
7903
+ }
7904
+ host2.logger.info && host2.logger.info("[environment] \u5DF2\u5237\u65B0\uFF1A" + Object.keys(secs).length + " \u4E2A\u7EF4\u5EA6\uFF0C\u6D4F\u89C8\u5668\u5019\u9009 " + (f && f.browsers && f.browsers.length || 0) + " \u4E2A\uFF0C\u5206\u53D1\u4F9D\u636E " + (f && f.pick && f.pick.how || "?"));
7905
+ return f;
7906
+ }).catch((e) => {
7907
+ host2.logger.warn && host2.logger.warn("[environment] \u5237\u65B0\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u5B88\u536B\u4E3B\u5FAA\u73AF\uFF09: " + (e && e.message || e));
7908
+ return null;
7909
+ });
7236
7910
  }
7237
7911
  function _startShellWatchdog(host2) {
7238
7912
  if (host2.config.shellWatchdog === false) {
@@ -7302,7 +7976,7 @@ var require_bootstrap = __commonJS({
7302
7976
  }
7303
7977
  }
7304
7978
  }
7305
- module2.exports = { _bootstrap, _startShellWatchdog, _registerFixedPorts, _bindNativeDshCommand };
7979
+ module2.exports = { _bootstrap, _startShellWatchdog, _registerFixedPorts, _bindNativeDshCommand, _refreshEnvironmentForm };
7306
7980
  }
7307
7981
  });
7308
7982
 
@@ -7832,7 +8506,7 @@ var require_release = __commonJS({
7832
8506
  });
7833
8507
 
7834
8508
  // src/platform/contract/registry.js
7835
- var require_registry = __commonJS({
8509
+ var require_registry2 = __commonJS({
7836
8510
  "src/platform/contract/registry.js"(exports2, module2) {
7837
8511
  "use strict";
7838
8512
  var fs2 = require("node:fs");
@@ -7948,7 +8622,7 @@ var require_registry_config = __commonJS({
7948
8622
  "use strict";
7949
8623
  var fs2 = require("node:fs");
7950
8624
  var path2 = require("node:path");
7951
- var registryContract = require_registry();
8625
+ var registryContract = require_registry2();
7952
8626
  var { writeAtomic } = require_fs();
7953
8627
  var policies = require_policies();
7954
8628
  var CONTRACT_TTL_MS = 60 * 1e3;
@@ -8106,7 +8780,7 @@ var require_matrix = __commonJS({
8106
8780
  });
8107
8781
 
8108
8782
  // src/platform/distribution/registry.js
8109
- var require_registry2 = __commonJS({
8783
+ var require_registry3 = __commonJS({
8110
8784
  "src/platform/distribution/registry.js"(exports2, module2) {
8111
8785
  "use strict";
8112
8786
  var matrix = require_matrix();
@@ -8327,7 +9001,7 @@ var require_version_check = __commonJS({
8327
9001
  var { VERSION_RE } = require_version2();
8328
9002
  var input = require_input();
8329
9003
  var policies = require_policies();
8330
- var registry = require_registry2();
9004
+ var registry = require_registry3();
8331
9005
  var ref = require_registry_ref();
8332
9006
  var release = require_release();
8333
9007
  var PKG_NAME_RE = input.PKG_NAME_RE;
@@ -8694,7 +9368,7 @@ var require_distribution = __commonJS({
8694
9368
  var policies = require_policies();
8695
9369
  var release = require_release();
8696
9370
  var registryConfig = require_registry_config();
8697
- var registry = require_registry2();
9371
+ var registry = require_registry3();
8698
9372
  var versionCheck = require_version_check();
8699
9373
  var install = require_install();
8700
9374
  var { semverCompare, VERSION_RE } = require_version2();
@@ -13852,14 +14526,25 @@ var require_capture = __commonJS({
13852
14526
  "src/platform/service/token/capture.js"(exports2, module2) {
13853
14527
  "use strict";
13854
14528
  var ex2 = require_exec();
14529
+ var service = require_service();
13855
14530
  var persist = require_persist();
13856
14531
  var kinds = require_kinds();
13857
14532
  function parseDshTokenLine(line) {
13858
14533
  const m = /(?:dsh web:)?\s*(?:https?:\/\/127\.0\.0\.1:\d+\/\?token=)([A-Za-z0-9_-]+)/.exec(String(line || ""));
13859
14534
  return m ? m[1] : null;
13860
14535
  }
14536
+ var _channelNoticed = /* @__PURE__ */ new Set();
13861
14537
  async function captureJournal(unit, opts) {
13862
- const logger = opts && opts.logger || console;
14538
+ const o = opts || {};
14539
+ const logger = o.logger || console;
14540
+ const kind = (typeof o.providerKind === "function" ? o.providerKind : service.kind)();
14541
+ if (kind !== "systemd") {
14542
+ if (!_channelNoticed.has(unit)) {
14543
+ _channelNoticed.add(unit);
14544
+ logger.info && logger.info("[token] journald \u6863\u5BF9 " + unit + " \u505C\u7528\uFF1A\u672C\u673A\u670D\u52A1\u6863=" + kind + "\uFF0C\u6CA1\u6709 systemd \u5355\u5143\u53EF\u67E5");
14545
+ }
14546
+ return null;
14547
+ }
13863
14548
  const out = await ex2.runOutAsync("journalctl", ["--user", "-u", unit + ".service", "--no-pager", "-o", "cat", "-g", "127\\.0\\.0\\.1:.*token=", "-n", "1"], {
13864
14549
  timeoutMs: 5e3,
13865
14550
  logger
@@ -14361,6 +15046,77 @@ var require_token = __commonJS({
14361
15046
  }
14362
15047
  });
14363
15048
 
15049
+ // src/app/native/npm.js
15050
+ var require_npm = __commonJS({
15051
+ "src/app/native/npm.js"(exports2, module2) {
15052
+ "use strict";
15053
+ var ex2 = require_exec();
15054
+ var runtimeContract = require_runtime();
15055
+ function npmLaunch(host2) {
15056
+ const h = host2 || {};
15057
+ if (h._npmBin) {
15058
+ return { program: h._npmBin, args: Array.isArray(h._npmBinArgs) ? h._npmBinArgs.slice() : [] };
15059
+ }
15060
+ const l = runtimeContract.npmLauncher();
15061
+ return { program: l.program, args: l.args };
15062
+ }
15063
+ async function resolveNpmRoot(host2, opts) {
15064
+ if (host2.npmRoot) return host2.npmRoot;
15065
+ const l = npmLaunch(host2);
15066
+ const r = await ex2.runOutAsync(l.program, l.args.concat(["root", "-g"]), opts || void 0);
15067
+ return r ? r.trim() : null;
15068
+ }
15069
+ async function checkEnvironment(host2) {
15070
+ const errors = [];
15071
+ const l = npmLaunch(host2);
15072
+ const [nv, npmv, npmRoot] = await Promise.all([
15073
+ ex2.runOutAsync("node", ["--version"]),
15074
+ ex2.runOutAsync(l.program, l.args.concat(["--version"])),
15075
+ resolveNpmRoot(host2)
15076
+ ]);
15077
+ if (!nv || !nv.trim()) errors.push("node \u672A\u5B89\u88C5\u6216\u4E0D\u53EF\u6267\u884C");
15078
+ if (!npmv || !npmv.trim()) errors.push("npm \u672A\u5B89\u88C5\u6216\u4E0D\u53EF\u6267\u884C");
15079
+ return { ok: errors.length === 0, errors, npmRoot };
15080
+ }
15081
+ async function latestVersion(host2) {
15082
+ 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");
15083
+ const channel = host2.config.releaseChannel || "npm";
15084
+ return host2.dist.fetchVersionInfo(host2.config.packageName, channel);
15085
+ }
15086
+ async function selectRegistry(host2) {
15087
+ if (!host2.dist) return null;
15088
+ try {
15089
+ return await host2.dist.registryOrigin(true);
15090
+ } catch {
15091
+ return null;
15092
+ }
15093
+ }
15094
+ function runNpm(host2, opts) {
15095
+ const a = opts && opts.action || "install";
15096
+ const verb = a === "uninstall" ? "\u5378\u8F7D" : "\u5B89\u88C5";
15097
+ if (!host2.dist) return Promise.resolve({ ok: false, error: "dist \u5206\u53D1\u670D\u52A1\u4E0D\u53EF\u7528\uFF0C\u65E0\u6CD5" + verb, output: [] });
15098
+ const tpl = a === "install" ? host2.config.installCommandTemplate : null;
15099
+ return host2.dist.runNpmInstall({
15100
+ action: a,
15101
+ pkg: host2.config.packageName || "@deepseek-ai/dsh",
15102
+ version: opts && opts.version,
15103
+ // 前缀单源:装与卸必须落在同一个全局前缀,否则「卸载成功」而包还在原地。
15104
+ prefix: host2.npmRoot || null,
15105
+ registry: opts && opts.registry,
15106
+ // 只在显式注入过 npm 形态时接管启动形态;生产留空,由执行器按运行期契约解析一次。
15107
+ launcher: host2._npmBin ? npmLaunch(host2) : null,
15108
+ commandTemplate: Array.isArray(tpl) && tpl.length ? tpl : null,
15109
+ timeoutMs: a === "uninstall" ? host2.config.uninstallTimeoutMs : host2.config.upgradeTimeoutMs,
15110
+ onLine: (l) => {
15111
+ host2._appendUpgradeLog(l);
15112
+ if (host2.installing) host2._appendInstallLog(l);
15113
+ }
15114
+ });
15115
+ }
15116
+ module2.exports = { npmLaunch, resolveNpmRoot, checkEnvironment, latestVersion, selectRegistry, runNpm };
15117
+ }
15118
+ });
15119
+
14364
15120
  // src/domains/shell/journal.js
14365
15121
  var require_journal = __commonJS({
14366
15122
  "src/domains/shell/journal.js"(exports2, module2) {
@@ -15013,6 +15769,9 @@ var require_core5 = __commonJS({
15013
15769
  var { extension: domainConfigExtension2 } = require_domain_config();
15014
15770
  var logcore = require_logcore();
15015
15771
  var { DshTokenService } = require_token();
15772
+ var { EnvCatalog } = require_env_catalog();
15773
+ var npm = require_npm();
15774
+ var FORM_NPM_ROOT_TIMEOUT_MS = 4e3;
15016
15775
  var { DistributionManager } = require_distribution();
15017
15776
  var shellDomain = require_shell();
15018
15777
  var { TaskRegistry } = require_tasks();
@@ -15023,6 +15782,68 @@ var require_core5 = __commonJS({
15023
15782
  host2.config = normalize(rawConfig, domainConfigExtension2());
15024
15783
  host2.configPath = typeof configPath === "string" ? configPath : null;
15025
15784
  platform.environment.bind({ preference: () => host2.config && host2.config.externalBrowser || null });
15785
+ platform.environment.registerSection("runtime", {
15786
+ label: "\u8FD0\u884C\u65F6\uFF08Node/npm/git/\u955C\u50CF\u6E90/\u5168\u5C40\u524D\u7F00\uFF09",
15787
+ probe: async () => {
15788
+ const cat = await new EnvCatalog(host2.config).probeAsync();
15789
+ const m = host2.nativeManager;
15790
+ const [reg, prefix] = await Promise.all([
15791
+ m && m.dist && typeof m.dist.registryInfo === "function" ? Promise.resolve(m.dist.registryInfo()).catch(() => null) : Promise.resolve(null),
15792
+ // 前缀实测就是安装/卸载用的那同一个解析口,只把超时收到表单预算内(默认 15s 会吃掉面板刷新)。
15793
+ m ? npm.resolveNpmRoot(m, { timeoutMs: FORM_NPM_ROOT_TIMEOUT_MS }).catch(() => null) : Promise.resolve(null)
15794
+ ]);
15795
+ return {
15796
+ node: cat.node,
15797
+ npm: cat.npm,
15798
+ git: cat.git,
15799
+ registry: reg ? {
15800
+ origin: reg.origin || null,
15801
+ mode: reg.mode || null,
15802
+ source: reg.source || null,
15803
+ manualOrigin: reg.manualOrigin || null,
15804
+ candidates: (reg.registries || []).map((r) => ({
15805
+ base: r.base,
15806
+ reachable: r.reachable === void 0 ? null : r.reachable,
15807
+ latencyMs: r.latencyMs === void 0 ? null : r.latencyMs,
15808
+ error: r.error || null
15809
+ }))
15810
+ } : null,
15811
+ // 全局前缀只来自 `npm root -g` 的实测,拿不到就是 null:装/卸落在哪个前缀是排障第一问,
15812
+ // 猜一个只会指错地方(壳侧的同名读数在 E4 上报接通后进这一维)。
15813
+ prefix: prefix || null
15814
+ };
15815
+ }
15816
+ });
15817
+ platform.environment.registerSection("dsh", {
15818
+ label: "DSH \u672C\u4F53\u4E0E\u5185\u6838\u66F4\u65B0",
15819
+ probe: async () => {
15820
+ const cat = new EnvCatalog(host2.config);
15821
+ const d = typeof host2.dshenvStatus === "function" ? host2.dshenvStatus() : null;
15822
+ if (!d) return null;
15823
+ return {
15824
+ dsh: cat.dshEntry(d.binOk, d.installed, d.bin),
15825
+ selfUpdate: cat.selfUpdateEntry(),
15826
+ managed: d.managed === true,
15827
+ phase: d.phase || null
15828
+ };
15829
+ }
15830
+ });
15831
+ platform.environment.registerSection("startup", {
15832
+ label: "\u542F\u52A8\u65E2\u6210\u4E8B\u5B9E\uFF08\u5B88\u536B\u8FD9\u4E00\u62CD\u8DD1\u8FC7\u4EC0\u4E48\uFF09",
15833
+ probe: () => {
15834
+ const s = host2._startupFacts;
15835
+ if (!s) return null;
15836
+ return {
15837
+ bootAt: s.bootAt,
15838
+ envDelayMs: s.envDelayMs,
15839
+ routerAutostart: s.routerAutostart,
15840
+ routerMode: s.routerMode,
15841
+ updateCheck: s.updateCheck,
15842
+ shellWatchdog: s.shellWatchdog,
15843
+ lastRefresh: s.lastRefresh
15844
+ };
15845
+ }
15846
+ });
15026
15847
  host2._fileProtectStatus = null;
15027
15848
  try {
15028
15849
  const fp = platform.fileProtect;
@@ -18777,7 +19598,12 @@ var require_oauth = __commonJS({
18777
19598
  waitMs: 18e4,
18778
19599
  opened: true,
18779
19600
  // 非隔离引擎(Safari/打包器包装)由平台层降级:账号隔离不成立,换账号只能靠超时重发或手动窗口。
18780
- isolated: ev.isolated === true
19601
+ isolated: ev.isolated === true,
19602
+ // 为什么隔离成立/不成立必须一起交出:面板上一句「未隔离」既没说原因也没法处置。
19603
+ // basis 来自环境表单的出网条件维度(cold-profile-blocked 即冷档案注定空白),
19604
+ // 与「引擎不支持隔离」是两种不同原因,分开才谈得上分开修(配代理 vs 换浏览器)。
19605
+ isolatedBasis: ev.egress ? ev.egress.basis : ev.isolated === true ? "isolated" : "engine-not-isolatable",
19606
+ isolatedDetail: ev.egress ? ev.egress.detail || null : null
18781
19607
  });
18782
19608
  }
18783
19609
  async function commandcodeLoginWait(timeoutMs) {
@@ -19286,7 +20112,7 @@ var require_router_ops = __commonJS({
19286
20112
  function createAuxCore(deps) {
19287
20113
  const d = deps || {};
19288
20114
  const getProviders = d.getProviders || (() => []);
19289
- const openInBrowser = (url, onExit) => platform.browser.openBrowser(url, { intent: "isolated-login", onExit });
20115
+ const openInBrowser = (url, onExit) => platform.browser.openBrowser(url, { intent: "isolated-login", onExit, logger: d.logger });
19290
20116
  const oauth = createOAuthOps({ ports, openInBrowser });
19291
20117
  const apps = createAppsRegistryOps({
19292
20118
  getProviders,
@@ -20357,10 +21183,18 @@ var require_sandbox = __commonJS({
20357
21183
  function defaultCommand(dshBin, inst) {
20358
21184
  return [process.execPath, dshBin, "web", "--port", String(inst.port), "--host", "127.0.0.1", "--trusted-host", "127.0.0.1", "--no-open"];
20359
21185
  }
21186
+ function withoutAutoOpen(cmd2) {
21187
+ const arr = (Array.isArray(cmd2) ? cmd2 : []).map(String);
21188
+ const webAt = arr.indexOf("web");
21189
+ if (webAt < 0 || arr.includes("--no-open") || arr.includes("--open")) return cmd2;
21190
+ const sep = arr.indexOf("--", webAt);
21191
+ if (sep < 0) return arr.concat(["--no-open"]);
21192
+ return arr.slice(0, sep).concat(["--no-open"], arr.slice(sep));
21193
+ }
20360
21194
  function effectiveCommand(rootDir, dshBin, inst) {
20361
- if (inst.domain === "sandbox" && (!inst.command || !inst.command.length)) return sandboxCommand(rootDir, inst);
20362
- if (inst.command && inst.command.length) return inst.command;
20363
- return defaultCommand(dshBin, inst);
21195
+ if (inst.domain === "sandbox" && (!inst.command || !inst.command.length)) return withoutAutoOpen(sandboxCommand(rootDir, inst));
21196
+ if (inst.command && inst.command.length) return withoutAutoOpen(inst.command);
21197
+ return withoutAutoOpen(defaultCommand(dshBin, inst));
20364
21198
  }
20365
21199
  function unitProps(inst, alloc) {
20366
21200
  const props = [
@@ -24138,7 +24972,7 @@ var require_heartbeat = __commonJS({
24138
24972
  });
24139
24973
 
24140
24974
  // src/app/control/registry.js
24141
- var require_registry3 = __commonJS({
24975
+ var require_registry4 = __commonJS({
24142
24976
  "src/app/control/registry.js"(exports2, module2) {
24143
24977
  "use strict";
24144
24978
  var fs2 = require("node:fs");
@@ -24709,77 +25543,6 @@ var require_manifest = __commonJS({
24709
25543
  }
24710
25544
  });
24711
25545
 
24712
- // src/app/native/npm.js
24713
- var require_npm = __commonJS({
24714
- "src/app/native/npm.js"(exports2, module2) {
24715
- "use strict";
24716
- var ex2 = require_exec();
24717
- var runtimeContract = require_runtime();
24718
- function npmLaunch(host2) {
24719
- const h = host2 || {};
24720
- if (h._npmBin) {
24721
- return { program: h._npmBin, args: Array.isArray(h._npmBinArgs) ? h._npmBinArgs.slice() : [] };
24722
- }
24723
- const l = runtimeContract.npmLauncher();
24724
- return { program: l.program, args: l.args };
24725
- }
24726
- async function resolveNpmRoot(host2) {
24727
- if (host2.npmRoot) return host2.npmRoot;
24728
- const l = npmLaunch(host2);
24729
- const r = await ex2.runOutAsync(l.program, l.args.concat(["root", "-g"]));
24730
- return r ? r.trim() : null;
24731
- }
24732
- async function checkEnvironment(host2) {
24733
- const errors = [];
24734
- const l = npmLaunch(host2);
24735
- const [nv, npmv, npmRoot] = await Promise.all([
24736
- ex2.runOutAsync("node", ["--version"]),
24737
- ex2.runOutAsync(l.program, l.args.concat(["--version"])),
24738
- resolveNpmRoot(host2)
24739
- ]);
24740
- if (!nv || !nv.trim()) errors.push("node \u672A\u5B89\u88C5\u6216\u4E0D\u53EF\u6267\u884C");
24741
- if (!npmv || !npmv.trim()) errors.push("npm \u672A\u5B89\u88C5\u6216\u4E0D\u53EF\u6267\u884C");
24742
- return { ok: errors.length === 0, errors, npmRoot };
24743
- }
24744
- async function latestVersion(host2) {
24745
- 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");
24746
- const channel = host2.config.releaseChannel || "npm";
24747
- return host2.dist.fetchVersionInfo(host2.config.packageName, channel);
24748
- }
24749
- async function selectRegistry(host2) {
24750
- if (!host2.dist) return null;
24751
- try {
24752
- return await host2.dist.registryOrigin(true);
24753
- } catch {
24754
- return null;
24755
- }
24756
- }
24757
- function runNpm(host2, opts) {
24758
- const a = opts && opts.action || "install";
24759
- const verb = a === "uninstall" ? "\u5378\u8F7D" : "\u5B89\u88C5";
24760
- if (!host2.dist) return Promise.resolve({ ok: false, error: "dist \u5206\u53D1\u670D\u52A1\u4E0D\u53EF\u7528\uFF0C\u65E0\u6CD5" + verb, output: [] });
24761
- const tpl = a === "install" ? host2.config.installCommandTemplate : null;
24762
- return host2.dist.runNpmInstall({
24763
- action: a,
24764
- pkg: host2.config.packageName || "@deepseek-ai/dsh",
24765
- version: opts && opts.version,
24766
- // 前缀单源:装与卸必须落在同一个全局前缀,否则「卸载成功」而包还在原地。
24767
- prefix: host2.npmRoot || null,
24768
- registry: opts && opts.registry,
24769
- // 只在显式注入过 npm 形态时接管启动形态;生产留空,由执行器按运行期契约解析一次。
24770
- launcher: host2._npmBin ? npmLaunch(host2) : null,
24771
- commandTemplate: Array.isArray(tpl) && tpl.length ? tpl : null,
24772
- timeoutMs: a === "uninstall" ? host2.config.uninstallTimeoutMs : host2.config.upgradeTimeoutMs,
24773
- onLine: (l) => {
24774
- host2._appendUpgradeLog(l);
24775
- if (host2.installing) host2._appendInstallLog(l);
24776
- }
24777
- });
24778
- }
24779
- module2.exports = { npmLaunch, resolveNpmRoot, checkEnvironment, latestVersion, selectRegistry, runNpm };
24780
- }
24781
- });
24782
-
24783
25546
  // src/app/native/ops.js
24784
25547
  var require_ops4 = __commonJS({
24785
25548
  "src/app/native/ops.js"(exports2, module2) {
@@ -25424,7 +26187,7 @@ var require_installer = __commonJS({
25424
26187
  var require_entry = __commonJS({
25425
26188
  "src/app/control/entry.js"(exports2, module2) {
25426
26189
  "use strict";
25427
- var { PHASES } = require_registry3();
26190
+ var { PHASES } = require_registry4();
25428
26191
  var ManagedLifecycle = class {
25429
26192
  constructor(opts) {
25430
26193
  this.id = opts.id || "lc-" + Math.random().toString(36).slice(2, 8);
@@ -25678,7 +26441,7 @@ var require_domains = __commonJS({
25678
26441
  var { InstanceManager } = require_instance();
25679
26442
  var { PluginMarket } = require_market();
25680
26443
  var { PluginManager } = require_plugin();
25681
- var { ManagedRegistry } = require_registry3();
26444
+ var { ManagedRegistry } = require_registry4();
25682
26445
  var { guardVersion } = require_version();
25683
26446
  var { Lifecycle } = require_lifecycle2();
25684
26447
  var { Health } = require_health();
@@ -25805,7 +26568,7 @@ var require_adapters = __commonJS({
25805
26568
  "src/app/control/adapters.js"(exports2, module2) {
25806
26569
  "use strict";
25807
26570
  var { ManagedLifecycle } = require_entry();
25808
- var { kindMeta } = require_registry3();
26571
+ var { kindMeta } = require_registry4();
25809
26572
  function capsOf(objectKind) {
25810
26573
  const m = kindMeta(objectKind);
25811
26574
  if (!m) return { startable: true, guardable: true };
@@ -26304,7 +27067,7 @@ var require_guard = __commonJS({
26304
27067
  var fs2 = require("node:fs");
26305
27068
  var path2 = require("node:path");
26306
27069
  function owns(pathname) {
26307
- return pathname === "/changelog" || pathname.startsWith("/guard/") || pathname === "/autostart" || pathname.startsWith("/settings/") || pathname.startsWith("/self-update/") || pathname === "/env/dsh" || pathname === "/env/status" || pathname === "/env/node-lts" || pathname === "/env/open-url" || pathname === "/env/environment" || pathname === "/ports" || pathname === "/shutdown";
27070
+ return pathname === "/changelog" || pathname.startsWith("/guard/") || pathname === "/autostart" || pathname.startsWith("/settings/") || pathname.startsWith("/self-update/") || pathname === "/env/dsh" || pathname === "/env/status" || pathname === "/env/node-lts" || pathname === "/env/open-url" || pathname === "/env/environment" || pathname === "/env/environment/last" || pathname === "/ports" || pathname === "/shutdown";
26308
27071
  }
26309
27072
  function fetchDshChangelog(res, sup) {
26310
27073
  const v = sup && sup.nativeManager ? sup.nativeManager.versionInfo() : {};
@@ -26511,7 +27274,14 @@ var require_guard = __commonJS({
26511
27274
  return send(403, { ok: false, error: "cross-origin request rejected" });
26512
27275
  }
26513
27276
  const force = /[?&]force=1/.test(String(req.url || ""));
26514
- return Promise.resolve(environment.form({ force, persist: force })).then((r) => send(200, r)).catch((e) => send(500, { ok: false, error: "\u73AF\u5883\u8868\u5355\u88C5\u914D\u5931\u8D25\uFF1A" + (e && e.message || e) }));
27277
+ return Promise.resolve(force ? environment.refresh({ persist: true, force: true }) : environment.form()).then((r) => send(200, r)).catch((e) => send(500, { ok: false, error: "\u73AF\u5883\u8868\u5355\u88C5\u914D\u5931\u8D25\uFF1A" + (e && e.message || e) }));
27278
+ }
27279
+ if (req.method === "GET" && pathname === "/env/environment/last") {
27280
+ if (!originAllowed(req, sup.config.apiPort)) {
27281
+ req.resume();
27282
+ return send(403, { ok: false, error: "cross-origin request rejected" });
27283
+ }
27284
+ return send(200, environment.lastSnapshot());
26515
27285
  }
26516
27286
  if (req.method === "POST" && pathname === "/env/open-url") {
26517
27287
  if (!identity.loopback) {
@@ -26530,7 +27300,7 @@ var require_guard = __commonJS({
26530
27300
  } catch {
26531
27301
  }
26532
27302
  if (!url) return send(400, { ok: false, error: '\u9700\u8981 {"url":"http(s)://\u2026"}' });
26533
- return Promise.resolve(browser.openBrowser(url)).then((r) => send(r.ok ? 200 : 500, r)).catch((e) => send(500, { ok: false, reason: "spawn-failed", error: "\u6253\u5F00\u6D4F\u89C8\u5668\u5931\u8D25\uFF1A" + (e && e.message || e), url }));
27303
+ return Promise.resolve(browser.openBrowser(url, { logger: sup.logger })).then((r) => send(r.ok ? 200 : 500, r)).catch((e) => send(500, { ok: false, reason: "spawn-failed", error: "\u6253\u5F00\u6D4F\u89C8\u5668\u5931\u8D25\uFF1A" + (e && e.message || e), url }));
26534
27304
  });
26535
27305
  return;
26536
27306
  }
@@ -27131,7 +27901,7 @@ var require_instances = __commonJS({
27131
27901
  function handle(ctx) {
27132
27902
  const { sup, req, res, pathname, identity, send, collectBody, originAllowed, tokOf, browser } = ctx;
27133
27903
  function openInSystemBrowser(url) {
27134
- return browser.openBrowser(url);
27904
+ return browser.openBrowser(url, { logger: sup.logger });
27135
27905
  }
27136
27906
  if (req.method === "GET" && pathname === "/open") return handleOpen(ctx);
27137
27907
  if (req.method === "GET" && pathname === "/instances") {