@nowcrew/daemon 0.6.99-beta.1 → 0.6.99-beta.2

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 (57) hide show
  1. package/dist/cloud-report-upload.js +10 -1
  2. package/dist/computer-service.js +30 -5
  3. package/dist/execution-journal.js +1 -3
  4. package/dist/execution-protocol.js +1 -1
  5. package/dist/execution-runner.js +1 -4
  6. package/dist/local-execution-prompt.js +3 -8
  7. package/dist/local-executor.js +39 -64
  8. package/dist/local-memory/index-budget.js +3 -9
  9. package/dist/local-memory/inventory-cli.js +8 -52
  10. package/dist/local-memory/inventory-source.js +8 -15
  11. package/dist/local-memory/pending-query.js +2 -5
  12. package/dist/local-memory/pending-schema.js +1 -1
  13. package/dist/local-memory/pending.js +2 -16
  14. package/dist/local-memory/prompt.js +5 -21
  15. package/dist/local-memory/read-cli.js +76 -98
  16. package/dist/local-memory/rollout.js +11 -79
  17. package/dist/local-memory/runtime.js +13 -181
  18. package/dist/local-memory/write.js +21 -189
  19. package/dist/local-memory-diagnostics.js +15 -96
  20. package/dist/local-memory-telemetry.js +3 -20
  21. package/dist/machine-info.js +0 -3
  22. package/dist/marketplace-protocol.js +1 -1
  23. package/dist/marketplace-remote.js +1 -1
  24. package/dist/marketplace-runner.js +1 -1
  25. package/dist/memory-prune-diagnostics.js +4 -60
  26. package/dist/message-file-preview.js +1 -11
  27. package/dist/prompt.js +17 -9
  28. package/dist/runner.js +1 -1
  29. package/dist/runtimes/claude-thread-runner.js +4 -25
  30. package/dist/serve.js +3 -38
  31. package/dist/token.js +0 -1
  32. package/dist/workspace-control-handler.js +3 -16
  33. package/dist/workspace.js +2 -13
  34. package/package.json +1 -1
  35. package/dist/local-memory/commit-telemetry.js +0 -30
  36. package/dist/local-memory/execution-workspace.js +0 -62
  37. package/dist/local-memory/full-index-search.js +0 -47
  38. package/dist/local-memory/initialization-identity.js +0 -36
  39. package/dist/local-memory/inventory-v2.js +0 -362
  40. package/dist/local-memory/legacy-adapter.js +0 -233
  41. package/dist/local-memory/migration-access.js +0 -242
  42. package/dist/local-memory/migration-cli.js +0 -54
  43. package/dist/local-memory/migration-io.js +0 -199
  44. package/dist/local-memory/migration-pending.js +0 -9
  45. package/dist/local-memory/migration-plan.js +0 -432
  46. package/dist/local-memory/migration-schema.js +0 -55
  47. package/dist/local-memory/migration-state-invariants.js +0 -65
  48. package/dist/local-memory/migration-store.js +0 -414
  49. package/dist/local-memory/migration-tool-entry.js +0 -21
  50. package/dist/local-memory/source-path.js +0 -13
  51. package/dist/local-memory/storage-format.js +0 -249
  52. package/dist/local-memory/writer-mode.js +0 -13
  53. package/dist/memory-migration-controller.js +0 -89
  54. package/dist/memory-migration-inspect.js +0 -108
  55. package/dist/memory-migration-journal.js +0 -14
  56. package/dist/memory-migration-protocol.js +0 -14
  57. package/dist/memory-migration-runtime.js +0 -305
package/dist/serve.js CHANGED
@@ -14,7 +14,6 @@ import { reconcileExecutionJournal } from "./execution-recovery.js";
14
14
  import { initReleaseSlog, reportDaemonConnectionClose, reportReleaseError } from "./release-channel-guard.js";
15
15
  import { handleWorkspaceControlRequest } from "./workspace-control-handler.js";
16
16
  import { inspectRaftWorkspace, importRaftWorkspace } from "./workspace-import.js";
17
- import { withMemoryAccess } from "./local-memory/migration-access.js";
18
17
  import { normalizeScheduledContext } from "./scheduled-report.js";
19
18
  import { formatDaemonLogLine } from "./log-format.js";
20
19
  import { reportAgentRunComplete } from "./scheduled-run-report.js";
@@ -51,8 +50,6 @@ import { probeRuntimeHealth } from "./runtime-health.js";
51
50
  import { createServeMarketplace } from "./marketplace-serve.js";
52
51
  import { buildControlPlaneUrl } from "./control-plane-url.js";
53
52
  import { resolveDaemonLocalStateRootFromEnv } from "./daemon-local-home.js";
54
- import { createMemoryMigrationController } from "./memory-migration-controller.js";
55
- import { createMemoryMigrationJournal, replayExecutionJournals } from "./memory-migration-journal.js";
56
53
  import { bindStorageServerIdentity, createStorageIdentityAdmission, } from "./storage-serve-adapter.js";
57
54
  export { buildControlPlaneUrl } from "./control-plane-url.js";
58
55
  // normalize.ts 的活动种类 → activity 枚举
@@ -78,8 +75,6 @@ export function serve(config, opts = {}) {
78
75
  let reconnectTimer = null;
79
76
  let stopPromise = null;
80
77
  let executionJournal;
81
- let migrationExecutionJournal;
82
- let migrationJournalReady = false;
83
78
  const injectedExecutionJournal = opts.execution?.journal;
84
79
  const agentMemory = opts.execution?.dependencies?.agentMemory
85
80
  ?? (config.agentMemory === null ? undefined : createAgentMemoryBridge(config.agentMemory));
@@ -94,15 +89,6 @@ export function serve(config, opts = {}) {
94
89
  startupGapMs: config.executionLimits.startupGapMs,
95
90
  });
96
91
  const localSlots = createSharedSlotManager(config.executionLimits);
97
- const memoryMigrations = createMemoryMigrationController({ config, coordinator: hostCoordinator,
98
- isAdmissionClosed: () => stopped || storageIdentityAdmission.isAdmissionClosed(),
99
- journal: () => { if (!migrationJournalReady)
100
- throw new Error("memory_migration_journal_unavailable"); return migrationExecutionJournal; }, send: frame => {
101
- if (frame.type === "execution:completed")
102
- completionRetransmitter.track(frame);
103
- else if (ws?.readyState === WebSocket.OPEN)
104
- ws.send(JSON.stringify(frame));
105
- } });
106
92
  const sharedSlots = hostCoordinatedSlotManager(localSlots, hostCoordinator);
107
93
  const concurrencyTelemetry = createExecutionConcurrencyTelemetry(sharedSlots, {
108
94
  ...(opts.execution?.concurrencySnapshotIntervalMs === undefined
@@ -284,7 +270,7 @@ export function serve(config, opts = {}) {
284
270
  return null;
285
271
  };
286
272
  const sendSnapshot = async (reqId) => {
287
- const entries = (await replayExecutionJournals(executionJournal, migrationExecutionJournal)).map(snapshotEntry).filter((entry) => entry !== null);
273
+ const entries = (await executionJournal.replay()).map(snapshotEntry).filter((entry) => entry !== null);
288
274
  safeExecutionSend(ExecutionSnapshotSchema.parse({
289
275
  type: "execution:snapshot", protocolVersion: 1, reqId, entries,
290
276
  }));
@@ -366,12 +352,6 @@ export function serve(config, opts = {}) {
366
352
  machineRuntime.open(openedSocket, { capabilities: capabilities.machineHello, beforePublish: Promise.resolve(), connectionId });
367
353
  opts.onOpen?.(ws);
368
354
  void sendSnapshot(`reconnect-${randomUUID()}`);
369
- // 普通回执不等待维护日志IO;两类记录分别重放到同一发送器。
370
- void migrationExecutionJournal.replay().then(entries => {
371
- for (const entry of entries)
372
- if (entry.completion && !entry.completionAcknowledged)
373
- completionRetransmitter.track(entry.completion);
374
- }).catch(() => dslog("memory_migration.journal_unavailable", "维护回执重放失败,普通回执继续", { level: "ERROR" }));
375
355
  void executionJournal.replay()
376
356
  .then((entries) => {
377
357
  for (const entry of entries) {
@@ -451,8 +431,7 @@ export function serve(config, opts = {}) {
451
431
  return;
452
432
  if (frame.type === "execution:completion-ack") {
453
433
  try {
454
- const journal = await executionJournal.get(frame.executionId) ? executionJournal : migrationExecutionJournal;
455
- await journal.acknowledgeCompletion(frame.executionId);
434
+ await executionJournal.acknowledgeCompletion(frame.executionId);
456
435
  const attempts = completionRetransmitter.acknowledge(frame.executionId);
457
436
  dslog("execution.completion_acknowledged", "execution completion ACK 已持久化", {
458
437
  execution_id: frame.executionId,
@@ -478,8 +457,6 @@ export function serve(config, opts = {}) {
478
457
  return;
479
458
  }
480
459
  if (frame.type === "execution:cancel") {
481
- if (memoryMigrations.cancel(frame.executionId))
482
- return;
483
460
  if (!knownExecutionHashes.has(frame.executionId)
484
461
  && !executionRuns.has(frame.executionId)
485
462
  && await executionJournal.get(frame.executionId) === null)
@@ -712,7 +689,6 @@ export function serve(config, opts = {}) {
712
689
  const execution = executeProtocol(config, spec, {
713
690
  ...opts.execution?.dependencies,
714
691
  machineEnvironment: machineRuntime.provider,
715
- ...(memoryMigrations.getIdentity() === null ? {} : { controlIdentity: memoryMigrations.getIdentity() }),
716
692
  capabilities: capabilities.executionRunner,
717
693
  projectSkills: opts.execution?.dependencies?.projectSkills ?? initializedProjectSkills,
718
694
  abilityRelease: opts.execution?.dependencies?.abilityRelease ?? agentAbilityRuntime.materializer,
@@ -803,8 +779,6 @@ export function serve(config, opts = {}) {
803
779
  // ready 帧带 server 视角的 machineId/workspaceId → 作为后续所有日志的默认关联键
804
780
  const r = msg;
805
781
  setSlogDefaults({ machine_id: r.machineId, workspace_id: r.workspaceId });
806
- if (r.workspaceId && r.machineId)
807
- memoryMigrations.setIdentity({ workspaceId: r.workspaceId, machineId: r.machineId });
808
782
  // 旧 server 无此字段 → 空集合(daemon 保持全部旧行为)。ackSupported() 依赖它判断是否重试,
809
783
  // 必须在任何 republish() 之前就位;否则本轮 republish 看到空集合→不排重试→整套 ack/重连机制哑火。
810
784
  serverCapabilities = new Set(Array.isArray(r.serverCapabilities)
@@ -873,8 +847,6 @@ export function serve(config, opts = {}) {
873
847
  }
874
848
  catch { /* server 会按请求超时处理 */ } }))
875
849
  return;
876
- if (await memoryMigrations.handle(msg))
877
- return;
878
850
  if (await agentAbilityRuntime.tryHandleControlMessage(msg, serverCapabilities, (frame) => ws?.send(JSON.stringify(frame))))
879
851
  return;
880
852
  // 导入 raft agent 工作区:inspect 反填 name/description;import 复制用户内容
@@ -889,7 +861,7 @@ export function serve(config, opts = {}) {
889
861
  try {
890
862
  const data2 = req.type === "raft:inspect"
891
863
  ? await inspectRaftWorkspace(req.path)
892
- : await withMemoryAccess(join(config.agentsRoot, req.handle), () => importRaftWorkspace(req.path, join(config.agentsRoot, req.handle)), { create: true });
864
+ : await importRaftWorkspace(req.path, join(config.agentsRoot, req.handle));
893
865
  if (req.type === "raft:import") {
894
866
  log(`📦 已导入 raft 工作区 → ${req.handle}: 复制 ${data2.copied.length} 项`);
895
867
  }
@@ -1282,7 +1254,6 @@ export function serve(config, opts = {}) {
1282
1254
  return;
1283
1255
  // server 能力随连接失效;下个连接的 ready 帧重新声明(防降级重连后沿用过期能力)。
1284
1256
  serverCapabilities = new Set();
1285
- memoryMigrations.clearIdentity();
1286
1257
  completionRetransmitter.pause();
1287
1258
  // 4001 = 控制面应用级「鉴权失败」关闭码(见 server control-plane.ts)。即使上面的
1288
1259
  // error 帧因 close 抢先而丢失,也能据关闭码识别这是凭证失效——退避拉满,不再每秒热循环。
@@ -1335,9 +1306,6 @@ export function serve(config, opts = {}) {
1335
1306
  writeStderr: (line) => process.stderr.write(line),
1336
1307
  });
1337
1308
  await runProjectSkillStartupCleanup(config.agentsRoot, executionJournal, dslog);
1338
- migrationExecutionJournal = createMemoryMigrationJournal(config.agentsRoot);
1339
- await migrationExecutionJournal.reconcileAfterRestart().then(() => { migrationJournalReady = true; })
1340
- .catch(() => dslog("memory_migration.journal_unavailable", "迁移日志恢复失败,普通执行继续,迁移请求单独报错", { level: "ERROR" }));
1341
1309
  await connect();
1342
1310
  })();
1343
1311
  const stop = () => {
@@ -1355,7 +1323,6 @@ export function serve(config, opts = {}) {
1355
1323
  const webSocketClosed = closeWebSocketWithinDeadline(ws, deadline.signal);
1356
1324
  const pending = [
1357
1325
  machineRuntime.stop(),
1358
- memoryMigrations.stop(),
1359
1326
  webSocketClosed,
1360
1327
  updateController.drain(),
1361
1328
  marketplace.stop(),
@@ -1374,8 +1341,6 @@ export function serve(config, opts = {}) {
1374
1341
  if (executionJournal !== undefined) {
1375
1342
  await executionJournal.close({ signal: deadline.signal });
1376
1343
  }
1377
- if (migrationExecutionJournal !== undefined)
1378
- await migrationExecutionJournal.close({ signal: deadline.signal });
1379
1344
  }
1380
1345
  finally {
1381
1346
  deadline.dispose();
package/dist/token.js CHANGED
@@ -7,7 +7,6 @@ export async function mintAgentToken(serverUrl, machineToken, handle, displayNam
7
7
  },
8
8
  // 把本轮唤醒的线程根钉到 per-launch 令牌:服务端据此让 task/消息默认绑/回当前线程。
9
9
  body: JSON.stringify({
10
- memoryStateGuardVersion: 1,
11
10
  handle,
12
11
  ...(displayName ? { displayName } : {}),
13
12
  ...(options.wakeThreadRoot ? { wakeThreadRoot: options.wakeThreadRoot } : {}),
@@ -1,22 +1,9 @@
1
1
  /** 控制面文件/技能查看的按需处理,独立于执行生命周期。 */
2
- import { lstat } from "node:fs/promises";
3
- import { join, resolve } from "node:path";
2
+ import { join } from "node:path";
4
3
  import { readSharedMessageFile } from "./message-file-preview.js";
5
4
  import { listWorkspace, readWorkspaceFile } from "./workspace-fs.js";
6
5
  import { listSkills } from "./skills.js";
7
6
  import { listRuntimeModels } from "./list-models.js";
8
- import { withMemoryAccess } from "./local-memory/migration-access.js";
9
- async function listProtectedWorkspace(root, path) {
10
- try {
11
- await lstat(root);
12
- }
13
- catch (error) {
14
- if (error.code !== "ENOENT")
15
- throw error;
16
- return { root: resolve(root), path: path.replace(/^\/+/, ""), entries: [] };
17
- }
18
- return withMemoryAccess(root, () => listWorkspace(root, path));
19
- }
20
7
  export async function handleWorkspaceControlRequest(raw, agentsRoot, registry, models = listRuntimeModels) {
21
8
  if (!raw || typeof raw !== "object")
22
9
  return null;
@@ -28,8 +15,8 @@ export async function handleWorkspaceControlRequest(raw, agentsRoot, registry, m
28
15
  try {
29
16
  const root = join(agentsRoot, request.handle);
30
17
  const data = request.type === "fs:read-shared" ? await readSharedMessageFile(agentsRoot, raw, registry)
31
- : request.type === "fs:list" ? await listProtectedWorkspace(root, request.path)
32
- : request.type === "fs:read" ? await withMemoryAccess(root, () => readWorkspaceFile(root, request.path))
18
+ : request.type === "fs:list" ? await listWorkspace(root, request.path)
19
+ : request.type === "fs:read" ? await readWorkspaceFile(root, request.path)
33
20
  : request.type === "skills:list" ? await listSkills(request.runtime)
34
21
  : { models: await models(request.runtime ?? "") };
35
22
  return { type: "fs:result", reqId: request.reqId, ok: true, data };
package/dist/workspace.js CHANGED
@@ -8,15 +8,12 @@
8
8
  *
9
9
  * spawn runtime 时把 <ws>/.crew 置于 PATH 最前,于是 agent 的 `crew ...` 命中 wrapper。
10
10
  */
11
- import { mkdir, writeFile, readFile, chmod, access, lstat, realpath } from "node:fs/promises";
11
+ import { mkdir, writeFile, readFile, chmod, access, lstat } from "node:fs/promises";
12
12
  import { createHash, randomUUID } from "node:crypto";
13
13
  import { dirname, join } from "node:path";
14
14
  import { fileURLToPath, pathToFileURL } from "node:url";
15
15
  import { createRequire } from "node:module";
16
16
  import { dslog } from "./slog.js";
17
- import { MigrationStateSchema } from "./local-memory/migration-schema.js";
18
- import { assertMigrationStateIntegrity } from "./local-memory/migration-state-invariants.js";
19
- import { detectLocalMemoryStorageVersion } from "./local-memory/storage-format.js";
20
17
  /** 文件系统安全的 taskKey:仅留 [\w.-],其余转 _,截断,避免路径穿越/超长。 */
21
18
  export function safeKey(key) {
22
19
  return key.replace(/[^\w.-]+/g, "_").replace(/^[-.]+/, "").slice(0, 80) || "default";
@@ -52,15 +49,7 @@ async function hasLocalMemoryV2Marker(agentDir) {
52
49
  const stat = await lstat(markerPath);
53
50
  if (!stat.isFile() || stat.isSymbolicLink())
54
51
  return false;
55
- if ((await readFile(markerPath, "utf8")) !== "1\n")
56
- return false;
57
- const root = await realpath(agentDir);
58
- const state = MigrationStateSchema.parse(JSON.parse(await readFile(join(memoryDir, "migration.v1.json"), "utf8")));
59
- assertMigrationStateIntegrity(state, state.identity);
60
- return state.phase === "committed" && state.storageVersion === 2
61
- && state.identity.rootFingerprint === createHash("sha256").update(root).digest("hex")
62
- && state.identity.ownerIdentity === String((await lstat(root)).uid)
63
- && detectLocalMemoryStorageVersion(await readFile(join(root, "MEMORY.md"), "utf8")) === 2;
52
+ return (await readFile(markerPath, "utf8")) === "1\n";
64
53
  }
65
54
  catch {
66
55
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nowcrew/daemon",
3
- "version": "0.6.99-beta.1",
3
+ "version": "0.6.99-beta.2",
4
4
  "type": "module",
5
5
  "description": "crew daemon — 运行在用户机器:拉起/管理 agent 进程,注入 crew CLI,归一化 runtime 事件",
6
6
  "license": "Apache-2.0",
@@ -1,30 +0,0 @@
1
- import { dslog } from "../slog.js";
2
- function boundedIds(ids) {
3
- return {
4
- value: (ids ?? []).slice(0, 100).join(","),
5
- count: ids?.length ?? 0,
6
- truncated: (ids?.length ?? 0) > 100,
7
- };
8
- }
9
- export function logLocalMemoryCommitApplied(input) {
10
- const { committed } = input;
11
- const created = boundedIds(committed.createdIds);
12
- const updated = boundedIds(committed.updatedIds);
13
- const statusChanged = boundedIds(committed.statusChangedIds);
14
- const pending = boundedIds(committed.pendingIds);
15
- dslog("local_memory.commit_applied", "结构化本地记忆提交已验证", {
16
- execution_id: input.executionId, agent_handle: input.agentHandle, prune_trace_id: input.pruneTraceId,
17
- storage_version_before: committed.storageVersionBefore,
18
- storage_version_after: committed.storageVersionAfter,
19
- committed_state: committed.committedState,
20
- writer_mode: committed.pendingReason === "legacy_requires_migration"
21
- ? "pending_only"
22
- : committed.storageVersionAfter === 2 && committed.committedState ? "v2" : "legacy",
23
- created_id_count: created.count, created_ids: created.value, created_ids_truncated: created.truncated,
24
- updated_id_count: updated.count, updated_ids: updated.value, updated_ids_truncated: updated.truncated,
25
- status_changed_id_count: statusChanged.count, status_changed_ids: statusChanged.value,
26
- status_changed_ids_truncated: statusChanged.truncated,
27
- pending_id_count: pending.count, pending_ids: pending.value, pending_ids_truncated: pending.truncated,
28
- pending_reason: committed.pendingReason,
29
- });
30
- }
@@ -1,62 +0,0 @@
1
- import { prepareWorkspace } from "../workspace.js";
2
- import { awaitWithCancellation } from "../runtime-cancellation.js";
3
- import { logLocalMemoryContextPrepareFailure } from "../local-memory-telemetry.js";
4
- import { resolveLocalMemoryV2Rollout } from "./rollout.js";
5
- import { initializeLocalMemoryV2ForWorkspace } from "./runtime.js";
6
- import { withMemoryAccess } from "./migration-access.js";
7
- import { join } from "node:path";
8
- import { readFile } from "node:fs/promises";
9
- // A fresh Agent may receive the daemon's full ten-wide execution burst. The
10
- // first turn publishes schema2 durably; the remaining turns must wait to reuse
11
- // that committed fact instead of timing out on the generic short IO window.
12
- const EXECUTION_MEMORY_ACCESS_WAIT_MS = 30_000;
13
- export async function prepareExecutionMemoryWorkspace(input, isolated, cancellation) {
14
- try {
15
- const prepare = async (context) => {
16
- const prepared = await prepareWorkspace({
17
- agentsRoot: input.launch.agentsRoot, handle: input.handle, cliPath: input.launch.cliPath,
18
- executionId: input.executionId,
19
- ...(input.keyMode === undefined ? {} : { keyMode: input.keyMode }),
20
- ...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }),
21
- ...(input.resumeKey === undefined ? {} : { resumeKey: input.resumeKey }),
22
- ...(input.sessionContextFingerprint === undefined ? {} : { sessionContextFingerprint: input.sessionContextFingerprint }),
23
- ...(input.launch.description ? { description: input.launch.description } : {}),
24
- ...(isolated ? { skipLocalMemory: true } : {}),
25
- });
26
- const workspace = context?.created ? { ...prepared, agentHomePreexisted: false } : prepared;
27
- const initialMode = await resolveLocalMemoryV2Rollout({ workspace, handle: input.handle, serverUrl: input.launch.serverUrl,
28
- agentId: input.launch.agentId, requested: input.localMemoryV2Enabled === true, selfTraining: isolated,
29
- ...(input.launch.description ? { description: input.launch.description } : {}) });
30
- const initializationBinding = input.launch.workspaceId !== undefined && input.launch.machineId !== undefined
31
- ? { workspaceId: input.launch.workspaceId, machineId: input.launch.machineId }
32
- : undefined;
33
- const initialized = await initializeLocalMemoryV2ForWorkspace(workspace, initialMode.enabled, input.launch.agentId, initializationBinding);
34
- const memory = initialized && !workspace.localMemoryV2Initialized
35
- ? await readFile(join(workspace.dir, "MEMORY.md"), "utf8")
36
- : workspace.memory;
37
- const currentWorkspace = { ...workspace, memory };
38
- const mode = initialized && !workspace.localMemoryV2Initialized
39
- ? await resolveLocalMemoryV2Rollout({ workspace: currentWorkspace, handle: input.handle,
40
- serverUrl: input.launch.serverUrl, agentId: input.launch.agentId,
41
- requested: input.localMemoryV2Enabled === true, selfTraining: isolated,
42
- ...(input.launch.description ? { description: input.launch.description } : {}) })
43
- : initialMode;
44
- return { workspace: { ...currentWorkspace, localMemoryV2Enabled: mode.enabled }, mode, initialized };
45
- };
46
- return await awaitWithCancellation(isolated ? prepare()
47
- : withMemoryAccess(join(input.launch.agentsRoot, input.handle), prepare, {
48
- create: true,
49
- waitMs: EXECUTION_MEMORY_ACCESS_WAIT_MS,
50
- initializedRecoveryIdentity: {
51
- agentId: input.launch.agentId,
52
- ...(input.launch.workspaceId === undefined ? {} : { workspaceId: input.launch.workspaceId }),
53
- ...(input.launch.machineId === undefined ? {} : { machineId: input.launch.machineId }),
54
- },
55
- }), cancellation);
56
- }
57
- catch (error) {
58
- logLocalMemoryContextPrepareFailure({ executionId: input.executionId, agentHandle: input.handle,
59
- ...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }) }, "workspace_prepare", error);
60
- throw error;
61
- }
62
- }
@@ -1,47 +0,0 @@
1
- import { parseFullMemoryIndex, LOCAL_MEMORY_GENERATED_INDEX_PATTERN } from "./storage-format.js";
2
- const excerpt = (text, size) => Array.from(text).slice(0, size).join("");
3
- /** 查询完整元数据;只在明确的历史入口返回非有效记录。正文仍按引用和哈希分页读取。 */
4
- export function searchFullMemoryIndex(memory, sha256, input, outputBytes) {
5
- const records = parseFullMemoryIndex(memory);
6
- const block = LOCAL_MEMORY_GENERATED_INDEX_PATTERN.exec(memory);
7
- const prefix = memory.slice(0, block.index);
8
- let line = (prefix.match(/\n/gu) ?? []).length + 1;
9
- let offset = Array.from(prefix).length;
10
- const positions = new Map();
11
- for (const part of block[0].matchAll(/[^\n]*(?:\n|$)/gu)) {
12
- const id = /^- id: ([A-Za-z0-9_-]+)\r?\n?$/u.exec(part[0])?.[1];
13
- if (id)
14
- positions.set(id, { line, offset });
15
- line += 1;
16
- offset += Array.from(part[0]).length;
17
- }
18
- const terms = input.query.normalize("NFKC").toLowerCase().split(/\s+/u).filter(Boolean);
19
- const candidates = records.filter(entry => {
20
- const active = entry.status === "active" || entry.status === "pinned";
21
- const content = `${entry.id} ${entry.title} ${entry.summary} ${entry.triggers.join(" ")}`.normalize("NFKC").toLowerCase();
22
- return active !== input.history && terms.every(term => content.includes(term));
23
- });
24
- const matches = [];
25
- let bytes = 512, hasMore = false;
26
- for (const entry of candidates) {
27
- const position = positions.get(entry.id);
28
- if (!position)
29
- throw new Error("memory_storage_position_invalid");
30
- if (position.line <= input.afterLine)
31
- continue;
32
- const item = { ...position, id: entry.id, status: entry.status, revision: entry.revision,
33
- file: entry.file, anchor: entry.anchor, heading: excerpt(entry.title, 96),
34
- title: excerpt(entry.title, 120), summary: excerpt(entry.summary, 240), text: excerpt(entry.summary, 240) };
35
- const size = Buffer.byteLength(JSON.stringify(item), "utf8") + 1;
36
- if (matches.length >= input.limit || bytes + size > outputBytes) {
37
- hasMore = true;
38
- break;
39
- }
40
- matches.push(item);
41
- bytes += size;
42
- }
43
- if (hasMore && matches.length === 0)
44
- throw new Error("memory_output_too_large");
45
- return { file: "MEMORY.md", storageVersion: 2, sha256, matches, matchCount: candidates.length,
46
- hasMore, complete: !hasMore, nextAfterLine: hasMore ? matches.at(-1).line : null };
47
- }
@@ -1,36 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { lstat, realpath } from "node:fs/promises";
3
- export const LEGACY_LOCAL_INITIALIZATION_IDENTITY = "local-initialized";
4
- export async function localMemoryInitializationIdentity(agentDir, agentId, binding) {
5
- const root = await realpath(agentDir);
6
- const rootFingerprint = createHash("sha256").update(root).digest("hex");
7
- const workspaceId = binding?.workspaceId ?? LEGACY_LOCAL_INITIALIZATION_IDENTITY;
8
- const machineId = binding?.machineId ?? LEGACY_LOCAL_INITIALIZATION_IDENTITY;
9
- // Keep the legacy digest byte-for-byte stable so an interrupted pre-upgrade
10
- // initialization can still be inspected. Every newly authenticated daemon
11
- // initialization includes both control-plane identities in its operation id.
12
- const operationSeed = workspaceId === LEGACY_LOCAL_INITIALIZATION_IDENTITY
13
- && machineId === LEGACY_LOCAL_INITIALIZATION_IDENTITY
14
- ? `${agentId}\0${root}`
15
- : `${workspaceId}\0${machineId}\0${agentId}\0${root}`;
16
- const operation = createHash("sha256").update(operationSeed, "utf8").digest("hex").slice(0, 24);
17
- return {
18
- workspaceId,
19
- agentId,
20
- migrationId: `initialize-${operation}`,
21
- sourceStorageVersion: 0,
22
- targetStorageVersion: 2,
23
- rootFingerprint,
24
- ownerIdentity: String((await lstat(root)).uid),
25
- machineId,
26
- executionId: `initialize-${operation}`,
27
- };
28
- }
29
- export function isLegacyLocalMemoryInitializationIdentity(identity) {
30
- return identity.workspaceId === LEGACY_LOCAL_INITIALIZATION_IDENTITY
31
- && identity.machineId === LEGACY_LOCAL_INITIALIZATION_IDENTITY;
32
- }
33
- export function isLocalMemoryInitializationIdentity(actual, expected) {
34
- return Object.keys(expected)
35
- .every(key => actual[key] === expected[key]);
36
- }