@claudexor/daemon 3.3.16 → 3.4.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/command-store.d.ts +3 -0
- package/dist/command-store.d.ts.map +1 -1
- package/dist/command-store.js +4 -0
- package/dist/command-store.js.map +1 -1
- package/dist/daemon-listen.d.ts +10 -0
- package/dist/daemon-listen.d.ts.map +1 -0
- package/dist/daemon-listen.js +36 -0
- package/dist/daemon-listen.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/interactions.d.ts +3 -0
- package/dist/interactions.d.ts.map +1 -1
- package/dist/interactions.js +4 -0
- package/dist/interactions.js.map +1 -1
- package/dist/journal-manager-lifecycle.d.ts +8 -0
- package/dist/journal-manager-lifecycle.d.ts.map +1 -0
- package/dist/journal-manager-lifecycle.js +2 -0
- package/dist/journal-manager-lifecycle.js.map +1 -0
- package/dist/journal-manager.d.ts +21 -11
- package/dist/journal-manager.d.ts.map +1 -1
- package/dist/journal-manager.js +234 -198
- package/dist/journal-manager.js.map +1 -1
- package/dist/journal-prepared-operation.d.ts +53 -0
- package/dist/journal-prepared-operation.d.ts.map +1 -0
- package/dist/journal-prepared-operation.js +158 -0
- package/dist/journal-prepared-operation.js.map +1 -0
- package/dist/journal-projection-slot.d.ts +28 -0
- package/dist/journal-projection-slot.d.ts.map +1 -0
- package/dist/journal-projection-slot.js +71 -0
- package/dist/journal-projection-slot.js.map +1 -0
- package/dist/journal-projection.d.ts +2 -0
- package/dist/journal-projection.d.ts.map +1 -1
- package/dist/journal-recovery-files.d.ts +19 -1
- package/dist/journal-recovery-files.d.ts.map +1 -1
- package/dist/journal-recovery-files.js +271 -26
- package/dist/journal-recovery-files.js.map +1 -1
- package/dist/journal-recovery-operation.d.ts +27 -0
- package/dist/journal-recovery-operation.d.ts.map +1 -0
- package/dist/journal-recovery-operation.js +68 -0
- package/dist/journal-recovery-operation.js.map +1 -0
- package/dist/project-partition-preparation.d.ts +75 -0
- package/dist/project-partition-preparation.d.ts.map +1 -0
- package/dist/project-partition-preparation.js +233 -0
- package/dist/project-partition-preparation.js.map +1 -0
- package/dist/project-partitions.d.ts +18 -16
- package/dist/project-partitions.d.ts.map +1 -1
- package/dist/project-partitions.js +98 -99
- package/dist/project-partitions.js.map +1 -1
- package/dist/project-thread-listing.d.ts +14 -0
- package/dist/project-thread-listing.d.ts.map +1 -0
- package/dist/project-thread-listing.js +37 -0
- package/dist/project-thread-listing.js.map +1 -0
- package/dist/quota-projection.d.ts +9 -0
- package/dist/quota-projection.d.ts.map +1 -0
- package/dist/quota-projection.js +10 -0
- package/dist/quota-projection.js.map +1 -0
- package/dist/quota-registry.d.ts +3 -5
- package/dist/quota-registry.d.ts.map +1 -1
- package/dist/quota-registry.js +9 -10
- package/dist/quota-registry.js.map +1 -1
- package/dist/root-authority.d.ts +68 -0
- package/dist/root-authority.d.ts.map +1 -0
- package/dist/root-authority.js +380 -0
- package/dist/root-authority.js.map +1 -0
- package/dist/rpc-followers.d.ts +17 -0
- package/dist/rpc-followers.d.ts.map +1 -0
- package/dist/rpc-followers.js +46 -0
- package/dist/rpc-followers.js.map +1 -0
- package/dist/server.d.ts +4 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +42 -62
- package/dist/server.js.map +1 -1
- package/dist/serving-admission.d.ts +21 -0
- package/dist/serving-admission.d.ts.map +1 -0
- package/dist/serving-admission.js +17 -0
- package/dist/serving-admission.js.map +1 -0
- package/dist/terminate.d.ts +18 -7
- package/dist/terminate.d.ts.map +1 -1
- package/dist/terminate.js +213 -69
- package/dist/terminate.js.map +1 -1
- package/dist/token.d.ts +6 -0
- package/dist/token.d.ts.map +1 -1
- package/dist/token.js +8 -0
- package/dist/token.js.map +1 -1
- package/dist/writer-lease.d.ts +76 -4
- package/dist/writer-lease.d.ts.map +1 -1
- package/dist/writer-lease.js +346 -56
- package/dist/writer-lease.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { JournalRecoveryRequiredError } from "@claudexor/journal";
|
|
3
|
+
import { commandProjection } from "./command-store.js";
|
|
4
|
+
import { interactionProjection } from "./interactions.js";
|
|
5
|
+
import { JournalManager } from "./journal-manager.js";
|
|
6
|
+
import { recoveryFrom } from "./journal-recovery-files.js";
|
|
7
|
+
import { operatorDecisionProjection } from "./operator-decisions.js";
|
|
8
|
+
import { runEventProjection } from "./run-events.js";
|
|
9
|
+
import { threadProjection } from "./threads.js";
|
|
10
|
+
export class ProjectPartitionCollection extends Map {
|
|
11
|
+
rootDir;
|
|
12
|
+
projects;
|
|
13
|
+
headPing;
|
|
14
|
+
constructor(rootDir, projects, headPing) {
|
|
15
|
+
super();
|
|
16
|
+
this.rootDir = rootDir;
|
|
17
|
+
this.projects = projects;
|
|
18
|
+
this.headPing = headPing;
|
|
19
|
+
}
|
|
20
|
+
sync() {
|
|
21
|
+
const ids = new Set(this.projects
|
|
22
|
+
.current()
|
|
23
|
+
.list()
|
|
24
|
+
.map((project) => project.id));
|
|
25
|
+
for (const id of ids)
|
|
26
|
+
this.ensure(id);
|
|
27
|
+
for (const [id, entry] of this) {
|
|
28
|
+
if (ids.has(id))
|
|
29
|
+
continue;
|
|
30
|
+
entry.manager.close();
|
|
31
|
+
this.delete(id);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
ensure(projectId) {
|
|
35
|
+
const existing = this.get(projectId);
|
|
36
|
+
if (existing)
|
|
37
|
+
return existing;
|
|
38
|
+
const entry = createProjectPartition(this.rootDir, `project:${projectId}`, this.headPing);
|
|
39
|
+
entry.manager.start();
|
|
40
|
+
this.set(projectId, entry);
|
|
41
|
+
return entry;
|
|
42
|
+
}
|
|
43
|
+
healthy() {
|
|
44
|
+
this.sync();
|
|
45
|
+
return [...this.values()].filter((entry) => entry.manager.ready());
|
|
46
|
+
}
|
|
47
|
+
healthyRoots() {
|
|
48
|
+
this.sync();
|
|
49
|
+
const registry = this.projects.current();
|
|
50
|
+
const roots = [];
|
|
51
|
+
for (const [id, entry] of this) {
|
|
52
|
+
if (!entry.manager.ready())
|
|
53
|
+
continue;
|
|
54
|
+
const root = registry.get(id)?.root;
|
|
55
|
+
if (root)
|
|
56
|
+
roots.push(root);
|
|
57
|
+
}
|
|
58
|
+
return roots;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function prepareProjectPartitions(input) {
|
|
62
|
+
let projects;
|
|
63
|
+
try {
|
|
64
|
+
const registry = input.projects.prepared();
|
|
65
|
+
registry.validateProjection();
|
|
66
|
+
projects = registry.list();
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return {
|
|
70
|
+
receipt: {
|
|
71
|
+
coverage: "global_registry_unavailable",
|
|
72
|
+
fingerprint: null,
|
|
73
|
+
registeredProjectIds: [],
|
|
74
|
+
trustedProjectRoots: [],
|
|
75
|
+
partitions: [],
|
|
76
|
+
readyPartitions: [],
|
|
77
|
+
recoveryRequiredPartitions: [],
|
|
78
|
+
},
|
|
79
|
+
entries: new Map(),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const entries = new Map();
|
|
83
|
+
const partitions = [];
|
|
84
|
+
for (const project of projects) {
|
|
85
|
+
const partition = `project:${project.id}`;
|
|
86
|
+
const value = createProjectPartition(input.rootDir, partition, input.headPing);
|
|
87
|
+
const preparation = value.manager.prepare();
|
|
88
|
+
entries.set(project.id, value);
|
|
89
|
+
partitions.push({
|
|
90
|
+
projectId: project.id,
|
|
91
|
+
partition,
|
|
92
|
+
status: preparation.inspection.status,
|
|
93
|
+
virtual: preparation.virtual,
|
|
94
|
+
fingerprint: preparation.preparationFingerprint,
|
|
95
|
+
manager: value.manager,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const readyPartitions = partitions
|
|
99
|
+
.filter((entry) => entry.status === "ready")
|
|
100
|
+
.map((entry) => entry.partition);
|
|
101
|
+
const recoveryRequiredPartitions = partitions
|
|
102
|
+
.filter((entry) => entry.status === "recovery_required")
|
|
103
|
+
.map((entry) => entry.partition);
|
|
104
|
+
const registeredProjectIds = projects.map((project) => project.id);
|
|
105
|
+
const trustedProjectRoots = projects.map((project) => project.root);
|
|
106
|
+
return {
|
|
107
|
+
receipt: {
|
|
108
|
+
coverage: "complete",
|
|
109
|
+
fingerprint: preparationFingerprint(registeredProjectIds, trustedProjectRoots, partitions),
|
|
110
|
+
registeredProjectIds,
|
|
111
|
+
trustedProjectRoots,
|
|
112
|
+
partitions,
|
|
113
|
+
readyPartitions,
|
|
114
|
+
recoveryRequiredPartitions,
|
|
115
|
+
},
|
|
116
|
+
entries,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Live re-verdict for the in-process reopen (C6): recompute the stage-2
|
|
121
|
+
* receipt from CURRENT partition state. A partition the operator quarantined
|
|
122
|
+
* over the recovery route was reopened by its manager (openGeneration) and
|
|
123
|
+
* now inspects ready; a registry that became readable after a global reopen
|
|
124
|
+
* restores coverage. Read-only for everything still prepared — a registered
|
|
125
|
+
* project without an entry gets a read-only prepare, never a write.
|
|
126
|
+
*/
|
|
127
|
+
export function refreshProjectPartitionsPreparation(input) {
|
|
128
|
+
let projects;
|
|
129
|
+
try {
|
|
130
|
+
const registry = input.projects.prepared();
|
|
131
|
+
registry.validateProjection();
|
|
132
|
+
projects = registry.list();
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return {
|
|
136
|
+
coverage: "global_registry_unavailable",
|
|
137
|
+
fingerprint: null,
|
|
138
|
+
registeredProjectIds: [],
|
|
139
|
+
trustedProjectRoots: [],
|
|
140
|
+
partitions: [],
|
|
141
|
+
readyPartitions: [],
|
|
142
|
+
recoveryRequiredPartitions: [],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const previousByPartition = new Map(input.previous.partitions.map((entry) => [entry.partition, entry]));
|
|
146
|
+
const partitions = [];
|
|
147
|
+
for (const project of projects) {
|
|
148
|
+
const partition = `project:${project.id}`;
|
|
149
|
+
let entry = input.entries.get(project.id);
|
|
150
|
+
if (!entry) {
|
|
151
|
+
entry = createProjectPartition(input.rootDir, partition, input.headPing);
|
|
152
|
+
entry.manager.prepare();
|
|
153
|
+
input.entries.set(project.id, entry);
|
|
154
|
+
}
|
|
155
|
+
const inspection = entry.manager.inspect();
|
|
156
|
+
partitions.push({
|
|
157
|
+
projectId: project.id,
|
|
158
|
+
partition,
|
|
159
|
+
status: inspection.status === "ready" ? "ready" : "recovery_required",
|
|
160
|
+
virtual: previousByPartition.get(partition)?.virtual ?? false,
|
|
161
|
+
fingerprint: inspection.fingerprint,
|
|
162
|
+
manager: entry.manager,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
const registeredProjectIds = projects.map((project) => project.id);
|
|
166
|
+
const trustedProjectRoots = projects.map((project) => project.root);
|
|
167
|
+
return {
|
|
168
|
+
coverage: "complete",
|
|
169
|
+
fingerprint: preparationFingerprint(registeredProjectIds, trustedProjectRoots, partitions),
|
|
170
|
+
registeredProjectIds,
|
|
171
|
+
trustedProjectRoots,
|
|
172
|
+
partitions,
|
|
173
|
+
readyPartitions: partitions
|
|
174
|
+
.filter((entry) => entry.status === "ready")
|
|
175
|
+
.map((entry) => entry.partition),
|
|
176
|
+
recoveryRequiredPartitions: partitions
|
|
177
|
+
.filter((entry) => entry.status === "recovery_required")
|
|
178
|
+
.map((entry) => entry.partition),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
export function activatePreparedProjectPartitions(input) {
|
|
182
|
+
if (input.receipt.coverage !== "complete" ||
|
|
183
|
+
input.receipt.recoveryRequiredPartitions.length > 0) {
|
|
184
|
+
throw new Error("project partitions require recovery before activation");
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
for (const entry of input.entries.values()) {
|
|
188
|
+
// Reopened-after-quarantine managers are live (C6); skip revalidation.
|
|
189
|
+
if (!entry.manager.ready())
|
|
190
|
+
entry.manager.revalidatePreparation();
|
|
191
|
+
}
|
|
192
|
+
for (const entry of input.entries.values())
|
|
193
|
+
entry.manager.activatePrepared();
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
const recovery = recoveryFrom(error, "project partition activation failed");
|
|
197
|
+
for (const entry of input.entries.values())
|
|
198
|
+
entry.manager.close();
|
|
199
|
+
input.entries.clear();
|
|
200
|
+
const rebuilt = prepareProjectPartitions(input);
|
|
201
|
+
for (const [id, entry] of rebuilt.entries)
|
|
202
|
+
input.entries.set(id, entry);
|
|
203
|
+
input.resetReceipt(rebuilt.receipt);
|
|
204
|
+
throw new JournalRecoveryRequiredError(recovery);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function createProjectPartition(rootDir, partition, headPing) {
|
|
208
|
+
const manager = new JournalManager(rootDir, { partition });
|
|
209
|
+
const value = {
|
|
210
|
+
manager,
|
|
211
|
+
commands: manager.registerProjection(commandProjection()),
|
|
212
|
+
interactions: manager.registerProjection(interactionProjection()),
|
|
213
|
+
decisions: manager.registerProjection(operatorDecisionProjection()),
|
|
214
|
+
runEvents: manager.registerProjection(runEventProjection()),
|
|
215
|
+
threads: manager.registerProjection(threadProjection(headPing)),
|
|
216
|
+
};
|
|
217
|
+
return value;
|
|
218
|
+
}
|
|
219
|
+
function preparationFingerprint(projectIds, projectRoots, partitions) {
|
|
220
|
+
return createHash("sha256")
|
|
221
|
+
.update(JSON.stringify({
|
|
222
|
+
projectIds,
|
|
223
|
+
projectRoots,
|
|
224
|
+
partitions: partitions.map((entry) => ({
|
|
225
|
+
partition: entry.partition,
|
|
226
|
+
status: entry.status,
|
|
227
|
+
virtual: entry.virtual,
|
|
228
|
+
fingerprint: entry.fingerprint,
|
|
229
|
+
})),
|
|
230
|
+
}))
|
|
231
|
+
.digest("hex");
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=project-partition-preparation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-partition-preparation.js","sourceRoot":"","sources":["../src/project-partition-preparation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { ControlProjectListingProblem, Project, RunEvent, Thread, ThreadTurn } from "@claudexor/schema";
|
|
2
|
-
import {
|
|
3
|
-
import { JournalManager,
|
|
4
|
-
import {
|
|
2
|
+
import type { CommandStore } from "./command-store.js";
|
|
3
|
+
import type { JournalManager, JournalProjectionSlot } from "./journal-manager.js";
|
|
4
|
+
import type { InteractionStore } from "./interactions.js";
|
|
5
5
|
import { type OperatorDecisionRecord, type OperatorDecisionStore, type RecordedOperatorDecision } from "./operator-decisions.js";
|
|
6
|
-
import {
|
|
6
|
+
import type { RunEventStore } from "./run-events.js";
|
|
7
7
|
import type { ProjectStore } from "./projects.js";
|
|
8
8
|
import { type CreateThreadInput, type CreateTurnInput, type ThreadHeadPingSink, type ThreadStore, type UpdateThreadInput } from "./threads.js";
|
|
9
9
|
import type { CommandAuthority } from "./command-authority.js";
|
|
10
|
+
import { type ProjectPartitionsPreparation } from "./project-partition-preparation.js";
|
|
11
|
+
export type { ProjectPartitionsPreparation } from "./project-partition-preparation.js";
|
|
10
12
|
export declare class ProjectPartitions implements CommandAuthority {
|
|
11
13
|
private readonly rootDir;
|
|
12
14
|
private readonly projects;
|
|
@@ -18,9 +20,19 @@ export declare class ProjectPartitions implements CommandAuthority {
|
|
|
18
20
|
/** Global-partition `thread.head.updated` sink, threaded into every project ThreadStore. */
|
|
19
21
|
private readonly headPing?;
|
|
20
22
|
private readonly partitions;
|
|
23
|
+
private preparationResult;
|
|
21
24
|
constructor(rootDir: string, projects: JournalProjectionSlot<ProjectStore>, globalCommands: JournalProjectionSlot<CommandStore>, globalInteractions: JournalProjectionSlot<InteractionStore>, globalDecisions: JournalProjectionSlot<OperatorDecisionStore>, globalRunEvents: JournalProjectionSlot<RunEventStore>, globalThreads: JournalProjectionSlot<ThreadStore>,
|
|
22
25
|
/** Global-partition `thread.head.updated` sink, threaded into every project ThreadStore. */
|
|
23
26
|
headPing?: ThreadHeadPingSink | undefined);
|
|
27
|
+
prepare(): ProjectPartitionsPreparation;
|
|
28
|
+
revalidatePreparation(): void;
|
|
29
|
+
/** Live stage-2 re-verdict for the in-process reopen (C6): quarantined
|
|
30
|
+
* partitions reopened by their manager count ready, and a registry that
|
|
31
|
+
* became readable after a global reopen restores coverage. Refreshes the
|
|
32
|
+
* cached receipt the activation gate checks. */
|
|
33
|
+
refreshPreparation(): ProjectPartitionsPreparation;
|
|
34
|
+
activatePrepared(): void;
|
|
35
|
+
recoverAfterStartup(): void;
|
|
24
36
|
all(): CommandStore[];
|
|
25
37
|
interactionStores(): InteractionStore[];
|
|
26
38
|
interactionsForRequest(params: unknown): InteractionStore;
|
|
@@ -98,15 +110,8 @@ export declare class ProjectPartitions implements CommandAuthority {
|
|
|
98
110
|
ephemeral?: boolean;
|
|
99
111
|
}): Thread;
|
|
100
112
|
listThreads(): Thread[];
|
|
101
|
-
/**
|
|
102
|
-
*
|
|
103
|
-
* registered project whose filesystem root has vanished (e.g. a swept ghost
|
|
104
|
-
* envelope worktree) is SKIPPED with a disclosed per-project problem instead
|
|
105
|
-
* of failing the whole listing, while every other project's threads load.
|
|
106
|
-
* Each store sorts ITS threads by recency, but the stores concatenate —
|
|
107
|
-
* without a merge-sort a fresh project thread lands below every global one
|
|
108
|
-
* (dogfood: the fresh thread sank to the bottom). One global recency order.
|
|
109
|
-
*/
|
|
113
|
+
/** Dead-project-resilient listing in one global recency order (F2);
|
|
114
|
+
* the mechanics live in project-thread-listing.ts. */
|
|
110
115
|
listThreadsResilient(): {
|
|
111
116
|
threads: Thread[];
|
|
112
117
|
problems: ControlProjectListingProblem[];
|
|
@@ -160,9 +165,6 @@ export declare class ProjectPartitions implements CommandAuthority {
|
|
|
160
165
|
*/
|
|
161
166
|
pingThreadHead(id: string): void;
|
|
162
167
|
close(): void;
|
|
163
|
-
private sync;
|
|
164
|
-
private ensure;
|
|
165
|
-
private healthy;
|
|
166
168
|
/**
|
|
167
169
|
* Canonical roots whose partition journal is READY — the set whose thread
|
|
168
170
|
* lineage / job records are trustworthy. Retention (W3.6) fails CLOSED on a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-partitions.d.ts","sourceRoot":"","sources":["../src/project-partitions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,4BAA4B,EAC5B,OAAO,EACP,QAAQ,EACR,MAAM,EACN,UAAU,EACX,MAAM,mBAAmB,CAAC;AAG3B,OAAO,
|
|
1
|
+
{"version":3,"file":"project-partitions.d.ts","sourceRoot":"","sources":["../src/project-partitions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { isEphemeralRunScope } from "@claudexor/schema";
|
|
3
3
|
import { hashJson, isClaudexorOwnedRuntimePath } from "@claudexor/util";
|
|
4
|
-
import { commandProjection } from "./command-store.js";
|
|
5
|
-
import { JournalManager } from "./journal-manager.js";
|
|
6
|
-
import { interactionProjection } from "./interactions.js";
|
|
7
|
-
import { operatorDecisionProjection, } from "./operator-decisions.js";
|
|
8
|
-
import { runEventProjection } from "./run-events.js";
|
|
9
|
-
import { threadProjection, } from "./threads.js";
|
|
10
4
|
import { beginDeliveryCommand, completeDeliveryCommand, failDeliveryCommand, } from "./delivery-command.js";
|
|
5
|
+
import { activatePreparedProjectPartitions, prepareProjectPartitions, refreshProjectPartitionsPreparation, ProjectPartitionCollection, } from "./project-partition-preparation.js";
|
|
6
|
+
import { listProjectThreadsResilient } from "./project-thread-listing.js";
|
|
11
7
|
export class ProjectPartitions {
|
|
12
8
|
rootDir;
|
|
13
9
|
projects;
|
|
@@ -17,7 +13,8 @@ export class ProjectPartitions {
|
|
|
17
13
|
globalRunEvents;
|
|
18
14
|
globalThreads;
|
|
19
15
|
headPing;
|
|
20
|
-
partitions
|
|
16
|
+
partitions;
|
|
17
|
+
preparationResult = null;
|
|
21
18
|
constructor(rootDir, projects, globalCommands, globalInteractions, globalDecisions, globalRunEvents, globalThreads,
|
|
22
19
|
/** Global-partition `thread.head.updated` sink, threaded into every project ThreadStore. */
|
|
23
20
|
headPing) {
|
|
@@ -29,25 +26,84 @@ export class ProjectPartitions {
|
|
|
29
26
|
this.globalRunEvents = globalRunEvents;
|
|
30
27
|
this.globalThreads = globalThreads;
|
|
31
28
|
this.headPing = headPing;
|
|
32
|
-
this.
|
|
29
|
+
this.partitions = new ProjectPartitionCollection(rootDir, projects, headPing);
|
|
30
|
+
}
|
|
31
|
+
prepare() {
|
|
32
|
+
if (this.preparationResult)
|
|
33
|
+
return this.preparationResult;
|
|
34
|
+
const prepared = prepareProjectPartitions({
|
|
35
|
+
rootDir: this.rootDir,
|
|
36
|
+
projects: this.projects,
|
|
37
|
+
headPing: this.headPing,
|
|
38
|
+
});
|
|
39
|
+
this.partitions.clear();
|
|
40
|
+
for (const [id, entry] of prepared.entries)
|
|
41
|
+
this.partitions.set(id, entry);
|
|
42
|
+
this.preparationResult = prepared.receipt;
|
|
43
|
+
return prepared.receipt;
|
|
44
|
+
}
|
|
45
|
+
revalidatePreparation() {
|
|
46
|
+
if (!this.preparationResult)
|
|
47
|
+
throw new Error("project partitions are not prepared");
|
|
48
|
+
for (const entry of this.partitions.values()) {
|
|
49
|
+
// A manager reopened by a recovery-route quarantine is live authority
|
|
50
|
+
// (C6): only still-prepared partitions revalidate.
|
|
51
|
+
if (entry.manager.ready())
|
|
52
|
+
continue;
|
|
53
|
+
entry.manager.revalidatePreparation();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Live stage-2 re-verdict for the in-process reopen (C6): quarantined
|
|
57
|
+
* partitions reopened by their manager count ready, and a registry that
|
|
58
|
+
* became readable after a global reopen restores coverage. Refreshes the
|
|
59
|
+
* cached receipt the activation gate checks. */
|
|
60
|
+
refreshPreparation() {
|
|
61
|
+
if (!this.preparationResult)
|
|
62
|
+
throw new Error("project partitions are not prepared");
|
|
63
|
+
this.preparationResult = refreshProjectPartitionsPreparation({
|
|
64
|
+
rootDir: this.rootDir,
|
|
65
|
+
projects: this.projects,
|
|
66
|
+
headPing: this.headPing,
|
|
67
|
+
previous: this.preparationResult,
|
|
68
|
+
entries: this.partitions,
|
|
69
|
+
});
|
|
70
|
+
return this.preparationResult;
|
|
71
|
+
}
|
|
72
|
+
activatePrepared() {
|
|
73
|
+
if (!this.preparationResult)
|
|
74
|
+
throw new Error("project partitions are not prepared");
|
|
75
|
+
activatePreparedProjectPartitions({
|
|
76
|
+
rootDir: this.rootDir,
|
|
77
|
+
projects: this.projects,
|
|
78
|
+
headPing: this.headPing,
|
|
79
|
+
receipt: this.preparationResult,
|
|
80
|
+
entries: this.partitions,
|
|
81
|
+
resetReceipt: (receipt) => (this.preparationResult = receipt),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
recoverAfterStartup() {
|
|
85
|
+
for (const entry of this.partitions.values())
|
|
86
|
+
entry.manager.recoverAfterStartup();
|
|
33
87
|
}
|
|
34
88
|
all() {
|
|
35
89
|
return [
|
|
36
90
|
this.globalCommands.current(),
|
|
37
|
-
...this.healthy().map((entry) => entry.commands.current()),
|
|
91
|
+
...this.partitions.healthy().map((entry) => entry.commands.current()),
|
|
38
92
|
];
|
|
39
93
|
}
|
|
40
94
|
interactionStores() {
|
|
41
95
|
return [
|
|
42
96
|
this.globalInteractions.current(),
|
|
43
|
-
...this.healthy().map((entry) => entry.interactions.current()),
|
|
97
|
+
...this.partitions.healthy().map((entry) => entry.interactions.current()),
|
|
44
98
|
];
|
|
45
99
|
}
|
|
46
100
|
interactionsForRequest(params) {
|
|
47
101
|
const commandStore = this.forRequest(params);
|
|
48
102
|
if (commandStore === this.globalCommands.current())
|
|
49
103
|
return this.globalInteractions.current();
|
|
50
|
-
const entry = this.
|
|
104
|
+
const entry = this.partitions
|
|
105
|
+
.healthy()
|
|
106
|
+
.find((candidate) => candidate.commands.current() === commandStore);
|
|
51
107
|
if (!entry)
|
|
52
108
|
throw new Error("command partition has no interaction authority");
|
|
53
109
|
return entry.interactions.current();
|
|
@@ -96,7 +152,7 @@ export class ProjectPartitions {
|
|
|
96
152
|
}
|
|
97
153
|
registerProject(input) {
|
|
98
154
|
const project = this.projects.current().register(input);
|
|
99
|
-
this.ensure(project.id);
|
|
155
|
+
this.partitions.ensure(project.id);
|
|
100
156
|
return project;
|
|
101
157
|
}
|
|
102
158
|
/**
|
|
@@ -123,12 +179,12 @@ export class ProjectPartitions {
|
|
|
123
179
|
});
|
|
124
180
|
}
|
|
125
181
|
if (retired.length > 0)
|
|
126
|
-
this.sync();
|
|
182
|
+
this.partitions.sync();
|
|
127
183
|
return retired;
|
|
128
184
|
}
|
|
129
185
|
relinkProject(id, root) {
|
|
130
186
|
const project = this.projects.current().relink(id, root);
|
|
131
|
-
this.ensure(id).threads.current().relinkProjectRoot(project.root);
|
|
187
|
+
this.partitions.ensure(id).threads.current().relinkProjectRoot(project.root);
|
|
132
188
|
return project;
|
|
133
189
|
}
|
|
134
190
|
/**
|
|
@@ -151,7 +207,7 @@ export class ProjectPartitions {
|
|
|
151
207
|
status: 404,
|
|
152
208
|
});
|
|
153
209
|
}
|
|
154
|
-
this.sync();
|
|
210
|
+
this.partitions.sync();
|
|
155
211
|
const entry = this.partitions.get(id);
|
|
156
212
|
if (entry) {
|
|
157
213
|
if (!entry.manager.ready()) {
|
|
@@ -208,9 +264,15 @@ export class ProjectPartitions {
|
|
|
208
264
|
if (!partition.startsWith("project:"))
|
|
209
265
|
throw unknownPartition(partition);
|
|
210
266
|
const id = partition.slice("project:".length);
|
|
267
|
+
const prepared = this.partitions.get(id);
|
|
268
|
+
if (prepared)
|
|
269
|
+
return prepared.manager;
|
|
270
|
+
if (this.preparationResult?.coverage === "global_registry_unavailable") {
|
|
271
|
+
throw unknownPartition(partition);
|
|
272
|
+
}
|
|
211
273
|
if (!id || !this.projects.current().get(id))
|
|
212
274
|
throw unknownPartition(partition);
|
|
213
|
-
return this.ensure(id).manager;
|
|
275
|
+
return this.partitions.ensure(id).manager;
|
|
214
276
|
}
|
|
215
277
|
/** `ephemeral`: the caller declared this root ONE-SHOT (INV-035) — never registered, so the
|
|
216
278
|
* thread takes the global no-project partition, exactly as its commands and run events do. */
|
|
@@ -225,40 +287,14 @@ export class ProjectPartitions {
|
|
|
225
287
|
listThreads() {
|
|
226
288
|
return this.listThreadsResilient().threads;
|
|
227
289
|
}
|
|
228
|
-
/**
|
|
229
|
-
*
|
|
230
|
-
* registered project whose filesystem root has vanished (e.g. a swept ghost
|
|
231
|
-
* envelope worktree) is SKIPPED with a disclosed per-project problem instead
|
|
232
|
-
* of failing the whole listing, while every other project's threads load.
|
|
233
|
-
* Each store sorts ITS threads by recency, but the stores concatenate —
|
|
234
|
-
* without a merge-sort a fresh project thread lands below every global one
|
|
235
|
-
* (dogfood: the fresh thread sank to the bottom). One global recency order.
|
|
236
|
-
*/
|
|
290
|
+
/** Dead-project-resilient listing in one global recency order (F2);
|
|
291
|
+
* the mechanics live in project-thread-listing.ts. */
|
|
237
292
|
listThreadsResilient() {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
if (!entry.manager.ready())
|
|
244
|
-
continue;
|
|
245
|
-
const root = registry.get(id)?.root;
|
|
246
|
-
if (!root)
|
|
247
|
-
continue;
|
|
248
|
-
if (!existsSync(root)) {
|
|
249
|
-
problems.push({
|
|
250
|
-
projectId: id,
|
|
251
|
-
root,
|
|
252
|
-
code: "project_root_missing",
|
|
253
|
-
message: `project root no longer exists: ${root}`,
|
|
254
|
-
});
|
|
255
|
-
continue;
|
|
256
|
-
}
|
|
257
|
-
for (const thread of entry.threads.current().listThreads())
|
|
258
|
-
threads.push(thread);
|
|
259
|
-
}
|
|
260
|
-
threads.sort((a, b) => a.updated_at < b.updated_at ? 1 : a.updated_at > b.updated_at ? -1 : 0);
|
|
261
|
-
return { threads, problems };
|
|
293
|
+
return listProjectThreadsResilient({
|
|
294
|
+
partitions: this.partitions,
|
|
295
|
+
projects: this.projects,
|
|
296
|
+
globalThreads: this.globalThreads,
|
|
297
|
+
});
|
|
262
298
|
}
|
|
263
299
|
getThread(id) {
|
|
264
300
|
return this.threadStoreForThread(id)?.getThread(id);
|
|
@@ -289,7 +325,7 @@ export class ProjectPartitions {
|
|
|
289
325
|
}, { clearedThreads: 0, invalidatedSessions: 0 });
|
|
290
326
|
}
|
|
291
327
|
assertCredentialProfileInvalidationReady() {
|
|
292
|
-
this.sync();
|
|
328
|
+
this.partitions.sync();
|
|
293
329
|
const unavailable = [...this.partitions.entries()]
|
|
294
330
|
.filter(([, entry]) => !entry.manager.ready())
|
|
295
331
|
.map(([id]) => id);
|
|
@@ -359,39 +395,6 @@ export class ProjectPartitions {
|
|
|
359
395
|
entry.manager.close();
|
|
360
396
|
this.partitions.clear();
|
|
361
397
|
}
|
|
362
|
-
sync() {
|
|
363
|
-
const ids = new Set(this.projects
|
|
364
|
-
.current()
|
|
365
|
-
.list()
|
|
366
|
-
.map((project) => project.id));
|
|
367
|
-
for (const id of ids)
|
|
368
|
-
this.ensure(id);
|
|
369
|
-
for (const [id, entry] of this.partitions) {
|
|
370
|
-
if (ids.has(id))
|
|
371
|
-
continue;
|
|
372
|
-
entry.manager.close();
|
|
373
|
-
this.partitions.delete(id);
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
ensure(projectId) {
|
|
377
|
-
const existing = this.partitions.get(projectId);
|
|
378
|
-
if (existing)
|
|
379
|
-
return existing;
|
|
380
|
-
const manager = new JournalManager(this.rootDir, { partition: `project:${projectId}` });
|
|
381
|
-
const commands = manager.registerProjection(commandProjection());
|
|
382
|
-
const interactions = manager.registerProjection(interactionProjection());
|
|
383
|
-
const decisions = manager.registerProjection(operatorDecisionProjection());
|
|
384
|
-
const runEvents = manager.registerProjection(runEventProjection());
|
|
385
|
-
const threads = manager.registerProjection(threadProjection(this.headPing));
|
|
386
|
-
manager.start();
|
|
387
|
-
const entry = { manager, commands, interactions, decisions, runEvents, threads };
|
|
388
|
-
this.partitions.set(projectId, entry);
|
|
389
|
-
return entry;
|
|
390
|
-
}
|
|
391
|
-
healthy() {
|
|
392
|
-
this.sync();
|
|
393
|
-
return [...this.partitions.values()].filter((entry) => entry.manager.ready());
|
|
394
|
-
}
|
|
395
398
|
/**
|
|
396
399
|
* Canonical roots whose partition journal is READY — the set whose thread
|
|
397
400
|
* lineage / job records are trustworthy. Retention (W3.6) fails CLOSED on a
|
|
@@ -400,17 +403,7 @@ export class ProjectPartitions {
|
|
|
400
403
|
* so its referenced runs would otherwise look unreferenced).
|
|
401
404
|
*/
|
|
402
405
|
healthyProjectRoots() {
|
|
403
|
-
this.
|
|
404
|
-
const registry = this.projects.current();
|
|
405
|
-
const roots = [];
|
|
406
|
-
for (const [id, entry] of this.partitions) {
|
|
407
|
-
if (!entry.manager.ready())
|
|
408
|
-
continue;
|
|
409
|
-
const root = registry.get(id)?.root;
|
|
410
|
-
if (root)
|
|
411
|
-
roots.push(root);
|
|
412
|
-
}
|
|
413
|
-
return roots;
|
|
406
|
+
return this.partitions.healthyRoots();
|
|
414
407
|
}
|
|
415
408
|
partitionForRoot(root) {
|
|
416
409
|
const project = this.projects.current().findByRoot(root);
|
|
@@ -420,12 +413,12 @@ export class ProjectPartitions {
|
|
|
420
413
|
status: 404,
|
|
421
414
|
});
|
|
422
415
|
}
|
|
423
|
-
return this.ensure(project.id);
|
|
416
|
+
return this.partitions.ensure(project.id);
|
|
424
417
|
}
|
|
425
418
|
threadStores() {
|
|
426
419
|
return [
|
|
427
420
|
this.globalThreads.current(),
|
|
428
|
-
...this.healthy().map((entry) => entry.threads.current()),
|
|
421
|
+
...this.partitions.healthy().map((entry) => entry.threads.current()),
|
|
429
422
|
];
|
|
430
423
|
}
|
|
431
424
|
threadStoreForRoot(root) {
|
|
@@ -452,7 +445,9 @@ export class ProjectPartitions {
|
|
|
452
445
|
commandStoreForThreadStore(store) {
|
|
453
446
|
if (store === this.globalThreads.current())
|
|
454
447
|
return this.globalCommands.current();
|
|
455
|
-
const entry = this.
|
|
448
|
+
const entry = this.partitions
|
|
449
|
+
.healthy()
|
|
450
|
+
.find((candidate) => candidate.threads.current() === store);
|
|
456
451
|
if (!entry)
|
|
457
452
|
throw new Error("thread partition has no command authority");
|
|
458
453
|
return entry.commands.current();
|
|
@@ -461,7 +456,9 @@ export class ProjectPartitions {
|
|
|
461
456
|
const commands = this.forRequest(params);
|
|
462
457
|
if (commands === this.globalCommands.current())
|
|
463
458
|
return this.globalDecisions.current();
|
|
464
|
-
const entry = this.
|
|
459
|
+
const entry = this.partitions
|
|
460
|
+
.healthy()
|
|
461
|
+
.find((candidate) => candidate.commands.current() === commands);
|
|
465
462
|
if (!entry)
|
|
466
463
|
throw new Error("command partition has no operator-decision authority");
|
|
467
464
|
return entry.decisions.current();
|
|
@@ -470,7 +467,9 @@ export class ProjectPartitions {
|
|
|
470
467
|
const commands = this.forRequest(params);
|
|
471
468
|
if (commands === this.globalCommands.current())
|
|
472
469
|
return this.globalRunEvents.current();
|
|
473
|
-
const entry = this.
|
|
470
|
+
const entry = this.partitions
|
|
471
|
+
.healthy()
|
|
472
|
+
.find((candidate) => candidate.commands.current() === commands);
|
|
474
473
|
if (!entry)
|
|
475
474
|
throw new Error("command partition has no run-event authority");
|
|
476
475
|
return entry.runEvents.current();
|