@veewo/claw-core 0.2.3 → 0.2.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/dist/src/io.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export declare function readJsonFile<T>(filePath: string): T;
2
2
  export declare function writeJsonFile(filePath: string, value: unknown): void;
3
+ export declare function serializeJsonFile(value: unknown): string;
4
+ export declare function writeJsonFileAtomic(filePath: string, value: unknown): void;
3
5
  export declare function readTextFile(filePath: string): string;
4
6
  export declare function writeTextFile(filePath: string, content: string): void;
5
7
  export declare function stripBom(content: string): string;
@@ -8,3 +10,7 @@ export declare function withSerializedAccess<T>(targetPath: string, action: () =
8
10
  pollMs?: number;
9
11
  timeoutMs?: number;
10
12
  }): Promise<T>;
13
+ export declare function withSerializedQueue<T>(queuePath: string, action: () => Promise<T>, options?: {
14
+ pollMs?: number;
15
+ timeoutMs?: number;
16
+ }): Promise<T>;
package/dist/src/io.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
+ import { randomUUID } from "node:crypto";
3
4
  import { setTimeout as delay } from "node:timers/promises";
4
5
  import { ClawError } from "./errors.js";
5
6
  export function readJsonFile(filePath) {
@@ -9,6 +10,30 @@ export function writeJsonFile(filePath, value) {
9
10
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
10
11
  fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
11
12
  }
13
+ export function serializeJsonFile(value) {
14
+ return `${JSON.stringify(value, null, 2)}\n`;
15
+ }
16
+ export function writeJsonFileAtomic(filePath, value) {
17
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
18
+ const temporaryPath = path.join(path.dirname(filePath), `.${path.basename(filePath)}.${process.pid}.${randomUUID()}.tmp`);
19
+ let descriptor;
20
+ try {
21
+ descriptor = fs.openSync(temporaryPath, "wx");
22
+ fs.writeFileSync(descriptor, serializeJsonFile(value), "utf-8");
23
+ fs.fsyncSync(descriptor);
24
+ fs.closeSync(descriptor);
25
+ descriptor = undefined;
26
+ fs.renameSync(temporaryPath, filePath);
27
+ }
28
+ finally {
29
+ if (descriptor !== undefined) {
30
+ fs.closeSync(descriptor);
31
+ }
32
+ if (fs.existsSync(temporaryPath)) {
33
+ fs.unlinkSync(temporaryPath);
34
+ }
35
+ }
36
+ }
12
37
  export function readTextFile(filePath) {
13
38
  return stripBom(fs.readFileSync(filePath, "utf-8"));
14
39
  }
@@ -67,38 +92,21 @@ async function withFileLockRetry(targetPath, action, options) {
67
92
  }
68
93
  }
69
94
  }
70
- function readSerializedAccessState(queuePath) {
71
- if (!fs.existsSync(queuePath)) {
72
- return { nextTicket: 1, serving: 1 };
73
- }
74
- return JSON.parse(stripBom(fs.readFileSync(queuePath, "utf-8")));
75
- }
76
- function writeSerializedAccessState(queuePath, state) {
77
- fs.mkdirSync(path.dirname(queuePath), { recursive: true });
78
- fs.writeFileSync(queuePath, `${JSON.stringify(state, null, 2)}\n`, "utf-8");
79
- }
80
95
  export async function withSerializedAccess(targetPath, action, options) {
81
- const queuePath = `${targetPath}.queue.json`;
96
+ return withSerializedQueue(`${targetPath}.queue.json`, action, options);
97
+ }
98
+ export async function withSerializedQueue(queuePath, action, options) {
82
99
  const pollMs = Math.max(10, options?.pollMs ?? 25);
83
100
  const timeoutMs = Math.max(pollMs, options?.timeoutMs ?? 30000);
84
- const ticket = await withFileLockRetry(queuePath, () => {
85
- const state = readSerializedAccessState(queuePath);
86
- const assignedTicket = state.nextTicket;
87
- state.nextTicket += 1;
88
- writeSerializedAccessState(queuePath, state);
89
- return assignedTicket;
90
- }, { pollMs, timeoutMs });
101
+ const token = randomUUID();
91
102
  const deadline = Date.now() + timeoutMs;
92
103
  while (true) {
93
- const state = readSerializedAccessState(queuePath);
94
- if (state.serving === ticket) {
104
+ if (tryAcquireSerializedQueue(queuePath, token)) {
95
105
  break;
96
106
  }
97
107
  if (Date.now() >= deadline) {
98
- throw new ClawError("PLAN_WRITE_CONFLICT", `Timed out waiting to serialize access for "${targetPath}".`, {
99
- targetPath,
108
+ throw new ClawError("PLAN_WRITE_CONFLICT", `Timed out waiting to serialize access for queue "${queuePath}".`, {
100
109
  queuePath,
101
- ticket,
102
110
  timeoutMs,
103
111
  });
104
112
  }
@@ -108,17 +116,109 @@ export async function withSerializedAccess(targetPath, action, options) {
108
116
  return await action();
109
117
  }
110
118
  finally {
111
- await withFileLockRetry(queuePath, () => {
112
- const state = readSerializedAccessState(queuePath);
113
- state.serving = Math.max(state.serving, ticket + 1);
114
- if (state.serving >= state.nextTicket) {
115
- if (fs.existsSync(queuePath)) {
116
- fs.unlinkSync(queuePath);
117
- }
118
- return;
119
+ releaseSerializedQueue(queuePath, token);
120
+ }
121
+ }
122
+ function tryAcquireSerializedQueue(queuePath, token) {
123
+ fs.mkdirSync(path.dirname(queuePath), { recursive: true });
124
+ let descriptor;
125
+ try {
126
+ descriptor = fs.openSync(queuePath, "wx");
127
+ const owner = {
128
+ schemaVersion: 1,
129
+ token,
130
+ pid: process.pid,
131
+ acquiredAt: new Date().toISOString(),
132
+ };
133
+ fs.writeFileSync(descriptor, serializeJsonFile(owner), "utf-8");
134
+ fs.fsyncSync(descriptor);
135
+ fs.closeSync(descriptor);
136
+ descriptor = undefined;
137
+ return true;
138
+ }
139
+ catch (error) {
140
+ if (descriptor !== undefined) {
141
+ fs.closeSync(descriptor);
142
+ }
143
+ const code = error && typeof error === "object" && "code" in error
144
+ ? String(error.code)
145
+ : "";
146
+ if (code !== "EEXIST") {
147
+ throw error;
148
+ }
149
+ }
150
+ const owner = readSerializedQueueOwner(queuePath);
151
+ if (!owner) {
152
+ // Another process may still be flushing the newly-created owner record.
153
+ // Only treat an unreadable record as abandoned after a short grace period.
154
+ try {
155
+ if (Date.now() - fs.statSync(queuePath).mtimeMs < 1000) {
156
+ return false;
119
157
  }
120
- writeSerializedAccessState(queuePath, state);
121
- }, { pollMs, timeoutMs });
158
+ }
159
+ catch {
160
+ return false;
161
+ }
162
+ }
163
+ else if (isProcessAlive(owner.pid)) {
164
+ return false;
165
+ }
166
+ const stalePath = `${queuePath}.stale.${owner?.token ?? "invalid"}.${randomUUID()}`;
167
+ try {
168
+ const current = readSerializedQueueOwner(queuePath);
169
+ if (owner && current?.token !== owner.token) {
170
+ return false;
171
+ }
172
+ fs.renameSync(queuePath, stalePath);
173
+ fs.unlinkSync(stalePath);
174
+ }
175
+ catch (error) {
176
+ const code = error && typeof error === "object" && "code" in error
177
+ ? String(error.code)
178
+ : "";
179
+ if (code !== "ENOENT" && code !== "EACCES" && code !== "EPERM") {
180
+ throw error;
181
+ }
182
+ }
183
+ return false;
184
+ }
185
+ function releaseSerializedQueue(queuePath, token) {
186
+ try {
187
+ const owner = readSerializedQueueOwner(queuePath);
188
+ if (owner?.token === token) {
189
+ fs.unlinkSync(queuePath);
190
+ }
191
+ }
192
+ catch {
193
+ // A recovered or externally removed queue is already released.
194
+ }
195
+ }
196
+ function readSerializedQueueOwner(queuePath) {
197
+ try {
198
+ const owner = readJsonFile(queuePath);
199
+ return owner.schemaVersion === 1
200
+ && typeof owner.token === "string"
201
+ && typeof owner.pid === "number"
202
+ && typeof owner.acquiredAt === "string"
203
+ ? owner
204
+ : null;
205
+ }
206
+ catch {
207
+ return null;
208
+ }
209
+ }
210
+ function isProcessAlive(pid) {
211
+ if (!Number.isInteger(pid) || pid <= 0)
212
+ return false;
213
+ try {
214
+ process.kill(pid, 0);
215
+ return true;
216
+ }
217
+ catch (error) {
218
+ const code = error && typeof error === "object" && "code" in error
219
+ ? String(error.code)
220
+ : "";
221
+ return code === "EPERM";
122
222
  }
123
223
  }
124
224
  //# sourceMappingURL=io.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"io.js","sourceRoot":"","sources":["../../src/io.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"io.js","sourceRoot":"","sources":["../../src/io.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,10 @@ export declare function buildKnowledgeDelegateDispatch(input: {
22
22
  finalizeId: string;
23
23
  writer?: KnowledgeWriterConfig | null;
24
24
  }): KnowledgeDelegateDispatch;
25
+ export declare function buildKnowledgeAtomicDispatch(input: {
26
+ finalizeId: string;
27
+ writer?: KnowledgeWriterConfig | null;
28
+ }): KnowledgeDelegateDispatch;
25
29
  export declare function buildKnowledgeWriterAssignments(job: Pick<KnowledgeFinalizationJob, "finalizeId" | "planPath" | "reportPath" | "writer">): KnowledgeWriterAssignment[];
26
30
  export declare function buildKnowledgeAssignmentTemplate(input: {
27
31
  assignments: KnowledgeWriterAssignment[];
@@ -22,6 +22,26 @@ export function buildKnowledgeDelegateDispatch(input) {
22
22
  ].join("\n"),
23
23
  };
24
24
  }
25
+ export function buildKnowledgeAtomicDispatch(input) {
26
+ return {
27
+ schemaVersion: 1,
28
+ policy: "subagent",
29
+ finalizeId: input.finalizeId,
30
+ ...(input.writer?.model ? { model: input.writer.model } : {}),
31
+ ...(input.writer?.reasoningEffort ? { reasoningEffort: input.writer.reasoningEffort } : {}),
32
+ prompt: [
33
+ "Execute this already-created claw knowledge-finalization job directly and unattended.",
34
+ "Use the claw-kit Cindy Ghost tools in the project workspace; do not use the claw CLI for claim or completion.",
35
+ "Call list_tools for category knowledge, then call_tool knowledge.claim with:",
36
+ JSON.stringify({ finalizeId: input.finalizeId }),
37
+ "The claim operation atomically captures the originating Cindy task conclusions into plan.report before it issues the claim token.",
38
+ "If claimed is false, stop without editing knowledge. If claimed is true, retain claimToken and execute each returned assignment prompt yourself in ascending index order.",
39
+ "Do not create a claw plan or subplan, invoke another finalizer, or delegate to another agent.",
40
+ "After a successful claim, call_tool knowledge.done exactly once in a finally-style step with finalizeId, claimToken, status, and result or error.",
41
+ "Use status succeeded with a concise result only when every assignment succeeds; otherwise use status failed with a concise error.",
42
+ ].join("\n"),
43
+ };
44
+ }
25
45
  export function buildKnowledgeWriterAssignments(job) {
26
46
  const configured = job.writer?.externalSkills?.map((skill) => skill.trim()).filter(Boolean) ?? [];
27
47
  if (configured.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"knowledge-assignments.js","sourceRoot":"","sources":["../../src/knowledge-assignments.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"knowledge-assignments.js","sourceRoot":"","sources":["../../src/knowledge-assignments.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,8 @@ export type KnowledgeSessionRegistry = {
19
19
  sessionId: string;
20
20
  activePlanPath?: string;
21
21
  activeReportPath?: string;
22
+ activeWriter?: KnowledgeWriterConfig;
23
+ activeStartedAt?: string;
22
24
  pendingTurnOwner?: KnowledgeReportTarget;
23
25
  lastCollectedTurnId?: string;
24
26
  updatedAt: string;
@@ -38,6 +40,14 @@ export type KnowledgeFinalizationJob = {
38
40
  host?: KnowledgeFinalizationHost | null;
39
41
  planPath: string;
40
42
  reportPath: string;
43
+ reportCapture?: {
44
+ mode: "claim";
45
+ status: "pending" | "captured";
46
+ startedAt?: string;
47
+ capturedAt?: string;
48
+ transcriptPath?: string;
49
+ messageCount?: number;
50
+ };
41
51
  status: "queued" | "running" | "succeeded" | "failed";
42
52
  attempts: number;
43
53
  queuedAt: string;
@@ -98,6 +108,7 @@ export type KnowledgeSidecarResult = {
98
108
  };
99
109
  export type KnowledgePlanEndResult = KnowledgeSidecarResult & {
100
110
  finalizeId?: string;
111
+ jobPath?: string;
101
112
  };
102
113
  export type KnowledgeStopResult = KnowledgeSidecarResult & {
103
114
  captured?: boolean;
@@ -124,10 +135,13 @@ export declare function deriveKnowledgeFinalizeId(input: {
124
135
  planPath: string;
125
136
  endedAt: string;
126
137
  }): string;
138
+ export declare function resolveKnowledgeWriterForHost(writer: KnowledgeWriterConfig | undefined, host?: string | null): KnowledgeWriterConfig | undefined;
127
139
  export declare function tryRegisterKnowledgePlan(input: {
128
140
  project: ProjectContext;
129
141
  sessionId?: string;
130
142
  planPath: string;
143
+ writer?: KnowledgeWriterConfig;
144
+ host?: KnowledgeFinalizationHost;
131
145
  }): KnowledgeSidecarResult;
132
146
  export declare function tryEndKnowledgePlan(input: {
133
147
  project: ProjectContext;
@@ -136,6 +150,7 @@ export declare function tryEndKnowledgePlan(input: {
136
150
  resumedPlanPath?: string;
137
151
  endedAt: string;
138
152
  writer?: KnowledgeWriterConfig;
153
+ host?: KnowledgeFinalizationHost;
139
154
  }): KnowledgePlanEndResult;
140
155
  /** @deprecated Use tryEndKnowledgePlan for lifecycle-neutral end.* finalization. */
141
156
  export declare function tryCompleteKnowledgePlan(input: {
@@ -154,7 +169,9 @@ export declare function tryCaptureKnowledgeStop(input: {
154
169
  taskConclusions?: KnowledgeTaskConclusion[];
155
170
  }): KnowledgeStopResult;
156
171
  export declare function readKnowledgeFinalizationJob(jobPath: string): KnowledgeFinalizationJob;
157
- export declare function claimKnowledgeFinalizationJob(jobPath: string): KnowledgeFinalizationJob | null;
172
+ export declare function claimKnowledgeFinalizationJob(jobPath: string, options?: {
173
+ prepare?: (job: KnowledgeFinalizationJob) => Partial<KnowledgeFinalizationJob> | void;
174
+ }): KnowledgeFinalizationJob | null;
158
175
  export declare function doneKnowledgeFinalizationJob(input: {
159
176
  jobPath: string;
160
177
  claimToken: string;
@@ -167,7 +184,14 @@ export declare function doneKnowledgeFinalizationJob(input: {
167
184
  job: KnowledgeFinalizationJob;
168
185
  alreadyDone: boolean;
169
186
  };
170
- export declare function listRetryableKnowledgeFinalizationJobs(project: ProjectContext): string[];
187
+ export declare function listRetryableKnowledgeFinalizationJobs(project: ProjectContext, options?: {
188
+ excludeHosts?: KnowledgeFinalizationHost[];
189
+ }): string[];
190
+ export declare function appendKnowledgeTaskConclusions(reportPath: string, sessionId: string, conclusions: KnowledgeTaskConclusion[], capturedAt?: string): {
191
+ written: number;
192
+ duplicates: number;
193
+ };
194
+ export declare function listKnowledgeFinalizationJobs(project: ProjectContext): string[];
171
195
  /** Remove obsolete legacy runtime records left by releases before task-local jobs. */
172
196
  export declare function pruneLegacyKnowledgeRuntime(project: ProjectContext): {
173
197
  jobsRemoved: number;
@@ -57,20 +57,39 @@ export function deriveKnowledgeFinalizeId(input) {
57
57
  .update(`${input.sessionId}\n${input.planPath}\n${input.endedAt}`)
58
58
  .digest("hex");
59
59
  }
60
+ export function resolveKnowledgeWriterForHost(writer, host) {
61
+ if (host !== "cindy") {
62
+ return writer;
63
+ }
64
+ return {
65
+ ...(writer ?? {}),
66
+ executionPolicy: "subagent",
67
+ };
68
+ }
60
69
  export function tryRegisterKnowledgePlan(input) {
61
70
  const sessionId = input.sessionId?.trim();
62
71
  if (!sessionId) {
63
72
  return { ok: true };
64
73
  }
65
74
  try {
75
+ const writer = resolveKnowledgeWriterForHost(input.writer, input.host);
66
76
  const planPath = toProjectRelativePlanPath(input.project, input.planPath);
67
77
  const reportPath = toProjectRelativeReportPath(input.project, deriveKnowledgeReportPath(input.planPath));
68
- updateKnowledgeRegistry(input.project, sessionId, (registry) => ({
69
- ...registry,
70
- activePlanPath: planPath,
71
- activeReportPath: reportPath,
72
- updatedAt: new Date().toISOString(),
73
- }));
78
+ updateKnowledgeRegistry(input.project, sessionId, (registry) => {
79
+ const samePlan = registry.activePlanPath === planPath;
80
+ const continuingSubagentCapture = writer?.executionPolicy === "subagent"
81
+ && registry.activeWriter?.executionPolicy === "subagent";
82
+ return {
83
+ ...registry,
84
+ activePlanPath: planPath,
85
+ activeReportPath: reportPath,
86
+ ...(writer ? { activeWriter: writer } : {}),
87
+ activeStartedAt: (samePlan || continuingSubagentCapture) && registry.activeStartedAt
88
+ ? registry.activeStartedAt
89
+ : new Date().toISOString(),
90
+ updatedAt: new Date().toISOString(),
91
+ };
92
+ });
74
93
  return { ok: true };
75
94
  }
76
95
  catch (error) {
@@ -83,6 +102,7 @@ export function tryEndKnowledgePlan(input) {
83
102
  return { ok: true };
84
103
  }
85
104
  try {
105
+ const writer = resolveKnowledgeWriterForHost(input.writer, input.host);
86
106
  const endedPlanPath = toProjectRelativePlanPath(input.project, input.endedPlanPath);
87
107
  const reportPath = toProjectRelativeReportPath(input.project, deriveKnowledgeReportPath(input.endedPlanPath));
88
108
  const resumedPlanPath = input.resumedPlanPath
@@ -96,21 +116,69 @@ export function tryEndKnowledgePlan(input) {
96
116
  planPath: endedPlanPath,
97
117
  endedAt: input.endedAt,
98
118
  });
99
- updateKnowledgeRegistry(input.project, sessionId, (registry) => ({
100
- ...registry,
101
- ...(resumedPlanPath
102
- ? { activePlanPath: resumedPlanPath, activeReportPath: resumedReportPath }
103
- : { activePlanPath: undefined, activeReportPath: undefined }),
104
- pendingTurnOwner: {
105
- planPath: endedPlanPath,
106
- reportPath,
107
- finalizeId,
108
- ...(input.writer ? { writer: input.writer } : {}),
109
- endedAt: input.endedAt,
110
- },
111
- updatedAt: new Date().toISOString(),
112
- }));
113
- return { ok: true, finalizeId };
119
+ let jobPath;
120
+ updateKnowledgeRegistry(input.project, sessionId, (registry) => {
121
+ const common = {
122
+ ...registry,
123
+ ...(resumedPlanPath
124
+ ? {
125
+ activePlanPath: resumedPlanPath,
126
+ activeReportPath: resumedReportPath,
127
+ activeWriter: writer,
128
+ activeStartedAt: registry.activeStartedAt,
129
+ }
130
+ : { activePlanPath: undefined, activeReportPath: undefined, activeWriter: undefined, activeStartedAt: undefined }),
131
+ updatedAt: new Date().toISOString(),
132
+ };
133
+ if (writer?.executionPolicy !== "subagent") {
134
+ return {
135
+ ...common,
136
+ pendingTurnOwner: {
137
+ planPath: endedPlanPath,
138
+ reportPath,
139
+ finalizeId,
140
+ ...(writer ? { writer } : {}),
141
+ endedAt: input.endedAt,
142
+ },
143
+ };
144
+ }
145
+ const subagentCommon = {
146
+ ...common,
147
+ pendingTurnOwner: undefined,
148
+ };
149
+ if (resumedPlanPath) {
150
+ return subagentCommon;
151
+ }
152
+ const absolutePlanPath = resolveProjectRelativePlanPath(input.project, endedPlanPath);
153
+ const absoluteReportPath = resolveProjectRelativeReportPath(input.project, reportPath);
154
+ jobPath = knowledgeFinalizationJobPathForPlan(input.project, absolutePlanPath, finalizeId);
155
+ if (!fs.existsSync(jobPath)) {
156
+ writeJsonFile(jobPath, {
157
+ schemaVersion: 1,
158
+ finalizeId,
159
+ sessionId,
160
+ projectRoot: input.project.projectRoot,
161
+ taskName: taskNameFromPlanPath(endedPlanPath),
162
+ writer,
163
+ host: input.host ?? null,
164
+ planPath: absolutePlanPath,
165
+ reportPath: absoluteReportPath,
166
+ reportCapture: {
167
+ mode: "claim",
168
+ status: "pending",
169
+ ...(registry.activeStartedAt ? { startedAt: registry.activeStartedAt } : {}),
170
+ },
171
+ status: "queued",
172
+ attempts: 0,
173
+ queuedAt: new Date().toISOString(),
174
+ });
175
+ }
176
+ return subagentCommon;
177
+ });
178
+ if (writer?.executionPolicy === "subagent" && resumedPlanPath) {
179
+ return { ok: true };
180
+ }
181
+ return { ok: true, finalizeId, ...(jobPath ? { jobPath } : {}) };
114
182
  }
115
183
  catch (error) {
116
184
  return { ok: false, error: errorMessage(error) };
@@ -141,26 +209,18 @@ export function tryCaptureKnowledgeStop(input) {
141
209
  return withFileLock(registryPath, () => {
142
210
  const registry = readKnowledgeRegistry(registryPath, sessionId);
143
211
  const target = registry.pendingTurnOwner ?? (registry.activePlanPath && registry.activeReportPath
144
- ? { planPath: registry.activePlanPath, reportPath: registry.activeReportPath }
212
+ ? { planPath: registry.activePlanPath, reportPath: registry.activeReportPath, writer: registry.activeWriter }
145
213
  : undefined);
146
214
  if (!target) {
147
215
  return { ok: true, captured: false };
148
216
  }
217
+ if (target.writer?.executionPolicy === "subagent"
218
+ || (!target.writer && input.project.projectConfig?.knowledgeWriter?.executionPolicy === "subagent")) {
219
+ return { ok: true, captured: false };
220
+ }
149
221
  const reportPath = resolveProjectRelativeReportPath(input.project, target.reportPath);
150
222
  const capturedAt = new Date().toISOString();
151
- for (const conclusion of input.taskConclusions ?? []) {
152
- if (conclusion.turnId !== turnId) {
153
- continue;
154
- }
155
- appendKnowledgeReportEntry(reportPath, {
156
- schemaVersion: 1,
157
- entryType: "task_conclusion",
158
- sessionId,
159
- turnId: conclusion.turnId,
160
- capturedAt,
161
- message: conclusion.message,
162
- });
163
- }
223
+ appendKnowledgeTaskConclusions(reportPath, sessionId, (input.taskConclusions ?? []).filter((conclusion) => conclusion.turnId === turnId), capturedAt);
164
224
  const duplicate = appendKnowledgeReportEntry(reportPath, {
165
225
  schemaVersion: 1,
166
226
  sessionId,
@@ -238,15 +298,17 @@ export function tryCaptureKnowledgeStop(input) {
238
298
  export function readKnowledgeFinalizationJob(jobPath) {
239
299
  return readJsonFile(jobPath);
240
300
  }
241
- export function claimKnowledgeFinalizationJob(jobPath) {
301
+ export function claimKnowledgeFinalizationJob(jobPath, options) {
242
302
  return withFileLock(jobPath, () => {
243
303
  const current = readJsonFile(jobPath);
244
304
  if (current.status === "succeeded" || current.status === "running" || current.attempts >= 3) {
245
305
  return null;
246
306
  }
247
307
  const now = new Date().toISOString();
308
+ const prepared = options?.prepare?.(structuredClone(current));
248
309
  const running = {
249
310
  ...current,
311
+ ...(prepared ?? {}),
250
312
  status: "running",
251
313
  attempts: current.attempts + 1,
252
314
  startedAt: now,
@@ -292,24 +354,49 @@ export function doneKnowledgeFinalizationJob(input) {
292
354
  return { job: terminal, alreadyDone: false };
293
355
  });
294
356
  }
295
- export function listRetryableKnowledgeFinalizationJobs(project) {
296
- const taskJobs = listTaskDirectories(project)
297
- .flatMap((task) => listKnowledgeJobs(path.join(task.taskDir, ".runtime", "knowledge-finalization")));
298
- const archivedTaskJobs = listTaskDirectories({ tasksDir: path.join(project.clawDir, "archive", "tasks") })
299
- .flatMap((task) => listKnowledgeJobs(path.join(task.taskDir, ".runtime", "knowledge-finalization")));
300
- // Read legacy central jobs so an upgrade does not strand retryable work. New jobs are never written there.
301
- const legacyJobs = listKnowledgeJobs(path.join(project.clawDir, "runtime", "knowledge-finalization", "jobs"));
302
- return [...taskJobs, ...archivedTaskJobs, ...legacyJobs]
357
+ export function listRetryableKnowledgeFinalizationJobs(project, options = {}) {
358
+ const excludedHosts = new Set(options.excludeHosts ?? []);
359
+ return listKnowledgeFinalizationJobs(project)
303
360
  .filter((jobPath) => {
304
361
  try {
305
362
  const job = readKnowledgeFinalizationJob(jobPath);
306
- return (job.status === "queued" || job.status === "failed") && job.attempts < 3;
363
+ return (job.status === "queued" || job.status === "failed")
364
+ && job.attempts < 3
365
+ && !excludedHosts.has(job.host);
307
366
  }
308
367
  catch {
309
368
  return false;
310
369
  }
311
370
  });
312
371
  }
372
+ export function appendKnowledgeTaskConclusions(reportPath, sessionId, conclusions, capturedAt = new Date().toISOString()) {
373
+ let written = 0;
374
+ let duplicates = 0;
375
+ for (const conclusion of conclusions) {
376
+ const entry = {
377
+ schemaVersion: 1,
378
+ entryType: "task_conclusion",
379
+ sessionId,
380
+ turnId: conclusion.turnId,
381
+ capturedAt,
382
+ message: conclusion.message,
383
+ };
384
+ if (appendKnowledgeReportEntry(reportPath, entry))
385
+ duplicates += 1;
386
+ else
387
+ written += 1;
388
+ }
389
+ return { written, duplicates };
390
+ }
391
+ export function listKnowledgeFinalizationJobs(project) {
392
+ const taskJobs = listTaskDirectories(project)
393
+ .flatMap((task) => listKnowledgeJobs(path.join(task.taskDir, ".runtime", "knowledge-finalization")));
394
+ const archivedTaskJobs = listTaskDirectories({ tasksDir: path.join(project.clawDir, "archive", "tasks") })
395
+ .flatMap((task) => listKnowledgeJobs(path.join(task.taskDir, ".runtime", "knowledge-finalization")));
396
+ // Read legacy central jobs so an upgrade does not strand retryable work. New jobs are never written there.
397
+ const legacyJobs = listKnowledgeJobs(path.join(project.clawDir, "runtime", "knowledge-finalization", "jobs"));
398
+ return [...taskJobs, ...archivedTaskJobs, ...legacyJobs];
399
+ }
313
400
  /** Remove obsolete legacy runtime records left by releases before task-local jobs. */
314
401
  export function pruneLegacyKnowledgeRuntime(project) {
315
402
  const legacyJobsDir = path.join(project.clawDir, "runtime", "knowledge-finalization", "jobs");