@fitlab-ai/agent-infra 0.11.15 → 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 (253) 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-ledger.js +1 -12
  14. package/dist/lib/internal/task-operation-registry.js +2 -1
  15. package/dist/lib/internal/task-qualification.js +6 -15
  16. package/dist/lib/internal/task-review.js +3 -16
  17. package/dist/lib/internal/task-short-id.js +2 -1
  18. package/dist/lib/internal/task-verify.js +1 -11
  19. package/dist/lib/internal/task-warning.js +1 -12
  20. package/dist/lib/internal/task-workspace.js +43 -0
  21. package/dist/lib/merge.js +4 -3
  22. package/dist/lib/platform/pr-summary.js +6 -15
  23. package/dist/lib/platform/pull-requests.js +3 -15
  24. package/dist/lib/pr-review/evidence-grading.js +3 -2
  25. package/dist/lib/process-data/index.js +5 -4
  26. package/dist/lib/process-data/sources.js +6 -0
  27. package/dist/lib/run/index.js +3 -2
  28. package/dist/lib/sandbox/commands/create.js +5 -1
  29. package/dist/lib/sandbox/commands/enter.js +1 -1
  30. package/dist/lib/sandbox/commands/list-running.js +2 -1
  31. package/dist/lib/sandbox/control/client.js +8 -13
  32. package/dist/lib/sandbox/control/completed-reentry.js +2 -1
  33. package/dist/lib/sandbox/control/task-view.js +4 -2
  34. package/dist/lib/sandbox/mounts.js +4 -4
  35. package/dist/lib/sandbox/recovery.js +26 -16
  36. package/dist/lib/sandbox/removal.js +3 -10
  37. package/dist/lib/sandbox/task-resolver.js +9 -6
  38. package/dist/lib/sandbox/workspace-identity.js +6 -5
  39. package/dist/lib/sandbox/workspace-view.js +29 -22
  40. package/dist/lib/task/activity-intent.js +2 -12
  41. package/dist/lib/task/artifact-lifecycle.js +17 -11
  42. package/dist/lib/task/artifact-operations.js +41 -49
  43. package/dist/lib/task/capabilities.js +2 -2
  44. package/dist/lib/task/commands/ls.js +4 -3
  45. package/dist/lib/task/commands/status.js +1 -1
  46. package/dist/lib/task/commit-operation.js +6 -6
  47. package/dist/lib/task/control-authority.js +32 -32
  48. package/dist/lib/task/create-service.js +2 -4
  49. package/dist/lib/task/create.js +12 -65
  50. package/dist/lib/task/delegation-receipts.js +1 -1
  51. package/dist/lib/task/delivery.js +2 -8
  52. package/dist/lib/task/events.js +5 -31
  53. package/dist/lib/task/finalization.js +17 -22
  54. package/dist/lib/task/lifecycle.js +9 -48
  55. package/dist/lib/task/local-artifact-finalization.js +1 -2
  56. package/dist/lib/task/orchestration.js +24 -57
  57. package/dist/lib/task/platform-operation-recovery.js +1 -2
  58. package/dist/lib/task/resolve-ref.js +17 -12
  59. package/dist/lib/task/review-finalization.js +2 -35
  60. package/dist/lib/task/review-identity.js +3 -1
  61. package/dist/lib/task/short-id.js +10 -8
  62. package/dist/lib/task/verification-engine.js +19 -58
  63. package/dist/lib/task/workspace-root.js +59 -0
  64. package/dist/lib/task/workspace-snapshot.js +4 -3
  65. package/dist/lifecycle-build-manifest.json +3 -3
  66. package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +6 -6
  67. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +8 -34
  68. package/lib/agent-clients/adapters/codex-orchestration.ts +1 -1
  69. package/lib/decide.ts +2 -7
  70. package/lib/internal/cli-route-inventory.ts +2 -0
  71. package/lib/internal/manual-validation.ts +8 -19
  72. package/lib/internal/platform-comment.ts +3 -2
  73. package/lib/internal/task-activity.ts +1 -10
  74. package/lib/internal/task-event.ts +1 -10
  75. package/lib/internal/task-ledger.ts +1 -10
  76. package/lib/internal/task-operation-registry.ts +2 -1
  77. package/lib/internal/task-qualification.ts +5 -11
  78. package/lib/internal/task-review.ts +3 -14
  79. package/lib/internal/task-short-id.ts +2 -1
  80. package/lib/internal/task-verify.ts +1 -9
  81. package/lib/internal/task-warning.ts +1 -10
  82. package/lib/internal/task-workspace.ts +39 -0
  83. package/lib/merge.ts +4 -3
  84. package/lib/platform/pr-summary.ts +7 -16
  85. package/lib/platform/pull-requests.ts +3 -24
  86. package/lib/pr-review/evidence-grading.ts +3 -2
  87. package/lib/process-data/index.ts +4 -3
  88. package/lib/process-data/sources.ts +6 -0
  89. package/lib/run/index.ts +3 -2
  90. package/lib/sandbox/commands/create.ts +5 -1
  91. package/lib/sandbox/commands/enter.ts +1 -1
  92. package/lib/sandbox/commands/list-running.ts +2 -1
  93. package/lib/sandbox/control/client.ts +7 -12
  94. package/lib/sandbox/control/completed-reentry.ts +2 -1
  95. package/lib/sandbox/control/task-view.ts +4 -2
  96. package/lib/sandbox/mounts.ts +4 -4
  97. package/lib/sandbox/recovery.ts +26 -18
  98. package/lib/sandbox/removal.ts +3 -26
  99. package/lib/sandbox/task-resolver.ts +9 -6
  100. package/lib/sandbox/workspace-identity.ts +6 -5
  101. package/lib/sandbox/workspace-view.ts +28 -20
  102. package/lib/task/activity-intent.ts +3 -17
  103. package/lib/task/artifact-lifecycle.ts +39 -11
  104. package/lib/task/artifact-operations.ts +28 -35
  105. package/lib/task/capabilities.ts +2 -2
  106. package/lib/task/commands/ls.ts +4 -3
  107. package/lib/task/commands/status.ts +1 -1
  108. package/lib/task/commit-operation.ts +5 -6
  109. package/lib/task/control-authority.ts +29 -35
  110. package/lib/task/create-service.ts +2 -4
  111. package/lib/task/create.ts +10 -51
  112. package/lib/task/delegation-receipts.ts +1 -1
  113. package/lib/task/delivery.ts +2 -10
  114. package/lib/task/events.ts +5 -32
  115. package/lib/task/finalization.ts +16 -24
  116. package/lib/task/lifecycle.ts +9 -50
  117. package/lib/task/local-artifact-finalization.ts +1 -4
  118. package/lib/task/orchestration.ts +31 -80
  119. package/lib/task/platform-operation-recovery.ts +1 -2
  120. package/lib/task/resolve-ref.ts +18 -12
  121. package/lib/task/review-finalization.ts +2 -52
  122. package/lib/task/review-identity.ts +3 -1
  123. package/lib/task/short-id.ts +10 -8
  124. package/lib/task/verification-engine.ts +20 -62
  125. package/lib/task/workspace-root.ts +78 -0
  126. package/lib/task/workspace-snapshot.ts +4 -3
  127. package/package.json +1 -1
  128. package/templates/.agents/QUICKSTART.en.md +19 -8
  129. package/templates/.agents/QUICKSTART.zh-CN.md +19 -8
  130. package/templates/.agents/README.en.md +10 -15
  131. package/templates/.agents/README.zh-CN.md +9 -13
  132. package/templates/.agents/rules/issue-sync.en.md +1 -1
  133. package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
  134. package/templates/.agents/rules/lifecycle-orchestration.en.md +1 -1
  135. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +1 -1
  136. package/templates/.agents/rules/next-step-output.en.md +2 -2
  137. package/templates/.agents/rules/next-step-output.zh-CN.md +2 -2
  138. package/templates/.agents/rules/pr-sync.en.md +1 -1
  139. package/templates/.agents/rules/pr-sync.zh-CN.md +1 -1
  140. package/templates/.agents/rules/release-commands.en.md +3 -0
  141. package/templates/.agents/rules/release-commands.zh-CN.md +3 -0
  142. package/templates/.agents/rules/task-management.en.md +0 -2
  143. package/templates/.agents/rules/task-management.zh-CN.md +0 -2
  144. package/templates/.agents/rules/task-short-id.en.md +2 -2
  145. package/templates/.agents/rules/task-short-id.zh-CN.md +2 -2
  146. package/templates/.agents/scripts/task-short-id.js +2 -8
  147. package/templates/.agents/skills/analyze-task/SKILL.en.md +6 -6
  148. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +6 -6
  149. package/templates/.agents/skills/analyze-task/config/verify.en.json +0 -1
  150. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +0 -1
  151. package/templates/.agents/skills/archive-tasks/SKILL.en.md +5 -5
  152. package/templates/.agents/skills/archive-tasks/SKILL.zh-CN.md +5 -5
  153. package/templates/.agents/skills/archive-tasks/scripts/archive-tasks.sh +10 -2
  154. package/templates/.agents/skills/block-task/SKILL.en.md +4 -4
  155. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +5 -5
  156. package/templates/.agents/skills/block-task/config/verify.json +0 -1
  157. package/templates/.agents/skills/cancel-task/SKILL.en.md +6 -6
  158. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +6 -6
  159. package/templates/.agents/skills/cancel-task/config/verify.json +0 -1
  160. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  161. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +3 -3
  162. package/templates/.agents/skills/code-task/config/verify.en.json +0 -1
  163. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +0 -1
  164. package/templates/.agents/skills/code-task/reference/output-template.en.md +1 -1
  165. package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +1 -1
  166. package/templates/.agents/skills/commit/SKILL.en.md +1 -1
  167. package/templates/.agents/skills/commit/SKILL.zh-CN.md +1 -1
  168. package/templates/.agents/skills/commit/config/verify.json +0 -1
  169. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +2 -2
  170. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +2 -2
  171. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
  172. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
  173. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +2 -2
  174. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +2 -2
  175. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +0 -1
  176. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +0 -1
  177. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
  178. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
  179. package/templates/.agents/skills/complete-task/SKILL.en.md +7 -7
  180. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +8 -8
  181. package/templates/.agents/skills/complete-task/config/verify.en.json +0 -1
  182. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +0 -1
  183. package/templates/.agents/skills/create-pr/SKILL.en.md +3 -3
  184. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +3 -3
  185. package/templates/.agents/skills/create-pr/config/verify.json +0 -1
  186. package/templates/.agents/skills/create-pr/reference/change-report.en.md +1 -1
  187. package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +1 -1
  188. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
  189. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
  190. package/templates/.agents/skills/create-release-note/SKILL.en.md +2 -2
  191. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +2 -2
  192. package/templates/.agents/skills/create-task/SKILL.en.md +4 -4
  193. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +4 -4
  194. package/templates/.agents/skills/create-task/config/verify.json +0 -1
  195. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  196. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  197. package/templates/.agents/skills/import-codescan/config/verify.json +0 -1
  198. package/templates/.agents/skills/import-dependabot/SKILL.en.md +3 -3
  199. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +3 -3
  200. package/templates/.agents/skills/import-dependabot/config/verify.json +0 -1
  201. package/templates/.agents/skills/import-issue/SKILL.en.md +5 -5
  202. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -5
  203. package/templates/.agents/skills/import-issue/config/verify.json +0 -1
  204. package/templates/.agents/skills/plan-task/SKILL.en.md +5 -5
  205. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -5
  206. package/templates/.agents/skills/plan-task/config/verify.en.json +0 -1
  207. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +0 -1
  208. package/templates/.agents/skills/restore-task/SKILL.en.md +2 -2
  209. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +3 -3
  210. package/templates/.agents/skills/restore-task/config/verify.json +0 -1
  211. package/templates/.agents/skills/review-analysis/SKILL.en.md +1 -1
  212. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
  213. package/templates/.agents/skills/review-analysis/config/verify.en.json +0 -1
  214. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +0 -1
  215. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +5 -5
  216. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +5 -5
  217. package/templates/.agents/skills/review-code/SKILL.en.md +2 -2
  218. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
  219. package/templates/.agents/skills/review-code/reference/output-templates.en.md +4 -4
  220. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +4 -4
  221. package/templates/.agents/skills/review-plan/SKILL.en.md +1 -1
  222. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
  223. package/templates/.agents/skills/review-plan/config/verify.en.json +0 -1
  224. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +0 -1
  225. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +5 -5
  226. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +5 -5
  227. package/templates/.agents/skills/review-pr/SKILL.en.md +2 -2
  228. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +2 -2
  229. package/templates/.agents/skills/review-pr/config/verify.en.json +0 -1
  230. package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +0 -1
  231. package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +1 -1
  232. package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +1 -1
  233. package/templates/.agents/skills/run-manual-validation/config/verify.en.json +0 -1
  234. package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +0 -1
  235. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  236. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  237. package/templates/.agents/skills/test/SKILL.en.md +0 -3
  238. package/templates/.agents/skills/test/SKILL.zh-CN.md +0 -3
  239. package/templates/.agents/skills/test-integration/SKILL.en.md +0 -3
  240. package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +0 -3
  241. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +13 -6
  242. package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +0 -3
  243. package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +0 -3
  244. package/templates/.agents/skills/watch-pr/SKILL.en.md +3 -3
  245. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +3 -3
  246. package/templates/.agents/skills/watch-pr/config/verify.json +0 -1
  247. package/templates/.agents/templates/handoff.en.md +1 -1
  248. package/templates/.agents/templates/handoff.zh-CN.md +1 -1
  249. package/templates/.agents/workflows/bug-fix.en.yaml +1 -1
  250. package/templates/.agents/workflows/feature-development.en.yaml +1 -1
  251. package/templates/.agents/workflows/refactoring.en.yaml +1 -1
  252. package/dist/lib/task/task-execution-lock.js +0 -250
  253. package/lib/task/task-execution-lock.ts +0 -320
@@ -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)
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { parseTypedTaskFrontmatter } from './frontmatter.js';
4
+ import { resolveProjectTaskWorkspaceRoot } from './workspace-root.js';
4
5
  const REGISTRY_NAME = '.short-ids.json';
5
6
  const LOCK_NAME = '.short-ids.json.lock';
6
7
  function normalizeShortIdInput(input, opts) {
@@ -42,7 +43,7 @@ function resolveShortIdReadOnly(input, repoRoot, opts) {
42
43
  return shortIdFailure('SHORT_ID_NOT_FOUND', `short id '${input}' not found in active task registry`);
43
44
  }
44
45
  const key = normalized.value;
45
- const registryPath = path.join(repoRoot, '.agents', 'workspace', 'active', REGISTRY_NAME);
46
+ const registryPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', REGISTRY_NAME);
46
47
  if (!fs.existsSync(registryPath)) {
47
48
  return shortIdFailure('SHORT_ID_REGISTRY_NOT_FOUND', `short id '${key}' not found; active task registry is empty.`);
48
49
  }
@@ -95,8 +96,9 @@ function resolveShortIdReadOnly(input, repoRoot, opts) {
95
96
  : `short id '${key}' not found in task short-id registry.`;
96
97
  return shortIdFailure('SHORT_ID_NOT_FOUND', message);
97
98
  }
98
- const activeTask = path.join(repoRoot, '.agents', 'workspace', 'active', taskId, 'task.md');
99
- const completedTask = path.join(repoRoot, '.agents', 'workspace', 'completed', taskId, 'task.md');
99
+ const workspaceRoot = resolveProjectTaskWorkspaceRoot(repoRoot);
100
+ const activeTask = path.join(workspaceRoot, 'active', taskId, 'task.md');
101
+ const completedTask = path.join(workspaceRoot, 'completed', taskId, 'task.md');
100
102
  let isValidCompletedTask = false;
101
103
  try {
102
104
  const task = parseTypedTaskFrontmatter(fs.readFileSync(completedTask, 'utf8'));
@@ -210,7 +212,7 @@ function writeRegistry(registryPath, registry) {
210
212
  }
211
213
  }
212
214
  function mutateShortIdRegistry(repoRoot, taskId, requested) {
213
- const activeDir = path.join(repoRoot, '.agents', 'workspace', 'active');
215
+ const activeDir = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active');
214
216
  return mutateShortIdRegistryAt(activeDir, configuredShortIdLength(repoRoot), taskId, requested);
215
217
  }
216
218
  function mutateShortIdRegistryAt(activeDir, width, taskId, requested, onlyReleaseWhenInactive = false, pruneOrphans = true) {
@@ -267,7 +269,7 @@ function mutateShortIdRegistryAt(activeDir, width, taskId, requested, onlyReleas
267
269
  });
268
270
  }
269
271
  function releaseStaleShortIdRegistry(repoRoot, taskId) {
270
- const activeDir = path.join(repoRoot, '.agents', 'workspace', 'active');
272
+ const activeDir = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active');
271
273
  return mutateShortIdRegistryAt(activeDir, configuredShortIdLength(repoRoot), taskId, 'release', true, false);
272
274
  }
273
275
  function executeShortIdCommand(request) {
@@ -327,7 +329,7 @@ function executeShortIdCommand(request) {
327
329
  }
328
330
  }
329
331
  function readRegistry(repoRoot) {
330
- const registryPath = path.join(repoRoot, '.agents', 'workspace', 'active', REGISTRY_NAME);
332
+ const registryPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', REGISTRY_NAME);
331
333
  if (!fs.existsSync(registryPath))
332
334
  return null;
333
335
  try {
@@ -342,7 +344,7 @@ function readRegistry(repoRoot) {
342
344
  }
343
345
  }
344
346
  function readBranchFromTaskMd(repoRoot, taskId) {
345
- const taskMdPath = path.join(repoRoot, '.agents', 'workspace', 'active', taskId, 'task.md');
347
+ const taskMdPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', taskId, 'task.md');
346
348
  if (!fs.existsSync(taskMdPath))
347
349
  return null;
348
350
  const content = fs.readFileSync(taskMdPath, 'utf8');
@@ -362,7 +364,7 @@ function loadShortIdByTaskId(repoRoot) {
362
364
  return map;
363
365
  }
364
366
  function inspectShortIdRegistry(repoRoot, shortIdLength = configuredShortIdLength(repoRoot)) {
365
- const registryPath = path.join(repoRoot, '.agents', 'workspace', 'active', REGISTRY_NAME);
367
+ const registryPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', REGISTRY_NAME);
366
368
  if (!fs.existsSync(registryPath)) {
367
369
  return {
368
370
  status: 'missing',
@@ -54,9 +54,7 @@ const DEFAULT_REQUIRED_FIELDS = [
54
54
  "assigned_to"
55
55
  ];
56
56
  const DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?$/;
57
- // Start markers (action suffixed with ` [started]`) are excluded from the
58
- // "latest action" / freshness computation so a step's in-flight marker never
59
- // satisfies a skill's expected_action_pattern; the matching done entry does.
57
+ // Started rows do not represent completed lifecycle actions.
60
58
  const ACTIVITY_LOG_STARTED_RE = /\s*\[started\]\s*$/;
61
59
  const BRANCH_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
62
60
  // Review disagreement ledger (see .agents/rules/review-handshake.md).
@@ -322,15 +320,9 @@ function checkTaskMeta({ taskDir, config, repositoryRoot, skillName, artifactFil
322
320
  if (expectedStep && metadata.current_step !== expectedStep) {
323
321
  let validLifecycleArtifact = false;
324
322
  if (currentTask) {
325
- const activityConfig = loadVerificationConfig(repositoryRoot, skillName).checks?.["activity-log"];
326
323
  const { section, invalidEntries } = inspectActivityLog(task.content);
327
- if (activityConfig && section && invalidEntries.length === 0) {
328
- let latestAction = "";
329
- for (const entry of section.entries) {
330
- if (!ACTIVITY_LOG_STARTED_RE.test(entry.step))
331
- latestAction = entry.step;
332
- }
333
- validLifecycleArtifact = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, activityConfig, task, section.entries, latestAction)?.status === "pass";
324
+ if (section && invalidEntries.length === 0) {
325
+ validLifecycleArtifact = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task, section.entries)?.status === "pass";
334
326
  }
335
327
  }
336
328
  if (!validLifecycleArtifact) {
@@ -634,14 +626,14 @@ function checkImplementationInput({ taskDir, artifactFile }) {
634
626
  return passResult("implementation-input", `${actionDecision} matches Activity Log, report, and task table`);
635
627
  }
636
628
  const ARTIFACT_ACTIVITY_STAGES = {
637
- "analyze-task": { family: "analysis", event: "analyze.completed" },
638
- "plan-task": { family: "plan", event: "plan.completed" },
639
- "review-analysis": { family: "review-analysis", event: "review-analysis.completed" },
640
- "review-plan": { family: "review-plan", event: "review-plan.completed" },
641
- "code-task": { family: "code", event: "code.completed" },
642
- "review-code": { family: "review-code", event: "review-code.completed" }
629
+ "analyze-task": { family: "analysis", event: "analyze.completed", action: "Analyze Task" },
630
+ "plan-task": { family: "plan", event: "plan.completed", action: "Plan Task" },
631
+ "review-analysis": { family: "review-analysis", event: "review-analysis.completed", action: "Review Analysis" },
632
+ "review-plan": { family: "review-plan", event: "review-plan.completed", action: "Review Plan" },
633
+ "code-task": { family: "code", event: "code.completed", action: "Code Task" },
634
+ "review-code": { family: "review-code", event: "review-code.completed", action: "Review Code" }
643
635
  };
644
- function checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, config, task, entries, latestAction) {
636
+ function checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task, entries) {
645
637
  const stage = ARTIFACT_ACTIVITY_STAGES[skillName];
646
638
  if (!stage)
647
639
  return null;
@@ -680,26 +672,18 @@ function checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, con
680
672
  return failResult("activity-log", `Input '${input.name}' changed or is no longer current; rerun ${skillName} to refresh '${output}'`);
681
673
  }
682
674
  }
683
- const expectedAction = new RegExp(config.expected_action_pattern);
675
+ const roundActionPattern = new RegExp(`^${stage.action} \\(Round ${identity.round}(?:, [^)]+)?\\)$`);
684
676
  const roundAction = entries.find((entry) => {
685
- if (ACTIVITY_LOG_STARTED_RE.test(entry.step))
686
- return false;
687
- if (!expectedAction.test(entry.step))
688
- return false;
689
- expectedAction.lastIndex = 0;
690
- const actionRound = /\(Round (\d+)/.exec(entry.step)?.[1];
691
- return actionRound === String(identity.round) && entry.note.includes(`→ ${output}`);
677
+ return !ACTIVITY_LOG_STARTED_RE.test(entry.step)
678
+ && roundActionPattern.test(entry.step)
679
+ && entry.note.includes(`→ ${output}`);
692
680
  });
693
681
  if (!roundAction) {
694
682
  return failResult("activity-log", `No completed Activity Log row records '${output}' for ${skillName} Round ${identity.round}`);
695
683
  }
696
- if (skillName === "plan-task" && /^(?:Human Decision|Decision)\b/.test(latestAction)
697
- && expectedAction.test(latestAction)) {
698
- return passResult("activity-log", `Plan completion '${output}' is current; latest action '${latestAction}' is a human decision`);
699
- }
700
684
  return passResult("activity-log", `Current ${stage.family} completion '${output}' is valid for Round ${identity.round}`);
701
685
  }
702
- function checkActivityLog({ taskDir, config, skillName, artifactFile }) {
686
+ function checkActivityLog({ taskDir, skillName, artifactFile }) {
703
687
  const task = loadTask(taskDir);
704
688
  if (!task.ok) {
705
689
  return failResult("activity-log", task.message);
@@ -712,37 +696,14 @@ function checkActivityLog({ taskDir, config, skillName, artifactFile }) {
712
696
  const entries = section.entries;
713
697
  if (entries.length === 0)
714
698
  return failResult("activity-log", "Activity Log has no entries");
715
- let latestAction = "";
716
- let latestTimestamp = "";
717
- const doneActions = [];
718
699
  for (const entry of entries) {
719
700
  if (!entry.note.trim())
720
701
  return failResult("activity-log", "Activity Log entry note is required");
721
- const { time: timestamp, step: action } = entry;
722
- // A `[started]` marker is not a terminal action: keep latestAction/latestTimestamp
723
- // on the most recent done entry so expected_action_pattern sees it.
724
- if (!ACTIVITY_LOG_STARTED_RE.test(action)) {
725
- latestTimestamp = timestamp;
726
- latestAction = action;
727
- doneActions.push(action);
728
- }
729
702
  }
730
- const artifactLifecycleResult = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, config, task, entries, latestAction);
703
+ const artifactLifecycleResult = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task, entries);
731
704
  if (artifactLifecycleResult)
732
705
  return artifactLifecycleResult;
733
- if (config.expected_action_pattern && !new RegExp(config.expected_action_pattern).test(latestAction)) {
734
- const expected = new RegExp(config.expected_action_pattern);
735
- let index = doneActions.length - 1;
736
- while (index >= 0 && doneActions[index] === 'Commit' && !expected.test(doneActions[index]))
737
- index -= 1;
738
- if (index >= 0 && expected.test(doneActions[index])) {
739
- latestAction = doneActions[index];
740
- }
741
- }
742
- if (config.expected_action_pattern && !new RegExp(config.expected_action_pattern).test(latestAction)) {
743
- return failResult("activity-log", `Latest action '${latestAction}' does not match '${config.expected_action_pattern}'`);
744
- }
745
- return passResult("activity-log", `Latest entry '${latestAction}' at ${latestTimestamp}`);
706
+ return passResult("activity-log", "Activity Log is valid");
746
707
  }
747
708
  function checkCompletionChecklist({ taskDir, config }) {
748
709
  const task = loadTask(taskDir);
@@ -932,10 +893,10 @@ async function checkPostReviewCommit({ taskDir, config, repositoryRoot }) {
932
893
  }
933
894
  let gitRoot;
934
895
  try {
935
- gitRoot = execFileSync("git", ["-C", taskDir, "rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
896
+ gitRoot = execFileSync("git", ["-C", repositoryRoot, "rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
936
897
  }
937
898
  catch {
938
- return blockedResult("post-review-commit", "git unavailable or task directory is not inside a git repository");
899
+ return blockedResult("post-review-commit", "git unavailable or repository root is not inside a git repository");
939
900
  }
940
901
  const task = loadTask(taskDir);
941
902
  if (!task.ok)