@fitlab-ai/agent-infra 0.9.3 → 0.9.5

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 (203) hide show
  1. package/README.md +3 -1
  2. package/README.zh-CN.md +3 -1
  3. package/bin/cli.ts +12 -0
  4. package/dist/bin/cli.js +14 -0
  5. package/dist/bin/internal-cli.js +144 -123
  6. package/dist/lib/agent-clients/adapter.js +94 -4
  7. package/dist/lib/{sandbox/credentials.js → agent-clients/adapters/claude-code-credentials.js} +4 -14
  8. package/dist/lib/agent-clients/adapters/claude-code-refresh.js +85 -0
  9. package/dist/lib/agent-clients/adapters/claude-code-sandbox.js +247 -0
  10. package/dist/lib/agent-clients/adapters/claude-code.js +17 -3
  11. package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +382 -0
  12. package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +163 -0
  13. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +211 -0
  14. package/dist/lib/agent-clients/adapters/codex.js +2 -2
  15. package/dist/lib/agent-clients/adapters/opencode-sandbox.js +108 -0
  16. package/dist/lib/agent-clients/adapters/opencode.js +15 -3
  17. package/dist/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  18. package/dist/lib/agent-clients/registry.js +9 -1
  19. package/dist/lib/git/worktree-identity.js +64 -0
  20. package/dist/lib/internal/codex-lifecycle.js +202 -0
  21. package/dist/lib/internal/sandbox-control.js +24 -0
  22. package/dist/lib/internal/task-activity.js +45 -13
  23. package/dist/lib/internal/task-create.js +48 -0
  24. package/dist/lib/internal/task-ledger.js +12 -3
  25. package/dist/lib/internal/task-lifecycle.js +19 -1
  26. package/dist/lib/internal/task-orchestration.js +170 -27
  27. package/dist/lib/platform/github-client.js +19 -2
  28. package/dist/lib/platform/pr-checks.js +1 -1
  29. package/dist/lib/platform/pull-requests.js +47 -1
  30. package/dist/lib/platform/releases.js +13 -5
  31. package/dist/lib/process-data/index.js +239 -0
  32. package/dist/lib/process-data/normalize.js +198 -0
  33. package/dist/lib/process-data/privacy.js +33 -0
  34. package/dist/lib/process-data/reconcile.js +95 -0
  35. package/dist/lib/process-data/repair.js +58 -0
  36. package/dist/lib/process-data/sources.js +345 -0
  37. package/dist/lib/process-data/store.js +282 -0
  38. package/dist/lib/process-data/types.js +2 -0
  39. package/dist/lib/run/index.js +4 -3
  40. package/dist/lib/run/tui.js +7 -8
  41. package/dist/lib/sandbox/agent-client-reconciler.js +26 -2
  42. package/dist/lib/sandbox/capture.js +7 -2
  43. package/dist/lib/sandbox/commands/create.js +110 -228
  44. package/dist/lib/sandbox/commands/enter.js +15 -47
  45. package/dist/lib/sandbox/commands/list-running.js +16 -6
  46. package/dist/lib/sandbox/commands/ls.js +10 -6
  47. package/dist/lib/sandbox/commands/rebuild.js +4 -3
  48. package/dist/lib/sandbox/commands/refresh.js +4 -84
  49. package/dist/lib/sandbox/commands/rm.js +24 -3
  50. package/dist/lib/sandbox/commands/show.js +12 -3
  51. package/dist/lib/sandbox/commands/start.js +7 -4
  52. package/dist/lib/sandbox/config.js +2 -0
  53. package/dist/lib/sandbox/constants.js +6 -0
  54. package/dist/lib/sandbox/control/client.js +58 -0
  55. package/dist/lib/sandbox/control/protocol.js +54 -0
  56. package/dist/lib/sandbox/control/server.js +144 -0
  57. package/dist/lib/sandbox/dockerfile.js +36 -13
  58. package/dist/lib/sandbox/mounts.js +17 -4
  59. package/dist/lib/sandbox/recovery.js +128 -5
  60. package/dist/lib/sandbox/redaction.js +12 -0
  61. package/dist/lib/sandbox/runtimes/base.dockerfile +24 -74
  62. package/dist/lib/sandbox/workspace-identity.js +95 -0
  63. package/dist/lib/sandbox/workspace-view.js +109 -0
  64. package/dist/lib/task/activity-intent.js +257 -51
  65. package/dist/lib/task/activity-log.js +32 -5
  66. package/dist/lib/task/commit-finalization.js +278 -0
  67. package/dist/lib/task/commit-intent.js +165 -0
  68. package/dist/lib/task/create-service.js +137 -0
  69. package/dist/lib/task/create.js +333 -0
  70. package/dist/lib/task/decision-intents.js +31 -17
  71. package/dist/lib/task/delegation-receipts.js +2 -2
  72. package/dist/lib/task/implementation-inputs.js +54 -7
  73. package/dist/lib/task/ledger-intents.js +35 -1
  74. package/dist/lib/task/orchestration.js +505 -34
  75. package/dist/lib/task/resolve-ref.js +41 -1
  76. package/dist/lib/task/review-fingerprint.js +4 -0
  77. package/dist/lib/task/workspace-snapshot.js +78 -3
  78. package/lib/agent-clients/adapter.ts +130 -6
  79. package/lib/{sandbox/credentials.ts → agent-clients/adapters/claude-code-credentials.ts} +3 -18
  80. package/lib/agent-clients/adapters/claude-code-refresh.ts +128 -0
  81. package/lib/agent-clients/adapters/claude-code-sandbox.ts +295 -0
  82. package/lib/agent-clients/adapters/claude-code.ts +21 -3
  83. package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +442 -0
  84. package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +307 -0
  85. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +250 -0
  86. package/lib/agent-clients/adapters/codex.ts +2 -2
  87. package/lib/agent-clients/adapters/opencode-sandbox.ts +136 -0
  88. package/lib/agent-clients/adapters/opencode.ts +18 -3
  89. package/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
  90. package/lib/agent-clients/registry.ts +9 -1
  91. package/lib/git/worktree-identity.ts +86 -0
  92. package/lib/internal/codex-lifecycle.ts +204 -0
  93. package/lib/internal/sandbox-control.ts +24 -0
  94. package/lib/internal/task-activity.ts +50 -14
  95. package/lib/internal/task-create.ts +49 -0
  96. package/lib/internal/task-ledger.ts +12 -3
  97. package/lib/internal/task-lifecycle.ts +22 -1
  98. package/lib/internal/task-orchestration.ts +117 -21
  99. package/lib/platform/github-client.ts +20 -2
  100. package/lib/platform/pr-checks.ts +1 -1
  101. package/lib/platform/pull-requests.ts +49 -1
  102. package/lib/platform/releases.ts +16 -4
  103. package/lib/process-data/index.ts +224 -0
  104. package/lib/process-data/normalize.ts +202 -0
  105. package/lib/process-data/privacy.ts +41 -0
  106. package/lib/process-data/reconcile.ts +110 -0
  107. package/lib/process-data/repair.ts +64 -0
  108. package/lib/process-data/sources.ts +354 -0
  109. package/lib/process-data/store.ts +315 -0
  110. package/lib/process-data/types.ts +135 -0
  111. package/lib/run/index.ts +5 -3
  112. package/lib/run/tui.ts +11 -8
  113. package/lib/sandbox/agent-client-reconciler.ts +44 -2
  114. package/lib/sandbox/capture.ts +9 -2
  115. package/lib/sandbox/commands/create.ts +127 -260
  116. package/lib/sandbox/commands/enter.ts +13 -59
  117. package/lib/sandbox/commands/list-running.ts +23 -6
  118. package/lib/sandbox/commands/ls.ts +22 -6
  119. package/lib/sandbox/commands/rebuild.ts +4 -3
  120. package/lib/sandbox/commands/refresh.ts +4 -126
  121. package/lib/sandbox/commands/rm.ts +24 -3
  122. package/lib/sandbox/commands/show.ts +29 -3
  123. package/lib/sandbox/commands/start.ts +6 -4
  124. package/lib/sandbox/config.ts +4 -0
  125. package/lib/sandbox/constants.ts +8 -0
  126. package/lib/sandbox/control/client.ts +79 -0
  127. package/lib/sandbox/control/protocol.ts +110 -0
  128. package/lib/sandbox/control/server.ts +155 -0
  129. package/lib/sandbox/dockerfile.ts +66 -13
  130. package/lib/sandbox/mounts.ts +24 -4
  131. package/lib/sandbox/recovery.ts +163 -6
  132. package/lib/sandbox/redaction.ts +14 -0
  133. package/lib/sandbox/runtimes/base.dockerfile +24 -74
  134. package/lib/sandbox/tool-types.ts +16 -0
  135. package/lib/sandbox/workspace-identity.ts +123 -0
  136. package/lib/sandbox/workspace-view.ts +150 -0
  137. package/lib/task/activity-intent.ts +350 -61
  138. package/lib/task/activity-log.ts +46 -7
  139. package/lib/task/commit-finalization.ts +376 -0
  140. package/lib/task/commit-intent.ts +230 -0
  141. package/lib/task/create-service.ts +171 -0
  142. package/lib/task/create.ts +372 -0
  143. package/lib/task/decision-intents.ts +32 -12
  144. package/lib/task/delegation-receipts.ts +2 -2
  145. package/lib/task/implementation-inputs.ts +62 -8
  146. package/lib/task/ledger-intents.ts +43 -3
  147. package/lib/task/orchestration.ts +673 -41
  148. package/lib/task/resolve-ref.ts +46 -1
  149. package/lib/task/review-fingerprint.ts +9 -0
  150. package/lib/task/workspace-snapshot.ts +98 -4
  151. package/package.json +7 -7
  152. package/templates/.agents/hooks/lifecycle-delegation.js +47 -3
  153. package/templates/.agents/rules/README.en.md +1 -1
  154. package/templates/.agents/rules/README.zh-CN.md +1 -1
  155. package/templates/.agents/rules/human-decision-context.en.md +11 -2
  156. package/templates/.agents/rules/human-decision-context.zh-CN.md +11 -2
  157. package/templates/.agents/rules/pr-checks-commands.en.md +1 -1
  158. package/templates/.agents/rules/pr-checks-commands.github.en.md +1 -1
  159. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +2 -2
  160. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +1 -1
  161. package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
  162. package/templates/.agents/rules/task-management.en.md +3 -0
  163. package/templates/.agents/rules/task-management.zh-CN.md +3 -0
  164. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  165. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +1 -1
  166. package/templates/.agents/skills/commit/SKILL.en.md +21 -17
  167. package/templates/.agents/skills/commit/SKILL.zh-CN.md +28 -16
  168. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +50 -0
  169. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +56 -0
  170. package/templates/.agents/skills/commit/reference/task-status-update.en.md +4 -4
  171. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +4 -4
  172. package/templates/.agents/skills/complete-task/SKILL.en.md +1 -1
  173. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +1 -1
  174. package/templates/.agents/skills/create-pr/SKILL.en.md +4 -4
  175. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +4 -4
  176. package/templates/.agents/skills/create-task/SKILL.en.md +26 -43
  177. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +26 -43
  178. package/templates/.agents/skills/create-task/reference/context-capture.en.md +34 -0
  179. package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +34 -0
  180. package/templates/.agents/skills/review-code/SKILL.en.md +2 -2
  181. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
  182. package/templates/.agents/skills/review-code/reference/output-templates.en.md +1 -1
  183. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +1 -1
  184. package/templates/.agents/skills/review-pr/SKILL.en.md +36 -8
  185. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +36 -8
  186. package/templates/.agents/skills/review-pr/reference/report-template.en.md +1 -1
  187. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +1 -1
  188. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +67 -50
  189. package/templates/.agents/skills/watch-pr/SKILL.en.md +4 -4
  190. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +4 -4
  191. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
  192. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
  193. package/templates/.agents/templates/task.en.md +1 -1
  194. package/templates/.agents/templates/task.zh-CN.md +1 -1
  195. package/templates/.claude/commands/watch-pr.en.md +1 -1
  196. package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
  197. package/templates/.claude/rules/tool-preferences.en.md +20 -0
  198. package/templates/.claude/rules/tool-preferences.zh-CN.md +20 -0
  199. package/templates/.codex/hooks.json +50 -0
  200. package/templates/.opencode/commands/watch-pr.en.md +1 -1
  201. package/templates/.opencode/commands/watch-pr.zh-CN.md +1 -1
  202. package/templates/.gemini/commands/_project_/review-pr.en.toml +0 -10
  203. package/templates/.gemini/commands/_project_/review-pr.zh-CN.toml +0 -10
@@ -1,6 +1,7 @@
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';
4
5
  import { parseTypedTaskFrontmatter } from './frontmatter.js';
5
6
  import { parseReviewSummary } from './review-artifacts.js';
6
7
  import { inspectArtifactDirectory } from './artifact-lifecycle.js';
@@ -12,7 +13,12 @@ import { inspectPlatformPullRequest } from '../platform/pull-requests.js';
12
13
  import { getAgentClientCapability, getAgentClientDelegationEvidence, getAgentClientModelSelection } from '../agent-clients/registry.js';
13
14
  import { isAgentClientId } from '../agent-clients/types.js';
14
15
  import { captureRepositorySnapshot, captureWorkspaceSnapshot, diffWorkspaceSnapshots } from './workspace-snapshot.js';
16
+ import { assertGitRepositoryBinding } from '../git/worktree-identity.js';
15
17
  import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
18
+ import { CommitIntentError, commitIntentPath, createCommitIntent, digest, readCommitIntent, removeCommitIntent, removeCommitIntentByDigest, serialize, updateCommitIntent } from './commit-intent.js';
19
+ import { inspectCommitFinalization, planCommitTaskFinalization } from './commit-finalization.js';
20
+ import { captureTaskWriteMetadata, writeTask } from './write.js';
21
+ import { appendActivityEntry, commitAttemptStartedNote, locateActivityLog, pairEntries } from './activity-log.js';
16
22
  function supportsLifecycleDelegation(client) {
17
23
  return getAgentClientCapability(client, 'subagents').level !== 'unsupported'
18
24
  && getAgentClientCapability(client, 'orchestration').level !== 'unsupported'
@@ -51,12 +57,76 @@ function atomicWrite(file, value) {
51
57
  function saveRun(taskDir, run) {
52
58
  atomicWrite(orchestrationPath(taskDir), run);
53
59
  }
54
- function withUpdatedRun(run, updates) {
55
- return Object.freeze({ ...run, ...updates, updatedAt: new Date().toISOString() });
60
+ function withUpdatedRun(run, updates, now) {
61
+ return Object.freeze({ ...run, ...updates, updatedAt: (now ?? (() => new Date().toISOString()))() });
56
62
  }
57
63
  function failed(code, message, taskId = null, details = {}) {
58
64
  return { status: 'failed', changed: false, taskId, run: null, next: null, error: { code, message, ...details } };
59
65
  }
66
+ function commitIntentFailed(code, message, taskId = null) {
67
+ return { status: 'failed', changed: false, taskId, intent: null, error: { code, message } };
68
+ }
69
+ function repositoryHead(repoRoot) {
70
+ return execFileSync('git', ['rev-parse', 'HEAD'], {
71
+ cwd: repoRoot,
72
+ encoding: 'utf8',
73
+ stdio: ['ignore', 'pipe', 'pipe']
74
+ }).trim();
75
+ }
76
+ function gitRootFor(stateRoot, options) {
77
+ if (!options.gitWorktreeRoot)
78
+ return stateRoot;
79
+ return assertGitRepositoryBinding(stateRoot, options.gitWorktreeRoot).worktreeRoot;
80
+ }
81
+ function isAncestor(repoRoot, ancestor, descendant) {
82
+ return spawnSync('git', ['merge-base', '--is-ancestor', ancestor, descendant], {
83
+ cwd: repoRoot,
84
+ stdio: 'ignore'
85
+ }).status === 0;
86
+ }
87
+ function commitIntentView(intent, currentHead) {
88
+ return {
89
+ mode: intent.mode,
90
+ phase: intent.phase,
91
+ baselineHead: intent.baselineHead,
92
+ currentHead,
93
+ committedHead: intent.committedHead,
94
+ pushEvidence: intent.pushEvidence,
95
+ runId: intent.orchestration?.runId ?? null,
96
+ receiptId: intent.orchestration?.receiptId ?? null
97
+ };
98
+ }
99
+ function commitFinalizationView(inspection) {
100
+ return {
101
+ disposition: inspection.disposition,
102
+ code: inspection.code,
103
+ message: inspection.message,
104
+ currentHead: inspection.currentHead,
105
+ committedHead: inspection.committedHead,
106
+ needsAnchor: inspection.needsAnchor,
107
+ needsLog: inspection.needsLog,
108
+ attempt: inspection.attempt
109
+ };
110
+ }
111
+ function validCommitRun(run, taskId) {
112
+ return run !== null
113
+ && [1, 2].includes(run.schemaVersion)
114
+ && run.taskId === taskId
115
+ && ['running', 'paused', 'completed'].includes(run.status)
116
+ && Array.isArray(run.receipts)
117
+ && Object.prototype.hasOwnProperty.call(run, 'pendingDelegation')
118
+ && typeof run.commitAuthorization === 'object'
119
+ && run.commitAuthorization !== null
120
+ && Object.prototype.hasOwnProperty.call(run.commitAuthorization, 'issuedAt')
121
+ && Object.prototype.hasOwnProperty.call(run.commitAuthorization, 'consumedAt');
122
+ }
123
+ function mapCommitIntentError(error, taskId) {
124
+ if (error instanceof CommitIntentError)
125
+ return commitIntentFailed(error.code, error.message, taskId);
126
+ if (error instanceof TaskExecutionLockError)
127
+ return commitIntentFailed(error.code, error.message, taskId);
128
+ return commitIntentFailed('ORCHESTRATION_COMMIT_INTENT_INVALID', error instanceof Error ? error.message : String(error), taskId);
129
+ }
60
130
  function validModel(value) {
61
131
  return typeof value === 'string' && value.length > 0 && value.trim() === value;
62
132
  }
@@ -337,6 +407,13 @@ function routeOrchestration(taskRef, options = {}) {
337
407
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
338
408
  if (!resolved.ok)
339
409
  return failed(resolved.code, resolved.message, resolved.taskId);
410
+ let gitRoot;
411
+ try {
412
+ gitRoot = gitRootFor(resolved.repoRoot, options);
413
+ }
414
+ catch (error) {
415
+ return failed('ORCHESTRATION_WORKTREE_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
416
+ }
340
417
  let content;
341
418
  try {
342
419
  content = fs.readFileSync(resolved.taskMdPath, 'utf8');
@@ -407,7 +484,7 @@ function routeOrchestration(taskRef, options = {}) {
407
484
  const capture = options.captureRepository ?? captureRepositorySnapshot;
408
485
  let before;
409
486
  try {
410
- before = capture(resolved.repoRoot);
487
+ before = capture(gitRoot);
411
488
  }
412
489
  catch (error) {
413
490
  return failed('ORCHESTRATION_SNAPSHOT_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
@@ -422,7 +499,7 @@ function routeOrchestration(taskRef, options = {}) {
422
499
  const inspect = options.inspectPullRequest ?? inspectPlatformPullRequest;
423
500
  let inspection;
424
501
  try {
425
- inspection = inspect(resolved.taskId, { cwd: resolved.repoRoot });
502
+ inspection = inspect(resolved.taskId, { cwd: gitRoot });
426
503
  }
427
504
  catch (error) {
428
505
  return failed('ORCHESTRATION_PR_INSPECTION_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
@@ -443,7 +520,7 @@ function routeOrchestration(taskRef, options = {}) {
443
520
  }
444
521
  let after;
445
522
  try {
446
- after = capture(resolved.repoRoot);
523
+ after = capture(gitRoot);
447
524
  }
448
525
  catch (error) {
449
526
  return failed('ORCHESTRATION_SNAPSHOT_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
@@ -476,6 +553,401 @@ function routeOrchestration(taskRef, options = {}) {
476
553
  }
477
554
  return { status: 'running', changed: false, taskId: resolved.taskId, run, next, error: null };
478
555
  }
556
+ function appendCommitActivity(resolved, step, agent, note) {
557
+ const taskContent = fs.readFileSync(resolved.taskMdPath, 'utf8');
558
+ const activity = locateActivityLog(taskContent);
559
+ if (!activity)
560
+ return { code: 'ORCHESTRATION_TASK_INVALID', message: 'task activity log is missing or ambiguous' };
561
+ const metadata = captureTaskWriteMetadata();
562
+ const written = writeTask({
563
+ taskRef: resolved.taskId,
564
+ expectedState: 'active',
565
+ mutations: [{
566
+ kind: 'section',
567
+ aliases: ['活动日志', 'Activity Log'],
568
+ heading: activity.heading,
569
+ body: appendActivityEntry(activity, { time: metadata.timestamp, step, agent, note })
570
+ }]
571
+ }, { repoRoot: resolved.repoRoot, metadataProvider: () => metadata });
572
+ return written.status === 'failed' ? written.error : null;
573
+ }
574
+ function startCommitAttempt(taskRef, input, options = {}) {
575
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
576
+ if (!resolved.ok)
577
+ return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
578
+ try {
579
+ const gitRoot = gitRootFor(resolved.repoRoot, options);
580
+ return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-attempt.start', () => {
581
+ if (fs.existsSync(commitIntentPath(resolved.taskDir))) {
582
+ return commitIntentFailed('ORCHESTRATION_COMMIT_INTENT_BUSY', 'an active commit intent already exists', resolved.taskId);
583
+ }
584
+ const taskContent = fs.readFileSync(resolved.taskMdPath, 'utf8');
585
+ const activity = locateActivityLog(taskContent);
586
+ if (!activity)
587
+ return commitIntentFailed('ORCHESTRATION_TASK_INVALID', 'task activity log is missing or ambiguous', resolved.taskId);
588
+ const open = pairEntries(activity.entries).filter((row) => row.step === 'Commit' && row.started !== '' && row.done === '');
589
+ if (open.length > 0) {
590
+ return commitIntentFailed('ORCHESTRATION_COMMIT_ATTEMPT_BUSY', 'an open Commit activity entry already exists', resolved.taskId);
591
+ }
592
+ const currentHead = repositoryHead(gitRoot);
593
+ const attempt = (options.id ?? randomUUID)();
594
+ const error = appendCommitActivity(resolved, 'Commit [started]', input.agent, commitAttemptStartedNote({
595
+ attempt,
596
+ baseline: currentHead,
597
+ agent: input.agent
598
+ }));
599
+ if (error)
600
+ return commitIntentFailed(error.code, error.message, resolved.taskId);
601
+ const inspection = inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId);
602
+ return {
603
+ status: 'ready', changed: true, taskId: resolved.taskId, intent: null,
604
+ finalization: commitFinalizationView(inspection), error: null
605
+ };
606
+ });
607
+ }
608
+ catch (error) {
609
+ return mapCommitIntentError(error, resolved.taskId);
610
+ }
611
+ }
612
+ function terminateCommitAttempt(taskRef, input, options = {}) {
613
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
614
+ if (!resolved.ok)
615
+ return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
616
+ try {
617
+ const gitRoot = gitRootFor(resolved.repoRoot, options);
618
+ return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-attempt.terminate', () => {
619
+ if (fs.existsSync(commitIntentPath(resolved.taskDir))) {
620
+ return commitIntentFailed('ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', 'an active commit intent must be aborted or recovered first', resolved.taskId);
621
+ }
622
+ const inspection = inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId);
623
+ if (inspection.disposition !== 'retryable-start'
624
+ || inspection.attempt?.attempt !== input.attempt
625
+ || inspection.attempt.agent !== input.agent
626
+ || inspection.attempt.baseline !== inspection.currentHead) {
627
+ return commitIntentFailed('ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', 'commit attempt identity or repository HEAD has drifted', resolved.taskId);
628
+ }
629
+ const error = appendCommitActivity(resolved, 'Commit [aborted]', input.agent, `aborted; attempt=${input.attempt}; code=${input.code}`);
630
+ if (error)
631
+ return commitIntentFailed(error.code, error.message, resolved.taskId);
632
+ return {
633
+ status: 'ready', changed: true, taskId: resolved.taskId, intent: null,
634
+ finalization: commitFinalizationView(inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId)),
635
+ error: null
636
+ };
637
+ });
638
+ }
639
+ catch (error) {
640
+ return mapCommitIntentError(error, resolved.taskId);
641
+ }
642
+ }
643
+ function beginCommitIntent(taskRef, input, options = {}) {
644
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
645
+ if (!resolved.ok)
646
+ return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
647
+ try {
648
+ const gitRoot = gitRootFor(resolved.repoRoot, options);
649
+ return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-intent.begin', () => {
650
+ const currentHead = repositoryHead(gitRoot);
651
+ if (currentHead !== input.baselineHead) {
652
+ return commitIntentFailed('ORCHESTRATION_COMMIT_BASELINE_MISMATCH', 'baseline HEAD does not match the repository HEAD', resolved.taskId);
653
+ }
654
+ if (fs.existsSync(commitIntentPath(resolved.taskDir))) {
655
+ try {
656
+ readCommitIntent(resolved.taskDir, resolved.taskId);
657
+ }
658
+ catch (error) {
659
+ return mapCommitIntentError(error, resolved.taskId);
660
+ }
661
+ return commitIntentFailed('ORCHESTRATION_COMMIT_INTENT_BUSY', 'an active commit intent already exists', resolved.taskId);
662
+ }
663
+ const attemptInspection = inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId);
664
+ if (attemptInspection.disposition !== 'retryable-start'
665
+ || attemptInspection.attempt?.attempt !== input.attempt
666
+ || attemptInspection.attempt.agent !== input.agent
667
+ || attemptInspection.attempt.baseline !== input.baselineHead) {
668
+ return commitIntentFailed('ORCHESTRATION_COMMIT_ATTEMPT_MISMATCH', 'commit begin requires one matching retryable Commit attempt', resolved.taskId);
669
+ }
670
+ const runFile = orchestrationPath(resolved.taskDir);
671
+ let run = null;
672
+ let sourceRunBytes = null;
673
+ if (fs.existsSync(runFile)) {
674
+ sourceRunBytes = fs.readFileSync(runFile, 'utf8');
675
+ try {
676
+ run = readRun(resolved.taskDir);
677
+ }
678
+ catch (error) {
679
+ return commitIntentFailed('ORCHESTRATION_STATE_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
680
+ }
681
+ if (!validCommitRun(run, resolved.taskId)) {
682
+ return commitIntentFailed('ORCHESTRATION_STATE_INVALID', 'orchestration state has an invalid schema', resolved.taskId);
683
+ }
684
+ }
685
+ const now = (options.now ?? (() => new Date().toISOString()))();
686
+ const failAndPause = (code, message) => {
687
+ if (run?.status === 'running') {
688
+ saveRun(resolved.taskDir, withUpdatedRun(run, {
689
+ status: 'paused', pause: { code, message, recoverable: true }
690
+ }, () => now));
691
+ }
692
+ return commitIntentFailed(code, message, resolved.taskId);
693
+ };
694
+ let orchestration = null;
695
+ if (!input.orchestrated) {
696
+ if (run?.pendingDelegation) {
697
+ return commitIntentFailed('ORCHESTRATION_STANDALONE_BUSY', 'standalone commit is blocked by a pending orchestration delegation', resolved.taskId);
698
+ }
699
+ }
700
+ else {
701
+ if (!run || run.status !== 'running') {
702
+ return commitIntentFailed('ORCHESTRATION_RUN_NOT_RUNNING', 'orchestrated commit requires a running orchestration', resolved.taskId);
703
+ }
704
+ const receipt = run.pendingDelegation;
705
+ if (!receipt
706
+ || receipt.status !== 'activated'
707
+ || receipt.stage !== 'commit'
708
+ || receipt.round !== 1
709
+ || receipt.artifact !== 'commit'
710
+ || receipt.role !== 'executor') {
711
+ return failAndPause('ORCHESTRATION_PROVENANCE_MISMATCH', 'orchestrated commit requires one matching activated commit delegation');
712
+ }
713
+ if (!run.commitAuthorization.issuedAt || run.commitAuthorization.consumedAt) {
714
+ return failAndPause('ORCHESTRATION_COMMIT_AUTHORIZATION_INVALID', 'orchestrated commit requires an unconsumed one-use authorization');
715
+ }
716
+ const planned = planOrchestrationStageCompletion(taskRef, {
717
+ stage: 'commit', round: 1, artifact: 'commit', role: 'executor', agent: input.agent
718
+ }, { ...options, now: () => now });
719
+ if (planned.result.status === 'failed' || !planned.plan?.updatedRun.pendingDelegation) {
720
+ return failAndPause(planned.result.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH', planned.result.error?.message ?? 'commit delegation could not be completed');
721
+ }
722
+ const plannedRunBytes = serialize(planned.plan.updatedRun);
723
+ orchestration = {
724
+ runId: run.runId,
725
+ receiptId: receipt.id,
726
+ authorizationIssuedAt: run.commitAuthorization.issuedAt,
727
+ sourceRunDigest: digest(sourceRunBytes),
728
+ plannedRunDigest: digest(plannedRunBytes),
729
+ completionUpdatedAt: planned.plan.updatedRun.updatedAt,
730
+ plannedReceipt: planned.plan.updatedRun.pendingDelegation
731
+ };
732
+ }
733
+ const created = createCommitIntent(resolved.taskDir, {
734
+ taskId: resolved.taskId,
735
+ mode: input.orchestrated ? 'orchestrated' : 'standalone',
736
+ phase: 'prepared',
737
+ baselineHead: input.baselineHead,
738
+ committedHead: null,
739
+ pushEvidence: null,
740
+ orchestration,
741
+ createdAt: now,
742
+ updatedAt: now
743
+ }, { token: options.token });
744
+ return {
745
+ status: 'ready', changed: true, taskId: resolved.taskId,
746
+ intent: commitIntentView(created.intent, currentHead), token: created.token, error: null
747
+ };
748
+ });
749
+ }
750
+ catch (error) {
751
+ return mapCommitIntentError(error, resolved.taskId);
752
+ }
753
+ }
754
+ function checkpointCommitIntent(taskRef, input, options = {}) {
755
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
756
+ if (!resolved.ok)
757
+ return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
758
+ try {
759
+ const gitRoot = gitRootFor(resolved.repoRoot, options);
760
+ return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-intent.checkpoint', () => {
761
+ const intent = readCommitIntent(resolved.taskDir, resolved.taskId, input.token);
762
+ const currentHead = repositoryHead(gitRoot);
763
+ if (currentHead !== input.head) {
764
+ return commitIntentFailed('ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', 'checkpoint HEAD does not match the repository HEAD', resolved.taskId);
765
+ }
766
+ if (input.kind === 'committed' && !isAncestor(gitRoot, intent.baselineHead, input.head)) {
767
+ return commitIntentFailed('ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', 'committed HEAD does not descend from the baseline', resolved.taskId);
768
+ }
769
+ if (input.kind === 'pushed') {
770
+ const expectedHead = intent.committedHead ?? intent.baselineHead;
771
+ if (input.head !== expectedHead || !input.remote || !input.ref) {
772
+ return commitIntentFailed('ORCHESTRATION_COMMIT_INTENT_STATE_INVALID', 'pushed checkpoint requires matching remote, ref and HEAD', resolved.taskId);
773
+ }
774
+ }
775
+ const now = (options.now ?? (() => new Date().toISOString()))();
776
+ const updated = updateCommitIntent(resolved.taskDir, resolved.taskId, input.token, input.kind === 'committed'
777
+ ? { phase: 'committed', committedHead: input.head, updatedAt: now }
778
+ : {
779
+ phase: 'pushed', committedHead: intent.committedHead ?? intent.baselineHead, updatedAt: now,
780
+ pushEvidence: { remote: input.remote, ref: input.ref, head: input.head }
781
+ });
782
+ return {
783
+ status: 'ready', changed: true, taskId: resolved.taskId,
784
+ intent: commitIntentView(updated, currentHead), error: null
785
+ };
786
+ });
787
+ }
788
+ catch (error) {
789
+ return mapCommitIntentError(error, resolved.taskId);
790
+ }
791
+ }
792
+ function completeCommitOrchestration(resolved, intent, agent) {
793
+ if (intent.orchestration === null)
794
+ return null;
795
+ if (intent.orchestration.plannedReceipt.agent !== agent) {
796
+ return { code: 'ORCHESTRATION_PROVENANCE_MISMATCH', message: 'completion agent does not match the planned receipt' };
797
+ }
798
+ const runFile = orchestrationPath(resolved.taskDir);
799
+ if (!fs.existsSync(runFile)) {
800
+ return { code: 'ORCHESTRATION_RUN_MISSING', message: 'orchestration run disappeared' };
801
+ }
802
+ const currentBytes = fs.readFileSync(runFile, 'utf8');
803
+ const currentDigest = digest(currentBytes);
804
+ if (currentDigest === intent.orchestration.sourceRunDigest) {
805
+ const run = readRun(resolved.taskDir);
806
+ if (!run)
807
+ return { code: 'ORCHESTRATION_RUN_MISSING', message: 'orchestration run disappeared' };
808
+ const plannedRun = Object.freeze({
809
+ ...run,
810
+ pendingDelegation: intent.orchestration.plannedReceipt,
811
+ updatedAt: intent.orchestration.completionUpdatedAt
812
+ });
813
+ if (digest(serialize(plannedRun)) !== intent.orchestration.plannedRunDigest) {
814
+ return { code: 'ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', message: 'planned orchestration bytes no longer match the intent' };
815
+ }
816
+ atomicWrite(runFile, plannedRun);
817
+ if (digest(fs.readFileSync(runFile)) !== intent.orchestration.plannedRunDigest) {
818
+ return { code: 'ORCHESTRATION_COMMIT_COMPLETE_PARTIAL', message: 'orchestration completion could not be verified' };
819
+ }
820
+ }
821
+ else if (currentDigest !== intent.orchestration.plannedRunDigest) {
822
+ return { code: 'ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', message: 'orchestration state changed after commit begin' };
823
+ }
824
+ return null;
825
+ }
826
+ function finalizeCommitIntentUnlocked(resolved, inspection, agent, remove) {
827
+ if (inspection.disposition !== 'recoverable' || !inspection.intent) {
828
+ return commitIntentFailed(inspection.code ?? 'COMMIT_FINALIZATION_PENDING', inspection.message, resolved.taskId);
829
+ }
830
+ if (inspection.intent.orchestration !== null
831
+ && inspection.intent.orchestration.plannedReceipt.agent !== agent) {
832
+ return commitIntentFailed('ORCHESTRATION_PROVENANCE_MISMATCH', 'completion agent does not match the planned receipt', resolved.taskId);
833
+ }
834
+ const metadata = captureTaskWriteMetadata();
835
+ const taskPlan = planCommitTaskFinalization(resolved.taskDir, inspection, agent, metadata.timestamp);
836
+ const written = writeTask({
837
+ taskRef: resolved.taskId,
838
+ expectedState: 'active',
839
+ mutations: taskPlan.mutations
840
+ }, {
841
+ repoRoot: resolved.repoRoot,
842
+ metadataProvider: () => metadata
843
+ });
844
+ if (written.status === 'failed') {
845
+ return commitIntentFailed(written.error.code, written.error.message, resolved.taskId);
846
+ }
847
+ const orchestrationError = completeCommitOrchestration(resolved, inspection.intent, agent);
848
+ if (orchestrationError) {
849
+ return commitIntentFailed(orchestrationError.code, orchestrationError.message, resolved.taskId);
850
+ }
851
+ try {
852
+ remove();
853
+ }
854
+ catch (error) {
855
+ return commitIntentFailed('ORCHESTRATION_COMMIT_COMPLETE_PARTIAL', error instanceof Error ? error.message : String(error), resolved.taskId);
856
+ }
857
+ return { status: 'ready', changed: true, taskId: resolved.taskId, intent: null, error: null };
858
+ }
859
+ function completeCommitIntent(taskRef, input, options = {}) {
860
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
861
+ if (!resolved.ok)
862
+ return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
863
+ try {
864
+ const gitRoot = gitRootFor(resolved.repoRoot, options);
865
+ return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-intent.complete', () => {
866
+ readCommitIntent(resolved.taskDir, resolved.taskId, input.token);
867
+ const inspection = inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId);
868
+ return finalizeCommitIntentUnlocked(resolved, inspection, input.agent, () => {
869
+ removeCommitIntent(resolved.taskDir, resolved.taskId, input.token);
870
+ });
871
+ });
872
+ }
873
+ catch (error) {
874
+ return mapCommitIntentError(error, resolved.taskId);
875
+ }
876
+ }
877
+ function recoverCommitIntent(taskRef, input, options = {}) {
878
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
879
+ if (!resolved.ok)
880
+ return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
881
+ try {
882
+ const gitRoot = gitRootFor(resolved.repoRoot, options);
883
+ return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'commit-intent.recover', () => {
884
+ const inspection = inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId);
885
+ if (inspection.disposition === 'retryable-start') {
886
+ return {
887
+ status: 'ready', changed: false, taskId: resolved.taskId, intent: null,
888
+ finalization: commitFinalizationView(inspection), error: null
889
+ };
890
+ }
891
+ if (inspection.disposition === 'prepared' && inspection.intentDigest) {
892
+ removeCommitIntentByDigest(resolved.taskDir, resolved.taskId, inspection.intentDigest);
893
+ return { status: 'ready', changed: true, taskId: resolved.taskId, intent: null, error: null };
894
+ }
895
+ if (!inspection.intentDigest) {
896
+ return commitIntentFailed(inspection.code ?? 'COMMIT_FINALIZATION_EVIDENCE_MISSING', inspection.message, resolved.taskId);
897
+ }
898
+ return finalizeCommitIntentUnlocked(resolved, inspection, input.agent, () => {
899
+ removeCommitIntentByDigest(resolved.taskDir, resolved.taskId, inspection.intentDigest);
900
+ });
901
+ });
902
+ }
903
+ catch (error) {
904
+ return mapCommitIntentError(error, resolved.taskId);
905
+ }
906
+ }
907
+ function abortCommitIntent(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.abort', () => {
914
+ const intent = readCommitIntent(resolved.taskDir, resolved.taskId, input.token);
915
+ const currentHead = repositoryHead(gitRoot);
916
+ if (intent.phase !== 'prepared'
917
+ || intent.pushEvidence !== null
918
+ || input.expectedHead !== intent.baselineHead
919
+ || currentHead !== intent.baselineHead) {
920
+ return commitIntentFailed('ORCHESTRATION_COMMIT_RECOVERY_REQUIRED', 'commit intent has side effects or repository drift', resolved.taskId);
921
+ }
922
+ removeCommitIntent(resolved.taskDir, resolved.taskId, input.token);
923
+ return { status: 'ready', changed: true, taskId: resolved.taskId, intent: null, error: null };
924
+ });
925
+ }
926
+ catch (error) {
927
+ return mapCommitIntentError(error, resolved.taskId);
928
+ }
929
+ }
930
+ function statusCommitIntent(taskRef, options = {}) {
931
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
932
+ if (!resolved.ok)
933
+ return commitIntentFailed(resolved.code, resolved.message, resolved.taskId);
934
+ let gitRoot;
935
+ try {
936
+ gitRoot = gitRootFor(resolved.repoRoot, options);
937
+ }
938
+ catch (error) {
939
+ return commitIntentFailed('ORCHESTRATION_WORKTREE_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
940
+ }
941
+ const inspection = inspectCommitFinalization(resolved.taskDir, gitRoot, resolved.taskId);
942
+ return {
943
+ status: 'ready',
944
+ changed: false,
945
+ taskId: resolved.taskId,
946
+ intent: inspection.intent ? commitIntentView(inspection.intent, inspection.currentHead) : null,
947
+ finalization: commitFinalizationView(inspection),
948
+ error: null
949
+ };
950
+ }
479
951
  function statusOrchestration(taskRef, options = {}) {
480
952
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
481
953
  if (!resolved.ok)
@@ -489,6 +961,15 @@ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
489
961
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
490
962
  if (!resolved.ok)
491
963
  return failed(resolved.code, resolved.message, resolved.taskId);
964
+ if (fs.existsSync(commitIntentPath(resolved.taskDir))) {
965
+ try {
966
+ readCommitIntent(resolved.taskDir, resolved.taskId);
967
+ }
968
+ catch (error) {
969
+ return failed('ORCHESTRATION_COMMIT_INTENT_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
970
+ }
971
+ return failed('ORCHESTRATION_COMMIT_INTENT_BUSY', 'an active commit intent blocks delegation preparation', resolved.taskId);
972
+ }
492
973
  if (!(options.supportsLifecycleDelegation ?? supportsLifecycleDelegation)(input.client)) {
493
974
  return failed('ORCHESTRATION_CLIENT_UNSUPPORTED', `client '${input.client}' does not support lifecycle orchestration`, resolved.taskId);
494
975
  }
@@ -499,8 +980,7 @@ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
499
980
  return failed('ORCHESTRATION_MODEL_EVIDENCE_MISSING', 'running orchestration has no persisted model policy', resolved.taskId);
500
981
  if (run.pendingDelegation)
501
982
  return failed('ORCHESTRATION_DELEGATION_BUSY', 'the run already has a pending delegation', resolved.taskId);
502
- const repositoryPending = ['claude-code', 'codex']
503
- .flatMap((client) => matchingDelegations(client, () => true, options));
983
+ const repositoryPending = matchingDelegations(() => true, options);
504
984
  if (repositoryPending.length > 0) {
505
985
  return failed('ORCHESTRATION_DELEGATION_BUSY', 'the repository already has a pending lifecycle delegation', resolved.taskId);
506
986
  }
@@ -525,7 +1005,11 @@ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
525
1005
  }
526
1006
  let beforeFingerprint;
527
1007
  try {
528
- beforeFingerprint = (options.captureWorkspace ?? captureWorkspaceSnapshot)(resolved.repoRoot, resolved.taskId);
1008
+ beforeFingerprint = (options.captureWorkspace ?? captureWorkspaceSnapshot)({
1009
+ gitRoot: gitRootFor(resolved.repoRoot, options),
1010
+ stateRoot: resolved.repoRoot,
1011
+ taskId: resolved.taskId
1012
+ });
529
1013
  }
530
1014
  catch (error) {
531
1015
  return failed('ORCHESTRATION_SNAPSHOT_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
@@ -558,7 +1042,7 @@ function prepareOrchestrationDelegation(taskRef, input, options = {}) {
558
1042
  if (!resolved.ok)
559
1043
  return failed(resolved.code, resolved.message, resolved.taskId);
560
1044
  try {
561
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-orchestration.prepare', () => prepareOrchestrationDelegationUnlocked(taskRef, input, options));
1045
+ return withTaskExecutionLock(resolved.repoRoot, '__repository__', 'task-orchestration.prepare.repository', () => withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-orchestration.prepare.task', () => prepareOrchestrationDelegationUnlocked(taskRef, input, options)));
562
1046
  }
563
1047
  catch (error) {
564
1048
  if (error instanceof TaskExecutionLockError)
@@ -566,7 +1050,7 @@ function prepareOrchestrationDelegation(taskRef, input, options = {}) {
566
1050
  throw error;
567
1051
  }
568
1052
  }
569
- function matchingDelegations(client, predicate, options) {
1053
+ function matchingDelegations(predicate, options) {
570
1054
  const repoRoot = options.repoRoot ?? process.cwd();
571
1055
  const activeRoot = path.join(repoRoot, '.agents', 'workspace', 'active');
572
1056
  if (!fs.existsSync(activeRoot))
@@ -578,13 +1062,13 @@ function matchingDelegations(client, predicate, options) {
578
1062
  if (!run?.pendingDelegation)
579
1063
  return [];
580
1064
  const receipt = run.pendingDelegation;
581
- return receipt.client === client && predicate(receipt)
1065
+ return predicate(receipt)
582
1066
  ? [{ taskId: entry.name, run }]
583
1067
  : [];
584
1068
  });
585
1069
  }
586
1070
  function uniqueMatchingDelegation(client, predicate, options) {
587
- const matches = matchingDelegations(client, predicate, options);
1071
+ const matches = matchingDelegations((receipt) => receipt.client === client && predicate(receipt), options);
588
1072
  if (matches.length === 0)
589
1073
  return failed('ORCHESTRATION_DELEGATION_MISSING', 'no matching lifecycle delegation exists');
590
1074
  if (matches.length > 1)
@@ -616,9 +1100,14 @@ function sealMatchingOrchestrationDelegation(client, event, options = {}) {
616
1100
  }
617
1101
  const repoRoot = options.repoRoot ?? process.cwd();
618
1102
  try {
1103
+ const gitRoot = gitRootFor(repoRoot, options);
619
1104
  const snapshotTaskId = receipt.workspaceSnapshotScope === 'task' ? receipt.taskId : null;
620
- const afterFingerprint = (options.captureWorkspace ?? captureWorkspaceSnapshot)(repoRoot, snapshotTaskId);
621
- const changedPaths = (options.diffWorkspace ?? diffWorkspaceSnapshots)(repoRoot, receipt.beforeFingerprint, afterFingerprint);
1105
+ const afterFingerprint = (options.captureWorkspace ?? captureWorkspaceSnapshot)({
1106
+ gitRoot,
1107
+ stateRoot: repoRoot,
1108
+ taskId: snapshotTaskId
1109
+ });
1110
+ const changedPaths = (options.diffWorkspace ?? diffWorkspaceSnapshots)(gitRoot, receipt.beforeFingerprint, afterFingerprint);
622
1111
  return sealOrchestrationDelegation(matched.taskId, {
623
1112
  childId: event.childId,
624
1113
  exitCode: 0,
@@ -700,7 +1189,7 @@ function planOrchestrationStageCompletion(taskRef, event, options = {}) {
700
1189
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
701
1190
  if (!resolved.ok)
702
1191
  return { result: failed(resolved.code, resolved.message, resolved.taskId), plan: null };
703
- const updatedRun = withUpdatedRun(inspected.run, { pendingDelegation: completed.receipt });
1192
+ const updatedRun = withUpdatedRun(inspected.run, { pendingDelegation: completed.receipt }, options.now);
704
1193
  return {
705
1194
  result: { status: 'running', changed: true, taskId: resolved.taskId, run: updatedRun, next: null, error: null },
706
1195
  plan: {
@@ -713,24 +1202,6 @@ function planOrchestrationStageCompletion(taskRef, event, options = {}) {
713
1202
  function commitOrchestrationStageCompletion(plan) {
714
1203
  saveRun(plan.taskDir, plan.updatedRun);
715
1204
  }
716
- function completeCommitOrchestrationStage(taskRef, agent, options = {}) {
717
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
718
- if (!resolved.ok)
719
- return failed(resolved.code, resolved.message, resolved.taskId);
720
- const run = readRun(resolved.taskDir);
721
- if (!run)
722
- return { status: 'running', changed: false, taskId: resolved.taskId, run: null, next: null, error: null };
723
- const receipt = run.pendingDelegation;
724
- if (!receipt || receipt.stage !== 'commit') {
725
- return failed('ORCHESTRATION_DELEGATION_MISSING', 'active run has no pending commit delegation', resolved.taskId);
726
- }
727
- return completeOrchestrationStage(taskRef, {
728
- stage: receipt.stage,
729
- round: receipt.round,
730
- artifact: receipt.artifact,
731
- agent
732
- }, options);
733
- }
734
1205
  function sealOrchestrationDelegation(taskRef, event, options = {}) {
735
1206
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
736
1207
  if (!resolved.ok)
@@ -780,5 +1251,5 @@ function pauseOrchestration(taskRef, code, message, recoverable, options = {}) {
780
1251
  saveRun(resolved.taskDir, updated);
781
1252
  return { status: 'paused', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
782
1253
  }
783
- export { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, advanceOrchestration, beginOrResumeOrchestration, commitOrchestrationStageCompletion, completeCommitOrchestrationStage, completeOrchestrationStage, inspectOrchestrationStage, orchestrationPath, pauseOrchestration, planOrchestrationStageCompletion, prepareOrchestrationDelegation, readRun, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, statusOrchestration };
1254
+ export { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, advanceOrchestration, abortCommitIntent, beginCommitIntent, beginOrResumeOrchestration, checkpointCommitIntent, commitOrchestrationStageCompletion, completeCommitIntent, completeOrchestrationStage, inspectOrchestrationStage, orchestrationPath, pauseOrchestration, planOrchestrationStageCompletion, prepareOrchestrationDelegation, readRun, recoverCommitIntent, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, startCommitAttempt, statusCommitIntent, statusOrchestration, terminateCommitAttempt };
784
1255
  //# sourceMappingURL=orchestration.js.map