@claudexor/daemon 4.3.1 → 4.5.0
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/account-evidence.d.ts +2 -0
- package/dist/account-evidence.d.ts.map +1 -1
- package/dist/account-evidence.js +2 -0
- package/dist/account-evidence.js.map +1 -1
- package/dist/command-rpc.d.ts.map +1 -1
- package/dist/command-rpc.js +6 -1
- package/dist/command-rpc.js.map +1 -1
- package/dist/continuation-admission.d.ts +1 -1
- package/dist/continuation-admission.d.ts.map +1 -1
- package/dist/continuation-admission.js +33 -2
- package/dist/continuation-admission.js.map +1 -1
- package/dist/daemon-health.d.ts +25 -0
- package/dist/daemon-health.d.ts.map +1 -1
- package/dist/daemon-health.js +2 -0
- package/dist/daemon-health.js.map +1 -1
- package/dist/delivery-command.d.ts +1 -1
- package/dist/delivery-command.d.ts.map +1 -1
- package/dist/delivery-command.js +10 -1
- package/dist/delivery-command.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/loop-facts.d.ts.map +1 -1
- package/dist/loop-facts.js +2 -0
- package/dist/loop-facts.js.map +1 -1
- package/dist/model-capability-ledger.d.ts +62 -0
- package/dist/model-capability-ledger.d.ts.map +1 -0
- package/dist/model-capability-ledger.js +279 -0
- package/dist/model-capability-ledger.js.map +1 -0
- package/dist/model-operation-execution.d.ts.map +1 -1
- package/dist/model-operation-execution.js +6 -1
- package/dist/model-operation-execution.js.map +1 -1
- package/dist/model-operations.d.ts +2 -2
- package/dist/model-operations.d.ts.map +1 -1
- package/dist/model-operations.js +7 -4
- package/dist/model-operations.js.map +1 -1
- package/dist/projects.d.ts.map +1 -1
- package/dist/projects.js +10 -1
- package/dist/projects.js.map +1 -1
- package/dist/run-file-admission.d.ts +6 -0
- package/dist/run-file-admission.d.ts.map +1 -0
- package/dist/run-file-admission.js +17 -0
- package/dist/run-file-admission.js.map +1 -0
- package/dist/store/external-files.d.ts.map +1 -1
- package/dist/store/external-files.js +30 -27
- package/dist/store/external-files.js.map +1 -1
- package/dist/store/project-router.d.ts +32 -0
- package/dist/store/project-router.d.ts.map +1 -1
- package/dist/store/project-router.js +7 -0
- package/dist/store/project-router.js.map +1 -1
- package/dist/store/publish-blob.d.ts +2 -1
- package/dist/store/publish-blob.d.ts.map +1 -1
- package/dist/store/publish-blob.js +6 -2
- package/dist/store/publish-blob.js.map +1 -1
- package/dist/store/resources.d.ts.map +1 -1
- package/dist/store/resources.js +4 -4
- package/dist/store/resources.js.map +1 -1
- package/dist/store/retention-changes.d.ts +26 -0
- package/dist/store/retention-changes.d.ts.map +1 -0
- package/dist/store/retention-changes.js +109 -0
- package/dist/store/retention-changes.js.map +1 -0
- package/dist/store/retention-command-references.d.ts +15 -0
- package/dist/store/retention-command-references.d.ts.map +1 -0
- package/dist/store/retention-command-references.js +133 -0
- package/dist/store/retention-command-references.js.map +1 -0
- package/dist/store/retention-generations.d.ts +13 -0
- package/dist/store/retention-generations.d.ts.map +1 -0
- package/dist/store/retention-generations.js +60 -0
- package/dist/store/retention-generations.js.map +1 -0
- package/dist/store/retention-pages.d.ts +6 -0
- package/dist/store/retention-pages.d.ts.map +1 -0
- package/dist/store/retention-pages.js +19 -0
- package/dist/store/retention-pages.js.map +1 -0
- package/dist/store/retention-reference-reader.d.ts +98 -0
- package/dist/store/retention-reference-reader.d.ts.map +1 -0
- package/dist/store/retention-reference-reader.js +110 -0
- package/dist/store/retention-reference-reader.js.map +1 -0
- package/dist/store/retention-references.d.ts +42 -0
- package/dist/store/retention-references.d.ts.map +1 -0
- package/dist/store/retention-references.js +138 -0
- package/dist/store/retention-references.js.map +1 -0
- package/dist/store/sql-command-router.d.ts.map +1 -1
- package/dist/store/sql-command-router.js +7 -1
- package/dist/store/sql-command-router.js.map +1 -1
- package/dist/store/sql-daemon-services.d.ts +1 -0
- package/dist/store/sql-daemon-services.d.ts.map +1 -1
- package/dist/store/store.d.ts +4 -0
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +21 -3
- package/dist/store/store.js.map +1 -1
- package/dist/store/upload-binding-retention.d.ts +1 -1
- package/dist/store/upload-binding-retention.d.ts.map +1 -1
- package/dist/store/upload-binding-retention.js +39 -5
- package/dist/store/upload-binding-retention.js.map +1 -1
- package/dist/store/uploads.d.ts +2 -1
- package/dist/store/uploads.d.ts.map +1 -1
- package/dist/store/uploads.js +4 -2
- package/dist/store/uploads.js.map +1 -1
- package/dist/store-contracts.d.ts +3 -0
- package/dist/store-contracts.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { isTerminalLifecycle, RunLifecycle, RecordedControlRunStartRequest, } from "@claudexor/schema";
|
|
2
|
+
import { readContinuationSources } from "@claudexor/workspace";
|
|
3
|
+
import { setImmediate as yieldToAdmission } from "node:timers/promises";
|
|
4
|
+
import { BlobFiles } from "./blob-files.js";
|
|
5
|
+
import { retentionPages } from "./retention-pages.js";
|
|
6
|
+
// Read the immutable request, not the public summary (which omits retry/plan
|
|
7
|
+
// sources). Historical requests need not satisfy today's full run contract.
|
|
8
|
+
const Dependencies = RecordedControlRunStartRequest.pick({
|
|
9
|
+
continueFrom: true,
|
|
10
|
+
retryOf: true,
|
|
11
|
+
planRef: true,
|
|
12
|
+
planRunId: true,
|
|
13
|
+
}).strip();
|
|
14
|
+
const COLUMNS = "id,pid,kind,run_id AS runId,run_dir AS runDir,state,finished_at AS finishedAt,continue_from,params_sha";
|
|
15
|
+
export async function commandRetentionReferences(store, retained, referencedRunIds = new Set(), signal) {
|
|
16
|
+
const blobs = new BlobFiles(store);
|
|
17
|
+
const paramsByDigest = new Map();
|
|
18
|
+
const aliases = new Map();
|
|
19
|
+
const records = [];
|
|
20
|
+
const byRun = new Map();
|
|
21
|
+
const active = new Set();
|
|
22
|
+
const nativeRunDirs = new Set();
|
|
23
|
+
const nativeWatchRunDirs = new Set();
|
|
24
|
+
const uncertainNativeOwners = new Map();
|
|
25
|
+
const add = (id) => {
|
|
26
|
+
if (!id)
|
|
27
|
+
return;
|
|
28
|
+
referencedRunIds.add(id);
|
|
29
|
+
const runId = aliases.get(id);
|
|
30
|
+
if (runId)
|
|
31
|
+
referencedRunIds.add(runId);
|
|
32
|
+
};
|
|
33
|
+
const record = (row) => {
|
|
34
|
+
if (row.runId === null)
|
|
35
|
+
return;
|
|
36
|
+
const next = { runId: row.runId, state: row.state, finishedAt: row.finishedAt ?? undefined };
|
|
37
|
+
const previous = byRun.get(row.runId);
|
|
38
|
+
if (previous)
|
|
39
|
+
Object.assign(previous, next);
|
|
40
|
+
else {
|
|
41
|
+
records.push(next);
|
|
42
|
+
byRun.set(row.runId, next);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const readRow = (row, changed) => {
|
|
46
|
+
if (!retained(row.pid)) {
|
|
47
|
+
// Terminal timestamps can date old payloads without reading retired
|
|
48
|
+
// requests or treating their abandoned work as an active owner.
|
|
49
|
+
if (row.kind === "product" &&
|
|
50
|
+
isTerminalLifecycle(row.state) &&
|
|
51
|
+
row.runId &&
|
|
52
|
+
!byRun.has(row.runId))
|
|
53
|
+
record(row);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Delivery may read source files after awaits, including a repeated
|
|
57
|
+
// apply. Historical delivery params do not reliably name the source.
|
|
58
|
+
if (row.kind === "delivery" && !isTerminalLifecycle(row.state))
|
|
59
|
+
throw new Error("disk retention kept while a delivery command is unsettled");
|
|
60
|
+
if (row.kind !== "product")
|
|
61
|
+
return;
|
|
62
|
+
const terminal = isTerminalLifecycle(row.state);
|
|
63
|
+
if (terminal)
|
|
64
|
+
active.delete(row.id);
|
|
65
|
+
else
|
|
66
|
+
active.add(row.id);
|
|
67
|
+
uncertainNativeOwners.delete(row.id);
|
|
68
|
+
if (!RunLifecycle.safeParse(row.state).success ||
|
|
69
|
+
(!terminal && !row.runDir && (row.state !== "queued" || row.runId)))
|
|
70
|
+
uncertainNativeOwners.set(row.id, `native ownership unknown for command ${row.id} in partition ${row.pid}: ${row.state}, run directory ${row.runDir ?? "unbound"}`);
|
|
71
|
+
if (row.runDir) {
|
|
72
|
+
nativeRunDirs.add(row.runDir);
|
|
73
|
+
// Active producers can publish a capsule without another SQL write.
|
|
74
|
+
// A changed producer may already have finished by the final recheck.
|
|
75
|
+
if (!terminal || changed)
|
|
76
|
+
nativeWatchRunDirs.add(row.runDir);
|
|
77
|
+
}
|
|
78
|
+
if (row.runDir)
|
|
79
|
+
for (const source of readContinuationSources(row.runDir, { strict: true }))
|
|
80
|
+
add(source.runId);
|
|
81
|
+
let params = paramsByDigest.get(row.params_sha);
|
|
82
|
+
if (!params) {
|
|
83
|
+
params = Dependencies.parse(JSON.parse(blobs.read(row.params_sha).toString("utf8")));
|
|
84
|
+
paramsByDigest.set(row.params_sha, params);
|
|
85
|
+
}
|
|
86
|
+
if ((params.continueFrom ?? null) !== row.continue_from)
|
|
87
|
+
throw new Error(`command ${row.id} retention predecessor disagrees`);
|
|
88
|
+
[row.continue_from, params.retryOf, params.planRef?.runId, params.planRunId].forEach(add);
|
|
89
|
+
if (row.runId !== null) {
|
|
90
|
+
aliases.set(row.id, row.runId);
|
|
91
|
+
if (referencedRunIds.has(row.id))
|
|
92
|
+
add(row.runId);
|
|
93
|
+
// The pass's lookup retains these objects, so final lifecycle/age checks
|
|
94
|
+
// observe changes without rebuilding a map of the entire command store.
|
|
95
|
+
record(row);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const read = (row, changed = false) => {
|
|
99
|
+
try {
|
|
100
|
+
readRow(row, changed);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
throw new Error(`retention command ${row.id} in partition ${row.pid}, params ${row.params_sha}: ${String(error)}`, { cause: error });
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
for await (const rows of retentionPages(store, "command", COLUMNS, signal)) {
|
|
107
|
+
for (const row of rows) {
|
|
108
|
+
await yieldToAdmission();
|
|
109
|
+
signal?.throwIfAborted();
|
|
110
|
+
read(row);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (const id of referencedRunIds)
|
|
114
|
+
add(id);
|
|
115
|
+
return {
|
|
116
|
+
records,
|
|
117
|
+
referencedRunIds,
|
|
118
|
+
nativeRunDirs,
|
|
119
|
+
nativeWatchRunDirs,
|
|
120
|
+
nativeReferenceError: () => [...uncertainNativeOwners.values()].join("; ") || null,
|
|
121
|
+
hasActiveCommands: () => active.size > 0,
|
|
122
|
+
refresh(id) {
|
|
123
|
+
const row = store.prepare(`SELECT ${COLUMNS} FROM command WHERE id=?`).get(id);
|
|
124
|
+
if (!row)
|
|
125
|
+
return; // Releases are recognized on the next pass.
|
|
126
|
+
// A newly bound run was absent from the pass's original lifecycle map.
|
|
127
|
+
if (retained(row.pid) && row.kind === "product" && row.runId && !byRun.has(row.runId))
|
|
128
|
+
add(row.runId);
|
|
129
|
+
read(row, true);
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=retention-command-references.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention-command-references.js","sourceRoot":"","sources":["../../src/store/retention-command-references.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EngineStore } from "./store.js";
|
|
2
|
+
/** Quarantine completes recovery: those rows are evidence, never live owners.
|
|
3
|
+
* Archived generations remain restorable owners. Unknown/pending states cannot
|
|
4
|
+
* prove absence and hold run retirement install-wide. */
|
|
5
|
+
export declare function retentionGenerations(store: EngineStore): {
|
|
6
|
+
retained: (pid: number) => boolean;
|
|
7
|
+
registeredProjectRoots: Set<string>;
|
|
8
|
+
archivedProjectRoots: Set<string>;
|
|
9
|
+
protectedProjectRoots: Set<string>;
|
|
10
|
+
errors: string[];
|
|
11
|
+
blocked: string | undefined;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=retention-generations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention-generations.d.ts","sourceRoot":"","sources":["../../src/store/retention-generations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;yDAEyD;AACzD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW;oBAmB9B,MAAM;;;;;;EA2D9B"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Quarantine completes recovery: those rows are evidence, never live owners.
|
|
2
|
+
* Archived generations remain restorable owners. Unknown/pending states cannot
|
|
3
|
+
* prove absence and hold run retirement install-wide. */
|
|
4
|
+
export function retentionGenerations(store) {
|
|
5
|
+
const rows = store
|
|
6
|
+
.prepare(`SELECT q.id,q.name,q.status,q.project_id,p.root,g.status AS registry_status FROM partition q
|
|
7
|
+
LEFT JOIN project p ON p.id=q.project_id LEFT JOIN partition g ON g.id=p.pid`)
|
|
8
|
+
.all();
|
|
9
|
+
const known = new Map(rows.map((row) => [row.id, row]));
|
|
10
|
+
// A completed global quarantine also retires its project descendants. Their
|
|
11
|
+
// own ready/archived/pending bits are historical, not an independent owner.
|
|
12
|
+
const retired = (row) => row.status === "quarantined" || row.registry_status === "quarantined";
|
|
13
|
+
const retained = (pid) => {
|
|
14
|
+
const row = known.get(pid);
|
|
15
|
+
if (!row)
|
|
16
|
+
throw new Error(`retention owner names missing partition ${pid}`);
|
|
17
|
+
return (!retired(row) &&
|
|
18
|
+
(!row.project_id || row.registry_status === "ready" || row.registry_status === "archived") &&
|
|
19
|
+
(row.status === "ready" || row.status === "archived"));
|
|
20
|
+
};
|
|
21
|
+
const registered = store
|
|
22
|
+
.prepare(`SELECT p.root,p.status FROM project p
|
|
23
|
+
JOIN partition g ON g.id=p.pid LEFT JOIN partition q ON q.id=p.current_pid
|
|
24
|
+
WHERE p.status IN ('active','archived') AND g.status IN ('ready','archived')
|
|
25
|
+
AND (q.id IS NULL OR q.status<>'quarantined')`)
|
|
26
|
+
.all();
|
|
27
|
+
const registeredProjectRoots = new Set(registered.map((row) => row.root));
|
|
28
|
+
const activeRoots = new Set(registered.filter((row) => row.status === "active").map((row) => row.root));
|
|
29
|
+
const archivedProjectRoots = new Set(registered
|
|
30
|
+
.filter((row) => row.status === "archived" && !activeRoots.has(row.root))
|
|
31
|
+
.map((row) => row.root));
|
|
32
|
+
const protectedProjectRoots = new Set();
|
|
33
|
+
const errors = [];
|
|
34
|
+
let blocked;
|
|
35
|
+
for (const row of rows) {
|
|
36
|
+
if (retained(row.id) || retired(row))
|
|
37
|
+
continue;
|
|
38
|
+
const reason = `partition ${row.name} (${row.id}, ${row.status}) awaits journal recovery`;
|
|
39
|
+
// Scope roots do not bound dependencies: a continuation may name any namespace.
|
|
40
|
+
blocked ??= reason;
|
|
41
|
+
errors.push(`all namespaces kept: ${reason}`);
|
|
42
|
+
}
|
|
43
|
+
for (const row of store
|
|
44
|
+
.prepare(`SELECT p.root,p.current_pid FROM project p
|
|
45
|
+
JOIN partition g ON g.id=p.pid LEFT JOIN partition q ON q.id=p.current_pid
|
|
46
|
+
WHERE g.status IN ('ready','archived') AND q.id IS NULL`)
|
|
47
|
+
.all()) {
|
|
48
|
+
protectedProjectRoots.add(row.root);
|
|
49
|
+
errors.push(`namespace ${row.root} kept: missing partition ${row.current_pid} awaits journal recovery`);
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
retained,
|
|
53
|
+
registeredProjectRoots,
|
|
54
|
+
archivedProjectRoots,
|
|
55
|
+
protectedProjectRoots,
|
|
56
|
+
errors,
|
|
57
|
+
blocked,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=retention-generations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention-generations.js","sourceRoot":"","sources":["../../src/store/retention-generations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { EngineStore } from "./store.js";
|
|
2
|
+
/** Bound each synchronous SQLite read, without holding a cursor/transaction
|
|
3
|
+
* across admission. Filter after paging so a sparse predicate cannot turn one
|
|
4
|
+
* page into an unbounded scan. This is an I/O batch, not a retention policy. */
|
|
5
|
+
export declare function retentionPages<T>(store: EngineStore, table: "thread" | "command", columns: string, signal?: AbortSignal): AsyncGenerator<T[]>;
|
|
6
|
+
//# sourceMappingURL=retention-pages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention-pages.d.ts","sourceRoot":"","sources":["../../src/store/retention-pages.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;gFAEgF;AAChF,wBAAuB,cAAc,CAAC,CAAC,EACrC,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,QAAQ,GAAG,SAAS,EAC3B,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,WAAW,GACnB,cAAc,CAAC,CAAC,EAAE,CAAC,CAcrB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { setImmediate as yieldToAdmission } from "node:timers/promises";
|
|
2
|
+
/** Bound each synchronous SQLite read, without holding a cursor/transaction
|
|
3
|
+
* across admission. Filter after paging so a sparse predicate cannot turn one
|
|
4
|
+
* page into an unbounded scan. This is an I/O batch, not a retention policy. */
|
|
5
|
+
export async function* retentionPages(store, table, columns, signal) {
|
|
6
|
+
const page = store.prepare(`SELECT rowid AS retention_rowid,${columns} FROM ${table} NOT INDEXED
|
|
7
|
+
WHERE rowid>? ORDER BY rowid LIMIT 100`);
|
|
8
|
+
let after = 0;
|
|
9
|
+
for (;;) {
|
|
10
|
+
signal?.throwIfAborted();
|
|
11
|
+
const rows = page.all(after);
|
|
12
|
+
if (!rows.length)
|
|
13
|
+
return;
|
|
14
|
+
yield rows;
|
|
15
|
+
after = rows[rows.length - 1].retention_rowid;
|
|
16
|
+
await yieldToAdmission();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=retention-pages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention-pages.js","sourceRoot":"","sources":["../../src/store/retention-pages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxE;;gFAEgF;AAChF,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,cAAc,CACnC,KAAkB,EAClB,KAA2B,EAC3B,OAAe,EACf,MAAoB;IAEpB,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CACxB,mCAAmC,OAAO,SAAS,KAAK;4CAChB,CACzC,CAAC;IACF,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,SAAS,CAAC;QACR,MAAM,EAAE,cAAc,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAA2C,CAAC;QACvE,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QACzB,MAAM,IAAI,CAAC;QACX,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,eAAe,CAAC;QAC/C,MAAM,gBAAgB,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Thread } from "@claudexor/schema";
|
|
2
|
+
import type { EngineStore } from "./store.js";
|
|
3
|
+
type Body = {
|
|
4
|
+
id: string;
|
|
5
|
+
pid: number;
|
|
6
|
+
body: Uint8Array;
|
|
7
|
+
};
|
|
8
|
+
type ThreadRow = Body & {
|
|
9
|
+
state: string;
|
|
10
|
+
};
|
|
11
|
+
type SessionRow = Body & {
|
|
12
|
+
harness_id: string;
|
|
13
|
+
thread_id: string;
|
|
14
|
+
};
|
|
15
|
+
type TurnRow = Body & {
|
|
16
|
+
thread_id: string;
|
|
17
|
+
};
|
|
18
|
+
/** One typed reader for the initial inventory AND changed-owner rechecks.
|
|
19
|
+
* Protection only grows during a pass; release is recognized by the next pass. */
|
|
20
|
+
export declare class RetentionReferenceReader {
|
|
21
|
+
private readonly store;
|
|
22
|
+
private readonly ignored;
|
|
23
|
+
private readonly retained;
|
|
24
|
+
readonly runs: Set<string>;
|
|
25
|
+
readonly sessions: Map<string, Set<string>>;
|
|
26
|
+
readonly roots: Set<string>;
|
|
27
|
+
readonly lanes: Map<string, Set<string>>;
|
|
28
|
+
constructor(store: EngineStore, ignored: ReadonlySet<string>, retained: (pid: number) => boolean);
|
|
29
|
+
add: (id: string | null | undefined) => void;
|
|
30
|
+
thread(row: ThreadRow): Thread | undefined;
|
|
31
|
+
turn(row: TurnRow, owner?: {
|
|
32
|
+
schema_version: 2;
|
|
33
|
+
id: string;
|
|
34
|
+
created_at: string;
|
|
35
|
+
updated_at: string;
|
|
36
|
+
repo: {
|
|
37
|
+
root: string;
|
|
38
|
+
base_ref: string;
|
|
39
|
+
} | null;
|
|
40
|
+
title: string | null;
|
|
41
|
+
folder: string | null;
|
|
42
|
+
mode: "agent" | "ask" | "plan";
|
|
43
|
+
auth_preference: "api_key" | "auto" | "subscription";
|
|
44
|
+
access: "external_sandbox_full" | "full" | "inherit_native" | "readonly" | "workspace_write" | null;
|
|
45
|
+
credential_profile_id: string | null;
|
|
46
|
+
primary_harness: string | null;
|
|
47
|
+
eligible_harnesses: string[];
|
|
48
|
+
workspace: {
|
|
49
|
+
mode: "delegated" | "in_place" | "isolated";
|
|
50
|
+
worktree_path: string | null;
|
|
51
|
+
base_sha: string | null;
|
|
52
|
+
delivered_through_run_id: string | null;
|
|
53
|
+
workspace_root: string | null;
|
|
54
|
+
};
|
|
55
|
+
run_ids: string[];
|
|
56
|
+
head_run_id: string | null;
|
|
57
|
+
state: "active" | "closed" | "purged" | "trashed";
|
|
58
|
+
trashed_at: string | null;
|
|
59
|
+
purge_after: string | null;
|
|
60
|
+
pre_trash_state: "active" | "closed" | null;
|
|
61
|
+
} | undefined): void;
|
|
62
|
+
session(row: SessionRow, owner?: {
|
|
63
|
+
schema_version: 2;
|
|
64
|
+
id: string;
|
|
65
|
+
created_at: string;
|
|
66
|
+
updated_at: string;
|
|
67
|
+
repo: {
|
|
68
|
+
root: string;
|
|
69
|
+
base_ref: string;
|
|
70
|
+
} | null;
|
|
71
|
+
title: string | null;
|
|
72
|
+
folder: string | null;
|
|
73
|
+
mode: "agent" | "ask" | "plan";
|
|
74
|
+
auth_preference: "api_key" | "auto" | "subscription";
|
|
75
|
+
access: "external_sandbox_full" | "full" | "inherit_native" | "readonly" | "workspace_write" | null;
|
|
76
|
+
credential_profile_id: string | null;
|
|
77
|
+
primary_harness: string | null;
|
|
78
|
+
eligible_harnesses: string[];
|
|
79
|
+
workspace: {
|
|
80
|
+
mode: "delegated" | "in_place" | "isolated";
|
|
81
|
+
worktree_path: string | null;
|
|
82
|
+
base_sha: string | null;
|
|
83
|
+
delivered_through_run_id: string | null;
|
|
84
|
+
workspace_root: string | null;
|
|
85
|
+
};
|
|
86
|
+
run_ids: string[];
|
|
87
|
+
head_run_id: string | null;
|
|
88
|
+
state: "active" | "closed" | "purged" | "trashed";
|
|
89
|
+
trashed_at: string | null;
|
|
90
|
+
purge_after: string | null;
|
|
91
|
+
pre_trash_state: "active" | "closed" | null;
|
|
92
|
+
} | undefined): void;
|
|
93
|
+
refresh(table: "thread" | "turn" | "session" | "interaction", id: string): void;
|
|
94
|
+
private read;
|
|
95
|
+
private owner;
|
|
96
|
+
}
|
|
97
|
+
export {};
|
|
98
|
+
//# sourceMappingURL=retention-reference-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention-reference-reader.d.ts","sourceRoot":"","sources":["../../src/store/retention-reference-reader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,MAAM,EAAc,MAAM,mBAAmB,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C,KAAK,IAAI,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAC1D,KAAK,SAAS,GAAG,IAAI,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAC1C,KAAK,UAAU,GAAG,IAAI,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AACnE,KAAK,OAAO,GAAG,IAAI,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5C;kFACkF;AAClF,qBAAa,wBAAwB;IAOjC,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAR3B,QAAQ,CAAC,IAAI,cAAqB;IAClC,QAAQ,CAAC,QAAQ,2BAAkC;IACnD,QAAQ,CAAC,KAAK,cAAqB;IACnC,QAAQ,CAAC,KAAK,2BAAkC;IAEhD,YACmB,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,EACjD;IAEJ,GAAG,OAAQ,MAAM,GAAG,IAAI,GAAG,SAAS,UAElC;IAEF,MAAM,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAgBzC;IAED,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA4B,GAAG,IAAI,CAM1D;IAED,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA4B,GAAG,IAAI,CAchE;IAED,OAAO,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAmB9E;IAED,OAAO,CAAC,IAAI;IAUZ,OAAO,CAAC,KAAK;CASd"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Session, Thread, ThreadTurn } from "@claudexor/schema";
|
|
2
|
+
import { noProjectRepoRoot } from "@claudexor/util";
|
|
3
|
+
import { decodeBody } from "./thread-rows.js";
|
|
4
|
+
const RetainedTurn = ThreadTurn.omit({ prompt: true });
|
|
5
|
+
/** One typed reader for the initial inventory AND changed-owner rechecks.
|
|
6
|
+
* Protection only grows during a pass; release is recognized by the next pass. */
|
|
7
|
+
export class RetentionReferenceReader {
|
|
8
|
+
store;
|
|
9
|
+
ignored;
|
|
10
|
+
retained;
|
|
11
|
+
runs = new Set();
|
|
12
|
+
sessions = new Map();
|
|
13
|
+
roots = new Set();
|
|
14
|
+
lanes = new Map();
|
|
15
|
+
constructor(store, ignored, retained) {
|
|
16
|
+
this.store = store;
|
|
17
|
+
this.ignored = ignored;
|
|
18
|
+
this.retained = retained;
|
|
19
|
+
}
|
|
20
|
+
add = (id) => {
|
|
21
|
+
if (id)
|
|
22
|
+
this.runs.add(id);
|
|
23
|
+
};
|
|
24
|
+
thread(row) {
|
|
25
|
+
if (!this.retained(row.pid) || row.state === "purged")
|
|
26
|
+
return;
|
|
27
|
+
const thread = this.read("thread", row, () => Thread.parse(decodeBody(row)));
|
|
28
|
+
if (thread.state !== row.state || thread.id !== row.id)
|
|
29
|
+
throw new Error(`thread ${row.id} in partition ${row.pid}: retention state or identity disagrees`);
|
|
30
|
+
if (thread.repo)
|
|
31
|
+
this.roots.add(thread.repo.root);
|
|
32
|
+
const root = thread.repo?.root ?? noProjectRepoRoot();
|
|
33
|
+
const lanes = this.lanes.get(root) ?? new Set();
|
|
34
|
+
lanes.add(thread.id);
|
|
35
|
+
this.lanes.set(root, lanes);
|
|
36
|
+
if (this.ignored.has(thread.id) && thread.state === "trashed")
|
|
37
|
+
return;
|
|
38
|
+
thread.run_ids.forEach(this.add);
|
|
39
|
+
this.add(thread.head_run_id);
|
|
40
|
+
return thread;
|
|
41
|
+
}
|
|
42
|
+
turn(row, owner = this.owner(row.thread_id)) {
|
|
43
|
+
if (!this.retained(row.pid) || !owner)
|
|
44
|
+
return;
|
|
45
|
+
const turn = this.read("turn", row, () => RetainedTurn.parse(decodeBody(row)));
|
|
46
|
+
if (turn.thread_id !== owner.id || turn.id !== row.id)
|
|
47
|
+
throw new Error(`turn ${row.id} in partition ${row.pid}: retention owner disagrees`);
|
|
48
|
+
[turn.run_id, turn.parent_run_id, turn.answers_plan_run_id, turn.plan_run_id].forEach(this.add);
|
|
49
|
+
}
|
|
50
|
+
session(row, owner = this.owner(row.thread_id)) {
|
|
51
|
+
if (!this.retained(row.pid) || !owner)
|
|
52
|
+
return;
|
|
53
|
+
const session = this.read("session", row, () => Session.parse(decodeBody(row)));
|
|
54
|
+
if (session.thread_id !== owner.id ||
|
|
55
|
+
session.harness_id !== row.harness_id ||
|
|
56
|
+
session.id !== row.id)
|
|
57
|
+
throw new Error(`session ${row.id} in partition ${row.pid}: retention owner disagrees`);
|
|
58
|
+
if (session.native_session_id) {
|
|
59
|
+
const ids = this.sessions.get(session.harness_id) ?? new Set();
|
|
60
|
+
ids.add(session.native_session_id);
|
|
61
|
+
this.sessions.set(session.harness_id, ids);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
refresh(table, id) {
|
|
65
|
+
if (table === "interaction") {
|
|
66
|
+
const row = this.store
|
|
67
|
+
.prepare("SELECT pid,run_id FROM interaction WHERE id=? AND state='pending'")
|
|
68
|
+
.get(id);
|
|
69
|
+
if (row && this.retained(row.pid))
|
|
70
|
+
this.add(row.run_id);
|
|
71
|
+
}
|
|
72
|
+
else if (table === "thread") {
|
|
73
|
+
this.owner(id);
|
|
74
|
+
}
|
|
75
|
+
else if (table === "turn") {
|
|
76
|
+
const row = this.store
|
|
77
|
+
.prepare("SELECT id,pid,thread_id,body FROM turn WHERE id=?")
|
|
78
|
+
.get(id);
|
|
79
|
+
if (row)
|
|
80
|
+
this.turn(row);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const row = this.store
|
|
84
|
+
.prepare("SELECT id,pid,thread_id,harness_id,body FROM session WHERE id=?")
|
|
85
|
+
.get(id);
|
|
86
|
+
if (row)
|
|
87
|
+
this.session(row);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
read(table, row, read) {
|
|
91
|
+
try {
|
|
92
|
+
return read();
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
throw new Error(`retention ${table} ${row.id} in partition ${row.pid}: ${String(error)}`, {
|
|
96
|
+
cause: error,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
owner(id) {
|
|
101
|
+
const row = this.store.prepare("SELECT id,pid,state,body FROM thread WHERE id=?").get(id);
|
|
102
|
+
if (!row)
|
|
103
|
+
return;
|
|
104
|
+
const thread = this.thread(row);
|
|
105
|
+
if (thread && thread.id !== id)
|
|
106
|
+
throw new Error(`thread ${id} in partition ${row.pid}: retention owner disagrees`);
|
|
107
|
+
return thread;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=retention-reference-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention-reference-reader.js","sourceRoot":"","sources":["../../src/store/retention-reference-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Thread } from "@claudexor/schema";
|
|
2
|
+
import type { EngineStore } from "./store.js";
|
|
3
|
+
export interface DiskRetentionReferences {
|
|
4
|
+
/** Legacy exact inventory witness; current retirement rechecks changed owners. */
|
|
5
|
+
isCurrent: () => boolean;
|
|
6
|
+
/** Cooperatively absorb changed owners, then synchronously recheck before expiry. */
|
|
7
|
+
refresh?: () => Promise<void>;
|
|
8
|
+
recheck?: () => boolean;
|
|
9
|
+
/** Native callers absorb the same changed owners before per-file rechecks. */
|
|
10
|
+
nativeCurrent?: () => boolean;
|
|
11
|
+
/** Pass-local ownership, refreshed synchronously at each lane sweep boundary. */
|
|
12
|
+
laneThreadIds?: (root: string) => Set<string>;
|
|
13
|
+
nativeRunDirs?: ReadonlySet<string>;
|
|
14
|
+
nativeWatchRunDirs?: ReadonlySet<string>;
|
|
15
|
+
nativeReferenceError?: () => string | null;
|
|
16
|
+
hasActiveCommands?: () => boolean;
|
|
17
|
+
/** Caller releases the observation after all deletions, including error paths. */
|
|
18
|
+
close?: () => void;
|
|
19
|
+
/** Recovery holds are receipt facts; completed quarantine is not a hold. */
|
|
20
|
+
blocked?: string;
|
|
21
|
+
errors?: string[];
|
|
22
|
+
projectRoots: string[];
|
|
23
|
+
/** Retained active/archived registrations; thread root names alone are not ownership. */
|
|
24
|
+
registeredProjectRoots: Set<string>;
|
|
25
|
+
/** Archived-only registrations need an extant root to own recent history. */
|
|
26
|
+
archivedProjectRoots?: Set<string>;
|
|
27
|
+
protectedProjectRoots: Set<string>;
|
|
28
|
+
referencedRunIds: Set<string>;
|
|
29
|
+
nativeSessions: Map<string, Set<string>>;
|
|
30
|
+
records: Array<{
|
|
31
|
+
runId: string;
|
|
32
|
+
state: string;
|
|
33
|
+
finishedAt?: string;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
/** Maintenance's served thread listing, including unfinished purges. Unlike
|
|
37
|
+
* public synchronous listing it does not stat every registered project root. */
|
|
38
|
+
export declare function diskRetentionThreads(store: EngineStore, signal?: AbortSignal): Promise<Thread[]>;
|
|
39
|
+
/** Retirement reads all retained generations, including archived projects. Public
|
|
40
|
+
* listing/admission remains served-generation-only. Any unreadable reference throws. */
|
|
41
|
+
export declare function diskRetentionReferences(store: EngineStore, ignoreThreadIds?: ReadonlySet<string>, signal?: AbortSignal): Promise<DiskRetentionReferences>;
|
|
42
|
+
//# sourceMappingURL=retention-references.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention-references.d.ts","sourceRoot":"","sources":["../../src/store/retention-references.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS9C,MAAM,WAAW,uBAAuB;IACtC,kFAAkF;IAClF,SAAS,EAAE,MAAM,OAAO,CAAC;IACzB,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;IACxB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC;IAC9B,iFAAiF;IACjF,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9C,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,oBAAoB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAC3C,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC;IAClC,kFAAkF;IAClF,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,yFAAyF;IACzF,sBAAsB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACpC,6EAA6E;IAC7E,oBAAoB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,qBAAqB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACzC,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvE;AAED;gFACgF;AAChF,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,WAAW,EAClB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,EAAE,CAAC,CA8CnB;AAED;wFACwF;AACxF,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,WAAW,EAClB,eAAe,GAAE,WAAW,CAAC,MAAM,CAAa,EAChD,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,uBAAuB,CAAC,CAyGlC"}
|