@nowcrew/daemon 0.6.87-beta.4 → 0.6.87-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/execution-runner.js +6 -3
- package/dist/local-execution-prompt.js +19 -25
- package/dist/local-executor.js +10 -42
- package/dist/local-memory/prompt.js +37 -0
- package/dist/local-memory/read-cli.js +232 -0
- package/dist/local-memory-diagnostics.js +79 -12
- package/dist/main.js +0 -0
- package/dist/prompt.js +24 -9
- package/dist/workspace.js +15 -0
- package/package.json +10 -9
- package/dist/project-skills/capability.js +0 -109
- package/dist/project-skills/controller-convergence.js +0 -57
- package/dist/project-skills/projection-set-switch.js +0 -419
- package/dist/project-skills/projection-state-domain.js +0 -170
- package/dist/project-skills/projection-state-store.js +0 -842
- package/dist/project-skills/projection-state-transaction.js +0 -322
- package/dist/project-skills/projection-state.js +0 -3
- package/dist/project-skills/runtime-root-bootstrap.js +0 -47
- package/dist/project-skills/runtime-root-domain.js +0 -268
- package/dist/project-skills/runtime-root-gc.js +0 -293
- package/dist/project-skills/runtime-root-lease-artifact.js +0 -46
- package/dist/project-skills/runtime-root-leases.js +0 -487
- package/dist/project-skills/runtime-root-source-identity.js +0 -60
- package/dist/project-skills/runtime-root-startup.js +0 -49
- package/dist/project-skills/runtime-root-state-artifact-domain.js +0 -143
- package/dist/project-skills/runtime-root-state-index.js +0 -356
- package/dist/project-skills/runtime-root-store.js +0 -722
- package/dist/project-skills/serve-capability.js +0 -28
- package/dist/project-skills/serve-startup.js +0 -37
package/dist/prompt.js
CHANGED
|
@@ -67,10 +67,23 @@ export function capWorkLogForInject(workLog, cap = WORKLOG_INJECT_CAP) {
|
|
|
67
67
|
const tail = workLog.slice(-WORKLOG_TAIL);
|
|
68
68
|
return `${head}\n…(work-log 过长已截去中段,全文用 Read 读 $CREW_TASK_LOG)\n${tail}`;
|
|
69
69
|
}
|
|
70
|
-
export function capMemoryForInject(memory, cap = MEMORY_INJECT_CAP) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
export function capMemoryForInject(memory, cap = MEMORY_INJECT_CAP, maxBytes = Number.POSITIVE_INFINITY) {
|
|
71
|
+
if (memory.length <= cap && Buffer.byteLength(memory, "utf8") <= maxBytes)
|
|
72
|
+
return memory;
|
|
73
|
+
const notice = "[MEMORY.md preview truncated; use crew-memory search/read for more.]\n";
|
|
74
|
+
const noticeBytes = Buffer.byteLength(notice, "utf8");
|
|
75
|
+
if (notice.length > cap || noticeBytes > maxBytes)
|
|
76
|
+
return "";
|
|
77
|
+
let end = 0;
|
|
78
|
+
let bytes = noticeBytes;
|
|
79
|
+
for (const character of memory) {
|
|
80
|
+
const size = Buffer.byteLength(character, "utf8");
|
|
81
|
+
if (notice.length + end + character.length > cap || bytes + size > maxBytes)
|
|
82
|
+
break;
|
|
83
|
+
end += character.length;
|
|
84
|
+
bytes += size;
|
|
85
|
+
}
|
|
86
|
+
return notice + memory.slice(0, end);
|
|
74
87
|
}
|
|
75
88
|
export function buildSystemPrompt(ctx) {
|
|
76
89
|
const product = ctx.productName ?? "nowwork";
|
|
@@ -99,7 +112,7 @@ export function buildSystemPrompt(ctx) {
|
|
|
99
112
|
// scheduled 换成静默版,不出现任何"先确认/先回复"的措辞。
|
|
100
113
|
const startupSequence = alwaysReport
|
|
101
114
|
? `## 启动序列(每轮汇报定时任务)
|
|
102
|
-
1.
|
|
115
|
+
1. 参考本提示词中的 MEMORY.md 预览;需要历史约束或经验时检索完整索引,再按索引中的 file 从 $CREW_HOME 读取明细。
|
|
103
116
|
2. 执行唤醒提示词里给出的定时指令。
|
|
104
117
|
3. Return exactly one self-contained final report as your runtime final response.
|
|
105
118
|
4. Do not call crew message send; the daemon delivers the final response.
|
|
@@ -107,14 +120,14 @@ export function buildSystemPrompt(ctx) {
|
|
|
107
120
|
6. 只有存在需要后续跟进的具体事项时,才用 \`crew task create\` 创建任务。`
|
|
108
121
|
: scheduled
|
|
109
122
|
? `## 启动序列(静默定时任务)
|
|
110
|
-
1.
|
|
123
|
+
1. 参考本提示词中的 MEMORY.md 预览;需要历史约束或经验时检索完整索引,再按索引中的 file 从 $CREW_HOME 读取明细。
|
|
111
124
|
2. 执行唤醒提示词里给出的定时指令。**默认零输出**:不判断"是否需要先确认/声明接手",本轮没有人在等你回复。
|
|
112
125
|
3. 只有发现异常、需要人处理、或指令明确要求汇报时,才用 \`crew message send --send-draft\` 输出到频道(用法见上面"通信"一节)。
|
|
113
126
|
4. 只有存在需要后续跟进的具体事项时,才用 \`crew task create\` 创建任务。
|
|
114
127
|
5. 无异常时直接结束,不需要任何输出,不必读频道历史(除非指令要求)。`
|
|
115
128
|
: `## 启动序列
|
|
116
129
|
1. 若本轮来信可以直接回答,不要先发确认消息;处理完后只发一条完整回复。只有需要澄清、调用工具、协调他人或较长时间处理时,才先发有信息量的确认/进度消息。
|
|
117
|
-
2.
|
|
130
|
+
2. 参考本提示词中的 MEMORY.md 预览;需要历史约束或经验时检索完整索引,再按索引中的 file 从 $CREW_HOME 读取明细。
|
|
118
131
|
3. 若本轮只有"有未读"的 inbox notice、没有正文:notice 表示存在你尚未看到的消息(正文被暂时省略以免刷屏,不是没有内容)。是否读、何时读由你判断,可用 \`crew message check\` / \`crew message read\` 拉取。**绝不能仅凭一条 content-free notice 就断定"没有工作"**;若选择暂不读,要诚实当作 defer。
|
|
119
132
|
4. 收到消息就处理,并用 \`crew message send\` 回复。
|
|
120
133
|
5. **做完你负责的所有事再停。** 多步任务(调研/改码/测试)要全部完成、汇报结果后再停。新消息会在你存活期间自动送达,无需轮询等待。`;
|
|
@@ -329,13 +342,15 @@ ${interactiveTaskRules}${freshnessRule}${externalReplyRule}${collaborationEtique
|
|
|
329
342
|
|
|
330
343
|
## Workspace 与分层记忆(CRITICAL — 索引+按需,配合上面的并行规则)
|
|
331
344
|
你的持久记忆在 \`$CREW_HOME\`(跨你所有任务共享),按“常驻索引 + 功能明细 + 当前工作”分层:
|
|
332
|
-
1. **MEMORY.md = 常驻索引 +
|
|
345
|
+
1. **MEMORY.md = 常驻索引 + 角色**:提示词末尾可能只有它的有界预览,预算不足时也可能省略。预览未命中不等于没有记忆。索引条目包含 \`file/type/scope/summary/triggers/priority/updated\`,其中 file 是相对于 \`$CREW_HOME\` 的路径(例如 \`notes/testing.md\`);需要历史约束、经验或偏好时先检索完整索引,再按需分段读取。
|
|
333
346
|
2. **notes/<topic>.md = 功能明细**:按用户偏好、项目规则、测试、调试、Git、事故复盘等主题拆分。优先读取与当前任务匹配的文件;\`notes/lessons.md\` 只保留未分类经验和历史兼容内容,不是所有新经验的默认目的地。普通任务默认只读不写,但当前用户明确要求时可以按最小范围更新;任务结束后的专门收尾执行仍按收尾指令复核。
|
|
334
347
|
- 对旧版 MEMORY.md,如果条目没有完整结构化字段但明确指向 \`notes/<file>.md\`,把它视为 legacy 索引;仍需结合条目标题/链接和当前请求判断相关性,不要因为缺少 summary/triggers 就假定正文已注入。
|
|
335
348
|
3. **本任务 work-log = \`$CREW_TASK_LOG\`**:每任务一份(别的运行不会碰),记当前阶段/下一步/卡点/关键结论。系统已把它的当前内容注入末尾让你续上;有进展就更新它——这是你**唯一**该在任务中持续写的记忆文件。**work-log 是现状快照,不是流水账**:保持 ≤100 行,更新时重写全文替换过时内容,不要无限追加(过长会被注入截断)。
|
|
336
349
|
|
|
337
350
|
**按需读取规则(提示词引导,不是 Daemon 自动召回保证)**:
|
|
338
|
-
-
|
|
351
|
+
- 需要历史约束、经验或偏好时,在最终回答或执行动作前先用只读命令 \`crew-memory search --query '关键词' [--after-line N]\` 搜索完整 \`$CREW_HOME/MEMORY.md\`;默认返回 JSON,有后续结果时按返回游标继续,不要把预览中未命中当成全文无结果。
|
|
352
|
+
- 用 \`crew-memory read [--file MEMORY.md|notes/xxx.md] [--offset N] [--limit N]\` 读取命中范围,再按索引中的 file 从 $CREW_HOME 读取明细;默认返回 JSON。以当前有效索引及其指向的正文为依据,不自动读取 pending,也不把未决或已替代片段当成有效记忆。
|
|
353
|
+
- 旧 daemon 没有 \`crew-memory\` 时,回退到 runtime 原生文件搜索和分段 Read:先搜索完整 \`$CREW_HOME/MEMORY.md\`,再用 \`Read $CREW_HOME/<file>\` 读取命中范围;不要再次拼接 \`notes/\`。工具提示截断或返回下一页时继续分页,不要一次读取整份大文件。
|
|
339
354
|
- 未命中时不要为了“保险”读取全部 notes;只读取能直接影响当前任务的文件。MEMORY.md 注入的是索引,不会自动让 note 正文可用。
|
|
340
355
|
|
|
341
356
|
**沉淀与瘦身由系统触发,不要平时自行扩展范围**:任务被改为 done/closed 时,系统会单独唤醒你收尾——那时按功能分类把可复用经验提炼进合适的 \`notes/<topic>.md\`,更新 MEMORY.md 索引。普通执行已经按用户明确要求写入时,收尾先检查、后修改,只在明确缺漏时做最小必要修正,不得重复追加或只为优化措辞而改写。最终结论必须且只能归类为:无变化、已修正、冲突、失败;无变化或已修正时必须满足对应后置条件并清空 work-log,冲突或失败时保留 work-log,任一记忆写入失败则保留 work-log。不要默认全部写入 \`notes/lessons.md\`。默认不要改 MEMORY.md/notes,但不能覆盖当前用户明确授权的最小范围更新。
|
package/dist/workspace.js
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
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
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
15
|
+
import { createRequire } from "node:module";
|
|
14
16
|
import { dslog } from "./slog.js";
|
|
15
17
|
/** 文件系统安全的 taskKey:仅留 [\w.-],其余转 _,截断,避免路径穿越/超长。 */
|
|
16
18
|
export function safeKey(key) {
|
|
@@ -96,6 +98,19 @@ export async function prepareWorkspace(input) {
|
|
|
96
98
|
await chmod(wrapper, 0o755);
|
|
97
99
|
// win32 侧 wrapper:cmd/PowerShell 不认 shebang 脚本,并存 crew.cmd(unix 下无害不会被命中)
|
|
98
100
|
await writeFile(join(crewDir, "crew.cmd"), `@echo off\r\nnode ${JSON.stringify(input.cliPath)} %*\r\n`, "utf8");
|
|
101
|
+
if (!input.skipLocalMemory) {
|
|
102
|
+
const sourceMode = import.meta.url.endsWith(".ts");
|
|
103
|
+
const reader = fileURLToPath(new URL(`./local-memory/read-cli.${sourceMode ? "ts" : "js"}`, import.meta.url));
|
|
104
|
+
const readerArgs = sourceMode
|
|
105
|
+
? ["--import", pathToFileURL(createRequire(import.meta.url).resolve("tsx/esm")).href, reader]
|
|
106
|
+
: [reader];
|
|
107
|
+
const readerWrapper = join(crewDir, "crew-memory");
|
|
108
|
+
const posixArgs = readerArgs.map((arg) => `'${arg.replace(/'/gu, "'\\''")}'`).join(" ");
|
|
109
|
+
const windowsArgs = readerArgs.map((arg) => `"${arg.replace(/%/gu, "%%")}"`).join(" ");
|
|
110
|
+
await writeFile(readerWrapper, `#!/bin/sh\nexec node ${posixArgs} "$@"\n`, "utf8");
|
|
111
|
+
await chmod(readerWrapper, 0o755);
|
|
112
|
+
await writeFile(join(crewDir, "crew-memory.cmd"), `@echo off\r\nnode ${windowsArgs} %*\r\n`, "utf8");
|
|
113
|
+
}
|
|
99
114
|
// 每个 agent 独立的 XDG 配置根:隔离第三方 CLI 凭证,避免 agent 之间互相串号
|
|
100
115
|
const homeDir = join(dir, ".home");
|
|
101
116
|
await mkdir(join(homeDir, ".config"), { recursive: true });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nowcrew/daemon",
|
|
3
|
-
"version": "0.6.87-beta.
|
|
3
|
+
"version": "0.6.87-beta.5",
|
|
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",
|
|
@@ -36,12 +44,5 @@
|
|
|
36
44
|
"tsx": "^4.19.0",
|
|
37
45
|
"typescript": "^5.6.0",
|
|
38
46
|
"vitest": "^2.1.0"
|
|
39
|
-
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"daemon": "pnpm --filter @nowcrew/cli build && tsx src/main.ts",
|
|
42
|
-
"build": "tsc -p tsconfig.json",
|
|
43
|
-
"codex-home:migrate": "tsx src/runtimes/codex-home-migration-cli.ts",
|
|
44
|
-
"test": "vitest run",
|
|
45
|
-
"typecheck": "tsc --noEmit"
|
|
46
47
|
}
|
|
47
|
-
}
|
|
48
|
+
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { PROJECT_SKILLS_CAPABILITY, PROJECT_SKILL_PROJECTION_V2_CAPABILITY, } from "./types.js";
|
|
2
|
-
export function projectSkillV2RolloutReady(platform, readiness) {
|
|
3
|
-
const platformReady = platform === "darwin"
|
|
4
|
-
|| platform === "linux"
|
|
5
|
-
|| (platform === "win32" && readiness.nativeWindowsSmokePassed);
|
|
6
|
-
return platformReady
|
|
7
|
-
&& readiness.runtimeRootStorePrimitiveReady
|
|
8
|
-
&& readiness.runtimeRootStoreRecoveryReady
|
|
9
|
-
&& readiness.leaseRecoveryReady
|
|
10
|
-
&& readiness.controllerReady
|
|
11
|
-
&& readiness.executionHandlerReady
|
|
12
|
-
&& readiness.codexAdapterReady
|
|
13
|
-
&& readiness.claudeAdapterReady;
|
|
14
|
-
}
|
|
15
|
-
export function effectiveProjectSkillCapabilities(capabilities, projectSkillsReady, projectSkillV2Ready) {
|
|
16
|
-
const projectSkillCapabilitiesReady = projectSkillsReady && projectSkillV2Ready;
|
|
17
|
-
if (!projectSkillCapabilitiesReady
|
|
18
|
-
&& !capabilities.includes(PROJECT_SKILLS_CAPABILITY)
|
|
19
|
-
&& !capabilities.includes(PROJECT_SKILL_PROJECTION_V2_CAPABILITY)
|
|
20
|
-
&& Object.isFrozen(capabilities))
|
|
21
|
-
return capabilities;
|
|
22
|
-
const filtered = capabilities.filter((capability) => capability !== PROJECT_SKILL_PROJECTION_V2_CAPABILITY
|
|
23
|
-
&& (projectSkillCapabilitiesReady || capability !== PROJECT_SKILLS_CAPABILITY));
|
|
24
|
-
if (!projectSkillCapabilitiesReady || !filtered.includes(PROJECT_SKILLS_CAPABILITY)) {
|
|
25
|
-
return Object.freeze(filtered);
|
|
26
|
-
}
|
|
27
|
-
const v1Index = filtered.indexOf(PROJECT_SKILLS_CAPABILITY);
|
|
28
|
-
return Object.freeze([
|
|
29
|
-
...filtered.slice(0, v1Index + 1),
|
|
30
|
-
PROJECT_SKILL_PROJECTION_V2_CAPABILITY,
|
|
31
|
-
...filtered.slice(v1Index + 1),
|
|
32
|
-
]);
|
|
33
|
-
}
|
|
34
|
-
export function withProjectSkillCapabilityStatus(value, status) {
|
|
35
|
-
return {
|
|
36
|
-
...value,
|
|
37
|
-
projectSkillsStatus: status,
|
|
38
|
-
capabilities: status === "ready"
|
|
39
|
-
? value.capabilities
|
|
40
|
-
: effectiveProjectSkillCapabilities(value.capabilities, false, false),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
const settleReadinessGate = async (operation) => {
|
|
44
|
-
try {
|
|
45
|
-
return await operation() === true;
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
export async function createProjectSkillConnectionCapabilitySnapshot(input) {
|
|
52
|
-
const runtimeRootStorePrimitiveReady = await settleReadinessGate(input.probeRuntimeRootStorePrimitive);
|
|
53
|
-
const controllerReady = await settleReadinessGate(input.initializeController);
|
|
54
|
-
const recoveryReady = await settleReadinessGate(input.recoverRuntimeRootsAndLeases);
|
|
55
|
-
const readiness = Object.freeze({
|
|
56
|
-
runtimeRootStorePrimitiveReady,
|
|
57
|
-
runtimeRootStoreRecoveryReady: recoveryReady,
|
|
58
|
-
leaseRecoveryReady: recoveryReady,
|
|
59
|
-
controllerReady,
|
|
60
|
-
executionHandlerReady: true,
|
|
61
|
-
codexAdapterReady: true,
|
|
62
|
-
claudeAdapterReady: true,
|
|
63
|
-
nativeWindowsSmokePassed: false,
|
|
64
|
-
});
|
|
65
|
-
const projectSkillsReady = projectSkillV2RolloutReady(input.platform, readiness);
|
|
66
|
-
return Object.freeze({
|
|
67
|
-
capabilities: effectiveProjectSkillCapabilities(input.baseCapabilities, projectSkillsReady, projectSkillsReady),
|
|
68
|
-
projectSkillsReady,
|
|
69
|
-
readiness,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
export async function prepareProjectSkillConnectionCapabilities(input) {
|
|
73
|
-
const snapshot = await createProjectSkillConnectionCapabilitySnapshot({
|
|
74
|
-
...input,
|
|
75
|
-
baseCapabilities: [...input.baseCapabilities, ...await input.additionalCapabilities()],
|
|
76
|
-
});
|
|
77
|
-
input.applyReadiness(snapshot.projectSkillsReady);
|
|
78
|
-
return snapshot.capabilities;
|
|
79
|
-
}
|
|
80
|
-
export function createProjectSkillControllerReadiness(input) {
|
|
81
|
-
let status = "initializing";
|
|
82
|
-
let initialization = null;
|
|
83
|
-
const ensure = () => {
|
|
84
|
-
if (status === "ready")
|
|
85
|
-
return Promise.resolve(true);
|
|
86
|
-
if (initialization !== null)
|
|
87
|
-
return initialization;
|
|
88
|
-
status = "initializing";
|
|
89
|
-
const attempt = input.initialize().then(() => {
|
|
90
|
-
status = "ready";
|
|
91
|
-
return true;
|
|
92
|
-
}, (error) => {
|
|
93
|
-
status = "unavailable";
|
|
94
|
-
input.onUnavailable(error);
|
|
95
|
-
return false;
|
|
96
|
-
}).finally(() => {
|
|
97
|
-
if (initialization === attempt)
|
|
98
|
-
initialization = null;
|
|
99
|
-
input.onSettled();
|
|
100
|
-
});
|
|
101
|
-
initialization = attempt;
|
|
102
|
-
return attempt;
|
|
103
|
-
};
|
|
104
|
-
return Object.freeze({
|
|
105
|
-
status: () => status,
|
|
106
|
-
ensure,
|
|
107
|
-
applyPreflight: (ready) => { status = ready ? "ready" : "unavailable"; },
|
|
108
|
-
});
|
|
109
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { ProjectProjectionError, } from "./reconciler.js";
|
|
2
|
-
export const MAX_REMEMBERED_PROJECT_SKILL_AGENTS = 64;
|
|
3
|
-
const compareBinary = (left, right) => {
|
|
4
|
-
if (left < right)
|
|
5
|
-
return -1;
|
|
6
|
-
if (left > right)
|
|
7
|
-
return 1;
|
|
8
|
-
return 0;
|
|
9
|
-
};
|
|
10
|
-
const copySnapshot = (snapshot) => Object.freeze({
|
|
11
|
-
bindings: Object.freeze(snapshot.bindings.map((binding) => Object.freeze({ ...binding }))),
|
|
12
|
-
generation: snapshot.generation,
|
|
13
|
-
});
|
|
14
|
-
export function createProjectSkillSnapshotEpoch(maxEntries = MAX_REMEMBERED_PROJECT_SKILL_AGENTS) {
|
|
15
|
-
if (!Number.isSafeInteger(maxEntries) || maxEntries < 1) {
|
|
16
|
-
throw new ProjectProjectionError("skill_projection_failed");
|
|
17
|
-
}
|
|
18
|
-
const snapshots = new Map();
|
|
19
|
-
return Object.freeze({
|
|
20
|
-
begin() {
|
|
21
|
-
snapshots.clear();
|
|
22
|
-
},
|
|
23
|
-
remember(handle, snapshot) {
|
|
24
|
-
const previous = snapshots.get(handle);
|
|
25
|
-
if (previous !== undefined && snapshot.generation < previous.generation)
|
|
26
|
-
return;
|
|
27
|
-
if (previous === undefined && snapshots.size >= maxEntries) {
|
|
28
|
-
throw new ProjectProjectionError("skill_projection_failed");
|
|
29
|
-
}
|
|
30
|
-
snapshots.set(handle, copySnapshot(snapshot));
|
|
31
|
-
},
|
|
32
|
-
forget(handle) {
|
|
33
|
-
snapshots.delete(handle);
|
|
34
|
-
},
|
|
35
|
-
entries() {
|
|
36
|
-
return Object.freeze([...snapshots.entries()]
|
|
37
|
-
.sort(([left], [right]) => compareBinary(left, right))
|
|
38
|
-
.map(([handle, snapshot]) => Object.freeze([handle, copySnapshot(snapshot)])));
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
const stableErrorCode = (reason) => reason?.code === "skill_projection_snapshot_corrupt"
|
|
43
|
-
? "skill_projection_snapshot_corrupt"
|
|
44
|
-
: "skill_projection_failed";
|
|
45
|
-
export function toPathPrivateConvergenceResults(entries, results) {
|
|
46
|
-
return Object.freeze(entries.map(([handle], index) => {
|
|
47
|
-
const result = results[index];
|
|
48
|
-
if (result?.status === "fulfilled") {
|
|
49
|
-
return Object.freeze({ handle, status: "fulfilled" });
|
|
50
|
-
}
|
|
51
|
-
return Object.freeze({
|
|
52
|
-
handle,
|
|
53
|
-
status: "rejected",
|
|
54
|
-
errorCode: stableErrorCode(result?.reason),
|
|
55
|
-
});
|
|
56
|
-
}));
|
|
57
|
-
}
|