@fitlab-ai/agent-infra 0.9.8 → 0.9.9

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 (133) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/bin/internal-cli.js +6 -1
  4. package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +58 -21
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +8 -1
  6. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +173 -10
  7. package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-context.js +147 -0
  8. package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +14 -0
  9. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +56 -67
  10. package/dist/lib/git/workflow.js +10 -1
  11. package/dist/lib/internal/codex-lifecycle.js +19 -5
  12. package/dist/lib/internal/codex-sandbox-controller.js +6 -13
  13. package/dist/lib/internal/git-workflow.js +5 -7
  14. package/dist/lib/internal/platform-pr.js +20 -7
  15. package/dist/lib/internal/release-workflow.js +2 -1
  16. package/dist/lib/internal/sandbox-control.js +79 -2
  17. package/dist/lib/internal/task-finalization.js +54 -0
  18. package/dist/lib/internal/task-orchestration.js +156 -291
  19. package/dist/lib/platform/pr-summary.js +48 -10
  20. package/dist/lib/platform/pull-requests.js +205 -41
  21. package/dist/lib/sandbox/commands/rm.js +316 -55
  22. package/dist/lib/sandbox/control/client.js +190 -6
  23. package/dist/lib/sandbox/control/controller-registration.js +273 -0
  24. package/dist/lib/sandbox/control/executor.js +137 -5
  25. package/dist/lib/sandbox/control/lifecycle.js +3 -1
  26. package/dist/lib/sandbox/control/protocol.js +67 -6
  27. package/dist/lib/sandbox/index.js +5 -3
  28. package/dist/lib/sandbox/managed-fs.js +5 -0
  29. package/dist/lib/sandbox/task-resolver.js +50 -6
  30. package/dist/lib/sandbox/workspace-identity.js +27 -0
  31. package/dist/lib/sandbox/worktree-safety.js +215 -2
  32. package/dist/lib/task/codex-orchestration.js +158 -33
  33. package/dist/lib/task/commands/status.js +59 -1
  34. package/dist/lib/task/commit-operation.js +335 -0
  35. package/dist/lib/task/commit-policy.js +18 -0
  36. package/dist/lib/task/delegation-receipts.js +243 -2
  37. package/dist/lib/task/finalization.js +567 -0
  38. package/dist/lib/task/operation-outcome.js +33 -0
  39. package/dist/lib/task/orchestration.js +187 -761
  40. package/dist/lib/task/short-id.js +59 -1
  41. package/dist/lib/task/task-execution-lock.js +6 -1
  42. package/dist/lib/task/verification-engine.js +113 -60
  43. package/dist/lib/task/verification.js +2 -1
  44. package/dist/lib/task/workflow-warning-intents.js +50 -1
  45. package/dist/lifecycle-build-manifest.json +3 -3
  46. package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +61 -19
  47. package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +12 -0
  48. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +276 -12
  49. package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +180 -0
  50. package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +19 -0
  51. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +9 -1
  52. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +83 -91
  53. package/lib/git/workflow.ts +11 -2
  54. package/lib/internal/codex-lifecycle.ts +18 -5
  55. package/lib/internal/codex-sandbox-controller.ts +6 -12
  56. package/lib/internal/git-workflow.ts +5 -6
  57. package/lib/internal/platform-pr.ts +14 -7
  58. package/lib/internal/release-workflow.ts +2 -1
  59. package/lib/internal/sandbox-control.ts +92 -2
  60. package/lib/internal/task-finalization.ts +68 -0
  61. package/lib/internal/task-orchestration.ts +20 -103
  62. package/lib/platform/pr-summary.ts +55 -11
  63. package/lib/platform/pull-requests.ts +211 -41
  64. package/lib/sandbox/commands/rm.ts +413 -61
  65. package/lib/sandbox/control/client.ts +255 -6
  66. package/lib/sandbox/control/controller-registration.ts +347 -0
  67. package/lib/sandbox/control/executor.ts +163 -5
  68. package/lib/sandbox/control/lifecycle.ts +2 -1
  69. package/lib/sandbox/control/protocol.ts +80 -7
  70. package/lib/sandbox/index.ts +5 -3
  71. package/lib/sandbox/managed-fs.ts +5 -0
  72. package/lib/sandbox/task-resolver.ts +58 -7
  73. package/lib/sandbox/workspace-identity.ts +50 -2
  74. package/lib/sandbox/workspace-view.ts +3 -3
  75. package/lib/sandbox/worktree-safety.ts +236 -2
  76. package/lib/task/codex-orchestration.ts +167 -33
  77. package/lib/task/commands/status.ts +78 -1
  78. package/lib/task/commit-operation.ts +430 -0
  79. package/lib/task/commit-policy.ts +30 -0
  80. package/lib/task/delegation-receipts.ts +258 -1
  81. package/lib/task/finalization.ts +719 -0
  82. package/lib/task/operation-outcome.ts +48 -0
  83. package/lib/task/orchestration.ts +217 -982
  84. package/lib/task/short-id.ts +65 -1
  85. package/lib/task/task-execution-lock.ts +10 -1
  86. package/lib/task/verification-engine.ts +118 -63
  87. package/lib/task/verification.ts +3 -2
  88. package/lib/task/workflow-warning-intents.ts +57 -2
  89. package/package.json +2 -2
  90. package/templates/.agents/QUICKSTART.en.md +2 -2
  91. package/templates/.agents/QUICKSTART.zh-CN.md +2 -2
  92. package/templates/.agents/hooks/lifecycle-delegation.js +1 -21
  93. package/templates/.agents/rules/lifecycle-orchestration.en.md +1 -1
  94. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +1 -1
  95. package/templates/.agents/rules/task-management.en.md +2 -2
  96. package/templates/.agents/rules/task-management.zh-CN.md +2 -2
  97. package/templates/.agents/skills/block-task/SKILL.en.md +2 -4
  98. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -4
  99. package/templates/.agents/skills/cancel-task/SKILL.en.md +3 -3
  100. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +3 -3
  101. package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -2
  102. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -2
  103. package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -2
  104. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -2
  105. package/templates/.agents/skills/commit/SKILL.en.md +41 -125
  106. package/templates/.agents/skills/commit/SKILL.zh-CN.md +52 -123
  107. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
  108. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
  109. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +14 -43
  110. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +14 -49
  111. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
  112. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
  113. package/templates/.agents/skills/commit/reference/task-status-update.en.md +2 -35
  114. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +2 -35
  115. package/templates/.agents/skills/complete-task/SKILL.en.md +31 -38
  116. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +31 -38
  117. package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
  118. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
  119. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +1 -1
  120. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +1 -1
  121. package/templates/.agents/skills/create-pr/SKILL.en.md +6 -4
  122. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +6 -4
  123. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +2 -2
  124. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +2 -2
  125. package/templates/.agents/skills/run-task/SKILL.en.md +5 -5
  126. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +5 -5
  127. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +1 -1
  128. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +1 -1
  129. package/templates/.codex/hooks.json +4 -4
  130. package/dist/lib/task/commit-finalization.js +0 -305
  131. package/dist/lib/task/commit-intent.js +0 -165
  132. package/lib/task/commit-finalization.ts +0 -419
  133. package/lib/task/commit-intent.ts +0 -230
@@ -1,13 +1,12 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { randomUUID } from 'node:crypto';
4
- import { execFileSync, spawnSync } from 'node:child_process';
5
4
  import { parseTypedTaskFrontmatter } from './frontmatter.js';
6
5
  import { parseReviewSummary } from './review-artifacts.js';
7
6
  import { inspectArtifactDirectory } from './artifact-lifecycle.js';
8
7
  import { parseLedger, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
9
8
  import { resolveTaskRef } from './resolve-ref.js';
10
- import { activateDelegation, abortPreparedDelegation, completeDelegationStage, consumeDelegation, dispatchDelegation, foldBlankToNull, managedDelegationRole, prepareDelegation, sealDelegation } from './delegation-receipts.js';
9
+ import { activateDelegation, abortPreparedDelegation, completeDelegationStage, consumeDelegation, dispatchDelegation, foldBlankToNull, isDelegationReceipt, managedDelegationRole, prepareDelegation, sealDelegation } from './delegation-receipts.js';
11
10
  import { normalizeAgentClients } from '../agent-clients/config.js';
12
11
  import { resolveAgentRuntimeStoreRoot } from '../runtime/agent-runtime.js';
13
12
  import { inspectPlatformPullRequest } from '../platform/pull-requests.js';
@@ -17,10 +16,6 @@ import { captureRepositorySnapshot, captureWorkspaceSnapshot, diffWorkspaceSnaps
17
16
  import { assertGitRepositoryBinding } from '../git/worktree-identity.js';
18
17
  import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
19
18
  import { hasActiveCodexLifecycleEvidence } from '../agent-clients/adapters/codex-lifecycle/store.js';
20
- import { CommitIntentError, commitIntentPath, createCommitIntent, digest, readCommitIntent, removeCommitIntent, removeCommitIntentByDigest, serialize, updateCommitIntent } from './commit-intent.js';
21
- import { inspectCommitFinalization, planCommitTaskFinalization } from './commit-finalization.js';
22
- import { captureTaskWriteMetadata, writeTask } from './write.js';
23
- import { appendActivityEntry, commitAttemptStartedNote, locateActivityLog, pairEntries } from './activity-log.js';
24
19
  function supportsLifecycleDelegation(client) {
25
20
  return getAgentClientCapability(client, 'subagents').level !== 'unsupported'
26
21
  && getAgentClientCapability(client, 'orchestration').level !== 'unsupported'
@@ -30,26 +25,138 @@ function supportsLifecycleDelegation(client) {
30
25
  function orchestrationPath(taskDir) {
31
26
  return path.join(taskDir, 'orchestration.json');
32
27
  }
28
+ const ORCHESTRATION_STATE_INVALID_MESSAGE = 'orchestration.json does not match the current runtime structure; finish or clear active runs before upgrading';
29
+ class OrchestrationStateError extends Error {
30
+ code = 'ORCHESTRATION_STATE_INVALID';
31
+ taskId;
32
+ constructor(taskId = null) {
33
+ super(ORCHESTRATION_STATE_INVALID_MESSAGE);
34
+ this.name = 'OrchestrationStateError';
35
+ this.taskId = taskId;
36
+ }
37
+ }
38
+ function isRecord(value) {
39
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
40
+ }
41
+ function hasExactKeys(value, keys) {
42
+ if (!isRecord(value))
43
+ return false;
44
+ const actual = Object.keys(value);
45
+ return actual.length === keys.length && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
46
+ }
47
+ function exactText(value) {
48
+ return typeof value === 'string' && value.length > 0 && value.trim() === value;
49
+ }
50
+ function nullableText(value) {
51
+ return value === null || exactText(value);
52
+ }
53
+ function isPause(value) {
54
+ return hasExactKeys(value, ['code', 'message', 'recoverable'])
55
+ && exactText(value.code)
56
+ && exactText(value.message)
57
+ && typeof value.recoverable === 'boolean';
58
+ }
59
+ function isModelPolicySource(value) {
60
+ return hasExactKeys(value, ['kind', 'client', 'resolvedAt'])
61
+ && ['explicit', 'project-config'].includes(value.kind)
62
+ && isAgentClientId(value.client)
63
+ && exactText(value.resolvedAt);
64
+ }
65
+ function isModelPolicy(value) {
66
+ if (!hasExactKeys(value, ['executor', 'reviewer']))
67
+ return false;
68
+ return [value.executor, value.reviewer].every((role) => hasExactKeys(role, ['model', 'reasoningEffort'])
69
+ && exactText(role.model)
70
+ && exactText(role.reasoningEffort));
71
+ }
72
+ const RECOVERY_GUARD_KEYS = [
73
+ 'stepCount', 'nextStage', 'baselineEmpty', 'receiptCount', 'pendingDelegation',
74
+ 'commitAuthorizationUnused', 'completionEvidenceAbsent'
75
+ ];
76
+ function isRecovery(value) {
77
+ if (!hasExactKeys(value, [
78
+ 'code', 'recoveredAt', 'previousStatus', 'previousPause', 'client', 'guards', 'resultingStatus'
79
+ ]))
80
+ return false;
81
+ const guards = value.guards;
82
+ return value.code === 'CLIENT_CAPABILITY_ENABLED'
83
+ && exactText(value.recoveredAt)
84
+ && value.previousStatus === 'paused'
85
+ && isPause(value.previousPause)
86
+ && value.previousPause.code === 'ORCHESTRATION_CLIENT_UNSUPPORTED'
87
+ && value.client === 'claude-code'
88
+ && hasExactKeys(guards, RECOVERY_GUARD_KEYS)
89
+ && guards.stepCount === 0
90
+ && guards.nextStage === null
91
+ && guards.baselineEmpty === true
92
+ && guards.receiptCount === 0
93
+ && guards.pendingDelegation === false
94
+ && guards.commitAuthorizationUnused === true
95
+ && guards.completionEvidenceAbsent === true
96
+ && value.resultingStatus === 'running';
97
+ }
98
+ function isCompletionEvidence(value) {
99
+ return hasExactKeys(value, [
100
+ 'kind', 'observedAt', 'head', 'headTree', 'worktreeTree', 'lastReviewedCommit', 'prNumber', 'prHead'
101
+ ])
102
+ && value.kind === 'reviewed-head-clean'
103
+ && exactText(value.observedAt)
104
+ && exactText(value.head)
105
+ && exactText(value.headTree)
106
+ && exactText(value.worktreeTree)
107
+ && exactText(value.lastReviewedCommit)
108
+ && Number.isSafeInteger(value.prNumber)
109
+ && value.prNumber > 0
110
+ && exactText(value.prHead);
111
+ }
112
+ const ORCHESTRATION_RUN_KEYS = [
113
+ 'taskId', 'runId', 'status', 'nextStage', 'stepCount', 'maxSteps', 'modelPolicy',
114
+ 'modelPolicySource', 'recoveryHistory', 'baseline', 'pendingDelegation', 'receipts',
115
+ 'pause', 'commitAuthorization', 'completionEvidence', 'createdAt', 'updatedAt'
116
+ ];
117
+ function parseOrchestrationRun(value, expectedTaskId) {
118
+ if (!hasExactKeys(value, ORCHESTRATION_RUN_KEYS)
119
+ || !exactText(value.taskId)
120
+ || (expectedTaskId !== undefined && value.taskId !== expectedTaskId)
121
+ || !exactText(value.runId)
122
+ || !['running', 'paused', 'completed'].includes(value.status)
123
+ || !(value.nextStage === null || ['analysis', 'review-analysis', 'plan', 'review-plan', 'code', 'review-code', 'commit'].includes(value.nextStage))
124
+ || !Number.isSafeInteger(value.stepCount) || value.stepCount < 0
125
+ || !Number.isSafeInteger(value.maxSteps) || value.maxSteps < 1
126
+ || !isModelPolicy(value.modelPolicy)
127
+ || !isModelPolicySource(value.modelPolicySource)
128
+ || !Array.isArray(value.recoveryHistory) || !value.recoveryHistory.every(isRecovery)
129
+ || typeof value.baseline !== 'string'
130
+ || !(value.pendingDelegation === null || isDelegationReceipt(value.pendingDelegation))
131
+ || !Array.isArray(value.receipts) || !value.receipts.every(isDelegationReceipt)
132
+ || !(value.pause === null || isPause(value.pause))
133
+ || !hasExactKeys(value.commitAuthorization, ['issuedAt', 'consumedAt'])
134
+ || !nullableText(value.commitAuthorization.issuedAt)
135
+ || !nullableText(value.commitAuthorization.consumedAt)
136
+ || !(value.completionEvidence === null || isCompletionEvidence(value.completionEvidence))
137
+ || !exactText(value.createdAt)
138
+ || !exactText(value.updatedAt)) {
139
+ throw new OrchestrationStateError();
140
+ }
141
+ const receipts = [...value.receipts, ...(value.pendingDelegation ? [value.pendingDelegation] : [])];
142
+ if (receipts.some((receipt) => receipt.taskId !== value.taskId || receipt.runId !== value.runId)) {
143
+ throw new OrchestrationStateError();
144
+ }
145
+ return value;
146
+ }
33
147
  function readRun(taskDir) {
34
148
  const file = orchestrationPath(taskDir);
35
149
  if (!fs.existsSync(file))
36
150
  return null;
37
- const run = JSON.parse(fs.readFileSync(file, 'utf8'));
38
- if (![2, 3].includes(run.schemaVersion) || !isV2Policy(run.modelPolicy))
39
- return run;
40
- return {
41
- ...run,
42
- modelPolicy: {
43
- executor: {
44
- model: run.modelPolicy.executor.model,
45
- reasoningEffort: run.modelPolicy.executor.reasoningEffort
46
- },
47
- reviewer: {
48
- model: run.modelPolicy.reviewer.model,
49
- reasoningEffort: run.modelPolicy.reviewer.reasoningEffort
50
- }
51
- }
52
- };
151
+ const taskId = path.basename(taskDir);
152
+ try {
153
+ return parseOrchestrationRun(JSON.parse(fs.readFileSync(file, 'utf8')), taskId);
154
+ }
155
+ catch (error) {
156
+ if (error instanceof OrchestrationStateError)
157
+ throw new OrchestrationStateError(taskId);
158
+ throw new OrchestrationStateError(taskId);
159
+ }
53
160
  }
54
161
  function atomicWrite(file, value) {
55
162
  const temp = `${file}.${process.pid}.${randomUUID()}.tmp`;
@@ -65,70 +172,11 @@ function withUpdatedRun(run, updates, now) {
65
172
  function failed(code, message, taskId = null, details = {}) {
66
173
  return { status: 'failed', changed: false, taskId, run: null, next: null, error: { code, message, ...details } };
67
174
  }
68
- function commitIntentFailed(code, message, taskId = null) {
69
- return { status: 'failed', changed: false, taskId, intent: null, error: { code, message } };
70
- }
71
- function repositoryHead(repoRoot) {
72
- return execFileSync('git', ['rev-parse', 'HEAD'], {
73
- cwd: repoRoot,
74
- encoding: 'utf8',
75
- stdio: ['ignore', 'pipe', 'pipe']
76
- }).trim();
77
- }
78
175
  function gitRootFor(stateRoot, options) {
79
176
  if (!options.gitWorktreeRoot)
80
177
  return stateRoot;
81
178
  return assertGitRepositoryBinding(stateRoot, options.gitWorktreeRoot).worktreeRoot;
82
179
  }
83
- function isAncestor(repoRoot, ancestor, descendant) {
84
- return spawnSync('git', ['merge-base', '--is-ancestor', ancestor, descendant], {
85
- cwd: repoRoot,
86
- stdio: 'ignore'
87
- }).status === 0;
88
- }
89
- function commitIntentView(intent, currentHead) {
90
- return {
91
- mode: intent.mode,
92
- phase: intent.phase,
93
- baselineHead: intent.baselineHead,
94
- currentHead,
95
- committedHead: intent.committedHead,
96
- pushEvidence: intent.pushEvidence,
97
- runId: intent.orchestration?.runId ?? null,
98
- receiptId: intent.orchestration?.receiptId ?? null
99
- };
100
- }
101
- function commitFinalizationView(inspection) {
102
- return {
103
- disposition: inspection.disposition,
104
- code: inspection.code,
105
- message: inspection.message,
106
- currentHead: inspection.currentHead,
107
- committedHead: inspection.committedHead,
108
- needsAnchor: inspection.needsAnchor,
109
- needsLog: inspection.needsLog,
110
- attempt: inspection.attempt
111
- };
112
- }
113
- function validCommitRun(run, taskId) {
114
- return run !== null
115
- && [1, 2, 3].includes(run.schemaVersion)
116
- && run.taskId === taskId
117
- && ['running', 'paused', 'completed'].includes(run.status)
118
- && Array.isArray(run.receipts)
119
- && Object.prototype.hasOwnProperty.call(run, 'pendingDelegation')
120
- && typeof run.commitAuthorization === 'object'
121
- && run.commitAuthorization !== null
122
- && Object.prototype.hasOwnProperty.call(run.commitAuthorization, 'issuedAt')
123
- && Object.prototype.hasOwnProperty.call(run.commitAuthorization, 'consumedAt');
124
- }
125
- function mapCommitIntentError(error, taskId) {
126
- if (error instanceof CommitIntentError)
127
- return commitIntentFailed(error.code, error.message, taskId);
128
- if (error instanceof TaskExecutionLockError)
129
- return commitIntentFailed(error.code, error.message, taskId);
130
- return commitIntentFailed('ORCHESTRATION_COMMIT_INTENT_INVALID', error instanceof Error ? error.message : String(error), taskId);
131
- }
132
180
  function validModel(value) {
133
181
  return typeof value === 'string' && value.length > 0 && value.trim() === value;
134
182
  }
@@ -148,11 +196,8 @@ function sameModelPolicy(left, right) {
148
196
  && left.reviewer.model === right.reviewer.model
149
197
  && left.reviewer.reasoningEffort === right.reviewer.reasoningEffort;
150
198
  }
151
- function isV2Policy(policy) {
152
- return typeof policy?.executor === 'object' && typeof policy?.reviewer === 'object';
153
- }
154
199
  function rolePolicy(run, role) {
155
- return isV2Policy(run.modelPolicy) ? run.modelPolicy[role] : null;
200
+ return run.modelPolicy[role];
156
201
  }
157
202
  function resolveProjectPolicy(repoRoot, client) {
158
203
  const configPath = path.join(repoRoot, '.agents', '.airc.json');
@@ -161,25 +206,8 @@ function resolveProjectPolicy(repoRoot, client) {
161
206
  const raw = JSON.parse(fs.readFileSync(configPath, 'utf8'));
162
207
  return normalizeAgentClients(raw).state[client].orchestration;
163
208
  }
164
- function canRecoverCodexUnsupportedPause(run, taskDir) {
165
- return run.schemaVersion === 2
166
- && run.status === 'paused'
167
- && run.pause?.code === 'ORCHESTRATION_CLIENT_UNSUPPORTED'
168
- && run.modelPolicySource?.client === 'codex'
169
- && run.stepCount === 0
170
- && run.nextStage === null
171
- && run.baseline === ''
172
- && run.pendingDelegation === null
173
- && run.receipts.length === 0
174
- && run.commitAuthorization?.issuedAt === null
175
- && run.commitAuthorization?.consumedAt === null
176
- && run.completionEvidence == null
177
- && !fs.existsSync(commitIntentPath(taskDir))
178
- && (run.recoveryHistory ?? []).every((entry) => entry.code === 'MODEL_POLICY_SUPPLEMENTED');
179
- }
180
209
  function canRecoverClaudeCodeUnsupportedPause(run, taskDir) {
181
- return run.schemaVersion === 3
182
- && run.status === 'paused'
210
+ return run.status === 'paused'
183
211
  && run.pause?.code === 'ORCHESTRATION_CLIENT_UNSUPPORTED'
184
212
  && run.modelPolicySource?.client === 'claude-code'
185
213
  && run.stepCount === 0
@@ -190,22 +218,7 @@ function canRecoverClaudeCodeUnsupportedPause(run, taskDir) {
190
218
  && run.commitAuthorization?.issuedAt === null
191
219
  && run.commitAuthorization?.consumedAt === null
192
220
  && run.completionEvidence == null
193
- && !fs.existsSync(commitIntentPath(taskDir))
194
- && (run.recoveryHistory ?? []).length === 0;
195
- }
196
- function canMigrateRecoverableV2Pause(run, taskDir) {
197
- return run.schemaVersion === 2
198
- && run.status === 'paused'
199
- && run.pause?.recoverable === true
200
- && run.stepCount === 0
201
- && run.nextStage === null
202
- && run.baseline === ''
203
- && run.pendingDelegation === null
204
- && run.receipts.length === 0
205
- && run.commitAuthorization?.issuedAt === null
206
- && run.commitAuthorization?.consumedAt === null
207
- && run.completionEvidence == null
208
- && !fs.existsSync(commitIntentPath(taskDir));
221
+ && run.recoveryHistory.length === 0;
209
222
  }
210
223
  function beginOrResumeOrchestration(taskRef, options = {}) {
211
224
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
@@ -222,226 +235,57 @@ function beginOrResumeOrchestration(taskRef, options = {}) {
222
235
  return failed('ORCHESTRATION_STATE_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
223
236
  }
224
237
  if (existing) {
225
- if (![1, 2, 3].includes(existing.schemaVersion)
226
- || !Array.isArray(existing.receipts)
227
- || !Object.prototype.hasOwnProperty.call(existing, 'pendingDelegation')) {
228
- return failed('ORCHESTRATION_STATE_INVALID', 'orchestration state has an invalid schema', resolved.taskId);
229
- }
230
- if (existing.status === 'completed' && existing.schemaVersion === 1) {
238
+ if (existing.status === 'completed') {
231
239
  return { status: 'completed', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
232
240
  }
233
- if (existing.schemaVersion === 2 || existing.schemaVersion === 3) {
234
- const policyError = validateModelPolicy(isV2Policy(existing.modelPolicy) ? existing.modelPolicy : undefined);
235
- if (policyError
236
- || !existing.modelPolicySource
237
- || !isAgentClientId(existing.modelPolicySource.client)
238
- || !Array.isArray(existing.recoveryHistory)) {
239
- return failed('ORCHESTRATION_STATE_INVALID', `schemaVersion ${existing.schemaVersion} orchestration state is incomplete`, resolved.taskId);
240
- }
241
- if (existing.status === 'completed') {
242
- return { status: 'completed', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
243
- }
244
- if (existing.schemaVersion === 2 && existing.status === 'running') {
245
- return failed('ORCHESTRATION_STATE_INVALID', 'active schemaVersion 2 runs cannot be advanced by lifecycle protocol v3', resolved.taskId);
246
- }
247
- if (existing.modelPolicySource.client !== options.client) {
248
- return failed('ORCHESTRATION_CLIENT_MISMATCH', 'provided client does not match the persisted run policy source', resolved.taskId);
249
- }
250
- if (options.modelPolicy) {
251
- const suppliedError = validateModelPolicy(options.modelPolicy);
252
- if (suppliedError)
253
- return failed(suppliedError.code, suppliedError.message, resolved.taskId);
254
- if (!sameModelPolicy(existing.modelPolicy, options.modelPolicy)) {
255
- return failed('ORCHESTRATION_MODEL_POLICY_MISMATCH', 'provided model policy does not match the persisted run policy', resolved.taskId);
256
- }
257
- }
258
- if (existing.status === 'paused' && existing.pause?.code === 'ORCHESTRATION_CLIENT_UNSUPPORTED') {
259
- if (existing.modelPolicySource.client === 'claude-code') {
260
- if (!canRecoverClaudeCodeUnsupportedPause(existing, resolved.taskDir)) {
261
- return { status: 'paused', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
262
- }
263
- const now = (options.now ?? (() => new Date().toISOString()))();
264
- const previousPause = existing.pause;
265
- const recovery = {
266
- code: 'CLIENT_CAPABILITY_ENABLED_NO_MIGRATION',
267
- recoveredAt: now,
268
- previousSchemaVersion: 3,
269
- previousStatus: 'paused',
270
- previousPause,
271
- client: 'claude-code',
272
- guards: {
273
- stepCount: 0,
274
- nextStage: null,
275
- baselineEmpty: true,
276
- receiptCount: 0,
277
- pendingDelegation: false,
278
- commitAuthorizationUnused: true,
279
- completionEvidenceAbsent: true,
280
- commitIntentAbsent: true
281
- },
282
- resultingStatus: 'running'
283
- };
284
- const resumed = withUpdatedRun(existing, {
285
- status: 'running',
286
- pause: null,
287
- recoveryHistory: Object.freeze([...(existing.recoveryHistory ?? []), recovery])
288
- }, () => now);
289
- saveRun(resolved.taskDir, resumed);
290
- return { status: 'running', changed: true, taskId: resolved.taskId, run: resumed, next: null, error: null };
291
- }
292
- if (!canRecoverCodexUnsupportedPause(existing, resolved.taskDir)) {
293
- return { status: 'paused', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
294
- }
295
- const now = (options.now ?? (() => new Date().toISOString()))();
296
- const previousPause = existing.pause;
297
- const recovery = {
298
- code: 'CLIENT_CAPABILITY_ENABLED',
299
- recoveredAt: now,
300
- previousSchemaVersion: 2,
301
- previousStatus: 'paused',
302
- previousPause,
303
- client: 'codex',
304
- guards: {
305
- stepCount: 0,
306
- nextStage: null,
307
- baselineEmpty: true,
308
- receiptCount: 0,
309
- pendingDelegation: false,
310
- commitAuthorizationUnused: true,
311
- completionEvidenceAbsent: true,
312
- commitIntentAbsent: true
313
- },
314
- resultingStatus: 'running'
315
- };
316
- const resumed = withUpdatedRun(existing, {
317
- schemaVersion: 3,
318
- status: 'running',
319
- pause: null,
320
- recoveryHistory: Object.freeze([...(existing.recoveryHistory ?? []), recovery])
321
- }, () => now);
322
- saveRun(resolved.taskDir, resumed);
323
- return { status: 'running', changed: true, taskId: resolved.taskId, run: resumed, next: null, error: null };
324
- }
325
- if (existing.status === 'paused' && existing.pause?.recoverable && existing.pendingDelegation === null) {
326
- if (existing.schemaVersion === 2 && !canMigrateRecoverableV2Pause(existing, resolved.taskDir)) {
327
- const paused = withUpdatedRun(existing, {
328
- pause: {
329
- code: 'ORCHESTRATION_SCHEMA_MIGRATION_REQUIRED',
330
- message: 'schemaVersion 2 recoverable pause contains execution evidence and cannot migrate automatically',
331
- recoverable: false
332
- }
333
- });
334
- saveRun(resolved.taskDir, paused);
335
- return { status: 'paused', changed: true, taskId: resolved.taskId, run: paused, next: null, error: null };
336
- }
337
- const now = (options.now ?? (() => new Date().toISOString()))();
338
- const recovery = existing.schemaVersion === 2 ? {
339
- code: 'SCHEMA_V3_MIGRATED',
340
- recoveredAt: now,
341
- previousSchemaVersion: 2,
342
- previousStatus: 'paused',
343
- previousPause: existing.pause,
344
- guards: {
345
- stepCount: 0,
346
- nextStage: null,
347
- baselineEmpty: true,
348
- receiptCount: 0,
349
- pendingDelegation: false,
350
- commitAuthorizationUnused: true,
351
- completionEvidenceAbsent: true,
352
- commitIntentAbsent: true
353
- },
354
- resultingStatus: 'running'
355
- } : null;
356
- const resumed = withUpdatedRun(existing, {
357
- schemaVersion: 3,
358
- status: 'running',
359
- pause: null,
360
- ...(recovery ? { recoveryHistory: Object.freeze([...(existing.recoveryHistory ?? []), recovery]) } : {})
361
- }, () => now);
362
- saveRun(resolved.taskDir, resumed);
363
- return { status: 'running', changed: true, taskId: resolved.taskId, run: resumed, next: null, error: null };
364
- }
365
- return { status: existing.status, changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
241
+ if (existing.modelPolicySource.client !== options.client) {
242
+ return failed('ORCHESTRATION_CLIENT_MISMATCH', 'provided client does not match the persisted run policy source', resolved.taskId);
366
243
  }
367
- let policy = options.modelPolicy;
368
- let sourceKind = 'explicit';
369
- if (!policy) {
370
- try {
371
- policy = resolveProjectPolicy(resolved.repoRoot, options.client);
372
- sourceKind = 'project-config';
373
- }
374
- catch (error) {
375
- return failed('ORCHESTRATION_CONFIG_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
244
+ if (options.modelPolicy) {
245
+ const suppliedError = validateModelPolicy(options.modelPolicy);
246
+ if (suppliedError)
247
+ return failed(suppliedError.code, suppliedError.message, resolved.taskId);
248
+ if (!sameModelPolicy(existing.modelPolicy, options.modelPolicy)) {
249
+ return failed('ORCHESTRATION_MODEL_POLICY_MISMATCH', 'provided model policy does not match the persisted run policy', resolved.taskId);
376
250
  }
377
251
  }
378
- const policyError = validateModelPolicy(policy);
379
- if (policyError) {
380
- return failed(policyError.code, policyError.message, resolved.taskId, {
381
- client: options.client,
382
- missingFields: ['executor.model', 'executor.reasoningEffort', 'reviewer.model', 'reviewer.reasoningEffort'],
383
- modelSelectionContext: getAgentClientModelSelection(options.client)
384
- });
385
- }
386
- if (existing.pendingDelegation !== null) {
387
- const alreadyPaused = existing.status === 'paused' && existing.pause?.code === 'ORCHESTRATION_DELEGATION_BUSY';
388
- if (alreadyPaused)
252
+ if (existing.status === 'paused' && existing.pause?.code === 'ORCHESTRATION_CLIENT_UNSUPPORTED') {
253
+ if (existing.modelPolicySource.client !== 'claude-code'
254
+ || !canRecoverClaudeCodeUnsupportedPause(existing, resolved.taskDir)) {
389
255
  return { status: 'paused', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
390
- const paused = withUpdatedRun(existing, {
391
- status: 'paused',
392
- pause: { code: 'ORCHESTRATION_DELEGATION_BUSY', message: 'legacy run has a pending delegation', recoverable: false }
393
- });
394
- saveRun(resolved.taskDir, paused);
395
- return { status: 'paused', changed: true, taskId: resolved.taskId, run: paused, next: null, error: null };
396
- }
397
- if (existing.receipts.length > 0) {
398
- const alreadyPaused = existing.status === 'paused' && existing.pause?.code === 'ORCHESTRATION_HISTORICAL_EFFORT_UNVERIFIED';
399
- if (alreadyPaused)
400
- return { status: 'paused', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
401
- const paused = withUpdatedRun(existing, {
402
- status: 'paused',
403
- pause: {
404
- code: 'ORCHESTRATION_HISTORICAL_EFFORT_UNVERIFIED',
405
- message: 'legacy receipts do not contain actual reasoning-effort evidence',
406
- recoverable: false
407
- }
408
- });
409
- saveRun(resolved.taskDir, paused);
410
- return { status: 'paused', changed: true, taskId: resolved.taskId, run: paused, next: null, error: null };
256
+ }
257
+ const now = (options.now ?? (() => new Date().toISOString()))();
258
+ const recovery = {
259
+ code: 'CLIENT_CAPABILITY_ENABLED',
260
+ recoveredAt: now,
261
+ previousStatus: 'paused',
262
+ previousPause: existing.pause,
263
+ client: 'claude-code',
264
+ guards: {
265
+ stepCount: 0,
266
+ nextStage: null,
267
+ baselineEmpty: true,
268
+ receiptCount: 0,
269
+ pendingDelegation: false,
270
+ commitAuthorizationUnused: true,
271
+ completionEvidenceAbsent: true
272
+ },
273
+ resultingStatus: 'running'
274
+ };
275
+ const resumed = withUpdatedRun(existing, {
276
+ status: 'running',
277
+ pause: null,
278
+ recoveryHistory: Object.freeze([...existing.recoveryHistory, recovery])
279
+ }, () => now);
280
+ saveRun(resolved.taskDir, resumed);
281
+ return { status: 'running', changed: true, taskId: resolved.taskId, run: resumed, next: null, error: null };
411
282
  }
412
- if (existing.modelPolicy
413
- && typeof existing.modelPolicy.executor === 'string'
414
- && (existing.modelPolicy.executor !== policy.executor.model
415
- || existing.modelPolicy.reviewer !== policy.reviewer.model)) {
416
- return failed('ORCHESTRATION_MODEL_POLICY_MISMATCH', 'provided model policy does not match the persisted run policy', resolved.taskId);
283
+ if (existing.status === 'paused' && existing.pause?.recoverable && existing.pendingDelegation === null) {
284
+ const resumed = withUpdatedRun(existing, { status: 'running', pause: null }, options.now);
285
+ saveRun(resolved.taskDir, resumed);
286
+ return { status: 'running', changed: true, taskId: resolved.taskId, run: resumed, next: null, error: null };
417
287
  }
418
- const now = (options.now ?? (() => new Date().toISOString()))();
419
- const source = { kind: sourceKind, client: options.client, resolvedAt: now };
420
- const clearsModelPause = existing.pause?.code === 'ORCHESTRATION_MODEL_EVIDENCE_MISSING';
421
- const resultingStatus = clearsModelPause ? 'running' : existing.status;
422
- const recovery = {
423
- code: 'MODEL_POLICY_SUPPLEMENTED',
424
- recoveredAt: now,
425
- previousSchemaVersion: 1,
426
- previousStatus: existing.status,
427
- previousPause: existing.pause,
428
- policySource: source,
429
- receiptCount: 0,
430
- pendingDelegation: false,
431
- resultingStatus
432
- };
433
- const recovered = Object.freeze({
434
- ...existing,
435
- schemaVersion: 3,
436
- status: resultingStatus,
437
- modelPolicy: policy,
438
- modelPolicySource: source,
439
- recoveryHistory: Object.freeze([recovery]),
440
- pause: clearsModelPause ? null : existing.pause,
441
- updatedAt: now
442
- });
443
- saveRun(resolved.taskDir, recovered);
444
- return { status: resultingStatus, changed: true, taskId: resolved.taskId, run: recovered, next: null, error: null };
288
+ return { status: existing.status, changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
445
289
  }
446
290
  let policy = options.modelPolicy;
447
291
  let sourceKind = 'explicit';
@@ -464,7 +308,6 @@ function beginOrResumeOrchestration(taskRef, options = {}) {
464
308
  const now = (options.now ?? (() => new Date().toISOString()))();
465
309
  const source = { kind: sourceKind, client: options.client, resolvedAt: now };
466
310
  const run = {
467
- schemaVersion: 3,
468
311
  taskId: resolved.taskId,
469
312
  runId: (options.id ?? randomUUID)(),
470
313
  status: 'running',
@@ -706,401 +549,6 @@ function routeOrchestration(taskRef, options = {}) {
706
549
  }
707
550
  return { status: 'running', changed: false, taskId: resolved.taskId, run, next, error: null };
708
551
  }
709
- function appendCommitActivity(resolved, step, agent, note) {
710
- const taskContent = fs.readFileSync(resolved.taskMdPath, 'utf8');
711
- const activity = locateActivityLog(taskContent);
712
- if (!activity)
713
- return { code: 'ORCHESTRATION_TASK_INVALID', message: 'task activity log is missing or ambiguous' };
714
- const metadata = captureTaskWriteMetadata();
715
- const written = writeTask({
716
- taskRef: resolved.taskId,
717
- expectedState: 'active',
718
- mutations: [{
719
- kind: 'section',
720
- aliases: ['活动日志', 'Activity Log'],
721
- heading: activity.heading,
722
- body: appendActivityEntry(activity, { time: metadata.timestamp, step, agent, note })
723
- }]
724
- }, { repoRoot: resolved.repoRoot, metadataProvider: () => metadata });
725
- return written.status === 'failed' ? written.error : null;
726
- }
727
- function startCommitAttempt(taskRef, input, options = {}) {
728
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
729
- if (!resolved.ok)
730
- return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
731
- try {
732
- const gitRoot = gitRootFor(resolved.repoRoot, options);
733
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-attempt.start', () => {
734
- if (fs.existsSync(commitIntentPath(resolved.taskDir))) {
735
- return commitIntentFailed('ORCHESTRATION_COMMIT_INTENT_BUSY', 'an active commit intent already exists', resolved.taskId);
736
- }
737
- const taskContent = fs.readFileSync(resolved.taskMdPath, 'utf8');
738
- const activity = locateActivityLog(taskContent);
739
- if (!activity)
740
- return commitIntentFailed('ORCHESTRATION_TASK_INVALID', 'task activity log is missing or ambiguous', resolved.taskId);
741
- const open = pairEntries(activity.entries).filter((row) => row.step === 'Commit' && row.started !== '' && row.done === '');
742
- if (open.length > 0) {
743
- return commitIntentFailed('ORCHESTRATION_COMMIT_ATTEMPT_BUSY', 'an open Commit activity entry already exists', resolved.taskId);
744
- }
745
- const currentHead = repositoryHead(gitRoot);
746
- const attempt = (options.id ?? randomUUID)();
747
- const error = appendCommitActivity(resolved, 'Commit [started]', input.agent, commitAttemptStartedNote({
748
- attempt,
749
- baseline: currentHead,
750
- agent: input.agent
751
- }));
752
- if (error)
753
- return commitIntentFailed(error.code, error.message, resolved.taskId);
754
- const inspection = inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId);
755
- return {
756
- status: 'ready', changed: true, taskId: resolved.taskId, intent: null,
757
- finalization: commitFinalizationView(inspection), error: null
758
- };
759
- });
760
- }
761
- catch (error) {
762
- return mapCommitIntentError(error, resolved.taskId);
763
- }
764
- }
765
- function terminateCommitAttempt(taskRef, input, options = {}) {
766
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
767
- if (!resolved.ok)
768
- return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
769
- try {
770
- const gitRoot = gitRootFor(resolved.repoRoot, options);
771
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-attempt.terminate', () => {
772
- if (fs.existsSync(commitIntentPath(resolved.taskDir))) {
773
- return commitIntentFailed('ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', 'an active commit intent must be aborted or recovered first', resolved.taskId);
774
- }
775
- const inspection = inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId);
776
- if (inspection.disposition !== 'retryable-start'
777
- || inspection.attempt?.attempt !== input.attempt
778
- || inspection.attempt.agent !== input.agent
779
- || inspection.attempt.baseline !== inspection.currentHead) {
780
- return commitIntentFailed('ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', 'commit attempt identity or repository HEAD has drifted', resolved.taskId);
781
- }
782
- const error = appendCommitActivity(resolved, 'Commit [aborted]', input.agent, `aborted; attempt=${input.attempt}; code=${input.code}`);
783
- if (error)
784
- return commitIntentFailed(error.code, error.message, resolved.taskId);
785
- return {
786
- status: 'ready', changed: true, taskId: resolved.taskId, intent: null,
787
- finalization: commitFinalizationView(inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId)),
788
- error: null
789
- };
790
- });
791
- }
792
- catch (error) {
793
- return mapCommitIntentError(error, resolved.taskId);
794
- }
795
- }
796
- function beginCommitIntent(taskRef, input, options = {}) {
797
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
798
- if (!resolved.ok)
799
- return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
800
- try {
801
- const gitRoot = gitRootFor(resolved.repoRoot, options);
802
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-intent.begin', () => {
803
- const currentHead = repositoryHead(gitRoot);
804
- if (currentHead !== input.baselineHead) {
805
- return commitIntentFailed('ORCHESTRATION_COMMIT_BASELINE_MISMATCH', 'baseline HEAD does not match the repository HEAD', resolved.taskId);
806
- }
807
- if (fs.existsSync(commitIntentPath(resolved.taskDir))) {
808
- try {
809
- readCommitIntent(resolved.taskDir, resolved.taskId);
810
- }
811
- catch (error) {
812
- return mapCommitIntentError(error, resolved.taskId);
813
- }
814
- return commitIntentFailed('ORCHESTRATION_COMMIT_INTENT_BUSY', 'an active commit intent already exists', resolved.taskId);
815
- }
816
- const attemptInspection = inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId);
817
- if (attemptInspection.disposition !== 'retryable-start'
818
- || attemptInspection.attempt?.attempt !== input.attempt
819
- || attemptInspection.attempt.agent !== input.agent
820
- || attemptInspection.attempt.baseline !== input.baselineHead) {
821
- return commitIntentFailed('ORCHESTRATION_COMMIT_ATTEMPT_MISMATCH', 'commit begin requires one matching retryable Commit attempt', resolved.taskId);
822
- }
823
- const runFile = orchestrationPath(resolved.taskDir);
824
- let run = null;
825
- let sourceRunBytes = null;
826
- if (fs.existsSync(runFile)) {
827
- sourceRunBytes = fs.readFileSync(runFile, 'utf8');
828
- try {
829
- run = readRun(resolved.taskDir);
830
- }
831
- catch (error) {
832
- return commitIntentFailed('ORCHESTRATION_STATE_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
833
- }
834
- if (!validCommitRun(run, resolved.taskId)) {
835
- return commitIntentFailed('ORCHESTRATION_STATE_INVALID', 'orchestration state has an invalid schema', resolved.taskId);
836
- }
837
- }
838
- const now = (options.now ?? (() => new Date().toISOString()))();
839
- const failAndPause = (code, message) => {
840
- if (run?.status === 'running') {
841
- saveRun(resolved.taskDir, withUpdatedRun(run, {
842
- status: 'paused', pause: { code, message, recoverable: true }
843
- }, () => now));
844
- }
845
- return commitIntentFailed(code, message, resolved.taskId);
846
- };
847
- let orchestration = null;
848
- if (!input.orchestrated) {
849
- if (run?.pendingDelegation) {
850
- return commitIntentFailed('ORCHESTRATION_STANDALONE_BUSY', 'standalone commit is blocked by a pending orchestration delegation', resolved.taskId);
851
- }
852
- }
853
- else {
854
- if (!run || run.status !== 'running') {
855
- return commitIntentFailed('ORCHESTRATION_RUN_NOT_RUNNING', 'orchestrated commit requires a running orchestration', resolved.taskId);
856
- }
857
- const receipt = run.pendingDelegation;
858
- if (!receipt
859
- || receipt.status !== 'activated'
860
- || receipt.stage !== 'commit'
861
- || receipt.round !== 1
862
- || receipt.artifact !== 'commit'
863
- || receipt.role !== 'executor') {
864
- return failAndPause('ORCHESTRATION_PROVENANCE_MISMATCH', 'orchestrated commit requires one matching activated commit delegation');
865
- }
866
- if (!run.commitAuthorization.issuedAt || run.commitAuthorization.consumedAt) {
867
- return failAndPause('ORCHESTRATION_COMMIT_AUTHORIZATION_INVALID', 'orchestrated commit requires an unconsumed one-use authorization');
868
- }
869
- const planned = planOrchestrationStageCompletion(taskRef, {
870
- stage: 'commit', round: 1, artifact: 'commit', role: 'executor', agent: input.agent
871
- }, { ...options, now: () => now });
872
- if (planned.result.status === 'failed' || !planned.plan?.updatedRun.pendingDelegation) {
873
- return failAndPause(planned.result.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH', planned.result.error?.message ?? 'commit delegation could not be completed');
874
- }
875
- const plannedRunBytes = serialize(planned.plan.updatedRun);
876
- orchestration = {
877
- runId: run.runId,
878
- receiptId: receipt.id,
879
- authorizationIssuedAt: run.commitAuthorization.issuedAt,
880
- sourceRunDigest: digest(sourceRunBytes),
881
- plannedRunDigest: digest(plannedRunBytes),
882
- completionUpdatedAt: planned.plan.updatedRun.updatedAt,
883
- plannedReceipt: planned.plan.updatedRun.pendingDelegation
884
- };
885
- }
886
- const created = createCommitIntent(resolved.taskDir, {
887
- taskId: resolved.taskId,
888
- mode: input.orchestrated ? 'orchestrated' : 'standalone',
889
- phase: 'prepared',
890
- baselineHead: input.baselineHead,
891
- committedHead: null,
892
- pushEvidence: null,
893
- orchestration,
894
- createdAt: now,
895
- updatedAt: now
896
- }, { token: options.token });
897
- return {
898
- status: 'ready', changed: true, taskId: resolved.taskId,
899
- intent: commitIntentView(created.intent, currentHead), token: created.token, error: null
900
- };
901
- });
902
- }
903
- catch (error) {
904
- return mapCommitIntentError(error, resolved.taskId);
905
- }
906
- }
907
- function checkpointCommitIntent(taskRef, input, options = {}) {
908
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
909
- if (!resolved.ok)
910
- return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
911
- try {
912
- const gitRoot = gitRootFor(resolved.repoRoot, options);
913
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-intent.checkpoint', () => {
914
- const intent = readCommitIntent(resolved.taskDir, resolved.taskId, input.token);
915
- const currentHead = repositoryHead(gitRoot);
916
- if (currentHead !== input.head) {
917
- return commitIntentFailed('ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', 'checkpoint HEAD does not match the repository HEAD', resolved.taskId);
918
- }
919
- if (input.kind === 'committed' && !isAncestor(gitRoot, intent.baselineHead, input.head)) {
920
- return commitIntentFailed('ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', 'committed HEAD does not descend from the baseline', resolved.taskId);
921
- }
922
- if (input.kind === 'pushed') {
923
- const expectedHead = intent.committedHead ?? intent.baselineHead;
924
- if (input.head !== expectedHead || !input.remote || !input.ref) {
925
- return commitIntentFailed('ORCHESTRATION_COMMIT_INTENT_STATE_INVALID', 'pushed checkpoint requires matching remote, ref and HEAD', resolved.taskId);
926
- }
927
- }
928
- const now = (options.now ?? (() => new Date().toISOString()))();
929
- const updated = updateCommitIntent(resolved.taskDir, resolved.taskId, input.token, input.kind === 'committed'
930
- ? { phase: 'committed', committedHead: input.head, updatedAt: now }
931
- : {
932
- phase: 'pushed', committedHead: intent.committedHead ?? intent.baselineHead, updatedAt: now,
933
- pushEvidence: { remote: input.remote, ref: input.ref, head: input.head }
934
- });
935
- return {
936
- status: 'ready', changed: true, taskId: resolved.taskId,
937
- intent: commitIntentView(updated, currentHead), error: null
938
- };
939
- });
940
- }
941
- catch (error) {
942
- return mapCommitIntentError(error, resolved.taskId);
943
- }
944
- }
945
- function completeCommitOrchestration(resolved, intent, agent) {
946
- if (intent.orchestration === null)
947
- return null;
948
- if (intent.orchestration.plannedReceipt.agent !== agent) {
949
- return { code: 'ORCHESTRATION_PROVENANCE_MISMATCH', message: 'completion agent does not match the planned receipt' };
950
- }
951
- const runFile = orchestrationPath(resolved.taskDir);
952
- if (!fs.existsSync(runFile)) {
953
- return { code: 'ORCHESTRATION_RUN_MISSING', message: 'orchestration run disappeared' };
954
- }
955
- const currentBytes = fs.readFileSync(runFile, 'utf8');
956
- const currentDigest = digest(currentBytes);
957
- if (currentDigest === intent.orchestration.sourceRunDigest) {
958
- const run = readRun(resolved.taskDir);
959
- if (!run)
960
- return { code: 'ORCHESTRATION_RUN_MISSING', message: 'orchestration run disappeared' };
961
- const plannedRun = Object.freeze({
962
- ...run,
963
- pendingDelegation: intent.orchestration.plannedReceipt,
964
- updatedAt: intent.orchestration.completionUpdatedAt
965
- });
966
- if (digest(serialize(plannedRun)) !== intent.orchestration.plannedRunDigest) {
967
- return { code: 'ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', message: 'planned orchestration bytes no longer match the intent' };
968
- }
969
- atomicWrite(runFile, plannedRun);
970
- if (digest(fs.readFileSync(runFile)) !== intent.orchestration.plannedRunDigest) {
971
- return { code: 'ORCHESTRATION_COMMIT_COMPLETE_PARTIAL', message: 'orchestration completion could not be verified' };
972
- }
973
- }
974
- else if (currentDigest !== intent.orchestration.plannedRunDigest) {
975
- return { code: 'ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', message: 'orchestration state changed after commit begin' };
976
- }
977
- return null;
978
- }
979
- function finalizeCommitIntentUnlocked(resolved, inspection, agent, remove) {
980
- if (inspection.disposition !== 'recoverable' || !inspection.intent) {
981
- return commitIntentFailed(inspection.code ?? 'COMMIT_FINALIZATION_PENDING', inspection.message, resolved.taskId);
982
- }
983
- if (inspection.intent.orchestration !== null
984
- && inspection.intent.orchestration.plannedReceipt.agent !== agent) {
985
- return commitIntentFailed('ORCHESTRATION_PROVENANCE_MISMATCH', 'completion agent does not match the planned receipt', resolved.taskId);
986
- }
987
- const metadata = captureTaskWriteMetadata();
988
- const taskPlan = planCommitTaskFinalization(resolved.taskDir, inspection, agent, metadata.timestamp);
989
- const written = writeTask({
990
- taskRef: resolved.taskId,
991
- expectedState: 'active',
992
- mutations: taskPlan.mutations
993
- }, {
994
- repoRoot: resolved.repoRoot,
995
- metadataProvider: () => metadata
996
- });
997
- if (written.status === 'failed') {
998
- return commitIntentFailed(written.error.code, written.error.message, resolved.taskId);
999
- }
1000
- const orchestrationError = completeCommitOrchestration(resolved, inspection.intent, agent);
1001
- if (orchestrationError) {
1002
- return commitIntentFailed(orchestrationError.code, orchestrationError.message, resolved.taskId);
1003
- }
1004
- try {
1005
- remove();
1006
- }
1007
- catch (error) {
1008
- return commitIntentFailed('ORCHESTRATION_COMMIT_COMPLETE_PARTIAL', error instanceof Error ? error.message : String(error), resolved.taskId);
1009
- }
1010
- return { status: 'ready', changed: true, taskId: resolved.taskId, intent: null, error: null };
1011
- }
1012
- function completeCommitIntent(taskRef, input, options = {}) {
1013
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1014
- if (!resolved.ok)
1015
- return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
1016
- try {
1017
- const gitRoot = gitRootFor(resolved.repoRoot, options);
1018
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-intent.complete', () => {
1019
- readCommitIntent(resolved.taskDir, resolved.taskId, input.token);
1020
- const inspection = inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId);
1021
- return finalizeCommitIntentUnlocked(resolved, inspection, input.agent, () => {
1022
- removeCommitIntent(resolved.taskDir, resolved.taskId, input.token);
1023
- });
1024
- });
1025
- }
1026
- catch (error) {
1027
- return mapCommitIntentError(error, resolved.taskId);
1028
- }
1029
- }
1030
- function recoverCommitIntent(taskRef, input, options = {}) {
1031
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1032
- if (!resolved.ok)
1033
- return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
1034
- try {
1035
- const gitRoot = gitRootFor(resolved.repoRoot, options);
1036
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-intent.recover', () => {
1037
- const inspection = inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId);
1038
- if (inspection.disposition === 'retryable-start') {
1039
- return {
1040
- status: 'ready', changed: false, taskId: resolved.taskId, intent: null,
1041
- finalization: commitFinalizationView(inspection), error: null
1042
- };
1043
- }
1044
- if (inspection.disposition === 'prepared' && inspection.intentDigest) {
1045
- removeCommitIntentByDigest(resolved.taskDir, resolved.taskId, inspection.intentDigest);
1046
- return { status: 'ready', changed: true, taskId: resolved.taskId, intent: null, error: null };
1047
- }
1048
- if (!inspection.intentDigest) {
1049
- return commitIntentFailed(inspection.code ?? 'COMMIT_FINALIZATION_EVIDENCE_MISSING', inspection.message, resolved.taskId);
1050
- }
1051
- return finalizeCommitIntentUnlocked(resolved, inspection, input.agent, () => {
1052
- removeCommitIntentByDigest(resolved.taskDir, resolved.taskId, inspection.intentDigest);
1053
- });
1054
- });
1055
- }
1056
- catch (error) {
1057
- return mapCommitIntentError(error, resolved.taskId);
1058
- }
1059
- }
1060
- function abortCommitIntent(taskRef, input, options = {}) {
1061
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1062
- if (!resolved.ok)
1063
- return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
1064
- try {
1065
- const gitRoot = gitRootFor(resolved.repoRoot, options);
1066
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-intent.abort', () => {
1067
- const intent = readCommitIntent(resolved.taskDir, resolved.taskId, input.token);
1068
- const currentHead = repositoryHead(gitRoot);
1069
- if (intent.phase !== 'prepared'
1070
- || intent.pushEvidence !== null
1071
- || input.expectedHead !== intent.baselineHead
1072
- || currentHead !== intent.baselineHead) {
1073
- return commitIntentFailed('ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', 'commit intent has side effects or repository drift', resolved.taskId);
1074
- }
1075
- removeCommitIntent(resolved.taskDir, resolved.taskId, input.token);
1076
- return { status: 'ready', changed: true, taskId: resolved.taskId, intent: null, error: null };
1077
- });
1078
- }
1079
- catch (error) {
1080
- return mapCommitIntentError(error, resolved.taskId);
1081
- }
1082
- }
1083
- function statusCommitIntent(taskRef, options = {}) {
1084
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1085
- if (!resolved.ok)
1086
- return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
1087
- let gitRoot;
1088
- try {
1089
- gitRoot = gitRootFor(resolved.repoRoot, options);
1090
- }
1091
- catch (error) {
1092
- return commitIntentFailed('ORCHESTRATION_WORKTREE_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
1093
- }
1094
- const inspection = inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId);
1095
- return {
1096
- status: 'ready',
1097
- changed: false,
1098
- taskId: resolved.taskId,
1099
- intent: inspection.intent ? commitIntentView(inspection.intent, inspection.currentHead) : null,
1100
- finalization: commitFinalizationView(inspection),
1101
- error: null
1102
- };
1103
- }
1104
552
  function statusOrchestration(taskRef, options = {}) {
1105
553
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1106
554
  if (!resolved.ok)
@@ -1114,26 +562,12 @@ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
1114
562
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1115
563
  if (!resolved.ok)
1116
564
  return failed(resolved.code, resolved.message, resolved.taskId);
1117
- if (fs.existsSync(commitIntentPath(resolved.taskDir))) {
1118
- try {
1119
- readCommitIntent(resolved.taskDir, resolved.taskId);
1120
- }
1121
- catch (error) {
1122
- return failed('ORCHESTRATION_COMMIT_INTENT_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
1123
- }
1124
- return failed('ORCHESTRATION_COMMIT_INTENT_BUSY', 'an active commit intent blocks delegation preparation', resolved.taskId);
1125
- }
1126
565
  if (!(options.supportsLifecycleDelegation ?? supportsLifecycleDelegation)(input.client)) {
1127
566
  return failed('ORCHESTRATION_CLIENT_UNSUPPORTED', `client '${input.client}' does not support lifecycle orchestration`, resolved.taskId);
1128
567
  }
1129
568
  const run = readRun(resolved.taskDir);
1130
569
  if (!run || run.status !== 'running')
1131
570
  return failed('ORCHESTRATION_RUN_NOT_RUNNING', 'a running orchestration is required', resolved.taskId);
1132
- if (run.schemaVersion !== 3) {
1133
- return failed('ORCHESTRATION_STATE_INVALID', 'delegation preparation requires orchestration schemaVersion 3', resolved.taskId);
1134
- }
1135
- if (!isV2Policy(run.modelPolicy))
1136
- return failed('ORCHESTRATION_MODEL_EVIDENCE_MISSING', 'running orchestration has no persisted model policy', resolved.taskId);
1137
571
  if (run.pendingDelegation)
1138
572
  return failed('ORCHESTRATION_DELEGATION_BUSY', 'the run already has a pending delegation', resolved.taskId);
1139
573
  const repositoryPending = matchingDelegations(() => true, options);
@@ -1162,6 +596,10 @@ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
1162
596
  if (input.requestedReasoningEffort !== expectedPolicy.reasoningEffort) {
1163
597
  return failed('ORCHESTRATION_REQUESTED_REASONING_EFFORT_MISMATCH', `requested reasoning effort does not match the persisted ${next.role} policy`, resolved.taskId);
1164
598
  }
599
+ const capabilityValidationError = options.validateLifecycleCapability?.();
600
+ if (capabilityValidationError) {
601
+ return failed(capabilityValidationError.code, capabilityValidationError.message, resolved.taskId, capabilityValidationError.detail ? { detail: capabilityValidationError.detail } : {});
602
+ }
1165
603
  let beforeFingerprint;
1166
604
  try {
1167
605
  beforeFingerprint = (options.captureWorkspace ?? captureWorkspaceSnapshot)({
@@ -1187,6 +625,10 @@ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
1187
625
  lifecycleProvenance: input.lifecycleProvenance ?? null,
1188
626
  beforeFingerprint
1189
627
  }, { id: options.id, now: options.now, monotonicNow: options.monotonicNow });
628
+ const capabilityError = options.consumeLifecycleCapability?.();
629
+ if (capabilityError) {
630
+ return failed(capabilityError.code, capabilityError.message, resolved.taskId, capabilityError.detail ? { detail: capabilityError.detail } : {});
631
+ }
1190
632
  const updated = withUpdatedRun(run, {
1191
633
  nextStage: next.stage,
1192
634
  pendingDelegation: receipt,
@@ -1217,8 +659,8 @@ function dispatchOrchestrationDelegationUnlocked(taskRef, options = {}) {
1217
659
  const run = readRun(resolved.taskDir);
1218
660
  if (!run?.pendingDelegation)
1219
661
  return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
1220
- if (run.schemaVersion !== 3 || run.status !== 'running') {
1221
- return failed('ORCHESTRATION_STATE_INVALID', 'spawn dispatch requires a running schemaVersion 3 orchestration', resolved.taskId);
662
+ if (run.status !== 'running') {
663
+ return failed('ORCHESTRATION_STATE_INVALID', 'spawn dispatch requires a running orchestration', resolved.taskId);
1222
664
  }
1223
665
  const result = dispatchDelegation(run.pendingDelegation, {
1224
666
  now: options.now,
@@ -1252,7 +694,7 @@ function matchingDelegations(predicate, options) {
1252
694
  .filter((entry) => entry.isDirectory())
1253
695
  .flatMap((entry) => {
1254
696
  const run = readRun(path.join(activeRoot, entry.name));
1255
- if (run?.schemaVersion !== 3 || run.status !== 'running' || !run.pendingDelegation)
697
+ if (!run || run.status !== 'running' || !run.pendingDelegation)
1256
698
  return [];
1257
699
  const receipt = run.pendingDelegation;
1258
700
  return predicate(receipt)
@@ -1412,8 +854,6 @@ function activateOrchestrationDelegation(taskRef, event, options = {}) {
1412
854
  const run = readRun(resolved.taskDir);
1413
855
  if (!run?.pendingDelegation)
1414
856
  return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
1415
- if (run.schemaVersion !== 3)
1416
- return failed('ORCHESTRATION_STATE_INVALID', 'active delegation requires schemaVersion 3', resolved.taskId);
1417
857
  if (run.status !== 'running') {
1418
858
  return { status: run.status, changed: false, taskId: resolved.taskId, run, next: null, error: null };
1419
859
  }
@@ -1441,9 +881,6 @@ async function awaitOrchestrationDelegationActivation(taskRef, event, options =
1441
881
  if (!run?.pendingDelegation) {
1442
882
  return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
1443
883
  }
1444
- if (run.schemaVersion !== 3) {
1445
- return failed('ORCHESTRATION_STATE_INVALID', 'activation barrier requires schemaVersion 3', resolved.taskId);
1446
- }
1447
884
  const receipt = run.pendingDelegation;
1448
885
  const matches = receipt.stage === event.stage
1449
886
  && receipt.round === event.round
@@ -1501,9 +938,6 @@ function recoverPreparedOrchestrationDelegation(taskRef, options = {}) {
1501
938
  if (activeLifecycleEvidence) {
1502
939
  return failed('ORCHESTRATION_PREPARED_RECOVERY_ACTIVE_EVIDENCE', 'active Codex lifecycle evidence blocks prepared receipt recovery', resolved.taskId);
1503
940
  }
1504
- if (fs.existsSync(commitIntentPath(resolved.taskDir))) {
1505
- return failed('ORCHESTRATION_PREPARED_RECOVERY_UNSAFE', 'active commit intent blocks prepared recovery', resolved.taskId);
1506
- }
1507
941
  const current = (options.captureWorkspace ?? captureWorkspaceSnapshot)({
1508
942
  gitRoot: gitRootFor(resolved.repoRoot, options),
1509
943
  stateRoot: resolved.repoRoot,
@@ -1539,8 +973,6 @@ function completeOrchestrationStage(taskRef, event, options = {}) {
1539
973
  const run = readRun(resolved.taskDir);
1540
974
  if (!run)
1541
975
  return { status: 'running', changed: false, taskId: resolved.taskId, run: null, next: null, error: null };
1542
- if (run.schemaVersion !== 3)
1543
- return failed('ORCHESTRATION_STATE_INVALID', 'stage completion requires schemaVersion 3', resolved.taskId);
1544
976
  if (!run.pendingDelegation)
1545
977
  return failed('ORCHESTRATION_DELEGATION_MISSING', 'active run has no pending delegation', resolved.taskId);
1546
978
  const result = completeDelegationStage(run.pendingDelegation, event);
@@ -1563,8 +995,6 @@ function inspectOrchestrationStage(taskRef, event, options = {}) {
1563
995
  }
1564
996
  if (!run)
1565
997
  return failed('ORCHESTRATION_RUN_MISSING', 'no orchestration run exists', resolved.taskId);
1566
- if (run.schemaVersion !== 3)
1567
- return failed('ORCHESTRATION_STATE_INVALID', 'stage inspection requires schemaVersion 3', resolved.taskId);
1568
998
  const receipt = run.pendingDelegation;
1569
999
  if (!receipt
1570
1000
  || receipt.status !== 'activated'
@@ -1609,8 +1039,6 @@ function sealOrchestrationDelegation(taskRef, event, options = {}) {
1609
1039
  const run = readRun(resolved.taskDir);
1610
1040
  if (!run?.pendingDelegation)
1611
1041
  return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
1612
- if (run.schemaVersion !== 3)
1613
- return failed('ORCHESTRATION_STATE_INVALID', 'delegation sealing requires schemaVersion 3', resolved.taskId);
1614
1042
  const result = sealDelegation(run.pendingDelegation, event, { now: options.now });
1615
1043
  if (!result.ok)
1616
1044
  return pauseOrchestration(taskRef, result.code, result.message, true, options);
@@ -1625,8 +1053,6 @@ function advanceOrchestration(taskRef, options = {}) {
1625
1053
  const run = readRun(resolved.taskDir);
1626
1054
  if (!run?.pendingDelegation)
1627
1055
  return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
1628
- if (run.schemaVersion !== 3)
1629
- return failed('ORCHESTRATION_STATE_INVALID', 'orchestration advance requires schemaVersion 3', resolved.taskId);
1630
1056
  const result = consumeDelegation(run.pendingDelegation, { now: options.now });
1631
1057
  if (!result.ok)
1632
1058
  return pauseOrchestration(taskRef, result.code, result.message, true, options);
@@ -1655,5 +1081,5 @@ function pauseOrchestration(taskRef, code, message, recoverable, options = {}) {
1655
1081
  saveRun(resolved.taskDir, updated);
1656
1082
  return { status: 'paused', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
1657
1083
  }
1658
- export { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, awaitOrchestrationDelegationActivation, advanceOrchestration, abortCommitIntent, beginCommitIntent, beginOrResumeOrchestration, checkpointCommitIntent, commitOrchestrationStageCompletion, completeCommitIntent, completeOrchestrationStage, dispatchOrchestrationDelegation, inspectOrchestrationStage, hasActivatableOrchestrationDelegation, hasSealableOrchestrationDelegation, orchestrationPath, pauseMatchingOrchestrationDelegation, pauseOrchestration, planOrchestrationStageCompletion, prepareOrchestrationDelegation, readRun, reconcileMatchingOrchestrationDelegation, recoverCommitIntent, recoverPreparedOrchestrationDelegation, routeOrchestration, sealMatchingOrchestrationDelegation, sealMatchingOrchestrationDelegationWithHostEvidence, sealOrchestrationDelegation, startCommitAttempt, statusCommitIntent, statusOrchestration, terminateCommitAttempt };
1084
+ export { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, awaitOrchestrationDelegationActivation, advanceOrchestration, beginOrResumeOrchestration, commitOrchestrationStageCompletion, completeOrchestrationStage, dispatchOrchestrationDelegation, inspectOrchestrationStage, hasActivatableOrchestrationDelegation, hasSealableOrchestrationDelegation, OrchestrationStateError, orchestrationPath, pauseMatchingOrchestrationDelegation, pauseOrchestration, planOrchestrationStageCompletion, prepareOrchestrationDelegation, readRun, reconcileMatchingOrchestrationDelegation, recoverPreparedOrchestrationDelegation, routeOrchestration, sealMatchingOrchestrationDelegation, sealMatchingOrchestrationDelegationWithHostEvidence, sealOrchestrationDelegation, statusOrchestration, };
1659
1085
  //# sourceMappingURL=orchestration.js.map