@fitlab-ai/agent-infra 0.11.11 → 0.11.13

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 (154) hide show
  1. package/dist/bin/internal-cli.js +2 -2
  2. package/dist/lib/agent-clients/adapter.js +7 -1
  3. package/dist/lib/agent-clients/adapters/claude-code.js +5 -1
  4. package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +78 -63
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +114 -0
  6. package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +447 -0
  7. package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-client.js +130 -0
  8. package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-operation.js +131 -0
  9. package/dist/lib/{sandbox/control → agent-clients/adapters/codex-lifecycle}/controller-registration.js +2 -2
  10. package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +48 -1
  11. package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +124 -62
  12. package/dist/lib/{internal/codex-sandbox-controller.js → agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.js} +3 -3
  13. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -5
  14. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +211 -213
  15. package/dist/lib/agent-clients/adapters/codex-orchestration.js +468 -0
  16. package/dist/lib/agent-clients/adapters/codex.js +40 -1
  17. package/dist/lib/agent-clients/adapters/index.js +2 -10
  18. package/dist/lib/agent-clients/tokens.js +3 -2
  19. package/dist/lib/internal/agent-client.js +132 -72
  20. package/dist/lib/internal/cli-route-inventory.js +2 -2
  21. package/dist/lib/internal/sandbox-control.js +1 -81
  22. package/dist/lib/internal/task-finalization.js +26 -19
  23. package/dist/lib/internal/task-lifecycle.js +1 -1
  24. package/dist/lib/internal/task-operation-registry.js +1 -1
  25. package/dist/lib/internal/task-validate.js +1 -1
  26. package/dist/lib/platform/github-client.js +33 -3
  27. package/dist/lib/platform/issues.js +18 -6
  28. package/dist/lib/runtime/agent-runtime.js +6 -29
  29. package/dist/lib/sandbox/commands/control-status.js +1 -0
  30. package/dist/lib/sandbox/commands/create.js +7 -2
  31. package/dist/lib/sandbox/commands/ls.js +4 -5
  32. package/dist/lib/sandbox/commands/rm.js +1 -1
  33. package/dist/lib/sandbox/control/agent-operation.js +34 -0
  34. package/dist/lib/sandbox/control/client.js +14 -201
  35. package/dist/lib/sandbox/control/executor.js +12 -125
  36. package/dist/lib/sandbox/control/lifecycle.js +66 -4
  37. package/dist/lib/sandbox/control/protocol.js +15 -54
  38. package/dist/lib/sandbox/control/server.js +216 -281
  39. package/dist/lib/sandbox/control/task-view.js +0 -13
  40. package/dist/lib/sandbox/mounts.js +9 -1
  41. package/dist/lib/sandbox/recovery.js +31 -10
  42. package/dist/lib/sandbox/removal.js +28 -5
  43. package/dist/lib/sandbox/workspace-identity.js +18 -6
  44. package/dist/lib/sandbox/workspace-view.js +56 -19
  45. package/dist/lib/task/commands/ls.js +3 -3
  46. package/dist/lib/task/control-authority.js +56 -264
  47. package/dist/lib/task/control-recovery.js +2 -3
  48. package/dist/lib/task/create.js +2 -2
  49. package/dist/lib/task/delegation-receipts.js +74 -161
  50. package/dist/lib/task/events.js +88 -44
  51. package/dist/lib/task/finalization.js +35 -6
  52. package/dist/lib/task/lifecycle.js +274 -115
  53. package/dist/lib/task/orchestration.js +201 -194
  54. package/dist/lib/task/runtime-paths.js +10 -0
  55. package/dist/lib/task/short-id.js +37 -27
  56. package/dist/lib/task/verification-engine.js +32 -26
  57. package/dist/lib/task/workspace-snapshot.js +1 -1
  58. package/dist/lifecycle-build-manifest.json +3 -3
  59. package/lib/agent-clients/adapter.ts +39 -0
  60. package/lib/agent-clients/adapters/claude-code.ts +5 -1
  61. package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +105 -80
  62. package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +147 -0
  63. package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +510 -0
  64. package/lib/agent-clients/adapters/codex-lifecycle/controller-client.ts +158 -0
  65. package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +1 -1
  66. package/lib/agent-clients/adapters/codex-lifecycle/controller-operation.ts +151 -0
  67. package/lib/{sandbox/control → agent-clients/adapters/codex-lifecycle}/controller-registration.ts +4 -4
  68. package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +43 -0
  69. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +8 -5
  70. package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +190 -65
  71. package/lib/{internal/codex-sandbox-controller.ts → agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.ts} +2 -2
  72. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -5
  73. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +270 -224
  74. package/lib/agent-clients/adapters/codex-orchestration.ts +632 -0
  75. package/lib/agent-clients/adapters/codex.ts +44 -1
  76. package/lib/agent-clients/adapters/index.ts +7 -20
  77. package/lib/agent-clients/tokens.ts +4 -3
  78. package/lib/internal/agent-client.ts +142 -73
  79. package/lib/internal/cli-route-inventory.ts +2 -2
  80. package/lib/internal/sandbox-control.ts +0 -97
  81. package/lib/internal/task-finalization.ts +30 -18
  82. package/lib/internal/task-lifecycle.ts +1 -1
  83. package/lib/internal/task-operation-registry.ts +1 -1
  84. package/lib/internal/task-validate.ts +1 -1
  85. package/lib/platform/github-client.ts +34 -3
  86. package/lib/platform/issues.ts +18 -6
  87. package/lib/runtime/agent-runtime.ts +6 -41
  88. package/lib/sandbox/commands/control-status.ts +1 -0
  89. package/lib/sandbox/commands/create.ts +7 -1
  90. package/lib/sandbox/commands/ls.ts +4 -5
  91. package/lib/sandbox/commands/rm.ts +1 -1
  92. package/lib/sandbox/control/agent-operation.ts +49 -0
  93. package/lib/sandbox/control/client.ts +20 -254
  94. package/lib/sandbox/control/executor.ts +13 -136
  95. package/lib/sandbox/control/lifecycle.ts +67 -4
  96. package/lib/sandbox/control/protocol.ts +22 -66
  97. package/lib/sandbox/control/server.ts +21 -95
  98. package/lib/sandbox/control/task-view.ts +0 -19
  99. package/lib/sandbox/mounts.ts +10 -1
  100. package/lib/sandbox/recovery.ts +38 -17
  101. package/lib/sandbox/removal.ts +33 -7
  102. package/lib/sandbox/workspace-identity.ts +16 -6
  103. package/lib/sandbox/workspace-view.ts +50 -18
  104. package/lib/task/commands/ls.ts +3 -3
  105. package/lib/task/control-authority.ts +66 -378
  106. package/lib/task/control-recovery.ts +3 -4
  107. package/lib/task/create.ts +3 -3
  108. package/lib/task/delegation-receipts.ts +87 -231
  109. package/lib/task/events.ts +100 -42
  110. package/lib/task/finalization.ts +37 -7
  111. package/lib/task/lifecycle.ts +257 -109
  112. package/lib/task/orchestration.ts +260 -237
  113. package/lib/task/runtime-paths.ts +12 -0
  114. package/lib/task/short-id.ts +33 -40
  115. package/lib/task/verification-engine.ts +30 -25
  116. package/lib/task/workspace-snapshot.ts +1 -1
  117. package/package.json +1 -1
  118. package/templates/.agents/hooks/lifecycle-delegation.js +1 -25
  119. package/templates/.agents/rules/README.en.md +2 -1
  120. package/templates/.agents/rules/README.zh-CN.md +2 -1
  121. package/templates/.agents/rules/next-step-output.en.md +6 -19
  122. package/templates/.agents/rules/next-step-output.zh-CN.md +6 -19
  123. package/templates/.agents/rules/strategy-pattern.en.md +25 -0
  124. package/templates/.agents/rules/strategy-pattern.zh-CN.md +25 -0
  125. package/templates/.agents/skills/analyze-task/SKILL.en.md +1 -1
  126. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +1 -1
  127. package/templates/.agents/skills/check-task/SKILL.en.md +1 -1
  128. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +1 -1
  129. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  130. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +1 -1
  131. package/templates/.agents/skills/code-task/reference/code-rules.en.md +4 -0
  132. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +4 -0
  133. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +0 -1
  134. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +0 -1
  135. package/templates/.agents/skills/complete-task/SKILL.en.md +5 -29
  136. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +5 -26
  137. package/templates/.agents/skills/plan-task/SKILL.en.md +7 -4
  138. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +7 -4
  139. package/templates/.agents/skills/review-analysis/SKILL.en.md +1 -1
  140. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +1 -1
  141. package/templates/.agents/skills/review-code/SKILL.en.md +1 -1
  142. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +1 -1
  143. package/templates/.agents/skills/review-plan/SKILL.en.md +1 -1
  144. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +1 -1
  145. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -1
  146. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -1
  147. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  148. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  149. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +0 -546
  150. package/dist/lib/internal/codex-lifecycle.js +0 -385
  151. package/dist/lib/task/codex-orchestration.js +0 -206
  152. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +0 -776
  153. package/lib/internal/codex-lifecycle.ts +0 -390
  154. package/lib/task/codex-orchestration.ts +0 -276
@@ -0,0 +1,468 @@
1
+ import { preflightCodexLifecycleEvidence, resolveCodexSpawnedChild, resolveCodexTerminal, resolveCodexThread } from './codex-lifecycle/app-server.js';
2
+ import { createCodexLifecycleStore } from './codex-lifecycle/store.js';
3
+ import { computeLifecycleBuildIdentity, } from './codex-lifecycle/build-identity.js';
4
+ import { resolveTaskRef } from '../../task/resolve-ref.js';
5
+ import { activateMatchingOrchestrationDelegation, hasActivatableOrchestrationDelegation, hasSealableOrchestrationDelegation, OrchestrationStateError, pauseMatchingOrchestrationDelegation, prepareOrchestrationDelegation, reconcileMatchingOrchestrationDelegation, readDelegationAdapterEvidence, readRun, sealMatchingOrchestrationDelegation } from '../../task/orchestration.js';
6
+ import { managedDelegationRole } from '../../task/delegation-receipts.js';
7
+ import { encodeCodexLifecycleBinding, parseCodexLifecycleBinding, verifyCodexLifecycleTaskBinding } from './codex-lifecycle/binding.js';
8
+ import { reduceCodexLifecycleEvent } from './codex-lifecycle/evidence.js';
9
+ function coreOptions(options) {
10
+ return {
11
+ ...options.orchestrationOptions,
12
+ repoRoot: options.repoRoot ?? options.orchestrationOptions?.repoRoot,
13
+ taskId: options.orchestrationOptions?.taskId ?? options.store?.taskId ?? undefined
14
+ };
15
+ }
16
+ function taskRunMatchesReceipt(run, binding, nativeAgent) {
17
+ const receipt = run?.pendingDelegation;
18
+ const role = nativeAgent.endsWith('reviewer') ? 'reviewer' : 'executor';
19
+ return run?.status === 'running'
20
+ && receipt?.runId === binding.runId
21
+ && receipt.id === binding.receiptId
22
+ && receipt.client === 'codex'
23
+ && receipt.role === role;
24
+ }
25
+ function recordMatchesTaskReceipt(childThreadId, options) {
26
+ const store = requiredStore(options);
27
+ let record;
28
+ try {
29
+ record = store.read(childThreadId);
30
+ }
31
+ catch (error) {
32
+ throw new Error(`CODEX_LIFECYCLE_TASK_BINDING_MISMATCH: ${error instanceof Error ? error.message : String(error)}`);
33
+ }
34
+ const binding = record.taskBinding;
35
+ if (!binding)
36
+ throw new Error('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH: lifecycle record has no receipt binding');
37
+ const repoRoot = options.repoRoot ?? options.orchestrationOptions?.repoRoot ?? process.cwd();
38
+ const resolved = resolveTaskRef(binding.taskId, { repoRoot });
39
+ if (!resolved.ok)
40
+ throw new Error(`${resolved.code}: ${resolved.message}`);
41
+ const run = readRun(resolved.taskDir);
42
+ const nativeAgent = record.state.startEvidence?.nativeAgent ?? record.state.spawn?.nativeAgent ?? '';
43
+ if (!taskRunMatchesReceipt(run, binding, nativeAgent)) {
44
+ throw new Error('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH: lifecycle record does not match the current pending task receipt');
45
+ }
46
+ const receipt = run.pendingDelegation;
47
+ return { store, record, binding, resolved, run, receipt };
48
+ }
49
+ function sameTaskReceipt(left, right) {
50
+ return left.runId === right.runId && left.id === right.id;
51
+ }
52
+ function sameLifecycleRevision(left, right) {
53
+ return left.revision === right.revision
54
+ && sameTaskBinding(left.taskBinding, right.taskBinding);
55
+ }
56
+ function sameTaskBinding(left, right) {
57
+ return left?.runId === right?.runId
58
+ && left?.receiptId === right?.receiptId;
59
+ }
60
+ function isBindingFailure(message) {
61
+ return /CODEX_LIFECYCLE_TASK_BINDING_MISMATCH|CODEX_EVIDENCE_(?:IDENTITY_MISMATCH|PARENT_MISMATCH|REPLAY_CONFLICT)|task binding|identity mismatch|ambiguous active children/iu.test(message);
62
+ }
63
+ function codexSealFailure(error, options, source) {
64
+ if (error instanceof OrchestrationStateError)
65
+ return bridgeFailure(error.code, error.message);
66
+ const message = error instanceof Error ? error.message : String(error);
67
+ if (message === 'CODEX_TURN_NOT_TERMINAL') {
68
+ return source === 'parent'
69
+ ? bridgeFailure('ORCHESTRATION_DELEGATION_MISSING', 'The matching Codex child has not completed')
70
+ : pauseBridge('ORCHESTRATION_CODEX_STOP_FAILED', message, options);
71
+ }
72
+ if (isBindingFailure(message))
73
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', message);
74
+ return pauseBridge('ORCHESTRATION_CODEX_STOP_FAILED', message, options);
75
+ }
76
+ function sameBoundLifecycleRecord(bound, current) {
77
+ return sameTaskReceipt(bound.receipt, current.receipt)
78
+ && sameLifecycleRevision(bound.record, current.record);
79
+ }
80
+ function candidateActivationState(state, events) {
81
+ return events.reduce((current, event) => reduceCodexLifecycleEvent(current, event), state);
82
+ }
83
+ function candidateActivationFailure(state, options) {
84
+ if (state.status === 'invalid') {
85
+ return bridgeFailure(state.error?.code ?? 'CODEX_EVIDENCE_IDENTITY_MISMATCH', state.error?.message ?? 'Codex lifecycle identity does not match');
86
+ }
87
+ if (state.status !== 'start-ready' || !state.startEvidence) {
88
+ return pauseBridge('ORCHESTRATION_CODEX_START_EVIDENCE_INVALID', 'Codex lifecycle start evidence is not ready', options);
89
+ }
90
+ return null;
91
+ }
92
+ async function collectActivationEvidence(childThreadId, options, bound) {
93
+ const resolved = await (options.resolveThread ?? resolveCodexThread)(childThreadId);
94
+ const current = recordMatchesTaskReceipt(childThreadId, options);
95
+ if (!sameBoundLifecycleRecord(bound, current)) {
96
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'task receipt or lifecycle revision changed while resolving Codex child evidence');
97
+ }
98
+ const candidateEvents = [resolved.resolution.thread, ...resolved.reroutes, resolved.resolution.settings];
99
+ const candidateState = candidateActivationState(bound.record.state, candidateEvents);
100
+ const candidateFailure = candidateActivationFailure(candidateState, options);
101
+ if (candidateFailure)
102
+ return candidateFailure;
103
+ const evidence = candidateState.startEvidence;
104
+ const repoRoot = options.repoRoot ?? process.cwd();
105
+ const preflight = await (options.preflight ?? preflightCodexLifecycleEvidence)(repoRoot, {
106
+ sessionId: evidence.parentThreadId,
107
+ turnId: evidence.parentTurnId,
108
+ toolUseId: evidence.spawnToolUseId
109
+ });
110
+ const afterPreflight = recordMatchesTaskReceipt(childThreadId, options);
111
+ if (!sameBoundLifecycleRecord(bound, afterPreflight)) {
112
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'task receipt or lifecycle revision changed while validating Codex host evidence');
113
+ }
114
+ return { preflight, events: candidateEvents, evidence };
115
+ }
116
+ function applyCollectedActivationEvidence(childThreadId, options, store, bound, events) {
117
+ const current = recordMatchesTaskReceipt(childThreadId, options);
118
+ if (!sameBoundLifecycleRecord(bound, current)) {
119
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'task receipt or lifecycle revision changed before Codex activation');
120
+ }
121
+ for (const event of events)
122
+ store.apply(event);
123
+ const record = store.read(childThreadId);
124
+ return record.state.status === 'start-ready' && record.state.startEvidence
125
+ ? record
126
+ : bridgeFailure('CODEX_EVIDENCE_IDENTITY_MISMATCH', 'Codex lifecycle identity changed before activation');
127
+ }
128
+ function bridgeFailure(code, message) {
129
+ return {
130
+ status: 'failed', changed: false, taskId: null, run: null, next: null,
131
+ error: { code, message }
132
+ };
133
+ }
134
+ function pauseBridge(code, message, options) {
135
+ const paused = pauseMatchingOrchestrationDelegation('codex', code, message, coreOptions(options));
136
+ return paused.error?.code === 'ORCHESTRATION_DELEGATION_MISSING'
137
+ ? bridgeFailure(code, message)
138
+ : paused;
139
+ }
140
+ function requiredStore(options) {
141
+ if (!options.store)
142
+ throw new Error('Codex lifecycle store is required for orchestration bridge events');
143
+ return options.store;
144
+ }
145
+ async function prepareCodexOrchestrationDelegation(taskRef, input, options = {}) {
146
+ if (input.client !== 'codex')
147
+ return prepareOrchestrationDelegation(taskRef, input, coreOptions(options));
148
+ try {
149
+ const repoRoot = options.repoRoot ?? process.cwd();
150
+ const resolved = resolveTaskRef(taskRef, { repoRoot });
151
+ if (!resolved.ok)
152
+ return bridgeFailure(resolved.code, resolved.message);
153
+ await (options.preflight ?? preflightCodexLifecycleEvidence)(repoRoot, undefined, resolved.taskId);
154
+ const prepared = prepareOrchestrationDelegation(taskRef, input, coreOptions(options));
155
+ const receipt = prepared.run?.pendingDelegation;
156
+ if (prepared.status !== 'running' || !receipt)
157
+ return prepared;
158
+ return Object.freeze({
159
+ ...prepared,
160
+ adapterContext: encodeCodexLifecycleBinding({
161
+ taskId: receipt.taskId,
162
+ runId: receipt.runId,
163
+ receiptId: receipt.id
164
+ })
165
+ });
166
+ }
167
+ catch (error) {
168
+ if (error instanceof OrchestrationStateError)
169
+ return bridgeFailure(error.code, error.message);
170
+ return bridgeFailure('ORCHESTRATION_CLIENT_PREFLIGHT_FAILED', error instanceof Error ? error.message : String(error));
171
+ }
172
+ }
173
+ async function activateCodexOrchestrationDelegation(childThreadId, options = {}) {
174
+ try {
175
+ const store = requiredStore(options);
176
+ const bound = recordMatchesTaskReceipt(childThreadId, options);
177
+ if (!['prepared', 'activated', 'stage-completed'].includes(bound.receipt.status)) {
178
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'lifecycle task receipt is not in an activatable state');
179
+ }
180
+ if (!hasActivatableOrchestrationDelegation('codex', childThreadId, coreOptions(options))) {
181
+ return bridgeFailure('ORCHESTRATION_DELEGATION_MISSING', 'No matching Codex delegation is active');
182
+ }
183
+ const activationEvidence = await collectActivationEvidence(childThreadId, options, bound);
184
+ if ('status' in activationEvidence)
185
+ return activationEvidence;
186
+ const { evidence, events, preflight } = activationEvidence;
187
+ const repoRoot = options.repoRoot ?? process.cwd();
188
+ const record = applyCollectedActivationEvidence(childThreadId, options, store, bound, events);
189
+ if ('status' in record)
190
+ return record;
191
+ const buildIdentity = options.buildIdentity ?? computeLifecycleBuildIdentity(repoRoot);
192
+ const storedAdapterEvidence = readDelegationAdapterEvidence(bound.receipt.taskId, bound.receipt.id, 'codex', coreOptions(options));
193
+ const adapterState = typeof storedAdapterEvidence === 'object' && storedAdapterEvidence !== null && !Array.isArray(storedAdapterEvidence)
194
+ ? storedAdapterEvidence
195
+ : {};
196
+ const activated = activateMatchingOrchestrationDelegation('codex', {
197
+ nativeAgent: evidence.nativeAgent,
198
+ childId: evidence.childThreadId,
199
+ parentId: evidence.parentThreadId,
200
+ spawnMode: evidence.spawnMode,
201
+ actualModel: evidence.actualModel.value,
202
+ actualReasoningEffort: evidence.actualReasoningEffort.value,
203
+ ...(evidence.modelFallbackReason ? { modelFallbackReason: evidence.modelFallbackReason } : {}),
204
+ ...(evidence.reasoningEffortFallbackReason
205
+ ? { reasoningEffortFallbackReason: evidence.reasoningEffortFallbackReason }
206
+ : {}),
207
+ clientEvidence: {
208
+ ...adapterState,
209
+ activationEvidence: {
210
+ kind: 'codex-lifecycle-v2',
211
+ hookDefinitionHash: evidence.hookDefinitionHash,
212
+ startRevision: record.revision,
213
+ ...buildIdentity,
214
+ ...preflight.hookProvenance,
215
+ capabilitySessionId: evidence.parentThreadId,
216
+ capabilityTurnId: evidence.parentTurnId,
217
+ spawnToolUseId: evidence.spawnToolUseId,
218
+ spawnObservedAt: record.spawnObservedAt ?? undefined,
219
+ controllerInstanceDigest: null,
220
+ controlGeneration: null
221
+ }
222
+ }
223
+ }, coreOptions(options));
224
+ return activated;
225
+ }
226
+ catch (error) {
227
+ if (error instanceof OrchestrationStateError)
228
+ return bridgeFailure(error.code, error.message);
229
+ const message = error instanceof Error ? error.message : String(error);
230
+ if (isBindingFailure(message)) {
231
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', message);
232
+ }
233
+ return pauseBridge('ORCHESTRATION_CODEX_START_FAILED', message, options);
234
+ }
235
+ }
236
+ function matchingSpawnRecords(store, binding, spawn) {
237
+ return store.findByTaskBinding(binding).filter((record) => record.state.spawn?.sessionId === spawn.sessionId
238
+ && record.state.spawn?.turnId === spawn.turnId
239
+ && record.state.spawn?.toolUseId === spawn.toolUseId
240
+ && record.state.spawn?.nativeAgent === spawn.nativeAgent);
241
+ }
242
+ function verifySpawnTask(binding, spawn, store, options) {
243
+ const resolved = resolveTaskRef(binding.taskId, { repoRoot: options.repoRoot ?? process.cwd() });
244
+ if (!resolved.ok)
245
+ return bridgeFailure(resolved.code, resolved.message);
246
+ const run = readRun(resolved.taskDir);
247
+ if (!run)
248
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'Codex task has no current orchestration run');
249
+ verifyCodexLifecycleTaskBinding(binding, run, spawn.nativeAgent, {
250
+ requestedModel: spawn.requestedModel,
251
+ requestedReasoningEffort: spawn.requestedReasoningEffort
252
+ });
253
+ return { taskDir: resolved.taskDir };
254
+ }
255
+ async function resolveCurrentSpawnChild(childThreadId, spawn, options) {
256
+ const resolved = await (options.resolveThread ?? resolveCodexThread)(childThreadId);
257
+ if (resolved.resolution.thread.childThreadId !== childThreadId
258
+ || resolved.resolution.thread.parentThreadId !== spawn.sessionId
259
+ || resolved.resolution.thread.nativeAgent !== spawn.nativeAgent) {
260
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'resolved Codex child does not match the native spawn identity');
261
+ }
262
+ return { resolved };
263
+ }
264
+ async function activateCodexSpawnDelegation(spawn, options = {}) {
265
+ try {
266
+ const store = requiredStore(options);
267
+ const parsed = parseCodexLifecycleBinding(spawn.taskName);
268
+ if (!parsed)
269
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISSING', 'Codex spawn task_name has no valid task binding');
270
+ const task = verifySpawnTask(parsed.binding, spawn, store, options);
271
+ if ('status' in task)
272
+ return task;
273
+ const candidates = matchingSpawnRecords(store, parsed.binding, spawn);
274
+ if (candidates.length !== 1) {
275
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'Codex spawn does not identify one current task lifecycle record');
276
+ }
277
+ const childThreadId = resolveCodexSpawnedChild(spawn.transcriptPath, spawn);
278
+ const current = await resolveCurrentSpawnChild(childThreadId, spawn, options);
279
+ if ('status' in current)
280
+ return current;
281
+ const latestTask = verifySpawnTask(parsed.binding, spawn, store, options);
282
+ if ('status' in latestTask)
283
+ return latestTask;
284
+ const latestCandidates = matchingSpawnRecords(store, parsed.binding, spawn);
285
+ if (latestCandidates.length !== 1 || latestCandidates[0].revision !== candidates[0].revision) {
286
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'Codex spawn record changed while resolving its child');
287
+ }
288
+ store.applyToSpawn({ ...spawn, taskBinding: parsed.binding }, {
289
+ type: 'hook-child',
290
+ sessionId: spawn.sessionId,
291
+ turnId: spawn.turnId,
292
+ childThreadId,
293
+ parentThreadId: current.resolved.resolution.thread.parentThreadId,
294
+ nativeAgent: spawn.nativeAgent,
295
+ source: 'parent-rollout'
296
+ }, latestCandidates[0].revision);
297
+ return activateCodexOrchestrationDelegation(childThreadId, {
298
+ ...options,
299
+ store,
300
+ resolveThread: async () => current.resolved
301
+ });
302
+ }
303
+ catch (error) {
304
+ if (error instanceof OrchestrationStateError)
305
+ return bridgeFailure(error.code, error.message);
306
+ const message = error instanceof Error ? error.message : String(error);
307
+ if (/CODEX_LIFECYCLE_TASK_BINDING_MISMATCH|task binding|task_name|identity does not match|does not match the current pending receipt|ambiguous/iu.test(message)) {
308
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', message);
309
+ }
310
+ return pauseBridge('ORCHESTRATION_CODEX_START_FAILED', message, options);
311
+ }
312
+ }
313
+ async function sealCodexOrchestrationDelegation(childThreadId, options = {}) {
314
+ try {
315
+ const bound = recordMatchesTaskReceipt(childThreadId, options);
316
+ if (!hasSealableOrchestrationDelegation('codex', childThreadId, coreOptions(options))) {
317
+ return bridgeFailure('ORCHESTRATION_DELEGATION_MISSING', 'No matching Codex delegation is active');
318
+ }
319
+ const store = requiredStore(options);
320
+ const existing = store.read(childThreadId);
321
+ if (!existing.consumer) {
322
+ const stopTurnId = existing.state.stop?.turnId;
323
+ if (!stopTurnId) {
324
+ return pauseBridge('ORCHESTRATION_CODEX_STOP_EVIDENCE_INVALID', 'Codex lifecycle stop hook is not available', options);
325
+ }
326
+ const terminal = await (options.resolveTerminal ?? resolveCodexTerminal)(childThreadId, stopTurnId);
327
+ const current = recordMatchesTaskReceipt(childThreadId, options);
328
+ if (!sameTaskReceipt(bound.receipt, current.receipt) || !sameLifecycleRevision(existing, current.record)) {
329
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'task receipt or lifecycle revision changed while resolving Codex terminal evidence');
330
+ }
331
+ store.apply(terminal);
332
+ }
333
+ const record = store.read(childThreadId);
334
+ const evidence = record.state.stopEvidence;
335
+ if (record.state.status !== 'stop-ready' || !evidence || !record.state.startEvidence) {
336
+ return pauseBridge('ORCHESTRATION_CODEX_STOP_EVIDENCE_INVALID', 'Codex lifecycle stop evidence is not ready', options);
337
+ }
338
+ const current = recordMatchesTaskReceipt(childThreadId, options);
339
+ const latest = store.read(childThreadId);
340
+ if (!sameTaskReceipt(bound.receipt, current.receipt) || !sameLifecycleRevision(record, latest)
341
+ || !sameTaskBinding(latest.taskBinding, current.binding)) {
342
+ throw new Error('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH: task receipt changed before lifecycle evidence consumption');
343
+ }
344
+ if (current.receipt.status === 'sealed') {
345
+ if (latest.consumer !== current.receipt.id || !latest.consumedAt) {
346
+ return pauseBridge('ORCHESTRATION_CODEX_RECONCILIATION_FAILED', 'Codex lifecycle evidence was not consumed by the sealed receipt', options);
347
+ }
348
+ return reconcileMatchingOrchestrationDelegation('codex', childThreadId, coreOptions(options));
349
+ }
350
+ return sealMatchingOrchestrationDelegation('codex', { nativeAgent: record.state.startEvidence.nativeAgent, childId: childThreadId }, coreOptions(options), () => {
351
+ try {
352
+ const consumed = store.consumeWithinTaskLock(childThreadId, current.receipt.id, existing.state.spawn?.hookDefinitionHash, existing.taskBinding ?? undefined);
353
+ return consumed.consumer === current.receipt.id && consumed.consumedAt
354
+ ? null
355
+ : bridgeFailure('ORCHESTRATION_CODEX_RECONCILIATION_FAILED', 'Codex lifecycle evidence was not consumed by the active receipt');
356
+ }
357
+ catch (error) {
358
+ return codexSealFailure(error, options, 'child');
359
+ }
360
+ });
361
+ }
362
+ catch (error) {
363
+ return codexSealFailure(error, options, 'child');
364
+ }
365
+ }
366
+ function findCurrentParentReceipt(store, repoRoot) {
367
+ if (!store.taskId)
368
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISSING', 'parent seal requires a task-scoped lifecycle store');
369
+ const resolved = resolveTaskRef(store.taskId, { repoRoot });
370
+ if (!resolved.ok)
371
+ return bridgeFailure(resolved.code, resolved.message);
372
+ const pending = readRun(resolved.taskDir)?.pendingDelegation;
373
+ if (!pending || pending.client !== 'codex') {
374
+ return bridgeFailure('ORCHESTRATION_DELEGATION_MISSING', 'No matching Codex delegation is active');
375
+ }
376
+ return { pending };
377
+ }
378
+ function findParentLifecycleRecord(parentThreadId, store, pending) {
379
+ const binding = { taskId: pending.taskId, runId: pending.runId, receiptId: pending.id };
380
+ const candidates = store.findByTaskBinding(binding).filter((record) => record.state.startEvidence?.parentThreadId === parentThreadId);
381
+ if (!candidates.length)
382
+ return bridgeFailure('ORCHESTRATION_DELEGATION_MISSING', 'No matching Codex delegation is active');
383
+ if (candidates.length !== 1) {
384
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'parent seal has multiple lifecycle records for the current task receipt');
385
+ }
386
+ const active = candidates[0];
387
+ const start = active.state.startEvidence;
388
+ const child = active.state.child;
389
+ if (!start || !child || start.childThreadId !== child.childThreadId
390
+ || start.parentThreadId !== parentThreadId
391
+ || active.state.spawn?.sessionId !== parentThreadId
392
+ || active.state.spawn.nativeAgent !== start.nativeAgent
393
+ || managedDelegationRole(start.nativeAgent) !== pending.role) {
394
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'parent lifecycle record does not match the current native delegation identity');
395
+ }
396
+ return { active, start, child };
397
+ }
398
+ async function collectParentTerminalIfNeeded(active, start, options) {
399
+ if (active.state.terminal)
400
+ return null;
401
+ const resolveTerminal = options.resolveTerminal ?? resolveCodexTerminal;
402
+ return active.state.stop
403
+ ? resolveTerminal(start.childThreadId, active.state.stop.turnId)
404
+ : resolveTerminal(start.childThreadId);
405
+ }
406
+ function applyParentTerminalCandidate(parentThreadId, repoRoot, store, pending, active, start, child, terminal) {
407
+ const latestReceipt = findCurrentParentReceipt(store, repoRoot);
408
+ if ('status' in latestReceipt)
409
+ return latestReceipt;
410
+ if (!sameTaskReceipt(pending, latestReceipt.pending)) {
411
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'task receipt changed while resolving parent terminal evidence');
412
+ }
413
+ const latestMatch = findParentLifecycleRecord(parentThreadId, store, latestReceipt.pending);
414
+ if ('status' in latestMatch)
415
+ return latestMatch;
416
+ if (!sameLifecycleRevision(active, latestMatch.active)
417
+ || !sameTaskBinding(active.taskBinding, latestMatch.active.taskBinding)) {
418
+ return bridgeFailure('CODEX_LIFECYCLE_TASK_BINDING_MISMATCH', 'task receipt or lifecycle revision changed while resolving parent terminal evidence');
419
+ }
420
+ if (terminal)
421
+ store.apply(terminal);
422
+ if (!store.read(start.childThreadId).state.stop) {
423
+ store.apply({
424
+ type: 'hook-stop', sessionId: parentThreadId, turnId: child.turnId,
425
+ childThreadId: start.childThreadId, nativeAgent: start.nativeAgent, source: 'parent-rollout'
426
+ });
427
+ }
428
+ return null;
429
+ }
430
+ async function sealCodexParentDelegation(parentThreadId, options = {}) {
431
+ try {
432
+ const store = requiredStore(options);
433
+ const repoRoot = options.repoRoot ?? options.orchestrationOptions?.repoRoot ?? process.cwd();
434
+ const current = findCurrentParentReceipt(store, repoRoot);
435
+ if ('status' in current)
436
+ return current;
437
+ const pending = current.pending;
438
+ const match = findParentLifecycleRecord(parentThreadId, store, pending);
439
+ if ('status' in match)
440
+ return match;
441
+ const { active, start, child } = match;
442
+ if (active.consumer)
443
+ return sealCodexOrchestrationDelegation(start.childThreadId, options);
444
+ const terminal = await collectParentTerminalIfNeeded(active, start, options);
445
+ const failure = applyParentTerminalCandidate(parentThreadId, repoRoot, store, pending, active, start, child, terminal);
446
+ if (failure)
447
+ return failure;
448
+ return sealCodexOrchestrationDelegation(start.childThreadId, options);
449
+ }
450
+ catch (error) {
451
+ return codexSealFailure(error, options, 'parent');
452
+ }
453
+ }
454
+ function reconcileCodexOrchestrationDelegation(childThreadId, options = {}) {
455
+ try {
456
+ const bound = recordMatchesTaskReceipt(childThreadId, options);
457
+ const record = requiredStore(options).read(childThreadId);
458
+ if (bound.receipt.status !== 'sealed' || record.consumer !== bound.receipt.id || !record.consumedAt) {
459
+ return pauseBridge('ORCHESTRATION_CODEX_RECONCILIATION_FAILED', 'Codex lifecycle evidence was not consumed by the sealed receipt', options);
460
+ }
461
+ }
462
+ catch (error) {
463
+ return codexSealFailure(error, options, 'child');
464
+ }
465
+ return reconcileMatchingOrchestrationDelegation('codex', childThreadId, coreOptions(options));
466
+ }
467
+ export { activateCodexOrchestrationDelegation, activateCodexSpawnDelegation, prepareCodexOrchestrationDelegation, reconcileCodexOrchestrationDelegation, sealCodexParentDelegation, sealCodexOrchestrationDelegation };
468
+ //# sourceMappingURL=codex-orchestration.js.map
@@ -1,6 +1,41 @@
1
1
  import { defineAgentClientAdapter } from '../adapter.js';
2
2
  import { hostJoin } from '../../sandbox/engines/wsl2-paths.js';
3
3
  import { codexBeforeContainerCreateHook, codexRecoveryChecks } from './codex-sandbox.js';
4
+ import { parseCodexLifecycleBinding } from './codex-lifecycle/binding.js';
5
+ import { isCodexDelegationReceiptEvidence, isCodexLifecycleActivationEvidence } from './codex-lifecycle/evidence.js';
6
+ import { codexControllerOperation } from './codex-lifecycle/controller-operation.js';
7
+ function codexCarrierError(code) {
8
+ const error = new Error(code);
9
+ error.name = code;
10
+ return error;
11
+ }
12
+ function codexStageToken(stage) {
13
+ const tokens = {
14
+ analysis: 'a',
15
+ plan: 'p',
16
+ code: 'c',
17
+ 'review-analysis': 'ra',
18
+ 'review-plan': 'rp',
19
+ 'review-code': 'rc',
20
+ commit: 'm'
21
+ };
22
+ const token = tokens[stage];
23
+ if (!token)
24
+ throw codexCarrierError('CODEX_LIFECYCLE_SPAWN_IDENTITY_INVALID');
25
+ return token;
26
+ }
27
+ function codexLaunchCarrier(adapterContext, identity) {
28
+ if (!Number.isSafeInteger(identity.round) || identity.round < 1
29
+ || !['executor', 'reviewer'].includes(identity.role)) {
30
+ throw codexCarrierError('CODEX_LIFECYCLE_SPAWN_IDENTITY_INVALID');
31
+ }
32
+ const label = `${codexStageToken(identity.stage)}_${identity.role === 'reviewer' ? 'r' : 'e'}_r${identity.round}`;
33
+ const taskName = `${label}${adapterContext}`;
34
+ const parsed = parseCodexLifecycleBinding(taskName);
35
+ if (!parsed)
36
+ throw codexCarrierError('CODEX_LIFECYCLE_LAUNCH_CONTEXT_INVALID');
37
+ return Object.freeze({ task_name: parsed.taskName });
38
+ }
4
39
  const codexAdapter = defineAgentClientAdapter({
5
40
  id: 'codex',
6
41
  displayName: 'Codex',
@@ -25,8 +60,11 @@ const codexAdapter = defineAgentClientAdapter({
25
60
  actualReasoningEffort: 'app-server'
26
61
  },
27
62
  orchestrationAdapter: {
63
+ validateActivationEvidence: isCodexLifecycleActivationEvidence,
64
+ validateReceiptEvidence: isCodexDelegationReceiptEvidence,
65
+ createLaunchCarrier: codexLaunchCarrier,
28
66
  prepareDelegation: async (...args) => {
29
- const { prepareCodexOrchestrationDelegation } = await import('../../task/codex-orchestration.js');
67
+ const { prepareCodexOrchestrationDelegation } = await import('./codex-orchestration.js');
30
68
  return prepareCodexOrchestrationDelegation(...args);
31
69
  },
32
70
  recoverStarted: async (...args) => {
@@ -34,6 +72,7 @@ const codexAdapter = defineAgentClientAdapter({
34
72
  return recoverStartedLifecycleFromAdapter(...args);
35
73
  }
36
74
  },
75
+ sandboxControlOperation: codexControllerOperation,
37
76
  project: {
38
77
  ownedPathPrefixes: ['.codex/'],
39
78
  managed: ['.codex/hooks.json', '.codex/agents/'],
@@ -1,22 +1,14 @@
1
- import { AGENT_CLIENT_IDS } from '../types.js';
2
1
  import { claudeCodeAdapter } from './claude-code.js';
3
2
  import { codexAdapter } from './codex.js';
4
3
  import { antigravityCliAdapter } from './antigravity-cli.js';
5
4
  import { opencodeAdapter } from './opencode.js';
6
5
  import { traecliAdapter } from './traecli.js';
7
- const adaptersById = new Map([
6
+ const BUILTIN_AGENT_CLIENT_ADAPTERS = Object.freeze([
8
7
  claudeCodeAdapter,
9
8
  codexAdapter,
10
9
  antigravityCliAdapter,
11
10
  opencodeAdapter,
12
11
  traecliAdapter
13
- ].map((adapter) => [adapter.id, adapter]));
14
- const BUILTIN_AGENT_CLIENT_ADAPTERS = Object.freeze(AGENT_CLIENT_IDS.map((id) => {
15
- const adapter = adaptersById.get(id);
16
- if (!adapter) {
17
- throw new Error(`Missing built-in Agent Client adapter '${id}'`);
18
- }
19
- return adapter;
20
- }));
12
+ ]);
21
13
  export { BUILTIN_AGENT_CLIENT_ADAPTERS };
22
14
  //# sourceMappingURL=index.js.map
@@ -1,14 +1,15 @@
1
1
  // Active AI collaborator short tokens — the write-side whitelist for the
2
2
  // activity log. Migrated from lib/task/commands/log.ts so that the write-side
3
3
  // internal commands and the rendering side share one definition.
4
- export const KNOWN_AI_AGENTS = new Set(['claude', 'codex', 'antigravity', 'opencode', 'cursor', 'traecli']);
4
+ export const AGENT_TOKEN_VALUES = ['claude', 'codex', 'antigravity', 'opencode', 'cursor', 'traecli'];
5
+ export const KNOWN_AI_AGENTS = new Set(AGENT_TOKEN_VALUES);
5
6
  // Long name -> short name mapping: `claude-code` reuses the existing
6
7
  // orchestration precedent, and `antigravity-cli` is the active client.
7
8
  export const AGENT_LONG_NAMES = {
8
9
  'claude-code': 'claude',
9
10
  'antigravity-cli': 'antigravity'
10
11
  };
11
- export const AGENT_USAGE_HINT = "agent must be a short token (claude/codex/antigravity/opencode/cursor/traecli), " +
12
+ export const AGENT_USAGE_HINT = `agent must be a short token (${AGENT_TOKEN_VALUES.join('/')}), ` +
12
13
  "a long name (claude-code -> claude, antigravity-cli -> antigravity), or 'human'";
13
14
  // Strict write-side validation: the value must be exactly a short token, a
14
15
  // long name, or 'human'; returns the normalized short token, or null when