@fitlab-ai/agent-infra 0.11.1 → 0.11.3
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/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/platform-comment.js +59 -0
- package/dist/lib/internal/sandbox-control.js +2 -171
- package/dist/lib/internal/task-artifact.js +1 -1
- package/dist/lib/internal/task-lifecycle.js +1 -1
- package/dist/lib/internal/task-operation-registry.js +7 -2
- package/dist/lib/internal/task-review.js +5 -5
- package/dist/lib/internal/task-validate.js +0 -6
- package/dist/lib/platform/comment-safety.js +7 -1
- package/dist/lib/platform/github-provider.js +13 -3
- package/dist/lib/platform/issue-comments.js +93 -15
- package/dist/lib/platform/pr-summary.js +7 -2
- package/dist/lib/platform/provider-contract.d.ts +2 -0
- package/dist/lib/platform/provider-validation.js +7 -2
- package/dist/lib/platform/verification-sync.js +19 -2
- package/dist/lib/sandbox/control/client.js +3 -44
- package/dist/lib/sandbox/control/executor.js +14 -117
- package/dist/lib/sandbox/control/finalization-response.js +8 -2
- package/dist/lib/sandbox/control/protocol.js +5 -64
- package/dist/lib/sandbox/control/server.js +29 -206
- package/dist/lib/sandbox/control/state.js +1 -7
- package/dist/lib/sandbox/control/task-view.js +2 -1
- package/dist/lib/task/artifact-command.js +6 -6
- package/dist/lib/task/codex-orchestration.js +10 -208
- package/dist/lib/task/commit-operation.js +3 -18
- package/dist/lib/task/control-authority.js +35 -44
- package/dist/lib/task/control-recovery.js +3 -42
- package/dist/lib/task/delegation-receipts.js +16 -78
- package/dist/lib/task/events.js +89 -237
- package/dist/lib/task/finalization-artifacts.js +1 -3
- package/dist/lib/task/finalization-state.js +2 -1
- package/dist/lib/task/finalization.js +208 -57
- package/dist/lib/task/lifecycle-execution.js +2 -11
- package/dist/lib/task/lifecycle.js +1 -1
- package/dist/lib/task/local-artifact-finalization.js +25 -242
- package/dist/lib/task/manual-validation-receipt.js +8 -3
- package/dist/lib/task/orchestration.js +12 -24
- package/dist/lib/task/review-command.js +0 -1
- package/dist/lib/task/review-finalization.js +46 -211
- 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/platform-comment.ts +38 -0
- package/lib/internal/sandbox-control.ts +1 -185
- package/lib/internal/task-artifact.ts +1 -1
- package/lib/internal/task-lifecycle.ts +2 -2
- package/lib/internal/task-operation-registry.ts +8 -4
- package/lib/internal/task-review.ts +5 -5
- package/lib/internal/task-validate.ts +0 -5
- package/lib/platform/comment-safety.ts +8 -0
- package/lib/platform/github-provider.ts +11 -2
- package/lib/platform/issue-comments.ts +102 -17
- package/lib/platform/pr-summary.ts +10 -2
- package/lib/platform/provider-contract.ts +2 -0
- package/lib/platform/provider-validation.ts +6 -2
- package/lib/platform/verification-sync.ts +19 -2
- package/lib/sandbox/control/client.ts +5 -68
- package/lib/sandbox/control/executor.ts +14 -125
- package/lib/sandbox/control/finalization-response.ts +8 -2
- package/lib/sandbox/control/protocol.ts +7 -83
- package/lib/sandbox/control/server.ts +30 -220
- package/lib/sandbox/control/state.ts +1 -9
- package/lib/sandbox/control/task-view.ts +2 -1
- package/lib/task/artifact-command.ts +6 -7
- package/lib/task/codex-orchestration.ts +8 -241
- package/lib/task/commit-operation.ts +3 -23
- package/lib/task/control-authority.ts +39 -55
- package/lib/task/control-recovery.ts +3 -43
- package/lib/task/delegation-receipts.ts +14 -81
- package/lib/task/events.ts +106 -255
- package/lib/task/finalization-artifacts.ts +1 -3
- package/lib/task/finalization-state.ts +2 -1
- package/lib/task/finalization.ts +221 -65
- package/lib/task/lifecycle-execution.ts +10 -21
- package/lib/task/lifecycle.ts +2 -2
- package/lib/task/local-artifact-finalization.ts +23 -281
- package/lib/task/manual-validation-receipt.ts +8 -2
- package/lib/task/orchestration.ts +30 -53
- package/lib/task/review-command.ts +0 -1
- package/lib/task/review-finalization.ts +45 -193
- package/package.json +2 -2
- package/templates/.agents/rules/lifecycle-orchestration.en.md +23 -9
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +23 -9
- package/templates/.agents/rules/local-artifact-repair.en.md +14 -60
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -60
- package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/code-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +3 -3
- 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 +3 -3
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-code/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-plan/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
- 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 +10 -9
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +10 -9
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +2 -2
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +2 -2
- package/dist/lib/sandbox/control/task-workflow.js +0 -74
- package/dist/lib/sandbox/control/workflow-executor.js +0 -157
- 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 -18
- package/dist/lib/task/workflow-dispatch.js +0 -161
- package/lib/sandbox/control/task-workflow.ts +0 -95
- package/lib/sandbox/control/workflow-executor.ts +0 -183
- package/lib/task/lifecycle-recovery.ts +0 -691
- package/lib/task/recovery-warning.ts +0 -21
- package/lib/task/workflow-command.ts +0 -19
- package/lib/task/workflow-dispatch.ts +0 -171
|
@@ -5,21 +5,10 @@ import {
|
|
|
5
5
|
resolveCodexThread
|
|
6
6
|
} from '../agent-clients/adapters/codex-lifecycle/app-server.ts';
|
|
7
7
|
import { createCodexLifecycleStore } from '../agent-clients/adapters/codex-lifecycle/store.ts';
|
|
8
|
-
import {
|
|
9
|
-
createCodexCapabilityStore,
|
|
10
|
-
isCodexCapabilityProvenanceDetail
|
|
11
|
-
} from '../agent-clients/adapters/codex-lifecycle/capability-store.ts';
|
|
12
|
-
import type { CodexCapabilityProvenanceDetail } from '../agent-clients/adapters/codex-lifecycle/capability-store.ts';
|
|
13
8
|
import {
|
|
14
9
|
computeLifecycleBuildIdentity,
|
|
15
|
-
verifyLifecycleBuildIdentity,
|
|
16
10
|
type LifecycleBuildIdentity,
|
|
17
|
-
type LifecycleIdentityWarning
|
|
18
11
|
} from '../agent-clients/adapters/codex-lifecycle/build-identity.ts';
|
|
19
|
-
import { verifyCodexSandboxControllerContextWithWarnings as verifySandboxControllerWithWarnings } from '../agent-clients/adapters/codex-lifecycle/sandbox-controller.ts';
|
|
20
|
-
import {
|
|
21
|
-
verifyCodexSandboxControllerContextWithWarnings as verifyControllerContextFileWithWarnings
|
|
22
|
-
} from '../agent-clients/adapters/codex-lifecycle/controller-context.ts';
|
|
23
12
|
import type { AgentClientId } from '../agent-clients/types.ts';
|
|
24
13
|
import { resolveTaskRef } from './resolve-ref.ts';
|
|
25
14
|
import {
|
|
@@ -29,32 +18,20 @@ import {
|
|
|
29
18
|
OrchestrationStateError,
|
|
30
19
|
pauseMatchingOrchestrationDelegation,
|
|
31
20
|
prepareOrchestrationDelegation,
|
|
32
|
-
routeOrchestration,
|
|
33
21
|
reconcileMatchingOrchestrationDelegation,
|
|
34
22
|
sealMatchingOrchestrationDelegationWithHostEvidence
|
|
35
23
|
} from './orchestration.ts';
|
|
36
|
-
import { randomUUID, createHash } from 'node:crypto';
|
|
37
24
|
import type { OrchestrationOptions, OrchestrationResult } from './orchestration.ts';
|
|
38
|
-
import {
|
|
39
|
-
consumeLifecycleRecoveryAttestation,
|
|
40
|
-
issueLifecycleRecoveryAttestation,
|
|
41
|
-
validateLifecycleRecoveryAttestation,
|
|
42
|
-
type LifecycleRecoveryAttestationV1
|
|
43
|
-
} from './control-authority.ts';
|
|
44
25
|
|
|
45
26
|
type LifecycleStore = ReturnType<typeof createCodexLifecycleStore>;
|
|
46
|
-
type CapabilityStore = ReturnType<typeof createCodexCapabilityStore>;
|
|
47
27
|
type CodexBridgeOptions = Readonly<{
|
|
48
28
|
repoRoot?: string;
|
|
49
29
|
store?: LifecycleStore;
|
|
50
30
|
preflight?: typeof preflightCodexLifecycleEvidence;
|
|
51
31
|
resolveThread?: typeof resolveCodexThread;
|
|
52
32
|
resolveTerminal?: typeof resolveCodexTerminal;
|
|
53
|
-
capabilityStore?: CapabilityStore;
|
|
54
33
|
buildIdentity?: LifecycleBuildIdentity;
|
|
55
34
|
orchestrationOptions?: OrchestrationOptions;
|
|
56
|
-
controllerBinding?: Readonly<{ instanceDigest: string; controlGeneration: string }>;
|
|
57
|
-
deferLifecycleRecoveryConsumption?: boolean;
|
|
58
35
|
}>;
|
|
59
36
|
|
|
60
37
|
type CodexSpawnIdentity = Readonly<{
|
|
@@ -68,35 +45,14 @@ type CodexSpawnIdentity = Readonly<{
|
|
|
68
45
|
requestedReasoningEffort?: string;
|
|
69
46
|
}>;
|
|
70
47
|
|
|
71
|
-
function buildIdentityDigest(value: LifecycleBuildIdentity): string {
|
|
72
|
-
return createHash('sha256').update(JSON.stringify(value), 'utf8').digest('hex');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
48
|
function coreOptions(options: CodexBridgeOptions): OrchestrationOptions {
|
|
76
49
|
return { ...options.orchestrationOptions, repoRoot: options.repoRoot ?? options.orchestrationOptions?.repoRoot };
|
|
77
50
|
}
|
|
78
51
|
|
|
79
|
-
function bridgeFailure(code: string, message: string
|
|
52
|
+
function bridgeFailure(code: string, message: string): OrchestrationResult {
|
|
80
53
|
return {
|
|
81
54
|
status: 'failed', changed: false, taskId: null, run: null, next: null,
|
|
82
|
-
error: { code, message
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function capabilityFailure(error: unknown): NonNullable<OrchestrationResult['error']> {
|
|
87
|
-
const detailValue = error instanceof Error
|
|
88
|
-
? (error as Error & { detail?: unknown }).detail
|
|
89
|
-
: undefined;
|
|
90
|
-
return {
|
|
91
|
-
code: error instanceof Error && error.name.startsWith('CODEX_CAPABILITY_')
|
|
92
|
-
? error.name
|
|
93
|
-
: 'ORCHESTRATION_CLIENT_PREFLIGHT_FAILED',
|
|
94
|
-
message: error instanceof Error ? error.message : String(error),
|
|
95
|
-
...(error instanceof Error
|
|
96
|
-
&& error.name === 'CODEX_CAPABILITY_PROVENANCE_MISMATCH'
|
|
97
|
-
&& isCodexCapabilityProvenanceDetail(detailValue)
|
|
98
|
-
? { detail: detailValue }
|
|
99
|
-
: {})
|
|
55
|
+
error: { code, message }
|
|
100
56
|
};
|
|
101
57
|
}
|
|
102
58
|
|
|
@@ -112,35 +68,12 @@ function requiredStore(options: CodexBridgeOptions): LifecycleStore {
|
|
|
112
68
|
return options.store;
|
|
113
69
|
}
|
|
114
70
|
|
|
115
|
-
function brokerControllerBinding(): Readonly<{ instanceDigest: string; controlGeneration: string }> | null {
|
|
116
|
-
const raw = process.env.AGENT_INFRA_CONTROL_CONTROLLER_BINDING;
|
|
117
|
-
if (!raw) return null;
|
|
118
|
-
let value: unknown;
|
|
119
|
-
try {
|
|
120
|
-
value = JSON.parse(raw);
|
|
121
|
-
} catch {
|
|
122
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_BINDING_INVALID');
|
|
123
|
-
}
|
|
124
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
125
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_BINDING_INVALID');
|
|
126
|
-
}
|
|
127
|
-
const binding = value as Record<string, unknown>;
|
|
128
|
-
if (Object.keys(binding).sort().join(',') !== 'controlGeneration,instanceDigest'
|
|
129
|
-
|| typeof binding.instanceDigest !== 'string' || !/^[a-f0-9]{64}$/u.test(binding.instanceDigest)
|
|
130
|
-
|| typeof binding.controlGeneration !== 'string' || binding.controlGeneration.length === 0) {
|
|
131
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_BINDING_INVALID');
|
|
132
|
-
}
|
|
133
|
-
return binding as { instanceDigest: string; controlGeneration: string };
|
|
134
|
-
}
|
|
135
|
-
|
|
136
71
|
async function prepareCodexOrchestrationDelegation(
|
|
137
72
|
taskRef: string,
|
|
138
73
|
input: Readonly<{
|
|
139
74
|
client: AgentClientId;
|
|
140
75
|
requestedModel?: string;
|
|
141
76
|
requestedReasoningEffort?: string;
|
|
142
|
-
capabilityRef?: string;
|
|
143
|
-
lifecycleRecoveryAttestation?: LifecycleRecoveryAttestationV1 | null;
|
|
144
77
|
}>,
|
|
145
78
|
options: CodexBridgeOptions = {}
|
|
146
79
|
): Promise<OrchestrationResult> {
|
|
@@ -149,164 +82,11 @@ async function prepareCodexOrchestrationDelegation(
|
|
|
149
82
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
150
83
|
const resolved = resolveTaskRef(taskRef, { repoRoot });
|
|
151
84
|
if (!resolved.ok) return bridgeFailure(resolved.code, resolved.message);
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (!capabilityRef) {
|
|
155
|
-
return bridgeFailure(
|
|
156
|
-
'ORCHESTRATION_CODEX_CAPABILITY_REQUIRED',
|
|
157
|
-
'Codex prepare requires a current-session capability reference'
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
const buildIdentity = options.buildIdentity ?? computeLifecycleBuildIdentity(repoRoot);
|
|
161
|
-
const brokerController = options.controllerBinding ?? brokerControllerBinding();
|
|
162
|
-
const contextPath = process.env.AGENT_INFRA_CODEX_CONTROLLER_CONTEXT;
|
|
163
|
-
const contextVerification = contextPath
|
|
164
|
-
? (brokerController
|
|
165
|
-
? verifyControllerContextFileWithWarnings(contextPath, {
|
|
166
|
-
repoRoot,
|
|
167
|
-
generation: process.env.AGENT_INFRA_CONTROL_GENERATION ?? brokerController.controlGeneration
|
|
168
|
-
})
|
|
169
|
-
: verifySandboxControllerWithWarnings(contextPath, { repoRoot }))
|
|
170
|
-
: null;
|
|
171
|
-
const identityWarnings: LifecycleIdentityWarning[] = [...(contextVerification?.warnings ?? [])];
|
|
172
|
-
const localController = contextVerification?.context ?? null;
|
|
173
|
-
if (localController && brokerController
|
|
174
|
-
&& (localController.controllerInstanceDigest !== brokerController.instanceDigest
|
|
175
|
-
|| localController.controlGeneration !== brokerController.controlGeneration)) {
|
|
176
|
-
return bridgeFailure(
|
|
177
|
-
'CODEX_SANDBOX_CONTROLLER_BINDING_MISMATCH',
|
|
178
|
-
'broker and local controller bindings do not match'
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
const controller = brokerController ?? (localController ? {
|
|
182
|
-
instanceDigest: localController.controllerInstanceDigest,
|
|
183
|
-
controlGeneration: localController.controlGeneration
|
|
184
|
-
} : null);
|
|
185
|
-
const capabilityStore = options.capabilityStore ?? createCodexCapabilityStore();
|
|
186
|
-
const attested = capabilityStore.inspectReference(capabilityRef);
|
|
187
|
-
const capabilityIdentity = verifyLifecycleBuildIdentity(attested.buildIdentity, buildIdentity);
|
|
188
|
-
if (!capabilityIdentity.ok) {
|
|
189
|
-
return bridgeFailure(capabilityIdentity.code!, capabilityIdentity.message!);
|
|
190
|
-
}
|
|
191
|
-
identityWarnings.push(...capabilityIdentity.warnings);
|
|
192
|
-
const lifecycleProvenance = {
|
|
193
|
-
...attested.buildIdentity,
|
|
194
|
-
hookDefinitionHash: preflight.hookDefinitionHash,
|
|
195
|
-
...preflight.hookProvenance,
|
|
196
|
-
capabilitySessionId: attested.sessionId!,
|
|
197
|
-
capabilityTurnId: attested.turnId!,
|
|
198
|
-
capabilityToolUseId: attested.toolUseId!,
|
|
199
|
-
controllerInstanceDigest: controller?.instanceDigest ?? null,
|
|
200
|
-
controlGeneration: controller?.controlGeneration ?? null
|
|
201
|
-
};
|
|
202
|
-
const capabilityExpected = {
|
|
203
|
-
taskId: resolved.taskId,
|
|
204
|
-
hookDefinitionHash: preflight.hookDefinitionHash,
|
|
205
|
-
buildIdentity,
|
|
206
|
-
...(controller ? { controller: {
|
|
207
|
-
instanceDigest: controller.instanceDigest,
|
|
208
|
-
controlGeneration: controller.controlGeneration
|
|
209
|
-
} } : {})
|
|
210
|
-
};
|
|
211
|
-
if (input.lifecycleRecoveryAttestation) {
|
|
212
|
-
try { validateLifecycleRecoveryAttestation(input.lifecycleRecoveryAttestation); }
|
|
213
|
-
catch (error) {
|
|
214
|
-
return bridgeFailure(
|
|
215
|
-
'LIFECYCLE_AUTHORITY_ATTESTATION_INVALID',
|
|
216
|
-
error instanceof Error ? error.message : String(error)
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
let lifecycleRecoveryAttestation: LifecycleRecoveryAttestationV1 | null = input.lifecycleRecoveryAttestation ?? null;
|
|
221
|
-
const routed = input.capabilityRef && !lifecycleRecoveryAttestation
|
|
222
|
-
? routeOrchestration(taskRef, coreOptions(options))
|
|
223
|
-
: null;
|
|
224
|
-
if (routed && !routed.next) return routed;
|
|
225
|
-
if (routed?.next && ['analysis', 'plan', 'code'].includes(routed.next.stage)) {
|
|
226
|
-
const recoveryRequest = {
|
|
227
|
-
version: 1 as const,
|
|
228
|
-
requestId: randomUUID(),
|
|
229
|
-
operationId: randomUUID(),
|
|
230
|
-
phase: 'orchestration.prepare' as const,
|
|
231
|
-
taskId: resolved.taskId,
|
|
232
|
-
family: routed.next.stage === 'analysis' ? 'analysis' as const
|
|
233
|
-
: routed.next.stage === 'plan' ? 'plan' as const : 'code' as const,
|
|
234
|
-
artifact: routed.next.artifact,
|
|
235
|
-
round: routed.next.round,
|
|
236
|
-
lifecycleRequestId: randomUUID(),
|
|
237
|
-
authorityRef: capabilityRef,
|
|
238
|
-
expectedControlGeneration: controller?.controlGeneration ?? '',
|
|
239
|
-
expectedControllerInstanceDigest: controller?.instanceDigest ?? '0'.repeat(64),
|
|
240
|
-
expectedBuildIdentityDigest: buildIdentityDigest(buildIdentity),
|
|
241
|
-
expectedHookDefinitionHash: preflight.hookDefinitionHash
|
|
242
|
-
};
|
|
243
|
-
const authority = issueLifecycleRecoveryAttestation(recoveryRequest, {
|
|
244
|
-
capabilityStore,
|
|
245
|
-
...(controller ? { controllerBinding: controller } : {}),
|
|
246
|
-
buildIdentity
|
|
247
|
-
});
|
|
248
|
-
if (authority.status === 'rejected' || !authority.attestation) {
|
|
249
|
-
return bridgeFailure(
|
|
250
|
-
authority.error?.code ?? 'LIFECYCLE_AUTHORITY_REJECTED',
|
|
251
|
-
authority.error?.message ?? 'lifecycle authority was rejected'
|
|
252
|
-
);
|
|
253
|
-
}
|
|
254
|
-
lifecycleRecoveryAttestation = authority.attestation;
|
|
255
|
-
}
|
|
256
|
-
const prepared = prepareOrchestrationDelegation(taskRef, {
|
|
257
|
-
...input,
|
|
258
|
-
lifecycleProvenance,
|
|
259
|
-
lifecycleRecoveryAttestation
|
|
260
|
-
}, {
|
|
261
|
-
...coreOptions(options),
|
|
262
|
-
validateLifecycleCapability: () => {
|
|
263
|
-
try {
|
|
264
|
-
const validated = capabilityStore.validateReference(capabilityRef, capabilityExpected);
|
|
265
|
-
if (validated.sessionId !== attested.sessionId
|
|
266
|
-
|| validated.turnId !== attested.turnId
|
|
267
|
-
|| validated.toolUseId !== attested.toolUseId) {
|
|
268
|
-
return {
|
|
269
|
-
code: 'CODEX_CAPABILITY_IDENTITY_CHANGED',
|
|
270
|
-
message: 'capability identity changed during validation'
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
return null;
|
|
274
|
-
} catch (error) {
|
|
275
|
-
return capabilityFailure(error);
|
|
276
|
-
}
|
|
277
|
-
},
|
|
278
|
-
consumeLifecycleCapability: () => null
|
|
279
|
-
});
|
|
280
|
-
if (lifecycleRecoveryAttestation && !options.deferLifecycleRecoveryConsumption && prepared.status !== 'failed') {
|
|
281
|
-
try {
|
|
282
|
-
consumeLifecycleRecoveryAttestation(lifecycleRecoveryAttestation);
|
|
283
|
-
} catch (error) {
|
|
284
|
-
return bridgeFailure(
|
|
285
|
-
error instanceof Error ? error.name : 'LIFECYCLE_AUTHORITY_CONSUME_FAILED',
|
|
286
|
-
error instanceof Error ? error.message : String(error)
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
return identityWarnings.length > 0 && prepared.status !== 'failed'
|
|
291
|
-
? { ...prepared, warnings: Object.freeze(identityWarnings) }
|
|
292
|
-
: prepared;
|
|
85
|
+
await (options.preflight ?? preflightCodexLifecycleEvidence)(repoRoot);
|
|
86
|
+
return prepareOrchestrationDelegation(taskRef, input, coreOptions(options));
|
|
293
87
|
} catch (error) {
|
|
294
88
|
if (error instanceof OrchestrationStateError) return bridgeFailure(error.code, error.message);
|
|
295
|
-
|
|
296
|
-
? (error as Error & { detail?: unknown }).detail
|
|
297
|
-
: undefined;
|
|
298
|
-
const detail = error instanceof Error
|
|
299
|
-
&& error.name === 'CODEX_CAPABILITY_PROVENANCE_MISMATCH'
|
|
300
|
-
&& isCodexCapabilityProvenanceDetail(detailValue)
|
|
301
|
-
? detailValue
|
|
302
|
-
: undefined;
|
|
303
|
-
return bridgeFailure(
|
|
304
|
-
error instanceof Error && error.name.startsWith('CODEX_CAPABILITY_')
|
|
305
|
-
? error.name
|
|
306
|
-
: 'ORCHESTRATION_CLIENT_PREFLIGHT_FAILED',
|
|
307
|
-
error instanceof Error ? error.message : String(error),
|
|
308
|
-
detail
|
|
309
|
-
);
|
|
89
|
+
return bridgeFailure('ORCHESTRATION_CLIENT_PREFLIGHT_FAILED', error instanceof Error ? error.message : String(error));
|
|
310
90
|
}
|
|
311
91
|
}
|
|
312
92
|
|
|
@@ -335,16 +115,6 @@ async function activateCodexOrchestrationDelegation(
|
|
|
335
115
|
toolUseId: evidence.spawnToolUseId
|
|
336
116
|
});
|
|
337
117
|
const buildIdentity = options.buildIdentity ?? computeLifecycleBuildIdentity(repoRoot);
|
|
338
|
-
const contextPath = process.env.AGENT_INFRA_CODEX_CONTROLLER_CONTEXT;
|
|
339
|
-
const contextVerification = contextPath
|
|
340
|
-
? verifySandboxControllerWithWarnings(contextPath, { repoRoot })
|
|
341
|
-
: null;
|
|
342
|
-
const controller = options.controllerBinding
|
|
343
|
-
?? brokerControllerBinding()
|
|
344
|
-
?? (contextVerification?.context ? {
|
|
345
|
-
instanceDigest: contextVerification.context.controllerInstanceDigest,
|
|
346
|
-
controlGeneration: contextVerification.context.controlGeneration
|
|
347
|
-
} : null);
|
|
348
118
|
const activated = activateMatchingOrchestrationDelegation('codex', {
|
|
349
119
|
nativeAgent: evidence.nativeAgent,
|
|
350
120
|
childId: evidence.childThreadId,
|
|
@@ -366,14 +136,11 @@ async function activateCodexOrchestrationDelegation(
|
|
|
366
136
|
capabilityTurnId: evidence.parentTurnId,
|
|
367
137
|
spawnToolUseId: evidence.spawnToolUseId,
|
|
368
138
|
spawnObservedAt: record.spawnObservedAt ?? undefined,
|
|
369
|
-
controllerInstanceDigest:
|
|
370
|
-
controlGeneration:
|
|
139
|
+
controllerInstanceDigest: null,
|
|
140
|
+
controlGeneration: null
|
|
371
141
|
}
|
|
372
142
|
}, coreOptions(options));
|
|
373
|
-
|
|
374
|
-
return warnings.length > 0 && activated.status !== 'failed'
|
|
375
|
-
? { ...activated, warnings: Object.freeze(warnings) }
|
|
376
|
-
: activated;
|
|
143
|
+
return activated;
|
|
377
144
|
} catch (error) {
|
|
378
145
|
if (error instanceof OrchestrationStateError) return bridgeFailure(error.code, error.message);
|
|
379
146
|
return pauseBridge('ORCHESTRATION_CODEX_START_FAILED', error instanceof Error ? error.message : String(error), options);
|
|
@@ -32,8 +32,6 @@ type CommitOperationInput = Readonly<{
|
|
|
32
32
|
agent?: string;
|
|
33
33
|
mode?: CommitExecutionMode;
|
|
34
34
|
round?: number;
|
|
35
|
-
/** Permit one retry to rebase a prepared intent's expected tree while HEAD and intent identity remain unchanged. */
|
|
36
|
-
recoverPreparedIntent?: boolean;
|
|
37
35
|
delivery?: Readonly<{
|
|
38
36
|
mode: 'local' | 'push';
|
|
39
37
|
remote: string;
|
|
@@ -282,20 +280,6 @@ function checkpointTimestamp(): string {
|
|
|
282
280
|
return new Date().toISOString();
|
|
283
281
|
}
|
|
284
282
|
|
|
285
|
-
function samePreparedCheckpointIdentity(
|
|
286
|
-
pending: NonNullable<ReturnType<typeof readCheckpointIntent>>,
|
|
287
|
-
identity: Parameters<typeof checkpointIntentDigest>[0]
|
|
288
|
-
): boolean {
|
|
289
|
-
return pending.state === 'prepared'
|
|
290
|
-
&& pending.taskId === identity.taskId
|
|
291
|
-
&& pending.branch === identity.branch
|
|
292
|
-
&& pending.mode === identity.mode
|
|
293
|
-
&& pending.expectedHead === identity.expectedHead
|
|
294
|
-
&& pending.message === identity.message
|
|
295
|
-
&& pending.round === identity.round
|
|
296
|
-
&& JSON.stringify(pending.paths) === JSON.stringify(identity.paths);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
283
|
function executeUnlocked(input: CommitOperationInput, task: BoundTask | null, mode: CommitExecutionMode): CommitOperationResult {
|
|
300
284
|
const inspected = inspectGitWorkflow(input.cwd);
|
|
301
285
|
if (!inspected.snapshot) return failure(input, mode, task?.taskId ?? null, 'GIT_INSPECT_FAILED', 'Unable to inspect Git repository');
|
|
@@ -330,15 +314,11 @@ function executeUnlocked(input: CommitOperationInput, task: BoundTask | null, mo
|
|
|
330
314
|
};
|
|
331
315
|
}
|
|
332
316
|
if (pendingIntent && !sameCheckpointIntent(pendingIntent, identity)) {
|
|
333
|
-
|
|
334
|
-
status: 'failed' as const, changed: false, snapshot: inspected.snapshot, operations: [],
|
|
335
|
-
error: { code: 'COMMIT_INTENT_CONFLICT', message: 'A different checkpoint intent is still pending for this task' }
|
|
336
|
-
};
|
|
317
|
+
const timestamp = checkpointTimestamp();
|
|
337
318
|
pendingIntent = {
|
|
338
|
-
...
|
|
339
|
-
expectedTree: identity.expectedTree,
|
|
319
|
+
version: 1, ...identity,
|
|
340
320
|
digest: checkpointIntentDigest(identity),
|
|
341
|
-
updatedAt:
|
|
321
|
+
state: 'prepared', committedHead: null, createdAt: timestamp, updatedAt: timestamp
|
|
342
322
|
};
|
|
343
323
|
try { writeCheckpointIntent(task!.repoRoot, pendingIntent); }
|
|
344
324
|
catch (error) {
|
|
@@ -5,6 +5,7 @@ import fs from 'node:fs';
|
|
|
5
5
|
import { normalizeAgentToken } from '../agent-clients/tokens.ts';
|
|
6
6
|
import { isAgentClientId } from '../agent-clients/types.ts';
|
|
7
7
|
import type { AgentClientId } from '../agent-clients/types.ts';
|
|
8
|
+
import { getAgentClientAdapter } from '../agent-clients/registry.ts';
|
|
8
9
|
import { consumeHumanOverride, failureId, overrideDryRunConflict } from './human-override.ts';
|
|
9
10
|
import {
|
|
10
11
|
activateMatchingOrchestrationDelegation,
|
|
@@ -22,12 +23,7 @@ import {
|
|
|
22
23
|
sealOrchestrationDelegation,
|
|
23
24
|
statusOrchestration
|
|
24
25
|
} from './orchestration.ts';
|
|
25
|
-
import type {
|
|
26
|
-
OrchestrationDiagnosticLogger,
|
|
27
|
-
OrchestrationOptions,
|
|
28
|
-
OrchestrationResult
|
|
29
|
-
} from './orchestration.ts';
|
|
30
|
-
import { prepareCodexOrchestrationDelegation } from './codex-orchestration.ts';
|
|
26
|
+
import type { OrchestrationOptions, OrchestrationResult } from './orchestration.ts';
|
|
31
27
|
import {
|
|
32
28
|
applyTaskFinalization,
|
|
33
29
|
type TaskFinalizationRequest,
|
|
@@ -39,12 +35,10 @@ import {
|
|
|
39
35
|
type TaskLifecycleRequest,
|
|
40
36
|
type TaskLifecycleResult
|
|
41
37
|
} from './lifecycle.ts';
|
|
42
|
-
import {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
} from './lifecycle-recovery.ts';
|
|
47
|
-
import type { LifecycleRecoveryRequest } from './lifecycle-recovery.ts';
|
|
38
|
+
import type {
|
|
39
|
+
AgentClientLifecycleRecoveryRequest as LifecycleRecoveryRequest,
|
|
40
|
+
AgentClientLifecycleRecoveryResult as LifecycleRecoveryResult
|
|
41
|
+
} from '../agent-clients/adapter.ts';
|
|
48
42
|
import { locateActivityLog } from './activity-log.ts';
|
|
49
43
|
import { resolveTaskRef, TASK_ID_RE } from './resolve-ref.ts';
|
|
50
44
|
import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.ts';
|
|
@@ -542,7 +536,6 @@ export type TaskControlExecutionContext =
|
|
|
542
536
|
generation: string;
|
|
543
537
|
manifestPath: string;
|
|
544
538
|
requestId: string;
|
|
545
|
-
diagnosticLog?: OrchestrationDiagnosticLogger;
|
|
546
539
|
controllerBinding?: TaskControlControllerBinding | null;
|
|
547
540
|
lifecycleRecoveryAttestation?: LifecycleRecoveryAttestationV1 | null;
|
|
548
541
|
}>;
|
|
@@ -631,7 +624,6 @@ export function createSandboxExecutorExecutionContext(params: Readonly<{
|
|
|
631
624
|
generation: string;
|
|
632
625
|
manifestPath: string;
|
|
633
626
|
requestId: string;
|
|
634
|
-
diagnosticLog?: OrchestrationDiagnosticLogger;
|
|
635
627
|
controllerBinding?: TaskControlControllerBinding | null;
|
|
636
628
|
lifecycleRecoveryAttestation?: LifecycleRecoveryAttestationV1 | null;
|
|
637
629
|
}>): TaskControlExecutionContext {
|
|
@@ -652,7 +644,6 @@ export function createSandboxExecutorExecutionContext(params: Readonly<{
|
|
|
652
644
|
generation: params.generation,
|
|
653
645
|
manifestPath: absolute('manifestPath', params.manifestPath),
|
|
654
646
|
requestId: params.requestId,
|
|
655
|
-
...(params.diagnosticLog === undefined ? {} : { diagnosticLog: params.diagnosticLog }),
|
|
656
647
|
...(params.controllerBinding === undefined ? {} : { controllerBinding: binding(params.controllerBinding) }),
|
|
657
648
|
...(params.lifecycleRecoveryAttestation === undefined ? {} : {
|
|
658
649
|
lifecycleRecoveryAttestation: params.lifecycleRecoveryAttestation === null
|
|
@@ -697,11 +688,7 @@ function domainOptions(
|
|
|
697
688
|
): OrchestrationOptions {
|
|
698
689
|
return {
|
|
699
690
|
...options,
|
|
700
|
-
repoRoot: context.repoRoot
|
|
701
|
-
...(context.source === 'sandbox-executor' && context.diagnosticLog !== undefined
|
|
702
|
-
? { diagnosticLog: context.diagnosticLog }
|
|
703
|
-
: {}),
|
|
704
|
-
...(context.source === 'sandbox-executor' ? { gitWorktreeRoot: context.worktreeRoot } : {})
|
|
691
|
+
repoRoot: context.repoRoot
|
|
705
692
|
};
|
|
706
693
|
}
|
|
707
694
|
|
|
@@ -725,7 +712,17 @@ async function applyLifecycleWithAuthority(
|
|
|
725
712
|
}
|
|
726
713
|
const execute = async (): Promise<(TaskLifecycleResult | LifecycleRecoveryResult) & { humanOverride?: unknown }> => {
|
|
727
714
|
if (request.intent === 'recover-started') {
|
|
728
|
-
|
|
715
|
+
const adapter = isAgentClientId(request.agent)
|
|
716
|
+
? getAgentClientAdapter(request.agent).orchestrationAdapter
|
|
717
|
+
: undefined;
|
|
718
|
+
if (!adapter?.recoverStarted) {
|
|
719
|
+
return {
|
|
720
|
+
status: 'no-op', changed: false, targetState: 'active',
|
|
721
|
+
requestRef: request.taskRef, intent: 'recover-started', taskId: null,
|
|
722
|
+
receiptId: null, childId: null, error: null
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
return adapter.recoverStarted(request as LifecycleRecoveryRequest, { repoRoot: context.repoRoot });
|
|
729
726
|
}
|
|
730
727
|
const lifecycleResult = applyTaskLifecycle(request, { repoRoot: context.repoRoot });
|
|
731
728
|
if (lifecycleResult.status !== 'failed' || !request.overrideTicket) return lifecycleResult;
|
|
@@ -761,7 +758,12 @@ async function applyLifecycleWithAuthority(
|
|
|
761
758
|
} catch (error) {
|
|
762
759
|
if (!(error instanceof TaskExecutionLockError)) throw error;
|
|
763
760
|
if (request.intent === 'recover-started') {
|
|
764
|
-
return
|
|
761
|
+
return {
|
|
762
|
+
status: 'owner-unknown', changed: false, targetState: 'active',
|
|
763
|
+
requestRef: request.taskRef, intent: 'recover-started', taskId,
|
|
764
|
+
receiptId: null, childId: null,
|
|
765
|
+
error: { code: error.code, message: error.message }
|
|
766
|
+
};
|
|
765
767
|
}
|
|
766
768
|
return taskLifecycleFailure(request, { code: error.code, message: error.message }, taskId);
|
|
767
769
|
}
|
|
@@ -789,17 +791,13 @@ function orchestration(
|
|
|
789
791
|
client: input.client as AgentClientId,
|
|
790
792
|
requestedModel: input.requestedModel as string | undefined,
|
|
791
793
|
requestedReasoningEffort: input.requestedReasoningEffort as string | undefined,
|
|
792
|
-
...(input.capabilityRef === undefined ? {} : { capabilityRef: input.capabilityRef as string }),
|
|
793
|
-
...(context.lifecycleRecoveryAttestation === undefined
|
|
794
|
-
? {}
|
|
795
|
-
: { lifecycleRecoveryAttestation: context.lifecycleRecoveryAttestation })
|
|
796
794
|
};
|
|
797
|
-
|
|
798
|
-
|
|
795
|
+
const prepareDelegation = getAgentClientAdapter(prepareInput.client)
|
|
796
|
+
.orchestrationAdapter?.prepareDelegation;
|
|
797
|
+
if (prepareDelegation) {
|
|
798
|
+
return prepareDelegation(operation.taskRef, prepareInput, {
|
|
799
799
|
repoRoot: context.repoRoot,
|
|
800
800
|
orchestrationOptions: options,
|
|
801
|
-
deferLifecycleRecoveryConsumption: context.source === 'sandbox-executor',
|
|
802
|
-
...(context.controllerBinding ? { controllerBinding: context.controllerBinding } : {})
|
|
803
801
|
});
|
|
804
802
|
}
|
|
805
803
|
return prepareOrchestrationDelegation(operation.taskRef, prepareInput, options);
|
|
@@ -904,7 +902,7 @@ function operationInvalid(message: string): never {
|
|
|
904
902
|
|
|
905
903
|
const LIFECYCLE_FLAGS = new Set([
|
|
906
904
|
'--agent', '--reason', '--unblock-condition', '--note', '--alert-number', '--staging-dir', '--issue-number',
|
|
907
|
-
'--
|
|
905
|
+
'--auto', '--override-ticket', '--override-target', '--override-scope', '--dry-run'
|
|
908
906
|
]);
|
|
909
907
|
|
|
910
908
|
const FINALIZATION_FLAGS = new Set(['--agent']);
|
|
@@ -912,10 +910,10 @@ const FINALIZATION_FLAGS = new Set(['--agent']);
|
|
|
912
910
|
const ORCHESTRATION_FLAGS = new Set([
|
|
913
911
|
'--agent', '--max-steps', '--executor-model', '--executor-reasoning-effort', '--reviewer-model',
|
|
914
912
|
'--reviewer-reasoning-effort', '--client', '--requested-model', '--requested-reasoning-effort',
|
|
915
|
-
'--
|
|
913
|
+
'--parent-id', '--before-fingerprint', '--stage', '--round', '--artifact', '--role',
|
|
916
914
|
'--native-agent', '--child-id', '--spawn-mode', '--actual-model', '--actual-reasoning-effort',
|
|
917
915
|
'--model-fallback-reason', '--reasoning-effort-fallback-reason', '--exit-code', '--after-fingerprint',
|
|
918
|
-
'--changed-paths', '--code', '--message', '--recoverable'
|
|
916
|
+
'--changed-paths', '--code', '--message', '--recoverable'
|
|
919
917
|
]);
|
|
920
918
|
|
|
921
919
|
function parseValues(
|
|
@@ -926,7 +924,7 @@ function parseValues(
|
|
|
926
924
|
const values: Record<string, string | boolean> = {};
|
|
927
925
|
for (let index = start; index < args.length; index += 1) {
|
|
928
926
|
const flag = args[index]!;
|
|
929
|
-
if (flag === '--dry-run') {
|
|
927
|
+
if (flag === '--dry-run' || flag === '--auto') {
|
|
930
928
|
if (!flags.has(flag)) operationInvalid(`unknown option '${flag}'`);
|
|
931
929
|
if (values[flag] !== undefined) operationInvalid(`duplicate option '${flag}'`);
|
|
932
930
|
values[flag] = true;
|
|
@@ -984,28 +982,18 @@ export function parseTaskControlOperation(
|
|
|
984
982
|
...(value(values, '--override-scope') ? { overrideScope: value(values, '--override-scope') } : {}),
|
|
985
983
|
...(value(values, '--alert-number') ? { alertNumber: Number(value(values, '--alert-number')) } : {}),
|
|
986
984
|
...(value(values, '--issue-number') ? { issueNumber: Number(value(values, '--issue-number')) } : {}),
|
|
987
|
-
...(
|
|
988
|
-
...(value(values, '--round') ? { round: Number(value(values, '--round')) } : {}),
|
|
989
|
-
...(value(values, '--artifact') ? { artifact: value(values, '--artifact') } : {}),
|
|
985
|
+
...(values['--auto'] === true ? { auto: true } : {}),
|
|
990
986
|
...(values['--dry-run'] === true ? { dryRun: true } : {})
|
|
991
987
|
};
|
|
992
988
|
if (intent === 'recover-started') {
|
|
993
|
-
const recoveryFlags = new Set(['--agent', '--
|
|
989
|
+
const recoveryFlags = new Set(['--agent', '--auto']);
|
|
994
990
|
for (const flag of Object.keys(values)) {
|
|
995
991
|
if (!recoveryFlags.has(flag)) operationInvalid(`option '${flag}' is not supported for recover-started`);
|
|
996
992
|
}
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
}
|
|
1002
|
-
const round = Number(value(values, '--round'));
|
|
1003
|
-
if (!Number.isSafeInteger(round) || round < 1) operationInvalid('--round must be a positive integer');
|
|
1004
|
-
if (value(values, '--reason')!.includes('\n') || value(values, '--reason')!.includes('\r')) {
|
|
1005
|
-
operationInvalid('--reason must be a single line');
|
|
1006
|
-
}
|
|
1007
|
-
} else if (values['--stage'] !== undefined || values['--round'] !== undefined || values['--artifact'] !== undefined) {
|
|
1008
|
-
operationInvalid('--stage, --round, and --artifact are only supported for recover-started');
|
|
993
|
+
if (values['--auto'] !== true) operationInvalid('--auto is required for recover-started');
|
|
994
|
+
return { family, request: input as unknown as TaskLifecycleControlRequest };
|
|
995
|
+
} else if (values['--auto'] !== undefined) {
|
|
996
|
+
operationInvalid('--auto is only supported for recover-started');
|
|
1009
997
|
}
|
|
1010
998
|
return { family, request: input as unknown as TaskLifecycleControlRequest };
|
|
1011
999
|
}
|
|
@@ -1049,7 +1037,6 @@ export function parseTaskControlOperation(
|
|
|
1049
1037
|
if (parsedIntent === 'prepare') {
|
|
1050
1038
|
input.requestedModel = value(values, '--requested-model');
|
|
1051
1039
|
input.requestedReasoningEffort = value(values, '--requested-reasoning-effort');
|
|
1052
|
-
input.capabilityRef = value(values, '--capability-ref');
|
|
1053
1040
|
}
|
|
1054
1041
|
if (parsedIntent === 'await-activation') {
|
|
1055
1042
|
required(values, ['--stage', '--round', '--artifact', '--role']);
|
|
@@ -1099,8 +1086,5 @@ export function parseTaskControlOperation(
|
|
|
1099
1086
|
if (recoverable !== 'true' && recoverable !== 'false') operationInvalid('--recoverable must be true or false');
|
|
1100
1087
|
input.code = value(values, '--code'); input.message = value(values, '--message'); input.recoverable = recoverable === 'true';
|
|
1101
1088
|
}
|
|
1102
|
-
|
|
1103
|
-
? undefined
|
|
1104
|
-
: { gitWorktreeRoot: value(values, '--git-worktree-root') };
|
|
1105
|
-
return { family, taskRef, intent: parsedIntent, input, ...(options ? { options } : {}) };
|
|
1089
|
+
return { family, taskRef, intent: parsedIntent, input };
|
|
1106
1090
|
}
|