@nowcrew/daemon 0.6.88-beta.21 → 0.6.88-beta.23

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.
@@ -0,0 +1,10 @@
1
+ /**
2
+ * launchd Background policy can stall dsh's synchronous startup reads before ACP.
3
+ * Apply application resource policy to this short-lived child, never the daemon.
4
+ * taskpolicy execs the target; no shell, alternate PATH, or protocol bypass.
5
+ */
6
+ export function deepSeekHarnessLaunch(bin, args, platform = process.platform) {
7
+ return platform === "darwin"
8
+ ? { bin: "/usr/sbin/taskpolicy", args: ["-a", "--", bin, ...args] }
9
+ : { bin, args: [...args] };
10
+ }
@@ -7,6 +7,7 @@ import { isAbsolute } from "node:path";
7
7
  import spawn from "cross-spawn";
8
8
  import { z } from "zod";
9
9
  import { client, methods, ndJsonStream, PROTOCOL_VERSION, } from "@agentclientprotocol/sdk";
10
+ import { deepSeekHarnessLaunch } from "./deepseek-harness-launch.js";
10
11
  import { prepareHarnessProfile } from "./deepseek-harness-profile.js";
11
12
  import { mapAcpUpdate } from "./kimi-acp-runner.js";
12
13
  import { prepareThreadDelivery } from "../thread-input-delivery.js";
@@ -56,7 +57,8 @@ export async function runHarness(input, bin, patchPath) {
56
57
  env: process.env,
57
58
  ...(patchPath ? { patchPath } : {}),
58
59
  });
59
- const child = spawn(bin, profile.args, {
60
+ const launch = deepSeekHarnessLaunch(bin, profile.args);
61
+ const child = spawn(launch.bin, launch.args, {
60
62
  cwd: profile.home,
61
63
  env: profile.env,
62
64
  stdio: ["pipe", "pipe", "pipe"],
@@ -180,7 +182,7 @@ export async function runHarness(input, bin, patchPath) {
180
182
  if (!cancelled)
181
183
  process.stderr.write(spawnError
182
184
  ? "DeepSeek Harness launch failed; verify the installed dsh executable.\n"
183
- : `DeepSeek Harness ACP execution failed at ${stage}; verify the pinned version, machine credentials and profile patch.\n`);
185
+ : `DeepSeek Harness ACP execution failed at ${stage}; verify DEEPSEEK_API_KEY, model access, the pinned version and profile patch.\n`);
184
186
  }
185
187
  finally {
186
188
  try {
@@ -3,6 +3,7 @@ import { isAbsolute } from "node:path";
3
3
  import { mkdtemp, rm } from "node:fs/promises";
4
4
  import { tmpdir } from "node:os";
5
5
  import { join } from "node:path";
6
+ import { deepSeekHarnessLaunch } from "./deepseek-harness-launch.js";
6
7
  import { prepareHarnessProfile } from "./deepseek-harness-profile.js";
7
8
  import { probeKimiAcp, AcpProbeCleanupError } from "./kimi-acp-runner.js";
8
9
  export const DEEPSEEK_HARNESS_CONFIG_ENV = "NOWCREW_DEEPSEEK_HARNESS_CONFIG";
@@ -52,11 +53,13 @@ export async function probeDeepSeekHarnessAcp(options, spawnProcess = spawn) {
52
53
  env: process.env,
53
54
  ...(launcher.patchPath ? { patchPath: launcher.patchPath } : {}),
54
55
  });
56
+ const launch = deepSeekHarnessLaunch(options.bin, profile.args);
55
57
  return await probeKimiAcp({
56
58
  ...options,
59
+ bin: launch.bin,
57
60
  provider: "deepseek-harness",
58
61
  effectivePermission: "sandboxed",
59
- launchArgs: profile.args,
62
+ launchArgs: launch.args,
60
63
  launchEnv: profile.env,
61
64
  launchCwd: root,
62
65
  }, spawnProcess);
@@ -13,7 +13,12 @@ import { prepareThreadDelivery } from "../thread-input-delivery.js";
13
13
  import { startFirstProgressWatchdog } from "./progress-watchdog.js";
14
14
  import { assertKimiLegacyPromptFits, buildKimiArgs } from "./kimi.js";
15
15
  const ERROR_MESSAGE_CAP = 2_000;
16
- const PROBE_TIMEOUT_MS = 5_000;
16
+ // macOS launchd cold-starts ACP runtimes materially slower than an interactive
17
+ // shell. DeepSeek Harness was measured at ~4.4s before returning initialize
18
+ // under launchd, while the daemon also creates an isolated profile. Keep this
19
+ // bounded below the control-plane request budget, with the existing 1s/2s
20
+ // Harness retries providing the outer bound.
21
+ export const ACP_PROBE_TIMEOUT_MS = 10_000;
17
22
  function jsonLine(event) {
18
23
  if (process.stdout.write(`${JSON.stringify(event)}\n`))
19
24
  return Promise.resolve();
@@ -222,6 +227,15 @@ export async function probeKimiAcp(options, spawnProcess = spawn) {
222
227
  env: { ...launchEnv, PATH: augmentedPath(launchEnv) },
223
228
  stdio: ["pipe", "pipe", "pipe"],
224
229
  });
230
+ // spawn errors are emitted by ChildProcess, not its stdio streams. A missing
231
+ // launcher must fail admission, not become an uncaught daemon exception.
232
+ const spawnFailed = new Promise((resolve) => {
233
+ child.once("error", () => {
234
+ if (reason === "initializing")
235
+ reason = "spawn_error";
236
+ resolve(false);
237
+ });
238
+ });
225
239
  child.once("spawn", () => {
226
240
  spawnConfirmedMs = elapsed();
227
241
  dslog("execution.acp_probe_spawned", "ACP 探测子进程已启动", fields());
@@ -256,13 +270,14 @@ export async function probeKimiAcp(options, spawnProcess = spawn) {
256
270
  });
257
271
  const result = await Promise.race([
258
272
  connected,
273
+ spawnFailed,
259
274
  new Promise((resolve) => {
260
275
  timeout = setTimeout(() => {
261
276
  if (reason === "initializing")
262
277
  reason = "timeout";
263
278
  void stopChild(child);
264
279
  resolve(false);
265
- }, PROBE_TIMEOUT_MS);
280
+ }, ACP_PROBE_TIMEOUT_MS);
266
281
  }),
267
282
  new Promise((resolve) => {
268
283
  onAbort = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nowcrew/daemon",
3
- "version": "0.6.88-beta.21",
3
+ "version": "0.6.88-beta.23",
4
4
  "type": "module",
5
5
  "description": "crew daemon — 运行在用户机器:拉起/管理 agent 进程,注入 crew CLI,归一化 runtime 事件",
6
6
  "license": "Apache-2.0",