@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
@@ -1,39 +1,15 @@
1
1
  import { preflightCodexLifecycleEvidence, resolveCodexSpawnedChild, resolveCodexTerminal, resolveCodexThread } from '../agent-clients/adapters/codex-lifecycle/app-server.js';
2
2
  import { createCodexLifecycleStore } from '../agent-clients/adapters/codex-lifecycle/store.js';
3
- import { createCodexCapabilityStore, isCodexCapabilityProvenanceDetail } from '../agent-clients/adapters/codex-lifecycle/capability-store.js';
4
- import { computeLifecycleBuildIdentity, verifyLifecycleBuildIdentity } from '../agent-clients/adapters/codex-lifecycle/build-identity.js';
5
- import { verifyCodexSandboxControllerContextWithWarnings as verifySandboxControllerWithWarnings } from '../agent-clients/adapters/codex-lifecycle/sandbox-controller.js';
6
- import { verifyCodexSandboxControllerContextWithWarnings as verifyControllerContextFileWithWarnings } from '../agent-clients/adapters/codex-lifecycle/controller-context.js';
3
+ import { computeLifecycleBuildIdentity, } from '../agent-clients/adapters/codex-lifecycle/build-identity.js';
7
4
  import { resolveTaskRef } from './resolve-ref.js';
8
- import { activateMatchingOrchestrationDelegation, hasActivatableOrchestrationDelegation, hasSealableOrchestrationDelegation, OrchestrationStateError, pauseMatchingOrchestrationDelegation, prepareOrchestrationDelegation, routeOrchestration, reconcileMatchingOrchestrationDelegation, sealMatchingOrchestrationDelegationWithHostEvidence } from './orchestration.js';
9
- import { randomUUID, createHash } from 'node:crypto';
10
- import { consumeLifecycleRecoveryAttestation, issueLifecycleRecoveryAttestation, validateLifecycleRecoveryAttestation } from './control-authority.js';
11
- function buildIdentityDigest(value) {
12
- return createHash('sha256').update(JSON.stringify(value), 'utf8').digest('hex');
13
- }
5
+ import { activateMatchingOrchestrationDelegation, hasActivatableOrchestrationDelegation, hasSealableOrchestrationDelegation, OrchestrationStateError, pauseMatchingOrchestrationDelegation, prepareOrchestrationDelegation, reconcileMatchingOrchestrationDelegation, sealMatchingOrchestrationDelegationWithHostEvidence } from './orchestration.js';
14
6
  function coreOptions(options) {
15
7
  return { ...options.orchestrationOptions, repoRoot: options.repoRoot ?? options.orchestrationOptions?.repoRoot };
16
8
  }
17
- function bridgeFailure(code, message, detail) {
9
+ function bridgeFailure(code, message) {
18
10
  return {
19
11
  status: 'failed', changed: false, taskId: null, run: null, next: null,
20
- error: { code, message, ...(detail ? { detail } : {}) }
21
- };
22
- }
23
- function capabilityFailure(error) {
24
- const detailValue = error instanceof Error
25
- ? error.detail
26
- : undefined;
27
- return {
28
- code: error instanceof Error && error.name.startsWith('CODEX_CAPABILITY_')
29
- ? error.name
30
- : 'ORCHESTRATION_CLIENT_PREFLIGHT_FAILED',
31
- message: error instanceof Error ? error.message : String(error),
32
- ...(error instanceof Error
33
- && error.name === 'CODEX_CAPABILITY_PROVENANCE_MISMATCH'
34
- && isCodexCapabilityProvenanceDetail(detailValue)
35
- ? { detail: detailValue }
36
- : {})
12
+ error: { code, message }
37
13
  };
38
14
  }
39
15
  function pauseBridge(code, message, options) {
@@ -47,28 +23,6 @@ function requiredStore(options) {
47
23
  throw new Error('Codex lifecycle store is required for orchestration bridge events');
48
24
  return options.store;
49
25
  }
50
- function brokerControllerBinding() {
51
- const raw = process.env.AGENT_INFRA_CONTROL_CONTROLLER_BINDING;
52
- if (!raw)
53
- return null;
54
- let value;
55
- try {
56
- value = JSON.parse(raw);
57
- }
58
- catch {
59
- throw new Error('CODEX_SANDBOX_CONTROLLER_BINDING_INVALID');
60
- }
61
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
62
- throw new Error('CODEX_SANDBOX_CONTROLLER_BINDING_INVALID');
63
- }
64
- const binding = value;
65
- if (Object.keys(binding).sort().join(',') !== 'controlGeneration,instanceDigest'
66
- || typeof binding.instanceDigest !== 'string' || !/^[a-f0-9]{64}$/u.test(binding.instanceDigest)
67
- || typeof binding.controlGeneration !== 'string' || binding.controlGeneration.length === 0) {
68
- throw new Error('CODEX_SANDBOX_CONTROLLER_BINDING_INVALID');
69
- }
70
- return binding;
71
- }
72
26
  async function prepareCodexOrchestrationDelegation(taskRef, input, options = {}) {
73
27
  if (input.client !== 'codex')
74
28
  return prepareOrchestrationDelegation(taskRef, input, coreOptions(options));
@@ -77,152 +31,13 @@ async function prepareCodexOrchestrationDelegation(taskRef, input, options = {})
77
31
  const resolved = resolveTaskRef(taskRef, { repoRoot });
78
32
  if (!resolved.ok)
79
33
  return bridgeFailure(resolved.code, resolved.message);
80
- const preflight = await (options.preflight ?? preflightCodexLifecycleEvidence)(repoRoot);
81
- const capabilityRef = input.capabilityRef;
82
- if (!capabilityRef) {
83
- return bridgeFailure('ORCHESTRATION_CODEX_CAPABILITY_REQUIRED', 'Codex prepare requires a current-session capability reference');
84
- }
85
- const buildIdentity = options.buildIdentity ?? computeLifecycleBuildIdentity(repoRoot);
86
- const brokerController = options.controllerBinding ?? brokerControllerBinding();
87
- const contextPath = process.env.AGENT_INFRA_CODEX_CONTROLLER_CONTEXT;
88
- const contextVerification = contextPath
89
- ? (brokerController
90
- ? verifyControllerContextFileWithWarnings(contextPath, {
91
- repoRoot,
92
- generation: process.env.AGENT_INFRA_CONTROL_GENERATION ?? brokerController.controlGeneration
93
- })
94
- : verifySandboxControllerWithWarnings(contextPath, { repoRoot }))
95
- : null;
96
- const identityWarnings = [...(contextVerification?.warnings ?? [])];
97
- const localController = contextVerification?.context ?? null;
98
- if (localController && brokerController
99
- && (localController.controllerInstanceDigest !== brokerController.instanceDigest
100
- || localController.controlGeneration !== brokerController.controlGeneration)) {
101
- return bridgeFailure('CODEX_SANDBOX_CONTROLLER_BINDING_MISMATCH', 'broker and local controller bindings do not match');
102
- }
103
- const controller = brokerController ?? (localController ? {
104
- instanceDigest: localController.controllerInstanceDigest,
105
- controlGeneration: localController.controlGeneration
106
- } : null);
107
- const capabilityStore = options.capabilityStore ?? createCodexCapabilityStore();
108
- const attested = capabilityStore.inspectReference(capabilityRef);
109
- const capabilityIdentity = verifyLifecycleBuildIdentity(attested.buildIdentity, buildIdentity);
110
- if (!capabilityIdentity.ok) {
111
- return bridgeFailure(capabilityIdentity.code, capabilityIdentity.message);
112
- }
113
- identityWarnings.push(...capabilityIdentity.warnings);
114
- const lifecycleProvenance = {
115
- ...attested.buildIdentity,
116
- hookDefinitionHash: preflight.hookDefinitionHash,
117
- ...preflight.hookProvenance,
118
- capabilitySessionId: attested.sessionId,
119
- capabilityTurnId: attested.turnId,
120
- capabilityToolUseId: attested.toolUseId,
121
- controllerInstanceDigest: controller?.instanceDigest ?? null,
122
- controlGeneration: controller?.controlGeneration ?? null
123
- };
124
- const capabilityExpected = {
125
- taskId: resolved.taskId,
126
- hookDefinitionHash: preflight.hookDefinitionHash,
127
- buildIdentity,
128
- ...(controller ? { controller: {
129
- instanceDigest: controller.instanceDigest,
130
- controlGeneration: controller.controlGeneration
131
- } } : {})
132
- };
133
- if (input.lifecycleRecoveryAttestation) {
134
- try {
135
- validateLifecycleRecoveryAttestation(input.lifecycleRecoveryAttestation);
136
- }
137
- catch (error) {
138
- return bridgeFailure('LIFECYCLE_AUTHORITY_ATTESTATION_INVALID', error instanceof Error ? error.message : String(error));
139
- }
140
- }
141
- let lifecycleRecoveryAttestation = input.lifecycleRecoveryAttestation ?? null;
142
- const routed = input.capabilityRef && !lifecycleRecoveryAttestation
143
- ? routeOrchestration(taskRef, coreOptions(options))
144
- : null;
145
- if (routed && !routed.next)
146
- return routed;
147
- if (routed?.next && ['analysis', 'plan', 'code'].includes(routed.next.stage)) {
148
- const recoveryRequest = {
149
- version: 1,
150
- requestId: randomUUID(),
151
- operationId: randomUUID(),
152
- phase: 'orchestration.prepare',
153
- taskId: resolved.taskId,
154
- family: routed.next.stage === 'analysis' ? 'analysis'
155
- : routed.next.stage === 'plan' ? 'plan' : 'code',
156
- artifact: routed.next.artifact,
157
- round: routed.next.round,
158
- lifecycleRequestId: randomUUID(),
159
- authorityRef: capabilityRef,
160
- expectedControlGeneration: controller?.controlGeneration ?? '',
161
- expectedControllerInstanceDigest: controller?.instanceDigest ?? '0'.repeat(64),
162
- expectedBuildIdentityDigest: buildIdentityDigest(buildIdentity),
163
- expectedHookDefinitionHash: preflight.hookDefinitionHash
164
- };
165
- const authority = issueLifecycleRecoveryAttestation(recoveryRequest, {
166
- capabilityStore,
167
- ...(controller ? { controllerBinding: controller } : {}),
168
- buildIdentity
169
- });
170
- if (authority.status === 'rejected' || !authority.attestation) {
171
- return bridgeFailure(authority.error?.code ?? 'LIFECYCLE_AUTHORITY_REJECTED', authority.error?.message ?? 'lifecycle authority was rejected');
172
- }
173
- lifecycleRecoveryAttestation = authority.attestation;
174
- }
175
- const prepared = prepareOrchestrationDelegation(taskRef, {
176
- ...input,
177
- lifecycleProvenance,
178
- lifecycleRecoveryAttestation
179
- }, {
180
- ...coreOptions(options),
181
- validateLifecycleCapability: () => {
182
- try {
183
- const validated = capabilityStore.validateReference(capabilityRef, capabilityExpected);
184
- if (validated.sessionId !== attested.sessionId
185
- || validated.turnId !== attested.turnId
186
- || validated.toolUseId !== attested.toolUseId) {
187
- return {
188
- code: 'CODEX_CAPABILITY_IDENTITY_CHANGED',
189
- message: 'capability identity changed during validation'
190
- };
191
- }
192
- return null;
193
- }
194
- catch (error) {
195
- return capabilityFailure(error);
196
- }
197
- },
198
- consumeLifecycleCapability: () => null
199
- });
200
- if (lifecycleRecoveryAttestation && !options.deferLifecycleRecoveryConsumption && prepared.status !== 'failed') {
201
- try {
202
- consumeLifecycleRecoveryAttestation(lifecycleRecoveryAttestation);
203
- }
204
- catch (error) {
205
- return bridgeFailure(error instanceof Error ? error.name : 'LIFECYCLE_AUTHORITY_CONSUME_FAILED', error instanceof Error ? error.message : String(error));
206
- }
207
- }
208
- return identityWarnings.length > 0 && prepared.status !== 'failed'
209
- ? { ...prepared, warnings: Object.freeze(identityWarnings) }
210
- : prepared;
34
+ await (options.preflight ?? preflightCodexLifecycleEvidence)(repoRoot);
35
+ return prepareOrchestrationDelegation(taskRef, input, coreOptions(options));
211
36
  }
212
37
  catch (error) {
213
38
  if (error instanceof OrchestrationStateError)
214
39
  return bridgeFailure(error.code, error.message);
215
- const detailValue = error instanceof Error
216
- ? error.detail
217
- : undefined;
218
- const detail = error instanceof Error
219
- && error.name === 'CODEX_CAPABILITY_PROVENANCE_MISMATCH'
220
- && isCodexCapabilityProvenanceDetail(detailValue)
221
- ? detailValue
222
- : undefined;
223
- return bridgeFailure(error instanceof Error && error.name.startsWith('CODEX_CAPABILITY_')
224
- ? error.name
225
- : 'ORCHESTRATION_CLIENT_PREFLIGHT_FAILED', error instanceof Error ? error.message : String(error), detail);
40
+ return bridgeFailure('ORCHESTRATION_CLIENT_PREFLIGHT_FAILED', error instanceof Error ? error.message : String(error));
226
41
  }
227
42
  }
228
43
  async function activateCodexOrchestrationDelegation(childThreadId, options = {}) {
@@ -248,16 +63,6 @@ async function activateCodexOrchestrationDelegation(childThreadId, options = {})
248
63
  toolUseId: evidence.spawnToolUseId
249
64
  });
250
65
  const buildIdentity = options.buildIdentity ?? computeLifecycleBuildIdentity(repoRoot);
251
- const contextPath = process.env.AGENT_INFRA_CODEX_CONTROLLER_CONTEXT;
252
- const contextVerification = contextPath
253
- ? verifySandboxControllerWithWarnings(contextPath, { repoRoot })
254
- : null;
255
- const controller = options.controllerBinding
256
- ?? brokerControllerBinding()
257
- ?? (contextVerification?.context ? {
258
- instanceDigest: contextVerification.context.controllerInstanceDigest,
259
- controlGeneration: contextVerification.context.controlGeneration
260
- } : null);
261
66
  const activated = activateMatchingOrchestrationDelegation('codex', {
262
67
  nativeAgent: evidence.nativeAgent,
263
68
  childId: evidence.childThreadId,
@@ -279,14 +84,11 @@ async function activateCodexOrchestrationDelegation(childThreadId, options = {})
279
84
  capabilityTurnId: evidence.parentTurnId,
280
85
  spawnToolUseId: evidence.spawnToolUseId,
281
86
  spawnObservedAt: record.spawnObservedAt ?? undefined,
282
- controllerInstanceDigest: controller?.instanceDigest ?? null,
283
- controlGeneration: controller?.controlGeneration ?? null
87
+ controllerInstanceDigest: null,
88
+ controlGeneration: null
284
89
  }
285
90
  }, coreOptions(options));
286
- const warnings = contextVerification?.warnings ?? [];
287
- return warnings.length > 0 && activated.status !== 'failed'
288
- ? { ...activated, warnings: Object.freeze(warnings) }
289
- : activated;
91
+ return activated;
290
92
  }
291
93
  catch (error) {
292
94
  if (error instanceof OrchestrationStateError)
@@ -181,16 +181,6 @@ function checkpointIdentity(input, task, delivery) {
181
181
  function checkpointTimestamp() {
182
182
  return new Date().toISOString();
183
183
  }
184
- function samePreparedCheckpointIdentity(pending, identity) {
185
- return pending.state === 'prepared'
186
- && pending.taskId === identity.taskId
187
- && pending.branch === identity.branch
188
- && pending.mode === identity.mode
189
- && pending.expectedHead === identity.expectedHead
190
- && pending.message === identity.message
191
- && pending.round === identity.round
192
- && JSON.stringify(pending.paths) === JSON.stringify(identity.paths);
193
- }
194
184
  function executeUnlocked(input, task, mode) {
195
185
  const inspected = inspectGitWorkflow(input.cwd);
196
186
  if (!inspected.snapshot)
@@ -225,16 +215,11 @@ function executeUnlocked(input, task, mode) {
225
215
  };
226
216
  }
227
217
  if (pendingIntent && !sameCheckpointIntent(pendingIntent, identity)) {
228
- if (!input.recoverPreparedIntent || !samePreparedCheckpointIdentity(pendingIntent, identity))
229
- return {
230
- status: 'failed', changed: false, snapshot: inspected.snapshot, operations: [],
231
- error: { code: 'COMMIT_INTENT_CONFLICT', message: 'A different checkpoint intent is still pending for this task' }
232
- };
218
+ const timestamp = checkpointTimestamp();
233
219
  pendingIntent = {
234
- ...pendingIntent,
235
- expectedTree: identity.expectedTree,
220
+ version: 1, ...identity,
236
221
  digest: checkpointIntentDigest(identity),
237
- updatedAt: checkpointTimestamp()
222
+ state: 'prepared', committedHead: null, createdAt: timestamp, updatedAt: timestamp
238
223
  };
239
224
  try {
240
225
  writeCheckpointIntent(task.repoRoot, pendingIntent);
@@ -3,12 +3,11 @@ import crypto from 'node:crypto';
3
3
  import fs from 'node:fs';
4
4
  import { normalizeAgentToken } from '../agent-clients/tokens.js';
5
5
  import { isAgentClientId } from '../agent-clients/types.js';
6
+ import { getAgentClientAdapter } from '../agent-clients/registry.js';
6
7
  import { consumeHumanOverride, failureId, overrideDryRunConflict } from './human-override.js';
7
8
  import { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, advanceOrchestration, awaitOrchestrationDelegationActivation, beginOrResumeOrchestration, dispatchOrchestrationDelegation, OrchestrationStateError, pauseOrchestration, prepareOrchestrationDelegation, recoverPreparedOrchestrationDelegation, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, statusOrchestration } from './orchestration.js';
8
- import { prepareCodexOrchestrationDelegation } from './codex-orchestration.js';
9
9
  import { applyTaskFinalization } from './finalization.js';
10
10
  import { applyTaskLifecycle, taskLifecycleFailure } from './lifecycle.js';
11
- import { recoverStartedLifecycleUnderLock, recoveryFailure } from './lifecycle-recovery.js';
12
11
  import { locateActivityLog } from './activity-log.js';
13
12
  import { resolveTaskRef, TASK_ID_RE } from './resolve-ref.js';
14
13
  import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
@@ -407,7 +406,6 @@ export function createSandboxExecutorExecutionContext(params) {
407
406
  generation: params.generation,
408
407
  manifestPath: absolute('manifestPath', params.manifestPath),
409
408
  requestId: params.requestId,
410
- ...(params.diagnosticLog === undefined ? {} : { diagnosticLog: params.diagnosticLog }),
411
409
  ...(params.controllerBinding === undefined ? {} : { controllerBinding: binding(params.controllerBinding) }),
412
410
  ...(params.lifecycleRecoveryAttestation === undefined ? {} : {
413
411
  lifecycleRecoveryAttestation: params.lifecycleRecoveryAttestation === null
@@ -450,11 +448,7 @@ function operationTaskId(context, taskRef) {
450
448
  function domainOptions(context, options) {
451
449
  return {
452
450
  ...options,
453
- repoRoot: context.repoRoot,
454
- ...(context.source === 'sandbox-executor' && context.diagnosticLog !== undefined
455
- ? { diagnosticLog: context.diagnosticLog }
456
- : {}),
457
- ...(context.source === 'sandbox-executor' ? { gitWorktreeRoot: context.worktreeRoot } : {})
451
+ repoRoot: context.repoRoot
458
452
  };
459
453
  }
460
454
  function lifecycleTaskId(request, repoRoot) {
@@ -475,7 +469,17 @@ async function applyLifecycleWithAuthority(context, request) {
475
469
  }
476
470
  const execute = async () => {
477
471
  if (request.intent === 'recover-started') {
478
- return recoverStartedLifecycleUnderLock(request, { repoRoot: context.repoRoot });
472
+ const adapter = isAgentClientId(request.agent)
473
+ ? getAgentClientAdapter(request.agent).orchestrationAdapter
474
+ : undefined;
475
+ if (!adapter?.recoverStarted) {
476
+ return {
477
+ status: 'no-op', changed: false, targetState: 'active',
478
+ requestRef: request.taskRef, intent: 'recover-started', taskId: null,
479
+ receiptId: null, childId: null, error: null
480
+ };
481
+ }
482
+ return adapter.recoverStarted(request, { repoRoot: context.repoRoot });
479
483
  }
480
484
  const lifecycleResult = applyTaskLifecycle(request, { repoRoot: context.repoRoot });
481
485
  if (lifecycleResult.status !== 'failed' || !request.overrideTicket)
@@ -511,7 +515,12 @@ async function applyLifecycleWithAuthority(context, request) {
511
515
  if (!(error instanceof TaskExecutionLockError))
512
516
  throw error;
513
517
  if (request.intent === 'recover-started') {
514
- return recoveryFailure(request, 'owner-unknown', error.code, error.message);
518
+ return {
519
+ status: 'owner-unknown', changed: false, targetState: 'active',
520
+ requestRef: request.taskRef, intent: 'recover-started', taskId,
521
+ receiptId: null, childId: null,
522
+ error: { code: error.code, message: error.message }
523
+ };
515
524
  }
516
525
  return taskLifecycleFailure(request, { code: error.code, message: error.message }, taskId);
517
526
  }
@@ -535,17 +544,13 @@ function orchestration(context, operation) {
535
544
  client: input.client,
536
545
  requestedModel: input.requestedModel,
537
546
  requestedReasoningEffort: input.requestedReasoningEffort,
538
- ...(input.capabilityRef === undefined ? {} : { capabilityRef: input.capabilityRef }),
539
- ...(context.lifecycleRecoveryAttestation === undefined
540
- ? {}
541
- : { lifecycleRecoveryAttestation: context.lifecycleRecoveryAttestation })
542
547
  };
543
- if (prepareInput.client === 'codex') {
544
- return prepareCodexOrchestrationDelegation(operation.taskRef, prepareInput, {
548
+ const prepareDelegation = getAgentClientAdapter(prepareInput.client)
549
+ .orchestrationAdapter?.prepareDelegation;
550
+ if (prepareDelegation) {
551
+ return prepareDelegation(operation.taskRef, prepareInput, {
545
552
  repoRoot: context.repoRoot,
546
553
  orchestrationOptions: options,
547
- deferLifecycleRecoveryConsumption: context.source === 'sandbox-executor',
548
- ...(context.controllerBinding ? { controllerBinding: context.controllerBinding } : {})
549
554
  });
550
555
  }
551
556
  return prepareOrchestrationDelegation(operation.taskRef, prepareInput, options);
@@ -623,22 +628,22 @@ function operationInvalid(message) {
623
628
  }
624
629
  const LIFECYCLE_FLAGS = new Set([
625
630
  '--agent', '--reason', '--unblock-condition', '--note', '--alert-number', '--staging-dir', '--issue-number',
626
- '--stage', '--round', '--artifact', '--override-ticket', '--override-target', '--override-scope', '--dry-run'
631
+ '--auto', '--override-ticket', '--override-target', '--override-scope', '--dry-run'
627
632
  ]);
628
633
  const FINALIZATION_FLAGS = new Set(['--agent']);
629
634
  const ORCHESTRATION_FLAGS = new Set([
630
635
  '--agent', '--max-steps', '--executor-model', '--executor-reasoning-effort', '--reviewer-model',
631
636
  '--reviewer-reasoning-effort', '--client', '--requested-model', '--requested-reasoning-effort',
632
- '--capability-ref', '--parent-id', '--before-fingerprint', '--stage', '--round', '--artifact', '--role',
637
+ '--parent-id', '--before-fingerprint', '--stage', '--round', '--artifact', '--role',
633
638
  '--native-agent', '--child-id', '--spawn-mode', '--actual-model', '--actual-reasoning-effort',
634
639
  '--model-fallback-reason', '--reasoning-effort-fallback-reason', '--exit-code', '--after-fingerprint',
635
- '--changed-paths', '--code', '--message', '--recoverable', '--git-worktree-root'
640
+ '--changed-paths', '--code', '--message', '--recoverable'
636
641
  ]);
637
642
  function parseValues(args, start, flags) {
638
643
  const values = {};
639
644
  for (let index = start; index < args.length; index += 1) {
640
645
  const flag = args[index];
641
- if (flag === '--dry-run') {
646
+ if (flag === '--dry-run' || flag === '--auto') {
642
647
  if (!flags.has(flag))
643
648
  operationInvalid(`unknown option '${flag}'`);
644
649
  if (values[flag] !== undefined)
@@ -699,31 +704,21 @@ export function parseTaskControlOperation(family, args) {
699
704
  ...(value(values, '--override-scope') ? { overrideScope: value(values, '--override-scope') } : {}),
700
705
  ...(value(values, '--alert-number') ? { alertNumber: Number(value(values, '--alert-number')) } : {}),
701
706
  ...(value(values, '--issue-number') ? { issueNumber: Number(value(values, '--issue-number')) } : {}),
702
- ...(value(values, '--stage') ? { stage: value(values, '--stage') } : {}),
703
- ...(value(values, '--round') ? { round: Number(value(values, '--round')) } : {}),
704
- ...(value(values, '--artifact') ? { artifact: value(values, '--artifact') } : {}),
707
+ ...(values['--auto'] === true ? { auto: true } : {}),
705
708
  ...(values['--dry-run'] === true ? { dryRun: true } : {})
706
709
  };
707
710
  if (intent === 'recover-started') {
708
- const recoveryFlags = new Set(['--agent', '--stage', '--round', '--artifact', '--reason']);
711
+ const recoveryFlags = new Set(['--agent', '--auto']);
709
712
  for (const flag of Object.keys(values)) {
710
713
  if (!recoveryFlags.has(flag))
711
714
  operationInvalid(`option '${flag}' is not supported for recover-started`);
712
715
  }
713
- required(values, ['--stage', '--round', '--artifact', '--reason']);
714
- const stage = value(values, '--stage');
715
- if (!['analysis', 'review-analysis', 'plan', 'review-plan', 'code', 'review-code'].includes(stage ?? '')) {
716
- operationInvalid('--stage must be a supported lifecycle stage');
717
- }
718
- const round = Number(value(values, '--round'));
719
- if (!Number.isSafeInteger(round) || round < 1)
720
- operationInvalid('--round must be a positive integer');
721
- if (value(values, '--reason').includes('\n') || value(values, '--reason').includes('\r')) {
722
- operationInvalid('--reason must be a single line');
723
- }
716
+ if (values['--auto'] !== true)
717
+ operationInvalid('--auto is required for recover-started');
718
+ return { family, request: input };
724
719
  }
725
- else if (values['--stage'] !== undefined || values['--round'] !== undefined || values['--artifact'] !== undefined) {
726
- operationInvalid('--stage, --round, and --artifact are only supported for recover-started');
720
+ else if (values['--auto'] !== undefined) {
721
+ operationInvalid('--auto is only supported for recover-started');
727
722
  }
728
723
  return { family, request: input };
729
724
  }
@@ -769,7 +764,6 @@ export function parseTaskControlOperation(family, args) {
769
764
  if (parsedIntent === 'prepare') {
770
765
  input.requestedModel = value(values, '--requested-model');
771
766
  input.requestedReasoningEffort = value(values, '--requested-reasoning-effort');
772
- input.capabilityRef = value(values, '--capability-ref');
773
767
  }
774
768
  if (parsedIntent === 'await-activation') {
775
769
  required(values, ['--stage', '--round', '--artifact', '--role']);
@@ -827,9 +821,6 @@ export function parseTaskControlOperation(family, args) {
827
821
  input.message = value(values, '--message');
828
822
  input.recoverable = recoverable === 'true';
829
823
  }
830
- const options = value(values, '--git-worktree-root') === undefined
831
- ? undefined
832
- : { gitWorktreeRoot: value(values, '--git-worktree-root') };
833
- return { family, taskRef, intent: parsedIntent, input, ...(options ? { options } : {}) };
824
+ return { family, taskRef, intent: parsedIntent, input };
834
825
  }
835
826
  //# sourceMappingURL=control-authority.js.map
@@ -1,7 +1,4 @@
1
1
  import { createHash } from 'node:crypto';
2
- import { isCompletionEvidence } from './orchestration.js';
3
- import { TASK_WORKFLOW_OPERATIONS } from './workflow-command.js';
4
- import { sameRecoveryWarning } from './recovery-warning.js';
5
2
  /** Normalize the command result once at the control transport boundary. */
6
3
  export function parseControlOutput(output) {
7
4
  if (output === null)
@@ -20,20 +17,10 @@ export const SANDBOX_CONTROL_REQUIRED_COMPLETION_PHASES = Object.freeze([
20
17
  'completed', 'evidence-written', 'publish-authorized'
21
18
  ]);
22
19
  const LIFECYCLE_INTENTS = ['block', 'activate', 'cancel', 'complete', 'close-codescan', 'close-dependabot', 'restore', 'recover-started'];
23
- const ORCHESTRATION_INTENTS = [
24
- 'begin-or-resume', 'route.read', 'route.clean-completion', 'status', 'prepare', 'dispatch',
25
- 'await-activation', 'recover-prepared', 'hook-start', 'hook-stop', 'advance', 'pause'
26
- ];
27
20
  export const SANDBOX_CONTROL_RECOVERY_OPERATIONS = Object.freeze([
28
21
  ...LIFECYCLE_INTENTS.map((intent) => ({ family: 'task-lifecycle', intent, class: 'lifecycle-mutation' })),
29
22
  { family: 'task-finalization', intent: 'complete', class: 'finalization' },
30
- ...ORCHESTRATION_INTENTS.map((intent) => ({
31
- family: 'task-orchestration',
32
- intent,
33
- class: intent === 'route.clean-completion' ? 'route.clean-completion' : intent === 'route.read' || intent === 'status' ? 'read-only' : 'orchestration'
34
- })),
35
23
  { family: 'task-create', intent: 'create', class: 'task-create' },
36
- ...TASK_WORKFLOW_OPERATIONS.map((intent) => ({ family: 'task-workflow', intent, class: intent === 'artifact-inspect' || intent === 'decision-next-id' ? 'read-only' : 'workflow' })),
37
24
  ...['open', 'close', 'verify'].map((intent) => ({ family: 'codex-controller', intent, class: 'codex-controller' }))
38
25
  ]);
39
26
  export function digestControlRecoveryIntent(family, intent) {
@@ -53,30 +40,8 @@ function domainEvidenceMatches(operation, result, domain) {
53
40
  return false;
54
41
  if (domain.consistent !== true)
55
42
  return false;
56
- if (operation.class === 'route.clean-completion') {
57
- const completion = domain.completionEvidence;
58
- const snapshot = domain.snapshot;
59
- const lastReviewedCommit = domain.lastReviewedCommit;
60
- return result.status === 'completed'
61
- && domain.status === 'completed'
62
- && domain.pendingDelegation === null
63
- && isCompletionEvidence(completion)
64
- && snapshot?.head === completion.head
65
- && snapshot.headTree === completion.headTree
66
- && snapshot.worktreeTree === completion.worktreeTree
67
- && lastReviewedCommit === completion.lastReviewedCommit;
68
- }
69
- if (operation.family === 'task-lifecycle' && operation.intent === 'recover-started') {
70
- const retryRequired = domain.recoveryState === 'retry-required'
71
- && sameRecoveryWarning(domain.warning, result.warning);
72
- return result.targetState === 'active'
73
- && ['applied', 'no-op'].includes(String(result.status))
74
- && domain.recovery === true
75
- && domain.targetState === 'active'
76
- && (domain.recoveryState === 'released' || retryRequired);
77
- }
78
- if (operation.class === 'read-only')
79
- return result.changed === false && domain.snapshotValid === true;
43
+ if (operation.family === 'task-lifecycle' && operation.intent === 'recover-started')
44
+ return false;
80
45
  return true;
81
46
  }
82
47
  export function classifySandboxControlRecovery(input) {
@@ -127,11 +92,7 @@ export function classifySandboxControlRecovery(input) {
127
92
  return {
128
93
  outcome: 'success',
129
94
  responseReconstructable: true,
130
- reasonCode: input.operation.class === 'route.clean-completion' && result.changed === false
131
- ? 'RECOVERY_ROUTE_COMPLETION_NOOP'
132
- : input.operation.intent === 'recover-started' && input.domain?.recoveryState === 'retry-required'
133
- ? 'RECOVERY_RELEASE_RETRY_REQUIRED'
134
- : 'RECOVERY_TERMINAL_AND_DOMAIN_MATCH'
95
+ reasonCode: 'RECOVERY_TERMINAL_AND_DOMAIN_MATCH'
135
96
  };
136
97
  }
137
98
  export function operationRecoveryBinding(requestId, generation, taskId, family, intent) {