@fitlab-ai/agent-infra 0.11.14 → 0.12.0

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 (271) hide show
  1. package/bin/cli.ts +1 -1
  2. package/dist/bin/cli.js +1 -1
  3. package/dist/bin/internal-cli.js +6 -1
  4. package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +6 -6
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +8 -18
  6. package/dist/lib/agent-clients/adapters/codex-orchestration.js +1 -1
  7. package/dist/lib/decide.js +2 -7
  8. package/dist/lib/internal/cli-route-inventory.js +3 -0
  9. package/dist/lib/internal/manual-validation.js +8 -16
  10. package/dist/lib/internal/platform-comment.js +3 -2
  11. package/dist/lib/internal/task-activity.js +1 -12
  12. package/dist/lib/internal/task-event.js +1 -12
  13. package/dist/lib/internal/task-finalization.js +2 -2
  14. package/dist/lib/internal/task-ledger.js +1 -12
  15. package/dist/lib/internal/task-operation-registry.js +2 -1
  16. package/dist/lib/internal/task-qualification.js +6 -15
  17. package/dist/lib/internal/task-review.js +3 -16
  18. package/dist/lib/internal/task-short-id.js +2 -1
  19. package/dist/lib/internal/task-verify.js +1 -11
  20. package/dist/lib/internal/task-warning.js +1 -12
  21. package/dist/lib/internal/task-workspace.js +43 -0
  22. package/dist/lib/merge.js +4 -3
  23. package/dist/lib/platform/pr-change-report.js +10 -3
  24. package/dist/lib/platform/pr-summary.js +6 -15
  25. package/dist/lib/platform/pull-requests.js +3 -15
  26. package/dist/lib/pr-review/evidence-grading.js +3 -2
  27. package/dist/lib/process-data/index.js +18 -6
  28. package/dist/lib/process-data/sources.js +6 -0
  29. package/dist/lib/run/index.js +3 -2
  30. package/dist/lib/sandbox/commands/create.js +5 -1
  31. package/dist/lib/sandbox/commands/enter.js +1 -1
  32. package/dist/lib/sandbox/commands/list-running.js +2 -1
  33. package/dist/lib/sandbox/control/client.js +8 -13
  34. package/dist/lib/sandbox/control/completed-reentry.js +2 -1
  35. package/dist/lib/sandbox/control/lifecycle.js +2 -21
  36. package/dist/lib/sandbox/control/task-view.js +4 -2
  37. package/dist/lib/sandbox/mounts.js +4 -4
  38. package/dist/lib/sandbox/recovery.js +26 -16
  39. package/dist/lib/sandbox/removal.js +3 -10
  40. package/dist/lib/sandbox/task-resolver.js +9 -6
  41. package/dist/lib/sandbox/workspace-identity.js +36 -20
  42. package/dist/lib/sandbox/workspace-view.js +29 -22
  43. package/dist/lib/task/activity-intent.js +2 -12
  44. package/dist/lib/task/artifact-lifecycle.js +17 -11
  45. package/dist/lib/task/artifact-operations.js +41 -49
  46. package/dist/lib/task/capabilities.js +2 -2
  47. package/dist/lib/task/commands/ls.js +4 -3
  48. package/dist/lib/task/commands/status.js +1 -1
  49. package/dist/lib/task/commit-operation.js +6 -6
  50. package/dist/lib/task/control-authority.js +32 -32
  51. package/dist/lib/task/create-service.js +2 -4
  52. package/dist/lib/task/create.js +12 -65
  53. package/dist/lib/task/delegation-receipts.js +1 -1
  54. package/dist/lib/task/delivery.js +2 -8
  55. package/dist/lib/task/events.js +5 -31
  56. package/dist/lib/task/finalization.js +17 -22
  57. package/dist/lib/task/lifecycle.js +38 -49
  58. package/dist/lib/task/local-artifact-finalization.js +1 -2
  59. package/dist/lib/task/orchestration.js +24 -57
  60. package/dist/lib/task/platform-operation-recovery.js +1 -2
  61. package/dist/lib/task/resolve-ref.js +17 -12
  62. package/dist/lib/task/review-finalization.js +2 -35
  63. package/dist/lib/task/review-identity.js +3 -1
  64. package/dist/lib/task/short-id.js +12 -10
  65. package/dist/lib/task/verification-engine.js +19 -58
  66. package/dist/lib/task/workspace-root.js +59 -0
  67. package/dist/lib/task/workspace-snapshot.js +4 -3
  68. package/dist/lifecycle-build-manifest.json +3 -3
  69. package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +6 -6
  70. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +8 -34
  71. package/lib/agent-clients/adapters/codex-orchestration.ts +1 -1
  72. package/lib/decide.ts +2 -7
  73. package/lib/internal/cli-route-inventory.ts +2 -0
  74. package/lib/internal/manual-validation.ts +8 -19
  75. package/lib/internal/platform-comment.ts +3 -2
  76. package/lib/internal/task-activity.ts +1 -10
  77. package/lib/internal/task-event.ts +1 -10
  78. package/lib/internal/task-finalization.ts +2 -2
  79. package/lib/internal/task-ledger.ts +1 -10
  80. package/lib/internal/task-operation-registry.ts +2 -1
  81. package/lib/internal/task-qualification.ts +5 -11
  82. package/lib/internal/task-review.ts +3 -14
  83. package/lib/internal/task-short-id.ts +2 -1
  84. package/lib/internal/task-verify.ts +1 -9
  85. package/lib/internal/task-warning.ts +1 -10
  86. package/lib/internal/task-workspace.ts +39 -0
  87. package/lib/merge.ts +4 -3
  88. package/lib/platform/pr-change-report.ts +9 -3
  89. package/lib/platform/pr-summary.ts +7 -16
  90. package/lib/platform/pull-requests.ts +3 -24
  91. package/lib/pr-review/evidence-grading.ts +3 -2
  92. package/lib/process-data/index.ts +17 -5
  93. package/lib/process-data/sources.ts +6 -0
  94. package/lib/run/index.ts +3 -2
  95. package/lib/sandbox/commands/create.ts +5 -1
  96. package/lib/sandbox/commands/enter.ts +1 -1
  97. package/lib/sandbox/commands/list-running.ts +2 -1
  98. package/lib/sandbox/control/client.ts +7 -12
  99. package/lib/sandbox/control/completed-reentry.ts +2 -1
  100. package/lib/sandbox/control/lifecycle.ts +4 -21
  101. package/lib/sandbox/control/task-view.ts +4 -2
  102. package/lib/sandbox/mounts.ts +4 -4
  103. package/lib/sandbox/recovery.ts +26 -18
  104. package/lib/sandbox/removal.ts +3 -26
  105. package/lib/sandbox/task-resolver.ts +9 -6
  106. package/lib/sandbox/workspace-identity.ts +42 -18
  107. package/lib/sandbox/workspace-view.ts +28 -20
  108. package/lib/task/activity-intent.ts +3 -17
  109. package/lib/task/artifact-lifecycle.ts +39 -11
  110. package/lib/task/artifact-operations.ts +28 -35
  111. package/lib/task/capabilities.ts +2 -2
  112. package/lib/task/commands/ls.ts +4 -3
  113. package/lib/task/commands/status.ts +1 -1
  114. package/lib/task/commit-operation.ts +5 -6
  115. package/lib/task/control-authority.ts +29 -35
  116. package/lib/task/create-service.ts +2 -4
  117. package/lib/task/create.ts +10 -51
  118. package/lib/task/delegation-receipts.ts +1 -1
  119. package/lib/task/delivery.ts +2 -10
  120. package/lib/task/events.ts +5 -32
  121. package/lib/task/finalization.ts +16 -24
  122. package/lib/task/lifecycle.ts +40 -51
  123. package/lib/task/local-artifact-finalization.ts +1 -4
  124. package/lib/task/orchestration.ts +31 -80
  125. package/lib/task/platform-operation-recovery.ts +1 -2
  126. package/lib/task/resolve-ref.ts +18 -12
  127. package/lib/task/review-finalization.ts +2 -52
  128. package/lib/task/review-identity.ts +3 -1
  129. package/lib/task/short-id.ts +15 -10
  130. package/lib/task/verification-engine.ts +20 -62
  131. package/lib/task/workspace-root.ts +78 -0
  132. package/lib/task/workspace-snapshot.ts +4 -3
  133. package/package.json +1 -1
  134. package/templates/.agents/QUICKSTART.en.md +19 -8
  135. package/templates/.agents/QUICKSTART.zh-CN.md +19 -8
  136. package/templates/.agents/README.en.md +10 -15
  137. package/templates/.agents/README.zh-CN.md +9 -13
  138. package/templates/.agents/rules/issue-sync.en.md +1 -1
  139. package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
  140. package/templates/.agents/rules/lifecycle-orchestration.en.md +1 -1
  141. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +1 -1
  142. package/templates/.agents/rules/next-step-output.en.md +2 -2
  143. package/templates/.agents/rules/next-step-output.zh-CN.md +2 -2
  144. package/templates/.agents/rules/pr-sync.en.md +1 -1
  145. package/templates/.agents/rules/pr-sync.zh-CN.md +1 -1
  146. package/templates/.agents/rules/release-commands.en.md +3 -0
  147. package/templates/.agents/rules/release-commands.zh-CN.md +3 -0
  148. package/templates/.agents/rules/task-management.en.md +0 -2
  149. package/templates/.agents/rules/task-management.zh-CN.md +0 -2
  150. package/templates/.agents/rules/task-short-id.en.md +2 -2
  151. package/templates/.agents/rules/task-short-id.zh-CN.md +2 -2
  152. package/templates/.agents/scripts/task-short-id.js +2 -8
  153. package/templates/.agents/skills/analyze-task/SKILL.en.md +6 -6
  154. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +6 -6
  155. package/templates/.agents/skills/analyze-task/config/verify.en.json +0 -1
  156. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +0 -1
  157. package/templates/.agents/skills/archive-tasks/SKILL.en.md +5 -5
  158. package/templates/.agents/skills/archive-tasks/SKILL.zh-CN.md +5 -5
  159. package/templates/.agents/skills/archive-tasks/scripts/archive-tasks.sh +10 -2
  160. package/templates/.agents/skills/block-task/SKILL.en.md +4 -4
  161. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +5 -5
  162. package/templates/.agents/skills/block-task/config/verify.json +0 -1
  163. package/templates/.agents/skills/cancel-task/SKILL.en.md +6 -6
  164. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +6 -6
  165. package/templates/.agents/skills/cancel-task/config/verify.json +0 -1
  166. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  167. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +3 -3
  168. package/templates/.agents/skills/code-task/config/verify.en.json +0 -1
  169. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +0 -1
  170. package/templates/.agents/skills/code-task/reference/output-template.en.md +1 -1
  171. package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +1 -1
  172. package/templates/.agents/skills/commit/SKILL.en.md +1 -1
  173. package/templates/.agents/skills/commit/SKILL.zh-CN.md +1 -1
  174. package/templates/.agents/skills/commit/config/verify.json +0 -1
  175. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +2 -2
  176. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +2 -2
  177. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
  178. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
  179. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +2 -2
  180. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +2 -2
  181. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +0 -1
  182. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +0 -1
  183. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
  184. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
  185. package/templates/.agents/skills/complete-task/SKILL.en.md +17 -9
  186. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +18 -10
  187. package/templates/.agents/skills/complete-task/config/verify.en.json +0 -1
  188. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +0 -1
  189. package/templates/.agents/skills/create-pr/SKILL.en.md +3 -3
  190. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +3 -3
  191. package/templates/.agents/skills/create-pr/config/verify.json +0 -1
  192. package/templates/.agents/skills/create-pr/reference/change-report.en.md +13 -3
  193. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +13 -3
  194. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
  195. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
  196. package/templates/.agents/skills/create-release-note/SKILL.en.md +2 -2
  197. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +2 -2
  198. package/templates/.agents/skills/create-task/SKILL.en.md +4 -4
  199. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +4 -4
  200. package/templates/.agents/skills/create-task/config/verify.json +0 -1
  201. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  202. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  203. package/templates/.agents/skills/import-codescan/config/verify.json +0 -1
  204. package/templates/.agents/skills/import-dependabot/SKILL.en.md +3 -3
  205. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +3 -3
  206. package/templates/.agents/skills/import-dependabot/config/verify.json +0 -1
  207. package/templates/.agents/skills/import-issue/SKILL.en.md +5 -5
  208. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -5
  209. package/templates/.agents/skills/import-issue/config/verify.json +0 -1
  210. package/templates/.agents/skills/plan-task/SKILL.en.md +5 -5
  211. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -5
  212. package/templates/.agents/skills/plan-task/config/verify.en.json +0 -1
  213. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +0 -1
  214. package/templates/.agents/skills/restore-task/SKILL.en.md +2 -2
  215. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +3 -3
  216. package/templates/.agents/skills/restore-task/config/verify.json +0 -1
  217. package/templates/.agents/skills/review-analysis/SKILL.en.md +1 -1
  218. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
  219. package/templates/.agents/skills/review-analysis/config/verify.en.json +0 -1
  220. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +0 -1
  221. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +5 -5
  222. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +5 -5
  223. package/templates/.agents/skills/review-code/SKILL.en.md +2 -2
  224. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
  225. package/templates/.agents/skills/review-code/reference/output-templates.en.md +4 -4
  226. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +4 -4
  227. package/templates/.agents/skills/review-plan/SKILL.en.md +1 -1
  228. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
  229. package/templates/.agents/skills/review-plan/config/verify.en.json +0 -1
  230. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +0 -1
  231. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +5 -5
  232. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +5 -5
  233. package/templates/.agents/skills/review-pr/SKILL.en.md +2 -2
  234. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +2 -2
  235. package/templates/.agents/skills/review-pr/config/verify.en.json +0 -1
  236. package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +0 -1
  237. package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +1 -1
  238. package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +1 -1
  239. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +5 -5
  240. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +5 -5
  241. package/templates/.agents/skills/run-manual-validation/config/verify.en.json +0 -1
  242. package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +0 -1
  243. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +13 -2
  244. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +13 -2
  245. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +2 -0
  246. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +2 -0
  247. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  248. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  249. package/templates/.agents/skills/test/SKILL.en.md +0 -3
  250. package/templates/.agents/skills/test/SKILL.zh-CN.md +0 -3
  251. package/templates/.agents/skills/test-integration/SKILL.en.md +0 -3
  252. package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +0 -3
  253. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +13 -6
  254. package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +0 -3
  255. package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +0 -3
  256. package/templates/.agents/skills/watch-pr/SKILL.en.md +21 -4
  257. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +22 -5
  258. package/templates/.agents/skills/watch-pr/config/verify.json +0 -1
  259. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +14 -0
  260. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +15 -1
  261. package/templates/.agents/templates/handoff.en.md +1 -1
  262. package/templates/.agents/templates/handoff.zh-CN.md +1 -1
  263. package/templates/.agents/workflows/bug-fix.en.yaml +1 -1
  264. package/templates/.agents/workflows/feature-development.en.yaml +1 -1
  265. package/templates/.agents/workflows/refactoring.en.yaml +1 -1
  266. package/dist/lib/runtime/agent-runtime.js +0 -33
  267. package/dist/lib/task/runtime-paths.js +0 -10
  268. package/dist/lib/task/task-execution-lock.js +0 -250
  269. package/lib/runtime/agent-runtime.ts +0 -41
  270. package/lib/task/runtime-paths.ts +0 -12
  271. package/lib/task/task-execution-lock.ts +0 -320
@@ -31,7 +31,6 @@ import { findSectionHeading } from './sections.ts';
31
31
  import { validateLifecycleExecution } from './lifecycle-execution.ts';
32
32
  import { commitOrchestrationStageCompletion } from './orchestration.ts';
33
33
  import type { OrchestrationStageCompletion } from './orchestration.ts';
34
- import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.ts';
35
34
  import { captureTaskWriteMetadata, writeTask } from './write.ts';
36
35
  import type { TaskOperationSummary, TaskWriteErrorCode, TaskWriteOptions } from './write.ts';
37
36
  import { validateLocalArtifact } from './local-artifact-finalization.ts';
@@ -86,7 +85,6 @@ type TaskEventRequest = {
86
85
  type TaskEventError = { code: TaskEventErrorCode; message: string };
87
86
  type TaskEventOptions = TaskWriteOptions & {
88
87
  commitOrchestrationCompletion?: (plan: OrchestrationStageCompletion) => void;
89
- lockAlreadyHeld?: boolean;
90
88
  };
91
89
  type TaskEventResult = {
92
90
  status: 'planned' | 'applied' | 'no-op' | 'failed'; changed: boolean;
@@ -519,6 +517,7 @@ function reworkIntentMutationForCompletion(
519
517
  function buildCompletionReceipt(
520
518
  content: string,
521
519
  taskDir: string,
520
+ repositoryRoot: string | undefined,
522
521
  family: EventFamily,
523
522
  artifact: ArtifactIdentity,
524
523
  completedAt: string,
@@ -527,7 +526,7 @@ function buildCompletionReceipt(
527
526
  ): { ok: true; receipts: readonly ArtifactReceipt[] } | { ok: false; message: string } | null {
528
527
  if (!['analyze', 'plan', 'code'].includes(family) && !family.startsWith('review-')) return null;
529
528
  if (family === 'review-code') {
530
- const identity = inspectReviewIdentity(taskDir, fs.readFileSync(artifact.path, 'utf8'));
529
+ const identity = inspectReviewIdentity(taskDir, fs.readFileSync(artifact.path, 'utf8'), repositoryRoot);
531
530
  if (identity.status !== 'matched') return { ok: false, message: `review-code identity is ${identity.status}: ${identity.message}` };
532
531
  }
533
532
  const event = family === 'analyze' ? 'analysis.completed'
@@ -627,7 +626,7 @@ function replaceCompletionFact(facts: readonly CompletionFact[], next: Completio
627
626
  return [...facts.filter((fact) => !(fact.event === next.event && fact.output === next.output)), next];
628
627
  }
629
628
 
630
- function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOptions = {}): TaskEventResult {
629
+ function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {}): TaskEventResult {
631
630
  const invalid = validateTaskEventRequest(request);
632
631
  if (invalid) return failed(request, invalid);
633
632
  const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
@@ -757,7 +756,7 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
757
756
  }
758
757
  if (eventIdentity.phase === 'started') {
759
758
  const trigger = eventTrigger(normalized, eventIdentity.family);
760
- const facts = buildLifecycleFacts(resolved.taskDir, content, resolved.state);
759
+ const facts = buildLifecycleFacts(resolved.taskDir, content, resolved.state, false, resolved.repoRoot);
761
760
  if (!facts.ok) return failed(normalized, { code: 'EVENT_TRANSITION_INVALID', message: `${facts.code}: ${facts.message}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
762
761
  const capability = canStart(lifecycleAction(eventIdentity.family), facts.facts, trigger);
763
762
  const safetyFailure = capability.reasonCode === 'TASK_NOT_ACTIVE'
@@ -804,7 +803,7 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
804
803
  let currentFact: CompletionFact | null = null;
805
804
  let completionRework: ReturnType<typeof reworkIntentMutation> | null = null;
806
805
  if (eventIdentity.phase === 'completed' && completedArtifact) {
807
- const receipt = buildCompletionReceipt(content, resolved.taskDir, eventIdentity.family, completedArtifact, metadata.timestamp, frontmatter, normalized);
806
+ const receipt = buildCompletionReceipt(content, resolved.taskDir, resolved.repoRoot, eventIdentity.family, completedArtifact, metadata.timestamp, frontmatter, normalized);
808
807
  if (receipt && !receipt.ok) {
809
808
  return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: receipt.message }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
810
809
  }
@@ -978,32 +977,6 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
978
977
  };
979
978
  }
980
979
 
981
- function applyTaskEvent(request: TaskEventRequest, options: TaskEventOptions = {}): TaskEventResult {
982
- const invalid = validateTaskEventRequest(request);
983
- if (invalid) return failed(request, invalid);
984
- const parts = eventParts(request.event);
985
- if (options.lockAlreadyHeld) return applyTaskEventUnlocked(request, options);
986
- if (request.dryRun || !['started', 'completed'].includes(parts.phase)) {
987
- return applyTaskEventUnlocked(request, options);
988
- }
989
- const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
990
- if (!resolved.ok) return applyTaskEventUnlocked(request, options);
991
- try {
992
- return withTaskExecutionLock(
993
- resolved.repoRoot,
994
- resolved.taskId,
995
- `task-event.${request.event}`,
996
- () => applyTaskEventUnlocked(request, { ...options, lockAlreadyHeld: true })
997
- );
998
- } catch (error) {
999
- if (!(error instanceof TaskExecutionLockError)) throw error;
1000
- return failed(request, {
1001
- code: 'EVENT_TRANSITION_INVALID',
1002
- message: `${error.code}: ${error.message}`
1003
- }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
1004
- }
1005
- }
1006
-
1007
980
  function successNoOp(
1008
981
  request: TaskEventRequest, taskId: string, taskMdPath: string, currentStep: string,
1009
982
  eventIdentity: ReturnType<typeof identity>, timestamp: string,
@@ -14,7 +14,6 @@ import { parseTaskFrontmatter } from './frontmatter.ts';
14
14
  import { recoverPlatformOperations } from './platform-operation-recovery.ts';
15
15
  import {
16
16
  applyTaskLifecycle,
17
- applyTaskLifecycleWithinTaskLock,
18
17
  inspectTaskLifecycleProgress,
19
18
  type TaskLifecycleOptions,
20
19
  type TaskLifecycleRequest,
@@ -24,7 +23,6 @@ import {
24
23
  } from './lifecycle.ts';
25
24
  import { enumerateAllTaskDirs, resolveTaskRef } from './resolve-ref.ts';
26
25
  import { inspectShortIdRegistry } from './short-id.ts';
27
- import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.ts';
28
26
  import { verifyTaskEvent } from './verification.ts';
29
27
  import type { TaskVerificationResult } from './verification.ts';
30
28
  import { projectFinalizationWarning } from './workflow-warning-intents.ts';
@@ -586,7 +584,7 @@ function mutationPatch(current: TaskFinalizationReceipt, mutation: FinalizationM
586
584
  : { warningProjection: 'pending', lastError: mutation.error };
587
585
  }
588
586
 
589
- function applyFinalizationReceiptMutationUnderLock(
587
+ function mutateFinalizationReceipt(
590
588
  repoRoot: string,
591
589
  receipt: TaskFinalizationReceipt,
592
590
  capability: FinalizationCapability,
@@ -615,9 +613,7 @@ function applyFinalizationReceiptMutation(
615
613
  if (!hasFinalizationTaskDocument(repoRoot, receipt.taskId)) {
616
614
  throw capabilityError('FINALIZATION_SCOPE_INVALID', 'finalization capability requires an active task or a completed task');
617
615
  }
618
- return withTaskExecutionLock(repoRoot, receipt.taskId, 'task-finalization.receipt-mutation', () =>
619
- applyFinalizationReceiptMutationUnderLock(repoRoot, receipt, capability, mutation, new Set<string>())
620
- );
616
+ return mutateFinalizationReceipt(repoRoot, receipt, capability, mutation, new Set<string>());
621
617
  }
622
618
 
623
619
  function warningKey(warning: Pick<FinalizationWarning, 'step' | 'code' | 'target'>): string {
@@ -640,20 +636,20 @@ function reconcileWarningProjection(repoRoot: string, taskId: string, receipt: T
640
636
  retryable: true
641
637
  };
642
638
  const capability = issueCapability(receipt, 'warning-projection');
643
- return applyFinalizationReceiptMutationUnderLock(repoRoot, receipt, capability, { scope: 'warning-projection', operation: 'failed', error: detail }, consumed);
639
+ return mutateFinalizationReceipt(repoRoot, receipt, capability, { scope: 'warning-projection', operation: 'failed', error: detail }, consumed);
644
640
  }
645
641
  } catch (error) {
646
642
  const detail = errorOf(error, 'FINALIZATION_WARNING_PROJECTION_FAILED', true);
647
643
  try {
648
644
  const capability = issueCapability(receipt, 'warning-projection');
649
- return applyFinalizationReceiptMutationUnderLock(repoRoot, receipt, capability, { scope: 'warning-projection', operation: 'failed', error: detail }, consumed);
645
+ return mutateFinalizationReceipt(repoRoot, receipt, capability, { scope: 'warning-projection', operation: 'failed', error: detail }, consumed);
650
646
  }
651
647
  catch { return receipt; }
652
648
  }
653
649
  }
654
650
  try {
655
651
  const capability = issueCapability(receipt, 'warning-projection');
656
- return applyFinalizationReceiptMutationUnderLock(repoRoot, receipt, capability, { scope: 'warning-projection', operation: 'succeeded' }, consumed);
652
+ return mutateFinalizationReceipt(repoRoot, receipt, capability, { scope: 'warning-projection', operation: 'succeeded' }, consumed);
657
653
  }
658
654
  catch { return receipt; }
659
655
  }
@@ -692,7 +688,7 @@ async function syncPendingTaskComment(input: {
692
688
  if (result.status === 'applied' || result.status === 'no-op') {
693
689
  const skipped = result.error?.code === 'ISSUE_NOT_LINKED';
694
690
  const capability = issueCapability(receipt, 'task-comment');
695
- receipt = applyFinalizationReceiptMutationUnderLock(repoRoot, receipt, capability, {
691
+ receipt = mutateFinalizationReceipt(repoRoot, receipt, capability, {
696
692
  scope: 'task-comment', operation: 'succeeded', state: skipped ? 'skipped' : 'done'
697
693
  }, consumedCapabilities);
698
694
  receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
@@ -708,7 +704,7 @@ async function syncPendingTaskComment(input: {
708
704
  }
709
705
  const detail = step.error ?? { code: 'COMMENT_SYNC_FAILED', message: 'task comment synchronization failed', retryable: true };
710
706
  const capability = issueCapability(receipt, 'task-comment');
711
- receipt = applyFinalizationReceiptMutationUnderLock(repoRoot, receipt, capability, {
707
+ receipt = mutateFinalizationReceipt(repoRoot, receipt, capability, {
712
708
  scope: 'task-comment', operation: 'failed', error: detail
713
709
  }, consumedCapabilities);
714
710
  receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
@@ -717,7 +713,7 @@ async function syncPendingTaskComment(input: {
717
713
  const detail = errorOf(error, 'COMMENT_SYNC_FAILED', true);
718
714
  try {
719
715
  const capability = issueCapability(receipt, 'task-comment');
720
- receipt = applyFinalizationReceiptMutationUnderLock(repoRoot, receipt, capability, {
716
+ receipt = mutateFinalizationReceipt(repoRoot, receipt, capability, {
721
717
  scope: 'task-comment', operation: 'failed', error: detail
722
718
  }, consumedCapabilities);
723
719
  receipt = reconcileWarningProjection(repoRoot, taskId, receipt, consumedCapabilities);
@@ -863,14 +859,14 @@ function preparedResult(
863
859
  };
864
860
  }
865
861
 
866
- async function prepareUnderLock(
862
+ async function prepareTaskFinalizationCore(
867
863
  request: TaskFinalizationRequest,
868
864
  taskId: string,
869
865
  options: TaskFinalizationOptions
870
866
  ): Promise<TaskFinalizationResult> {
871
867
  const repoRoot = path.resolve(options.repoRoot);
872
868
  const lifecycle = options.lifecycle ?? ((lifecycleRequest, lifecycleOptions) => (
873
- applyTaskLifecycleWithinTaskLock(lifecycleRequest, lifecycleOptions ?? { repoRoot }, taskId)
869
+ applyTaskLifecycle(lifecycleRequest, lifecycleOptions ?? { repoRoot })
874
870
  ));
875
871
  const backfill = options.backfill ?? backfillCompletionComments;
876
872
  const commentSync = options.commentSync ?? syncPlatformComment;
@@ -1142,11 +1138,9 @@ async function prepareTaskFinalization(request: TaskFinalizationRequest, options
1142
1138
  const resolved = resolveTaskRef(request.taskRef, { repoRoot });
1143
1139
  if (!resolved.ok) return failed(resolved.taskId, { code: resolved.code, message: resolved.message, retryable: false });
1144
1140
  try {
1145
- return await withTaskExecutionLock(repoRoot, resolved.taskId, 'task-finalization.prepare', () => prepareUnderLock(request, resolved.taskId, options));
1141
+ return await prepareTaskFinalizationCore(request, resolved.taskId, options);
1146
1142
  } catch (error) {
1147
- const detail = error instanceof TaskExecutionLockError
1148
- ? { code: error.code, message: error.message, retryable: error.code === 'ORCHESTRATION_LOCK_BUSY' }
1149
- : errorOf(error, 'TASK_FINALIZATION_FAILED');
1143
+ const detail = errorOf(error, 'TASK_FINALIZATION_FAILED');
1150
1144
  return failed(resolved.taskId, detail);
1151
1145
  }
1152
1146
  }
@@ -1159,7 +1153,7 @@ async function commitPreparedTaskFinalization(request: TaskFinalizationRequest,
1159
1153
  const resolved = resolveTaskRef(request.taskRef, { repoRoot });
1160
1154
  if (!resolved.ok) return failed(resolved.taskId, { code: resolved.code, message: resolved.message, retryable: false });
1161
1155
  try {
1162
- return await withTaskExecutionLock(repoRoot, resolved.taskId, 'task-finalization.commit', async () => {
1156
+ return await (async () => {
1163
1157
  if (options.controlBinding && options.manifestPath) {
1164
1158
  try {
1165
1159
  const manifest = readSandboxControlManifest(options.manifestPath);
@@ -1223,7 +1217,7 @@ async function commitPreparedTaskFinalization(request: TaskFinalizationRequest,
1223
1217
  };
1224
1218
  const result = options.lifecycle
1225
1219
  ? options.lifecycle(lifecycleRequest, lifecycleOptions)
1226
- : applyTaskLifecycleWithinTaskLock(lifecycleRequest, lifecycleOptions, resolved.taskId);
1220
+ : applyTaskLifecycle(lifecycleRequest, lifecycleOptions);
1227
1221
  const step = lifecycleStep(result);
1228
1222
  if (result.status !== 'applied' && result.status !== 'no-op') {
1229
1223
  const updated = updateReceipt(repoRoot, receipt, { lifecycle: 'pending', lastError: step.error });
@@ -1305,11 +1299,9 @@ async function commitPreparedTaskFinalization(request: TaskFinalizationRequest,
1305
1299
  });
1306
1300
  }
1307
1301
  return terminalResult(resolved.taskId, updated, { lifecycle: step, verification }, result.changed, detail);
1308
- });
1302
+ })();
1309
1303
  } catch (error) {
1310
- const detail = error instanceof TaskExecutionLockError
1311
- ? { code: error.code, message: error.message, retryable: error.code === 'ORCHESTRATION_LOCK_BUSY' }
1312
- : errorOf(error, 'TASK_FINALIZATION_FAILED');
1304
+ const detail = errorOf(error, 'TASK_FINALIZATION_FAILED');
1313
1305
  return failed(resolved.taskId, detail);
1314
1306
  }
1315
1307
  }
@@ -18,7 +18,7 @@ import { validateCurrentTaskContract } from './current-contract.ts';
18
18
  import { isValidAgentInfraVersion } from '../version.ts';
19
19
  import { taskIssueIdentity } from '../platform/task-identities.ts';
20
20
  import { resourceIdentityEquals } from '../platform/resource-identity.ts';
21
- import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.ts';
21
+ import { resolveProjectTaskWorkspaceRoot } from './workspace-root.ts';
22
22
 
23
23
  const lifecycleIntentCatalog = [
24
24
  'block', 'activate', 'cancel', 'complete', 'close-codescan', 'close-dependabot', 'restore', 'recover-started'
@@ -103,6 +103,9 @@ type LifecycleFileSystem = {
103
103
  readFileSync: (file: string) => string;
104
104
  writeFileSync: (file: string, content: string, flag?: string) => void;
105
105
  unlinkSync: (file: string) => void;
106
+ rmdirSync: (directory: string) => void;
107
+ readdirSync: (directory: string) => string[];
108
+ readMountInfoSync: () => string;
106
109
  };
107
110
  type TaskLifecycleOptions = {
108
111
  repoRoot?: string;
@@ -127,9 +130,25 @@ const DEFAULT_IO: LifecycleFileSystem = {
127
130
  renameSync: (source, target) => fs.renameSync(source, target),
128
131
  readFileSync: (file) => fs.readFileSync(file, 'utf8'),
129
132
  writeFileSync: (file, content, flag) => fs.writeFileSync(file, content, { encoding: 'utf8', flag: flag ?? 'w' }),
130
- unlinkSync: (file) => fs.unlinkSync(file)
133
+ unlinkSync: (file) => fs.unlinkSync(file),
134
+ rmdirSync: (directory) => fs.rmdirSync(directory),
135
+ readdirSync: (directory) => fs.readdirSync(directory),
136
+ readMountInfoSync: () => fs.readFileSync('/proc/self/mountinfo', 'utf8')
131
137
  };
132
138
 
139
+ function isVirtiofsMountPoint(directory: string, mountInfo: string): boolean {
140
+ const decodeMountInfoPath = (value: string): string => value.replace(/\\([0-7]{3})/gu, (_match, octal: string) => String.fromCharCode(Number.parseInt(octal, 8)));
141
+ const expected = fs.realpathSync.native(directory);
142
+ return mountInfo.split('\n').some((line) => {
143
+ if (!line) return false;
144
+ const fields = line.split(' ');
145
+ const separator = fields.indexOf('-');
146
+ return separator >= 0
147
+ && fields[separator + 1] === 'virtiofs'
148
+ && path.resolve(decodeMountInfoPath(fields[4] ?? '')) === expected;
149
+ });
150
+ }
151
+
133
152
  function failed(request: Pick<TaskLifecycleRequest, 'taskRef' | 'intent'>, error: LifecycleError, extra: Partial<TaskLifecycleResult> = {}): TaskLifecycleResult {
134
153
  return {
135
154
  status: 'failed', changed: false, requestRef: request.taskRef, taskId: null,
@@ -418,14 +437,14 @@ function validateRestoreStaging(request: Extract<TaskLifecycleRequest, { intent:
418
437
  let workspace: string;
419
438
  let stagingDir: string;
420
439
  try {
421
- workspace = fs.realpathSync.native(path.resolve(repoRoot, '.agents', 'workspace'));
440
+ workspace = fs.realpathSync.native(resolveProjectTaskWorkspaceRoot(repoRoot));
422
441
  stagingDir = fs.realpathSync.native(path.resolve(request.stagingDir));
423
442
  } catch (error) {
424
443
  return { code: 'LIFECYCLE_STAGING_INVALID', message: String(error) };
425
444
  }
426
445
  const relative = path.relative(workspace, stagingDir);
427
446
  if (!relative || relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative) || path.basename(stagingDir) === taskId) {
428
- return { code: 'LIFECYCLE_STAGING_INVALID', message: 'restore staging must be a non-final directory inside .agents/workspace' };
447
+ return { code: 'LIFECYCLE_STAGING_INVALID', message: 'restore staging must be a non-final directory inside the project task workspace' };
429
448
  }
430
449
  let entries: fs.Dirent[];
431
450
  try { entries = fs.readdirSync(stagingDir, { withFileTypes: true }); }
@@ -610,7 +629,7 @@ export function inspectTaskLifecycleProgress(
610
629
  }
611
630
  }
612
631
 
613
- function applyTaskLifecycleUnlocked(requestInput: TaskLifecycleRequest, options: TaskLifecycleOptions = {}): TaskLifecycleResult {
632
+ function applyTaskLifecycle(requestInput: TaskLifecycleRequest, options: TaskLifecycleOptions = {}): TaskLifecycleResult {
614
633
  if (requestInput.intent === 'recover-started') {
615
634
  return failed(requestInput, { code: 'LIFECYCLE_RECOVERY_REQUIRES_AUTHORITY', message: 'recover-started must be dispatched through task control authority' });
616
635
  }
@@ -652,7 +671,7 @@ function applyTaskLifecycleUnlocked(requestInput: TaskLifecycleRequest, options:
652
671
  } else {
653
672
  return failed(request, { code: 'LIFECYCLE_TASK_NOT_FOUND', message: `task ${taskId} has no lifecycle source` }, { taskId });
654
673
  }
655
- const targetPath = path.join(repoRoot, '.agents', 'workspace', spec.target, taskId);
674
+ const targetPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), spec.target, taskId);
656
675
  const requiredSteps = stepsForIntent(request.intent);
657
676
  const movingTaskDirectory = sourcePath !== targetPath;
658
677
  const currentTaskFile = path.join(sourcePath, 'task.md');
@@ -690,7 +709,7 @@ function applyTaskLifecycleUnlocked(requestInput: TaskLifecycleRequest, options:
690
709
  if (!contract.ok) return failed(request, { code: 'LIFECYCLE_DOCUMENT_INVALID', message: contract.message }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
691
710
  }
692
711
  const registryRequest = executeShortIdCommand({
693
- operation: 'list', activeDir: path.join(repoRoot, '.agents', 'workspace', 'active'),
712
+ operation: 'list', activeDir: path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active'),
694
713
  shortIdLength: configuredShortIdLength(repoRoot)
695
714
  });
696
715
  if (registryRequest.status === 'failed') {
@@ -861,9 +880,20 @@ function applyTaskLifecycleUnlocked(requestInput: TaskLifecycleRequest, options:
861
880
  }
862
881
  }
863
882
  }
864
- const activeTaskPath = path.join(repoRoot, '.agents', 'workspace', 'active', taskId);
883
+ const activeTaskPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', taskId);
865
884
  if (request.intent === 'complete' && fs.existsSync(activeTaskPath)) {
866
- try { fs.rmdirSync(activeTaskPath); }
885
+ try {
886
+ let sourceIsVirtiofsMount = false;
887
+ try { sourceIsVirtiofsMount = isVirtiofsMountPoint(activeTaskPath, io.readMountInfoSync()); }
888
+ catch { /* Platforms without mountinfo retain the ordinary directory cleanup path. */ }
889
+ if (sourceIsVirtiofsMount) {
890
+ if (io.readdirSync(activeTaskPath).length > 0) {
891
+ throw new Error('virtiofs source directory is not empty after task contents were transferred');
892
+ }
893
+ } else {
894
+ io.rmdirSync(activeTaskPath);
895
+ }
896
+ }
867
897
  catch (error) {
868
898
  return failed(request, { code: 'LIFECYCLE_SOURCE_DIRECTORY_CLEANUP_FAILED', message: String(error) }, {
869
899
  taskId, sourceState, targetState: spec.target, sourcePath: activeTaskPath, targetPath, journalPath,
@@ -895,50 +925,9 @@ function applyTaskLifecycleUnlocked(requestInput: TaskLifecycleRequest, options:
895
925
  };
896
926
  }
897
927
 
898
- function applyTaskLifecycle(request: TaskLifecycleRequest, options: TaskLifecycleOptions = {}): TaskLifecycleResult {
899
- const normalized = normalizedRequest(request);
900
- if ('code' in normalized) return applyTaskLifecycleUnlocked(request, options);
901
- const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
902
- const taskId = normalized.intent === 'restore'
903
- ? normalized.taskRef
904
- : (() => {
905
- const resolved = resolveTaskRef(normalized.taskRef, { repoRoot });
906
- return resolved.ok ? resolved.taskId : null;
907
- })();
908
- if (!taskId) return applyTaskLifecycleUnlocked(request, options);
909
- try {
910
- return withTaskExecutionLock(repoRoot, taskId, 'task-lifecycle.move', () => applyTaskLifecycleUnlocked(request, options));
911
- } catch (error) {
912
- if (error instanceof TaskExecutionLockError) {
913
- return failed(request, { code: error.code, message: error.message }, { taskId });
914
- }
915
- throw error;
916
- }
917
- }
918
-
919
- function applyTaskLifecycleWithinTaskLock(
920
- request: TaskLifecycleRequest,
921
- options: TaskLifecycleOptions,
922
- lockedTaskId: string
923
- ): TaskLifecycleResult {
924
- const normalized = normalizedRequest(request);
925
- if ('code' in normalized) return failed(request, normalized);
926
- const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
927
- const resolved = normalized.intent === 'restore'
928
- ? { ok: true as const, taskId: normalized.taskRef }
929
- : resolveTaskRef(normalized.taskRef, { repoRoot });
930
- if (!resolved.ok || resolved.taskId !== lockedTaskId) {
931
- return failed(request, {
932
- code: 'LIFECYCLE_LOCK_SCOPE_MISMATCH',
933
- message: 'task lifecycle request does not match the held task lock'
934
- }, { taskId: resolved.ok ? resolved.taskId : resolved.taskId });
935
- }
936
- return applyTaskLifecycleUnlocked(request, options);
937
- }
938
-
939
928
  export {
940
929
  lifecycleIntentCatalog, lifecycleFailureCatalog, lifecycleProducerCatalog,
941
- applyTaskLifecycle, applyTaskLifecycleWithinTaskLock, previewTaskCompletion
930
+ applyTaskLifecycle, previewTaskCompletion
942
931
  };
943
932
  export type {
944
933
  TaskLifecycleIntent, TaskLifecycleRequest, TaskLifecycleResult, TaskLifecycleOptions,
@@ -52,7 +52,6 @@ type LocalArtifactFinalizationRequest = {
52
52
  artifact: string;
53
53
  repoRoot?: string;
54
54
  requiredSections?: readonly string[];
55
- lockAlreadyHeld?: boolean;
56
55
  };
57
56
 
58
57
  type LocalArtifactFinalizationResult = {
@@ -129,7 +128,6 @@ type LocalArtifactPreparation = Readonly<{
129
128
  result: LocalArtifactFinalizationResult;
130
129
  content: string;
131
130
  repoRoot?: string;
132
- lockAlreadyHeld?: boolean;
133
131
  }>;
134
132
 
135
133
  function prepareLocalArtifact(
@@ -180,8 +178,7 @@ function prepareLocalArtifact(
180
178
  return {
181
179
  result: validation.ok && !qualificationError ? { ...result, status: 'passed', error: null } : result,
182
180
  content,
183
- repoRoot: resolved.repoRoot,
184
- lockAlreadyHeld: request.lockAlreadyHeld
181
+ repoRoot: resolved.repoRoot
185
182
  };
186
183
 
187
184
  }