@sift-wiki/conductor 0.1.0 → 0.2.0-beta.2
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/README.md +28 -58
- package/dist/adapters/claudeAgent.js +1 -0
- package/dist/adapters/claudeAgent.js.map +1 -1
- package/dist/adapters/codexAgent.js +1 -0
- package/dist/adapters/codexAgent.js.map +1 -1
- package/dist/adapters/fakeAgent.js +1 -0
- package/dist/adapters/fakeAgent.js.map +1 -1
- package/dist/adapters/httpAgent.js +1 -0
- package/dist/adapters/httpAgent.js.map +1 -1
- package/dist/adapters/processAgent.js +4 -0
- package/dist/adapters/processAgent.js.map +1 -1
- package/dist/adapters/provider/runProvider.js +4 -0
- package/dist/adapters/provider/runProvider.js.map +1 -1
- package/dist/adapters/provider/store.js +3 -4
- package/dist/adapters/provider/store.js.map +1 -1
- package/dist/adapters/types.d.ts +9 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.js +44 -3
- package/dist/cli.js.map +1 -1
- package/dist/conductorClient.d.ts +245 -17
- package/dist/conductorClient.js +147 -38
- package/dist/conductorClient.js.map +1 -1
- package/dist/config.js +4 -5
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +23 -6
- package/dist/daemon.js +173 -95
- package/dist/daemon.js.map +1 -1
- package/dist/desktop/app/contracts.d.ts +71 -0
- package/dist/desktop/app/contracts.js +19 -0
- package/dist/desktop/app/contracts.js.map +1 -0
- package/dist/desktop/app/controller.d.ts +58 -0
- package/dist/desktop/app/controller.js +161 -0
- package/dist/desktop/app/controller.js.map +1 -0
- package/dist/desktop/app/runtimeController.d.ts +29 -0
- package/dist/desktop/app/runtimeController.js +55 -0
- package/dist/desktop/app/runtimeController.js.map +1 -0
- package/dist/localApi/authorizedPairing.d.ts +12 -0
- package/dist/localApi/authorizedPairing.js +18 -0
- package/dist/localApi/authorizedPairing.js.map +1 -0
- package/dist/localApi/contracts.d.ts +264 -0
- package/dist/localApi/contracts.js +191 -0
- package/dist/localApi/contracts.js.map +1 -0
- package/dist/localApi/recovery.d.ts +66 -0
- package/dist/localApi/recovery.js +115 -0
- package/dist/localApi/recovery.js.map +1 -0
- package/dist/localApi/server.d.ts +20 -0
- package/dist/localApi/server.js +414 -0
- package/dist/localApi/server.js.map +1 -0
- package/dist/localApi/workConsole.d.ts +74 -0
- package/dist/localApi/workConsole.js +342 -0
- package/dist/localApi/workConsole.js.map +1 -0
- package/dist/localApi/workContracts.d.ts +213 -0
- package/dist/localApi/workContracts.js +130 -0
- package/dist/localApi/workContracts.js.map +1 -0
- package/dist/localApp/platform.d.ts +2 -0
- package/dist/localApp/platform.js +57 -0
- package/dist/localApp/platform.js.map +1 -0
- package/dist/localApp/service.d.ts +25 -0
- package/dist/localApp/service.js +126 -0
- package/dist/localApp/service.js.map +1 -0
- package/dist/protocol/fenced.d.ts +135 -0
- package/dist/protocol/fenced.js +142 -0
- package/dist/protocol/fenced.js.map +1 -0
- package/dist/redaction.js +2 -0
- package/dist/redaction.js.map +1 -1
- package/dist/runtime/atomicFile.d.ts +6 -0
- package/dist/runtime/atomicFile.js +78 -0
- package/dist/runtime/atomicFile.js.map +1 -0
- package/dist/runtime/daemonCapabilities.d.ts +7 -0
- package/dist/runtime/daemonCapabilities.js +24 -0
- package/dist/runtime/daemonCapabilities.js.map +1 -0
- package/dist/runtime/eventOutbox.d.ts +100 -0
- package/dist/runtime/eventOutbox.js +206 -0
- package/dist/runtime/eventOutbox.js.map +1 -0
- package/dist/runtime/executionJournal.d.ts +102 -0
- package/dist/runtime/executionJournal.js +209 -0
- package/dist/runtime/executionJournal.js.map +1 -0
- package/dist/runtime/executionSafety.d.ts +76 -0
- package/dist/runtime/executionSafety.js +207 -0
- package/dist/runtime/executionSafety.js.map +1 -0
- package/dist/runtime/fencedExecutionState.d.ts +43 -0
- package/dist/runtime/fencedExecutionState.js +158 -0
- package/dist/runtime/fencedExecutionState.js.map +1 -0
- package/dist/runtime/leaseManager.d.ts +38 -0
- package/dist/runtime/leaseManager.js +102 -0
- package/dist/runtime/leaseManager.js.map +1 -0
- package/dist/runtime/localLogSpool.d.ts +1 -0
- package/dist/runtime/localLogSpool.js +4 -0
- package/dist/runtime/localLogSpool.js.map +1 -1
- package/dist/runtime/localRunQueue.d.ts +1 -1
- package/dist/runtime/localRunQueue.js +8 -0
- package/dist/runtime/localRunQueue.js.map +1 -1
- package/dist/runtime/localSessionCache.d.ts +1 -1
- package/dist/runtime/localSessionCache.js.map +1 -1
- package/dist/runtime/process.d.ts +13 -1
- package/dist/runtime/process.js +39 -9
- package/dist/runtime/process.js.map +1 -1
- package/dist/runtime/recoveryCoordinator.d.ts +19 -0
- package/dist/runtime/recoveryCoordinator.js +183 -0
- package/dist/runtime/recoveryCoordinator.js.map +1 -0
- package/dist/runtime/runtimeLock.d.ts +33 -0
- package/dist/runtime/runtimeLock.js +140 -0
- package/dist/runtime/runtimeLock.js.map +1 -0
- package/dist/runtime/runtimeService.d.ts +6 -1
- package/dist/runtime/runtimeService.js +54 -20
- package/dist/runtime/runtimeService.js.map +1 -1
- package/dist/runtime/taskExecution.d.ts +2 -0
- package/dist/runtime/taskExecution.js +18 -12
- package/dist/runtime/taskExecution.js.map +1 -1
- package/dist/types.d.ts +28 -13
- package/dist/userAuth/service.d.ts +26 -0
- package/dist/userAuth/service.js +170 -0
- package/dist/userAuth/service.js.map +1 -0
- package/dist/userAuth/store.d.ts +42 -0
- package/dist/userAuth/store.js +160 -0
- package/dist/userAuth/store.js.map +1 -0
- package/dist/userAuth/types.d.ts +63 -0
- package/dist/userAuth/types.js +29 -0
- package/dist/userAuth/types.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/workTypes.d.ts +162 -31
- package/dist/workTypes.js +31 -0
- package/dist/workTypes.js.map +1 -1
- package/dist-web/assets/index-CWAdDb9V.js +72 -0
- package/dist-web/assets/index-CWfnzdLn.css +1 -0
- package/dist-web/index.html +15 -0
- package/docs/provider-setup.md +81 -0
- package/docs/quickstart.md +62 -0
- package/docs/troubleshooting.md +63 -0
- package/package.json +13 -3
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { ConductorApiError } from "../conductorClient.js";
|
|
2
|
+
export async function reconcileUnfinishedAttempts(input) {
|
|
3
|
+
const unfinished = await input.journalStore.listUnfinished();
|
|
4
|
+
if (unfinished.length === 0) {
|
|
5
|
+
return { reconciledAttempts: 0, resumedAttempts: 0, closedAttempts: 0, canClaim: true };
|
|
6
|
+
}
|
|
7
|
+
if (input.client.reconcileAttempt === undefined) {
|
|
8
|
+
throw new Error("Sift reconciliation is unavailable while unfinished fenced attempts exist.");
|
|
9
|
+
}
|
|
10
|
+
let resumedAttempts = 0;
|
|
11
|
+
let closedAttempts = 0;
|
|
12
|
+
let canClaim = true;
|
|
13
|
+
for (const entry of unfinished) {
|
|
14
|
+
const journal = await updateJournal(input, entry.journal, { phase: "recovering" });
|
|
15
|
+
const adapter = input.adapters.find((candidate) => candidate.localKey === journal.localKey);
|
|
16
|
+
const providerResumeSupported = adapter?.resumeSupport === "session";
|
|
17
|
+
const decision = await input.client.reconcileAttempt(input.credential, {
|
|
18
|
+
attemptId: journal.authority.attemptId,
|
|
19
|
+
leaseGeneration: journal.authority.leaseGeneration,
|
|
20
|
+
lastAcknowledgedClientSequence: journal.lastAcknowledgedClientSequence,
|
|
21
|
+
providerResumeSupported,
|
|
22
|
+
supervisedProcessRunning: false,
|
|
23
|
+
...(journal.terminalResult === undefined
|
|
24
|
+
? {}
|
|
25
|
+
: {
|
|
26
|
+
terminalResult: {
|
|
27
|
+
disposition: journal.terminalResult.status === "overtime"
|
|
28
|
+
? "failed"
|
|
29
|
+
: journal.terminalResult.status,
|
|
30
|
+
summary: { summary: journal.terminalResult.summary },
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
if (decision.decision === "resume") {
|
|
35
|
+
resumedAttempts += 1;
|
|
36
|
+
if (!providerResumeSupported && journal.terminalResult === undefined) {
|
|
37
|
+
await updateJournal(input, journal, {
|
|
38
|
+
phase: "interrupted",
|
|
39
|
+
interruptionReason: "Sift returned resume for a provider without verified safe resume support.",
|
|
40
|
+
});
|
|
41
|
+
canClaim = false;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const resumed = await applyResume(input, journal, { ...decision, decision: "resume" });
|
|
45
|
+
if (resumed.terminalResult === undefined)
|
|
46
|
+
canClaim = false;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (decision.decision === "stop" && !isTerminalCanonicalStatus(decision.canonicalStatus)) {
|
|
50
|
+
if (decision.cancellationRequested) {
|
|
51
|
+
try {
|
|
52
|
+
const settled = await settleCancellation(input, journal);
|
|
53
|
+
await updateJournal(input, journal, {
|
|
54
|
+
phase: "terminal",
|
|
55
|
+
terminalResult: journal.terminalResult ?? {
|
|
56
|
+
status: "cancelled",
|
|
57
|
+
summary: settled.summary,
|
|
58
|
+
},
|
|
59
|
+
interruptionReason: "Canonical cancellation confirmed during recovery.",
|
|
60
|
+
});
|
|
61
|
+
await input.outbox.discardAttempt(journal.attemptId);
|
|
62
|
+
closedAttempts += 1;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
canClaim = false;
|
|
67
|
+
await updateJournal(input, journal, {
|
|
68
|
+
phase: "recovering",
|
|
69
|
+
interruptionReason: `Cancellation settlement remains pending: ${errorMessage(error)}`,
|
|
70
|
+
});
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
canClaim = false;
|
|
75
|
+
await updateJournal(input, journal, {
|
|
76
|
+
phase: "recovering",
|
|
77
|
+
interruptionReason: decision.reason ?? "Sift returned stop while canonical work remains nonterminal.",
|
|
78
|
+
});
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
await updateJournal(input, journal, decisionJournalUpdate(decision));
|
|
82
|
+
await input.outbox.discardAttempt(journal.attemptId);
|
|
83
|
+
closedAttempts += 1;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
reconciledAttempts: unfinished.length,
|
|
87
|
+
resumedAttempts,
|
|
88
|
+
closedAttempts,
|
|
89
|
+
canClaim,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async function settleCancellation(input, journal) {
|
|
93
|
+
const summary = journal.terminalResult?.status === "cancelled"
|
|
94
|
+
? journal.terminalResult.summary
|
|
95
|
+
: "Stopped local execution after Sift cancellation during recovery.";
|
|
96
|
+
const options = {
|
|
97
|
+
authority: journal.authority,
|
|
98
|
+
idempotencyKey: journal.settlementIdempotencyKey ?? `recovery-cancel:${journal.attemptId}`,
|
|
99
|
+
};
|
|
100
|
+
if (journal.taskRecordId !== undefined) {
|
|
101
|
+
if (input.workClient === undefined) {
|
|
102
|
+
throw new Error("Task cancellation settlement client is unavailable.");
|
|
103
|
+
}
|
|
104
|
+
await input.workClient.setTaskDisposition(input.credential, journal.runId, journal.taskRecordId, "cancelled", { summary }, options);
|
|
105
|
+
return { summary };
|
|
106
|
+
}
|
|
107
|
+
if (input.client.acknowledgeCancellation === undefined) {
|
|
108
|
+
throw new Error("Run cancellation settlement client is unavailable.");
|
|
109
|
+
}
|
|
110
|
+
await input.client.acknowledgeCancellation(input.credential, journal.runId, { summary }, options);
|
|
111
|
+
return { summary };
|
|
112
|
+
}
|
|
113
|
+
function isTerminalCanonicalStatus(status) {
|
|
114
|
+
return status === "completed" || status === "failed" || status === "cancelled";
|
|
115
|
+
}
|
|
116
|
+
function errorMessage(error) {
|
|
117
|
+
return error instanceof Error ? error.message : "Unknown cancellation settlement failure.";
|
|
118
|
+
}
|
|
119
|
+
async function applyResume(input, journal, decision) {
|
|
120
|
+
if (decision.authority === undefined) {
|
|
121
|
+
throw new Error("Resume reconciliation omitted refreshed authority.");
|
|
122
|
+
}
|
|
123
|
+
let next = await updateJournal(input, journal, {
|
|
124
|
+
authority: decision.authority,
|
|
125
|
+
lastAcknowledgedClientSequence: Math.max(journal.lastAcknowledgedClientSequence, decision.lastAcknowledgedClientSequence),
|
|
126
|
+
phase: "recovering",
|
|
127
|
+
});
|
|
128
|
+
await input.outbox.acknowledge(next.attemptId, next.lastAcknowledgedClientSequence);
|
|
129
|
+
for (const entry of await input.outbox.listAttempt(next.attemptId)) {
|
|
130
|
+
let response;
|
|
131
|
+
try {
|
|
132
|
+
response = await input.client.appendRunEvent(input.credential, next.runId, {
|
|
133
|
+
eventType: entry.event.eventType,
|
|
134
|
+
...(entry.event.payload === undefined ? {} : { payload: entry.event.payload }),
|
|
135
|
+
...(entry.event.occurredAt === undefined ? {} : { occurredAt: entry.event.occurredAt }),
|
|
136
|
+
clientEventId: entry.clientEventId,
|
|
137
|
+
clientSequence: entry.clientSequence,
|
|
138
|
+
authority: next.authority,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (error instanceof ConductorApiError && error.disposition === "retryable")
|
|
143
|
+
throw error;
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
const acknowledged = acknowledgementSequence(response);
|
|
147
|
+
if (acknowledged === undefined) {
|
|
148
|
+
throw new Error("Fenced event delivery response omitted acknowledgedClientSequence.");
|
|
149
|
+
}
|
|
150
|
+
await input.outbox.acknowledge(next.attemptId, acknowledged);
|
|
151
|
+
next = await updateJournal(input, next, {
|
|
152
|
+
lastAcknowledgedClientSequence: Math.max(next.lastAcknowledgedClientSequence, acknowledged),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return next;
|
|
156
|
+
}
|
|
157
|
+
function decisionJournalUpdate(decision) {
|
|
158
|
+
switch (decision.decision) {
|
|
159
|
+
case "already_terminal":
|
|
160
|
+
return { phase: "terminal", interruptionReason: decision.reason ?? "Canonical run is already terminal." };
|
|
161
|
+
case "superseded":
|
|
162
|
+
return { phase: "superseded", interruptionReason: decision.reason ?? "Another attempt owns this work." };
|
|
163
|
+
case "stop":
|
|
164
|
+
return { phase: "interrupted", interruptionReason: decision.reason ?? "Sift instructed local execution to stop." };
|
|
165
|
+
case "retry_as_new_attempt":
|
|
166
|
+
return { phase: "interrupted", interruptionReason: decision.reason ?? "Retry requires a new fenced attempt." };
|
|
167
|
+
case "resume":
|
|
168
|
+
throw new Error("Resume decisions require refreshed authority handling.");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async function updateJournal(input, journal, update) {
|
|
172
|
+
const next = {
|
|
173
|
+
...journal,
|
|
174
|
+
...update,
|
|
175
|
+
updatedAt: (input.now ?? (() => new Date()))().toISOString(),
|
|
176
|
+
};
|
|
177
|
+
await input.journalStore.write(next);
|
|
178
|
+
return next;
|
|
179
|
+
}
|
|
180
|
+
function acknowledgementSequence(response) {
|
|
181
|
+
return response.acknowledgedClientSequence;
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=recoveryCoordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recoveryCoordinator.js","sourceRoot":"","sources":["../../src/runtime/recoveryCoordinator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAqB1D,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,KASjD;IACC,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;IAC7D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,kBAAkB,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1F,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAC;IAChG,CAAC;IAED,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,QAAQ,GAAG,IAAI,CAAC;IACpB,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;QACnF,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC5F,MAAM,uBAAuB,GAAG,OAAO,EAAE,aAAa,KAAK,SAAS,CAAC;QACrE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,UAAU,EAAE;YACrE,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,SAAS;YACtC,eAAe,EAAE,OAAO,CAAC,SAAS,CAAC,eAAe;YAClD,8BAA8B,EAAE,OAAO,CAAC,8BAA8B;YACtE,uBAAuB;YACvB,wBAAwB,EAAE,KAAK;YAC/B,GAAG,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS;gBACtC,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC;oBACE,cAAc,EAAE;wBACd,WAAW,EAAE,OAAO,CAAC,cAAc,CAAC,MAAM,KAAK,UAAU;4BACvD,CAAC,CAAC,QAAQ;4BACV,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,MAAM;wBACjC,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,OAAO,EAAE;qBACrD;iBACF,CAAC;SACP,CAAC,CAAC;QACH,IAAI,QAAQ,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACnC,eAAe,IAAI,CAAC,CAAC;YACrB,IAAI,CAAC,uBAAuB,IAAI,OAAO,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;gBACrE,MAAM,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE;oBAClC,KAAK,EAAE,aAAa;oBACpB,kBAAkB,EAAE,2EAA2E;iBAChG,CAAC,CAAC;gBACH,QAAQ,GAAG,KAAK,CAAC;gBACjB,SAAS;YACX,CAAC;YACD,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,GAAG,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;YACvF,IAAI,OAAO,CAAC,cAAc,KAAK,SAAS;gBAAE,QAAQ,GAAG,KAAK,CAAC;YAC3D,SAAS;QACX,CAAC;QACD,IAAI,QAAQ,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,yBAAyB,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YACzF,IAAI,QAAQ,CAAC,qBAAqB,EAAE,CAAC;gBACnC,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;oBACzD,MAAM,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE;wBAClC,KAAK,EAAE,UAAU;wBACjB,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI;4BACxC,MAAM,EAAE,WAAW;4BACnB,OAAO,EAAE,OAAO,CAAC,OAAO;yBACzB;wBACD,kBAAkB,EAAE,mDAAmD;qBACxE,CAAC,CAAC;oBACH,MAAM,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;oBACrD,cAAc,IAAI,CAAC,CAAC;oBACpB,SAAS;gBACX,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,QAAQ,GAAG,KAAK,CAAC;oBACjB,MAAM,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE;wBAClC,KAAK,EAAE,YAAY;wBACnB,kBAAkB,EAAE,4CAA4C,YAAY,CAAC,KAAK,CAAC,EAAE;qBACtF,CAAC,CAAC;oBACH,SAAS;gBACX,CAAC;YACH,CAAC;YACD,QAAQ,GAAG,KAAK,CAAC;YACjB,MAAM,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE;gBAClC,KAAK,EAAE,YAAY;gBACnB,kBAAkB,EAAE,QAAQ,CAAC,MAAM,IAAI,8DAA8D;aACtG,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,MAAM,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,qBAAqB,CAAC,QAAQ,CAAC,CAAC,CAAC;QACrE,MAAM,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACrD,cAAc,IAAI,CAAC,CAAC;IACtB,CAAC;IACD,OAAO;QACL,kBAAkB,EAAE,UAAU,CAAC,MAAM;QACrC,eAAe;QACf,cAAc;QACd,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,KAAwD,EACxD,OAAyB;IAEzB,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,EAAE,MAAM,KAAK,WAAW;QAC5D,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO;QAChC,CAAC,CAAC,kEAAkE,CAAC;IACvE,MAAM,OAAO,GAAG;QACd,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,cAAc,EACZ,OAAO,CAAC,wBAAwB,IAAI,mBAAmB,OAAO,CAAC,SAAS,EAAE;KAC7E,CAAC;IACF,IAAI,OAAO,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACvC,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,KAAK,CAAC,UAAU,CAAC,kBAAkB,CACvC,KAAK,CAAC,UAAU,EAChB,OAAO,CAAC,KAAK,EACb,OAAO,CAAC,YAAY,EACpB,WAAW,EACX,EAAE,OAAO,EAAE,EACX,OAAO,CACR,CAAC;QACF,OAAO,EAAE,OAAO,EAAE,CAAC;IACrB,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,CAAC,uBAAuB,KAAK,SAAS,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,KAAK,CAAC,MAAM,CAAC,uBAAuB,CACxC,KAAK,CAAC,UAAU,EAChB,OAAO,CAAC,KAAK,EACb,EAAE,OAAO,EAAE,EACX,OAAO,CACR,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC;AAED,SAAS,yBAAyB,CAAC,MAAc;IAC/C,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,WAAW,CAAC;AACjF,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,0CAA0C,CAAC;AAC7F,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,KAAwD,EACxD,OAAyB,EACzB,QAA2D;IAE3D,IAAI,QAAQ,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,IAAI,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE;QAC7C,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,8BAA8B,EAAE,IAAI,CAAC,GAAG,CACtC,OAAO,CAAC,8BAA8B,EACtC,QAAQ,CAAC,8BAA8B,CACxC;QACD,KAAK,EAAE,YAAY;KACpB,CAAC,CAAC;IACH,MAAM,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,8BAA8B,CAAC,CAAC;IACpF,KAAK,MAAM,KAAK,IAAI,MAAM,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACnE,IAAI,QAA8B,CAAC;QACnC,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,EAAE;gBACzE,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,SAAS;gBAChC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;gBAC9E,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;gBACvF,aAAa,EAAE,KAAK,CAAC,aAAa;gBAClC,cAAc,EAAE,KAAK,CAAC,cAAc;gBACpC,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,iBAAiB,IAAI,KAAK,CAAC,WAAW,KAAK,WAAW;gBAAE,MAAM,KAAK,CAAC;YACzF,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,YAAY,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QACvD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;QACxF,CAAC;QACD,MAAM,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;QAC7D,IAAI,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE;YACtC,8BAA8B,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,8BAA8B,EAAE,YAAY,CAAC;SAC5F,CAAC,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,qBAAqB,CAC5B,QAAkC;IAElC,QAAQ,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAC1B,KAAK,kBAAkB;YACrB,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,QAAQ,CAAC,MAAM,IAAI,oCAAoC,EAAE,CAAC;QAC5G,KAAK,YAAY;YACf,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,QAAQ,CAAC,MAAM,IAAI,iCAAiC,EAAE,CAAC;QAC3G,KAAK,MAAM;YACT,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,QAAQ,CAAC,MAAM,IAAI,0CAA0C,EAAE,CAAC;QACrH,KAAK,sBAAsB;YACzB,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,QAAQ,CAAC,MAAM,IAAI,sCAAsC,EAAE,CAAC;QACjH,KAAK,QAAQ;YACX,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,KAAsF,EACtF,OAAyB,EACzB,MAAiC;IAEjC,MAAM,IAAI,GAAG;QACX,GAAG,OAAO;QACV,GAAG,MAAM;QACT,SAAS,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE;KAC7D,CAAC;IACF,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,uBAAuB,CAAC,QAA8B;IAC7D,OAAO,QAAQ,CAAC,0BAA0B,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
declare const lockSchema: z.ZodObject<{
|
|
3
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
4
|
+
identityKey: z.ZodString;
|
|
5
|
+
pid: z.ZodNumber;
|
|
6
|
+
processStartMarker: z.ZodString;
|
|
7
|
+
nonce: z.ZodString;
|
|
8
|
+
acquiredAt: z.ZodISODateTime;
|
|
9
|
+
}, z.core.$strict>;
|
|
10
|
+
export type RuntimeLockRecord = z.infer<typeof lockSchema>;
|
|
11
|
+
export type RuntimeLockHandle = {
|
|
12
|
+
record: RuntimeLockRecord;
|
|
13
|
+
release(): Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
export type RuntimeLockOptions = {
|
|
16
|
+
pid?: number | undefined;
|
|
17
|
+
now?: (() => Date) | undefined;
|
|
18
|
+
createNonce?: (() => string) | undefined;
|
|
19
|
+
readProcessStartMarker?: ((pid: number) => Promise<string | undefined>) | undefined;
|
|
20
|
+
};
|
|
21
|
+
export declare class RuntimeIdentityLock {
|
|
22
|
+
readonly path: string;
|
|
23
|
+
private readonly options;
|
|
24
|
+
constructor(path?: string, options?: RuntimeLockOptions);
|
|
25
|
+
acquire(identityKey: string): Promise<RuntimeLockHandle>;
|
|
26
|
+
private tryCreate;
|
|
27
|
+
private readExisting;
|
|
28
|
+
private recoverStaleLock;
|
|
29
|
+
private handle;
|
|
30
|
+
}
|
|
31
|
+
export declare function defaultRuntimeLockPath(env?: NodeJS.ProcessEnv): string;
|
|
32
|
+
export declare function readProcessStartMarker(pid: number): Promise<string | undefined>;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { chmod, mkdir, open, readFile, rename, rm } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { defaultConfigPath } from "../config.js";
|
|
8
|
+
import { isNodeError } from "./atomicFile.js";
|
|
9
|
+
const execFileAsync = promisify(execFile);
|
|
10
|
+
const lockSchema = z.object({
|
|
11
|
+
schemaVersion: z.literal(1),
|
|
12
|
+
identityKey: z.string().min(1).max(500),
|
|
13
|
+
pid: z.number().int().positive(),
|
|
14
|
+
processStartMarker: z.string().min(1).max(500),
|
|
15
|
+
nonce: z.string().min(1),
|
|
16
|
+
acquiredAt: z.iso.datetime(),
|
|
17
|
+
}).strict();
|
|
18
|
+
export class RuntimeIdentityLock {
|
|
19
|
+
path;
|
|
20
|
+
options;
|
|
21
|
+
constructor(path = defaultRuntimeLockPath(), options = {}) {
|
|
22
|
+
this.path = path;
|
|
23
|
+
this.options = options;
|
|
24
|
+
}
|
|
25
|
+
async acquire(identityKey) {
|
|
26
|
+
await mkdir(path.dirname(this.path), { recursive: true, mode: 0o700 });
|
|
27
|
+
await chmod(path.dirname(this.path), 0o700);
|
|
28
|
+
const pid = this.options.pid ?? process.pid;
|
|
29
|
+
const markerReader = this.options.readProcessStartMarker ?? readProcessStartMarker;
|
|
30
|
+
const processStartMarker = await markerReader(pid);
|
|
31
|
+
if (processStartMarker === undefined) {
|
|
32
|
+
throw new Error("Cannot establish a PID-reuse-safe runtime identity.");
|
|
33
|
+
}
|
|
34
|
+
const record = lockSchema.parse({
|
|
35
|
+
schemaVersion: 1,
|
|
36
|
+
identityKey,
|
|
37
|
+
pid,
|
|
38
|
+
processStartMarker,
|
|
39
|
+
nonce: (this.options.createNonce ?? randomUUID)(),
|
|
40
|
+
acquiredAt: (this.options.now ?? (() => new Date()))().toISOString(),
|
|
41
|
+
});
|
|
42
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
43
|
+
if (await this.tryCreate(record))
|
|
44
|
+
return this.handle(record);
|
|
45
|
+
const existing = await this.readExisting();
|
|
46
|
+
if (existing !== undefined && await sameLiveProcess(existing, markerReader)) {
|
|
47
|
+
throw new Error("Another Conductor runtime already owns this paired identity and state directory.");
|
|
48
|
+
}
|
|
49
|
+
await this.recoverStaleLock(existing);
|
|
50
|
+
}
|
|
51
|
+
throw new Error("Could not acquire the Conductor runtime identity lock.");
|
|
52
|
+
}
|
|
53
|
+
async tryCreate(record) {
|
|
54
|
+
try {
|
|
55
|
+
const handle = await open(this.path, "wx", 0o600);
|
|
56
|
+
try {
|
|
57
|
+
await handle.writeFile(`${JSON.stringify(record, null, 2)}\n`, "utf8");
|
|
58
|
+
await handle.sync();
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
await handle.close();
|
|
62
|
+
}
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (isNodeError(error) && error.code === "EEXIST")
|
|
67
|
+
return false;
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async readExisting() {
|
|
72
|
+
try {
|
|
73
|
+
return lockSchema.parse(JSON.parse(await readFile(this.path, "utf8")));
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
if (isNodeError(error) && error.code === "ENOENT")
|
|
77
|
+
return undefined;
|
|
78
|
+
if (error instanceof SyntaxError || error instanceof z.ZodError)
|
|
79
|
+
return undefined;
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async recoverStaleLock(existing) {
|
|
84
|
+
try {
|
|
85
|
+
await rename(this.path, `${this.path}.stale-${existing?.nonce ?? randomUUID()}`);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (!isNodeError(error) || error.code !== "ENOENT")
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
handle(record) {
|
|
93
|
+
return {
|
|
94
|
+
record,
|
|
95
|
+
release: async () => {
|
|
96
|
+
const existing = await this.readExisting();
|
|
97
|
+
if (existing?.nonce === record.nonce)
|
|
98
|
+
await rm(this.path, { force: true });
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export function defaultRuntimeLockPath(env = process.env) {
|
|
104
|
+
return path.join(path.dirname(defaultConfigPath(env)), "runtime", "conductor.lock");
|
|
105
|
+
}
|
|
106
|
+
async function sameLiveProcess(record, markerReader) {
|
|
107
|
+
try {
|
|
108
|
+
process.kill(record.pid, 0);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (isNodeError(error) && error.code === "EPERM")
|
|
112
|
+
return true;
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return await markerReader(record.pid) === record.processStartMarker;
|
|
116
|
+
}
|
|
117
|
+
export async function readProcessStartMarker(pid) {
|
|
118
|
+
if (process.platform === "linux") {
|
|
119
|
+
try {
|
|
120
|
+
const stat = await readFile(`/proc/${String(pid)}/stat`, "utf8");
|
|
121
|
+
return stat.trim().split(/\s+/u)[21];
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const command = process.platform === "win32" ? "powershell.exe" : "ps";
|
|
128
|
+
const args = process.platform === "win32"
|
|
129
|
+
? ["-NoProfile", "-Command", `(Get-Process -Id ${String(pid)}).StartTime.ToUniversalTime().Ticks`]
|
|
130
|
+
: ["-o", "lstart=", "-p", String(pid)];
|
|
131
|
+
try {
|
|
132
|
+
const { stdout } = await execFileAsync(command, args, { timeout: 2_000 });
|
|
133
|
+
const marker = stdout.trim();
|
|
134
|
+
return marker.length === 0 ? undefined : marker;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=runtimeLock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtimeLock.js","sourceRoot":"","sources":["../../src/runtime/runtimeLock.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DaemonOnceResult, RunDaemonOnceInput } from "../daemon.js";
|
|
2
|
+
import type { RuntimeIdentityLock } from "./runtimeLock.js";
|
|
2
3
|
export type RuntimeServiceState = "stopped" | "starting" | "running" | "stopping" | "failed";
|
|
3
4
|
export type RuntimeServiceStatus = {
|
|
4
5
|
state: RuntimeServiceState;
|
|
@@ -9,6 +10,7 @@ export type RuntimeServiceStatus = {
|
|
|
9
10
|
};
|
|
10
11
|
export declare class HeadlessRuntimeService {
|
|
11
12
|
private readonly input;
|
|
13
|
+
private readonly runtimeLock?;
|
|
12
14
|
private state;
|
|
13
15
|
private startedAt;
|
|
14
16
|
private stoppedAt;
|
|
@@ -16,7 +18,8 @@ export declare class HeadlessRuntimeService {
|
|
|
16
18
|
private lastErrorMessage;
|
|
17
19
|
private controller;
|
|
18
20
|
private runPromise;
|
|
19
|
-
|
|
21
|
+
private lockHandle;
|
|
22
|
+
constructor(input: Omit<RunDaemonOnceInput, "signal">, runtimeLock?: RuntimeIdentityLock | undefined);
|
|
20
23
|
status(): RuntimeServiceStatus;
|
|
21
24
|
runOnce(): Promise<DaemonOnceResult>;
|
|
22
25
|
start(): Promise<RuntimeServiceStatus>;
|
|
@@ -24,4 +27,6 @@ export declare class HeadlessRuntimeService {
|
|
|
24
27
|
restart(): Promise<RuntimeServiceStatus>;
|
|
25
28
|
waitUntilStopped(): Promise<RuntimeServiceStatus>;
|
|
26
29
|
private runUntilStopped;
|
|
30
|
+
private acquireOwnership;
|
|
31
|
+
private releaseOwnership;
|
|
27
32
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { runDaemon, runDaemonOnce } from "../daemon.js";
|
|
2
3
|
import { redactSecrets } from "../redaction.js";
|
|
3
4
|
export class HeadlessRuntimeService {
|
|
4
5
|
input;
|
|
6
|
+
runtimeLock;
|
|
5
7
|
state = "stopped";
|
|
6
8
|
startedAt;
|
|
7
9
|
stoppedAt;
|
|
@@ -9,8 +11,10 @@ export class HeadlessRuntimeService {
|
|
|
9
11
|
lastErrorMessage;
|
|
10
12
|
controller;
|
|
11
13
|
runPromise;
|
|
12
|
-
|
|
14
|
+
lockHandle;
|
|
15
|
+
constructor(input, runtimeLock) {
|
|
13
16
|
this.input = input;
|
|
17
|
+
this.runtimeLock = runtimeLock;
|
|
14
18
|
}
|
|
15
19
|
status() {
|
|
16
20
|
return {
|
|
@@ -30,6 +34,7 @@ export class HeadlessRuntimeService {
|
|
|
30
34
|
this.stoppedAt = undefined;
|
|
31
35
|
this.lastErrorMessage = undefined;
|
|
32
36
|
try {
|
|
37
|
+
await this.acquireOwnership();
|
|
33
38
|
this.state = "running";
|
|
34
39
|
const result = await runDaemonOnce(this.input);
|
|
35
40
|
this.lastResult = result;
|
|
@@ -43,6 +48,9 @@ export class HeadlessRuntimeService {
|
|
|
43
48
|
this.lastErrorMessage = safeRuntimeErrorMessage(error);
|
|
44
49
|
throw error;
|
|
45
50
|
}
|
|
51
|
+
finally {
|
|
52
|
+
await this.releaseOwnership();
|
|
53
|
+
}
|
|
46
54
|
}
|
|
47
55
|
async start() {
|
|
48
56
|
await Promise.resolve();
|
|
@@ -58,6 +66,15 @@ export class HeadlessRuntimeService {
|
|
|
58
66
|
this.startedAt = new Date().toISOString();
|
|
59
67
|
this.stoppedAt = undefined;
|
|
60
68
|
this.lastErrorMessage = undefined;
|
|
69
|
+
try {
|
|
70
|
+
await this.acquireOwnership();
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
this.state = "failed";
|
|
74
|
+
this.stoppedAt = new Date().toISOString();
|
|
75
|
+
this.lastErrorMessage = safeRuntimeErrorMessage(error);
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
61
78
|
this.runPromise = this.runUntilStopped(controller);
|
|
62
79
|
this.state = "running";
|
|
63
80
|
return this.status();
|
|
@@ -80,27 +97,44 @@ export class HeadlessRuntimeService {
|
|
|
80
97
|
await this.runPromise;
|
|
81
98
|
return this.status();
|
|
82
99
|
}
|
|
83
|
-
runUntilStopped(controller) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (this.controller
|
|
87
|
-
|
|
100
|
+
async runUntilStopped(controller) {
|
|
101
|
+
try {
|
|
102
|
+
await runDaemon({ ...this.input, signal: controller.signal });
|
|
103
|
+
if (this.controller === controller) {
|
|
104
|
+
this.state = "stopped";
|
|
105
|
+
this.stoppedAt = new Date().toISOString();
|
|
88
106
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
this.controller
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (this.controller !== controller) {
|
|
96
|
-
return;
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (this.controller === controller) {
|
|
110
|
+
this.state = "failed";
|
|
111
|
+
this.stoppedAt = new Date().toISOString();
|
|
112
|
+
this.lastErrorMessage = safeRuntimeErrorMessage(error);
|
|
97
113
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
this.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
if (this.controller === controller) {
|
|
117
|
+
this.controller = undefined;
|
|
118
|
+
this.runPromise = undefined;
|
|
119
|
+
}
|
|
120
|
+
await this.releaseOwnership();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async acquireOwnership() {
|
|
124
|
+
if (this.runtimeLock === undefined)
|
|
125
|
+
return;
|
|
126
|
+
const config = await this.input.store.read();
|
|
127
|
+
if (config === undefined)
|
|
128
|
+
throw new Error("No paired Conductor config found. Run pair first.");
|
|
129
|
+
const identityKey = config.conductorId ?? createHash("sha256")
|
|
130
|
+
.update(`${config.apiBaseUrl}\0${config.displayName}`)
|
|
131
|
+
.digest("hex");
|
|
132
|
+
this.lockHandle = await this.runtimeLock.acquire(identityKey);
|
|
133
|
+
}
|
|
134
|
+
async releaseOwnership() {
|
|
135
|
+
const handle = this.lockHandle;
|
|
136
|
+
this.lockHandle = undefined;
|
|
137
|
+
await handle?.release();
|
|
104
138
|
}
|
|
105
139
|
}
|
|
106
140
|
function safeRuntimeErrorMessage(error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeService.js","sourceRoot":"","sources":["../../src/runtime/runtimeService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtimeService.js","sourceRoot":"","sources":["../../src/runtime/runtimeService.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ConductorClient, ConductorWorkClient, ClaimedJob } from "../types.js";
|
|
2
|
+
import type { AttemptAuthority } from "../protocol/fenced.js";
|
|
2
3
|
export type TaskExecutionClient = Pick<ConductorWorkClient, "readWorkContext" | "checkoutTask" | "createChildTasks" | "addTaskComment" | "registerArtifact" | "requestApproval" | "reportUsage" | "setTaskDisposition">;
|
|
3
4
|
export type OpenTaskExecution = {
|
|
4
5
|
taskId: string;
|
|
@@ -11,6 +12,7 @@ export declare function openTaskExecution(input: {
|
|
|
11
12
|
workClient: TaskExecutionClient;
|
|
12
13
|
credential: string;
|
|
13
14
|
job: ClaimedJob;
|
|
15
|
+
authority?: AttemptAuthority | undefined;
|
|
14
16
|
onHardStop?: (() => void) | undefined;
|
|
15
17
|
}): Promise<OpenTaskExecution>;
|
|
16
18
|
export declare function taskIdFromJob(job: ClaimedJob): string;
|
|
@@ -3,7 +3,7 @@ import { startLocalBridgeServer } from "../bridge/server.js";
|
|
|
3
3
|
import { LocalBridgeSessionRegistry } from "../bridge/sessionRegistry.js";
|
|
4
4
|
export async function openTaskExecution(input) {
|
|
5
5
|
const taskId = taskIdFromJob(input.job);
|
|
6
|
-
await input.workClient.checkoutTask(input.credential, input.job.runId, taskId);
|
|
6
|
+
await input.workClient.checkoutTask(input.credential, input.job.runId, taskId, mutationOptions(input.authority));
|
|
7
7
|
const sessions = new LocalBridgeSessionRegistry();
|
|
8
8
|
const session = sessions.create({
|
|
9
9
|
runId: input.job.runId,
|
|
@@ -13,7 +13,7 @@ export async function openTaskExecution(input) {
|
|
|
13
13
|
});
|
|
14
14
|
const handler = createLocalBridgeHandler({
|
|
15
15
|
sessions,
|
|
16
|
-
client: bridgeClient(input.coreClient, input.workClient),
|
|
16
|
+
client: bridgeClient(input.coreClient, input.workClient, input.authority),
|
|
17
17
|
machineCredential: input.credential,
|
|
18
18
|
onHardStop: input.onHardStop,
|
|
19
19
|
});
|
|
@@ -41,19 +41,25 @@ export function taskIdFromJob(job) {
|
|
|
41
41
|
}
|
|
42
42
|
return taskId;
|
|
43
43
|
}
|
|
44
|
-
function bridgeClient(core, work) {
|
|
44
|
+
function bridgeClient(core, work, authority) {
|
|
45
45
|
return {
|
|
46
|
-
readWorkContext: (
|
|
47
|
-
checkoutTask: (
|
|
48
|
-
createChildTasks: (
|
|
49
|
-
addTaskComment: (
|
|
50
|
-
registerArtifact: (
|
|
51
|
-
requestApproval: (
|
|
52
|
-
reportUsage: (
|
|
53
|
-
setTaskDisposition: (
|
|
54
|
-
appendRunEvent: (
|
|
46
|
+
readWorkContext: (credential, runId, taskId) => work.readWorkContext(credential, runId, taskId, mutationOptions(authority)),
|
|
47
|
+
checkoutTask: (credential, runId, taskId) => work.checkoutTask(credential, runId, taskId, mutationOptions(authority)),
|
|
48
|
+
createChildTasks: (credential, runId, taskId, children) => work.createChildTasks(credential, runId, taskId, children, mutationOptions(authority)),
|
|
49
|
+
addTaskComment: (credential, runId, taskId, bodyMarkdown) => work.addTaskComment(credential, runId, taskId, bodyMarkdown, mutationOptions(authority)),
|
|
50
|
+
registerArtifact: (credential, runId, taskId, artifact) => work.registerArtifact(credential, runId, taskId, artifact, mutationOptions(authority)),
|
|
51
|
+
requestApproval: (credential, runId, taskId, request) => work.requestApproval(credential, runId, taskId, request, mutationOptions(authority)),
|
|
52
|
+
reportUsage: (credential, runId, taskId, usage) => work.reportUsage(credential, runId, taskId, usage, mutationOptions(authority)),
|
|
53
|
+
setTaskDisposition: (credential, runId, taskId, disposition, resultSummary) => work.setTaskDisposition(credential, runId, taskId, disposition, resultSummary, mutationOptions(authority)),
|
|
54
|
+
appendRunEvent: (credential, runId, event) => core.appendRunEvent(credential, runId, {
|
|
55
|
+
...event,
|
|
56
|
+
...(authority === undefined ? {} : { authority }),
|
|
57
|
+
}),
|
|
55
58
|
};
|
|
56
59
|
}
|
|
60
|
+
function mutationOptions(authority) {
|
|
61
|
+
return authority === undefined ? undefined : { authority };
|
|
62
|
+
}
|
|
57
63
|
function bridgeSessionTtlMs(job) {
|
|
58
64
|
const maxRunMinutes = job.wakeEnvelope?.limits.maxRunMinutes;
|
|
59
65
|
return (maxRunMinutes ?? 60) * 60_000 + 60_000;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"taskExecution.js","sourceRoot":"","sources":["../../src/runtime/taskExecution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"taskExecution.js","sourceRoot":"","sources":["../../src/runtime/taskExecution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AA2B1E,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAOvC;IACC,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,KAAK,CAAC,UAAU,CAAC,YAAY,CACjC,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,GAAG,CAAC,KAAK,EACf,MAAM,EACN,eAAe,CAAC,KAAK,CAAC,SAAS,CAAC,CACjC,CAAC;IACF,MAAM,QAAQ,GAAG,IAAI,0BAA0B,EAAE,CAAC;IAClD,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC9B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK;QACtB,MAAM;QACN,MAAM,EAAE,aAAa,EAAE;QACvB,KAAK,EAAE,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC;KACrC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,wBAAwB,CAAC;QACvC,QAAQ;QACR,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC;QACzE,iBAAiB,EAAE,KAAK,CAAC,UAAU;QACnC,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACjE,OAAO;QACL,MAAM;QACN,aAAa,EAAE,MAAM,CAAC,OAAO;QAC7B,WAAW,EAAE,OAAO,CAAC,QAAQ;QAC7B,KAAK,CAAC,KAAK;YACT,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACjC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAe;IAC3C,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,YAAY,CAAC;IAC7D,IAAI,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IAC9E,IAAI,GAAG,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACnC,IAAI,GAAG,CAAC,YAAY,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAClG,IAAI,GAAG,CAAC,YAAY,KAAK,SAAS,IAAI,GAAG,CAAC,YAAY,KAAK,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACpF,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CACnB,IAA6C,EAC7C,IAAyB,EACzB,SAA4B;IAE5B,OAAO;QACL,eAAe,EAAE,CACf,UAAkB,EAClB,KAAa,EACb,MAAc,EACd,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;QAChF,YAAY,EAAE,CACZ,UAAkB,EAClB,KAAa,EACb,MAAc,EACd,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;QAC7E,gBAAgB,EAAE,CAChB,UAAkB,EAClB,KAAa,EACb,MAAc,EACd,QAAgE,EAChE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3F,cAAc,EAAE,CACd,UAAkB,EAClB,KAAa,EACb,MAAc,EACd,YAAoB,EACpB,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;QAC7F,gBAAgB,EAAE,CAChB,UAAkB,EAClB,KAAa,EACb,MAAc,EACd,QAAgE,EAChE,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;QAC3F,eAAe,EAAE,CACf,UAAkB,EAClB,KAAa,EACb,MAAc,EACd,OAA8D,EAC9D,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;QACzF,WAAW,EAAE,CACX,UAAkB,EAClB,KAAa,EACb,MAAc,EACd,KAAwD,EACxD,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;QACnF,kBAAkB,EAAE,CAClB,UAAkB,EAClB,KAAa,EACb,MAAc,EACd,WAAqE,EACrE,aAAwE,EACxE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAC1B,UAAU,EACV,KAAK,EACL,MAAM,EACN,WAAW,EACX,aAAa,EACb,eAAe,CAAC,SAAS,CAAC,CAC3B;QACD,cAAc,EAAE,CACd,UAAkB,EAClB,KAAa,EACb,KAAuD,EACvD,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,KAAK,EAAE;YAC1C,GAAG,KAAK;YACR,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;SAClD,CAAC;KACH,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,SAA4B;IACnD,OAAO,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;AAC7D,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAe;IACzC,MAAM,aAAa,GAAG,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,aAAa,CAAC;IAC7D,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC;AACjD,CAAC;AAED,SAAS,aAAa;IACpB,OAAO;QACL,UAAU;QACV,iBAAiB;QACjB,eAAe;QACf,kBAAkB;QAClB,oBAAoB;QACpB,gBAAgB;QAChB,gBAAgB;QAChB,aAAa;QACb,wBAAwB;KACzB,CAAC;AACJ,CAAC"}
|