@fitlab-ai/agent-infra 0.11.1 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/lib/internal/cli-route-inventory.js +1 -1
  2. package/dist/lib/internal/platform-comment.js +59 -0
  3. package/dist/lib/internal/sandbox-control.js +4 -131
  4. package/dist/lib/internal/task-artifact.js +1 -1
  5. package/dist/lib/internal/task-operation-registry.js +1 -0
  6. package/dist/lib/internal/task-review.js +5 -5
  7. package/dist/lib/internal/task-validate.js +0 -6
  8. package/dist/lib/platform/comment-safety.js +7 -1
  9. package/dist/lib/platform/github-provider.js +13 -3
  10. package/dist/lib/platform/issue-comments.js +120 -13
  11. package/dist/lib/platform/provider-contract.d.ts +2 -0
  12. package/dist/lib/platform/provider-validation.js +7 -2
  13. package/dist/lib/platform/verification-sync.js +19 -2
  14. package/dist/lib/sandbox/control/executor.js +0 -38
  15. package/dist/lib/sandbox/control/finalization-response.js +10 -2
  16. package/dist/lib/sandbox/control/task-view.js +3 -1
  17. package/dist/lib/sandbox/control/workflow-executor.js +28 -43
  18. package/dist/lib/task/artifact-command.js +6 -6
  19. package/dist/lib/task/codex-orchestration.js +10 -208
  20. package/dist/lib/task/commit-operation.js +3 -18
  21. package/dist/lib/task/control-authority.js +1 -8
  22. package/dist/lib/task/delegation-receipts.js +14 -76
  23. package/dist/lib/task/events.js +89 -237
  24. package/dist/lib/task/finalization-state.js +2 -1
  25. package/dist/lib/task/finalization.js +273 -49
  26. package/dist/lib/task/lifecycle-execution.js +2 -11
  27. package/dist/lib/task/local-artifact-finalization.js +25 -242
  28. package/dist/lib/task/orchestration.js +0 -18
  29. package/dist/lib/task/review-command.js +0 -1
  30. package/dist/lib/task/review-finalization.js +46 -211
  31. package/dist/lib/task/workflow-command.js +4 -1
  32. package/dist/lib/task/workflow-dispatch.js +55 -3
  33. package/dist/lifecycle-build-manifest.json +3 -3
  34. package/lib/internal/cli-route-inventory.ts +1 -1
  35. package/lib/internal/platform-comment.ts +38 -0
  36. package/lib/internal/sandbox-control.ts +3 -145
  37. package/lib/internal/task-artifact.ts +1 -1
  38. package/lib/internal/task-operation-registry.ts +1 -0
  39. package/lib/internal/task-review.ts +5 -5
  40. package/lib/internal/task-validate.ts +0 -5
  41. package/lib/platform/comment-safety.ts +8 -0
  42. package/lib/platform/github-provider.ts +11 -2
  43. package/lib/platform/issue-comments.ts +132 -13
  44. package/lib/platform/provider-contract.ts +2 -0
  45. package/lib/platform/provider-validation.ts +6 -2
  46. package/lib/platform/verification-sync.ts +19 -2
  47. package/lib/sandbox/control/executor.ts +0 -44
  48. package/lib/sandbox/control/finalization-response.ts +10 -2
  49. package/lib/sandbox/control/task-view.ts +3 -1
  50. package/lib/sandbox/control/workflow-executor.ts +23 -50
  51. package/lib/task/artifact-command.ts +6 -7
  52. package/lib/task/codex-orchestration.ts +8 -241
  53. package/lib/task/commit-operation.ts +3 -23
  54. package/lib/task/control-authority.ts +1 -8
  55. package/lib/task/delegation-receipts.ts +12 -79
  56. package/lib/task/events.ts +106 -255
  57. package/lib/task/finalization-state.ts +2 -1
  58. package/lib/task/finalization.ts +277 -57
  59. package/lib/task/lifecycle-execution.ts +10 -21
  60. package/lib/task/local-artifact-finalization.ts +23 -281
  61. package/lib/task/orchestration.ts +0 -34
  62. package/lib/task/review-command.ts +0 -1
  63. package/lib/task/review-finalization.ts +45 -193
  64. package/lib/task/workflow-command.ts +4 -1
  65. package/lib/task/workflow-dispatch.ts +46 -3
  66. package/package.json +2 -2
  67. package/templates/.agents/rules/lifecycle-orchestration.en.md +7 -7
  68. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +7 -7
  69. package/templates/.agents/rules/local-artifact-repair.en.md +14 -60
  70. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -60
  71. package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
  72. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
  73. package/templates/.agents/skills/code-task/SKILL.en.md +3 -3
  74. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +3 -3
  75. package/templates/.agents/skills/complete-task/SKILL.en.md +3 -3
  76. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +3 -3
  77. package/templates/.agents/skills/plan-task/SKILL.en.md +3 -3
  78. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +3 -3
  79. package/templates/.agents/skills/review-analysis/SKILL.en.md +2 -2
  80. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
  81. package/templates/.agents/skills/review-code/SKILL.en.md +3 -3
  82. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +3 -3
  83. package/templates/.agents/skills/review-plan/SKILL.en.md +2 -2
  84. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
  85. package/templates/.agents/skills/run-task/SKILL.en.md +6 -6
  86. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +6 -6
  87. package/templates/.agents/skills/run-task/reference/host-validation.en.md +2 -2
  88. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +2 -2
@@ -357,43 +357,6 @@ async function executeRequestInner(manifest, manifestPath, request, options = {}
357
357
  ? lifecycleFailure('LIFECYCLE_PAYLOAD_INVALID', message)
358
358
  : orchestrationFailure(code, message);
359
359
  }
360
- let controllerBinding = null;
361
- if (request.family === 'task-orchestration') {
362
- const codexPrepare = operation.family === 'task-orchestration'
363
- && operation.intent === 'prepare'
364
- && operation.input.client === 'codex';
365
- if (codexPrepare) {
366
- if (!request.controllerProof) {
367
- const authority = options.lifecycleRecoveryAttestation;
368
- if (!authority || authority.phase !== 'orchestration.prepare') {
369
- return orchestrationFailure('CODEX_SANDBOX_CONTROLLER_PROOF_REQUIRED', 'Codex prepare requires a current controller lease proof');
370
- }
371
- controllerBinding = {
372
- instanceDigest: authority.controllerInstanceDigest,
373
- controlGeneration: authority.controlGeneration
374
- };
375
- }
376
- else {
377
- try {
378
- controllerBinding = (options.resolveControllerBinding ?? resolveCodexControllerBinding)({
379
- manifest,
380
- manifestPath,
381
- proof: request.controllerProof,
382
- buildIdentity: (options.buildIdentity ?? computeLifecycleBuildIdentity)(manifest.repoRoot)
383
- });
384
- }
385
- catch (error) {
386
- const code = error instanceof CodexControllerRegistrationError
387
- ? error.code
388
- : 'CODEX_SANDBOX_CONTROLLER_PROOF_INVALID';
389
- return orchestrationFailure(code, `${code}: Codex controller proof was rejected`);
390
- }
391
- }
392
- }
393
- else if (request.controllerProof !== null) {
394
- return orchestrationFailure('CODEX_SANDBOX_CONTROLLER_PROOF_INVALID', 'Controller proof is only accepted for canonical Codex prepare');
395
- }
396
- }
397
360
  const diagnosticLog = (event, fields) => {
398
361
  appendExecutorAudit(manifest, event.startsWith('orchestration-') ? event : `orchestration-${event}`, {
399
362
  requestId: request.id,
@@ -411,7 +374,6 @@ async function executeRequestInner(manifest, manifestPath, request, options = {}
411
374
  manifestPath,
412
375
  requestId: request.id,
413
376
  diagnosticLog,
414
- ...(controllerBinding ? { controllerBinding } : {}),
415
377
  lifecycleRecoveryAttestation: options.lifecycleRecoveryAttestation ?? null
416
378
  });
417
379
  const format = (value) => {
@@ -1,9 +1,15 @@
1
1
  export function finalizationTerminalResponse(taskId, requestId, receipt) {
2
2
  const pendingSteps = [
3
3
  receipt.taskComment === 'pending' ? 'task-comment' : null,
4
- receipt.verification === 'pending' ? 'verification' : null
4
+ receipt.verification === 'pending' ? 'verification' : null,
5
+ receipt.summary === 'pending' ? 'summary' : null,
6
+ receipt.postSummaryVerification === 'pending' ? 'post-summary-verification' : null
5
7
  ].filter((step) => step !== null);
6
- const completedSteps = ['lifecycle', receipt.taskComment === 'pending' ? null : 'task-comment', receipt.verification === 'pending' ? null : 'verification']
8
+ const completedSteps = [
9
+ 'lifecycle', receipt.taskComment === 'pending' ? null : 'task-comment',
10
+ receipt.verification === 'pending' ? null : 'verification', receipt.summary === 'pending' ? null : 'summary',
11
+ receipt.postSummaryVerification === 'pending' ? null : 'post-summary-verification'
12
+ ]
7
13
  .filter((step) => step !== null);
8
14
  const warnings = receipt.warnings
9
15
  .filter((warning) => warning.status === 'open')
@@ -13,6 +19,8 @@ export function finalizationTerminalResponse(taskId, requestId, receipt) {
13
19
  lifecycle: { status: 'no-op', changed: false, error: null },
14
20
  taskComment: receipt.taskComment === 'pending' ? null : { status: 'no-op', changed: false, error: null },
15
21
  verification: receipt.verification === 'pending' ? null : { status: 'no-op', changed: false, error: null },
22
+ summary: receipt.summary === 'pending' ? null : { status: 'no-op', changed: false, error: null },
23
+ postSummaryVerification: receipt.postSummaryVerification === 'pending' ? null : { status: 'no-op', changed: false, error: null },
16
24
  completedSteps, pendingSteps,
17
25
  result: pendingSteps.length > 0 || receipt.warningProjection === 'pending' || warnings.length > 0
18
26
  ? 'completed_with_warnings' : 'completed',
@@ -13,9 +13,11 @@ function receiptIdentity(value, generation, requestId) {
13
13
  if (!binding || typeof binding !== 'object' || Array.isArray(binding))
14
14
  return null;
15
15
  const controlBinding = binding;
16
- if (receipt.version !== 2 || typeof receipt.receiptId !== 'string' || receipt.receiptId.length === 0
16
+ if (receipt.version !== 3 || typeof receipt.receiptId !== 'string' || receipt.receiptId.length === 0
17
17
  || !Number.isSafeInteger(receipt.revision) || receipt.revision < 0
18
18
  || receipt.lifecycle !== 'done'
19
+ || !['pending', 'done', 'skipped'].includes(String(receipt.summary))
20
+ || !['pending', 'done', 'skipped'].includes(String(receipt.postSummaryVerification))
19
21
  || controlBinding.generation !== generation
20
22
  || typeof controlBinding.requestId !== 'string'
21
23
  || !/^[a-f0-9-]{16,64}$/u.test(controlBinding.requestId)
@@ -1,9 +1,11 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { randomUUID } from 'node:crypto';
1
4
  import { TASK_WORKFLOW_COMMANDS } from '../../task/workflow-command.js';
2
5
  import { parseArtifactCommand, executeArtifactCommand } from '../../task/artifact-command.js';
3
6
  import { parseReviewCommand } from '../../task/review-command.js';
4
7
  import { prepareLocalArtifact, preflightLocalArtifact, commitLocalArtifactProvenance } from '../../task/local-artifact-finalization.js';
5
- import { prepareReviewSummaryCandidate, commitReviewSummaryProvenance, preflightReviewSummary } from '../../task/review-finalization.js';
6
- import { readArtifactRecoveryIntent } from '../../task/artifact-repair-intent.js';
8
+ import { prepareReviewSummaryCandidate, preflightReviewSummary } from '../../task/review-finalization.js';
7
9
  import { withTaskExecutionLock } from '../../task/task-execution-lock.js';
8
10
  import { dispatchWorkflowCommand } from '../../task/workflow-dispatch.js';
9
11
  import { assertSandboxTaskSource } from '../workspace-view.js';
@@ -14,20 +16,25 @@ import { parseTaskEventRequest } from '../../internal/task-event.js';
14
16
  function executionResult(result) {
15
17
  return { exitCode: result.status === 'failed' || result.status === 'refused' ? 1 : 0, stdout: `${JSON.stringify(result)}\n`, stderr: '' };
16
18
  }
19
+ function replaceCurrentArtifactAtomically(file, content) {
20
+ const temporary = path.join(path.dirname(file), `.${path.basename(file)}.${process.pid}.${randomUUID()}.tmp`);
21
+ try {
22
+ fs.writeFileSync(temporary, content, { encoding: 'utf8', flag: 'wx' });
23
+ fs.renameSync(temporary, file);
24
+ }
25
+ finally {
26
+ try {
27
+ fs.unlinkSync(temporary);
28
+ }
29
+ catch (error) {
30
+ if (error.code !== 'ENOENT')
31
+ throw error;
32
+ }
33
+ }
34
+ }
17
35
  /** The broker already authorized this host executor; domain operations own validation. */
18
36
  export async function executeTaskWorkflow(manifest, request, lifecycleRecoveryAttestation = null, options = {}) {
19
37
  let publicationCommitted = false;
20
- let recoveryObservation = null;
21
- const observeRecoveryPublication = () => {
22
- if (!recoveryObservation || recoveryObservation.wasPassed)
23
- return;
24
- const intent = readArtifactRecoveryIntent(manifest.repoRoot, request.taskId, recoveryObservation.family, recoveryObservation.artifact);
25
- publicationCommitted ||= intent?.state === 'preflight-ready'
26
- || intent?.state === 'preflight-commit-started'
27
- || intent?.state === 'preflight-passed'
28
- || intent?.state === 'passed'
29
- || intent?.state === 'commit-started';
30
- };
31
38
  let faultTriggered = false;
32
39
  const fault = (window) => {
33
40
  if (faultTriggered || options.faultWindow !== window)
@@ -91,26 +98,13 @@ export async function executeTaskWorkflow(manifest, request, lifecycleRecoveryAt
91
98
  const { family } = input;
92
99
  if (family !== 'analysis' && family !== 'plan' && family !== 'code')
93
100
  throw new Error('ARTIFACT_IDENTITY_INVALID');
94
- const local = { taskRef: request.taskId, family, artifact: input.artifact, repoRoot: manifest.repoRoot, recoveryId: input.recoveryId, lockAlreadyHeld: true };
101
+ const local = { taskRef: request.taskId, family, artifact: input.artifact, repoRoot: manifest.repoRoot, lockAlreadyHeld: true };
95
102
  if (input.operation === 'preflight') {
96
- // Preflight only seals a verified generation. It must not publish the
97
- // formal artifact, set publicationStarted, or append finalizer audit.
98
103
  const result = preflightLocalArtifact(local);
99
- recoveryObservation = { family, artifact: input.artifact, wasPassed: false };
100
- observeRecoveryPublication();
101
104
  return response(result);
102
105
  }
103
- recoveryObservation = {
104
- family,
105
- artifact: input.artifact,
106
- wasPassed: readArtifactRecoveryIntent(manifest.repoRoot, request.taskId, family, input.artifact)?.state === 'passed'
107
- };
108
- const prepared = prepareLocalArtifact(local, content, lifecycleRecoveryAttestation ?? undefined);
109
- observeRecoveryPublication();
110
- const commitOptions = { afterPublish: () => fault('after-atomic-rename') };
111
- if (prepared.result.status === 'failed')
112
- return executionResult(commitLocalArtifactProvenance(prepared, commitOptions));
113
- result = commitLocalArtifactProvenance(prepared, commitOptions);
106
+ const prepared = prepareLocalArtifact(local, content);
107
+ result = commitLocalArtifactProvenance(prepared);
114
108
  }
115
109
  else {
116
110
  if (input.overrideTicket)
@@ -118,25 +112,17 @@ export async function executeTaskWorkflow(manifest, request, lifecycleRecoveryAt
118
112
  const family = `review-${input.stage}`;
119
113
  if (request.operation === 'review-preflight') {
120
114
  const result = preflightReviewSummary(input, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true });
121
- recoveryObservation = { family, artifact: input.artifact, wasPassed: false };
122
- observeRecoveryPublication();
123
115
  return response(result);
124
116
  }
125
- recoveryObservation = {
126
- family,
127
- artifact: input.artifact,
128
- wasPassed: readArtifactRecoveryIntent(manifest.repoRoot, request.taskId, family, input.artifact)?.state === 'passed'
129
- };
130
- const prepared = prepareReviewSummaryCandidate(input, content, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true, startRecovery: true });
131
- observeRecoveryPublication();
117
+ const prepared = prepareReviewSummaryCandidate(input, content, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true });
132
118
  if (input.dryRun || prepared.result.status === 'planned')
133
119
  return executionResult(prepared.result);
134
- const commitOptions = { afterPublish: () => fault('after-atomic-rename') };
135
120
  if (prepared.result.status === 'failed')
136
- return executionResult(commitReviewSummaryProvenance(prepared, manifest.repoRoot, commitOptions));
137
- result = commitReviewSummaryProvenance(prepared, manifest.repoRoot, commitOptions);
121
+ return executionResult(prepared.result);
122
+ if (prepared.result.changed)
123
+ replaceCurrentArtifactAtomically(path.join(taskDir, input.artifact), prepared.content);
124
+ result = prepared.result;
138
125
  }
139
- observeRecoveryPublication();
140
126
  publicationCommitted ||= result.changed === true;
141
127
  if (result.status !== 'failed')
142
128
  appendDiagnosticAudit(manifest, 'task-workflow-artifact-finalized', {
@@ -148,7 +134,6 @@ export async function executeTaskWorkflow(manifest, request, lifecycleRecoveryAt
148
134
  });
149
135
  }
150
136
  catch (error) {
151
- observeRecoveryPublication();
152
137
  const message = error instanceof Error ? error.message : String(error);
153
138
  const code = error?.code ?? /^([A-Z][A-Z0-9_]+)/u.exec(message)?.[1] ?? 'TASK_WORKFLOW_REQUEST_INVALID';
154
139
  return executionResult({ status: 'failed', changed: publicationCommitted ? null : false, error: { code, message } });
@@ -15,8 +15,8 @@ export function parseArtifactCommand(args) {
15
15
  const allowed = {
16
16
  inspect: ['--family'],
17
17
  init: ['--family', '--artifact', '--locale'],
18
- 'preflight': ['--family', '--artifact', '--recovery-id'],
19
- 'finalize-local': ['--family', '--artifact', '--recovery-id']
18
+ 'preflight': ['--family', '--artifact'],
19
+ 'finalize-local': ['--family', '--artifact']
20
20
  }[operation];
21
21
  for (let index = 2; index < args.length; index += 1) {
22
22
  const flag = args[index];
@@ -38,12 +38,12 @@ export function parseArtifactCommand(args) {
38
38
  throw new Error("option '--locale' must be 'zh-CN' or 'en'");
39
39
  return {
40
40
  taskRef, operation: operation, family: fields['--family'],
41
- artifact: fields['--artifact'] ?? '', locale, recoveryId: fields['--recovery-id']
41
+ artifact: fields['--artifact'] ?? '', locale
42
42
  };
43
43
  }
44
44
  /** Resolve authoritative task metadata separately from a trusted candidate directory. */
45
45
  export function executeArtifactCommand(command, options = {}) {
46
- const { taskRef, operation, family, artifact, locale, recoveryId } = command;
46
+ const { taskRef, operation, family, artifact, locale } = command;
47
47
  const fail = (code, message) => ({ status: 'failed', changed: false, error: { code, message } });
48
48
  if (operation === 'inspect') {
49
49
  const result = resolveArtifactContext(taskRef, family, { repoRoot: options.repoRoot });
@@ -76,7 +76,7 @@ export function executeArtifactCommand(command, options = {}) {
76
76
  return fail('ARTIFACT_PAYLOAD_INVALID', "preflight and finalize-local only support 'analysis', 'plan', and 'code'");
77
77
  }
78
78
  if (operation === 'preflight')
79
- return { ...preflightLocalArtifact({ taskRef, family, artifact, repoRoot: resolved.repoRoot, recoveryId }) };
80
- return { ...finalizeLocalArtifact({ taskRef, family, artifact, repoRoot: resolved.repoRoot, recoveryId }) };
79
+ return { ...preflightLocalArtifact({ taskRef, family, artifact, repoRoot: resolved.repoRoot }) };
80
+ return { ...finalizeLocalArtifact({ taskRef, family, artifact, repoRoot: resolved.repoRoot }) };
81
81
  }
82
82
  //# sourceMappingURL=artifact-command.js.map
@@ -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);
@@ -535,17 +535,11 @@ function orchestration(context, operation) {
535
535
  client: input.client,
536
536
  requestedModel: input.requestedModel,
537
537
  requestedReasoningEffort: input.requestedReasoningEffort,
538
- ...(input.capabilityRef === undefined ? {} : { capabilityRef: input.capabilityRef }),
539
- ...(context.lifecycleRecoveryAttestation === undefined
540
- ? {}
541
- : { lifecycleRecoveryAttestation: context.lifecycleRecoveryAttestation })
542
538
  };
543
539
  if (prepareInput.client === 'codex') {
544
540
  return prepareCodexOrchestrationDelegation(operation.taskRef, prepareInput, {
545
541
  repoRoot: context.repoRoot,
546
542
  orchestrationOptions: options,
547
- deferLifecycleRecoveryConsumption: context.source === 'sandbox-executor',
548
- ...(context.controllerBinding ? { controllerBinding: context.controllerBinding } : {})
549
543
  });
550
544
  }
551
545
  return prepareOrchestrationDelegation(operation.taskRef, prepareInput, options);
@@ -629,7 +623,7 @@ const FINALIZATION_FLAGS = new Set(['--agent']);
629
623
  const ORCHESTRATION_FLAGS = new Set([
630
624
  '--agent', '--max-steps', '--executor-model', '--executor-reasoning-effort', '--reviewer-model',
631
625
  '--reviewer-reasoning-effort', '--client', '--requested-model', '--requested-reasoning-effort',
632
- '--capability-ref', '--parent-id', '--before-fingerprint', '--stage', '--round', '--artifact', '--role',
626
+ '--parent-id', '--before-fingerprint', '--stage', '--round', '--artifact', '--role',
633
627
  '--native-agent', '--child-id', '--spawn-mode', '--actual-model', '--actual-reasoning-effort',
634
628
  '--model-fallback-reason', '--reasoning-effort-fallback-reason', '--exit-code', '--after-fingerprint',
635
629
  '--changed-paths', '--code', '--message', '--recoverable', '--git-worktree-root'
@@ -769,7 +763,6 @@ export function parseTaskControlOperation(family, args) {
769
763
  if (parsedIntent === 'prepare') {
770
764
  input.requestedModel = value(values, '--requested-model');
771
765
  input.requestedReasoningEffort = value(values, '--requested-reasoning-effort');
772
- input.capabilityRef = value(values, '--capability-ref');
773
766
  }
774
767
  if (parsedIntent === 'await-activation') {
775
768
  required(values, ['--stage', '--round', '--artifact', '--role']);