@fitlab-ai/agent-infra 0.11.0 → 0.11.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/dist/lib/internal/cli-route-inventory.js +1 -1
- package/dist/lib/internal/manual-validation.js +6 -2
- package/dist/lib/internal/platform-comment.js +59 -0
- package/dist/lib/internal/sandbox-control.js +4 -131
- package/dist/lib/internal/task-artifact.js +1 -1
- package/dist/lib/internal/task-operation-registry.js +1 -0
- 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 +120 -13
- package/dist/lib/platform/issues.js +3 -4
- 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 +161 -156
- package/dist/lib/sandbox/control/executor.js +0 -38
- package/dist/lib/sandbox/control/finalization-response.js +10 -2
- package/dist/lib/sandbox/control/task-view.js +3 -1
- package/dist/lib/sandbox/control/workflow-executor.js +32 -41
- package/dist/lib/task/artifact-command.js +6 -6
- package/dist/lib/task/artifact-lifecycle.js +15 -52
- package/dist/lib/task/artifact-operations.js +27 -1
- package/dist/lib/task/capabilities.js +0 -2
- 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 +1 -8
- package/dist/lib/task/delegation-receipts.js +14 -76
- package/dist/lib/task/events.js +147 -278
- package/dist/lib/task/finalization-state.js +2 -1
- package/dist/lib/task/finalization.js +273 -49
- package/dist/lib/task/gate-policy.js +94 -0
- package/dist/lib/task/lifecycle-execution.js +2 -11
- package/dist/lib/task/local-artifact-finalization.js +31 -245
- package/dist/lib/task/orchestration.js +8 -24
- package/dist/lib/task/review-artifacts.js +12 -6
- package/dist/lib/task/review-command.js +0 -1
- package/dist/lib/task/review-finalization.js +47 -218
- package/dist/lib/task/verification-engine.js +28 -17
- package/dist/lib/task/verification.js +25 -9
- package/dist/lib/task/workflow-command.js +4 -1
- package/dist/lib/task/workflow-dispatch.js +55 -3
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/internal/cli-route-inventory.ts +1 -1
- package/lib/internal/manual-validation.ts +6 -2
- package/lib/internal/platform-comment.ts +38 -0
- package/lib/internal/sandbox-control.ts +3 -145
- package/lib/internal/task-artifact.ts +1 -1
- package/lib/internal/task-operation-registry.ts +1 -0
- 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 +132 -13
- package/lib/platform/issues.ts +3 -4
- package/lib/platform/provider-contract.ts +2 -0
- package/lib/platform/provider-validation.ts +6 -2
- package/lib/platform/verification-sync.ts +178 -179
- package/lib/sandbox/control/executor.ts +0 -44
- package/lib/sandbox/control/finalization-response.ts +10 -2
- package/lib/sandbox/control/task-view.ts +3 -1
- package/lib/sandbox/control/workflow-executor.ts +31 -48
- package/lib/task/artifact-command.ts +6 -7
- package/lib/task/artifact-lifecycle.ts +12 -49
- package/lib/task/artifact-operations.ts +27 -1
- package/lib/task/capabilities.ts +0 -1
- package/lib/task/codex-orchestration.ts +8 -241
- package/lib/task/commit-operation.ts +3 -23
- package/lib/task/control-authority.ts +1 -8
- package/lib/task/delegation-receipts.ts +12 -79
- package/lib/task/events.ts +155 -287
- package/lib/task/finalization-state.ts +2 -1
- package/lib/task/finalization.ts +277 -57
- package/lib/task/gate-policy.ts +133 -0
- package/lib/task/lifecycle-execution.ts +10 -21
- package/lib/task/local-artifact-finalization.ts +29 -285
- package/lib/task/orchestration.ts +12 -41
- package/lib/task/review-artifacts.ts +8 -2
- package/lib/task/review-command.ts +0 -1
- package/lib/task/review-finalization.ts +46 -200
- package/lib/task/verification-engine.ts +24 -14
- package/lib/task/verification-types.ts +7 -0
- package/lib/task/verification.ts +25 -9
- package/lib/task/workflow-command.ts +4 -1
- package/lib/task/workflow-dispatch.ts +46 -3
- package/package.json +2 -2
- package/templates/.agents/rules/issue-sync.en.md +2 -0
- package/templates/.agents/rules/issue-sync.zh-CN.md +5 -8
- package/templates/.agents/rules/lifecycle-orchestration.en.md +7 -7
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +7 -7
- package/templates/.agents/rules/local-artifact-repair.en.md +14 -52
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -52
- 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/analyze-task/config/verify.en.json +1 -10
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -10
- package/templates/.agents/skills/block-task/config/verify.json +1 -3
- package/templates/.agents/skills/cancel-task/config/verify.json +1 -4
- 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/code-task/config/verify.en.json +1 -12
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +1 -12
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -0
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -0
- package/templates/.agents/skills/commit/config/verify.json +1 -5
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +6 -6
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +6 -6
- package/templates/.agents/skills/complete-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/complete-task/config/verify.en.json +3 -14
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +3 -14
- package/templates/.agents/skills/create-pr/config/verify.json +1 -10
- package/templates/.agents/skills/create-task/config/verify.json +1 -4
- package/templates/.agents/skills/import-issue/config/verify.json +1 -2
- 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/plan-task/config/verify.en.json +1 -10
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -10
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +4 -4
- 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-analysis/config/verify.en.json +1 -10
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -10
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +2 -0
- 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-code/config/verify.en.json +1 -10
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -10
- package/templates/.agents/skills/review-code/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +2 -0
- 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/review-plan/config/verify.en.json +1 -10
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -10
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +2 -0
- package/templates/.agents/skills/review-pr/config/verify.en.json +1 -8
- package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +1 -8
- package/templates/.agents/skills/run-manual-validation/config/verify.en.json +38 -13
- package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +38 -13
- package/templates/.agents/skills/run-task/SKILL.en.md +6 -6
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +6 -6
- 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
|
@@ -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) {
|
|
@@ -789,17 +789,11 @@ function orchestration(
|
|
|
789
789
|
client: input.client as AgentClientId,
|
|
790
790
|
requestedModel: input.requestedModel as string | undefined,
|
|
791
791
|
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
792
|
};
|
|
797
793
|
if (prepareInput.client === 'codex') {
|
|
798
794
|
return prepareCodexOrchestrationDelegation(operation.taskRef, prepareInput, {
|
|
799
795
|
repoRoot: context.repoRoot,
|
|
800
796
|
orchestrationOptions: options,
|
|
801
|
-
deferLifecycleRecoveryConsumption: context.source === 'sandbox-executor',
|
|
802
|
-
...(context.controllerBinding ? { controllerBinding: context.controllerBinding } : {})
|
|
803
797
|
});
|
|
804
798
|
}
|
|
805
799
|
return prepareOrchestrationDelegation(operation.taskRef, prepareInput, options);
|
|
@@ -912,7 +906,7 @@ const FINALIZATION_FLAGS = new Set(['--agent']);
|
|
|
912
906
|
const ORCHESTRATION_FLAGS = new Set([
|
|
913
907
|
'--agent', '--max-steps', '--executor-model', '--executor-reasoning-effort', '--reviewer-model',
|
|
914
908
|
'--reviewer-reasoning-effort', '--client', '--requested-model', '--requested-reasoning-effort',
|
|
915
|
-
'--
|
|
909
|
+
'--parent-id', '--before-fingerprint', '--stage', '--round', '--artifact', '--role',
|
|
916
910
|
'--native-agent', '--child-id', '--spawn-mode', '--actual-model', '--actual-reasoning-effort',
|
|
917
911
|
'--model-fallback-reason', '--reasoning-effort-fallback-reason', '--exit-code', '--after-fingerprint',
|
|
918
912
|
'--changed-paths', '--code', '--message', '--recoverable', '--git-worktree-root'
|
|
@@ -1049,7 +1043,6 @@ export function parseTaskControlOperation(
|
|
|
1049
1043
|
if (parsedIntent === 'prepare') {
|
|
1050
1044
|
input.requestedModel = value(values, '--requested-model');
|
|
1051
1045
|
input.requestedReasoningEffort = value(values, '--requested-reasoning-effort');
|
|
1052
|
-
input.capabilityRef = value(values, '--capability-ref');
|
|
1053
1046
|
}
|
|
1054
1047
|
if (parsedIntent === 'await-activation') {
|
|
1055
1048
|
required(values, ['--stage', '--round', '--artifact', '--role']);
|
|
@@ -108,13 +108,6 @@ function exactText(value: unknown): value is string {
|
|
|
108
108
|
return typeof value === 'string' && value.length > 0 && value.trim() === value;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
function validCodexBuildMetadata(value: Readonly<Record<string, unknown>>): boolean {
|
|
112
|
-
return Number.isSafeInteger(value.protocolVersion) && (value.protocolVersion as number) > 0
|
|
113
|
-
&& exactText(value.packageVersion)
|
|
114
|
-
&& exactText(value.internalExecutableBuildHash)
|
|
115
|
-
&& exactText(value.lifecycleContractHash);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
111
|
function nullableText(value: unknown): value is string | null {
|
|
119
112
|
return value === null || exactText(value);
|
|
120
113
|
}
|
|
@@ -183,52 +176,6 @@ function isDelegationHostEvidence(value: unknown): value is DelegationHostEviden
|
|
|
183
176
|
&& nullableText(value.controlGeneration);
|
|
184
177
|
}
|
|
185
178
|
|
|
186
|
-
function hasCurrentCodexEvidence(receipt: DelegationReceipt): boolean {
|
|
187
|
-
const provenance = receipt.lifecycleProvenance;
|
|
188
|
-
if (!provenance) return false;
|
|
189
|
-
const activated = ['activated', 'stage-completed', 'sealed', 'consumed'].includes(receipt.status)
|
|
190
|
-
|| (receipt.status === 'aborted' && receipt.activatedAt !== null);
|
|
191
|
-
if (!activated) return receipt.hostEvidence === null;
|
|
192
|
-
const host = receipt.hostEvidence;
|
|
193
|
-
if (
|
|
194
|
-
host?.kind !== 'codex-lifecycle-v2'
|
|
195
|
-
|| host.protocolVersion !== provenance.protocolVersion
|
|
196
|
-
|| host.hookDefinitionHash !== provenance.hookDefinitionHash
|
|
197
|
-
|| host.hookSource !== provenance.hookSource
|
|
198
|
-
|| host.hookSourcePathDigest !== provenance.hookSourcePathDigest
|
|
199
|
-
|| host.hookSourceHash !== provenance.hookSourceHash
|
|
200
|
-
|| host.capabilitySessionId !== provenance.capabilitySessionId
|
|
201
|
-
|| host.capabilityTurnId !== provenance.capabilityTurnId
|
|
202
|
-
|| host.controllerInstanceDigest !== provenance.controllerInstanceDigest
|
|
203
|
-
|| host.controlGeneration !== provenance.controlGeneration
|
|
204
|
-
|| receipt.parentId !== provenance.capabilitySessionId
|
|
205
|
-
|| host.spawnToolUseId === provenance.capabilityToolUseId
|
|
206
|
-
) return false;
|
|
207
|
-
const spawnObservedAt = Date.parse(host.spawnObservedAt ?? '');
|
|
208
|
-
const spawnDispatchedAt = Date.parse(receipt.spawnDispatchedAt ?? '');
|
|
209
|
-
const activationDeadlineAt = Date.parse(receipt.activationDeadlineAt ?? '');
|
|
210
|
-
if (
|
|
211
|
-
!Number.isFinite(spawnObservedAt)
|
|
212
|
-
|| !Number.isFinite(spawnDispatchedAt)
|
|
213
|
-
|| !Number.isFinite(activationDeadlineAt)
|
|
214
|
-
|| spawnObservedAt < spawnDispatchedAt
|
|
215
|
-
|| spawnObservedAt > activationDeadlineAt
|
|
216
|
-
) return false;
|
|
217
|
-
if (['sealed', 'consumed'].includes(receipt.status)) {
|
|
218
|
-
return Number.isSafeInteger(host.stopRevision)
|
|
219
|
-
&& (host.stopRevision as number) > host.startRevision
|
|
220
|
-
&& host.consumer === receipt.id
|
|
221
|
-
&& exactText(host.consumedAt);
|
|
222
|
-
}
|
|
223
|
-
if (receipt.status === 'aborted') {
|
|
224
|
-
return Number.isSafeInteger(host.stopRevision)
|
|
225
|
-
&& (host.stopRevision as number) > host.startRevision
|
|
226
|
-
&& host.consumer === `lifecycle-recovery:${receipt.taskId}:${receipt.id}`
|
|
227
|
-
&& exactText(host.consumedAt);
|
|
228
|
-
}
|
|
229
|
-
return host.stopRevision === null && host.consumer === null && host.consumedAt === null;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
179
|
const RECEIPT_KEYS = [
|
|
233
180
|
'id', 'taskId', 'runId', 'role', 'stage', 'round', 'artifact', 'client',
|
|
234
181
|
'requestedModel', 'requestedReasoningEffort', 'actualModel', 'actualReasoningEffort',
|
|
@@ -366,8 +313,15 @@ function isDelegationReceipt(value: unknown): value is DelegationReceipt {
|
|
|
366
313
|
&& nullableText(value.consumedAt);
|
|
367
314
|
if (!structurallyValid) return false;
|
|
368
315
|
const receipt = value as unknown as DelegationReceipt;
|
|
369
|
-
|
|
370
|
-
|
|
316
|
+
if (!hasStatusBoundEvidence(receipt)) return false;
|
|
317
|
+
const host = receipt.hostEvidence;
|
|
318
|
+
if (receipt.client === 'codex' && receipt.activatedAt !== null) {
|
|
319
|
+
if (host?.kind !== 'codex-lifecycle-v2' || host.capabilitySessionId !== receipt.parentId) return false;
|
|
320
|
+
if (['sealed', 'consumed'].includes(receipt.status)) {
|
|
321
|
+
return Number.isSafeInteger(host.stopRevision) && host.stopRevision! > host.startRevision;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return true;
|
|
371
325
|
}
|
|
372
326
|
|
|
373
327
|
const MANAGED_AGENTS = {
|
|
@@ -550,30 +504,9 @@ function activateDelegation(
|
|
|
550
504
|
|| event.hostEvidence.startRevision < 1
|
|
551
505
|
)
|
|
552
506
|
) return fail('DELEGATION_HOST_EVIDENCE_INVALID', 'Codex start evidence reference is invalid');
|
|
553
|
-
if (event.hostEvidence?.kind === 'codex-lifecycle-v2'
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
const spawnDispatchedAt = Date.parse(receipt.spawnDispatchedAt);
|
|
557
|
-
const activationDeadlineAt = Date.parse(receipt.activationDeadlineAt);
|
|
558
|
-
if (
|
|
559
|
-
!expected
|
|
560
|
-
|| event.hostEvidence.protocolVersion !== expected.protocolVersion
|
|
561
|
-
|| event.hostEvidence.hookDefinitionHash !== expected.hookDefinitionHash
|
|
562
|
-
|| event.hostEvidence.hookSource !== expected.hookSource
|
|
563
|
-
|| event.hostEvidence.hookSourcePathDigest !== expected.hookSourcePathDigest
|
|
564
|
-
|| event.hostEvidence.hookSourceHash !== expected.hookSourceHash
|
|
565
|
-
|| event.hostEvidence.capabilitySessionId !== expected.capabilitySessionId
|
|
566
|
-
|| event.hostEvidence.capabilityTurnId !== expected.capabilityTurnId
|
|
567
|
-
|| !event.hostEvidence.spawnToolUseId?.trim()
|
|
568
|
-
|| event.hostEvidence.spawnToolUseId === expected.capabilityToolUseId
|
|
569
|
-
|| !Number.isFinite(spawnObservedAt)
|
|
570
|
-
|| spawnObservedAt < spawnDispatchedAt
|
|
571
|
-
|| spawnObservedAt > activationDeadlineAt
|
|
572
|
-
|| event.parentId !== expected.capabilitySessionId
|
|
573
|
-
|| (event.hostEvidence.controllerInstanceDigest ?? null) !== expected.controllerInstanceDigest
|
|
574
|
-
|| (event.hostEvidence.controlGeneration ?? null) !== expected.controlGeneration
|
|
575
|
-
|| !validCodexBuildMetadata(event.hostEvidence)
|
|
576
|
-
) return fail('DELEGATION_HOST_EVIDENCE_INVALID', 'Codex lifecycle provenance does not match the prepared receipt');
|
|
507
|
+
if (event.hostEvidence?.kind === 'codex-lifecycle-v2'
|
|
508
|
+
&& event.hostEvidence.capabilitySessionId !== event.parentId) {
|
|
509
|
+
return fail('DELEGATION_HOST_EVIDENCE_INVALID', 'Codex start evidence does not match the observed parent');
|
|
577
510
|
}
|
|
578
511
|
return { ok: true, receipt: Object.freeze({
|
|
579
512
|
...receipt,
|