@nowcrew/daemon 0.6.60 → 0.6.64

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 (47) hide show
  1. package/README.md +9 -8
  2. package/dist/agent-ability/materializer.js +1 -20
  3. package/dist/automatic-install-target.js +10 -15
  4. package/dist/computer-cli.js +1 -10
  5. package/dist/computer-service.js +1 -41
  6. package/dist/config.js +0 -35
  7. package/dist/daemon-migration-controller.js +18 -16
  8. package/dist/execution-runner.js +13 -35
  9. package/dist/local-executor.js +1 -44
  10. package/dist/machine-info.js +2 -3
  11. package/dist/main.js +0 -83
  12. package/dist/managed-service-lifecycle.js +2 -47
  13. package/dist/managed-service-startup.js +0 -2
  14. package/dist/profile-layout.js +4 -10
  15. package/dist/runner.js +0 -1
  16. package/dist/serve.js +3 -64
  17. package/dist/workspace.js +1 -24
  18. package/package.json +10 -9
  19. package/dist/local-memory/index-budget.js +0 -74
  20. package/dist/local-memory/pending.js +0 -111
  21. package/dist/local-memory/runtime.js +0 -87
  22. package/dist/local-memory/types.js +0 -1
  23. package/dist/local-memory/write.js +0 -448
  24. package/dist/storage-config.js +0 -175
  25. package/dist/storage-control.js +0 -131
  26. package/dist/storage-copy.js +0 -444
  27. package/dist/storage-credential-guard.js +0 -21
  28. package/dist/storage-doctor.js +0 -175
  29. package/dist/storage-identity.js +0 -29
  30. package/dist/storage-layout.js +0 -143
  31. package/dist/storage-manifest.js +0 -440
  32. package/dist/storage-migration-controller.js +0 -417
  33. package/dist/storage-migration-manifest.js +0 -105
  34. package/dist/storage-migration-policy.js +0 -100
  35. package/dist/storage-runtime-controller.js +0 -313
  36. package/dist/storage-runtime-readiness.js +0 -184
  37. package/dist/storage-runtime.js +0 -39
  38. package/dist/storage-safe-fs.js +0 -293
  39. package/dist/storage-serve-adapter.js +0 -65
  40. package/dist/storage-status-delivery.js +0 -201
  41. package/dist/storage-status-replay.js +0 -125
  42. package/dist/storage-target-confirmation.js +0 -129
  43. package/dist/storage-worker-command.js +0 -27
  44. package/dist/storage-worker-executor.js +0 -383
  45. package/dist/storage-worker-handoff.js +0 -151
  46. package/dist/storage-worker-operation.js +0 -283
  47. package/dist/storage-worker-status.js +0 -105
package/dist/main.js CHANGED
@@ -7,7 +7,6 @@
7
7
  */
8
8
  import { parseArgs } from "node:util";
9
9
  import { homedir } from "node:os";
10
- import { join } from "node:path";
11
10
  import { loadConfig, ConfigError } from "./config.js";
12
11
  import { detectDaemonLang, formatDaemonText, translateDaemon } from "./i18n.js";
13
12
  import { cliVersion, daemonVersion } from "./machine-info.js";
@@ -22,18 +21,7 @@ import { formatDaemonStartupError } from "./daemon-startup-error.js";
22
21
  import { assertManagedServiceStartup } from "./managed-service-startup.js";
23
22
  import { daemonGlobalInstallation } from "./daemon-installation.js";
24
23
  import { acquireDaemonInstallationLease, runWithDaemonInstallationLease, } from "./daemon-installation-lease.js";
25
- import { loadStorageRuntime } from "./storage-runtime.js";
26
- import { readStorageMigrationReceipt } from "./storage-migration-controller.js";
27
- import { storageMigrationStatusReplay } from "./storage-status-replay.js";
28
- import { runStorageWorkerCommand } from "./storage-worker-command.js";
29
- import { probeStorageMigrationRuntime } from "./storage-runtime-readiness.js";
30
- import { createStorageTargetConfirmationHandler } from "./storage-target-confirmation.js";
31
24
  async function main() {
32
- const workerResult = await runStorageWorkerCommand(process.argv.slice(2));
33
- if (workerResult !== null) {
34
- process.exitCode = workerResult;
35
- return;
36
- }
37
25
  const computerResult = await runComputerCommand(process.argv.slice(2));
38
26
  if (computerResult !== null) {
39
27
  process.exitCode = computerResult;
@@ -69,10 +57,8 @@ async function main() {
69
57
  // 不把 machine token 放进 argv / plist / systemd unit / scheduled task。
70
58
  if (values["daemon-home"])
71
59
  process.env.CREW_DAEMON_HOME = values["daemon-home"];
72
- let activeDaemonHome;
73
60
  if (values.profile) {
74
61
  const home = daemonHome();
75
- activeDaemonHome = home;
76
62
  const profile = await loadProfile(values.profile, home);
77
63
  if (cmd === "serve") {
78
64
  await assertProfileAgentsRootUnique(profile, home, homedir());
@@ -85,12 +71,6 @@ async function main() {
85
71
  agentsRoot: resolveAgentsRoot(profile.agentsRoot, homedir(), process.platform),
86
72
  nodePath: process.execPath,
87
73
  entryPath: builtDaemonEntry(),
88
- environment: {
89
- ...(process.env.NOWWORK_HOME === undefined ? {} : { NOWWORK_HOME: process.env.NOWWORK_HOME }),
90
- ...(process.env.NOWWORK_ENV_TAG === undefined ? {} : { NOWWORK_ENV_TAG: process.env.NOWWORK_ENV_TAG }),
91
- ...(process.env.NOWWORK_STORAGE_POLICY_PATH === undefined
92
- ? {} : { NOWWORK_STORAGE_POLICY_PATH: process.env.NOWWORK_STORAGE_POLICY_PATH }),
93
- },
94
74
  });
95
75
  }
96
76
  applyProfileToEnv(profile, process.env);
@@ -120,72 +100,9 @@ async function main() {
120
100
  const installationLease = installation === null
121
101
  ? null
122
102
  : await acquireDaemonInstallationLease(installation.npmPrefix);
123
- const storageRuntime = values.profile === undefined
124
- ? null
125
- : await loadStorageRuntime({
126
- profile: values.profile,
127
- serverUrl: config.serverUrl,
128
- userHome: homedir(),
129
- platform: process.platform,
130
- environment: process.env,
131
- });
132
- const migrationRuntime = values.profile === undefined || activeDaemonHome === undefined || storageRuntime !== null
133
- ? { ready: false, reason: "not_legacy_source" }
134
- : await probeStorageMigrationRuntime({
135
- profile: values.profile,
136
- serverUrl: config.serverUrl,
137
- currentDaemonHome: activeDaemonHome,
138
- currentAgentsRoot: config.agentsRoot,
139
- userHome: homedir(),
140
- platform: process.platform,
141
- ...(process.getuid === undefined ? {} : { uid: process.getuid() }),
142
- environment: process.env,
143
- });
144
- const targetConfirmation = storageRuntime?.identity.storageMigrationId === undefined
145
- ? null
146
- : createStorageTargetConfirmationHandler({
147
- backupsRoot: storageRuntime.local.backupsRoot,
148
- identity: storageRuntime.identity,
149
- profile: storageRuntime.installation.profile,
150
- completionTimeoutMs: 180_000,
151
- });
152
- const storageMigration = storageRuntime !== null
153
- ? {
154
- ready: false,
155
- statusOutboxPath: join(storageRuntime.local.stateRoot, "storage-status-outbox.json"),
156
- identity: storageRuntime.identity,
157
- ...(targetConfirmation === null ? {} : { confirm: targetConfirmation.handle }),
158
- ...(storageRuntime.identity.storageMigrationId === undefined ? {} : {
159
- replayStatus: async (send) => {
160
- const migrationId = storageRuntime.identity.storageMigrationId;
161
- const receipt = await readStorageMigrationReceipt(storageRuntime.local.backupsRoot, migrationId);
162
- if (receipt === null)
163
- throw new Error(`storage migration receipt not found: ${migrationId}`);
164
- for (const frame of storageMigrationStatusReplay(receipt, {
165
- migrationId,
166
- environment: storageRuntime.identity.storageEnvironment,
167
- workspaceId: storageRuntime.identity.storageWorkspaceId,
168
- profile: storageRuntime.installation.profile,
169
- }))
170
- send(frame);
171
- },
172
- }),
173
- }
174
- : migrationRuntime.ready
175
- ? {
176
- ready: true,
177
- statusOutboxPath: migrationRuntime.runtime.statusOutboxPath,
178
- identity: migrationRuntime.runtime.identity,
179
- controller: migrationRuntime.runtime.controller,
180
- attach: migrationRuntime.runtime.attach,
181
- bindServerIdentity: migrationRuntime.runtime.bindServerIdentity,
182
- replayStatus: migrationRuntime.runtime.replayStatus,
183
- }
184
- : undefined;
185
103
  await runWithDaemonInstallationLease(installationLease, async () => {
186
104
  const service = serve(config, {
187
105
  ...(values.profile === undefined ? {} : { profileName: values.profile }),
188
- ...(storageMigration === undefined ? {} : { storageMigration }),
189
106
  });
190
107
  await runServeLifecycle(service);
191
108
  });
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { acquireDaemonInstallationLease } from "./daemon-installation-lease.js";
3
- import { installService, ensureServiceEnabled, readServiceDescriptor, serviceAction, replaceInstalledServiceDescriptor, uninstallService, } from "./computer-service.js";
3
+ import { installService, ensureServiceEnabled, readServiceDescriptor, serviceAction, uninstallService, } from "./computer-service.js";
4
4
  import { ManagedServiceConflictError, ManagedServiceRegistryError, assertRegistryCoversDescriptors, listManagedServiceDescriptorPaths, managedServiceIdentityMatches, managedServiceConflict, normalizeManagedServiceRecord, serviceDescriptorSha256, withManagedServiceRegistryLock, } from "./managed-service-registry.js";
5
5
  function requirePortableManagedSpec(spec) {
6
6
  if ((spec.platform !== "darwin" && spec.platform !== "linux")
@@ -35,17 +35,6 @@ function sameManagedIdentity(left, right) {
35
35
  const { generation: _generation, createdAt: _createdAt, ...expected } = right;
36
36
  return managedServiceIdentityMatches(left, expected);
37
37
  }
38
- function sameManagedResource(left, right) {
39
- const { generation: _leftGeneration, createdAt: _leftCreatedAt, descriptorSha256: _leftHash, ...leftResource } = left;
40
- const { generation: _rightGeneration, createdAt: _rightCreatedAt, descriptorSha256: _rightHash, ...rightResource } = right;
41
- return JSON.stringify(leftResource) === JSON.stringify(rightResource);
42
- }
43
- function descriptorDiffIsStorageEnvironmentOnly(previous, next) {
44
- if (!next.includes("\n <key>EnvironmentVariables</key>\n"))
45
- return false;
46
- const strip = (descriptor) => descriptor.replace(/\n <key>EnvironmentVariables<\/key>\n <dict>\n(?: <key>(?:NOWWORK_HOME|NOWWORK_ENV_TAG|NOWWORK_STORAGE_POLICY_PATH)<\/key><string>[^<]*<\/string>\n)+ <\/dict>\n/u, "\n");
47
- return strip(previous) === strip(next);
48
- }
49
38
  function assertRecordDescribesSpec(input) {
50
39
  requirePortableManagedSpec(input.spec);
51
40
  const { spec, record } = input;
@@ -62,20 +51,8 @@ function assertRecordDescribesSpec(input) {
62
51
  }
63
52
  }
64
53
  export async function installManagedService(input) {
54
+ assertRecordDescribesSpec(input);
65
55
  requirePortableManagedSpec(input.spec);
66
- const requestedDescriptor = input.spec.descriptor;
67
- const expectedDescriptorHash = serviceDescriptorSha256(input.spec.descriptor);
68
- const expectedPath = normalizeManagedServiceRecord({
69
- ...input.record,
70
- descriptorPath: input.spec.descriptorPath,
71
- descriptorSha256: expectedDescriptorHash,
72
- }).descriptorPath;
73
- if (input.record.platform !== input.spec.platform
74
- || input.record.serviceId !== input.spec.id
75
- || input.record.profile !== input.spec.profile
76
- || input.record.descriptorPath !== expectedPath) {
77
- throw new ManagedServiceRegistryError(`Managed service record does not describe '${input.spec.id}'`);
78
- }
79
56
  const acquire = input.acquireInstallationLease ?? acquireDaemonInstallationLease;
80
57
  await withManagedServiceRegistryLock(input.registry ?? {}, async ({ services, replace }) => {
81
58
  const exact = services.find((record) => sameManagedIdentity(record, input.record));
@@ -99,28 +76,6 @@ export async function installManagedService(input) {
99
76
  }
100
77
  return;
101
78
  }
102
- const registered = services.find((record) => record.serviceId === input.record.serviceId
103
- && record.profile === input.record.profile
104
- && record.daemonHome === input.record.daemonHome);
105
- if (registered !== undefined && sameManagedResource(registered, input.record)) {
106
- const current = await readServiceDescriptor(input.spec);
107
- if (current === null || serviceDescriptorSha256(current) !== registered.descriptorSha256) {
108
- throw new ManagedServiceRegistryError(`Installed descriptor for '${input.spec.id}' does not match its registry record`);
109
- }
110
- if (!descriptorDiffIsStorageEnvironmentOnly(current, requestedDescriptor)) {
111
- throw new ManagedServiceRegistryError(`Installed descriptor for '${input.spec.id}' conflicts with the requested identity`);
112
- }
113
- await replaceInstalledServiceDescriptor(input.spec, current, input.runner);
114
- try {
115
- await replace(services.map((record) => record === registered ? input.record : record));
116
- }
117
- catch (error) {
118
- const rollbackSpec = { ...input.spec, descriptor: current };
119
- await replaceInstalledServiceDescriptor(rollbackSpec, requestedDescriptor, input.runner).catch(() => undefined);
120
- throw error;
121
- }
122
- return;
123
- }
124
79
  const conflict = managedServiceConflict(services, input.record);
125
80
  if (conflict !== null) {
126
81
  throw new ManagedServiceConflictError(conflict.resource, input.record, conflict.owner);
@@ -14,7 +14,6 @@ export async function assertManagedServiceStartup(input) {
14
14
  nodePath: input.nodePath,
15
15
  entryPath: input.entryPath,
16
16
  profileHome: input.daemonHome,
17
- ...(input.environment === undefined ? {} : { environment: input.environment }),
18
17
  });
19
18
  const readRegistry = input.readManagedServices
20
19
  ?? (() => readManagedServiceRegistry({ userHome: input.userHome }));
@@ -43,7 +42,6 @@ export async function assertManagedServiceStartup(input) {
43
42
  nodePath: input.nodePath,
44
43
  entryPath: input.entryPath,
45
44
  profileHome: input.daemonHome,
46
- ...(input.environment === undefined ? {} : { environment: input.environment }),
47
45
  legacyServiceId: true,
48
46
  });
49
47
  const legacyDescriptor = await readDescriptor(legacySpec);
@@ -2,10 +2,6 @@ import { posix, win32 } from "node:path";
2
2
  export const PROFILE_LAYOUT_VERSION = 1;
3
3
  const PROFILE_NAME = /^[a-z0-9][a-z0-9_-]{0,47}$/u;
4
4
  const LOCAL_INSTANCE_NAME = /^[a-z0-9][a-z0-9_-]{0,39}$/u;
5
- /** Accept the legacy `in` tag at the boundary, but never persist it in a new layout. */
6
- export function normalizeProfileEnvironment(value) {
7
- return value === "in" ? "production" : value;
8
- }
9
5
  export function validateLocalInstanceName(value) {
10
6
  const normalized = value.trim().toLowerCase();
11
7
  if (!LOCAL_INSTANCE_NAME.test(normalized) || normalized.includes("..")) {
@@ -14,21 +10,19 @@ export function validateLocalInstanceName(value) {
14
10
  return normalized;
15
11
  }
16
12
  export function profileForLocalInstance(environment, localInstanceName) {
17
- const canonicalEnvironment = normalizeProfileEnvironment(environment);
18
- const profile = `nw-${canonicalEnvironment}-${validateLocalInstanceName(localInstanceName)}`;
13
+ const profile = `nw-${environment}-${validateLocalInstanceName(localInstanceName)}`;
19
14
  if (!PROFILE_NAME.test(profile))
20
15
  throw new Error("derived daemon profile exceeds 48 characters");
21
16
  return profile;
22
17
  }
23
18
  export function profileLayout(input) {
24
- const environment = normalizeProfileEnvironment(input.environment);
25
19
  const localInstanceName = validateLocalInstanceName(input.localInstanceName);
26
- const profile = profileForLocalInstance(environment, localInstanceName);
20
+ const profile = profileForLocalInstance(input.environment, localInstanceName);
27
21
  const paths = input.platform === "win32" ? win32 : posix;
28
- const base = `${environment}-${localInstanceName}`;
22
+ const base = `${input.environment}-${localInstanceName}`;
29
23
  return Object.freeze({
30
24
  layoutVersion: PROFILE_LAYOUT_VERSION,
31
- environment,
25
+ environment: input.environment,
32
26
  localInstanceName,
33
27
  profile,
34
28
  daemonHome: paths.join(input.userHome, ".crew", `daemon-${base}`),
package/dist/runner.js CHANGED
@@ -105,7 +105,6 @@ export async function runAgent(config, input, onActivity = defaultPrint, onConso
105
105
  softTokens: config.sessionSoftTokens,
106
106
  maxTurns: config.sessionMaxTurns,
107
107
  },
108
- localMemoryV2Enabled: config.localMemoryV2Handles?.has(input.handle) === true,
109
108
  }, {
110
109
  onActivity,
111
110
  onConsole,
package/dist/serve.js CHANGED
@@ -51,7 +51,6 @@ import { handleRuntimeProbeFrame, probeRuntimeHealth } from "./runtime-health.js
51
51
  import { buildControlPlaneUrl } from "./control-plane-url.js";
52
52
  import { createServeMigrationController, handleMigrationControlMessage } from "./daemon-migration-wiring.js";
53
53
  import { createCodexHomeModeController } from "./codex-home-mode-controller.js";
54
- import { attachStorageMigrationRuntime, createServeStorageStatusDelivery, handleStorageMigrationControl, replayStorageMigrationStatus, storageMigrationCapabilities, } from "./storage-serve-adapter.js";
55
54
  export { buildControlPlaneUrl } from "./control-plane-url.js";
56
55
  // normalize.ts 的活动种类 → activity 枚举
57
56
  const ACTIVITY_MAP = {
@@ -176,36 +175,13 @@ export function serve(config, opts = {}) {
176
175
  });
177
176
  const machineHelloPublisher = createProjectSkillMachineHelloPublisher({
178
177
  status: projectSkillControllerReadiness.status,
179
- effective: (hello, status) => {
180
- const effective = withProjectSkillCapabilityStatus(hello, status);
181
- const configuredIdentity = opts.storageMigration?.identity;
182
- const currentIdentity = typeof configuredIdentity === "function"
183
- ? configuredIdentity()
184
- : configuredIdentity;
185
- return currentIdentity === undefined ? effective : { ...effective, ...currentIdentity };
186
- },
178
+ effective: withProjectSkillCapabilityStatus,
187
179
  onSent: (hello) => log(`📤 已上报机器信息: ${hello.hostname} · ${hello.os} · installed=[${hello.runtimes.join(",")}] · executable=[${hello.executionRuntimes.join(",")}] · agents=[${hello.agentHandles.join(",")}]`),
188
180
  });
189
181
  const initializedProjectSkills = initializedProjectSkillsReconciler(projectSkillControllerReadiness.ensure, projectSkillsReconciler);
190
- const configuredCapabilities = opts.machineInfo?.capabilities ?? daemonCapabilities(process.platform);
191
- const storageCapabilities = storageMigrationCapabilities(configuredCapabilities, opts.storageMigration);
192
- const storageStatusDelivery = createServeStorageStatusDelivery(opts.storageMigration, {
193
- onPersistenceError: (error) => dslog("daemon.storage_status_outbox_failed", "存储迁移状态 outbox 持久化失败", { level: "ERROR", error_message: error.message }),
194
- transmit: (frame) => { try {
195
- if (ws?.readyState === WebSocket.OPEN)
196
- ws.send(JSON.stringify(frame));
197
- }
198
- catch { /* retry */ } },
199
- });
200
- const storageMigrationRuntime = attachStorageMigrationRuntime(opts.storageMigration, {
201
- isBusy: () => executionRuns.size > 0 || legacyRuns.size > 0,
202
- waitForExecutionFrames: () => executionFrameQueue,
203
- flushLocalState: flushSlog,
204
- sendStatus: storageStatusDelivery.send,
205
- });
206
182
  const prepareProjectSkillCapabilities = createProjectSkillConnectionCapabilityProvider({
207
183
  platform: process.platform,
208
- baseCapabilities: storageCapabilities,
184
+ baseCapabilities: opts.machineInfo?.capabilities ?? daemonCapabilities(process.platform),
209
185
  additionalCapabilities: () => managedDaemonCapabilities(updateEligibility),
210
186
  probeRuntimeRootStorePrimitive: projectSkillRuntimeRootStartup.probeNativePublicationPrimitiveReadiness,
211
187
  initializeController: projectSkillControllerReadiness.ensure,
@@ -334,12 +310,6 @@ export function serve(config, opts = {}) {
334
310
  // 连上了才有机会把离线期间(断连原因/退出前)落盘的日志补传上去
335
311
  void drainSpool();
336
312
  // 上报本机信息 (hostname/os/daemon 版本/已装 runtimes)
337
- storageStatusDelivery.replayPending();
338
- const storageReplay = replayStorageMigrationStatus(opts.storageMigration, openedSocket, () => ws === openedSocket, (error) => {
339
- dslog("daemon.storage_status_replay_failed", "存储迁移状态重放失败", {
340
- level: "ERROR", error_message: error.message,
341
- });
342
- }, storageStatusDelivery.send);
343
313
  const { detectInstalled, detectExecutable = detectExecutionRuntimesWithSignal } = opts.machineInfo ?? {};
344
314
  const helloPromise = (opts.machineInfo?.collect ?? collectMachineHello)(config.agentsRoot, config.executionLimits, process.platform, {
345
315
  ...(detectInstalled ? { detectInstalled } : {}),
@@ -355,7 +325,6 @@ export function serve(config, opts = {}) {
355
325
  if (hello.executionProtocol === undefined)
356
326
  return [];
357
327
  const detected = await runtimeProbe.detect(hello.runtimes, detectExecutable);
358
- await storageReplay;
359
328
  if (ws === openedSocket && openedSocket.readyState === WebSocket.OPEN
360
329
  && detected.some((runtime) => !hello.executionRuntimes.includes(runtime))) {
361
330
  detectedExecutionRuntimes = detected;
@@ -370,8 +339,7 @@ export function serve(config, opts = {}) {
370
339
  return [];
371
340
  });
372
341
  void helloPromise
373
- .then(async (hello) => {
374
- await storageReplay;
342
+ .then((hello) => {
375
343
  if (ws !== openedSocket || openedSocket.readyState !== WebSocket.OPEN)
376
344
  return;
377
345
  detectedExecutionRuntimes = hello.executionRuntimes;
@@ -419,8 +387,6 @@ export function serve(config, opts = {}) {
419
387
  if (typeof decoded !== "object" || decoded === null)
420
388
  return;
421
389
  const rawType = "type" in decoded && typeof decoded.type === "string" ? decoded.type : "";
422
- if (storageStatusDelivery.acknowledge(decoded))
423
- return;
424
390
  if (rawType === "daemon:update" || rawType === "daemon:restart") {
425
391
  void updateController.handle(decoded).catch((error) => {
426
392
  dslog("daemon.control_failed", "daemon 控制操作处理失败", {
@@ -437,11 +403,6 @@ export function serve(config, opts = {}) {
437
403
  void codexHomeModeController.handle(decoded).catch((error) => dslog("daemon.codex_home_mode_failed", "Codex Home 模式切换失败", { level: "ERROR", error_message: error.message }));
438
404
  return;
439
405
  }
440
- if (handleStorageMigrationControl(opts.storageMigration, rawType, decoded, storageStatusDelivery.send, (kind, error) => {
441
- dslog(kind === "migration" ? "daemon.storage_migration_failed" : "daemon.storage_migration_confirmation_failed", kind === "migration" ? "存储迁移控制操作失败" : "存储迁移 hello 确认处理失败", { level: "ERROR", error_message: error.message });
442
- })) {
443
- return;
444
- }
445
406
  if (rawType.startsWith("execution:")) {
446
407
  const parsedExecution = ServerToDaemonExecutionFrameSchema.safeParse(decoded);
447
408
  if (!parsedExecution.success) {
@@ -503,14 +464,6 @@ export function serve(config, opts = {}) {
503
464
  return;
504
465
  }
505
466
  const spec = frame;
506
- if (storageMigrationRuntime.isAdmissionClosed()) {
507
- safeExecutionSend(ExecutionRejectedSchema.parse({
508
- type: "execution:rejected", protocolVersion: 1, executionId: spec.executionId,
509
- reason: "resource_limit", message: "Storage migration is quiescing this machine",
510
- at: new Date().toISOString(),
511
- }));
512
- return;
513
- }
514
467
  const workspaceRejection = projectWorkspaceCapabilityRejection(spec, capabilities.executionRunner, new Date().toISOString());
515
468
  if (workspaceRejection !== null)
516
469
  return void safeExecutionSend(workspaceRejection);
@@ -817,17 +770,6 @@ export function serve(config, opts = {}) {
817
770
  // ready 帧带 server 视角的 machineId/workspaceId → 作为后续所有日志的默认关联键
818
771
  const r = msg;
819
772
  setSlogDefaults({ machine_id: r.machineId, workspace_id: r.workspaceId });
820
- if (opts.storageMigration?.ready === true && typeof r.workspaceId === "string") {
821
- try {
822
- opts.storageMigration.bindServerIdentity?.({ workspaceId: r.workspaceId });
823
- machineHelloPublisher.republish();
824
- }
825
- catch (error) {
826
- dslog("daemon.storage_identity_bind_failed", "存储迁移 Workspace 身份绑定失败", {
827
- level: "ERROR", error_message: error.message,
828
- });
829
- }
830
- }
831
773
  // 旧 server 无此字段 → 空集合(daemon 保持全部旧行为)。
832
774
  serverCapabilities = new Set(Array.isArray(r.serverCapabilities)
833
775
  ? r.serverCapabilities.filter((c) => typeof c === "string")
@@ -926,8 +868,6 @@ export function serve(config, opts = {}) {
926
868
  }
927
869
  if (msg.type !== "agent:start")
928
870
  return; // ready/error 等忽略
929
- if (storageMigrationRuntime.isAdmissionClosed())
930
- return;
931
871
  // 任务键:scheduled run 用 runId(每次运行独立 cwd/work-log;overlap 由 server 端 skip_if_running 管,
932
872
  // daemon 的 running 去重只兜底"同一 run 重复投递");普通唤醒仍是 线程锚点 ?? 频道。
933
873
  const scheduled = msg.reason === "scheduled_job" && msg.scheduledRun
@@ -1343,7 +1283,6 @@ export function serve(config, opts = {}) {
1343
1283
  concurrencyTelemetry.stop();
1344
1284
  runtimeProbe.stop();
1345
1285
  completionRetransmitter.stop();
1346
- storageStatusDelivery.stop();
1347
1286
  const deadline = createShutdownDeadline(shutdownTimeoutMs);
1348
1287
  if (reconnectTimer !== null) {
1349
1288
  clearTimeout(reconnectTimer);
package/dist/workspace.js CHANGED
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * spawn runtime 时把 <ws>/.crew 置于 PATH 最前,于是 agent 的 `crew ...` 命中 wrapper。
10
10
  */
11
- import { mkdir, writeFile, readFile, chmod, access, lstat } from "node:fs/promises";
11
+ import { mkdir, writeFile, readFile, chmod, access } from "node:fs/promises";
12
12
  import { createHash, randomUUID } from "node:crypto";
13
13
  import { dirname, join } from "node:path";
14
14
  import { dslog } from "./slog.js";
@@ -34,28 +34,8 @@ async function exists(p) {
34
34
  return false;
35
35
  }
36
36
  }
37
- async function hasLocalMemoryV2Marker(agentDir) {
38
- const crewDir = join(agentDir, ".crew");
39
- const memoryDir = join(crewDir, "memory");
40
- const markerPath = join(agentDir, ".crew", "memory", "v2-enabled");
41
- try {
42
- const crewStat = await lstat(crewDir);
43
- const memoryStat = await lstat(memoryDir);
44
- if (!crewStat.isDirectory() || crewStat.isSymbolicLink()
45
- || !memoryStat.isDirectory() || memoryStat.isSymbolicLink())
46
- return false;
47
- const stat = await lstat(markerPath);
48
- if (!stat.isFile() || stat.isSymbolicLink())
49
- return false;
50
- return (await readFile(markerPath, "utf8")) === "1\n";
51
- }
52
- catch {
53
- return false;
54
- }
55
- }
56
37
  export async function prepareWorkspace(input) {
57
38
  const dir = join(input.agentsRoot, input.handle);
58
- const agentHomePreexisted = await exists(dir);
59
39
  const crewDir = join(dir, ".crew");
60
40
  await mkdir(crewDir, { recursive: true });
61
41
  // 预先创建明细目录,让收尾流程可以按功能创建 notes/<topic>.md。
@@ -63,7 +43,6 @@ export async function prepareWorkspace(input) {
63
43
  // MEMORY.md:首次创建"持久身份 + 知识索引"骨架,之后由 agent 自己维护
64
44
  const memoryPath = join(dir, "MEMORY.md");
65
45
  const memorySeedCreated = !(await exists(memoryPath));
66
- const localMemoryV2Initialized = await hasLocalMemoryV2Marker(dir);
67
46
  if (memorySeedCreated) {
68
47
  try {
69
48
  await writeFile(memoryPath, memorySeed(input.handle, input.description), "utf8");
@@ -145,9 +124,7 @@ export async function prepareWorkspace(input) {
145
124
  crewDir,
146
125
  systemPromptPath,
147
126
  memory,
148
- agentHomePreexisted,
149
127
  memorySeedCreated,
150
- localMemoryV2Initialized,
151
128
  homeDir,
152
129
  runDir,
153
130
  workLogPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nowcrew/daemon",
3
- "version": "0.6.60",
3
+ "version": "0.6.64",
4
4
  "type": "module",
5
5
  "description": "crew daemon — 运行在用户机器:拉起/管理 agent 进程,注入 crew CLI,归一化 runtime 事件",
6
6
  "license": "Apache-2.0",
@@ -16,6 +16,14 @@
16
16
  "publishConfig": {
17
17
  "access": "public"
18
18
  },
19
+ "scripts": {
20
+ "daemon": "pnpm --filter @nowcrew/cli build && tsx src/main.ts",
21
+ "build": "tsc -p tsconfig.json",
22
+ "codex-home:migrate": "tsx src/runtimes/codex-home-migration-cli.ts",
23
+ "prepublishOnly": "pnpm build && node ../scripts/daemon-release-artifact.mjs --strict-registry",
24
+ "test": "vitest run",
25
+ "typecheck": "tsc --noEmit"
26
+ },
19
27
  "dependencies": {
20
28
  "@agentclientprotocol/sdk": "1.2.1",
21
29
  "@nowcrew/cli": "^0.4.13",
@@ -34,12 +42,5 @@
34
42
  "tsx": "^4.19.0",
35
43
  "typescript": "^5.6.0",
36
44
  "vitest": "^2.1.0"
37
- },
38
- "scripts": {
39
- "daemon": "pnpm --filter @nowcrew/cli build && tsx src/main.ts",
40
- "build": "tsc -p tsconfig.json",
41
- "codex-home:migrate": "tsx src/runtimes/codex-home-migration-cli.ts",
42
- "test": "vitest run",
43
- "typecheck": "tsc --noEmit"
44
45
  }
45
- }
46
+ }
@@ -1,74 +0,0 @@
1
- export const LOCAL_MEMORY_TOTAL_CODE_POINT_CAP = 6_000;
2
- export const LOCAL_MEMORY_INDEX_CODE_POINT_CAP = 3_000;
3
- export const LOCAL_MEMORY_INDEX_ENTRY_CAP = 20;
4
- const PROJECTABLE_STATUSES = new Set(["pinned", "active"]);
5
- function codePointLength(value) {
6
- return Array.from(value).length;
7
- }
8
- export function renderLocalMemoryIndexCard(entry) {
9
- return `### ${entry.title}\n`
10
- + `- id: ${entry.id}\n`
11
- + `- file: ${entry.file}\n`
12
- + `- type: ${entry.type}\n`
13
- + `- status: ${entry.status}\n`
14
- + `- summary: ${entry.summary}\n`
15
- + `- triggers: ${entry.triggers.join(", ")}\n`
16
- + `- priority: ${entry.priority}\n`
17
- + `- revision: ${entry.revision}\n`
18
- + `- anchor: ${entry.anchor ?? ""}\n`
19
- + `- updated: ${entry.updated}\n`
20
- + (entry.reviewAfter === null ? "" : `- review_after: ${entry.reviewAfter}\n`);
21
- }
22
- function compareEntries(left, right) {
23
- const statusRank = (status) => status === "pinned" ? 0 : 1;
24
- const priorityRank = (priority) => (priority === "high" ? 0 : priority === "medium" ? 1 : 2);
25
- return statusRank(left.status) - statusRank(right.status)
26
- || priorityRank(left.priority) - priorityRank(right.priority)
27
- || right.updated.localeCompare(left.updated)
28
- || left.id.localeCompare(right.id);
29
- }
30
- function cardLength(entry, hasPrevious) {
31
- return codePointLength(renderLocalMemoryIndexCard(entry)) + (hasPrevious ? 1 : 0);
32
- }
33
- function overBudgetReason(entries) {
34
- return entries.some((entry) => entry.status === "pinned")
35
- ? "index_over_budget_pinned"
36
- : "index_over_budget_active";
37
- }
38
- export function selectLocalMemoryIndexEntries(entries, budget, options = {}) {
39
- const projectable = entries.filter((entry) => PROJECTABLE_STATUSES.has(entry.status));
40
- const omittedIds = entries
41
- .filter((entry) => !PROJECTABLE_STATUSES.has(entry.status))
42
- .map((entry) => entry.id);
43
- const protectedIds = options.protectedIds ?? new Set();
44
- const protectedEntries = projectable.filter((entry) => protectedIds.has(entry.id)).sort(compareEntries);
45
- const candidates = projectable.filter((entry) => !protectedIds.has(entry.id)).sort(compareEntries);
46
- const selected = [];
47
- let renderedLength = 0;
48
- for (const entry of protectedEntries) {
49
- selected.push(entry);
50
- renderedLength += cardLength(entry, selected.length > 1);
51
- }
52
- if (selected.length > budget.entryCap || renderedLength > budget.indexCodePointCap) {
53
- return {
54
- entries: selected,
55
- omittedIds: [...omittedIds, ...candidates.map((entry) => entry.id)],
56
- reason: overBudgetReason(selected),
57
- };
58
- }
59
- for (const entry of candidates) {
60
- if (selected.length >= budget.entryCap || renderedLength + cardLength(entry, selected.length > 0) > budget.indexCodePointCap) {
61
- omittedIds.push(entry.id);
62
- continue;
63
- }
64
- selected.push(entry);
65
- renderedLength += cardLength(entry, selected.length > 1);
66
- }
67
- return {
68
- entries: selected,
69
- omittedIds,
70
- reason: omittedIds.length === entries.filter((item) => !PROJECTABLE_STATUSES.has(item.status)).length
71
- ? null
72
- : "index_over_budget",
73
- };
74
- }