dsh-cloud-experts 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -30,7 +30,7 @@
30
30
 
31
31
  ## 版本
32
32
 
33
- - 0.1.1:对齐官方 bundle 的 inject 声明(`subagents` + `subprocess`)。
33
+ - 0.1.3:本地看门狗 360s→1200s,支持 `DSH_CLOUD_EXPERTS_WATCHDOG_MS` 环境变量覆盖(配套 VPS `/etc/dsh-fed/expert.conf` 单次上限 300s→900s,2026-11-07);0.1.2:ssh 内置 ServerAliveInterval=15(NAT 防断)+ 本地 360s 看门狗;0.1.1:对齐官方 inject。
34
34
 
35
35
  ## License
36
36
 
package/lib/index.js CHANGED
@@ -16,6 +16,10 @@ const Config = z.object({
16
16
 
17
17
  const MINIMAL_ENV_KEYS = ["PATH", "SystemRoot", "USERPROFILE", "HOME"];
18
18
 
19
+ // 本地看门狗:默认 1200s(覆盖服务端 expert.conf 派生 CALL_TIMEOUT=950s + flock 排队余量)。
20
+ // 服务端上限再调整时可用 DSH_CLOUD_EXPERTS_WATCHDOG_MS 环境变量覆盖,无需发版。
21
+ const WATCHDOG_MS = Number.parseInt(process.env.DSH_CLOUD_EXPERTS_WATCHDOG_MS || "", 10) || 1200000;
22
+
19
23
  function minimalEnv() {
20
24
  const env = {};
21
25
  for (const key of MINIMAL_ENV_KEYS) if (process.env[key] !== undefined) env[key] = process.env[key];
@@ -69,7 +73,8 @@ class CloudExpertProvider {
69
73
  const stamp = new Date().toISOString().replace(/[^0-9]/g, "").slice(0, 14);
70
74
  const consultId = `PLUGIN-${stamp}-${this.expert}-${randomUUID().slice(0, 8)}`;
71
75
  const remoteCmd = [this.config.remoteEntry, this.expert, "--id", consultId, "--origin", this.config.origin].join(" ");
72
- const argv = ["ssh", "-o", "BatchMode=yes", "-o", "IdentitiesOnly=yes", "-o", "ConnectTimeout=15"];
76
+ const argv = ["ssh", "-o", "BatchMode=yes", "-o", "IdentitiesOnly=yes", "-o", "ConnectTimeout=15",
77
+ "-o", "ServerAliveInterval=15", "-o", "ServerAliveCountMax=4", "-o", "LogLevel=ERROR"];
73
78
  if (this.config.keyPath) argv.push("-i", this.config.keyPath);
74
79
  argv.push(this.config.host, remoteCmd);
75
80
 
@@ -91,6 +96,11 @@ class CloudExpertProvider {
91
96
  const stdinWrite = writeAll(child.stdin, Buffer.from(text, "utf8")).catch(() => {});
92
97
 
93
98
  const controller = new AbortController();
99
+ const watchdog = setTimeout(() => {
100
+ try { child.stdin?.end(); } catch {}
101
+ try { child.terminate(); } catch {}
102
+ controller.abort(new Error(`cloud-experts: ${this.expert} local watchdog fired (${Math.round(WATCHDOG_MS / 1000)}s)`));
103
+ }, WATCHDOG_MS);
94
104
  const requestCancel = () => {
95
105
  if (!controller.signal.aborted) controller.abort(new Error(`cloud-experts: ${this.expert} run cancelled locally`));
96
106
  try { child.stdin?.end(); } catch {}
@@ -100,7 +110,8 @@ class CloudExpertProvider {
100
110
  request.signal.addEventListener("abort", onAbort, { once: true });
101
111
 
102
112
  const attempt = async () => {
103
- await stdinWrite;
113
+ try {
114
+ await stdinWrite;
104
115
  const info = await child.done;
105
116
  const code = info && typeof info.code === "number" ? info.code : 0;
106
117
  const envelope = /FED_ENVELOPE:(\{[^\n]*\})/.exec(err);
@@ -113,6 +124,9 @@ class CloudExpertProvider {
113
124
  }
114
125
  const failure = /FED_ERROR:([\w:.-]+)/.exec(err);
115
126
  throw new Error(`cloud-experts: ${failure?.[1] ?? `exit-${code}`} ${err.slice(0, 200)}`);
127
+ } finally {
128
+ clearTimeout(watchdog);
129
+ }
116
130
  };
117
131
 
118
132
  const result = settleRunResult({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-cloud-experts",
3
3
  "description": "Cloud expert subagents (claude/codex on the fed VPS) over SSH fed-expert wrapper",
4
- "version": "0.1.1",
4
+ "version": "0.1.3",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {