@fitlab-ai/agent-infra 0.11.2 → 0.11.4
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 +17 -8
- package/README.zh-CN.md +17 -8
- package/dist/bin/internal-cli.js +7 -2
- package/dist/lib/agent-clients/adapter.js +3 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +234 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +8 -35
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +1 -34
- package/dist/lib/agent-clients/adapters/codex.js +10 -0
- package/dist/lib/internal/cli-route-inventory.js +1 -1
- package/dist/lib/internal/manual-validation.js +22 -27
- package/dist/lib/internal/sandbox-control.js +1 -43
- package/dist/lib/internal/task-artifact.js +1 -1
- package/dist/lib/internal/task-finalization.js +41 -1
- package/dist/lib/internal/task-ledger.js +13 -5
- package/dist/lib/internal/task-lifecycle.js +1 -1
- package/dist/lib/internal/task-operation-registry.js +7 -2
- package/dist/lib/platform/completion-backfill.js +63 -17
- package/dist/lib/platform/issue-comments.js +2 -31
- package/dist/lib/platform/pr-summary.js +7 -2
- package/dist/lib/sandbox/control/client.js +3 -44
- package/dist/lib/sandbox/control/executor.js +14 -79
- package/dist/lib/sandbox/control/protocol.js +5 -64
- package/dist/lib/sandbox/control/server.js +49 -343
- package/dist/lib/sandbox/control/state.js +1 -7
- package/dist/lib/sandbox/control/task-view.js +1 -2
- package/dist/lib/sandbox/task-cleanup.js +13 -20
- package/dist/lib/task/artifact-command.js +11 -4
- package/dist/lib/task/artifact-lifecycle.js +217 -85
- package/dist/lib/task/artifact-operations.js +1 -26
- package/dist/lib/task/artifact-receipts.js +4 -1
- package/dist/lib/task/artifact-schema.js +1 -0
- package/dist/lib/task/artifact-selection.js +25 -0
- package/dist/lib/task/capabilities.js +158 -39
- package/dist/lib/task/commands/status.js +9 -2
- package/dist/lib/task/control-authority.js +37 -38
- package/dist/lib/task/control-recovery.js +3 -42
- package/dist/lib/task/decision-intents.js +12 -0
- package/dist/lib/task/delegation-receipts.js +2 -2
- package/dist/lib/task/delivery.js +1 -43
- package/dist/lib/task/events.js +80 -64
- package/dist/lib/task/finalization-artifacts.js +1 -3
- package/dist/lib/task/finalization-state.js +1 -1
- package/dist/lib/task/finalization.js +319 -234
- package/dist/lib/task/ledger-intents.js +157 -15
- package/dist/lib/task/lifecycle-path.js +75 -0
- package/dist/lib/task/lifecycle.js +11 -1
- package/dist/lib/task/local-artifact-finalization.js +1 -20
- package/dist/lib/task/manual-validation-receipt.js +8 -3
- package/dist/lib/task/orchestration.js +29 -13
- package/dist/lib/task/review-finalization.js +3 -16
- package/dist/lib/task/rework-intent.js +70 -4
- package/dist/lib/task/verification-engine.js +20 -30
- package/dist/lib/task/verification.js +1 -0
- package/dist/lib/task/workflow-warning-intents.js +21 -6
- package/dist/lib/task/workspace-snapshot.js +7 -2
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapter.ts +46 -0
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +297 -0
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +13 -33
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +1 -44
- package/lib/agent-clients/adapters/codex.ts +10 -0
- package/lib/internal/cli-route-inventory.ts +1 -1
- package/lib/internal/manual-validation.ts +22 -26
- package/lib/internal/sandbox-control.ts +0 -42
- package/lib/internal/task-artifact.ts +1 -1
- package/lib/internal/task-finalization.ts +40 -1
- package/lib/internal/task-ledger.ts +12 -5
- package/lib/internal/task-lifecycle.ts +2 -2
- package/lib/internal/task-operation-registry.ts +8 -4
- package/lib/platform/completion-backfill.ts +78 -16
- package/lib/platform/issue-comments.ts +1 -35
- package/lib/platform/pr-summary.ts +10 -2
- package/lib/sandbox/control/client.ts +5 -68
- package/lib/sandbox/control/executor.ts +14 -81
- package/lib/sandbox/control/protocol.ts +7 -83
- package/lib/sandbox/control/server.ts +47 -362
- package/lib/sandbox/control/state.ts +1 -9
- package/lib/sandbox/control/task-view.ts +1 -2
- package/lib/sandbox/task-cleanup.ts +12 -20
- package/lib/task/artifact-command.ts +14 -4
- package/lib/task/artifact-lifecycle.ts +236 -85
- package/lib/task/artifact-operations.ts +1 -26
- package/lib/task/artifact-receipts.ts +4 -1
- package/lib/task/artifact-schema.ts +1 -0
- package/lib/task/artifact-selection.ts +53 -0
- package/lib/task/capabilities.ts +154 -40
- package/lib/task/commands/status.ts +11 -2
- package/lib/task/control-authority.ts +41 -48
- package/lib/task/control-recovery.ts +3 -43
- package/lib/task/decision-intents.ts +9 -0
- package/lib/task/delegation-receipts.ts +2 -2
- package/lib/task/delivery.ts +1 -40
- package/lib/task/events.ts +82 -64
- package/lib/task/finalization-artifacts.ts +1 -3
- package/lib/task/finalization-state.ts +1 -1
- package/lib/task/finalization.ts +310 -216
- package/lib/task/ledger-intents.ts +155 -15
- package/lib/task/lifecycle-path.ts +98 -0
- package/lib/task/lifecycle.ts +15 -2
- package/lib/task/local-artifact-finalization.ts +2 -25
- package/lib/task/manual-validation-receipt.ts +8 -2
- package/lib/task/orchestration.ts +56 -27
- package/lib/task/review-finalization.ts +3 -16
- package/lib/task/rework-intent.ts +75 -5
- package/lib/task/verification-engine.ts +19 -30
- package/lib/task/verification.ts +2 -1
- package/lib/task/workflow-warning-intents.ts +18 -6
- package/lib/task/workspace-snapshot.ts +3 -2
- package/package.json +1 -1
- package/templates/.agents/rules/lifecycle-orchestration.en.md +19 -5
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +19 -5
- package/templates/.agents/rules/review-handshake.en.md +4 -4
- package/templates/.agents/rules/review-handshake.zh-CN.md +4 -4
- package/templates/.agents/skills/analyze-task/SKILL.en.md +11 -4
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +11 -4
- package/templates/.agents/skills/code-task/SKILL.en.md +14 -8
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +18 -13
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +2 -2
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +4 -4
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +4 -4
- package/templates/.agents/skills/code-task/reference/report-template.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-task/SKILL.en.md +7 -8
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +7 -8
- package/templates/.agents/skills/plan-task/SKILL.en.md +13 -10
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +13 -10
- package/templates/.agents/skills/review-analysis/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-plan/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +2 -2
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/run-task/SKILL.en.md +9 -8
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +9 -8
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +18 -2
- package/templates/.agents/templates/task.en.md +2 -2
- package/templates/.agents/templates/task.zh-CN.md +2 -2
- package/templates/.agents/workflows/bug-fix.en.yaml +11 -6
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +11 -6
- package/templates/.agents/workflows/feature-development.en.yaml +11 -6
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +11 -6
- package/templates/.agents/workflows/refactoring.en.yaml +11 -6
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +11 -6
- package/dist/lib/sandbox/control/finalization-response.js +0 -35
- package/dist/lib/sandbox/control/task-workflow.js +0 -74
- package/dist/lib/sandbox/control/workflow-executor.js +0 -142
- package/dist/lib/task/lifecycle-recovery.js +0 -549
- package/dist/lib/task/recovery-warning.js +0 -19
- package/dist/lib/task/workflow-command.js +0 -21
- package/dist/lib/task/workflow-dispatch.js +0 -213
- package/lib/sandbox/control/finalization-response.ts +0 -37
- package/lib/sandbox/control/task-workflow.ts +0 -95
- package/lib/sandbox/control/workflow-executor.ts +0 -156
- package/lib/task/lifecycle-recovery.ts +0 -691
- package/lib/task/recovery-warning.ts +0 -21
- package/lib/task/workflow-command.ts +0 -22
- package/lib/task/workflow-dispatch.ts +0 -214
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { finalizationTerminalResponse } from './finalization-response.js';
|
|
2
|
-
import { isDeepStrictEqual } from 'node:util';
|
|
3
1
|
import { completedReentryView } from './completed-reentry.js';
|
|
4
2
|
import fs from 'node:fs';
|
|
5
3
|
import path from 'node:path';
|
|
@@ -13,10 +11,6 @@ import { validateSandboxControlRequest } from './protocol.js';
|
|
|
13
11
|
import { requestAuditFields, resultAuditFields, appendCriticalAudit, appendDiagnosticAudit, createSandboxControlAuditContext, writeSandboxControlTransition, readSandboxControlTransition } from './audit.js';
|
|
14
12
|
import { parseTaskControlOperation } from '../../task/control-authority.js';
|
|
15
13
|
import { parseControlOutput, classifySandboxControlRecovery, findSandboxControlRecoveryOperation, operationRecoveryBinding, SANDBOX_CONTROL_REQUIRED_COMPLETION_PHASES } from '../../task/control-recovery.js';
|
|
16
|
-
import { readRun } from '../../task/orchestration.js';
|
|
17
|
-
import { readLifecycleRecoveryDomainEvidence } from '../../task/lifecycle-recovery.js';
|
|
18
|
-
import { captureRepositorySnapshot } from '../../task/workspace-snapshot.js';
|
|
19
|
-
import { parseTypedTaskFrontmatter } from '../../task/frontmatter.js';
|
|
20
14
|
import { readLifecycleJournalEvidence } from '../../task/lifecycle.js';
|
|
21
15
|
import { resolveTaskRef } from '../../task/resolve-ref.js';
|
|
22
16
|
import { loadShortIdByTaskId } from '../../task/short-id.js';
|
|
@@ -26,96 +20,34 @@ import { nextSandboxControlBackoff } from './timing.js';
|
|
|
26
20
|
import { readTaskFinalizationReceipt } from '../../task/finalization.js';
|
|
27
21
|
import { readCodexControllerRegistration } from './controller-registration.js';
|
|
28
22
|
import { validateSandboxControlIdentity } from './identity-sentinel.js';
|
|
29
|
-
import { mergeSandboxTaskView,
|
|
23
|
+
import { mergeSandboxTaskView, taskViewForManifest } from './task-view.js';
|
|
30
24
|
import { taskCreateOutputUnavailableResult } from '../../task/create-service.js';
|
|
31
|
-
import { consumeLifecycleRecoveryAttestation, issueLifecycleRecoveryAttestation, recoverLifecycleRecoveryOperation } from '../../task/control-authority.js';
|
|
32
|
-
import { createCodexCapabilityStore } from '../../agent-clients/adapters/codex-lifecycle/capability-store.js';
|
|
33
|
-
import { computeLifecycleBuildIdentity } from '../../agent-clients/adapters/codex-lifecycle/build-identity.js';
|
|
34
|
-
function consumeLifecycleAuthorityForResult(manifest, execution) {
|
|
35
|
-
const authority = execution.lifecycleAuthority?.attestation;
|
|
36
|
-
if (!authority || execution.result?.exitCode !== 0)
|
|
37
|
-
return true;
|
|
38
|
-
try {
|
|
39
|
-
consumeLifecycleRecoveryAttestation(authority);
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
appendBrokerAudit(manifest, 'lifecycle-authority-consume-retry', {
|
|
44
|
-
...requestAuditFields(manifest, execution.request),
|
|
45
|
-
errorCode: error instanceof Error ? error.name : 'LIFECYCLE_AUTHORITY_CONSUME_FAILED'
|
|
46
|
-
});
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
function lifecycleAuthorityForRequest(manifest, manifestPath, request) {
|
|
51
|
-
const selector = request.family === 'task-workflow' || request.family === 'task-orchestration'
|
|
52
|
-
? request.authority
|
|
53
|
-
: undefined;
|
|
54
|
-
if (!selector)
|
|
55
|
-
return undefined;
|
|
56
|
-
let controllerBinding = null;
|
|
57
|
-
try {
|
|
58
|
-
const registration = readCodexControllerRegistration(manifestPath);
|
|
59
|
-
controllerBinding = {
|
|
60
|
-
instanceDigest: registration.controllerInstanceDigest,
|
|
61
|
-
controlGeneration: registration.controlGeneration
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
// The issuer reports the stable unavailable result; the broker never trusts
|
|
66
|
-
// a controller binding supplied by the request.
|
|
67
|
-
}
|
|
68
|
-
return issueLifecycleRecoveryAttestation(selector, {
|
|
69
|
-
controllerBinding,
|
|
70
|
-
capabilityStore: createCodexCapabilityStore(),
|
|
71
|
-
buildIdentity: computeLifecycleBuildIdentity(manifest.repoRoot)
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
25
|
function appendBrokerAudit(manifest, event, fields = {}) {
|
|
75
26
|
appendDiagnosticAudit(manifest, event, { source: 'broker', ...fields });
|
|
76
27
|
}
|
|
77
|
-
function operationKey(request
|
|
28
|
+
function operationKey(request) {
|
|
78
29
|
if (request.family === 'task-finalization')
|
|
79
30
|
return request.operation;
|
|
80
31
|
if (request.family === 'task-create')
|
|
81
32
|
return 'create';
|
|
82
33
|
if (request.family === 'codex-controller')
|
|
83
34
|
return request.command;
|
|
84
|
-
if (request.family
|
|
85
|
-
return request.workflow.operation;
|
|
86
|
-
if (request.family !== 'task-lifecycle' && request.family !== 'task-orchestration')
|
|
35
|
+
if (request.family !== 'task-lifecycle')
|
|
87
36
|
return null;
|
|
88
|
-
if (request.family === 'task-orchestration' && request.args[1] === 'route') {
|
|
89
|
-
if (!output)
|
|
90
|
-
return 'route';
|
|
91
|
-
const result = parseControlOutput(output);
|
|
92
|
-
return result?.changed === true && result.status === 'completed' ? 'route.clean-completion' : 'route.read';
|
|
93
|
-
}
|
|
94
37
|
try {
|
|
95
38
|
const operation = parseTaskControlOperation(request.family, request.args);
|
|
96
|
-
return operation.family === 'task-
|
|
39
|
+
return operation.family === 'task-lifecycle' ? operation.request.intent : null;
|
|
97
40
|
}
|
|
98
41
|
catch {
|
|
99
42
|
return null;
|
|
100
43
|
}
|
|
101
44
|
}
|
|
102
|
-
function recoveryOperationKey(request
|
|
103
|
-
|
|
104
|
-
if (operation !== 'route')
|
|
105
|
-
return operation;
|
|
106
|
-
const digest = terminalResult?.intentDigest;
|
|
107
|
-
for (const candidate of ['route.read', 'route.clean-completion']) {
|
|
108
|
-
const expected = operationRecoveryBinding(request.id, request.generation, null, request.family, candidate).intentDigest;
|
|
109
|
-
if (digest === expected)
|
|
110
|
-
return candidate;
|
|
111
|
-
}
|
|
112
|
-
return null;
|
|
45
|
+
function recoveryOperationKey(request) {
|
|
46
|
+
return operationKey(request);
|
|
113
47
|
}
|
|
114
48
|
function terminalResultMatchesRequest(request, terminalResult) {
|
|
115
49
|
const operation = operationKey(request);
|
|
116
|
-
const candidates = operation
|
|
117
|
-
? ['route.read', 'route.clean-completion']
|
|
118
|
-
: operation ? [operation] : [];
|
|
50
|
+
const candidates = operation ? [operation] : [];
|
|
119
51
|
return candidates.some((candidate) => createHash('sha256').update(`${request.family}\0${candidate}`, 'utf8').digest('hex') === terminalResult.intentDigest);
|
|
120
52
|
}
|
|
121
53
|
function criticalRequestPhase(manifest, request, phase, outcome, reference) {
|
|
@@ -192,48 +124,6 @@ export function writeSandboxControlResponse(manifest, response) {
|
|
|
192
124
|
}
|
|
193
125
|
return true;
|
|
194
126
|
}
|
|
195
|
-
function finalizationRecoveryResponse(manifest, requestId, exitCode) {
|
|
196
|
-
if (!manifest.taskId || exitCode !== 0)
|
|
197
|
-
return { status: 'not-applicable' };
|
|
198
|
-
let receipt;
|
|
199
|
-
try {
|
|
200
|
-
receipt = readTaskFinalizationReceipt(manifest.repoRoot, manifest.taskId);
|
|
201
|
-
if (!receipt || !receipt.controlBinding
|
|
202
|
-
|| receipt.controlBinding.generation !== manifest.generation
|
|
203
|
-
|| receipt.controlBinding.requestId !== requestId)
|
|
204
|
-
return { status: 'deferred' };
|
|
205
|
-
const resolved = resolveTaskRef(manifest.taskId, { repoRoot: manifest.repoRoot });
|
|
206
|
-
if (!resolved.ok || resolved.state !== 'completed' || receipt.lifecycle !== 'done')
|
|
207
|
-
return { status: 'deferred' };
|
|
208
|
-
}
|
|
209
|
-
catch {
|
|
210
|
-
return { status: 'deferred' };
|
|
211
|
-
}
|
|
212
|
-
return { status: 'matched', response: finalizationTerminalResponse(manifest.taskId, requestId, receipt) };
|
|
213
|
-
}
|
|
214
|
-
function publishFinalizationTaskView(manifest, broker, requestId, state, reasonCode, activeRequestId) {
|
|
215
|
-
let view;
|
|
216
|
-
try {
|
|
217
|
-
const resolved = resolveTaskRef(manifest.taskId ?? '', { repoRoot: manifest.repoRoot });
|
|
218
|
-
const receipt = readTaskFinalizationReceipt(manifest.repoRoot, manifest.taskId ?? '');
|
|
219
|
-
view = resolved.ok && resolved.state === 'completed'
|
|
220
|
-
? taskViewAfterFinalization({
|
|
221
|
-
taskId: manifest.taskId ?? '', generation: manifest.generation, requestId, receipt
|
|
222
|
-
})
|
|
223
|
-
: {
|
|
224
|
-
state: 'unknown', taskId: manifest.taskId, observedSource: 'unknown', receipt: null,
|
|
225
|
-
reasonCode: 'SANDBOX_TASK_VIEW_SOURCE_UNCONFIRMED'
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
catch {
|
|
229
|
-
view = {
|
|
230
|
-
state: 'unknown', taskId: manifest.taskId, observedSource: 'unknown', receipt: null,
|
|
231
|
-
reasonCode: 'SANDBOX_TASK_VIEW_RECEIPT_INVALID'
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
writeSandboxControlStatus(manifest, broker, state, reasonCode, activeRequestId, Date.now(), view);
|
|
235
|
-
return view;
|
|
236
|
-
}
|
|
237
127
|
function payloadReference(payload) {
|
|
238
128
|
return {
|
|
239
129
|
version: payload.version,
|
|
@@ -257,7 +147,7 @@ function outputMatchesEvidence(output, bytes, sha256) {
|
|
|
257
147
|
return Buffer.byteLength(output, 'utf8') === bytes
|
|
258
148
|
&& createHash('sha256').update(output, 'utf8').digest('hex') === sha256;
|
|
259
149
|
}
|
|
260
|
-
export function genericRecoveryResponse(request, exitCode, payload, cause = 'recovery'
|
|
150
|
+
export function genericRecoveryResponse(request, exitCode, payload, cause = 'recovery') {
|
|
261
151
|
const outputUnavailable = request.family === 'task-create' && !payload;
|
|
262
152
|
return {
|
|
263
153
|
version: 2,
|
|
@@ -265,11 +155,9 @@ export function genericRecoveryResponse(request, exitCode, payload, cause = 'rec
|
|
|
265
155
|
phase: 'completed',
|
|
266
156
|
exitCode,
|
|
267
157
|
stdout: outputUnavailable ? `${JSON.stringify(taskCreateOutputUnavailableResult(request.id))}\n` : '',
|
|
268
|
-
stderr: payload ? '' :
|
|
269
|
-
?
|
|
270
|
-
:
|
|
271
|
-
? 'SANDBOX_CONTROL_OUTPUT_UNAVAILABLE: output payload was not retained\n'
|
|
272
|
-
: 'SANDBOX_CONTROL_OUTPUT_UNAVAILABLE: broker restarted after executor completion\n',
|
|
158
|
+
stderr: payload ? '' : cause === 'publish'
|
|
159
|
+
? 'SANDBOX_CONTROL_OUTPUT_UNAVAILABLE: output payload was not retained\n'
|
|
160
|
+
: 'SANDBOX_CONTROL_OUTPUT_UNAVAILABLE: broker restarted after executor completion\n',
|
|
273
161
|
error: null,
|
|
274
162
|
outputState: payload ? 'available' : 'unavailable',
|
|
275
163
|
payload: payload ? payloadReference(payload) : null
|
|
@@ -335,32 +223,10 @@ function controllerDomainEvidence(manifest, manifestPath, request, output) {
|
|
|
335
223
|
&& output?.status === 'closed' && typeof output.changed === 'boolean' };
|
|
336
224
|
}
|
|
337
225
|
}
|
|
338
|
-
function
|
|
339
|
-
if (!operation || !output)
|
|
340
|
-
return { consistent: false };
|
|
341
|
-
const outputRun = output.run && typeof output.run === 'object' && !Array.isArray(output.run)
|
|
342
|
-
? output.run : null;
|
|
343
|
-
const runMatches = outputRun === null ? run === null : run !== null && JSON.stringify(run) === JSON.stringify(outputRun);
|
|
344
|
-
if (operation.class === 'read-only') {
|
|
345
|
-
return {
|
|
346
|
-
consistent: output.status === terminalResult.status && output.changed === terminalResult.changed && runMatches,
|
|
347
|
-
snapshotValid: true,
|
|
348
|
-
status: run?.status ?? terminalResult.status,
|
|
349
|
-
pendingDelegation: run?.pendingDelegation ?? null
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
if (!run || !outputRun)
|
|
353
|
-
return { consistent: false };
|
|
354
|
-
return {
|
|
355
|
-
consistent: output.status === terminalResult.status && output.changed === terminalResult.changed && runMatches,
|
|
356
|
-
status: run.status,
|
|
357
|
-
pendingDelegation: run.pendingDelegation
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
function readRecoveryDomain(manifest, manifestPath, request, operation, terminalResult, payloadOutput) {
|
|
226
|
+
async function readRecoveryDomain(manifest, manifestPath, request, operation, terminalResult, payloadOutput) {
|
|
361
227
|
if (!operation)
|
|
362
228
|
return { domain: null };
|
|
363
|
-
const taskRef = request.family === 'task-finalization'
|
|
229
|
+
const taskRef = request.family === 'task-finalization'
|
|
364
230
|
? manifest.taskId
|
|
365
231
|
: 'args' in request ? request.args[0] ?? null : manifest.taskId;
|
|
366
232
|
const output = parseControlOutput(payloadOutput);
|
|
@@ -369,21 +235,7 @@ function readRecoveryDomain(manifest, manifestPath, request, operation, terminal
|
|
|
369
235
|
}
|
|
370
236
|
if (operation.family === 'task-lifecycle') {
|
|
371
237
|
if (operation.intent === 'recover-started') {
|
|
372
|
-
|
|
373
|
-
if (!('args' in request))
|
|
374
|
-
return { domain: null };
|
|
375
|
-
const parsed = parseTaskControlOperation('task-lifecycle', request.args);
|
|
376
|
-
if (parsed.family !== 'task-lifecycle' || parsed.request.intent !== 'recover-started') {
|
|
377
|
-
return { domain: null };
|
|
378
|
-
}
|
|
379
|
-
return {
|
|
380
|
-
domain: readLifecycleRecoveryDomainEvidence(manifest.repoRoot, parsed.request, terminalResult),
|
|
381
|
-
journal: readLifecycleJournalEvidence(manifest.repoRoot, taskRef)
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
catch {
|
|
385
|
-
return { domain: null };
|
|
386
|
-
}
|
|
238
|
+
return { domain: null };
|
|
387
239
|
}
|
|
388
240
|
if (!taskRef || !terminalResult.targetState)
|
|
389
241
|
return { domain: null };
|
|
@@ -403,51 +255,12 @@ function readRecoveryDomain(manifest, manifestPath, request, operation, terminal
|
|
|
403
255
|
return { domain: { consistent: false }, journal };
|
|
404
256
|
}
|
|
405
257
|
}
|
|
406
|
-
if (operation.family === 'task-orchestration') {
|
|
407
|
-
if (!taskRef)
|
|
408
|
-
return { domain: null };
|
|
409
|
-
try {
|
|
410
|
-
const resolved = resolveTaskRef(taskRef, { repoRoot: manifest.repoRoot });
|
|
411
|
-
if (!resolved.ok)
|
|
412
|
-
return { domain: { consistent: false } };
|
|
413
|
-
const run = readRun(resolved.taskDir);
|
|
414
|
-
if (!run && operation.class !== 'read-only')
|
|
415
|
-
return { domain: { consistent: false } };
|
|
416
|
-
if (operation.class === 'route.clean-completion') {
|
|
417
|
-
const snapshot = captureRepositorySnapshot(manifest.repoRoot);
|
|
418
|
-
const metadata = parseTypedTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
|
|
419
|
-
const completion = run?.completionEvidence ?? null;
|
|
420
|
-
const consistent = run !== null && completion !== null
|
|
421
|
-
&& terminalResult.completionEvidence !== null
|
|
422
|
-
&& isDeepStrictEqual(completion, terminalResult.completionEvidence);
|
|
423
|
-
return {
|
|
424
|
-
domain: {
|
|
425
|
-
consistent,
|
|
426
|
-
status: run?.status ?? null,
|
|
427
|
-
pendingDelegation: run?.pendingDelegation ?? null,
|
|
428
|
-
completionEvidence: completion,
|
|
429
|
-
snapshot,
|
|
430
|
-
lastReviewedCommit: metadata.last_reviewed_commit
|
|
431
|
-
}
|
|
432
|
-
};
|
|
433
|
-
}
|
|
434
|
-
return { domain: orchestrationDomainEvidence(operation, terminalResult, output, run) };
|
|
435
|
-
}
|
|
436
|
-
catch {
|
|
437
|
-
return { domain: { consistent: false } };
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
258
|
if (operation.family === 'task-create') {
|
|
441
259
|
return { domain: taskCreateDomainEvidence(manifest, output) };
|
|
442
260
|
}
|
|
443
261
|
if (operation.family === 'codex-controller') {
|
|
444
262
|
return { domain: controllerDomainEvidence(manifest, manifestPath, request, output) };
|
|
445
263
|
}
|
|
446
|
-
if (operation.family === 'task-workflow') {
|
|
447
|
-
return {
|
|
448
|
-
domain: { consistent: output?.status === terminalResult.status && output.changed === terminalResult.changed, snapshotValid: true }
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
264
|
return { domain: null };
|
|
452
265
|
}
|
|
453
266
|
function readCommittedCriticalPhases(manifest, requestId) {
|
|
@@ -461,8 +274,8 @@ function readCommittedCriticalPhases(manifest, requestId) {
|
|
|
461
274
|
}
|
|
462
275
|
});
|
|
463
276
|
}
|
|
464
|
-
export function recoveryResponse(manifest, manifestPath, request, evidence, payload, terminalResult) {
|
|
465
|
-
const operationName = recoveryOperationKey(request
|
|
277
|
+
export async function recoveryResponse(manifest, manifestPath, request, evidence, payload, terminalResult) {
|
|
278
|
+
const operationName = recoveryOperationKey(request);
|
|
466
279
|
const operation = operationName ? findSandboxControlRecoveryOperation(request.family, operationName) : null;
|
|
467
280
|
if (!operation)
|
|
468
281
|
return null;
|
|
@@ -473,35 +286,7 @@ export function recoveryResponse(manifest, manifestPath, request, evidence, payl
|
|
|
473
286
|
if (JSON.stringify(payloadTerminal) !== JSON.stringify(terminalResult))
|
|
474
287
|
return unknown(request.id);
|
|
475
288
|
}
|
|
476
|
-
const
|
|
477
|
-
if (evidence.exitCode === 0 && finalization?.status === 'deferred')
|
|
478
|
-
return null;
|
|
479
|
-
if (evidence.exitCode === 0 && request.family === 'task-workflow' && request.authority?.phase === 'task-event.completed') {
|
|
480
|
-
try {
|
|
481
|
-
const registration = readCodexControllerRegistration(manifestPath);
|
|
482
|
-
const recovered = recoverLifecycleRecoveryOperation(request.authority, {
|
|
483
|
-
repoRoot: manifest.repoRoot,
|
|
484
|
-
capabilityStore: createCodexCapabilityStore(),
|
|
485
|
-
buildIdentity: computeLifecycleBuildIdentity(manifest.repoRoot),
|
|
486
|
-
controllerBinding: {
|
|
487
|
-
instanceDigest: registration.controllerInstanceDigest,
|
|
488
|
-
controlGeneration: registration.controlGeneration
|
|
489
|
-
}
|
|
490
|
-
});
|
|
491
|
-
if (recovered.status !== 'committed')
|
|
492
|
-
return null;
|
|
493
|
-
}
|
|
494
|
-
catch (error) {
|
|
495
|
-
appendBrokerAudit(manifest, 'lifecycle-authority-recovery-failed', {
|
|
496
|
-
...requestAuditFields(manifest, request),
|
|
497
|
-
errorCode: error instanceof Error ? error.name : 'LIFECYCLE_AUTHORITY_RECOVERY_FAILED'
|
|
498
|
-
});
|
|
499
|
-
return null;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
const recovery = finalization
|
|
503
|
-
? { domain: { consistent: finalization.status === 'matched' } }
|
|
504
|
-
: readRecoveryDomain(manifest, manifestPath, request, operation, terminalResult, payload?.stdout ?? null);
|
|
289
|
+
const recovery = await readRecoveryDomain(manifest, manifestPath, request, operation, terminalResult, payload?.stdout ?? null);
|
|
505
290
|
const binding = operationRecoveryBinding(request.id, manifest.generation, manifest.taskId, request.family, operationName);
|
|
506
291
|
const decision = classifySandboxControlRecovery({
|
|
507
292
|
operation,
|
|
@@ -518,23 +303,9 @@ export function recoveryResponse(manifest, manifestPath, request, evidence, payl
|
|
|
518
303
|
return notExecuted(request.id);
|
|
519
304
|
if (decision.outcome !== 'success' && decision.outcome !== 'failure')
|
|
520
305
|
return null;
|
|
521
|
-
|
|
522
|
-
if (finalization?.status !== 'matched')
|
|
523
|
-
return null;
|
|
524
|
-
return finalization.response ?? null;
|
|
525
|
-
}
|
|
526
|
-
return genericRecoveryResponse(request, evidence.exitCode, payload, 'recovery', terminalResult.warning ?? null);
|
|
306
|
+
return genericRecoveryResponse(request, evidence.exitCode, payload);
|
|
527
307
|
}
|
|
528
|
-
function terminalMatchesEvidence(manifest,
|
|
529
|
-
if (request.family === 'task-finalization' && evidence.exitCode === 0) {
|
|
530
|
-
if (!terminalResult)
|
|
531
|
-
return { valid: false, payloadReferenced: false };
|
|
532
|
-
const expected = recoveryResponse(manifest, manifestPath, request, evidence, payload, terminalResult);
|
|
533
|
-
return {
|
|
534
|
-
valid: expected !== null && JSON.stringify(response) === JSON.stringify(expected),
|
|
535
|
-
payloadReferenced: false
|
|
536
|
-
};
|
|
537
|
-
}
|
|
308
|
+
async function terminalMatchesEvidence(manifest, request, response, evidence, payload, payloadInvalid, terminalResult) {
|
|
538
309
|
if (response.version !== 2 || response.id !== request.id || response.phase !== 'completed'
|
|
539
310
|
|| response.exitCode !== evidence.exitCode || response.error !== null) {
|
|
540
311
|
return { valid: false, payloadReferenced: false };
|
|
@@ -558,7 +329,7 @@ function terminalMatchesEvidence(manifest, manifestPath, request, response, evid
|
|
|
558
329
|
if (response.outputState === 'unavailable') {
|
|
559
330
|
const causes = ['recovery', 'publish'];
|
|
560
331
|
const valid = causes.some((cause) => JSON.stringify(response)
|
|
561
|
-
=== JSON.stringify(genericRecoveryResponse(request, evidence.exitCode, null, cause
|
|
332
|
+
=== JSON.stringify(genericRecoveryResponse(request, evidence.exitCode, null, cause)));
|
|
562
333
|
return { valid, payloadReferenced: false };
|
|
563
334
|
}
|
|
564
335
|
return {
|
|
@@ -568,58 +339,41 @@ function terminalMatchesEvidence(manifest, manifestPath, request, response, evid
|
|
|
568
339
|
payloadReferenced: false
|
|
569
340
|
};
|
|
570
341
|
}
|
|
571
|
-
function publishExecutionResult(manifest, request, result,
|
|
342
|
+
function publishExecutionResult(manifest, request, result, brokerOwns) {
|
|
572
343
|
const normalized = sanitizeSandboxControlResult(manifest, result);
|
|
573
344
|
const terminalResult = writeSandboxControlTerminalResult(manifest, {
|
|
574
345
|
id: request.id,
|
|
575
346
|
family: request.family,
|
|
576
|
-
operation: operationKey(request
|
|
347
|
+
operation: operationKey(request)
|
|
577
348
|
}, normalized.stdout);
|
|
578
349
|
if (fs.existsSync(path.join(manifest.processingDir, request.id, 'transitions'))) {
|
|
579
350
|
criticalRequestPhase(manifest, request, 'completed', normalized.exitCode === 0 ? 'success' : 'failure');
|
|
580
351
|
criticalRequestPhase(manifest, request, 'evidence-written', normalized.exitCode === 0 ? 'success' : 'failure');
|
|
581
352
|
criticalRequestPhase(manifest, request, 'publish-authorized', normalized.exitCode === 0 ? 'success' : 'failure');
|
|
582
353
|
}
|
|
583
|
-
let terminal =
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
terminal = finalization.response ?? null;
|
|
589
|
-
}
|
|
590
|
-
if (!terminal) {
|
|
591
|
-
const inline = {
|
|
592
|
-
version: 2, id: request.id, phase: 'completed', exitCode: normalized.exitCode,
|
|
593
|
-
stdout: normalized.stdout, stderr: normalized.stderr, error: null
|
|
594
|
-
};
|
|
595
|
-
if (sandboxControlEncodedJsonBytes(inline) <= SANDBOX_CONTROL_MAX_TERMINAL_RECORD_BYTES) {
|
|
596
|
-
terminal = inline;
|
|
597
|
-
}
|
|
354
|
+
let terminal = {
|
|
355
|
+
version: 2, id: request.id, phase: 'completed', exitCode: normalized.exitCode,
|
|
356
|
+
stdout: normalized.stdout, stderr: normalized.stderr, error: null
|
|
357
|
+
};
|
|
358
|
+
if (sandboxControlEncodedJsonBytes(terminal) > SANDBOX_CONTROL_MAX_TERMINAL_RECORD_BYTES) {
|
|
598
359
|
let payload = null;
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
writeSandboxControlPayload(manifest, request.id, normalized);
|
|
605
|
-
}
|
|
606
|
-
else {
|
|
607
|
-
payload = null;
|
|
608
|
-
}
|
|
360
|
+
try {
|
|
361
|
+
payload = createSandboxControlPayload(manifest, request.id, normalized);
|
|
362
|
+
const usage = sandboxControlGenerationUsage(manifest);
|
|
363
|
+
if (usage.bytes + sandboxControlEncodedJsonBytes(payload) <= SANDBOX_CONTROL_MAX_RESPONSE_BYTES) {
|
|
364
|
+
writeSandboxControlPayload(manifest, request.id, normalized);
|
|
609
365
|
}
|
|
610
|
-
|
|
366
|
+
else {
|
|
611
367
|
payload = null;
|
|
612
368
|
}
|
|
613
|
-
terminal = genericRecoveryResponse(request, normalized.exitCode, payload, 'publish', terminalResult.warning ?? null);
|
|
614
369
|
}
|
|
370
|
+
catch {
|
|
371
|
+
payload = null;
|
|
372
|
+
}
|
|
373
|
+
terminal = genericRecoveryResponse(request, normalized.exitCode, payload, 'publish');
|
|
615
374
|
}
|
|
616
375
|
if (!brokerOwns())
|
|
617
376
|
return false;
|
|
618
|
-
if (request.family === 'task-finalization' && normalized.exitCode === 0) {
|
|
619
|
-
const view = publishFinalizationTaskView(manifest, broker, request.id, 'healthy', null, null);
|
|
620
|
-
if (view.state === 'unknown')
|
|
621
|
-
return false;
|
|
622
|
-
}
|
|
623
377
|
const committed = writeSandboxControlResponse(manifest, terminal);
|
|
624
378
|
if (committed && fs.existsSync(path.join(manifest.processingDir, request.id, 'transitions'))) {
|
|
625
379
|
criticalRequestPhase(manifest, request, 'published-committed', normalized.exitCode === 0 ? 'success' : 'failure');
|
|
@@ -697,7 +451,7 @@ function assertCurrentSandboxControlIdentity(manifest, manifestPath) {
|
|
|
697
451
|
throw new Error(`SANDBOX_CONTROL_IDENTITY_${result.state.replaceAll('-', '_').toUpperCase()}`);
|
|
698
452
|
}
|
|
699
453
|
}
|
|
700
|
-
function recoverProcessing(manifest, manifestPath, broker, brokerOwns) {
|
|
454
|
+
async function recoverProcessing(manifest, manifestPath, broker, brokerOwns) {
|
|
701
455
|
for (const entry of fs.readdirSync(manifest.processingDir, { withFileTypes: true })) {
|
|
702
456
|
if (!entry.isDirectory() || !/^[a-f0-9-]{16,64}$/.test(entry.name))
|
|
703
457
|
continue;
|
|
@@ -819,16 +573,11 @@ function recoverProcessing(manifest, manifestPath, broker, brokerOwns) {
|
|
|
819
573
|
if (terminal && request && resultEvidence) {
|
|
820
574
|
if (!terminalResult && request.family !== 'task-create')
|
|
821
575
|
continue;
|
|
822
|
-
const reconciliation = terminalMatchesEvidence(manifest,
|
|
576
|
+
const reconciliation = await terminalMatchesEvidence(manifest, request, existingTerminalResponse, resultEvidence, payload, payloadInvalid, terminalResult);
|
|
823
577
|
if (!reconciliation.valid)
|
|
824
578
|
continue;
|
|
825
579
|
terminalReconciled = true;
|
|
826
580
|
payloadReferenced = reconciliation.payloadReferenced;
|
|
827
|
-
if (request.family === 'task-finalization' && resultEvidence.exitCode === 0) {
|
|
828
|
-
const view = publishFinalizationTaskView(manifest, broker, request.id, 'starting', null, null);
|
|
829
|
-
if (view.state === 'unknown')
|
|
830
|
-
continue;
|
|
831
|
-
}
|
|
832
581
|
}
|
|
833
582
|
if (!terminalResult && !terminalReconciled) {
|
|
834
583
|
if (terminal)
|
|
@@ -852,14 +601,9 @@ function recoverProcessing(manifest, manifestPath, broker, brokerOwns) {
|
|
|
852
601
|
return false;
|
|
853
602
|
if (!resultEvidence || !request || payloadInvalid)
|
|
854
603
|
continue;
|
|
855
|
-
const recovered = recoveryResponse(manifest, manifestPath, request, resultEvidence, payload, terminalResult);
|
|
604
|
+
const recovered = await recoveryResponse(manifest, manifestPath, request, resultEvidence, payload, terminalResult);
|
|
856
605
|
if (!recovered)
|
|
857
606
|
continue;
|
|
858
|
-
if (request.family === 'task-finalization' && resultEvidence.exitCode === 0) {
|
|
859
|
-
const view = publishFinalizationTaskView(manifest, broker, request.id, 'starting', null, null);
|
|
860
|
-
if (view.state === 'unknown')
|
|
861
|
-
continue;
|
|
862
|
-
}
|
|
863
607
|
writeSandboxControlResponse(manifest, recovered);
|
|
864
608
|
const preserveRecoveryEvidence = recovered.error?.code === 'SANDBOX_CONTROL_RESULT_UNKNOWN';
|
|
865
609
|
if (transitionProtocolActive && !preserveRecoveryEvidence) {
|
|
@@ -867,7 +611,7 @@ function recoverProcessing(manifest, manifestPath, broker, brokerOwns) {
|
|
|
867
611
|
}
|
|
868
612
|
if (preserveRecoveryEvidence)
|
|
869
613
|
continue;
|
|
870
|
-
payloadReferenced = Boolean(payload)
|
|
614
|
+
payloadReferenced = Boolean(payload);
|
|
871
615
|
}
|
|
872
616
|
}
|
|
873
617
|
else {
|
|
@@ -961,14 +705,10 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
961
705
|
startupReceipt = readTaskFinalizationReceipt(manifest.repoRoot, manifest.taskId);
|
|
962
706
|
}
|
|
963
707
|
catch {
|
|
964
|
-
// Preserve malformed receipt evidence as unknown rather than treating it as no receipt.
|
|
965
708
|
startupReceipt = {};
|
|
966
709
|
}
|
|
967
710
|
}
|
|
968
|
-
let taskView = taskViewForManifest({
|
|
969
|
-
...manifest,
|
|
970
|
-
receipt: startupReceipt
|
|
971
|
-
});
|
|
711
|
+
let taskView = taskViewForManifest({ ...manifest, receipt: startupReceipt });
|
|
972
712
|
try {
|
|
973
713
|
const previous = readSandboxControlStatus(manifest.publicStatusDir);
|
|
974
714
|
if (previous.generation === manifest.generation)
|
|
@@ -1008,7 +748,7 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
1008
748
|
pid: broker.pid,
|
|
1009
749
|
brokerId: broker.brokerId
|
|
1010
750
|
});
|
|
1011
|
-
if (!recoverProcessing(manifest, manifestPath, broker, brokerOwns))
|
|
751
|
+
if (!await recoverProcessing(manifest, manifestPath, broker, brokerOwns))
|
|
1012
752
|
return;
|
|
1013
753
|
try {
|
|
1014
754
|
const published = readSandboxControlStatus(manifest.publicStatusDir);
|
|
@@ -1150,21 +890,7 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
1150
890
|
break;
|
|
1151
891
|
let terminalCommitted = false;
|
|
1152
892
|
if (settledExecution.result && settledExecution.resultEvidenceWritten) {
|
|
1153
|
-
|
|
1154
|
-
active = settledExecution;
|
|
1155
|
-
continue;
|
|
1156
|
-
}
|
|
1157
|
-
terminalCommitted = publishExecutionResult(manifest, settledExecution.request, settledExecution.result, broker, brokerOwns);
|
|
1158
|
-
if (terminalCommitted && settledExecution.request.family === 'task-finalization') {
|
|
1159
|
-
try {
|
|
1160
|
-
const published = readSandboxControlStatus(manifest.publicStatusDir);
|
|
1161
|
-
if (published.generation === manifest.generation)
|
|
1162
|
-
taskView = published.taskView;
|
|
1163
|
-
}
|
|
1164
|
-
catch {
|
|
1165
|
-
taskView = { state: 'unknown', taskId: manifest.taskId, observedSource: 'unknown', receipt: null, reasonCode: 'SANDBOX_TASK_VIEW_STATUS_INVALID' };
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
893
|
+
terminalCommitted = publishExecutionResult(manifest, settledExecution.request, settledExecution.result, brokerOwns);
|
|
1168
894
|
}
|
|
1169
895
|
else {
|
|
1170
896
|
terminalCommitted = writeSandboxControlResponse(manifest, unknown(settledExecution.request.id));
|
|
@@ -1247,14 +973,9 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
1247
973
|
executorCwd: manifest.repoRoot,
|
|
1248
974
|
executorEntry: options.internalCliPath ?? process.argv[1] ?? null
|
|
1249
975
|
});
|
|
1250
|
-
const lifecycleAuthority = lifecycleAuthorityForRequest(manifest, manifestPath, request);
|
|
1251
|
-
if (lifecycleAuthority?.status === 'rejected') {
|
|
1252
|
-
throw Object.assign(new Error(lifecycleAuthority.error?.message ?? 'lifecycle authority was rejected'), { code: lifecycleAuthority.error?.code ?? 'LIFECYCLE_AUTHORITY_REJECTED' });
|
|
1253
|
-
}
|
|
1254
976
|
prepared = await prepareExecution({
|
|
1255
977
|
manifest, manifestPath, request, requestPath: claimed,
|
|
1256
|
-
internalCliPath: options.internalCliPath ?? process.argv[1]
|
|
1257
|
-
...(lifecycleAuthority ? { lifecycleAuthority } : {})
|
|
978
|
+
internalCliPath: options.internalCliPath ?? process.argv[1]
|
|
1258
979
|
});
|
|
1259
980
|
const preparedExecution = prepared;
|
|
1260
981
|
if (!preparedExecution)
|
|
@@ -1270,7 +991,7 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
1270
991
|
executionPath: executionPath(manifest, request.id)
|
|
1271
992
|
});
|
|
1272
993
|
const execution = {
|
|
1273
|
-
request, prepared: preparedExecution,
|
|
994
|
+
request, prepared: preparedExecution, result: null,
|
|
1274
995
|
resultEvidenceWritten: false, failure: null, settled: false
|
|
1275
996
|
};
|
|
1276
997
|
active = execution;
|
|
@@ -1431,8 +1152,7 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
1431
1152
|
}
|
|
1432
1153
|
}
|
|
1433
1154
|
if (owned && active.result && active.resultEvidenceWritten) {
|
|
1434
|
-
if (
|
|
1435
|
-
&& publishExecutionResult(manifest, active.request, active.result, broker, brokerOwns)) {
|
|
1155
|
+
if (publishExecutionResult(manifest, active.request, active.result, brokerOwns)) {
|
|
1436
1156
|
if (brokerOwns()) {
|
|
1437
1157
|
removeAcceptedResponse(manifest, active.request.id);
|
|
1438
1158
|
fs.rmSync(path.join(manifest.processingDir, active.request.id), { recursive: true, force: true });
|
|
@@ -1441,22 +1161,8 @@ export async function serveSandboxControl(manifestPath, signal = new AbortContro
|
|
|
1441
1161
|
}
|
|
1442
1162
|
}
|
|
1443
1163
|
if (active) {
|
|
1444
|
-
|
|
1445
|
-
if (owned && brokerOwns() && active
|
|
1446
|
-
const recovered = finalizationRecoveryResponse(manifest, active.request.id, 0);
|
|
1447
|
-
const view = recovered.status === 'matched'
|
|
1448
|
-
? publishFinalizationTaskView(manifest, broker, active.request.id, 'healthy', null, null)
|
|
1449
|
-
: null;
|
|
1450
|
-
if (view?.state !== 'unknown' && recovered.status === 'matched' && recovered.response
|
|
1451
|
-
&& writeSandboxControlResponse(manifest, recovered.response)) {
|
|
1452
|
-
if (terminationConfirmed && brokerOwns()) {
|
|
1453
|
-
removeAcceptedResponse(manifest, active.request.id);
|
|
1454
|
-
fs.rmSync(path.join(manifest.processingDir, active.request.id), { recursive: true, force: true });
|
|
1455
|
-
active = null;
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
if (owned && brokerOwns() && active && active.request.family !== 'task-finalization' && !active.resultEvidenceWritten) {
|
|
1164
|
+
active.prepared.terminate(owned);
|
|
1165
|
+
if (owned && brokerOwns() && active && !active.resultEvidenceWritten) {
|
|
1460
1166
|
writeSandboxControlResponse(manifest, unknown(active.request.id));
|
|
1461
1167
|
}
|
|
1462
1168
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { isCompletionEvidence } from '../../task/orchestration.js';
|
|
2
2
|
import { parseControlOutput } from '../../task/control-recovery.js';
|
|
3
|
-
import { isRecoveryWarning } from '../../task/recovery-warning.js';
|
|
4
3
|
import { execFileSync } from 'node:child_process';
|
|
5
4
|
import fs from 'node:fs';
|
|
6
5
|
import path from 'node:path';
|
|
@@ -84,7 +83,6 @@ export function createSandboxControlTerminalResult(manifest, request, output) {
|
|
|
84
83
|
? nested.run : null;
|
|
85
84
|
const rawCompletion = nested.completionEvidence ?? run?.completionEvidence;
|
|
86
85
|
const operation = request.operation ?? (typeof nested.intent === 'string' ? nested.intent : null) ?? '';
|
|
87
|
-
const warning = isRecoveryWarning(nested.warning) ? nested.warning : null;
|
|
88
86
|
return {
|
|
89
87
|
version: 1,
|
|
90
88
|
requestId: request.id,
|
|
@@ -94,8 +92,7 @@ export function createSandboxControlTerminalResult(manifest, request, output) {
|
|
|
94
92
|
targetState: typeof nested.targetState === 'string' ? nested.targetState : null,
|
|
95
93
|
status: typeof nested.status === 'string' ? nested.status : 'completed',
|
|
96
94
|
changed: typeof nested.changed === 'boolean' ? nested.changed : null,
|
|
97
|
-
completionEvidence: isCompletionEvidence(rawCompletion) ? rawCompletion : null
|
|
98
|
-
...(warning ? { warning } : {})
|
|
95
|
+
completionEvidence: isCompletionEvidence(rawCompletion) ? rawCompletion : null
|
|
99
96
|
};
|
|
100
97
|
}
|
|
101
98
|
export function writeSandboxControlTerminalResult(manifest, request, output) {
|
|
@@ -126,9 +123,6 @@ export function readSandboxControlTerminalResult(filePath) {
|
|
|
126
123
|
if (value.completionEvidence !== null && !isCompletionEvidence(value.completionEvidence)) {
|
|
127
124
|
throw new Error('SANDBOX_CONTROL_TERMINAL_RESULT_INVALID');
|
|
128
125
|
}
|
|
129
|
-
if (value.warning !== undefined && value.warning !== null && !isRecoveryWarning(value.warning)) {
|
|
130
|
-
throw new Error('SANDBOX_CONTROL_TERMINAL_RESULT_INVALID');
|
|
131
|
-
}
|
|
132
126
|
if (value.changed === undefined) {
|
|
133
127
|
throw new Error('SANDBOX_CONTROL_TERMINAL_RESULT_INVALID');
|
|
134
128
|
}
|