@claudexor/cli 3.25.1 → 4.0.1
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-reset-services.d.ts +2 -2
- package/dist/account-reset-services.d.ts.map +1 -1
- package/dist/account-reset-services.js.map +1 -1
- package/dist/account-resource-query.d.ts +2 -2
- package/dist/account-resource-query.d.ts.map +1 -1
- package/dist/account-resource-query.js +3 -3
- package/dist/account-resource-query.js.map +1 -1
- package/dist/claude-statusline.d.ts +2 -4
- package/dist/claude-statusline.d.ts.map +1 -1
- package/dist/claude-statusline.js +6 -5
- package/dist/claude-statusline.js.map +1 -1
- package/dist/claudexord-entry.d.ts +7 -2
- package/dist/claudexord-entry.d.ts.map +1 -1
- package/dist/claudexord-entry.js +10 -3
- package/dist/claudexord-entry.js.map +1 -1
- package/dist/claudexord.d.ts +0 -1
- package/dist/claudexord.d.ts.map +1 -1
- package/dist/claudexord.js +308 -240
- package/dist/claudexord.js.map +1 -1
- package/dist/cli-error.js +3 -3
- package/dist/cli-error.js.map +1 -1
- package/dist/cli.js +4 -49
- package/dist/cli.js.map +1 -1
- package/dist/codex-quota-source.js +2 -2
- package/dist/codex-quota-source.js.map +1 -1
- package/dist/command-flags.d.ts.map +1 -1
- package/dist/command-flags.js +1 -0
- package/dist/command-flags.js.map +1 -1
- package/dist/command-registry.js +1 -1
- package/dist/command-registry.js.map +1 -1
- package/dist/continue-from-run.d.ts +7 -8
- package/dist/continue-from-run.d.ts.map +1 -1
- package/dist/continue-from-run.js +3 -4
- package/dist/continue-from-run.js.map +1 -1
- package/dist/control-api-address.d.ts +6 -0
- package/dist/control-api-address.d.ts.map +1 -0
- package/dist/control-api-address.js +53 -0
- package/dist/control-api-address.js.map +1 -0
- package/dist/control-services.d.ts +139 -115
- package/dist/control-services.d.ts.map +1 -1
- package/dist/control-services.js +11 -32
- package/dist/control-services.js.map +1 -1
- package/dist/daemon-admission-runtime.d.ts +0 -60
- package/dist/daemon-admission-runtime.d.ts.map +1 -1
- package/dist/daemon-admission-runtime.js +3 -168
- package/dist/daemon-admission-runtime.js.map +1 -1
- package/dist/daemon-agent-runner.d.ts +6 -3
- package/dist/daemon-agent-runner.d.ts.map +1 -1
- package/dist/daemon-agent-runner.js +2 -1
- package/dist/daemon-agent-runner.js.map +1 -1
- package/dist/daemon-lifecycle.d.ts +10 -3
- package/dist/daemon-lifecycle.d.ts.map +1 -1
- package/dist/daemon-lifecycle.js +16 -7
- package/dist/daemon-lifecycle.js.map +1 -1
- package/dist/daemon-owner.d.ts +7 -0
- package/dist/daemon-owner.d.ts.map +1 -0
- package/dist/daemon-owner.js +39 -0
- package/dist/daemon-owner.js.map +1 -0
- package/dist/daemon-run.d.ts +8 -1
- package/dist/daemon-run.d.ts.map +1 -1
- package/dist/daemon-run.js +31 -3
- package/dist/daemon-run.js.map +1 -1
- package/dist/daemon-runtime-shutdown.d.ts +1 -1
- package/dist/daemon-runtime-shutdown.d.ts.map +1 -1
- package/dist/daemon-runtime-shutdown.js +2 -2
- package/dist/daemon-runtime-shutdown.js.map +1 -1
- package/dist/daemon-startup.d.ts +5 -42
- package/dist/daemon-startup.d.ts.map +1 -1
- package/dist/daemon-startup.js +7 -85
- package/dist/daemon-startup.js.map +1 -1
- package/dist/daemon-status-report.d.ts +4 -0
- package/dist/daemon-status-report.d.ts.map +1 -0
- package/dist/daemon-status-report.js +39 -0
- package/dist/daemon-status-report.js.map +1 -0
- package/dist/engine-skew.d.ts +1 -0
- package/dist/engine-skew.d.ts.map +1 -1
- package/dist/engine-skew.js +6 -2
- package/dist/engine-skew.js.map +1 -1
- package/dist/harness-maintenance-service.d.ts +9 -222
- package/dist/harness-maintenance-service.d.ts.map +1 -1
- package/dist/harness-maintenance-service.js +7 -37
- package/dist/harness-maintenance-service.js.map +1 -1
- package/dist/live.d.ts +2 -5
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +2 -44
- package/dist/live.js.map +1 -1
- package/dist/mcp-catalog-query.d.ts +2 -1
- package/dist/mcp-catalog-query.d.ts.map +1 -1
- package/dist/mcp-catalog-query.js +6 -5
- package/dist/mcp-catalog-query.js.map +1 -1
- package/dist/mcp-daemon-unavailable.d.ts.map +1 -1
- package/dist/mcp-daemon-unavailable.js +4 -3
- package/dist/mcp-daemon-unavailable.js.map +1 -1
- package/dist/mcp-journal-recovery.d.ts.map +1 -1
- package/dist/mcp-journal-recovery.js +4 -4
- package/dist/mcp-journal-recovery.js.map +1 -1
- package/dist/mcp-runner.d.ts +1 -1
- package/dist/mcp-runner.d.ts.map +1 -1
- package/dist/mcp-runner.js +8 -6
- package/dist/mcp-runner.js.map +1 -1
- package/dist/mcp-thread-query.d.ts +1 -1
- package/dist/mcp-thread-query.d.ts.map +1 -1
- package/dist/mcp-thread-query.js +2 -2
- package/dist/mcp-thread-query.js.map +1 -1
- package/dist/model-operation-control.d.ts +375 -0
- package/dist/model-operation-control.d.ts.map +1 -0
- package/dist/model-operation-control.js +16 -0
- package/dist/model-operation-control.js.map +1 -0
- package/dist/model-services.d.ts +302 -91
- package/dist/model-services.d.ts.map +1 -1
- package/dist/model-services.js +5 -7
- package/dist/model-services.js.map +1 -1
- package/dist/ops-commands.d.ts +1 -8
- package/dist/ops-commands.d.ts.map +1 -1
- package/dist/ops-commands.js +13 -16
- package/dist/ops-commands.js.map +1 -1
- package/dist/orphan-reaper.d.ts +18 -0
- package/dist/orphan-reaper.d.ts.map +1 -1
- package/dist/orphan-reaper.js +50 -0
- package/dist/orphan-reaper.js.map +1 -1
- package/dist/plugin-cli.d.ts +3 -0
- package/dist/plugin-cli.d.ts.map +1 -0
- package/dist/plugin-cli.js +57 -0
- package/dist/plugin-cli.js.map +1 -0
- package/dist/plugin-mcp.d.ts +3 -0
- package/dist/plugin-mcp.d.ts.map +1 -0
- package/dist/plugin-mcp.js +116 -0
- package/dist/plugin-mcp.js.map +1 -0
- package/dist/plugin-runtime.d.ts +24 -0
- package/dist/plugin-runtime.d.ts.map +1 -0
- package/dist/plugin-runtime.js +113 -0
- package/dist/plugin-runtime.js.map +1 -0
- package/dist/plugins.d.ts +2 -0
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +92 -184
- package/dist/plugins.js.map +1 -1
- package/dist/project-command.d.ts +4 -1
- package/dist/project-command.d.ts.map +1 -1
- package/dist/project-command.js +14 -5
- package/dist/project-command.js.map +1 -1
- package/dist/quota-services.d.ts +6 -4
- package/dist/quota-services.d.ts.map +1 -1
- package/dist/quota-services.js +58 -23
- package/dist/quota-services.js.map +1 -1
- package/dist/recovery-control-services.d.ts +99 -0
- package/dist/recovery-control-services.d.ts.map +1 -0
- package/dist/recovery-control-services.js +32 -0
- package/dist/recovery-control-services.js.map +1 -0
- package/dist/remote-filesystem.d.ts +3 -3
- package/dist/remote-filesystem.d.ts.map +1 -1
- package/dist/remote-filesystem.js.map +1 -1
- package/dist/request-preflight.d.ts +2 -2
- package/dist/request-preflight.d.ts.map +1 -1
- package/dist/request-preflight.js.map +1 -1
- package/dist/retention-service.d.ts +3 -3
- package/dist/retention-service.d.ts.map +1 -1
- package/dist/settings-command.d.ts.map +1 -1
- package/dist/settings-command.js +7 -2
- package/dist/settings-command.js.map +1 -1
- package/dist/settings-service.d.ts +66 -6
- package/dist/settings-service.d.ts.map +1 -1
- package/dist/settings-service.js +1 -1
- package/dist/settings-service.js.map +1 -1
- package/dist/setup-client-pty.js +1 -1
- package/dist/setup-client-pty.js.map +1 -1
- package/dist/setup-credential-window.d.ts +4 -4
- package/dist/setup-credential-window.d.ts.map +1 -1
- package/dist/setup-credential-window.js +1 -1
- package/dist/setup-credential-window.js.map +1 -1
- package/dist/setup-device-code-disclosure.js +1 -1
- package/dist/setup-device-code-disclosure.js.map +1 -1
- package/dist/setup-job-persistence.d.ts +30 -0
- package/dist/setup-job-persistence.d.ts.map +1 -0
- package/dist/setup-job-persistence.js +3 -0
- package/dist/setup-job-persistence.js.map +1 -0
- package/dist/{setup-job-store.d.ts → setup-job-projection.d.ts} +9 -17
- package/dist/setup-job-projection.d.ts.map +1 -0
- package/dist/{setup-job-store.js → setup-job-projection.js} +29 -68
- package/dist/setup-job-projection.js.map +1 -0
- package/dist/setup-job-support.js +1 -1
- package/dist/setup-job-support.js.map +1 -1
- package/dist/setup-jobs.d.ts +3 -4
- package/dist/setup-jobs.d.ts.map +1 -1
- package/dist/setup-jobs.js +3 -3
- package/dist/setup-jobs.js.map +1 -1
- package/dist/setup-lifecycle-binding.js +1 -1
- package/dist/setup-lifecycle-binding.js.map +1 -1
- package/dist/setup-login-completion.js +1 -1
- package/dist/setup-login-completion.js.map +1 -1
- package/dist/sql-daemon-queries.d.ts +24 -0
- package/dist/sql-daemon-queries.d.ts.map +1 -0
- package/dist/sql-daemon-queries.js +41 -0
- package/dist/sql-daemon-queries.js.map +1 -0
- package/dist/sql-daemon-runtime.d.ts +1415 -0
- package/dist/sql-daemon-runtime.d.ts.map +1 -0
- package/dist/sql-daemon-runtime.js +94 -0
- package/dist/sql-daemon-runtime.js.map +1 -0
- package/dist/sql-daemon-storage.d.ts +40 -0
- package/dist/sql-daemon-storage.d.ts.map +1 -0
- package/dist/sql-daemon-storage.js +203 -0
- package/dist/sql-daemon-storage.js.map +1 -0
- package/dist/sql-import-publication.d.ts +19 -0
- package/dist/sql-import-publication.d.ts.map +1 -0
- package/dist/sql-import-publication.js +54 -0
- package/dist/sql-import-publication.js.map +1 -0
- package/dist/sql-setup-lifecycle.d.ts +15 -0
- package/dist/sql-setup-lifecycle.d.ts.map +1 -0
- package/dist/sql-setup-lifecycle.js +28 -0
- package/dist/sql-setup-lifecycle.js.map +1 -0
- package/dist/sql-setup-store.d.ts +7 -0
- package/dist/sql-setup-store.d.ts.map +1 -0
- package/dist/sql-setup-store.js +102 -0
- package/dist/sql-setup-store.js.map +1 -0
- package/dist/sql-startup-storage.d.ts +15 -0
- package/dist/sql-startup-storage.d.ts.map +1 -0
- package/dist/sql-startup-storage.js +75 -0
- package/dist/sql-startup-storage.js.map +1 -0
- package/dist/thread-delivery.d.ts +2 -2
- package/dist/thread-purge.d.ts +8 -2
- package/dist/thread-purge.d.ts.map +1 -1
- package/dist/thread-purge.js +37 -8
- package/dist/thread-purge.js.map +1 -1
- package/dist/thread-turn-services.d.ts +2 -2
- package/dist/thread-turn-services.d.ts.map +1 -1
- package/dist/thread-turn-services.js.map +1 -1
- package/package.json +25 -26
- package/dist/setup-job-store.d.ts.map +0 -1
- package/dist/setup-job-store.js.map +0 -1
package/dist/claudexord.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { DaemonLocalClient, DaemonServer, RunEventBus, quotaPacerFileStore, daemonDir, defaultSocketPath, acquireRootAuthority, ensureToken, ensureDaemonRuntimeRoot, logPath, socketAlive, loadEngineRuntime, recordAdmissionMemory, processMemoryFields, recoveryOnlyRefusal, } from "@claudexor/daemon";
|
|
5
5
|
import { DaemonControlApiServer } from "@claudexor/control-api";
|
|
6
|
-
import { createDaemonQuotaPoller,
|
|
7
|
-
import { armDaemonLifecycle,
|
|
8
|
-
import { bindRecoveryTransport,
|
|
6
|
+
import { createDaemonQuotaPoller, openStartupDiagnostics } from "./daemon-admission-runtime.js";
|
|
7
|
+
import { armDaemonLifecycle, runStartupCrashGc } from "./daemon-lifecycle.js";
|
|
8
|
+
import { bindRecoveryTransport, DaemonStartupAdmission, proveRecoveryTransport, quarantineGhostProjectsAtStartup, } from "./daemon-startup.js";
|
|
9
9
|
import { engineBuildIdentity, noProjectRepoRoot, redactSecrets } from "@claudexor/util";
|
|
10
|
-
import {
|
|
11
|
-
import { runtimeConcurrencyCaps } from "@claudexor/schema";
|
|
10
|
+
import { loadRuntimeConcurrencyCaps, sweepRetiredConfigKeysAtStartup } from "@claudexor/config";
|
|
12
11
|
import { scheduleStartupRetention } from "./retention-service.js";
|
|
13
12
|
import { controlServices } from "./control-services.js";
|
|
13
|
+
import { recoveryControlServices } from "./recovery-control-services.js";
|
|
14
14
|
import { AuthReadinessService } from "@claudexor/gateway";
|
|
15
15
|
import { bindCredentialMutationWindow } from "@claudexor/core";
|
|
16
16
|
import { buildGateway } from "./registry.js";
|
|
17
17
|
import { createSetupJobManager } from "./setup-jobs.js";
|
|
18
18
|
import { bustLoginCredentialState } from "./credential-status-invalidation.js";
|
|
19
|
-
import { SetupJobStore } from "./setup-job-store.js";
|
|
20
19
|
import { SetupLifecycleBinding } from "./setup-lifecycle-binding.js";
|
|
20
|
+
import { SqlSetupLifecycleSlot } from "./sql-setup-lifecycle.js";
|
|
21
21
|
import { DaemonRuntimeShutdown } from "./daemon-runtime-shutdown.js";
|
|
22
22
|
import { quotaRefreshers } from "./quota-refreshers.js";
|
|
23
23
|
import { dispatchClaudexordEntry, runIfDirectEntry, runProbeIfRequested, } from "./claudexord-entry.js";
|
|
@@ -25,289 +25,357 @@ import { createDelegationDaemonBinding } from "./delegation-daemon-binding.js";
|
|
|
25
25
|
import { quotaSubjectUniverseFromConfig } from "./quota-subject-universe.js";
|
|
26
26
|
import { runStartupAccountsMigration } from "./accounts-unified-migration.js";
|
|
27
27
|
import { runStopIfRequested } from "./runtime-replacement-stop.js";
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
28
|
+
import { createSqlDaemonExecutors } from "./sql-daemon-runtime.js";
|
|
29
|
+
import { SqlDaemonStorage } from "./sql-daemon-storage.js";
|
|
30
|
+
import { deferredCommands, sqlActivityRecords, sqlStartupRoots } from "./sql-daemon-queries.js";
|
|
31
|
+
import { threadPurgeEffect } from "./thread-purge.js";
|
|
32
|
+
import { accountResetServices } from "./account-reset-services.js";
|
|
32
33
|
export async function main() {
|
|
33
|
-
// Probe and identity-proven stop must run before any durable startup.
|
|
34
34
|
if (runProbeIfRequested(process.argv.slice(2)))
|
|
35
35
|
return;
|
|
36
36
|
if (await runStopIfRequested(process.argv.slice(2)))
|
|
37
37
|
return;
|
|
38
|
-
|
|
38
|
+
// Refuse unsupported Node/SQLite before touching the root or lease.
|
|
39
|
+
await loadEngineRuntime();
|
|
40
|
+
const identity = engineBuildIdentity();
|
|
39
41
|
ensureDaemonRuntimeRoot();
|
|
40
42
|
const socketPath = defaultSocketPath();
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// can still write, and releasing would let a successor acquire ownership
|
|
49
|
-
// beside them. On failure the lease dies with the process instead.
|
|
50
|
-
let releaseWriterLease = true;
|
|
43
|
+
const authority = acquireRootAuthority({ socketPath, version: identity.version });
|
|
44
|
+
const diagnostics = openStartupDiagnostics(identity);
|
|
45
|
+
const log = (message) => diagnostics.log("sql_runtime", message);
|
|
46
|
+
const admission = new DaemonStartupAdmission();
|
|
47
|
+
const abort = new AbortController();
|
|
48
|
+
let cleanShutdown = true;
|
|
49
|
+
let shutdown = null;
|
|
51
50
|
let lifecycle = null;
|
|
52
|
-
let
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
let control = null;
|
|
52
|
+
let opening = null;
|
|
53
|
+
let storage;
|
|
54
|
+
let setup = null;
|
|
55
|
+
let executors = null;
|
|
56
|
+
let server;
|
|
57
|
+
let listening = false;
|
|
58
|
+
let admissionFlight = null;
|
|
59
|
+
let dutiesFor = null;
|
|
60
|
+
const graph = () => storage.graph();
|
|
61
|
+
const quotaPoller = createDaemonQuotaPoller(() => {
|
|
62
|
+
if (admission.snapshot() !== "normal")
|
|
63
|
+
return;
|
|
64
|
+
void Promise.resolve()
|
|
65
|
+
.then(() => graph().quota.pollStale())
|
|
66
|
+
.catch((error) => log(`quota poll: ${String(error)}`));
|
|
67
|
+
});
|
|
68
|
+
let readiness;
|
|
69
|
+
function setupFor(value) {
|
|
70
|
+
return new SetupLifecycleBinding(new SqlSetupLifecycleSlot(daemonDir(), value), (store) => createSetupJobManager({
|
|
71
|
+
rootDir: daemonDir(),
|
|
72
|
+
store,
|
|
73
|
+
onCredentialStateMayHaveChanged: (harness) => bustLoginCredentialState(() => value.quota, readiness, harness),
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
56
76
|
try {
|
|
77
|
+
readiness = new AuthReadinessService(buildGateway({ includeFakes: false }), {
|
|
78
|
+
cwd: noProjectRepoRoot(),
|
|
79
|
+
});
|
|
57
80
|
const token = ensureToken();
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
if (await socketAlive(socketPath)) {
|
|
81
|
+
const caps = loadRuntimeConcurrencyCaps(noProjectRepoRoot());
|
|
82
|
+
if (await socketAlive(socketPath))
|
|
61
83
|
throw new Error(`a claudexor daemon is already listening on ${socketPath}; stop it first`);
|
|
62
|
-
}
|
|
63
84
|
const bus = new RunEventBus();
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
85
|
+
const delegation = createDelegationDaemonBinding();
|
|
86
|
+
const selfClient = new DaemonLocalClient(() => server);
|
|
87
|
+
const services = {};
|
|
88
|
+
const makeServer = () => {
|
|
89
|
+
const next = new DaemonServer({
|
|
90
|
+
socketPath,
|
|
91
|
+
token,
|
|
92
|
+
commands: deferredCommands(() => graph().commands),
|
|
93
|
+
runtimeConcurrencyCaps: caps,
|
|
94
|
+
servingMode: admission.snapshot,
|
|
95
|
+
storeFacts: () => storage.facts(),
|
|
96
|
+
delegationAuthority: delegation.authority,
|
|
97
|
+
runtimeIdentity: { version: identity.version, buildSha: identity.sha },
|
|
98
|
+
runtimeLeaseOwner: authority.lease.owner,
|
|
99
|
+
onCommandTerminal: (record) => executors?.onCommandTerminal(record),
|
|
100
|
+
onRunTerminal: (runId, threadId) => executors?.onRunTerminal(runId, threadId),
|
|
101
|
+
onTurnEnqueueFailed: (turnId, problem) => executors?.onTurnEnqueueFailed(turnId, problem),
|
|
102
|
+
onShutdownRequested: () => shutdown.beginShutdown("socket-rpc stop"),
|
|
103
|
+
onRuntimeReplacementRequested: () => shutdown.beginRuntimeReplacement(),
|
|
104
|
+
runner: (params, ctx) => {
|
|
105
|
+
if (!executors)
|
|
106
|
+
throw recoveryOnlyRefusal("runner");
|
|
107
|
+
return executors.runner(params, ctx);
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
delegation.bind(next);
|
|
111
|
+
return next;
|
|
112
|
+
};
|
|
113
|
+
server = makeServer();
|
|
114
|
+
const partition = (name) => storage.partition(name);
|
|
115
|
+
const recovery = recoveryControlServices({
|
|
116
|
+
partition,
|
|
117
|
+
setup: () => setup,
|
|
118
|
+
onValidated: (name, result) => {
|
|
119
|
+
if (result.status === "recovery_required" && name === "global")
|
|
120
|
+
admission.enterRecoveryOnly();
|
|
121
|
+
},
|
|
122
|
+
afterQuarantine: async () => {
|
|
123
|
+
try {
|
|
124
|
+
await completeAdmission();
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
admission.enterRecoveryOnly();
|
|
128
|
+
log(`recovery completed; reopening failed: ${String(error)}`);
|
|
129
|
+
}
|
|
130
|
+
},
|
|
105
131
|
});
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
132
|
+
const attach = (value) => {
|
|
133
|
+
if (!listening)
|
|
134
|
+
server = makeServer();
|
|
135
|
+
setup = setupFor(value);
|
|
136
|
+
executors = createSqlDaemonExecutors(value, {
|
|
137
|
+
client: selfClient,
|
|
138
|
+
authority: delegation.authority,
|
|
139
|
+
admission: (id) => server.admission(id),
|
|
140
|
+
authReadiness: () => readiness,
|
|
141
|
+
bus,
|
|
142
|
+
runtimeConcurrencyCaps: caps,
|
|
143
|
+
warn: log,
|
|
144
|
+
});
|
|
145
|
+
const threads = Object.assign(value.threads, { journal: partition });
|
|
146
|
+
const product = controlServices(value.interactions, value.liveInputs, () => value.projects, threads, setup, partition("global"), readiness, () => value.resources, () => value.quota, () => sqlActivityRecords(value.store), caps, value.purgeFiles);
|
|
147
|
+
const retention = executors.models.withRetention(product.runRetention);
|
|
148
|
+
product.runRetention = async (request) => {
|
|
149
|
+
const result = await retention(request);
|
|
150
|
+
if (!request.dry_run)
|
|
151
|
+
value.resources.pruneUploadBindings();
|
|
152
|
+
return result;
|
|
153
|
+
};
|
|
154
|
+
executors.harnessMaintenance.bind(product);
|
|
155
|
+
Object.assign(services, product, executors.models.routes, accountResetServices({ current: () => value.commands.current() }, { current: () => value.quota }), recovery);
|
|
156
|
+
};
|
|
157
|
+
storage = new SqlDaemonStorage({
|
|
158
|
+
rootDir: daemonDir(),
|
|
159
|
+
advanceFloor: () => authority.advanceFloor(),
|
|
160
|
+
graph: {
|
|
161
|
+
purgeFiles: threadPurgeEffect(noProjectRepoRoot()),
|
|
162
|
+
log,
|
|
163
|
+
refreshers: quotaRefreshers((record) => log(`quota.observation ${JSON.stringify(record)}`)),
|
|
164
|
+
subjects: quotaSubjectUniverseFromConfig,
|
|
165
|
+
pacerStore: quotaPacerFileStore(daemonDir()),
|
|
166
|
+
},
|
|
167
|
+
log,
|
|
168
|
+
onOpen: attach,
|
|
169
|
+
onCorrupt: (error) => {
|
|
170
|
+
admission.enterRecoveryOnly();
|
|
171
|
+
quotaPoller.stop();
|
|
172
|
+
log(`engine store recovery required: ${error.message}`);
|
|
173
|
+
void ensureRecoveryControl().catch((problem) => log(`recovery transport unavailable: ${String(problem)}`));
|
|
174
|
+
},
|
|
175
|
+
beforeClose: async () => {
|
|
176
|
+
admission.enterRecoveryOnly();
|
|
177
|
+
quotaPoller.stop();
|
|
178
|
+
setup?.beginDrain();
|
|
179
|
+
executors?.models.close();
|
|
180
|
+
await Promise.all([server.stopForStoreRecovery(), setup?.shutdown()]);
|
|
181
|
+
listening = false;
|
|
182
|
+
setup = null;
|
|
183
|
+
executors = null;
|
|
184
|
+
dutiesFor = null;
|
|
185
|
+
},
|
|
117
186
|
});
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
interactions,
|
|
124
|
-
liveInputs,
|
|
125
|
-
resources,
|
|
126
|
-
bus,
|
|
127
|
-
runtimeConcurrencyCaps: startupConcurrencyCaps,
|
|
187
|
+
Object.assign(services, recovery);
|
|
188
|
+
bindCredentialMutationWindow((harness) => {
|
|
189
|
+
if (!setup)
|
|
190
|
+
throw recoveryOnlyRefusal("setup");
|
|
191
|
+
return setup.current().credentialMutationOpen(harness);
|
|
128
192
|
});
|
|
129
|
-
|
|
130
|
-
|
|
193
|
+
let address = null;
|
|
194
|
+
let controlStarting = null;
|
|
195
|
+
const makeControl = () => new DaemonControlApiServer({
|
|
131
196
|
token,
|
|
132
|
-
|
|
133
|
-
|
|
197
|
+
daemon: selfClient,
|
|
198
|
+
port: Number(process.env.CLAUDEXOR_CONTROL_PORT ?? 0),
|
|
134
199
|
servingMode: admission.snapshot,
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
interactions.dropForRun(runId);
|
|
139
|
-
liveInputs.dropForRun(runId);
|
|
140
|
-
// Run-terminal is the one W12 path with no thread-store mutation to
|
|
141
|
-
// ride — the terminal changes the thread's presented state, so ping.
|
|
142
|
-
if (threadId)
|
|
143
|
-
threads.pingThreadHead(threadId);
|
|
144
|
-
},
|
|
145
|
-
onTurnEnqueueFailed: (turnId, problem) => threads.setTurnEnqueueError(turnId, problem),
|
|
146
|
-
onShutdownRequested: () => shutdownRuntime?.beginShutdown("socket-rpc stop") ??
|
|
147
|
-
Promise.reject(new Error("daemon shutdown coordinator is not initialized")),
|
|
148
|
-
onRuntimeReplacementRequested: () => {
|
|
149
|
-
if (!shutdownRuntime) {
|
|
150
|
-
throw Object.assign(new Error("daemon shutdown coordinator is not initialized"), {
|
|
151
|
-
code: "runtime_activity_unknown",
|
|
152
|
-
status: 503,
|
|
153
|
-
retryable: true,
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
return shutdownRuntime.beginRuntimeReplacement();
|
|
157
|
-
},
|
|
158
|
-
runtimeIdentity: { version: servingIdentity.version, buildSha: servingIdentity.sha },
|
|
159
|
-
runtimeLeaseOwner: rootAuthority.lease.owner,
|
|
160
|
-
runner: (params, ctx) => isModelOperation(params)
|
|
161
|
-
? models.operations.execute(params, ctx)
|
|
162
|
-
: maintenance.owns(params)
|
|
163
|
-
? maintenance.execute(params, ctx)
|
|
164
|
-
: agentRunner(params, ctx),
|
|
165
|
-
});
|
|
166
|
-
bindDelegationDaemon(server);
|
|
167
|
-
const authReadiness = new AuthReadinessService(buildGateway({ includeFakes: false }), {
|
|
168
|
-
cwd: noProjectRepoRoot(),
|
|
200
|
+
bus,
|
|
201
|
+
services,
|
|
202
|
+
terminalFilesPending: (id) => graph().terminalFiles.pending(id),
|
|
169
203
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
204
|
+
async function ensureRecoveryControl() {
|
|
205
|
+
if (shutdown?.requested())
|
|
206
|
+
return;
|
|
207
|
+
if (controlStarting)
|
|
208
|
+
return controlStarting;
|
|
209
|
+
if (control)
|
|
210
|
+
return;
|
|
211
|
+
control = makeControl();
|
|
212
|
+
log("recovery-required SQL state overrides CLAUDEXOR_NO_CONTROL_API=1 for recovery access");
|
|
213
|
+
controlStarting = bindRecoveryTransport({
|
|
214
|
+
server,
|
|
215
|
+
control,
|
|
216
|
+
requested: () => shutdown.requested(),
|
|
217
|
+
daemonDir: daemonDir(),
|
|
218
|
+
logPath: logPath(),
|
|
219
|
+
socketPath,
|
|
220
|
+
}).then((value) => {
|
|
221
|
+
address = value;
|
|
222
|
+
});
|
|
223
|
+
await controlStarting;
|
|
224
|
+
}
|
|
225
|
+
const importing = !existsSync(join(daemonDir(), "engine.sqlite")) && existsSync(join(daemonDir(), "journal"));
|
|
226
|
+
if (process.env.CLAUDEXOR_NO_CONTROL_API !== "1" || importing)
|
|
227
|
+
control = makeControl();
|
|
228
|
+
shutdown = new DaemonRuntimeShutdown({
|
|
180
229
|
daemon: {
|
|
181
230
|
stop: async () => {
|
|
182
|
-
|
|
183
|
-
models.close();
|
|
184
|
-
await
|
|
231
|
+
abort.abort();
|
|
232
|
+
executors?.models.close();
|
|
233
|
+
await server.stop();
|
|
234
|
+
await opening?.catch(() => { });
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
setup: {
|
|
238
|
+
hasActiveWork: () => {
|
|
239
|
+
if (!setup)
|
|
240
|
+
throw recoveryOnlyRefusal("setup activity");
|
|
241
|
+
return setup.hasActiveWork();
|
|
242
|
+
},
|
|
243
|
+
beginDrain: () => setup?.beginDrain(),
|
|
244
|
+
shutdown: async () => {
|
|
245
|
+
await setup?.shutdown();
|
|
185
246
|
},
|
|
186
247
|
},
|
|
187
|
-
setup: setupBinding,
|
|
188
248
|
control: () => control,
|
|
189
249
|
journal: {
|
|
190
|
-
close: () => {
|
|
191
|
-
quotaPoller
|
|
192
|
-
|
|
193
|
-
journalManager.close();
|
|
250
|
+
close: async () => {
|
|
251
|
+
quotaPoller.stop();
|
|
252
|
+
await storage?.close();
|
|
194
253
|
},
|
|
195
254
|
},
|
|
196
|
-
log
|
|
255
|
+
log,
|
|
197
256
|
});
|
|
198
|
-
// Services and retention read all partition activity directly, without self-RPC.
|
|
199
|
-
const services = controlServices(interactions, liveInputs, () => projectStoreSlot.current(), threads, setupBinding, journalManager, authReadiness, resources, () => quotaStoreSlot.current(), () => commandActivityRecords(threads.all().flatMap((store) => store.records())), startupConcurrencyCaps);
|
|
200
|
-
services.runRetention = models.withRetention(services.runRetention);
|
|
201
|
-
const accountControls = accountResetServices(commandStoreSlot, quotaStoreSlot);
|
|
202
|
-
Object.assign(services, models.routes, accountControls);
|
|
203
|
-
maintenance.bind(services);
|
|
204
|
-
control = !controlApiEnabledForStartup({
|
|
205
|
-
disabledByEnv: process.env.CLAUDEXOR_NO_CONTROL_API === "1",
|
|
206
|
-
blockedPartitions: startupBlockedPartitions,
|
|
207
|
-
log: (message) => logLine(logPath(), message),
|
|
208
|
-
})
|
|
209
|
-
? null
|
|
210
|
-
: new DaemonControlApiServer({
|
|
211
|
-
token,
|
|
212
|
-
daemon: new DaemonClient(socketPath, token),
|
|
213
|
-
port: Number(process.env.CLAUDEXOR_CONTROL_PORT ?? 0),
|
|
214
|
-
servingMode: admission.snapshot,
|
|
215
|
-
bus,
|
|
216
|
-
services,
|
|
217
|
-
});
|
|
218
257
|
lifecycle = armDaemonLifecycle({
|
|
219
258
|
daemonDir: daemonDir(),
|
|
220
259
|
logPath: logPath(),
|
|
221
|
-
...(
|
|
222
|
-
beginShutdown: (reason) =>
|
|
223
|
-
});
|
|
224
|
-
const { runAdmissionCompletion, wrapQuarantineWithReopen } = createStartupAdmissionRuntime({
|
|
225
|
-
admission,
|
|
226
|
-
grant: rootAuthority,
|
|
227
|
-
global: journalManager,
|
|
228
|
-
partitions: threads,
|
|
229
|
-
diagnostics: startupDiagnostics,
|
|
230
|
-
knownProjectRoots: () => {
|
|
231
|
-
const commands = commandStoreSlot.prepared();
|
|
232
|
-
return [...commandScopeRoots(commands.records()), ...commands.prunedScopeRoots()];
|
|
233
|
-
},
|
|
234
|
-
// Delegated runs (thread turns live in project partitions) keep their
|
|
235
|
-
// runtime scratch under the caller-owned execution root.
|
|
236
|
-
knownExecutionRoots: () => [
|
|
237
|
-
...commandExecutionRoots(commandStoreSlot.prepared().records()),
|
|
238
|
-
...threads.preparedExecutionRoots(),
|
|
239
|
-
],
|
|
240
|
-
normalPlane: {
|
|
241
|
-
requested: () => shutdownRuntime.requested(),
|
|
242
|
-
armQuotaPolling: () => quotaPoller.arm(),
|
|
243
|
-
beginPidSnapshots: () => lifecycle.beginPidSnapshots(),
|
|
244
|
-
migrateAccounts: () => runStartupAccountsMigration(threads, quotaStoreSlot.current(), (m) => logLine(logPath(), redactSecrets(m))),
|
|
245
|
-
startSetup: () => setupBinding.start(),
|
|
246
|
-
quarantineGhosts: () => quarantineGhostProjectsAtStartup(threads, (message) => logLine(logPath(), message)),
|
|
247
|
-
scheduleRetention: () => scheduleStartupRetention(services.runRetention, {
|
|
248
|
-
logPath: logPath(),
|
|
249
|
-
shuttingDown: () => shutdownRuntime.requested(),
|
|
250
|
-
}),
|
|
251
|
-
pruneCommandHistory: () => server.pruneHistory(),
|
|
252
|
-
armJournalMaintenance: () => journalMaintenance.arm(),
|
|
253
|
-
},
|
|
260
|
+
...(diagnostics.diagnostics ? { diagnostics: diagnostics.diagnostics } : {}),
|
|
261
|
+
beginShutdown: (reason) => shutdown.beginShutdown(reason),
|
|
254
262
|
});
|
|
255
|
-
|
|
256
|
-
// D5 stage 3: bind the REAL transport with product admission CLOSED, then
|
|
257
|
-
// prove self-health/exact identity through it before anything destructive.
|
|
258
|
-
const controlAddr = await bindRecoveryTransport({
|
|
263
|
+
address = await bindRecoveryTransport({
|
|
259
264
|
server,
|
|
260
265
|
control,
|
|
261
|
-
requested: () =>
|
|
266
|
+
requested: () => shutdown.requested(),
|
|
262
267
|
daemonDir: daemonDir(),
|
|
263
268
|
logPath: logPath(),
|
|
264
269
|
socketPath,
|
|
265
270
|
});
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
271
|
+
listening = !shutdown.requested();
|
|
272
|
+
async function completeAdmission() {
|
|
273
|
+
if (admissionFlight)
|
|
274
|
+
return admissionFlight;
|
|
275
|
+
if (shutdown.requested() || admission.snapshot() === "normal")
|
|
276
|
+
return;
|
|
277
|
+
const value = graph();
|
|
278
|
+
const blocked = storage.blockedPartitions();
|
|
279
|
+
if (blocked.length) {
|
|
280
|
+
admission.enterRecoveryOnly();
|
|
281
|
+
log(`recovery required: ${blocked.join(", ")}`);
|
|
282
|
+
await ensureRecoveryControl();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const work = async () => {
|
|
286
|
+
if (!listening) {
|
|
287
|
+
await server.start();
|
|
288
|
+
listening = true;
|
|
289
|
+
await proveRecoveryTransport({ socketPath, identity, token, control: address });
|
|
290
|
+
}
|
|
291
|
+
if (dutiesFor !== value) {
|
|
292
|
+
await value.recoverAfterStartup();
|
|
293
|
+
const roots = sqlStartupRoots(value.store);
|
|
294
|
+
await runStartupCrashGc({
|
|
295
|
+
daemonDir: daemonDir(),
|
|
296
|
+
logPath: logPath(),
|
|
297
|
+
knownProjectRoots: roots.projects,
|
|
298
|
+
knownExecutionRoots: roots.execution,
|
|
299
|
+
...(diagnostics.diagnostics ? { diagnostics: diagnostics.diagnostics } : {}),
|
|
300
|
+
});
|
|
301
|
+
if (shutdown.requested())
|
|
302
|
+
return;
|
|
303
|
+
for (const sweep of sweepRetiredConfigKeysAtStartup())
|
|
304
|
+
log(`swept retired config keys from ${sweep.path}: ${sweep.removed.join(", ")}`);
|
|
305
|
+
runStartupAccountsMigration(value.threads, value.quota, (message) => log(redactSecrets(message)));
|
|
306
|
+
server.pruneHistory();
|
|
307
|
+
await setup.start();
|
|
308
|
+
quarantineGhostProjectsAtStartup(value.threads, log);
|
|
309
|
+
if (shutdown.requested())
|
|
310
|
+
return;
|
|
311
|
+
dutiesFor = value;
|
|
312
|
+
}
|
|
313
|
+
admission.openNormal();
|
|
314
|
+
recordAdmissionMemory();
|
|
315
|
+
quotaPoller.arm();
|
|
316
|
+
lifecycle.beginPidSnapshots();
|
|
317
|
+
scheduleStartupRetention(services.runRetention, {
|
|
318
|
+
logPath: logPath(),
|
|
319
|
+
shuttingDown: () => shutdown.requested() || admission.snapshot() !== "normal",
|
|
320
|
+
});
|
|
321
|
+
void value.maintenance
|
|
322
|
+
.integrityCheck()
|
|
323
|
+
.then(async (result) => {
|
|
324
|
+
if (result.ok && admission.snapshot() === "normal")
|
|
325
|
+
await value.maintenance.sweepOrphans();
|
|
326
|
+
})
|
|
327
|
+
.catch((error) => log(`store maintenance: ${String(error)}`));
|
|
328
|
+
log(`startup admission: normal product admission open (${processMemoryFields()})`);
|
|
329
|
+
};
|
|
330
|
+
admissionFlight = work();
|
|
331
|
+
try {
|
|
332
|
+
await admissionFlight;
|
|
333
|
+
}
|
|
334
|
+
finally {
|
|
335
|
+
admissionFlight = null;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (!shutdown.requested()) {
|
|
339
|
+
await proveRecoveryTransport({ socketPath, identity, token, control: address });
|
|
340
|
+
opening = storage.open(abort.signal).then(completeAdmission);
|
|
341
|
+
try {
|
|
342
|
+
await opening;
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
admission.enterRecoveryOnly();
|
|
346
|
+
log(`SQL startup remains recovery-only: ${redactSecrets(String(error))}`);
|
|
347
|
+
diagnostics.recordFailure("SQL startup remains recovery-only", error);
|
|
348
|
+
if (!shutdown.requested())
|
|
349
|
+
await ensureRecoveryControl();
|
|
350
|
+
}
|
|
277
351
|
}
|
|
278
|
-
await
|
|
279
|
-
lifecycle.finalize();
|
|
280
|
-
|
|
281
|
-
|
|
352
|
+
await shutdown.wait();
|
|
353
|
+
await lifecycle.finalize();
|
|
354
|
+
log("claudexord shut down");
|
|
355
|
+
diagnostics.recordStage("shutdown_complete", "claudexord shut down");
|
|
282
356
|
}
|
|
283
357
|
catch (error) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
startupDiagnostics.recordFailure("daemon lifecycle FAILED", error);
|
|
288
|
-
if (shutdownRuntime) {
|
|
358
|
+
log(`daemon lifecycle FAILED: ${redactSecrets(String(error))}`);
|
|
359
|
+
diagnostics.recordFailure("daemon lifecycle FAILED", error);
|
|
360
|
+
if (shutdown) {
|
|
289
361
|
try {
|
|
290
|
-
await
|
|
291
|
-
lifecycle?.finalize();
|
|
362
|
+
await shutdown.beginShutdown("startup failure");
|
|
363
|
+
await lifecycle?.finalize();
|
|
292
364
|
}
|
|
293
365
|
catch (shutdownError) {
|
|
294
|
-
|
|
295
|
-
releaseWriterLease = false;
|
|
366
|
+
cleanShutdown = false;
|
|
296
367
|
throw new AggregateError([error, shutdownError], "claudexord failed and could not complete shutdown");
|
|
297
368
|
}
|
|
298
369
|
}
|
|
299
370
|
throw error;
|
|
300
371
|
}
|
|
301
372
|
finally {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (releaseWriterLease)
|
|
307
|
-
rootAuthority.release();
|
|
373
|
+
quotaPoller.stop();
|
|
374
|
+
diagnostics.close();
|
|
375
|
+
if (cleanShutdown)
|
|
376
|
+
authority.release();
|
|
308
377
|
}
|
|
309
378
|
}
|
|
310
|
-
/** Explicit entry preserves import-side-effect freedom for daemon probes. */
|
|
311
379
|
export function runClaudexordEntry() {
|
|
312
380
|
dispatchClaudexordEntry(main);
|
|
313
381
|
}
|