@nowcrew/daemon 0.6.89 → 0.6.91-beta.1

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 (116) hide show
  1. package/README.md +64 -3
  2. package/dist/agent-ability/materializer.js +21 -10
  3. package/dist/agent-environment-contract.js +55 -0
  4. package/dist/agent-environment-control.js +24 -0
  5. package/dist/agent-environment-execution.js +98 -0
  6. package/dist/agent-environments.js +275 -0
  7. package/dist/automatic-daemon-installer.js +49 -1
  8. package/dist/computer-main.js +18 -0
  9. package/dist/computer-profile.js +17 -4
  10. package/dist/computer-setup-client.js +318 -0
  11. package/dist/computer-setup-orchestration.js +203 -0
  12. package/dist/computer-setup.js +244 -0
  13. package/dist/config.js +30 -12
  14. package/dist/console-formatter.js +3 -3
  15. package/dist/console.js +15 -2
  16. package/dist/daemon-update-eligibility.js +1 -1
  17. package/dist/daemon-updater.js +2 -12
  18. package/dist/execution-journal.js +9 -6
  19. package/dist/execution-protocol.js +1 -0
  20. package/dist/execution-runner.js +13 -8
  21. package/dist/i18n.js +19 -0
  22. package/dist/list-models.js +12 -12
  23. package/dist/local-execution-lease.js +22 -0
  24. package/dist/local-executor.js +57 -84
  25. package/dist/local-memory/candidate.js +43 -0
  26. package/dist/local-memory/index-budget.js +8 -0
  27. package/dist/local-memory/inventory-cli.js +61 -0
  28. package/dist/local-memory/inventory-preview.js +159 -0
  29. package/dist/local-memory/inventory-source.js +159 -0
  30. package/dist/local-memory/pending-match.js +29 -0
  31. package/dist/local-memory/pending-query.js +100 -0
  32. package/dist/local-memory/pending-schema.js +29 -0
  33. package/dist/local-memory/pending-source.js +126 -0
  34. package/dist/local-memory/pending.js +34 -84
  35. package/dist/local-memory/prompt.js +19 -12
  36. package/dist/local-memory/read-cli.js +97 -12
  37. package/dist/local-memory/rollout.js +82 -0
  38. package/dist/local-memory/runtime.js +23 -17
  39. package/dist/local-memory/work-log-execution.js +31 -0
  40. package/dist/local-memory/work-log.js +58 -0
  41. package/dist/local-memory/write.js +27 -58
  42. package/dist/local-runtime-environment.js +50 -0
  43. package/dist/machine-environment-cache.js +147 -0
  44. package/dist/machine-environment-contract.js +10 -0
  45. package/dist/machine-environment-control.js +27 -0
  46. package/dist/machine-environment-policy.js +75 -0
  47. package/dist/machine-environment-process.js +110 -0
  48. package/dist/machine-info.js +70 -25
  49. package/dist/machine-runtime-environment.js +189 -0
  50. package/dist/machine-shell-environment-capture.js +135 -0
  51. package/dist/machine-windows-environment-capture.js +215 -0
  52. package/dist/machine-windows-environment-script.js +158 -0
  53. package/dist/main.js +4 -69
  54. package/dist/marketplace-command.js +21 -0
  55. package/dist/marketplace-controller.js +80 -0
  56. package/dist/marketplace-protocol.js +38 -0
  57. package/dist/marketplace-remote.js +48 -0
  58. package/dist/marketplace-runner.js +235 -0
  59. package/dist/marketplace-serve.js +41 -0
  60. package/dist/marketplace-source.js +103 -0
  61. package/dist/message-file-preview.js +246 -0
  62. package/dist/pre-admission-rejection.js +64 -0
  63. package/dist/project-skills/execution-adapter.js +3 -2
  64. package/dist/project-skills/runtime-launch.js +14 -0
  65. package/dist/provider-env.js +26 -15
  66. package/dist/runner.js +17 -4
  67. package/dist/runtime-environment-merge.js +16 -0
  68. package/dist/runtime-health-handler.js +10 -0
  69. package/dist/runtime-health.js +3 -1
  70. package/dist/runtime-path.js +22 -12
  71. package/dist/runtime-probe.js +35 -6
  72. package/dist/runtimes/acp-probe-transport.js +69 -0
  73. package/dist/runtimes/claude-models.js +20 -9
  74. package/dist/runtimes/deepseek-harness-launch.js +10 -0
  75. package/dist/runtimes/deepseek-harness-profile.js +92 -0
  76. package/dist/runtimes/deepseek-harness-runner.js +226 -0
  77. package/dist/runtimes/deepseek-harness.js +76 -15
  78. package/dist/runtimes/harness-probe-retry.js +42 -0
  79. package/dist/runtimes/hermes-models.js +2 -1
  80. package/dist/runtimes/kimi-acp-runner.js +78 -13
  81. package/dist/runtimes/opencode.js +2 -2
  82. package/dist/serve.js +88 -178
  83. package/dist/storage-identity.js +0 -3
  84. package/dist/storage-serve-adapter.js +6 -72
  85. package/dist/supervised-runtime.js +17 -2
  86. package/dist/token.js +0 -1
  87. package/dist/workspace-control-handler.js +27 -0
  88. package/dist/workspace-fs.js +66 -15
  89. package/dist/workspace.js +1 -1
  90. package/package.json +13 -12
  91. package/dist/codex-home-launch.js +0 -7
  92. package/dist/codex-home-mode-controller.js +0 -68
  93. package/dist/daemon-migration-controller.js +0 -211
  94. package/dist/daemon-migration-wiring.js +0 -22
  95. package/dist/runtimes/codex-home-migration-cli.js +0 -26
  96. package/dist/runtimes/codex-home-migration.js +0 -112
  97. package/dist/runtimes/codex-home.js +0 -236
  98. package/dist/storage-control.js +0 -212
  99. package/dist/storage-copy.js +0 -628
  100. package/dist/storage-credential-guard.js +0 -21
  101. package/dist/storage-doctor.js +0 -228
  102. package/dist/storage-manifest.js +0 -1027
  103. package/dist/storage-migration-controller.js +0 -440
  104. package/dist/storage-migration-manifest.js +0 -105
  105. package/dist/storage-migration-policy.js +0 -100
  106. package/dist/storage-runtime-controller.js +0 -381
  107. package/dist/storage-runtime-readiness.js +0 -241
  108. package/dist/storage-safe-fs.js +0 -302
  109. package/dist/storage-status-delivery.js +0 -224
  110. package/dist/storage-status-replay.js +0 -140
  111. package/dist/storage-target-confirmation.js +0 -129
  112. package/dist/storage-worker-command.js +0 -37
  113. package/dist/storage-worker-executor.js +0 -447
  114. package/dist/storage-worker-handoff.js +0 -151
  115. package/dist/storage-worker-operation.js +0 -294
  116. package/dist/storage-worker-status.js +0 -259
package/dist/serve.js CHANGED
@@ -1,21 +1,19 @@
1
- /**
2
- * 常驻模式 (M3c):连接 server 控制面 WS,注册机器,监听 agent:start 自动唤醒 agent。
3
- * 断线指数退避重连。一个 agent:start 进来就跑一次现有的 runAgent。
4
- */
1
+ /** 常驻控制面桥接;按请求拉起本地 runtime。 */
2
+ import { handleAgentEnvironmentFrame } from "./agent-environment-control.js";
3
+ import { handleMachineEnvironmentFrame } from "./machine-environment-control.js";
4
+ import { createMachineRuntimeEnvironment } from "./machine-runtime-environment.js";
5
5
  import { WebSocket } from "ws";
6
+ import { persistPreAdmissionRejection, rejectQueuedAdmission } from "./pre-admission-rejection.js";
6
7
  import { join } from "node:path";
7
8
  import { randomUUID } from "node:crypto";
8
9
  import { dslog, setSlogDefaults, drainSpool, flushSlog } from "./slog.js";
9
10
  import { mergeRunAgentResults, reportScheduledStartFailure, runAgent } from "./runner.js";
10
11
  import { buildOriginDecisionRetryPrompt, buildScheduledPrompt } from "./prompt.js";
11
- import { collectMachineHello, daemonCapabilities, daemonCapabilityBindings, detectExecutionRuntimesWithSignal, } from "./machine-info.js";
12
+ import { daemonCapabilities, daemonCapabilityBindings, } from "./machine-info.js";
12
13
  import { reconcileExecutionJournal } from "./execution-recovery.js";
13
14
  import { initReleaseSlog, reportDaemonConnectionClose, reportReleaseError } from "./release-channel-guard.js";
14
- import { conservativeExecutionRuntimes, createRuntimeProbeCoordinator, } from "./runtime-probe.js";
15
- import { listWorkspace, readWorkspaceFile } from "./workspace-fs.js";
16
- import { listSkills } from "./skills.js";
15
+ import { handleWorkspaceControlRequest } from "./workspace-control-handler.js";
17
16
  import { inspectRaftWorkspace, importRaftWorkspace } from "./workspace-import.js";
18
- import { listRuntimeModels } from "./list-models.js";
19
17
  import { normalizeScheduledContext } from "./scheduled-report.js";
20
18
  import { formatDaemonLogLine } from "./log-format.js";
21
19
  import { reportAgentRunComplete } from "./scheduled-run-report.js";
@@ -49,12 +47,10 @@ import { createProjectSkillsReconciler, } from "./project-skills/reconciler.js";
49
47
  import { initializedProjectSkillsReconciler } from "./project-skills/initialized-reconciler.js";
50
48
  import { parseMemoryPruneTraceId } from "./memory-prune-diagnostics.js";
51
49
  import { probeRuntimeHealth } from "./runtime-health.js";
52
- import { handleRuntimeHealthProbeFrame } from "./runtime-health-handler.js";
50
+ import { createServeMarketplace } from "./marketplace-serve.js";
53
51
  import { buildControlPlaneUrl } from "./control-plane-url.js";
54
- import { createServeMigrationController, handleMigrationControlMessage } from "./daemon-migration-wiring.js";
55
- import { createCodexHomeModeController } from "./codex-home-mode-controller.js";
56
52
  import { resolveDaemonLocalStateRootFromEnv } from "./daemon-local-home.js";
57
- import { attachStorageMigrationRuntime, bindStorageMigrationServerIdentity, createServeStorageStatusDelivery, handleStorageMigrationControl, replayStorageMigrationStatus, storageMigrationCapabilities, } from "./storage-serve-adapter.js";
53
+ import { bindStorageServerIdentity, createStorageIdentityAdmission, } from "./storage-serve-adapter.js";
58
54
  export { buildControlPlaneUrl } from "./control-plane-url.js";
59
55
  // normalize.ts 的活动种类 → activity 枚举
60
56
  const ACTIVITY_MAP = {
@@ -80,9 +76,6 @@ export function serve(config, opts = {}) {
80
76
  ?? (config.agentMemory === null ? undefined : createAgentMemoryBridge(config.agentMemory));
81
77
  const executionTelemetry = createExecutionTelemetryJournal(config.agentsRoot);
82
78
  const executeProtocol = opts.execution?.runExecution ?? runExecution;
83
- let detectedExecutionRuntimes = [], executionRuntimesKnown = false;
84
- let runtimeFacts = null;
85
- const runtimeProbe = createRuntimeProbeCoordinator();
86
79
  const localHome = opts.localHome ?? resolveDaemonLocalStateRootFromEnv();
87
80
  const hostCoordinator = opts.execution?.hostCoordinator
88
81
  ?? createHostExecutionCoordinator({
@@ -112,11 +105,9 @@ export function serve(config, opts = {}) {
112
105
  install: opts.update?.install ?? ((input) => installExactDaemonUpdate({
113
106
  ...input,
114
107
  localSlots,
115
- hostCoordinator,
116
108
  })),
117
109
  prepareRestart: opts.update?.prepareRestart ?? (() => prepareDaemonRestart({
118
110
  localSlots,
119
- hostCoordinator,
120
111
  })),
121
112
  scheduleRestart: opts.update?.scheduleRestart ?? scheduleServiceRestart,
122
113
  sendStatus: (frame) => {
@@ -127,28 +118,14 @@ export function serve(config, opts = {}) {
127
118
  catch { /* reconnect/timeout reconciliation handles a lost status frame */ }
128
119
  },
129
120
  });
130
- let storageMigrationAdmissionClosed = () => false;
131
- const migrationController = createServeMigrationController({
132
- config,
133
- ...(opts.profileName === undefined ? {} : { profileName: opts.profileName }),
134
- isBusy: () => executionRuns.size > 0 || legacyRuns.size > 0,
135
- sendStatus: (frame) => { try {
136
- if (ws?.readyState === WebSocket.OPEN)
137
- ws.send(JSON.stringify(frame));
138
- }
139
- catch { /* reconnect */ } },
140
- });
141
- const codexHomeModeController = createCodexHomeModeController({ ...(opts.profileName === undefined ? {} : { profileName: opts.profileName }), scheduleRestart: opts.update?.scheduleRestart ?? scheduleServiceRestart, getServiceSpec: async () => { const eligibility = await updateEligibility(); return eligibility.eligible ? eligibility.serviceSpec : null; }, isBusy: () => executionRuns.size > 0 || legacyRuns.size > 0, sendStatus: (frame) => { try {
142
- if (ws?.readyState === WebSocket.OPEN)
143
- ws.send(JSON.stringify(frame));
144
- }
145
- catch { /* reconnect */ } } });
121
+ const marketplace = createServeMarketplace(config, localSlots, hostCoordinator);
122
+ const storageIdentityAdmission = createStorageIdentityAdmission(opts.storageRuntime);
146
123
  const projectionCoordinator = createAgentProjectionCoordinator();
147
124
  const { projectRegistry, projectWorkspaceRegistry, projectDependencyProvisioner } = createProjectRegistryWiring(config.agentsRoot, opts.execution?.dependencies);
148
125
  const agentAbilityRuntime = createAgentAbilityRuntime(config.agentsRoot, {
149
126
  ...opts.agentAbility,
150
127
  coordinator: projectionCoordinator,
151
- isAdmissionClosed: () => storageMigrationAdmissionClosed(),
128
+ isAdmissionClosed: storageIdentityAdmission.isAdmissionClosed,
152
129
  });
153
130
  let projectSkillsController;
154
131
  const projectSkillsReconciler = opts.projectSkills?.reconciler ?? createProjectSkillsReconciler({
@@ -169,7 +146,7 @@ export function serve(config, opts = {}) {
169
146
  }
170
147
  catch { /* 下一次 ready 或项目操作会重新发送完整快照 */ }
171
148
  },
172
- isAdmissionClosed: () => storageMigrationAdmissionClosed(),
149
+ isAdmissionClosed: storageIdentityAdmission.isAdmissionClosed,
173
150
  reconcile: (handle, bindings) => projectSkillsReconciler.reconcile(handle, bindings),
174
151
  });
175
152
  const logRegistryFailure = (error) => dslog("project_skills.registry_failed", "本机项目注册表读取失败,本次不上报项目清单(能力不受影响)", {
@@ -177,7 +154,7 @@ export function serve(config, opts = {}) {
177
154
  });
178
155
  const machineHelloPublisher = createMachineHelloPublisher({
179
156
  effective: (hello) => {
180
- const configuredIdentity = opts.storageMigration?.identity;
157
+ const configuredIdentity = opts.storageRuntime?.identity;
181
158
  const currentIdentity = typeof configuredIdentity === "function"
182
159
  ? configuredIdentity()
183
160
  : configuredIdentity;
@@ -185,25 +162,19 @@ export function serve(config, opts = {}) {
185
162
  },
186
163
  onSent: (hello) => log(`📤 已上报机器信息: ${hello.hostname} · ${hello.os} · installed=[${hello.runtimes.join(",")}] · executable=[${hello.executionRuntimes.join(",")}] · agents=[${hello.agentHandles.join(",")}]`),
187
164
  });
165
+ const machineRuntime = createMachineRuntimeEnvironment({
166
+ config,
167
+ ...(opts.machineEnvironment === undefined ? {} : { provider: opts.machineEnvironment }),
168
+ ...(opts.machineInfo === undefined ? {} : { machineInfo: opts.machineInfo }),
169
+ ...(opts.profileName === undefined ? {} : { profileName: opts.profileName }),
170
+ additionalCapabilities: async () => managedDaemonCapabilities(updateEligibility),
171
+ publish: machineHelloPublisher.publish,
172
+ onError: (code, context) => dslog("execution.runtime_detection_failed", "机器环境或 runtime 探测失败", { level: "ERROR", error_code: code, ...context }),
173
+ });
174
+ machineRuntime.prewarm();
188
175
  const initializedProjectSkills = initializedProjectSkillsReconciler(() => projectSkillsController.ensureScanned(), projectSkillsReconciler);
189
176
  const configuredCapabilities = opts.machineInfo?.capabilities ?? daemonCapabilities(process.platform);
190
- const storageCapabilities = storageMigrationCapabilities(configuredCapabilities, opts.storageMigration);
191
- const storageStatusDelivery = createServeStorageStatusDelivery(opts.storageMigration, {
192
- onPersistenceError: (error) => dslog("daemon.storage_status_outbox_failed", "存储迁移状态 outbox 持久化失败", { level: "ERROR", error_message: error.message }),
193
- transmit: (frame) => { try {
194
- if (ws?.readyState === WebSocket.OPEN)
195
- ws.send(JSON.stringify(frame));
196
- }
197
- catch { /* retry */ } },
198
- });
199
- const storageMigrationRuntime = attachStorageMigrationRuntime(opts.storageMigration, {
200
- isBusy: () => executionRuns.size > 0 || legacyRuns.size > 0,
201
- waitForExecutionFrames: () => executionFrameQueue,
202
- flushLocalState: flushSlog,
203
- sendStatus: storageStatusDelivery.send,
204
- });
205
- storageMigrationAdmissionClosed = storageMigrationRuntime.isAdmissionClosed;
206
- const prepareCapabilities = async () => daemonCapabilityBindings(process.platform, [...storageCapabilities, ...await managedDaemonCapabilities(updateEligibility)]);
177
+ const prepareCapabilities = async () => daemonCapabilityBindings(process.platform, [...configuredCapabilities, ...await managedDaemonCapabilities(updateEligibility)]);
207
178
  const safeExecutionSend = (frame) => {
208
179
  try {
209
180
  if (ws?.readyState !== WebSocket.OPEN)
@@ -237,6 +208,11 @@ export function serve(config, opts = {}) {
237
208
  return;
238
209
  }
239
210
  safeExecutionSend(frame);
211
+ if (frame.type === "execution:rejected" && frame.preAdmissionProof) {
212
+ const entry = await executionJournal.get(frame.executionId);
213
+ if (entry?.completion)
214
+ completionRetransmitter.track(entry.completion);
215
+ }
240
216
  };
241
217
  const replayExecutionTelemetry = async () => {
242
218
  const frames = await executionTelemetry.replay();
@@ -312,67 +288,29 @@ export function serve(config, opts = {}) {
312
288
  if (stopped)
313
289
  return;
314
290
  const wsUrl = (opts.buildControlPlaneUrl ?? buildControlPlaneUrl)(config.serverUrl, config.machineToken, process.platform, undefined, capabilities.controlPlaneUrl);
315
- ws = createWebSocket(wsUrl);
291
+ const connectionSocket = createWebSocket(wsUrl);
292
+ ws = connectionSocket;
293
+ const sendToConnection = (frame) => {
294
+ try {
295
+ if (!stopped && ws === connectionSocket && connectionSocket.readyState === WebSocket.OPEN)
296
+ connectionSocket.send(JSON.stringify(frame));
297
+ }
298
+ catch { /* 旧连接请求由服务端超时处理。 */ }
299
+ };
316
300
  let connectionEpochToken;
317
- ws.on("open", () => {
301
+ connectionSocket.on("open", () => {
318
302
  connectionEpochToken = projectSkillsController.beginConnectionEpoch();
319
- storageMigrationRuntime.beginIdentityBinding();
320
- const openedSocket = ws;
303
+ storageIdentityAdmission.beginIdentityBinding();
304
+ const openedSocket = connectionSocket;
305
+ const connectionId = randomUUID();
321
306
  backoff = 1000;
322
307
  connectedAt = Date.now();
323
308
  log(`🔌 已连接控制面 ${config.serverUrl}`);
324
- dslog("daemon.ws_open", "已连接控制面", { server_url: config.serverUrl });
309
+ dslog("daemon.ws_open", "已连接控制面", { server_url: config.serverUrl, connection_id: connectionId });
325
310
  // 连上了才有机会把离线期间(断连原因/退出前)落盘的日志补传上去
326
311
  void drainSpool();
327
312
  // 上报本机信息 (hostname/os/daemon 版本/已装 runtimes)
328
- storageStatusDelivery.replayPending();
329
- const storageReplay = replayStorageMigrationStatus(opts.storageMigration, openedSocket, () => ws === openedSocket, (error) => {
330
- dslog("daemon.storage_status_replay_failed", "存储迁移状态重放失败", {
331
- level: "ERROR", error_message: error.message,
332
- });
333
- }, storageStatusDelivery.send);
334
- const { detectInstalled, detectExecutable = detectExecutionRuntimesWithSignal } = opts.machineInfo ?? {};
335
- const helloPromise = (opts.machineInfo?.collect ?? collectMachineHello)(config.agentsRoot, config.executionLimits, process.platform, {
336
- ...(detectInstalled ? { detectInstalled } : {}),
337
- ...(opts.profileName === undefined ? {} : { profileName: opts.profileName }),
338
- // First hello must not wait for third-party handshakes; optional transports arrive in the refresh.
339
- detectExecutable: async (installed) => conservativeExecutionRuntimes(installed),
340
- additionalCapabilities: async () => [...(await managedDaemonCapabilities(updateEligibility)), ...(opts.profileName === undefined ? [] : ["codex_home_mode_v1"])],
341
- capabilities: capabilities.machineHello,
342
- codexHomeMode: config.codexHomeMode,
343
- });
344
- runtimeFacts = helloPromise
345
- .then(async (hello) => {
346
- if (hello.executionProtocol === undefined) {
347
- executionRuntimesKnown = true;
348
- return [];
349
- }
350
- const detected = await runtimeProbe.detect(hello.runtimes, detectExecutable);
351
- executionRuntimesKnown = true;
352
- await storageReplay;
353
- if (ws === openedSocket && openedSocket.readyState === WebSocket.OPEN
354
- && detected.some((runtime) => !hello.executionRuntimes.includes(runtime))) {
355
- detectedExecutionRuntimes = detected;
356
- machineHelloPublisher.publish({ ...hello, executionRuntimes: [...detected] }, openedSocket);
357
- }
358
- return detected;
359
- })
360
- .catch((error) => {
361
- executionRuntimesKnown = true;
362
- dslog("execution.runtime_detection_failed", "runtime 探测失败", {
363
- level: "ERROR", error_message: error.message,
364
- });
365
- return [];
366
- });
367
- void helloPromise
368
- .then(async (hello) => {
369
- await storageReplay;
370
- if (ws !== openedSocket || openedSocket.readyState !== WebSocket.OPEN)
371
- return;
372
- detectedExecutionRuntimes = hello.executionRuntimes;
373
- machineHelloPublisher.publish(hello, openedSocket);
374
- })
375
- .catch(() => { });
313
+ machineRuntime.open(openedSocket, { capabilities: capabilities.machineHello, beforePublish: Promise.resolve(), connectionId });
376
314
  opts.onOpen?.(ws);
377
315
  void sendSnapshot(`reconnect-${randomUUID()}`);
378
316
  void executionJournal.replay()
@@ -401,8 +339,8 @@ export function serve(config, opts = {}) {
401
339
  });
402
340
  });
403
341
  });
404
- ws.on("message", async (data) => {
405
- if (stopped)
342
+ connectionSocket.on("message", async (data) => {
343
+ if (stopped || ws !== connectionSocket)
406
344
  return;
407
345
  let decoded;
408
346
  try {
@@ -414,8 +352,10 @@ export function serve(config, opts = {}) {
414
352
  if (typeof decoded !== "object" || decoded === null)
415
353
  return;
416
354
  const rawType = "type" in decoded && typeof decoded.type === "string" ? decoded.type : "";
417
- if (storageStatusDelivery.acknowledge(decoded))
355
+ if (rawType === "machine:environment:get" || rawType === "machine:environment:refresh") {
356
+ await handleMachineEnvironmentFrame(decoded, machineRuntime.provider, sendToConnection);
418
357
  return;
358
+ }
419
359
  if (rawType === "daemon:update" || rawType === "daemon:restart") {
420
360
  void updateController.handle(decoded).catch((error) => {
421
361
  dslog("daemon.control_failed", "daemon 控制操作处理失败", {
@@ -424,19 +364,6 @@ export function serve(config, opts = {}) {
424
364
  });
425
365
  return;
426
366
  }
427
- if (rawType === "daemon:migrate") {
428
- void handleMigrationControlMessage(migrationController, decoded).catch((error) => dslog("daemon.migration_failed", "daemon 布局迁移失败", { level: "ERROR", error_message: error.message }));
429
- return;
430
- }
431
- if (rawType === "daemon:codex-home-mode") {
432
- void codexHomeModeController.handle(decoded).catch((error) => dslog("daemon.codex_home_mode_failed", "Codex Home 模式切换失败", { level: "ERROR", error_message: error.message }));
433
- return;
434
- }
435
- if (handleStorageMigrationControl(opts.storageMigration, rawType, decoded, storageStatusDelivery.send, (kind, error) => {
436
- dslog(kind === "migration" ? "daemon.storage_migration_failed" : "daemon.storage_migration_confirmation_failed", kind === "migration" ? "存储迁移控制操作失败" : "存储迁移 hello 确认处理失败", { level: "ERROR", error_message: error.message });
437
- })) {
438
- return;
439
- }
440
367
  if (rawType.startsWith("execution:")) {
441
368
  const parsedExecution = ServerToDaemonExecutionFrameSchema.safeParse(decoded);
442
369
  if (!parsedExecution.success) {
@@ -498,10 +425,10 @@ export function serve(config, opts = {}) {
498
425
  return;
499
426
  }
500
427
  const spec = frame;
501
- if (storageMigrationRuntime.isAdmissionClosed()) {
428
+ if (storageIdentityAdmission.isAdmissionClosed()) {
502
429
  safeExecutionSend(ExecutionRejectedSchema.parse({
503
430
  type: "execution:rejected", protocolVersion: 1, executionId: spec.executionId,
504
- reason: "resource_limit", message: "Storage migration is quiescing this machine",
431
+ reason: "resource_limit", message: "Storage identity binding is not complete",
505
432
  at: new Date().toISOString(),
506
433
  }));
507
434
  return;
@@ -560,18 +487,8 @@ export function serve(config, opts = {}) {
560
487
  : spec.context.scheduledRunId === undefined ? "normal" : "scheduled";
561
488
  let reservation = sharedSlots.reserve(spec.agent.handle, "execution", executionClass);
562
489
  if (!reservation.accepted) {
563
- dslog("execution.machine_queue_rejected", "机器执行队列已满", {
564
- level: "WARN",
565
- execution_id: spec.executionId,
566
- agent_handle: spec.agent.handle,
567
- execution_class: executionClass,
568
- ...reservation.facts,
569
- });
570
- safeExecutionSend(ExecutionRejectedSchema.parse({
571
- type: "execution:rejected", protocolVersion: 1, executionId: spec.executionId,
572
- reason: "resource_limit", message: "Local machine execution queue is full",
573
- at: new Date().toISOString(),
574
- }));
490
+ await rejectQueuedAdmission({ journal: executionJournal, knownExecutionHashes, executionRuns,
491
+ report: reportExecutionFrame, replay: sendJournalStatus }, spec, executionClass, reservation.facts);
575
492
  return;
576
493
  }
577
494
  knownExecutionHashes.set(spec.executionId, hash);
@@ -710,9 +627,7 @@ export function serve(config, opts = {}) {
710
627
  let availableRuntimes;
711
628
  try {
712
629
  availableRuntimes = opts.execution?.availableRuntimes?.()
713
- ?? (detectedExecutionRuntimes.includes(spec.runtime.name)
714
- ? detectedExecutionRuntimes
715
- : await (runtimeFacts ?? Promise.resolve(detectedExecutionRuntimes)));
630
+ ?? await machineRuntime.availableRuntimes(spec.runtime.name);
716
631
  }
717
632
  catch (error) {
718
633
  cleanupExecutionReservation("runtime_detection_failed");
@@ -729,6 +644,7 @@ export function serve(config, opts = {}) {
729
644
  }
730
645
  const execution = executeProtocol(config, spec, {
731
646
  ...opts.execution?.dependencies,
647
+ machineEnvironment: machineRuntime.provider,
732
648
  capabilities: capabilities.executionRunner,
733
649
  projectSkills: opts.execution?.dependencies?.projectSkills ?? initializedProjectSkills,
734
650
  abilityRelease: opts.execution?.dependencies?.abilityRelease ?? agentAbilityRuntime.materializer,
@@ -741,6 +657,13 @@ export function serve(config, opts = {}) {
741
657
  ...reservation.facts,
742
658
  },
743
659
  report: reportExecutionFrame,
660
+ confirmPreAdmission: async (rejection) => {
661
+ const prior = await executionJournal.get(spec.executionId);
662
+ if (prior !== null || stopped || knownExecutionHashes.get(spec.executionId) !== hash
663
+ || executionRuns.get(spec.executionId) !== execution)
664
+ return false;
665
+ return await persistPreAdmissionRejection(executionJournal, spec, rejection) !== null;
666
+ },
744
667
  startupGate: runtimeStartupGate,
745
668
  startupTimeoutMs: config.executionLimits.startupTimeoutMs,
746
669
  onRuntimePhase: (phase, runtime) => {
@@ -812,17 +735,17 @@ export function serve(config, opts = {}) {
812
735
  // ready 帧带 server 视角的 machineId/workspaceId → 作为后续所有日志的默认关联键
813
736
  const r = msg;
814
737
  setSlogDefaults({ machine_id: r.machineId, workspace_id: r.workspaceId });
815
- if (opts.storageMigration !== undefined && typeof r.workspaceId === "string" && typeof r.machineId === "string") {
738
+ if (opts.storageRuntime !== undefined && typeof r.workspaceId === "string" && typeof r.machineId === "string") {
816
739
  const bindingSocket = ws;
817
- bindStorageMigrationServerIdentity(opts.storageMigration, { workspaceId: r.workspaceId, machineId: r.machineId }, {
740
+ bindStorageServerIdentity(opts.storageRuntime, { workspaceId: r.workspaceId, machineId: r.machineId }, {
818
741
  onBound: () => {
819
742
  if (bindingSocket !== ws || bindingSocket?.readyState !== WebSocket.OPEN)
820
743
  return;
821
- storageMigrationRuntime.completeIdentityBinding();
744
+ storageIdentityAdmission.completeIdentityBinding();
822
745
  machineHelloPublisher.republish();
823
746
  },
824
747
  onError: (error) => {
825
- dslog("daemon.storage_identity_bind_failed", "存储迁移 Workspace 身份绑定失败", { level: "ERROR", error_message: error.message });
748
+ dslog("daemon.storage_identity_bind_failed", "存储 Workspace 身份绑定失败", { level: "ERROR", error_message: error.message });
826
749
  if (bindingSocket === ws && bindingSocket?.readyState === WebSocket.OPEN)
827
750
  bindingSocket.close(1011, "storage identity binding failed");
828
751
  },
@@ -867,15 +790,17 @@ export function serve(config, opts = {}) {
867
790
  return;
868
791
  }
869
792
  if (msg.type === "runtime-health:probe") {
870
- const result = await handleRuntimeHealthProbeFrame(msg, opts.runtimeHealth?.probe, executionRuntimesKnown, detectedExecutionRuntimes);
793
+ const result = await machineRuntime.health(msg, opts.runtimeHealth?.probe);
871
794
  if (result !== null) {
872
- try {
873
- ws?.send(JSON.stringify({ type: "fs:result", ...result }));
874
- }
875
- catch { /* server 会超时 */ }
795
+ sendToConnection({ type: "fs:result", ...result });
876
796
  }
877
797
  return;
878
798
  }
799
+ if (marketplace.handle(msg, frame => { try {
800
+ ws?.send(JSON.stringify(frame));
801
+ }
802
+ catch { /* server 会按请求超时处理 */ } }))
803
+ return;
879
804
  if (await agentAbilityRuntime.tryHandleControlMessage(msg, serverCapabilities, (frame) => ws?.send(JSON.stringify(frame))))
880
805
  return;
881
806
  // 导入 raft agent 工作区:inspect 反填 name/description;import 复制用户内容
@@ -901,31 +826,16 @@ export function serve(config, opts = {}) {
901
826
  }
902
827
  return;
903
828
  }
904
- // workspace 文件浏览 / skills 枚举请求 (只读、沙箱;见 workspace-fs.ts / skills.ts)
905
- if (msg.type === "fs:list" || msg.type === "fs:read" || msg.type === "skills:list" || msg.type === "probe-models") {
906
- const req = msg;
907
- const root = join(config.agentsRoot, req.handle);
908
- const reply = (r) => {
909
- try {
910
- ws?.send(JSON.stringify({ type: "fs:result", reqId: req.reqId, ...r }));
911
- }
912
- catch { /* 忽略 */ }
913
- };
914
- try {
915
- const data2 = req.type === "fs:list" ? await listWorkspace(root, req.path)
916
- : req.type === "fs:read" ? await readWorkspaceFile(root, req.path)
917
- : req.type === "skills:list" ? await listSkills(req.runtime)
918
- : { models: await listRuntimeModels(req.type === "probe-models" ? (req.runtime ?? "") : "") };
919
- reply({ ok: true, data: data2 });
920
- }
921
- catch (e) {
922
- reply({ ok: false, error: e.message });
923
- }
829
+ if (await handleAgentEnvironmentFrame(msg, config.agentsRoot, sendToConnection))
830
+ return;
831
+ const fileResult = await handleWorkspaceControlRequest(msg, config.agentsRoot, projectWorkspaceRegistry, machineRuntime.models);
832
+ if (fileResult) {
833
+ sendToConnection(fileResult);
924
834
  return;
925
835
  }
926
836
  if (msg.type !== "agent:start")
927
837
  return; // ready/error 等忽略
928
- if (storageMigrationRuntime.isAdmissionClosed())
838
+ if (storageIdentityAdmission.isAdmissionClosed())
929
839
  return;
930
840
  // 任务键:scheduled run 用 runId(每次运行独立 cwd/work-log;overlap 由 server 端 skip_if_running 管,
931
841
  // daemon 的 running 去重只兜底"同一 run 重复投递");普通唤醒仍是 线程锚点 ?? 频道。
@@ -1128,6 +1038,7 @@ export function serve(config, opts = {}) {
1128
1038
  ...(!scheduled && msg.wake?.seq !== undefined ? { wakeContextUpToSeq: msg.wake.seq } : {}),
1129
1039
  ...(attemptWake ? { wake: attemptWake } : {}),
1130
1040
  }, reportActivity, reportConsole, {
1041
+ machineEnvironment: machineRuntime.provider,
1131
1042
  cancellation: controller.cancellation,
1132
1043
  startupGate: runtimeStartupGate,
1133
1044
  startupTimeoutMs: config.executionLimits.startupTimeoutMs,
@@ -1290,8 +1201,9 @@ export function serve(config, opts = {}) {
1290
1201
  void flushSlog(); // 每轮收尾冲一次,保证 run.end 尽快可查
1291
1202
  }
1292
1203
  });
1293
- ws.on("close", (code) => {
1294
- if (stopped)
1204
+ connectionSocket.on("close", (code) => {
1205
+ machineRuntime.close(connectionSocket);
1206
+ if (stopped || ws !== connectionSocket)
1295
1207
  return;
1296
1208
  // server 能力随连接失效;下个连接的 ready 帧重新声明(防降级重连后沿用过期能力)。
1297
1209
  serverCapabilities = new Set();
@@ -1315,9 +1227,9 @@ export function serve(config, opts = {}) {
1315
1227
  }, backoff);
1316
1228
  backoff = Math.min(backoff * 2, maxBackoff);
1317
1229
  });
1318
- ws.on("error", () => {
1230
+ connectionSocket.on("error", () => {
1319
1231
  if (!stopped)
1320
- ws?.close();
1232
+ connectionSocket.close();
1321
1233
  });
1322
1234
  }
1323
1235
  const ready = (async () => {
@@ -1355,9 +1267,7 @@ export function serve(config, opts = {}) {
1355
1267
  stopPromise = (async () => {
1356
1268
  stopped = true;
1357
1269
  concurrencyTelemetry.stop();
1358
- runtimeProbe.stop();
1359
1270
  completionRetransmitter.stop();
1360
- storageStatusDelivery.stop();
1361
1271
  const deadline = createShutdownDeadline(shutdownTimeoutMs);
1362
1272
  if (reconnectTimer !== null) {
1363
1273
  clearTimeout(reconnectTimer);
@@ -1365,10 +1275,10 @@ export function serve(config, opts = {}) {
1365
1275
  }
1366
1276
  const webSocketClosed = closeWebSocketWithinDeadline(ws, deadline.signal);
1367
1277
  const pending = [
1278
+ machineRuntime.stop(),
1368
1279
  webSocketClosed,
1369
1280
  updateController.drain(),
1370
- ...(migrationController === null ? [] : [migrationController.drain()]),
1371
- codexHomeModeController.drain(),
1281
+ marketplace.stop(),
1372
1282
  executionFrameQueue,
1373
1283
  ...executionRuns.values(),
1374
1284
  ...[...legacyRuns.values()].map((run) => run.done),
@@ -39,8 +39,5 @@ export function storageHelloIdentity(input) {
39
39
  daemonRootFingerprint: fingerprint("daemon-root", layout.daemonRoot),
40
40
  agentRootFingerprint: fingerprint("agent-root", layout.agentItemsRoot),
41
41
  ...(ownership === undefined ? {} : { storageOwnership: ownership }),
42
- ...(installation.storageMigrationId === undefined
43
- ? {}
44
- : { storageMigrationId: installation.storageMigrationId }),
45
42
  });
46
43
  }
@@ -1,55 +1,12 @@
1
- import { STORAGE_MIGRATION_CAPABILITY, STORAGE_MIGRATION_STATUS_CAPABILITY, } from "./storage-control.js";
2
- import { createStorageStatusDelivery } from "./storage-status-delivery.js";
3
- export function storageMigrationCapabilities(configured, options) {
4
- if (options === undefined)
5
- return configured;
6
- return Object.freeze([...new Set([
7
- ...configured,
8
- STORAGE_MIGRATION_STATUS_CAPABILITY,
9
- ...(options.ready ? [STORAGE_MIGRATION_CAPABILITY] : []),
10
- ])]);
1
+ export function bindStorageServerIdentity(options, identity, callbacks) {
2
+ void Promise.resolve().then(() => options.bindServerIdentity?.(identity))
3
+ .then(callbacks.onBound).catch(callbacks.onError);
11
4
  }
12
- export function bindStorageMigrationServerIdentity(options, identity, callbacks) {
13
- const bind = options?.bindServerIdentity;
14
- if (bind === undefined) {
15
- if (options?.ready === true)
16
- callbacks.onBound();
17
- return;
18
- }
19
- void Promise.resolve().then(() => bind(identity)).then(callbacks.onBound).catch(callbacks.onError);
20
- }
21
- export function createServeStorageStatusDelivery(options, dependencies) {
22
- return createStorageStatusDelivery({
23
- ...(options?.statusOutboxPath === undefined ? {} : { outboxPath: options.statusOutboxPath }),
24
- ...(options?.statusRetryMs === undefined ? {} : { retryMs: options.statusRetryMs }),
25
- ...dependencies,
26
- });
27
- }
28
- export function attachStorageMigrationRuntime(options, dependencies) {
29
- let migrationAdmissionClosed = false;
5
+ /** 新连接必须重新验证 Server 身份,不能沿用上一次连接的执行准入。 */
6
+ export function createStorageIdentityAdmission(options) {
30
7
  let identityAdmissionClosed = options?.bindServerIdentity !== undefined;
31
- if (options?.ready === true) {
32
- options.attach?.({
33
- gate: {
34
- isBusy: dependencies.isBusy,
35
- closeAndFlush: async () => {
36
- migrationAdmissionClosed = true;
37
- await dependencies.waitForExecutionFrames();
38
- if (dependencies.isBusy()) {
39
- migrationAdmissionClosed = false;
40
- throw Object.assign(new Error("active execution entered before storage migration quiesce"), {
41
- code: "runtime_busy",
42
- });
43
- }
44
- await dependencies.flushLocalState();
45
- },
46
- reopen: () => { migrationAdmissionClosed = false; },
47
- },
48
- sendStatus: dependencies.sendStatus,
49
- });
50
- }
51
8
  return Object.freeze({
52
- isAdmissionClosed: () => migrationAdmissionClosed || identityAdmissionClosed,
9
+ isAdmissionClosed: () => identityAdmissionClosed,
53
10
  beginIdentityBinding: () => {
54
11
  if (options?.bindServerIdentity !== undefined)
55
12
  identityAdmissionClosed = true;
@@ -57,26 +14,3 @@ export function attachStorageMigrationRuntime(options, dependencies) {
57
14
  completeIdentityBinding: () => { identityAdmissionClosed = false; },
58
15
  });
59
16
  }
60
- export function replayStorageMigrationStatus(options, socket, isCurrent, onError, deliver) {
61
- return options?.replayStatus?.((frame) => {
62
- if (!isCurrent())
63
- return;
64
- if (deliver !== undefined)
65
- deliver(frame);
66
- else if (socket.readyState === socket.OPEN)
67
- socket.send(JSON.stringify(frame));
68
- }).catch(onError) ?? Promise.resolve();
69
- }
70
- export function handleStorageMigrationControl(options, rawType, raw, sendStatus, onError) {
71
- if (rawType === "daemon:storage-doctor" || rawType === "daemon:storage-migrate") {
72
- if (options?.ready === true)
73
- void options.controller.handle(raw).catch((error) => onError("migration", error));
74
- return true;
75
- }
76
- if (rawType !== "daemon:storage-migration-confirmed")
77
- return false;
78
- const confirm = options?.ready === false ? options.confirm : undefined;
79
- if (confirm !== undefined)
80
- void confirm(raw, sendStatus).catch((error) => onError("confirmation", error));
81
- return true;
82
- }
@@ -1,7 +1,7 @@
1
1
  import { fileURLToPath } from "node:url";
2
2
  import { startDormantSupervisor, } from "./execution-supervisor.js";
3
3
  import { buildClaudeLaunch } from "./runtimes/claude.js";
4
- import { DEEPSEEK_HARNESS_CONFIG_ENV, deepSeekHarnessConfigPath, } from "./runtimes/deepseek-harness.js";
4
+ import { DEEPSEEK_HARNESS_CONFIG_ENV, deepSeekHarnessConfigPath, deepSeekHarnessLauncher, } from "./runtimes/deepseek-harness.js";
5
5
  import { RuntimeCancelledError } from "./runtime-cancellation.js";
6
6
  export function supervisorLaunch(request) {
7
7
  const common = {
@@ -82,7 +82,22 @@ export function supervisorLaunch(request) {
82
82
  if (request.runtime === "deepseek-harness") {
83
83
  if (request.resume)
84
84
  throw new Error("DeepSeek Harness ACP does not support session resume");
85
- const configPath = deepSeekHarnessConfigPath();
85
+ const launcher = deepSeekHarnessLauncher(request.env);
86
+ if (launcher.kind === "profile") {
87
+ return {
88
+ command: process.execPath,
89
+ args: [fileURLToPath(new URL("./runtimes/deepseek-harness-runner.js", import.meta.url)),
90
+ "--bin", request.bin, ...(launcher.patchPath ? ["--patch", launcher.patchPath] : [])],
91
+ cwd: request.cwd, env: request.env,
92
+ stdinText: JSON.stringify({ systemPrompt: request.systemPrompt, wakePrompt: request.wakePrompt,
93
+ stateRoot: request.harnessStateRoot ?? request.cwd, skillRoots: request.harnessSkillRoots ?? [],
94
+ effectivePermission: request.effectivePermission }),
95
+ };
96
+ }
97
+ if ((request.harnessSkillRoots?.length ?? 0) > 0) {
98
+ throw new Error("DeepSeek Harness bound Skills require the modern dsh ACP profile");
99
+ }
100
+ const configPath = deepSeekHarnessConfigPath(request.env);
86
101
  if (configPath === null) {
87
102
  throw new Error(`${DEEPSEEK_HARNESS_CONFIG_ENV} must be an absolute path`);
88
103
  }
package/dist/token.js CHANGED
@@ -1,4 +1,3 @@
1
- /** 用机器令牌为某 agent 换取 per-launch 的 sk_agent_*。 */
2
1
  export async function mintAgentToken(serverUrl, machineToken, handle, displayName, options = {}, fetchImpl = fetch) {
3
2
  const res = await fetchImpl(`${serverUrl}/daemon/agents/token`, {
4
3
  method: "POST",