@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
@@ -13,7 +13,7 @@ import { validateCurrentTaskContract } from './current-contract.js';
13
13
  import { isValidAgentInfraVersion } from '../version.js';
14
14
  import { taskIssueIdentity } from '../platform/task-identities.js';
15
15
  import { resourceIdentityEquals } from '../platform/resource-identity.js';
16
- import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
16
+ import { resolveProjectTaskWorkspaceRoot } from './workspace-root.js';
17
17
  const lifecycleIntentCatalog = [
18
18
  'block', 'activate', 'cancel', 'complete', 'close-codescan', 'close-dependabot', 'restore', 'recover-started'
19
19
  ];
@@ -54,8 +54,24 @@ const DEFAULT_IO = {
54
54
  renameSync: (source, target) => fs.renameSync(source, target),
55
55
  readFileSync: (file) => fs.readFileSync(file, 'utf8'),
56
56
  writeFileSync: (file, content, flag) => fs.writeFileSync(file, content, { encoding: 'utf8', flag: flag ?? 'w' }),
57
- unlinkSync: (file) => fs.unlinkSync(file)
57
+ unlinkSync: (file) => fs.unlinkSync(file),
58
+ rmdirSync: (directory) => fs.rmdirSync(directory),
59
+ readdirSync: (directory) => fs.readdirSync(directory),
60
+ readMountInfoSync: () => fs.readFileSync('/proc/self/mountinfo', 'utf8')
58
61
  };
62
+ function isVirtiofsMountPoint(directory, mountInfo) {
63
+ const decodeMountInfoPath = (value) => value.replace(/\\([0-7]{3})/gu, (_match, octal) => String.fromCharCode(Number.parseInt(octal, 8)));
64
+ const expected = fs.realpathSync.native(directory);
65
+ return mountInfo.split('\n').some((line) => {
66
+ if (!line)
67
+ return false;
68
+ const fields = line.split(' ');
69
+ const separator = fields.indexOf('-');
70
+ return separator >= 0
71
+ && fields[separator + 1] === 'virtiofs'
72
+ && path.resolve(decodeMountInfoPath(fields[4] ?? '')) === expected;
73
+ });
74
+ }
59
75
  function failed(request, error, extra = {}) {
60
76
  return {
61
77
  status: 'failed', changed: false, requestRef: request.taskRef, taskId: null,
@@ -355,7 +371,7 @@ function validateRestoreStaging(request, repoRoot, taskId) {
355
371
  let workspace;
356
372
  let stagingDir;
357
373
  try {
358
- workspace = fs.realpathSync.native(path.resolve(repoRoot, '.agents', 'workspace'));
374
+ workspace = fs.realpathSync.native(resolveProjectTaskWorkspaceRoot(repoRoot));
359
375
  stagingDir = fs.realpathSync.native(path.resolve(request.stagingDir));
360
376
  }
361
377
  catch (error) {
@@ -363,7 +379,7 @@ function validateRestoreStaging(request, repoRoot, taskId) {
363
379
  }
364
380
  const relative = path.relative(workspace, stagingDir);
365
381
  if (!relative || relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative) || path.basename(stagingDir) === taskId) {
366
- return { code: 'LIFECYCLE_STAGING_INVALID', message: 'restore staging must be a non-final directory inside .agents/workspace' };
382
+ return { code: 'LIFECYCLE_STAGING_INVALID', message: 'restore staging must be a non-final directory inside the project task workspace' };
367
383
  }
368
384
  let entries;
369
385
  try {
@@ -578,7 +594,7 @@ export function inspectTaskLifecycleProgress(repoRoot, taskId, agent) {
578
594
  return 'unknown';
579
595
  }
580
596
  }
581
- function applyTaskLifecycleUnlocked(requestInput, options = {}) {
597
+ function applyTaskLifecycle(requestInput, options = {}) {
582
598
  if (requestInput.intent === 'recover-started') {
583
599
  return failed(requestInput, { code: 'LIFECYCLE_RECOVERY_REQUIRES_AUTHORITY', message: 'recover-started must be dispatched through task control authority' });
584
600
  }
@@ -633,7 +649,7 @@ function applyTaskLifecycleUnlocked(requestInput, options = {}) {
633
649
  else {
634
650
  return failed(request, { code: 'LIFECYCLE_TASK_NOT_FOUND', message: `task ${taskId} has no lifecycle source` }, { taskId });
635
651
  }
636
- const targetPath = path.join(repoRoot, '.agents', 'workspace', spec.target, taskId);
652
+ const targetPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), spec.target, taskId);
637
653
  const requiredSteps = stepsForIntent(request.intent);
638
654
  const movingTaskDirectory = sourcePath !== targetPath;
639
655
  const currentTaskFile = path.join(sourcePath, 'task.md');
@@ -679,7 +695,7 @@ function applyTaskLifecycleUnlocked(requestInput, options = {}) {
679
695
  return failed(request, { code: 'LIFECYCLE_DOCUMENT_INVALID', message: contract.message }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
680
696
  }
681
697
  const registryRequest = executeShortIdCommand({
682
- operation: 'list', activeDir: path.join(repoRoot, '.agents', 'workspace', 'active'),
698
+ operation: 'list', activeDir: path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active'),
683
699
  shortIdLength: configuredShortIdLength(repoRoot)
684
700
  });
685
701
  if (registryRequest.status === 'failed') {
@@ -889,10 +905,22 @@ function applyTaskLifecycleUnlocked(requestInput, options = {}) {
889
905
  }
890
906
  }
891
907
  }
892
- const activeTaskPath = path.join(repoRoot, '.agents', 'workspace', 'active', taskId);
908
+ const activeTaskPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', taskId);
893
909
  if (request.intent === 'complete' && fs.existsSync(activeTaskPath)) {
894
910
  try {
895
- fs.rmdirSync(activeTaskPath);
911
+ let sourceIsVirtiofsMount = false;
912
+ try {
913
+ sourceIsVirtiofsMount = isVirtiofsMountPoint(activeTaskPath, io.readMountInfoSync());
914
+ }
915
+ catch { /* Platforms without mountinfo retain the ordinary directory cleanup path. */ }
916
+ if (sourceIsVirtiofsMount) {
917
+ if (io.readdirSync(activeTaskPath).length > 0) {
918
+ throw new Error('virtiofs source directory is not empty after task contents were transferred');
919
+ }
920
+ }
921
+ else {
922
+ io.rmdirSync(activeTaskPath);
923
+ }
896
924
  }
897
925
  catch (error) {
898
926
  return failed(request, { code: 'LIFECYCLE_SOURCE_DIRECTORY_CLEANUP_FAILED', message: String(error) }, {
@@ -939,44 +967,5 @@ function applyTaskLifecycleUnlocked(requestInput, options = {}) {
939
967
  journalPath, completedSteps: [...completed], pendingSteps: []
940
968
  };
941
969
  }
942
- function applyTaskLifecycle(request, options = {}) {
943
- const normalized = normalizedRequest(request);
944
- if ('code' in normalized)
945
- return applyTaskLifecycleUnlocked(request, options);
946
- const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
947
- const taskId = normalized.intent === 'restore'
948
- ? normalized.taskRef
949
- : (() => {
950
- const resolved = resolveTaskRef(normalized.taskRef, { repoRoot });
951
- return resolved.ok ? resolved.taskId : null;
952
- })();
953
- if (!taskId)
954
- return applyTaskLifecycleUnlocked(request, options);
955
- try {
956
- return withTaskExecutionLock(repoRoot, taskId, 'task-lifecycle.move', () => applyTaskLifecycleUnlocked(request, options));
957
- }
958
- catch (error) {
959
- if (error instanceof TaskExecutionLockError) {
960
- return failed(request, { code: error.code, message: error.message }, { taskId });
961
- }
962
- throw error;
963
- }
964
- }
965
- function applyTaskLifecycleWithinTaskLock(request, options, lockedTaskId) {
966
- const normalized = normalizedRequest(request);
967
- if ('code' in normalized)
968
- return failed(request, normalized);
969
- const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
970
- const resolved = normalized.intent === 'restore'
971
- ? { ok: true, taskId: normalized.taskRef }
972
- : resolveTaskRef(normalized.taskRef, { repoRoot });
973
- if (!resolved.ok || resolved.taskId !== lockedTaskId) {
974
- return failed(request, {
975
- code: 'LIFECYCLE_LOCK_SCOPE_MISMATCH',
976
- message: 'task lifecycle request does not match the held task lock'
977
- }, { taskId: resolved.ok ? resolved.taskId : resolved.taskId });
978
- }
979
- return applyTaskLifecycleUnlocked(request, options);
980
- }
981
- export { lifecycleIntentCatalog, lifecycleFailureCatalog, lifecycleProducerCatalog, applyTaskLifecycle, applyTaskLifecycleWithinTaskLock, previewTaskCompletion };
970
+ export { lifecycleIntentCatalog, lifecycleFailureCatalog, lifecycleProducerCatalog, applyTaskLifecycle, previewTaskCompletion };
982
971
  //# sourceMappingURL=lifecycle.js.map
@@ -110,8 +110,7 @@ function prepareLocalArtifact(request, candidate) {
110
110
  return {
111
111
  result: validation.ok && !qualificationError ? { ...result, status: 'passed', error: null } : result,
112
112
  content,
113
- repoRoot: resolved.repoRoot,
114
- lockAlreadyHeld: request.lockAlreadyHeld
113
+ repoRoot: resolved.repoRoot
115
114
  };
116
115
  }
117
116
  function commitLocalArtifactProvenance(prepared) {
@@ -7,19 +7,19 @@ import { validateCurrentTaskContract } from './current-contract.js';
7
7
  import { parseReviewSummary } from './review-artifacts.js';
8
8
  import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
9
9
  import { resolveTaskRef, TASK_ID_RE } from './resolve-ref.js';
10
+ import { resolveProjectTaskWorkspaceRoot } from './workspace-root.js';
10
11
  import { activateDelegation, abortActivatedDelegation, abortPreparedDelegation, completeDelegationStage, consumeDelegation, dispatchDelegation, foldBlankToNull, isDelegationReceipt, managedDelegationRole, prepareDelegation, sealDelegation } from './delegation-receipts.js';
11
12
  import { normalizeAgentClients } from '../agent-clients/config.js';
12
13
  import { getAgentClientAdapter, 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';
15
16
  import { assertGitRepositoryBinding } from '../git/worktree-identity.js';
16
- import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
17
17
  import { extractReviewBaseline, extractReviewDiffBase, extractReviewTargetHead, extractReviewedHead } from './review-fingerprint.js';
18
18
  import { resolveDeliveryTarget, resolveDiffBase, resolveTargetHead } from './delivery-target.js';
19
19
  import { buildLifecycleFacts, canStart, recommendNext } from './capabilities.js';
20
20
  import { hasOpenLifecycleExecution } from './activity-log.js';
21
21
  import { normalizeAgentToken } from '../agent-clients/tokens.js';
22
- import { resolveArtifactContext } from './artifact-lifecycle.js';
22
+ import { resolveArtifactContextForResolvedTask } from './artifact-lifecycle.js';
23
23
  function supportsLifecycleDelegation(client) {
24
24
  return getAgentClientCapability(client, 'subagents').level !== 'unsupported'
25
25
  && getAgentClientCapability(client, 'orchestration').level !== 'unsupported'
@@ -274,15 +274,9 @@ function mutateDelegationAdapterEvidence(taskRef, receiptId, adapterId, mutate,
274
274
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
275
275
  if (!resolved.ok)
276
276
  throw new Error(`${resolved.code}: ${resolved.message}`);
277
- return mutateDelegationAdapterEvidenceAtResolved(resolved, receiptId, adapterId, mutate, options, false);
277
+ return mutateDelegationAdapterEvidenceAtResolved(resolved, receiptId, adapterId, mutate, options);
278
278
  }
279
- function mutateDelegationAdapterEvidenceWithinTaskLock(taskRef, receiptId, adapterId, mutate, options = {}) {
280
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
281
- if (!resolved.ok)
282
- throw new Error(`${resolved.code}: ${resolved.message}`);
283
- return mutateDelegationAdapterEvidenceAtResolved(resolved, receiptId, adapterId, mutate, options, true);
284
- }
285
- function mutateDelegationAdapterEvidenceAtResolved(resolved, receiptId, adapterId, mutate, options, taskLockHeld) {
279
+ function mutateDelegationAdapterEvidenceAtResolved(resolved, receiptId, adapterId, mutate, options) {
286
280
  const update = () => {
287
281
  try {
288
282
  const run = readRun(resolved.taskDir, options);
@@ -316,9 +310,7 @@ function mutateDelegationAdapterEvidenceAtResolved(resolved, receiptId, adapterI
316
310
  }
317
311
  };
318
312
  let mutationError;
319
- const result = taskLockHeld
320
- ? update()
321
- : withTaskExecutionLock(resolved.repoRoot, resolved.taskId, `agent-adapter.${adapterId}.evidence`, update);
313
+ const result = update();
322
314
  if (mutationError)
323
315
  throw mutationError;
324
316
  return result;
@@ -542,10 +534,7 @@ function routeFromFacts(facts) {
542
534
  const role = action.startsWith('review-') ? 'reviewer' : 'executor';
543
535
  return { action: command, role, stage: action };
544
536
  }
545
- function routeOrchestration(taskRef, options = {}) {
546
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
547
- if (!resolved.ok)
548
- return failed(resolved.code, resolved.message, resolved.taskId);
537
+ function routeResolvedTask(taskRef, resolved, options) {
549
538
  let gitRoot;
550
539
  try {
551
540
  gitRoot = gitRootFor(resolved.repoRoot, options);
@@ -584,7 +573,7 @@ function routeOrchestration(taskRef, options = {}) {
584
573
  catch (error) {
585
574
  return failed('ORCHESTRATION_STATE_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
586
575
  }
587
- const facts = buildLifecycleFacts(resolved.taskDir, content, resolved.state, hasOpenLifecycleExecution(content) || Boolean(run?.pendingDelegation));
576
+ const facts = buildLifecycleFacts(resolved.taskDir, content, resolved.state, hasOpenLifecycleExecution(content) || Boolean(run?.pendingDelegation), resolved.repoRoot);
588
577
  if (!facts.ok)
589
578
  return failed('ORCHESTRATION_CAPABILITY_FACTS_INVALID', facts.message, resolved.taskId);
590
579
  const routed = routeFromFacts(facts.facts);
@@ -674,7 +663,7 @@ function routeOrchestration(taskRef, options = {}) {
674
663
  }
675
664
  const action = routed.stage;
676
665
  const family = action === 'analysis' ? 'analysis' : action;
677
- const artifactContext = resolveArtifactContext(taskRef, family, {
666
+ const artifactContext = resolveArtifactContextForResolvedTask(resolved, family, {
678
667
  repoRoot: resolved.repoRoot
679
668
  });
680
669
  if (artifactContext.status !== 'ready' || !artifactContext.selection) {
@@ -700,6 +689,12 @@ function routeOrchestration(taskRef, options = {}) {
700
689
  };
701
690
  return { status: 'running', changed: false, taskId: resolved.taskId, run, next, error: null };
702
691
  }
692
+ function routeOrchestration(taskRef, options = {}) {
693
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
694
+ if (!resolved.ok)
695
+ return failed(resolved.code, resolved.message, resolved.taskId);
696
+ return routeResolvedTask(taskRef, resolved, options);
697
+ }
703
698
  function statusOrchestration(taskRef, options = {}) {
704
699
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
705
700
  if (!resolved.ok)
@@ -743,7 +738,7 @@ function validateDelegationRun(taskRef, taskId, run, options) {
743
738
  }
744
739
  return null;
745
740
  }
746
- function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
741
+ function prepareOrchestrationDelegation(taskRef, input, options = {}) {
747
742
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
748
743
  if (!resolved.ok)
749
744
  return failed(resolved.code, resolved.message, resolved.taskId);
@@ -763,7 +758,7 @@ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
763
758
  if (runFailure)
764
759
  return runFailure;
765
760
  const activeRun = run;
766
- const routed = routeOrchestration(taskRef, options);
761
+ const routed = routeResolvedTask(taskRef, resolved, options);
767
762
  if (!routed.next)
768
763
  return routed;
769
764
  const next = routed.next;
@@ -797,20 +792,7 @@ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
797
792
  saveRun(resolved.taskDir, updated);
798
793
  return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next, error: null };
799
794
  }
800
- function prepareOrchestrationDelegation(taskRef, input, options = {}) {
801
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
802
- if (!resolved.ok)
803
- return failed(resolved.code, resolved.message, resolved.taskId);
804
- try {
805
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-orchestration.prepare.task', () => prepareOrchestrationDelegationUnlocked(taskRef, input, options));
806
- }
807
- catch (error) {
808
- if (error instanceof TaskExecutionLockError)
809
- return failed(error.code, error.message, resolved.taskId);
810
- throw error;
811
- }
812
- }
813
- function dispatchOrchestrationDelegationUnlocked(taskRef, options = {}) {
795
+ function dispatchOrchestrationDelegation(taskRef, options = {}) {
814
796
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
815
797
  if (!resolved.ok)
816
798
  return failed(resolved.code, resolved.message, resolved.taskId);
@@ -830,19 +812,6 @@ function dispatchOrchestrationDelegationUnlocked(taskRef, options = {}) {
830
812
  saveRun(resolved.taskDir, updated);
831
813
  return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
832
814
  }
833
- function dispatchOrchestrationDelegation(taskRef, options = {}) {
834
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
835
- if (!resolved.ok)
836
- return failed(resolved.code, resolved.message, resolved.taskId);
837
- try {
838
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-orchestration.dispatch.task', () => dispatchOrchestrationDelegationUnlocked(taskRef, options));
839
- }
840
- catch (error) {
841
- if (error instanceof TaskExecutionLockError)
842
- return failed(error.code, error.message, resolved.taskId);
843
- throw error;
844
- }
845
- }
846
815
  function matchingDelegations(predicate, options) {
847
816
  const taskId = options.taskId;
848
817
  if (taskId === undefined || taskId === '') {
@@ -852,7 +821,7 @@ function matchingDelegations(predicate, options) {
852
821
  return { ok: false, error: failed('ORCHESTRATION_TASK_ID_INVALID', 'taskId must be a canonical TASK-id') };
853
822
  }
854
823
  const repoRoot = options.repoRoot ?? process.cwd();
855
- const taskDir = path.join(repoRoot, '.agents', 'workspace', 'active', taskId);
824
+ const taskDir = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', taskId);
856
825
  const run = readRun(taskDir, options);
857
826
  const matches = run && run.status === 'running' && run.pendingDelegation && predicate(run.pendingDelegation)
858
827
  ? [{ taskId, run }]
@@ -1033,7 +1002,7 @@ function recoverPreparedOrchestrationDelegation(taskRef, options = {}) {
1033
1002
  if (!resolved.ok)
1034
1003
  return failed(resolved.code, resolved.message, resolved.taskId);
1035
1004
  try {
1036
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-orchestration.recover-prepared', () => {
1005
+ return (() => {
1037
1006
  const run = readRun(resolved.taskDir, options);
1038
1007
  const receipt = run?.pendingDelegation;
1039
1008
  if (!run || !receipt) {
@@ -1073,11 +1042,9 @@ function recoverPreparedOrchestrationDelegation(taskRef, options = {}) {
1073
1042
  }, options.now);
1074
1043
  saveRun(resolved.taskDir, updated);
1075
1044
  return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
1076
- });
1045
+ })();
1077
1046
  }
1078
1047
  catch (error) {
1079
- if (error instanceof TaskExecutionLockError)
1080
- return failed(error.code, error.message, resolved.taskId);
1081
1048
  return failed('ORCHESTRATION_PREPARED_RECOVERY_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
1082
1049
  }
1083
1050
  }
@@ -1088,7 +1055,7 @@ function recoveryReceiptMatches(receipt, event) {
1088
1055
  && receipt.childId === event.childId
1089
1056
  && normalizeAgentToken(event.startedAgent) === normalizeAgentToken(receipt.client);
1090
1057
  }
1091
- function recoverActivatedOrchestrationDelegationUnderLock(taskRef, event, options = {}) {
1058
+ function recoverActivatedOrchestrationDelegation(taskRef, event, options = {}) {
1092
1059
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
1093
1060
  if (!resolved.ok)
1094
1061
  return failed(resolved.code, resolved.message, resolved.taskId);
@@ -1204,7 +1171,7 @@ function sealOrchestrationDelegation(taskRef, event, expected, options = {}, bef
1204
1171
  const resolved = resolveTaskRef(taskRef, { repoRoot: orchestrationOptions.repoRoot });
1205
1172
  if (!resolved.ok)
1206
1173
  return failed(resolved.code, resolved.message, resolved.taskId);
1207
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-orchestration.seal', () => {
1174
+ return (() => {
1208
1175
  const run = readRun(resolved.taskDir, orchestrationOptions);
1209
1176
  if (!run?.pendingDelegation)
1210
1177
  return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
@@ -1226,7 +1193,7 @@ function sealOrchestrationDelegation(taskRef, event, expected, options = {}, bef
1226
1193
  const updated = withUpdatedRun(current, { pendingDelegation: result.receipt });
1227
1194
  saveRun(resolved.taskDir, updated);
1228
1195
  return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
1229
- });
1196
+ })();
1230
1197
  }
1231
1198
  function advanceOrchestration(taskRef, options = {}) {
1232
1199
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
@@ -1262,5 +1229,5 @@ function pauseOrchestration(taskRef, code, message, recoverable, options = {}) {
1262
1229
  saveRun(resolved.taskDir, updated);
1263
1230
  return { status: 'paused', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
1264
1231
  }
1265
- export { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, awaitOrchestrationDelegationActivation, advanceOrchestration, beginOrResumeOrchestration, commitOrchestrationStageCompletion, completeOrchestrationStage, dispatchOrchestrationDelegation, inspectOrchestrationStage, hasActivatableOrchestrationDelegation, hasSealableOrchestrationDelegation, OrchestrationStateError, orchestrationPath, readDelegationAdapterEvidence, mutateDelegationAdapterEvidence, mutateDelegationAdapterEvidenceWithinTaskLock, pauseMatchingOrchestrationDelegation, pauseOrchestration, planOrchestrationStageCompletion, prepareOrchestrationDelegation, readRun, reconcileMatchingOrchestrationDelegation, recoverPreparedOrchestrationDelegation, recoverActivatedOrchestrationDelegationUnderLock, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, statusOrchestration, };
1232
+ export { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, awaitOrchestrationDelegationActivation, advanceOrchestration, beginOrResumeOrchestration, commitOrchestrationStageCompletion, completeOrchestrationStage, dispatchOrchestrationDelegation, inspectOrchestrationStage, hasActivatableOrchestrationDelegation, hasSealableOrchestrationDelegation, OrchestrationStateError, orchestrationPath, readDelegationAdapterEvidence, mutateDelegationAdapterEvidence, pauseMatchingOrchestrationDelegation, pauseOrchestration, planOrchestrationStageCompletion, prepareOrchestrationDelegation, readRun, reconcileMatchingOrchestrationDelegation, recoverPreparedOrchestrationDelegation, recoverActivatedOrchestrationDelegation, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, statusOrchestration, };
1266
1233
  //# sourceMappingURL=orchestration.js.map
@@ -234,8 +234,7 @@ async function replayPullRequestSummary(taskId, operation, agent, cwd, client) {
234
234
  ...(summary.manualValidation ? { manualValidation: summary.manualValidation } : {}),
235
235
  primaryResult: 'no_op',
236
236
  strict: true,
237
- skipQueue: true,
238
- lockAlreadyHeld: true
237
+ skipQueue: true
239
238
  });
240
239
  if ((replayed.status === 'applied' || replayed.status === 'no-op') && !replayed.error && replayed.warnings.length === 0) {
241
240
  return platformResult(replayed.status, { changed: replayed.changed });
@@ -3,10 +3,12 @@ import path from 'node:path';
3
3
  import { execFileSync } from 'node:child_process';
4
4
  import { normalizeShortIdInput, resolveShortIdReadOnly } from './short-id.js';
5
5
  import { parseTaskFrontmatter } from './frontmatter.js';
6
+ import { resolveProjectTaskWorkspaceRoot } from './workspace-root.js';
6
7
  const TASK_ID_RE = /^TASK-\d{8}-\d{6}$/;
7
8
  // Flat-structured workspace dirs that hold tasks under `{dir}/{taskId}/task.md`.
8
9
  // Note: `archive` uses a three-level YYYY/MM/DD layout and is handled separately.
9
10
  const FLAT_WORKSPACE_DIRS = ['active', 'blocked', 'completed'];
11
+ function taskRoot(repoRoot) { return resolveProjectTaskWorkspaceRoot(repoRoot); }
10
12
  function detectRepoRoot() {
11
13
  try {
12
14
  return execFileSync('git', ['rev-parse', '--show-toplevel'], {
@@ -40,12 +42,12 @@ function listSortedNumeric(dir, width) {
40
42
  .sort()
41
43
  .reverse();
42
44
  }
43
- function findInArchive(repoRoot, taskId) {
44
- // archive-tasks stores local material at .agents/workspace/archive/YYYY/MM/DD/{taskId}/local/task.md
45
+ function findInArchive(workspaceRoot, taskId) {
46
+ // archive-tasks stores local material at the project task workspace archive/YYYY/MM/DD/{taskId}/local/task.md
45
47
  // where YYYY/MM/DD comes from completed_at (or updated_at fallback) — NOT from
46
48
  // the task id's creation date. So we cannot derive the path from taskId alone;
47
49
  // walk the bounded YYYY/MM/DD tree instead. Newest-first to favor recent archives.
48
- const archiveDir = path.join(repoRoot, '.agents', 'workspace', 'archive');
50
+ const archiveDir = path.join(workspaceRoot, 'archive');
49
51
  for (const year of listSortedNumeric(archiveDir, 4)) {
50
52
  const yearDir = path.join(archiveDir, year);
51
53
  for (const month of listSortedNumeric(yearDir, 2)) {
@@ -59,13 +61,13 @@ function findInArchive(repoRoot, taskId) {
59
61
  }
60
62
  return null;
61
63
  }
62
- function findTaskMd(repoRoot, taskId) {
64
+ function findTaskMd(workspaceRoot, taskId) {
63
65
  for (const sub of FLAT_WORKSPACE_DIRS) {
64
- const candidate = path.join(repoRoot, '.agents', 'workspace', sub, taskId, 'task.md');
66
+ const candidate = path.join(workspaceRoot, sub, taskId, 'task.md');
65
67
  if (fs.existsSync(candidate))
66
68
  return { taskMdPath: candidate, state: sub };
67
69
  }
68
- const archived = findInArchive(repoRoot, taskId);
70
+ const archived = findInArchive(workspaceRoot, taskId);
69
71
  return archived ? { taskMdPath: archived, state: 'archive' } : null;
70
72
  }
71
73
  /**
@@ -76,8 +78,9 @@ function findTaskMd(repoRoot, taskId) {
76
78
  */
77
79
  function enumerateTaskDirs(repoRoot) {
78
80
  const out = [];
81
+ const workspaceRoot = taskRoot(repoRoot);
79
82
  for (const sub of FLAT_WORKSPACE_DIRS) {
80
- const base = path.join(repoRoot, '.agents', 'workspace', sub);
83
+ const base = path.join(workspaceRoot, sub);
81
84
  if (!fs.existsSync(base))
82
85
  continue;
83
86
  for (const entry of fs.readdirSync(base).sort()) {
@@ -98,6 +101,7 @@ function enumerateTaskDirs(repoRoot) {
98
101
  */
99
102
  function enumerateAllTaskDirs(repoRoot) {
100
103
  const out = [];
104
+ const workspaceRoot = taskRoot(repoRoot);
101
105
  const seen = new Map();
102
106
  const add = (taskId, taskDir, state) => {
103
107
  if (!TASK_ID_RE.test(taskId))
@@ -116,13 +120,13 @@ function enumerateAllTaskDirs(repoRoot) {
116
120
  out.push({ taskId, taskDir, state });
117
121
  };
118
122
  for (const state of FLAT_WORKSPACE_DIRS) {
119
- const base = path.join(repoRoot, '.agents', 'workspace', state);
123
+ const base = path.join(workspaceRoot, state);
120
124
  if (!fs.existsSync(base))
121
125
  continue;
122
126
  for (const taskId of fs.readdirSync(base).sort())
123
127
  add(taskId, path.join(base, taskId), state);
124
128
  }
125
- const archive = path.join(repoRoot, '.agents', 'workspace', 'archive');
129
+ const archive = path.join(workspaceRoot, 'archive');
126
130
  for (const year of listSortedNumeric(archive, 4).reverse()) {
127
131
  const yearDir = path.join(archive, year);
128
132
  for (const month of listSortedNumeric(yearDir, 2).reverse()) {
@@ -137,8 +141,9 @@ function enumerateAllTaskDirs(repoRoot) {
137
141
  return out;
138
142
  }
139
143
  function locateHotTaskDirs(repoRoot, taskId) {
144
+ const workspaceRoot = taskRoot(repoRoot);
140
145
  return FLAT_WORKSPACE_DIRS.flatMap((state) => {
141
- const taskDir = path.join(repoRoot, '.agents', 'workspace', state, taskId);
146
+ const taskDir = path.join(workspaceRoot, state, taskId);
142
147
  const taskMdPath = path.join(taskDir, 'task.md');
143
148
  return fs.existsSync(taskMdPath) ? [{ taskId, taskDir, taskMdPath, state }] : [];
144
149
  });
@@ -203,7 +208,7 @@ function resolveTaskRef(arg, options = {}) {
203
208
  }
204
209
  taskId = shortResult.taskId;
205
210
  }
206
- const located = findTaskMd(repoRoot, taskId);
211
+ const located = findTaskMd(taskRoot(repoRoot), taskId);
207
212
  if (!located) {
208
213
  return {
209
214
  ok: false,
@@ -255,7 +260,7 @@ function resolveTaskContext(taskRef, options = {}) {
255
260
  taskId: null
256
261
  };
257
262
  }
258
- const activeDir = path.join(repoRoot, '.agents', 'workspace', 'active');
263
+ const activeDir = path.join(taskRoot(repoRoot), 'active');
259
264
  const matches = [];
260
265
  if (fs.existsSync(activeDir)) {
261
266
  for (const entry of fs.readdirSync(activeDir).sort()) {
@@ -8,7 +8,6 @@ import { finalizeReviewSummaryContent } from './review-artifacts.js';
8
8
  import { inspectDecisionDetailDuplicates } from './decision-details.js';
9
9
  import { resolveTaskRef } from './resolve-ref.js';
10
10
  import { validateLifecycleExecution } from './lifecycle-execution.js';
11
- import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
12
11
  import { getArtifactSchema } from './artifact-schema.js';
13
12
  import { validateQualificationAudit } from './qualification-audit.js';
14
13
  import { canonicalSemanticDigest, inspectArtifactContract, sha256Content } from './artifact-operations.js';
@@ -47,7 +46,7 @@ function preflightFailed(request, code, message, taskId = null, extra = {}) {
47
46
  };
48
47
  }
49
48
  /** Validate the current review draft before any finding-ledger write. */
50
- function preflightReviewSummaryUnlocked(request, options = {}) {
49
+ function preflightReviewSummary(request, options = {}) {
51
50
  const stage = request.stage;
52
51
  const spec = STAGES[stage];
53
52
  if (!spec)
@@ -106,21 +105,6 @@ function preflightReviewSummaryUnlocked(request, options = {}) {
106
105
  status: 'passed', changed: false, error: null
107
106
  };
108
107
  }
109
- function preflightReviewSummary(request, options = {}) {
110
- if (request.dryRun || options.lockAlreadyHeld)
111
- return preflightReviewSummaryUnlocked(request, options);
112
- const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
113
- if (!resolved.ok)
114
- return preflightReviewSummaryUnlocked(request, options);
115
- try {
116
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-review.preflight', () => preflightReviewSummaryUnlocked(request, { ...options, lockAlreadyHeld: true }));
117
- }
118
- catch (error) {
119
- if (!(error instanceof TaskExecutionLockError))
120
- throw error;
121
- return preflightFailed(request, 'REVIEW_PROVENANCE_INVALID', `${error.code}: ${error.message}`, resolved.taskId);
122
- }
123
- }
124
108
  /** Prepare domain validation, summary bytes and provenance before any publication. */
125
109
  function prepareReviewSummaryCandidate(request, artifactContent, options = {}) {
126
110
  let taskId = null;
@@ -208,7 +192,6 @@ function prepareReviewSummaryCandidate(request, artifactContent, options = {}) {
208
192
  operations: transformed.changed ? [{ kind: 'artifact', artifact: request.artifact, operation: 'update' }] : [],
209
193
  error: null
210
194
  },
211
- lockAlreadyHeld: options.lockAlreadyHeld
212
195
  };
213
196
  }
214
197
  function commitReviewSummaryProvenance(prepared, repoRoot, options = {}) {
@@ -230,7 +213,7 @@ function replaceCurrentArtifactAtomically(file, content) {
230
213
  }
231
214
  }
232
215
  }
233
- function finalizeReviewSummaryUnlocked(request, options = {}) {
216
+ function finalizeReviewSummary(request, options = {}) {
234
217
  const spec = STAGES[request.stage];
235
218
  if (!spec || !request.taskRef || !request.artifact)
236
219
  return prepareReviewSummaryCandidate(request, '', options).result;
@@ -267,21 +250,5 @@ function finalizeReviewSummaryUnlocked(request, options = {}) {
267
250
  return failed(request, 'REVIEW_RECOVERY_COMMIT_FAILED', `cannot update current review artifact: ${error instanceof Error ? error.message : String(error)}`, resolved.taskId);
268
251
  }
269
252
  }
270
- function finalizeReviewSummary(request, options = {}) {
271
- const effectiveOptions = options;
272
- if (request.dryRun || options.lockAlreadyHeld)
273
- return finalizeReviewSummaryUnlocked(request, effectiveOptions);
274
- const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
275
- if (!resolved.ok)
276
- return finalizeReviewSummaryUnlocked(request, effectiveOptions);
277
- try {
278
- return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-review.finalize-summary', () => finalizeReviewSummaryUnlocked(request, { ...effectiveOptions, lockAlreadyHeld: true }));
279
- }
280
- catch (error) {
281
- if (!(error instanceof TaskExecutionLockError))
282
- throw error;
283
- return failed(request, 'REVIEW_PROVENANCE_INVALID', `${error.code}: ${error.message}`, resolved.taskId);
284
- }
285
- }
286
253
  export { finalizeReviewSummary, preflightReviewSummary, prepareReviewSummaryCandidate, commitReviewSummaryProvenance };
287
254
  //# sourceMappingURL=review-finalization.js.map
@@ -23,7 +23,9 @@ export function inspectReviewIdentity(taskDir, reportContent, repositoryRoot) {
23
23
  }
24
24
  try {
25
25
  const metadata = parseTypedTaskFrontmatter(fs.readFileSync(path.join(taskDir, 'task.md'), 'utf8'));
26
- const taskRepositoryRoot = git(taskDir, ['rev-parse', '--show-toplevel']);
26
+ const taskRepositoryRoot = repositoryRoot
27
+ ? fs.realpathSync.native(repositoryRoot)
28
+ : git(taskDir, ['rev-parse', '--show-toplevel']);
27
29
  const branch = String(metadata.branch ?? '').trim();
28
30
  const gitRoot = branch ? resolveBranchWorktree(taskRepositoryRoot, branch) : taskRepositoryRoot;
29
31
  if (!gitRoot)