@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.
Files changed (131) hide show
  1. package/dist/bin/internal-cli.js +7 -2
  2. package/dist/lib/agent-clients/adapter.js +3 -0
  3. package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +234 -0
  4. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +8 -35
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +1 -34
  6. package/dist/lib/agent-clients/adapters/codex.js +10 -0
  7. package/dist/lib/internal/cli-route-inventory.js +1 -1
  8. package/dist/lib/internal/manual-validation.js +22 -27
  9. package/dist/lib/internal/platform-comment.js +59 -0
  10. package/dist/lib/internal/sandbox-control.js +2 -171
  11. package/dist/lib/internal/task-artifact.js +1 -1
  12. package/dist/lib/internal/task-lifecycle.js +1 -1
  13. package/dist/lib/internal/task-operation-registry.js +7 -2
  14. package/dist/lib/internal/task-review.js +5 -5
  15. package/dist/lib/internal/task-validate.js +0 -6
  16. package/dist/lib/platform/comment-safety.js +7 -1
  17. package/dist/lib/platform/github-provider.js +13 -3
  18. package/dist/lib/platform/issue-comments.js +93 -15
  19. package/dist/lib/platform/pr-summary.js +7 -2
  20. package/dist/lib/platform/provider-contract.d.ts +2 -0
  21. package/dist/lib/platform/provider-validation.js +7 -2
  22. package/dist/lib/platform/verification-sync.js +19 -2
  23. package/dist/lib/sandbox/control/client.js +3 -44
  24. package/dist/lib/sandbox/control/executor.js +14 -117
  25. package/dist/lib/sandbox/control/finalization-response.js +8 -2
  26. package/dist/lib/sandbox/control/protocol.js +5 -64
  27. package/dist/lib/sandbox/control/server.js +29 -206
  28. package/dist/lib/sandbox/control/state.js +1 -7
  29. package/dist/lib/sandbox/control/task-view.js +2 -1
  30. package/dist/lib/task/artifact-command.js +6 -6
  31. package/dist/lib/task/codex-orchestration.js +10 -208
  32. package/dist/lib/task/commit-operation.js +3 -18
  33. package/dist/lib/task/control-authority.js +35 -44
  34. package/dist/lib/task/control-recovery.js +3 -42
  35. package/dist/lib/task/delegation-receipts.js +16 -78
  36. package/dist/lib/task/events.js +89 -237
  37. package/dist/lib/task/finalization-artifacts.js +1 -3
  38. package/dist/lib/task/finalization-state.js +2 -1
  39. package/dist/lib/task/finalization.js +208 -57
  40. package/dist/lib/task/lifecycle-execution.js +2 -11
  41. package/dist/lib/task/lifecycle.js +1 -1
  42. package/dist/lib/task/local-artifact-finalization.js +25 -242
  43. package/dist/lib/task/manual-validation-receipt.js +8 -3
  44. package/dist/lib/task/orchestration.js +12 -24
  45. package/dist/lib/task/review-command.js +0 -1
  46. package/dist/lib/task/review-finalization.js +46 -211
  47. package/dist/lifecycle-build-manifest.json +3 -3
  48. package/lib/agent-clients/adapter.ts +46 -0
  49. package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +297 -0
  50. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +13 -33
  51. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +1 -44
  52. package/lib/agent-clients/adapters/codex.ts +10 -0
  53. package/lib/internal/cli-route-inventory.ts +1 -1
  54. package/lib/internal/manual-validation.ts +22 -26
  55. package/lib/internal/platform-comment.ts +38 -0
  56. package/lib/internal/sandbox-control.ts +1 -185
  57. package/lib/internal/task-artifact.ts +1 -1
  58. package/lib/internal/task-lifecycle.ts +2 -2
  59. package/lib/internal/task-operation-registry.ts +8 -4
  60. package/lib/internal/task-review.ts +5 -5
  61. package/lib/internal/task-validate.ts +0 -5
  62. package/lib/platform/comment-safety.ts +8 -0
  63. package/lib/platform/github-provider.ts +11 -2
  64. package/lib/platform/issue-comments.ts +102 -17
  65. package/lib/platform/pr-summary.ts +10 -2
  66. package/lib/platform/provider-contract.ts +2 -0
  67. package/lib/platform/provider-validation.ts +6 -2
  68. package/lib/platform/verification-sync.ts +19 -2
  69. package/lib/sandbox/control/client.ts +5 -68
  70. package/lib/sandbox/control/executor.ts +14 -125
  71. package/lib/sandbox/control/finalization-response.ts +8 -2
  72. package/lib/sandbox/control/protocol.ts +7 -83
  73. package/lib/sandbox/control/server.ts +30 -220
  74. package/lib/sandbox/control/state.ts +1 -9
  75. package/lib/sandbox/control/task-view.ts +2 -1
  76. package/lib/task/artifact-command.ts +6 -7
  77. package/lib/task/codex-orchestration.ts +8 -241
  78. package/lib/task/commit-operation.ts +3 -23
  79. package/lib/task/control-authority.ts +39 -55
  80. package/lib/task/control-recovery.ts +3 -43
  81. package/lib/task/delegation-receipts.ts +14 -81
  82. package/lib/task/events.ts +106 -255
  83. package/lib/task/finalization-artifacts.ts +1 -3
  84. package/lib/task/finalization-state.ts +2 -1
  85. package/lib/task/finalization.ts +221 -65
  86. package/lib/task/lifecycle-execution.ts +10 -21
  87. package/lib/task/lifecycle.ts +2 -2
  88. package/lib/task/local-artifact-finalization.ts +23 -281
  89. package/lib/task/manual-validation-receipt.ts +8 -2
  90. package/lib/task/orchestration.ts +30 -53
  91. package/lib/task/review-command.ts +0 -1
  92. package/lib/task/review-finalization.ts +45 -193
  93. package/package.json +2 -2
  94. package/templates/.agents/rules/lifecycle-orchestration.en.md +23 -9
  95. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +23 -9
  96. package/templates/.agents/rules/local-artifact-repair.en.md +14 -60
  97. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -60
  98. package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
  99. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
  100. package/templates/.agents/skills/code-task/SKILL.en.md +3 -3
  101. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +3 -3
  102. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +2 -2
  103. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +2 -2
  104. package/templates/.agents/skills/complete-task/SKILL.en.md +7 -8
  105. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +7 -8
  106. package/templates/.agents/skills/plan-task/SKILL.en.md +3 -3
  107. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +3 -3
  108. package/templates/.agents/skills/review-analysis/SKILL.en.md +2 -2
  109. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
  110. package/templates/.agents/skills/review-code/SKILL.en.md +3 -3
  111. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +3 -3
  112. package/templates/.agents/skills/review-plan/SKILL.en.md +2 -2
  113. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
  114. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +2 -2
  115. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +2 -2
  116. package/templates/.agents/skills/run-task/SKILL.en.md +10 -9
  117. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +10 -9
  118. package/templates/.agents/skills/run-task/reference/host-validation.en.md +2 -2
  119. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +2 -2
  120. package/dist/lib/sandbox/control/task-workflow.js +0 -74
  121. package/dist/lib/sandbox/control/workflow-executor.js +0 -157
  122. package/dist/lib/task/lifecycle-recovery.js +0 -549
  123. package/dist/lib/task/recovery-warning.js +0 -19
  124. package/dist/lib/task/workflow-command.js +0 -18
  125. package/dist/lib/task/workflow-dispatch.js +0 -161
  126. package/lib/sandbox/control/task-workflow.ts +0 -95
  127. package/lib/sandbox/control/workflow-executor.ts +0 -183
  128. package/lib/task/lifecycle-recovery.ts +0 -691
  129. package/lib/task/recovery-warning.ts +0 -21
  130. package/lib/task/workflow-command.ts +0 -19
  131. 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, detail?: CodexCapabilityProvenanceDetail): OrchestrationResult {
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, ...(detail ? { detail } : {}) }
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
- const preflight = await (options.preflight ?? preflightCodexLifecycleEvidence)(repoRoot);
153
- const capabilityRef = input.capabilityRef;
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
- const detailValue = error instanceof Error
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: controller?.instanceDigest ?? null,
370
- controlGeneration: controller?.controlGeneration ?? null
139
+ controllerInstanceDigest: null,
140
+ controlGeneration: null
371
141
  }
372
142
  }, coreOptions(options));
373
- const warnings = contextVerification?.warnings ?? [];
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
- if (!input.recoverPreparedIntent || !samePreparedCheckpointIdentity(pendingIntent, identity)) return {
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
- ...pendingIntent,
339
- expectedTree: identity.expectedTree,
319
+ version: 1, ...identity,
340
320
  digest: checkpointIntentDigest(identity),
341
- updatedAt: checkpointTimestamp()
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
- recoverStartedLifecycleUnderLock,
44
- recoveryFailure,
45
- type LifecycleRecoveryResult
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
- return recoverStartedLifecycleUnderLock(request as LifecycleRecoveryRequest, { repoRoot: context.repoRoot });
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 recoveryFailure(request as LifecycleRecoveryRequest, 'owner-unknown', error.code, error.message);
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
- if (prepareInput.client === 'codex') {
798
- return prepareCodexOrchestrationDelegation(operation.taskRef, prepareInput, {
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
- '--stage', '--round', '--artifact', '--override-ticket', '--override-target', '--override-scope', '--dry-run'
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
- '--capability-ref', '--parent-id', '--before-fingerprint', '--stage', '--round', '--artifact', '--role',
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', '--git-worktree-root'
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
- ...(value(values, '--stage') ? { stage: value(values, '--stage') } : {}),
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', '--stage', '--round', '--artifact', '--reason']);
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
- required(values, ['--stage', '--round', '--artifact', '--reason']);
998
- const stage = value(values, '--stage');
999
- if (!['analysis', 'review-analysis', 'plan', 'review-plan', 'code', 'review-code'].includes(stage ?? '')) {
1000
- operationInvalid('--stage must be a supported lifecycle stage');
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
- const options = value(values, '--git-worktree-root') === undefined
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
  }