@claudexor/cli 3.3.15 → 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/acp-surface-runner.d.ts +3 -2
- package/dist/acp-surface-runner.d.ts.map +1 -1
- package/dist/acp-surface-runner.js +20 -17
- package/dist/acp-surface-runner.js.map +1 -1
- package/dist/claudexord-entry.d.ts +7 -0
- package/dist/claudexord-entry.d.ts.map +1 -1
- package/dist/claudexord-entry.js +14 -0
- package/dist/claudexord-entry.js.map +1 -1
- package/dist/claudexord.d.ts +0 -10
- package/dist/claudexord.d.ts.map +1 -1
- package/dist/claudexord.js +95 -100
- package/dist/claudexord.js.map +1 -1
- package/dist/cli.js +10 -12
- package/dist/cli.js.map +1 -1
- package/dist/control-services.d.ts +4 -1
- package/dist/control-services.d.ts.map +1 -1
- package/dist/control-services.js +22 -21
- package/dist/control-services.js.map +1 -1
- package/dist/daemon-admission-runtime.d.ts +63 -0
- package/dist/daemon-admission-runtime.d.ts.map +1 -0
- package/dist/daemon-admission-runtime.js +180 -0
- package/dist/daemon-admission-runtime.js.map +1 -0
- package/dist/daemon-launch.d.ts +53 -0
- package/dist/daemon-launch.d.ts.map +1 -0
- package/dist/daemon-launch.js +211 -0
- package/dist/daemon-launch.js.map +1 -0
- package/dist/daemon-lifecycle.d.ts +14 -2
- package/dist/daemon-lifecycle.d.ts.map +1 -1
- package/dist/daemon-lifecycle.js +53 -10
- package/dist/daemon-lifecycle.js.map +1 -1
- package/dist/daemon-run.d.ts +7 -1
- package/dist/daemon-run.d.ts.map +1 -1
- package/dist/daemon-run.js +76 -20
- package/dist/daemon-run.js.map +1 -1
- package/dist/daemon-start-report.d.ts +8 -0
- package/dist/daemon-start-report.d.ts.map +1 -0
- package/dist/daemon-start-report.js +24 -0
- package/dist/daemon-start-report.js.map +1 -0
- package/dist/daemon-startup.d.ts +90 -0
- package/dist/daemon-startup.d.ts.map +1 -0
- package/dist/daemon-startup.js +156 -0
- package/dist/daemon-startup.js.map +1 -0
- package/dist/delegation-belt-descriptor.d.ts +1 -1
- package/dist/delegation-belt-descriptor.js +1 -1
- package/dist/engine-skew.d.ts +4 -0
- package/dist/engine-skew.d.ts.map +1 -1
- package/dist/engine-skew.js +10 -3
- package/dist/engine-skew.js.map +1 -1
- package/dist/mcp-run-projections.d.ts +78 -1
- package/dist/mcp-run-projections.d.ts.map +1 -1
- package/dist/mcp-run-projections.js +57 -3
- package/dist/mcp-run-projections.js.map +1 -1
- package/dist/mcp-runner.d.ts.map +1 -1
- package/dist/mcp-runner.js +41 -37
- package/dist/mcp-runner.js.map +1 -1
- package/dist/ops-commands.d.ts +9 -0
- package/dist/ops-commands.d.ts.map +1 -1
- package/dist/ops-commands.js +62 -67
- package/dist/ops-commands.js.map +1 -1
- package/dist/ops-harness-selection.d.ts +6 -0
- package/dist/ops-harness-selection.d.ts.map +1 -0
- package/dist/ops-harness-selection.js +29 -0
- package/dist/ops-harness-selection.js.map +1 -0
- package/dist/orphan-sweeper.js +13 -3
- package/dist/orphan-sweeper.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +1 -0
- package/dist/registry.js.map +1 -1
- package/dist/remote-command.d.ts +10 -1
- package/dist/remote-command.d.ts.map +1 -1
- package/dist/remote-command.js +34 -10
- package/dist/remote-command.js.map +1 -1
- package/dist/runtime-replacement-stop.d.ts +13 -2
- package/dist/runtime-replacement-stop.d.ts.map +1 -1
- package/dist/runtime-replacement-stop.js +46 -11
- package/dist/runtime-replacement-stop.js.map +1 -1
- package/dist/setup-lifecycle-binding.d.ts +7 -1
- package/dist/setup-lifecycle-binding.d.ts.map +1 -1
- package/dist/setup-lifecycle-binding.js +27 -17
- package/dist/setup-lifecycle-binding.js.map +1 -1
- package/dist/startup-diagnostics.d.ts +61 -0
- package/dist/startup-diagnostics.d.ts.map +1 -0
- package/dist/startup-diagnostics.js +416 -0
- package/dist/startup-diagnostics.js.map +1 -0
- package/dist/thread-turn-services.d.ts +1 -1
- package/dist/thread-turn-services.d.ts.map +1 -1
- package/dist/thread-turn-services.js.map +1 -1
- package/package.json +23 -23
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claudexord's startup-admission runtime, kept out of main() so the
|
|
3
|
+
* entrypoint stays a thin composition root:
|
|
4
|
+
*
|
|
5
|
+
* - C8: the best-effort post-authority diagnostics opener with launch
|
|
6
|
+
* provenance (a diagnostics failure never controls daemon lifecycle);
|
|
7
|
+
* - the quota poller armed only on normal admission (C1a);
|
|
8
|
+
* - D5 stage 4 as ONE single-flight completion shared by the startup path
|
|
9
|
+
* and the C6b recovery-route reopen, which re-runs it with a LIVE
|
|
10
|
+
* re-verdict so the daemon transitions to normal without a restart.
|
|
11
|
+
*/
|
|
12
|
+
import { type DaemonServingMode, type JournalManager, type ProjectPartitions, type RootAuthorityGrant } from "@claudexor/daemon";
|
|
13
|
+
import { type DaemonStartupAdmission } from "./daemon-startup.js";
|
|
14
|
+
import { type DaemonStartupDiagnostics } from "./startup-diagnostics.js";
|
|
15
|
+
export interface StartupDiagnosticsHandle {
|
|
16
|
+
diagnostics: DaemonStartupDiagnostics | null;
|
|
17
|
+
recordStage(stage: string, message: string): void;
|
|
18
|
+
recordFailure(message: string, error: unknown): void;
|
|
19
|
+
close(): void;
|
|
20
|
+
}
|
|
21
|
+
/** C8: open the private post-authority diagnostics with full launch
|
|
22
|
+
* provenance (runtime identity, entry path, pid, data root, and the
|
|
23
|
+
* CLAUDEXOR_DAEMON_LAUNCH_SOURCE value coerced to a safe label). */
|
|
24
|
+
export declare function openStartupDiagnostics(identity: {
|
|
25
|
+
version: string;
|
|
26
|
+
sha: string;
|
|
27
|
+
entry: string;
|
|
28
|
+
}): StartupDiagnosticsHandle;
|
|
29
|
+
/** C1a/G-QUOTA-01: quota polling belongs to the NORMAL plane — polling
|
|
30
|
+
* against unactivated projections is a swallowed throw, and the recovery
|
|
31
|
+
* plane must stay non-mutating. Arming polls immediately, removing the
|
|
32
|
+
* one-minute stale window the swallowed stage-2 poll used to leave. */
|
|
33
|
+
export declare function createDaemonQuotaPoller(poll: () => void): {
|
|
34
|
+
arm(): void;
|
|
35
|
+
stop(): void;
|
|
36
|
+
};
|
|
37
|
+
/** The composition root's normal-plane duties, run exactly once from either
|
|
38
|
+
* the startup path or the C6b reopen (C1a quota arming, C2 pid snapshots,
|
|
39
|
+
* C5a retired-key sweep persistence, setup binding, ghost quarantine,
|
|
40
|
+
* startup retention). */
|
|
41
|
+
export interface NormalPlaneDuties {
|
|
42
|
+
requested(): boolean;
|
|
43
|
+
armQuotaPolling(): void;
|
|
44
|
+
beginPidSnapshots(): void;
|
|
45
|
+
startSetup(): Promise<void>;
|
|
46
|
+
quarantineGhosts(): void;
|
|
47
|
+
scheduleRetention(): void;
|
|
48
|
+
}
|
|
49
|
+
/** D5 stage 4, single-flight: the startup path runs it with the frozen
|
|
50
|
+
* stage-2 verdict; the C6b recovery-route reopen re-runs it with a live one.
|
|
51
|
+
* Concurrent callers join the in-flight completion. */
|
|
52
|
+
export declare function createStartupAdmissionRuntime(input: {
|
|
53
|
+
admission: DaemonStartupAdmission;
|
|
54
|
+
grant: Pick<RootAuthorityGrant, "advanceFloor">;
|
|
55
|
+
global: JournalManager;
|
|
56
|
+
partitions: ProjectPartitions;
|
|
57
|
+
diagnostics: StartupDiagnosticsHandle;
|
|
58
|
+
normalPlane: NormalPlaneDuties;
|
|
59
|
+
}): {
|
|
60
|
+
runAdmissionCompletion(blockedPartitions: () => string[]): Promise<DaemonServingMode>;
|
|
61
|
+
wrapQuarantineWithReopen<T>(service: (partition: string, request: unknown) => Promise<T>): (partition: string, request: unknown) => Promise<T>;
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=daemon-admission-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-admission-runtime.d.ts","sourceRoot":"","sources":["../src/daemon-admission-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC7C,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAClD,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACrD,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;oEAEoE;AACpE,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,wBAAwB,CAoC3B;AAED;;;uEAGuE;AACvE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,IAAI,GAAG;IAAE,GAAG,IAAI,IAAI,CAAC;IAAC,IAAI,IAAI,IAAI,CAAA;CAAE,CAcvF;AAED;;;yBAGyB;AACzB,MAAM,WAAW,iBAAiB;IAChC,SAAS,IAAI,OAAO,CAAC;IACrB,eAAe,IAAI,IAAI,CAAC;IACxB,iBAAiB,IAAI,IAAI,CAAC;IAC1B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,gBAAgB,IAAI,IAAI,CAAC;IACzB,iBAAiB,IAAI,IAAI,CAAC;CAC3B;AAED;;uDAEuD;AACvD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IACnD,SAAS,EAAE,sBAAsB,CAAC;IAClC,KAAK,EAAE,IAAI,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;IAChD,MAAM,EAAE,cAAc,CAAC;IACvB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,WAAW,EAAE,wBAAwB,CAAC;IACtC,WAAW,EAAE,iBAAiB,CAAC;CAChC,GAAG;IACF,sBAAsB,CAAC,iBAAiB,EAAE,MAAM,MAAM,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACtF,wBAAwB,CAAC,CAAC,EACxB,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,GAC3D,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CACxD,CA4GA"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claudexord's startup-admission runtime, kept out of main() so the
|
|
3
|
+
* entrypoint stays a thin composition root:
|
|
4
|
+
*
|
|
5
|
+
* - C8: the best-effort post-authority diagnostics opener with launch
|
|
6
|
+
* provenance (a diagnostics failure never controls daemon lifecycle);
|
|
7
|
+
* - the quota poller armed only on normal admission (C1a);
|
|
8
|
+
* - D5 stage 4 as ONE single-flight completion shared by the startup path
|
|
9
|
+
* and the C6b recovery-route reopen, which re-runs it with a LIVE
|
|
10
|
+
* re-verdict so the daemon transitions to normal without a restart.
|
|
11
|
+
*/
|
|
12
|
+
import { daemonDir, logPath, } from "@claudexor/daemon";
|
|
13
|
+
import { sweepRetiredConfigKeysAtStartup } from "@claudexor/config";
|
|
14
|
+
import { redactSecrets } from "@claudexor/util";
|
|
15
|
+
import { DAEMON_LAUNCH_SOURCE_ENV } from "./daemon-launch.js";
|
|
16
|
+
import { logLine, runStartupCrashGc } from "./daemon-lifecycle.js";
|
|
17
|
+
import { completeStartupAdmission, recoveryBlockedPartitions, } from "./daemon-startup.js";
|
|
18
|
+
import { openDaemonStartupDiagnosticsAfterAuthority, safeDaemonLaunchSource, } from "./startup-diagnostics.js";
|
|
19
|
+
/** C8: open the private post-authority diagnostics with full launch
|
|
20
|
+
* provenance (runtime identity, entry path, pid, data root, and the
|
|
21
|
+
* CLAUDEXOR_DAEMON_LAUNCH_SOURCE value coerced to a safe label). */
|
|
22
|
+
export function openStartupDiagnostics(identity) {
|
|
23
|
+
let diagnostics = null;
|
|
24
|
+
try {
|
|
25
|
+
diagnostics = openDaemonStartupDiagnosticsAfterAuthority({
|
|
26
|
+
runtimeVersion: identity.version,
|
|
27
|
+
buildSha: identity.sha,
|
|
28
|
+
entryPath: identity.entry,
|
|
29
|
+
pid: process.pid,
|
|
30
|
+
dataRoot: daemonDir(),
|
|
31
|
+
launchSource: safeDaemonLaunchSource(process.env[DAEMON_LAUNCH_SOURCE_ENV]),
|
|
32
|
+
});
|
|
33
|
+
diagnostics.record({
|
|
34
|
+
stage: "root_authority_won",
|
|
35
|
+
message: "root authority acquired; startup diagnostics online",
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
logLine(logPath(), `startup diagnostics unavailable: ${redactSecrets(error instanceof Error ? error.message : String(error))}`);
|
|
40
|
+
}
|
|
41
|
+
const record = (value) => {
|
|
42
|
+
try {
|
|
43
|
+
diagnostics?.record(value);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
/* diagnostics never control lifecycle */
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
diagnostics,
|
|
51
|
+
recordStage: (stage, message) => record({ stage, message }),
|
|
52
|
+
recordFailure: (message, error) => record({ stage: "startup_failure", message, error }),
|
|
53
|
+
close: () => diagnostics?.close(),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/** C1a/G-QUOTA-01: quota polling belongs to the NORMAL plane — polling
|
|
57
|
+
* against unactivated projections is a swallowed throw, and the recovery
|
|
58
|
+
* plane must stay non-mutating. Arming polls immediately, removing the
|
|
59
|
+
* one-minute stale window the swallowed stage-2 poll used to leave. */
|
|
60
|
+
export function createDaemonQuotaPoller(poll) {
|
|
61
|
+
let timer = null;
|
|
62
|
+
return {
|
|
63
|
+
arm: () => {
|
|
64
|
+
if (timer)
|
|
65
|
+
return;
|
|
66
|
+
timer = setInterval(poll, 60_000);
|
|
67
|
+
timer.unref();
|
|
68
|
+
poll();
|
|
69
|
+
},
|
|
70
|
+
stop: () => {
|
|
71
|
+
if (timer)
|
|
72
|
+
clearInterval(timer);
|
|
73
|
+
timer = null;
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** D5 stage 4, single-flight: the startup path runs it with the frozen
|
|
78
|
+
* stage-2 verdict; the C6b recovery-route reopen re-runs it with a live one.
|
|
79
|
+
* Concurrent callers join the in-flight completion. */
|
|
80
|
+
export function createStartupAdmissionRuntime(input) {
|
|
81
|
+
// Normal-plane side effects run exactly once, from whichever path opened
|
|
82
|
+
// normal admission first.
|
|
83
|
+
let normalAdmissionCompleted = false;
|
|
84
|
+
const onNormalAdmission = async () => {
|
|
85
|
+
if (normalAdmissionCompleted || input.normalPlane.requested())
|
|
86
|
+
return;
|
|
87
|
+
normalAdmissionCompleted = true;
|
|
88
|
+
input.normalPlane.armQuotaPolling();
|
|
89
|
+
// Crash-GC has consumed the previous life's pids.json by now; live
|
|
90
|
+
// snapshots may own the file again (C2).
|
|
91
|
+
input.normalPlane.beginPidSnapshots();
|
|
92
|
+
// Same-root config evolution hygiene (B9): persist the retired-key sweep
|
|
93
|
+
// only on the NORMAL plane (C5a). Pre-admission parses already tolerate
|
|
94
|
+
// retired keys via loadConfig's in-memory strip; unknown keys NOT on the
|
|
95
|
+
// retired registry still fail loud (INV-021).
|
|
96
|
+
for (const sweep of sweepRetiredConfigKeysAtStartup()) {
|
|
97
|
+
logLine(logPath(), `swept retired config keys from ${sweep.path}: ${sweep.removed.join(", ")}`);
|
|
98
|
+
}
|
|
99
|
+
await input.normalPlane.startSetup();
|
|
100
|
+
input.normalPlane.quarantineGhosts();
|
|
101
|
+
input.normalPlane.scheduleRetention();
|
|
102
|
+
};
|
|
103
|
+
let admissionCompletion = null;
|
|
104
|
+
const runAdmissionCompletion = (blockedPartitions) => {
|
|
105
|
+
if (input.admission.snapshot() === "normal")
|
|
106
|
+
return Promise.resolve("normal");
|
|
107
|
+
admissionCompletion ??= (async () => {
|
|
108
|
+
try {
|
|
109
|
+
const servingMode = await completeStartupAdmission({
|
|
110
|
+
grant: input.grant,
|
|
111
|
+
blockedPartitions: blockedPartitions(),
|
|
112
|
+
global: {
|
|
113
|
+
// A manager already reopened by a recovery-route quarantine
|
|
114
|
+
// (openGeneration) is live authority; only still-prepared state
|
|
115
|
+
// revalidates (the reopen runs over a mix of both).
|
|
116
|
+
revalidatePreparation: () => {
|
|
117
|
+
if (!input.global.ready())
|
|
118
|
+
input.global.revalidatePreparation();
|
|
119
|
+
},
|
|
120
|
+
activatePrepared: () => input.global.activatePrepared(),
|
|
121
|
+
recoverAfterStartup: () => input.global.recoverAfterStartup(),
|
|
122
|
+
},
|
|
123
|
+
partitions: input.partitions,
|
|
124
|
+
crashGc: () => runStartupCrashGc({
|
|
125
|
+
daemonDir: daemonDir(),
|
|
126
|
+
logPath: logPath(),
|
|
127
|
+
...(input.diagnostics.diagnostics
|
|
128
|
+
? { diagnostics: input.diagnostics.diagnostics }
|
|
129
|
+
: {}),
|
|
130
|
+
}),
|
|
131
|
+
admission: input.admission,
|
|
132
|
+
log: (message) => {
|
|
133
|
+
logLine(logPath(), message);
|
|
134
|
+
input.diagnostics.recordStage("startup_admission", message);
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
if (servingMode === "normal")
|
|
138
|
+
await onNormalAdmission();
|
|
139
|
+
return servingMode;
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
admissionCompletion = null;
|
|
143
|
+
}
|
|
144
|
+
})();
|
|
145
|
+
return admissionCompletion;
|
|
146
|
+
};
|
|
147
|
+
// C6b: after a successful recovery-route quarantine the daemon transitions
|
|
148
|
+
// to normal WITHOUT a restart, re-verdicting the CURRENT partition state.
|
|
149
|
+
const reopenAfterRecovery = async () => {
|
|
150
|
+
while (input.admission.snapshot() !== "normal") {
|
|
151
|
+
const joined = admissionCompletion;
|
|
152
|
+
if (joined) {
|
|
153
|
+
await joined.catch(() => { });
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const servingMode = await runAdmissionCompletion(() => recoveryBlockedPartitions({
|
|
157
|
+
globalPreparation: { inspection: input.global.inspect() },
|
|
158
|
+
partitionsPreparation: input.partitions.refreshPreparation(),
|
|
159
|
+
}));
|
|
160
|
+
if (servingMode !== "normal")
|
|
161
|
+
return; // partitions still block: stay protected
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
return {
|
|
165
|
+
runAdmissionCompletion,
|
|
166
|
+
wrapQuarantineWithReopen: (service) => async (partition, request) => {
|
|
167
|
+
const receipt = await service(partition, request);
|
|
168
|
+
try {
|
|
169
|
+
await reopenAfterRecovery();
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
// The quarantine itself SUCCEEDED; a failed reopen stays on the
|
|
173
|
+
// protected recovery plane and is disclosed.
|
|
174
|
+
logLine(logPath(), `recovery reopen failed; still serving recovery only: ${redactSecrets(error instanceof Error ? error.message : String(error))}`);
|
|
175
|
+
}
|
|
176
|
+
return receipt;
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=daemon-admission-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-admission-runtime.js","sourceRoot":"","sources":["../src/daemon-admission-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { CliError } from "./cli-error.js";
|
|
2
|
+
export declare const DAEMON_LAUNCH_SOURCE_ENV = "CLAUDEXOR_DAEMON_LAUNCH_SOURCE";
|
|
3
|
+
export declare const CLI_DAEMON_LAUNCH_SOURCES: {
|
|
4
|
+
readonly ensureDaemon: "cli_ensure_daemon";
|
|
5
|
+
readonly explicitStart: "cli_explicit_start";
|
|
6
|
+
};
|
|
7
|
+
export type CliDaemonLaunchSource = (typeof CLI_DAEMON_LAUNCH_SOURCES)[keyof typeof CLI_DAEMON_LAUNCH_SOURCES];
|
|
8
|
+
export type DaemonLaunchStderrEvidence = {
|
|
9
|
+
kind: "empty";
|
|
10
|
+
} | {
|
|
11
|
+
kind: "retained";
|
|
12
|
+
byteLength: number;
|
|
13
|
+
message: string;
|
|
14
|
+
} | {
|
|
15
|
+
kind: "oversize_discarded";
|
|
16
|
+
observedBytes: number;
|
|
17
|
+
limitBytes: number;
|
|
18
|
+
};
|
|
19
|
+
export type DaemonLaunchFailure = {
|
|
20
|
+
kind: "spawn_error";
|
|
21
|
+
message: string;
|
|
22
|
+
code?: string;
|
|
23
|
+
} | {
|
|
24
|
+
kind: "preclaim_exit";
|
|
25
|
+
exitCode: number | null;
|
|
26
|
+
signal: NodeJS.Signals | null;
|
|
27
|
+
stderr: DaemonLaunchStderrEvidence;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "startup_timeout";
|
|
30
|
+
timeoutMs: number;
|
|
31
|
+
stderr: DaemonLaunchStderrEvidence;
|
|
32
|
+
};
|
|
33
|
+
export interface DetachedDaemonLaunch {
|
|
34
|
+
readonly pid: number | null;
|
|
35
|
+
failure(): DaemonLaunchFailure | null;
|
|
36
|
+
waitForFailure(): Promise<DaemonLaunchFailure>;
|
|
37
|
+
markReady(): void;
|
|
38
|
+
callerError(stage: string, timeoutMs: number): CliError;
|
|
39
|
+
}
|
|
40
|
+
export interface LaunchDetachedDaemonOptions {
|
|
41
|
+
entryPath: string;
|
|
42
|
+
launchSource: CliDaemonLaunchSource;
|
|
43
|
+
env?: NodeJS.ProcessEnv;
|
|
44
|
+
nodePath?: string;
|
|
45
|
+
}
|
|
46
|
+
export declare function daemonLaunchEnvironment(source: NodeJS.ProcessEnv, launchSource: CliDaemonLaunchSource): NodeJS.ProcessEnv;
|
|
47
|
+
/**
|
|
48
|
+
* Spawn without an inherited canonical-log descriptor. Import, spawn and
|
|
49
|
+
* pre-claim exits remain bounded caller evidence; the daemon may start its own
|
|
50
|
+
* permanent diagnostic writer only after a separate root-authority decision.
|
|
51
|
+
*/
|
|
52
|
+
export declare function launchDetachedDaemon(options: LaunchDetachedDaemonOptions): DetachedDaemonLaunch;
|
|
53
|
+
//# sourceMappingURL=daemon-launch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-launch.d.ts","sourceRoot":"","sources":["../src/daemon-launch.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,eAAO,MAAM,wBAAwB,mCAAmC,CAAC;AAEzE,eAAO,MAAM,yBAAyB;aACpC,YAAY,EAAE,mBAAmB;aACjC,aAAa,EAAE,oBAAoB;CAC3B,CAAC;AAEX,MAAM,MAAM,qBAAqB,GAC/B,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,OAAO,yBAAyB,CAAC,CAAC;AAI7E,MAAM,MAAM,0BAA0B,GAClC;IACE,IAAI,EAAE,OAAO,CAAC;CACf,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,GACD;IACE,IAAI,EAAE,oBAAoB,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEN,MAAM,MAAM,mBAAmB,GAC3B;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GACD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,0BAA0B,CAAC;CACpC,GACD;IACE,IAAI,EAAE,iBAAiB,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,0BAA0B,CAAC;CACpC,CAAC;AAEN,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,IAAI,mBAAmB,GAAG,IAAI,CAAC;IACtC,cAAc,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC/C,SAAS,IAAI,IAAI,CAAC;IAClB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC;CACzD;AAED,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,qBAAqB,CAAC;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,CAAC,UAAU,EACzB,YAAY,EAAE,qBAAqB,GAClC,MAAM,CAAC,UAAU,CAEnB;AAoHD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,oBAAoB,CAuF/F"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/** Caller-visible daemon launch evidence before root authority exists. */
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { lstatSync } from "node:fs";
|
|
4
|
+
import { logPath } from "@claudexor/daemon";
|
|
5
|
+
import { safeProblemContext, safeProblemMessage, safeProblemRequiredActions, } from "@claudexor/util";
|
|
6
|
+
import { CliError } from "./cli-error.js";
|
|
7
|
+
export const DAEMON_LAUNCH_SOURCE_ENV = "CLAUDEXOR_DAEMON_LAUNCH_SOURCE";
|
|
8
|
+
export const CLI_DAEMON_LAUNCH_SOURCES = {
|
|
9
|
+
ensureDaemon: "cli_ensure_daemon",
|
|
10
|
+
explicitStart: "cli_explicit_start",
|
|
11
|
+
};
|
|
12
|
+
const DAEMON_LAUNCH_STDERR_RAW_LIMIT_BYTES = 64 * 1_024;
|
|
13
|
+
export function daemonLaunchEnvironment(source, launchSource) {
|
|
14
|
+
return { ...source, [DAEMON_LAUNCH_SOURCE_ENV]: launchSource };
|
|
15
|
+
}
|
|
16
|
+
function missingEntryError(entryPath, reason) {
|
|
17
|
+
return new CliError("operational", `cannot start the daemon: the selected entry is unavailable (${safeProblemMessage(reason)})`, {
|
|
18
|
+
code: "daemon_entry_missing",
|
|
19
|
+
retryable: false,
|
|
20
|
+
requiredActions: [
|
|
21
|
+
"Reinstall Claudexor or rebuild the matching runtime before retrying.",
|
|
22
|
+
"Use an eligible fixed runtime; do not fall back to an older daemon for this data root.",
|
|
23
|
+
],
|
|
24
|
+
context: safeProblemContext({ entryPath }),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function proveEntry(entryPath) {
|
|
28
|
+
try {
|
|
29
|
+
const stat = lstatSync(entryPath);
|
|
30
|
+
if (!stat.isFile() && !stat.isSymbolicLink()) {
|
|
31
|
+
throw missingEntryError(entryPath, "entry is not a file");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (error instanceof CliError)
|
|
36
|
+
throw error;
|
|
37
|
+
throw missingEntryError(entryPath, error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function canonicalLogRemedy() {
|
|
41
|
+
try {
|
|
42
|
+
return `Run \`claudexor daemon logs\` for the canonical post-authority log at ${logPath()}; a pre-authority failure may have no log record.`;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return "Run `claudexor daemon logs` for the canonical post-authority log; a pre-authority failure may have no log record.";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function capturePreAuthorityStderr(stream) {
|
|
49
|
+
let chunks = [];
|
|
50
|
+
let retainedBytes = 0;
|
|
51
|
+
let observedBytes = 0;
|
|
52
|
+
let oversize = false;
|
|
53
|
+
let discarded = false;
|
|
54
|
+
const onData = (chunk) => {
|
|
55
|
+
if (discarded)
|
|
56
|
+
return;
|
|
57
|
+
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
58
|
+
observedBytes += bytes.length;
|
|
59
|
+
if (oversize)
|
|
60
|
+
return;
|
|
61
|
+
if (observedBytes > DAEMON_LAUNCH_STDERR_RAW_LIMIT_BYTES) {
|
|
62
|
+
oversize = true;
|
|
63
|
+
chunks = [];
|
|
64
|
+
retainedBytes = 0;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
chunks.push(Buffer.from(bytes));
|
|
68
|
+
retainedBytes += bytes.length;
|
|
69
|
+
};
|
|
70
|
+
stream?.on("data", onData);
|
|
71
|
+
return {
|
|
72
|
+
evidence: () => {
|
|
73
|
+
if (oversize) {
|
|
74
|
+
return {
|
|
75
|
+
kind: "oversize_discarded",
|
|
76
|
+
observedBytes,
|
|
77
|
+
limitBytes: DAEMON_LAUNCH_STDERR_RAW_LIMIT_BYTES,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if (retainedBytes === 0)
|
|
81
|
+
return { kind: "empty" };
|
|
82
|
+
const raw = Buffer.concat(chunks, retainedBytes).toString("utf8");
|
|
83
|
+
return {
|
|
84
|
+
kind: "retained",
|
|
85
|
+
byteLength: retainedBytes,
|
|
86
|
+
message: safeProblemMessage(raw),
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
destroyAndDiscard: () => {
|
|
90
|
+
if (discarded)
|
|
91
|
+
return;
|
|
92
|
+
discarded = true;
|
|
93
|
+
chunks = [];
|
|
94
|
+
retainedBytes = 0;
|
|
95
|
+
stream?.off("data", onData);
|
|
96
|
+
stream?.destroy();
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function stderrMessage(evidence) {
|
|
101
|
+
switch (evidence.kind) {
|
|
102
|
+
case "empty":
|
|
103
|
+
return "; pre-authority stderr: empty";
|
|
104
|
+
case "retained":
|
|
105
|
+
return `; pre-authority stderr (retained): ${evidence.message}`;
|
|
106
|
+
case "oversize_discarded":
|
|
107
|
+
return `; pre-authority stderr: oversize_discarded after ${evidence.observedBytes} bytes (limit ${evidence.limitBytes})`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function failureMessage(failure) {
|
|
111
|
+
switch (failure.kind) {
|
|
112
|
+
case "spawn_error":
|
|
113
|
+
return `daemon launch failed before root authority: ${failure.message}`;
|
|
114
|
+
case "preclaim_exit":
|
|
115
|
+
return `daemon exited before it became ready (exit ${failure.exitCode ?? "null"}${failure.signal ? `, signal ${failure.signal}` : ""})${stderrMessage(failure.stderr)}`;
|
|
116
|
+
case "startup_timeout":
|
|
117
|
+
return `daemon did not become ready within ${Math.round(failure.timeoutMs / 1_000)}s${stderrMessage(failure.stderr)}`;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Spawn without an inherited canonical-log descriptor. Import, spawn and
|
|
122
|
+
* pre-claim exits remain bounded caller evidence; the daemon may start its own
|
|
123
|
+
* permanent diagnostic writer only after a separate root-authority decision.
|
|
124
|
+
*/
|
|
125
|
+
export function launchDetachedDaemon(options) {
|
|
126
|
+
proveEntry(options.entryPath);
|
|
127
|
+
let failure = null;
|
|
128
|
+
let ready = false;
|
|
129
|
+
let stderrCapture;
|
|
130
|
+
let resolveFailure;
|
|
131
|
+
const failurePromise = new Promise((resolve) => {
|
|
132
|
+
resolveFailure = resolve;
|
|
133
|
+
});
|
|
134
|
+
const settleFailure = (value) => {
|
|
135
|
+
if (failure || ready)
|
|
136
|
+
return;
|
|
137
|
+
failure = value;
|
|
138
|
+
resolveFailure?.(value);
|
|
139
|
+
};
|
|
140
|
+
const discardStderr = () => {
|
|
141
|
+
stderrCapture?.destroyAndDiscard();
|
|
142
|
+
stderrCapture = undefined;
|
|
143
|
+
};
|
|
144
|
+
let child;
|
|
145
|
+
try {
|
|
146
|
+
child = spawn(options.nodePath ?? process.execPath, [options.entryPath], {
|
|
147
|
+
detached: true,
|
|
148
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
149
|
+
env: daemonLaunchEnvironment(options.env ?? process.env, options.launchSource),
|
|
150
|
+
});
|
|
151
|
+
stderrCapture = capturePreAuthorityStderr(child.stderr);
|
|
152
|
+
child.once("error", (error) => {
|
|
153
|
+
const code = typeof error.code === "string"
|
|
154
|
+
? error.code
|
|
155
|
+
: undefined;
|
|
156
|
+
settleFailure({ kind: "spawn_error", message: safeProblemMessage(error), code });
|
|
157
|
+
discardStderr();
|
|
158
|
+
});
|
|
159
|
+
child.once("close", (exitCode, signal) => {
|
|
160
|
+
const stderr = stderrCapture?.evidence() ?? { kind: "empty" };
|
|
161
|
+
discardStderr();
|
|
162
|
+
settleFailure({ kind: "preclaim_exit", exitCode, signal, stderr });
|
|
163
|
+
});
|
|
164
|
+
child.unref();
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
const code = typeof error.code === "string"
|
|
168
|
+
? error.code
|
|
169
|
+
: undefined;
|
|
170
|
+
settleFailure({ kind: "spawn_error", message: safeProblemMessage(error), code });
|
|
171
|
+
}
|
|
172
|
+
const callerError = (stage, timeoutMs) => {
|
|
173
|
+
let observed = failure;
|
|
174
|
+
if (!observed) {
|
|
175
|
+
const timeoutFailure = {
|
|
176
|
+
kind: "startup_timeout",
|
|
177
|
+
timeoutMs,
|
|
178
|
+
stderr: stderrCapture?.evidence() ?? { kind: "empty" },
|
|
179
|
+
};
|
|
180
|
+
settleFailure(timeoutFailure);
|
|
181
|
+
discardStderr();
|
|
182
|
+
observed = failure ?? timeoutFailure;
|
|
183
|
+
}
|
|
184
|
+
return new CliError("operational", safeProblemMessage(failureMessage(observed)), {
|
|
185
|
+
code: "daemon_start_failed",
|
|
186
|
+
retryable: true,
|
|
187
|
+
requiredActions: safeProblemRequiredActions([
|
|
188
|
+
canonicalLogRemedy(),
|
|
189
|
+
"Verify that this CLI uses an eligible fixed runtime, then retry; stop an older root claimant explicitly if it still owns the root.",
|
|
190
|
+
]),
|
|
191
|
+
context: safeProblemContext({
|
|
192
|
+
stage,
|
|
193
|
+
timeoutMs,
|
|
194
|
+
entryPath: options.entryPath,
|
|
195
|
+
launchSource: options.launchSource,
|
|
196
|
+
failure: observed,
|
|
197
|
+
}),
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
pid: child?.pid ?? null,
|
|
202
|
+
failure: () => failure,
|
|
203
|
+
waitForFailure: () => (failure ? Promise.resolve(failure) : failurePromise),
|
|
204
|
+
markReady: () => {
|
|
205
|
+
ready = true;
|
|
206
|
+
discardStderr();
|
|
207
|
+
},
|
|
208
|
+
callerError,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=daemon-launch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-launch.js","sourceRoot":"","sources":["../src/daemon-launch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import type { DaemonStartupDiagnostics } from "./startup-diagnostics.js";
|
|
1
2
|
interface LifecycleDeps {
|
|
2
3
|
daemonDir: string;
|
|
3
|
-
|
|
4
|
+
/** Compatibility fallback until the shared composition root wires the sink. */
|
|
5
|
+
logPath?: string;
|
|
6
|
+
/** Narrow post-authority diagnostic port; it never controls lifecycle. */
|
|
7
|
+
diagnostics?: Pick<DaemonStartupDiagnostics, "record">;
|
|
4
8
|
/** Enter the shutdown state machine (DaemonRuntimeShutdown.beginShutdown). */
|
|
5
9
|
beginShutdown: (reason: string) => Promise<void>;
|
|
6
10
|
signals?: Pick<NodeJS.Process, "on" | "off">;
|
|
@@ -9,13 +13,21 @@ interface LifecycleDeps {
|
|
|
9
13
|
export declare const logLine: (path: string, message: string) => void;
|
|
10
14
|
/** Pre-start: kill surviving children of a previous daemon life, then GC
|
|
11
15
|
* envelopes/branches/tmp-homes nothing owns anymore. */
|
|
12
|
-
export declare function runStartupCrashGc(deps: Pick<LifecycleDeps, "daemonDir" | "logPath">): Promise<void>;
|
|
16
|
+
export declare function runStartupCrashGc(deps: Pick<LifecycleDeps, "daemonDir" | "diagnostics" | "logPath">): Promise<void>;
|
|
13
17
|
/**
|
|
14
18
|
* Post-start: periodic live-children snapshots (the reap list a crash leaves
|
|
15
19
|
* behind) and SIGTERM/SIGINT -> the shutdown state machine (abort children,
|
|
16
20
|
* persist, close, bounded escalation). Returns the finalizer for main()'s tail.
|
|
21
|
+
*
|
|
22
|
+
* The snapshot timer is NOT armed here: with zero live children a snapshot
|
|
23
|
+
* DELETES pids.json, and until stage-4 crash-GC has consumed the previous
|
|
24
|
+
* life's file that file is the only record of surviving children (C2). The
|
|
25
|
+
* composition root calls `beginPidSnapshots()` once admission is normal;
|
|
26
|
+
* recovery-only serving leaves the previous pids.json byte-untouched, and the
|
|
27
|
+
* finalizer writes a final snapshot only when snapshots were armed.
|
|
17
28
|
*/
|
|
18
29
|
export declare function armDaemonLifecycle(deps: LifecycleDeps): {
|
|
30
|
+
beginPidSnapshots: () => void;
|
|
19
31
|
finalize: () => void;
|
|
20
32
|
};
|
|
21
33
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon-lifecycle.d.ts","sourceRoot":"","sources":["../src/daemon-lifecycle.ts"],"names":[],"mappings":"AAaA,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"daemon-lifecycle.d.ts","sourceRoot":"","sources":["../src/daemon-lifecycle.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAEV,wBAAwB,EACzB,MAAM,0BAA0B,CAAC;AAElC,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,IAAI,CAAC,wBAAwB,EAAE,QAAQ,CAAC,CAAC;IACvD,8EAA8E;IAC9E,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,GAAG,KAAK,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,eAAO,MAAM,OAAO,SAAU,MAAM,WAAW,MAAM,KAAG,IAMvD,CAAC;AAiBF;wDACwD;AACxD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC,GACjE,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,aAAa,GAAG;IACvD,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB,CA0DA"}
|