@zq-silk/yui 0.15.12 → 0.16.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 (236) hide show
  1. package/ARCHITECTURE.md +3 -2
  2. package/ARCHITECTURE.zh-CN.md +3 -2
  3. package/dist/artifacts/artifactCommitLock.js +16 -55
  4. package/dist/artifacts/taskArtifactRepository.js +3 -3
  5. package/dist/cli/agentConfigurationPicker.js +1 -1
  6. package/dist/cli/commandCatalog.js +57 -41
  7. package/dist/cli/completion.js +18 -18
  8. package/dist/cli/completionWizard.js +1 -1
  9. package/dist/cli/dynamicCompletion.js +1 -1
  10. package/dist/cli/interactionPolicy.js +7 -3
  11. package/dist/cli/invocationAuthority.js +64 -0
  12. package/dist/cli/managedDiagnostics.js +1 -1
  13. package/dist/cli/parseRepeatable.js +35 -0
  14. package/dist/cli/updatePorts.js +26 -5
  15. package/dist/cli.js +1280 -1243
  16. package/dist/commands/agentCommands.js +4 -4
  17. package/dist/commands/capabilityCommands.js +1 -1
  18. package/dist/commands/configCommands.js +6 -57
  19. package/dist/commands/configOverview.js +2 -2
  20. package/dist/commands/durableJobCommands.js +12 -6
  21. package/dist/commands/globalRoleCommands.js +53 -29
  22. package/dist/commands/grantCommands.js +0 -3
  23. package/dist/commands/jobCommands.js +1 -4
  24. package/dist/commands/operatorCommands.js +3 -3
  25. package/dist/commands/projectCommands.js +1 -10
  26. package/dist/commands/resourcesCommands.js +10 -40
  27. package/dist/commands/roleConfiguration.js +2 -6
  28. package/dist/commands/taskActivationCommands.js +4 -8
  29. package/dist/commands/taskAgentCapabilities.js +9 -0
  30. package/dist/commands/taskCommandSupport.js +155 -0
  31. package/dist/commands/taskCommandTypes.js +1 -0
  32. package/dist/commands/taskCommands.js +271 -710
  33. package/dist/commands/taskCompletionGate.js +1 -1
  34. package/dist/commands/taskExecutionCommands.js +1 -1
  35. package/dist/commands/taskFactCommands.js +325 -0
  36. package/dist/commands/taskInputCommands.js +12 -42
  37. package/dist/commands/taskIntegrationCommands.js +17 -57
  38. package/dist/commands/taskNextActionCommand.js +7 -6
  39. package/dist/commands/taskPublicationAdoptCommand.js +3 -3
  40. package/dist/commands/taskPublicationCommands.js +1 -1
  41. package/dist/commands/taskPublicationVerifyCommand.js +1 -1
  42. package/dist/commands/taskRemoteDeliveryCommand.js +2 -94
  43. package/dist/commands/taskUpstreamCommands.js +19 -8
  44. package/dist/commands/workflowCommands.js +6 -1
  45. package/dist/completion/completionInstaller.js +26 -26
  46. package/dist/completion/completionState.js +26 -26
  47. package/dist/completion/fileCompletionManager.js +6 -11
  48. package/dist/config/configCatalog.js +0 -2
  49. package/dist/config/timeZone.js +14 -0
  50. package/dist/config/yuiConfig.js +0 -29
  51. package/dist/context/runContextPack.js +2 -3
  52. package/dist/context/taskCatalog.js +3 -5
  53. package/dist/context/taskContext.js +139 -151
  54. package/dist/context/wakeRunReferences.js +11 -0
  55. package/dist/controller/agentCapabilities.js +58 -0
  56. package/dist/controller/agentRuntimeObserver.js +6 -11
  57. package/dist/controller/clientRuntime.js +22 -14
  58. package/dist/controller/controller.js +9 -22
  59. package/dist/controller/fileSchedulerStoreAdapter.js +117 -212
  60. package/dist/controller/jobClient.js +4 -4
  61. package/dist/controller/jobControl.js +60 -25
  62. package/dist/controller/jobSupervisor.js +4 -4
  63. package/dist/controller/providerRetryDelivery.js +7 -7
  64. package/dist/controller/runtime.js +51 -44
  65. package/dist/controller/runtimeEventProcessor.js +0 -5
  66. package/dist/controller/sessionOwnerReconciliation.js +5 -0
  67. package/dist/controller/taskAgentError.js +35 -0
  68. package/dist/coordination/workMailboxQueue.js +2 -24
  69. package/dist/core/controllerClient.js +2 -2
  70. package/dist/core/fileLockOwner.js +74 -0
  71. package/dist/decision/decision.js +17 -0
  72. package/dist/doctor/doctor.js +18 -9
  73. package/dist/event/taskEvent.js +12 -0
  74. package/dist/execution/workItemExecutionProjection.js +2 -2
  75. package/dist/executor/agentCapabilityConfig.js +43 -0
  76. package/dist/executor/agentConfigurationCatalog.js +49 -11
  77. package/dist/executor/agentExecutor.js +5 -8
  78. package/dist/executor/fileRoleLaunchPlanner.js +11 -53
  79. package/dist/executor/taskAgentCapabilities.js +64 -0
  80. package/dist/integration/deliveryObligation.js +1 -69
  81. package/dist/integration/gitIntegrationService.js +60 -84
  82. package/dist/integration/integrationAttempt.js +3 -14
  83. package/dist/integration/integrationSourceApplication.js +4 -12
  84. package/dist/integration/manifestTags.js +2 -2
  85. package/dist/job/durableJob.js +4 -25
  86. package/dist/job/jobAssignmentScope.js +22 -0
  87. package/dist/job/jobOperation.js +16 -0
  88. package/dist/job/jobRunner.js +2 -1
  89. package/dist/job/stepDirectory.js +15 -0
  90. package/dist/kernel/builtinCapabilities.js +15 -11
  91. package/dist/kernel/kernelPorts.js +1 -17
  92. package/dist/lifecycle/exactRunTerminalization.js +1 -9
  93. package/dist/message/inputControlResolution.js +3 -4
  94. package/dist/message/message.js +17 -20
  95. package/dist/message/messageContinuation.js +1 -1
  96. package/dist/milestone/milestone.js +11 -0
  97. package/dist/observability/orchestrationMetrics.js +24 -1
  98. package/dist/observability/runtimeIdentity.js +1 -17
  99. package/dist/output/agentConfigurationPresentation.js +2 -0
  100. package/dist/output/timePresentation.js +1 -14
  101. package/dist/plugins/pluginService.js +12 -4
  102. package/dist/release/releaseWorkflowPorts.js +45 -96
  103. package/dist/release/runtimeRelease.js +9 -15
  104. package/dist/repository/projectMaintenanceLock.js +23 -64
  105. package/dist/repository/taskBaseFreshness.js +1 -1
  106. package/dist/repository/taskWorkspaceCoordinator.js +13 -22
  107. package/dist/repository/taskWorkspacePreparer.js +29 -25
  108. package/dist/repository/workspaceCleanupInspection.js +5 -5
  109. package/dist/resources/autoResourceGc.js +4 -77
  110. package/dist/resources/liveReferences.js +7 -54
  111. package/dist/resources/resourceDiscovery.js +5 -118
  112. package/dist/resources/resourceGc.js +233 -181
  113. package/dist/resources/resourceRegistrar.js +5 -4
  114. package/dist/resources/resourceRegistry.js +3 -37
  115. package/dist/resources/resourceRegistryStore.js +13 -36
  116. package/dist/resources/sqliteResourceRegistry.js +43 -26
  117. package/dist/review/deltaRecheck.js +1 -1
  118. package/dist/review/reviewAcceptance.js +1 -1
  119. package/dist/review/reviewDecision.js +1 -1
  120. package/dist/review/reviewRound.js +8 -7
  121. package/dist/review/taskFinalReviewContractResolution.js +1 -1
  122. package/dist/runtime/acpProtocol.js +4 -51
  123. package/dist/runtime/acpSession.js +10 -75
  124. package/dist/runtime/acpSessionConfiguration.js +1 -8
  125. package/dist/runtime/agentEndpoint.js +3 -2
  126. package/dist/runtime/agentFailureContext.js +43 -0
  127. package/dist/runtime/agentHost.js +15 -15
  128. package/dist/runtime/codexInteractiveHost.js +2 -2
  129. package/dist/runtime/index.js +0 -1
  130. package/dist/runtime/managedCaller.js +21 -1
  131. package/dist/runtime/providerErrors.js +38 -0
  132. package/dist/runtime/runtimeObservation.js +0 -5
  133. package/dist/runtime/runtimeSessionCandidate.js +2 -3
  134. package/dist/runtime/sessionOwnerIdentity.js +1 -1
  135. package/dist/runtime/structuredProviderHost.js +4 -41
  136. package/dist/runtime/tmuxAdapters.js +6 -8
  137. package/dist/scheduler/activeRoleRunDelivery.js +7 -7
  138. package/dist/scheduler/leaderWakeupProcessor.js +19 -6
  139. package/dist/scheduler/operatorEvent.js +12 -20
  140. package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
  141. package/dist/scheduler/ports.js +5 -8
  142. package/dist/scheduler/roleRunLiveness.js +4 -4
  143. package/dist/scheduler/roleRunStall.js +16 -23
  144. package/dist/scheduler/taskExecutionProjection.js +25 -33
  145. package/dist/scheduler/taskObservabilityProjection.js +0 -1
  146. package/dist/scheduler/taskWake.js +5 -10
  147. package/dist/scheduler/wakeReason.js +2 -0
  148. package/dist/scheduler/wakeupQueue.js +2 -4
  149. package/dist/setup/setupCommand.js +1 -1
  150. package/dist/storage/contextRecords.js +106 -0
  151. package/dist/storage/currentTaskStore.js +1 -1
  152. package/dist/storage/homeLayout.js +13 -17
  153. package/dist/storage/migrations/agentFailureContext.js +22 -0
  154. package/dist/storage/migrations/currentInputContract.js +86 -0
  155. package/dist/storage/migrations/currentRuntimeContract.js +228 -0
  156. package/dist/storage/migrations/historicalVerificationPlan.js +35 -0
  157. package/dist/storage/migrations/integrationContinuation.js +5 -4
  158. package/dist/storage/migrations/narrowAgentFailureContext.js +65 -0
  159. package/dist/storage/migrations/notificationOnlyWakes.js +74 -0
  160. package/dist/storage/migrations/verificationPlanV1.js +162 -0
  161. package/dist/storage/migrations/verificationPolicy.js +74 -0
  162. package/dist/storage/migrations/workItemHistory.js +46 -0
  163. package/dist/storage/persistenceWorker.js +12 -4
  164. package/dist/storage/recordValidation.js +87 -0
  165. package/dist/storage/sqliteSchema.js +142 -1
  166. package/dist/storage/sqliteStore.js +156 -162
  167. package/dist/storage/storageSchema.js +2 -14
  168. package/dist/storage/storageVersions.js +1 -1
  169. package/dist/storage/storeRpc.js +15 -7
  170. package/dist/storage/taskStore.js +3 -7
  171. package/dist/storage/upgrade/upgradeOrchestrator.js +25 -37
  172. package/dist/task/completionReadiness.js +5 -24
  173. package/dist/task/draftPlan.js +0 -53
  174. package/dist/task/nextAction.js +7 -13
  175. package/dist/task/remoteDeliveryService.js +89 -0
  176. package/dist/task/taskActivation.js +2 -25
  177. package/dist/task/taskActivationService.js +0 -2
  178. package/dist/task/taskRecordReference.js +0 -1
  179. package/dist/task/taskSubmission.js +3 -14
  180. package/dist/telemetry/sqliteTelemetryBatch.js +29 -0
  181. package/dist/telemetry/sqliteTelemetryStore.js +49 -49
  182. package/dist/telemetry/telemetryWiring.js +4 -3
  183. package/dist/tmux/tmuxManager.js +29 -20
  184. package/dist/verification/gateArtifact.js +15 -24
  185. package/dist/verification/gateArtifactStore.js +14 -7
  186. package/dist/verification/verificationGateService.js +29 -88
  187. package/dist/verification/verificationPlan.js +27 -72
  188. package/dist/web/assets/client/app.js +1 -1
  189. package/dist/web/assets/client/taskSurface.js +4 -4
  190. package/dist/web/webServer.js +4 -6
  191. package/dist/web/webSnapshot.js +3 -83
  192. package/dist/web/webTaskSurface.js +17 -46
  193. package/dist/workItem/workItem.js +1 -12
  194. package/docs/architecture/capabilities-and-resources.md +14 -2
  195. package/docs/architecture/capabilities-and-resources.zh-CN.md +11 -1
  196. package/docs/managed-turn-and-session-runtime.md +83 -10
  197. package/docs/managed-turn-and-session-runtime.zh-CN.md +65 -11
  198. package/docs/plugin-sdk.md +4 -2
  199. package/docs/provider-runtime.md +3 -1
  200. package/docs/provider-runtime.zh-CN.md +4 -2
  201. package/docs/release-workflow.md +190 -7
  202. package/docs/release-workflow.zh-CN.md +139 -5
  203. package/docs/roles-and-configuration.md +29 -0
  204. package/docs/roles-and-configuration.zh-CN.md +21 -0
  205. package/docs/sqlite-control-plane-design.md +16 -3
  206. package/docs/sqlite-control-plane-design.zh-CN.md +13 -2
  207. package/docs/task-dag-semantics.md +3 -3
  208. package/docs/task-dag-semantics.zh-CN.md +2 -2
  209. package/docs/task-delivery.md +91 -5
  210. package/docs/task-delivery.zh-CN.md +72 -4
  211. package/docs/task-discovery.md +10 -11
  212. package/docs/task-discovery.zh-CN.md +8 -9
  213. package/docs/testing/verification-levels.md +145 -9
  214. package/docs/testing/verification-levels.zh-CN.md +103 -8
  215. package/package.json +1 -1
  216. package/skills/yui-leader/SKILL.md +5 -0
  217. package/skills/yui-leader/references/integration.md +9 -5
  218. package/skills/yui-leader/references/planning.md +9 -3
  219. package/skills/yui-operator/SKILL.md +15 -10
  220. package/skills/yui-runtime/SKILL.md +6 -6
  221. package/skills/yui-runtime/references/recovery.md +47 -0
  222. package/dist/agent/agentRegistry.js +0 -10
  223. package/dist/agentRun/runIdentity.js +0 -22
  224. package/dist/commands/deliveryGuardPreflight.js +0 -30
  225. package/dist/commands/taskIntegrationQueueCommands.js +0 -226
  226. package/dist/commands/taskOverviewCommand.js +0 -377
  227. package/dist/completion/completionWizard.js +0 -125
  228. package/dist/context/dispatchContext.js +0 -110
  229. package/dist/context/wakeNotification.js +0 -144
  230. package/dist/integration/integrationCheckEvidenceReuse.js +0 -53
  231. package/dist/integration/integrationQueueEntry.js +0 -191
  232. package/dist/integration/integrationQueueService.js +0 -810
  233. package/dist/release/fakeReleasePorts.js +0 -55
  234. package/dist/runtime/sessionOwnerRegistry.js +0 -137
  235. package/dist/task/deliveryGuard.js +0 -226
  236. /package/dist/{commands/taskActor.js → task/taskAuthority.js} +0 -0
@@ -1,91 +1,87 @@
1
- import { controlProviderRetry, providerRetryProjection, renderProviderRetry } from "../runtime/providerRetry.js";
2
- import { roleLaunchEventPayload, saveTaskRoleUpdate } from "../role/taskRoleUpdate.js";
3
1
  import { createHash, randomUUID } from "node:crypto";
4
- import { archiveDeliveryWarnings, archiveRetainedResources, renderArchiveDiagnostics, taskArchiveDiagnostics } from "../task/archiveDiagnostics.js";
5
- import { archiveSettlementChecks } from "../task/archivePreflight.js";
6
- import { CleanupInspectionError } from "../workspace/cleanupInspection.js";
7
2
  import { isDeepStrictEqual } from "node:util";
8
- import { createRunInput } from "../context/runInputContract.js";
9
- import { buildRunContextPack, buildRunContextDelta, contextSnapshotDeltaRefIds, expandRunContextRef, freezeWorkItemExecutionAssignmentContextSnapshot, freezeReviewStageContextSnapshot, freezeRunContextSnapshot } from "../context/runContextPack.js";
3
+ import { agentExecutionComponentLabel } from "../agent/executionComponents.js";
4
+ import { createRun, runExecutionObservation, runPurposeAdmitsTaskState, withRunContextSnapshot } from "../agentRun/agentRun.js";
5
+ import { isGitArtifactRefString, parseGitArtifactRef } from "../artifacts/gitArtifactRef.js";
10
6
  import { contextSnapshotRef } from "../context/contextSnapshot.js";
7
+ import { buildRunContextDelta, buildRunContextPack, contextSnapshotDeltaRefIds, expandRunContextRef, freezeReviewStageContextSnapshot, freezeRunContextSnapshot, freezeWorkItemExecutionAssignmentContextSnapshot, synthesisSourceRunIds } from "../context/runContextPack.js";
8
+ import { createRunInput } from "../context/runInputContract.js";
9
+ import { parseTaskCatalogOptions, readTaskCatalog, renderTaskCatalog } from "../context/taskCatalog.js";
10
+ import { listContextMessages } from "../context/taskContext.js";
11
+ import { referencedWakeRunIds } from "../context/wakeRunReferences.js";
12
+ import { completeProcessing, releaseProcessing } from "../coordination/workMailbox.js";
13
+ import { enqueueRoleRunDispatch, enqueueWork, settleExactWorkExecution } from "../coordination/workMailboxQueue.js";
11
14
  import { CliError, dataError, roleNotFound, runtimeError, taskNotFound, usageError } from "../errors/cliError.js";
12
- import { createTaskEvent } from "../event/taskEvent.js";
13
- import { createTaskRecordRetirement, isTaskRecordRetired, operationalTaskRecords, taskRecordRetirement } from "../task/taskRecordRetirement.js";
14
- import { referencedWakeRunIds } from "../context/wakeNotification.js";
15
- import { isRoleRunStalled, RUN_PROGRESS_EVENT, RUN_RECOVERED_EVENT } from "../scheduler/roleRunStall.js";
16
- import { readCommandText } from "./textInput.js";
17
- import { assertTaskCompletionPublishedTreeProof } from "./taskCompletionGate.js";
18
- import { createRoleSessionSet, roleAgentSessionResumeMode, updateTaskRoleProviderRuntime, taskRoleControlTarget } from "../executor/agentExecutor.js";
19
- import { transferProviderAuthority, currentProviderConversation } from "../runtime/providerRuntimeIdentity.js";
15
+ import { dispatchReviewSynthesis, selectedReviewSynthesisProducers } from "../execution/reviewMainRun.js";
16
+ import { createExecutionGroup, createReviewExecutionAssignment, createWorkItemExecutionAssignment, createWorkItemExecutionGroup, updateExecutionLane as updateUnifiedExecutionLane, updateWorkItemExecutionLane, workItemExecutionGroupSettled } from "../execution/workItemExecution.js";
17
+ import { projectWorkItemExecution } from "../execution/workItemExecutionProjection.js";
18
+ import { dispatchWorkItemSynthesis, selectedWorkItemSynthesisProducers } from "../execution/workItemMainRun.js";
19
+ import { createRoleSessionSet, roleAgentSessionResumeMode, taskRoleControlTarget, updateTaskRoleProviderRuntime } from "../executor/agentExecutor.js";
20
20
  import { resolveEffectiveLaunch } from "../executor/effectiveLaunch.js";
21
- import { defaultTableWidth, renderTable } from "../output/table.js";
22
- import { agentExecutionComponentLabel } from "../agent/executionComponents.js";
23
- import { agentRunConfigurationLabel, renderAgentRunConfiguration } from "../output/agentRunConfigurationPresentation.js";
24
- import { formatTimestamp } from "../output/timePresentation.js";
25
- import { renderRoleDetails, renderRoleLaunchComparison } from "../output/rolePresentation.js";
26
- import { createTaskMessage, expandTaskMessageResult, recordTaskMessageControlOutcome, taskMessageAuthorLabel, taskMessageInputControlState, updateDraftTaskMessage, withSubmissionReceipt, TASK_SUBMISSION_INTENTS } from "../message/message.js";
27
- import { assertDraftTaskExecutionFree, validateDraftWorkItemEdit } from "../task/draftPlan.js";
28
- import { TASK_PLANNING_ENTERED_EVENT, decideSubmissionRouting, describeSubmissionFeedback, draftActivationState, draftHasEnteredPlanning, normalizeSubmissionIntent, sameSubmissionTarget } from "../task/taskSubmission.js";
29
- import { recordTaskActivationRequestInTransaction, taskActivationOperationRef } from "../task/taskActivationService.js";
30
21
  import { cancelInputRequest } from "../input/inputRequest.js";
31
22
  import { retireExactActiveRun, terminalizeExactTaskRun, validateExactRunReviewRound } from "../lifecycle/exactRunTerminalization.js";
32
- import { copyGlobalRoleToTaskRole, createRole, createRoleAgentBinding, switchActiveRoleAgent, unbindRoleAgent, updateRole } from "../role/role.js";
33
- import { createRun, runPurposeAdmitsTaskState, runExecutionObservation, withRunContextSnapshot } from "../agentRun/agentRun.js";
34
- import { createReviewRound, createTaskReviewRound, createTaskDeltaReviewRound, attachReviewExecutionGroup, finishReviewRound, recordReviewWorkspaceDisposition, retryReviewRound, retryRunningReviewExecutionLane, retryTaskReviewRound, startReplicatedReviewRound, startReviewRound, updateReviewExecutionGroup, validateTaskReviewCandidate } from "../review/reviewRound.js";
23
+ import { resolveTaskInputControl } from "../message/inputControlResolution.js";
24
+ import { createTaskMessage, expandTaskMessageResult, recordTaskMessageControlOutcome, TASK_SUBMISSION_INTENTS, taskMessageAuthorLabel, taskMessageInputControlState, updateDraftTaskMessage, withSubmissionReceipt } from "../message/message.js";
25
+ import { messageContinuationBlocker, resolveMessageRecipient } from "../message/messageContinuation.js";
26
+ import { findTaskInterrupt, reserveTaskInterrupt, taskInterruptReceipt, taskInterruptWasRejected } from "../message/taskInterrupt.js";
27
+ import { agentRunConfigurationLabel, renderAgentRunConfiguration } from "../output/agentRunConfigurationPresentation.js";
28
+ import { renderRoleDetails, renderRoleLaunchComparison } from "../output/rolePresentation.js";
29
+ import { defaultTableWidth, renderTable } from "../output/table.js";
30
+ import { requireResolvedAgentProfileRuntime } from "../profile/agentProfileRuntime.js";
31
+ import { assertProjectActive, resolveProject } from "../repository/project.js";
32
+ import { createProjectResources } from "../resources/projectResourceService.js";
35
33
  import { buildDeltaRecheckDispatchContext, verifyDeltaRecheckDiff } from "../review/deltaRecheck.js";
36
34
  import { isCompletedTaskReviewEvidence } from "../review/reviewAcceptance.js";
37
35
  import { projectReviewerAvailability } from "../review/reviewerAvailability.js";
38
- import { createTaskBrief, updateTaskBrief } from "../brief/taskBrief.js";
39
- import { createDecision, supersedeDecision } from "../decision/decision.js";
40
- import { createMilestone } from "../milestone/milestone.js";
41
- import { runPublicationCommand } from "./taskPublicationCommands.js";
42
- import { runTaskActivationCommand, nonLeaderActivationIdentity } from "./taskActivationCommands.js";
43
- import { assertTaskRemoteDeliveryProof, projectTaskRemoteDeliveryFromStore, renderTaskRemoteDelivery, runTaskRemoteDeliveryCommand } from "./taskRemoteDeliveryCommand.js";
44
- import { enqueueRoleRunDispatch, enqueueWork, settleExactWorkExecution } from "../coordination/workMailboxQueue.js";
45
- import { completeProcessing } from "../coordination/workMailbox.js";
46
- import { runtimeLifecycleTarget, RUNTIME_SESSION_REPLACE_REQUIRED_REASON } from "../runtime/lifecycleReservation.js";
36
+ import { attachReviewExecutionGroup, createReviewRound, createTaskDeltaReviewRound, createTaskReviewRound, finishReviewRound, recordReviewWorkspaceDisposition, retryReviewRound, retryRunningReviewExecutionLane, retryTaskReviewRound, startReplicatedReviewRound, startReviewRound, updateReviewExecutionGroup, validateTaskReviewCandidate } from "../review/reviewRound.js";
37
+ import { sameTaskFinalReviewContract, taskFinalReviewConfig, validateTaskFinalReviewContract } from "../review/taskFinalReviewContract.js";
38
+ import { resolveRecordedTaskFinalReviewContract } from "../review/taskFinalReviewContractResolution.js";
39
+ import { copyGlobalRoleToTaskRole, createRole, createRoleAgentBinding, switchActiveRoleAgent, unbindRoleAgent, updateRole } from "../role/role.js";
40
+ import { roleLaunchEventPayload, saveTaskRoleUpdate } from "../role/taskRoleUpdate.js";
41
+ import { RUNTIME_SESSION_REPLACE_REQUIRED_REASON, runtimeLifecycleTarget } from "../runtime/lifecycleReservation.js";
42
+ import { currentManagedRuntime, resolveManagedTaskReader } from "../runtime/managedCaller.js";
43
+ import { controlProviderRetry, providerRetryProjection, renderProviderRetry } from "../runtime/providerRetry.js";
44
+ import { currentProviderConversation, transferProviderAuthority } from "../runtime/providerRuntimeIdentity.js";
47
45
  import { projectProviderContinuations } from "../runtime/runtimeContinuationProjection.js";
48
46
  import { runtimeObservationFromTaskEvent } from "../runtime/runtimeObservation.js";
49
- import { addTaskProjectBinding, archiveTask, completeTask, createTask, retireTask, reopenTask, taskOwnsManagedWorkspace, updateTaskMetadata } from "../task/task.js";
50
- import { resolveTaskRecordReference } from "../task/taskRecordReference.js";
51
- import { projectCompletionReadiness } from "../task/completionReadiness.js";
52
- import { StorageConflictError } from "../storage/taskStore.js";
47
+ import { failureCapabilitiesCommand } from "../runtime/agentFailureContext.js";
48
+ import { enqueueOperatorEvent } from "../scheduler/operatorEvent.js";
49
+ import { isRoleRunStalled, RUN_PROGRESS_EVENT, RUN_RECOVERED_EVENT } from "../scheduler/roleRunStall.js";
50
+ import { renderWakeReason, wakeReason } from "../scheduler/wakeReason.js";
51
+ import { queueLeaderWakeup } from "../scheduler/wakeupQueue.js";
53
52
  import { planningRuntimeCwd } from "../storage/homeLayout.js";
54
- import { requireResolvedAgentProfileRuntime } from "../profile/agentProfileRuntime.js";
55
- import { assertProjectActive, resolveProject } from "../repository/project.js";
56
- import { currentWorkItemCandidate, currentWorkItemExecutionGroup, workItemExecutionGroupById, createWorkItem, editWorkItemDefinition, attachWorkItemExecutionGroup, updateWorkItemExecutionGroup, retireWorkItem, prepareWorkItemDispatch, submitWorkItemCandidate, updateWorkItemWriteProjects, updateWorkItemStatus } from "../workItem/workItem.js";
53
+ import { StorageConflictError } from "../storage/taskStore.js";
54
+ import { archiveDeliveryWarnings, archiveRetainedResources, renderArchiveDiagnostics, taskArchiveDiagnostics } from "../task/archiveDiagnostics.js";
55
+ import { archiveSettlementChecks } from "../task/archivePreflight.js";
56
+ import { projectCompletionReadiness } from "../task/completionReadiness.js";
57
+ import { assertDraftTaskExecutionFree, validateDraftWorkItemEdit } from "../task/draftPlan.js";
58
+ import { assertTaskRemoteDeliveryProof, projectTaskRemoteDeliveryFromStore } from "../task/remoteDeliveryService.js";
59
+ import { addTaskProjectBinding, archiveTask, completeTask, createTask, reopenTask, retireTask, taskOwnsManagedWorkspace, updateTaskMetadata } from "../task/task.js";
60
+ import { recordTaskActivationRequestInTransaction, taskActivationOperationRef } from "../task/taskActivationService.js";
61
+ import { assertTaskDeliveryAuthority, assertTaskInputControlAuthority } from "../task/taskAuthority.js";
62
+ import { resolveTaskRecordReference } from "../task/taskRecordReference.js";
63
+ import { createTaskRecordRetirement, isTaskRecordRetired, operationalTaskRecords, taskRecordRetirement } from "../task/taskRecordRetirement.js";
64
+ import { decideSubmissionRouting, describeSubmissionFeedback, draftActivationState, draftHasEnteredPlanning, normalizeSubmissionIntent, sameSubmissionTarget, TASK_PLANNING_ENTERED_EVENT } from "../task/taskSubmission.js";
57
65
  import { assertWorkItemDependenciesCompleted as assertWorkItemDependencyGate, WorkItemDependencyGateError } from "../workItem/dependencyGate.js";
58
- import { createExecutionGroup, createReviewExecutionAssignment, createWorkItemExecutionAssignment, createWorkItemExecutionGroup, updateExecutionLane as updateUnifiedExecutionLane, updateWorkItemExecutionLane, workItemExecutionGroupSettled } from "../execution/workItemExecution.js";
59
- import { dispatchWorkItemSynthesis, selectedWorkItemSynthesisProducers } from "../execution/workItemMainRun.js";
60
- import { dispatchReviewSynthesis, selectedReviewSynthesisProducers } from "../execution/reviewMainRun.js";
61
- import { synthesisSourceRunIds } from "../context/runContextPack.js";
62
- import { projectWorkItemExecution } from "../execution/workItemExecutionProjection.js";
63
- import { sameTaskFinalReviewContract, taskFinalReviewConfig, validateTaskFinalReviewContract } from "../review/taskFinalReviewContract.js";
64
- import { resolveRecordedTaskFinalReviewContract } from "../review/taskFinalReviewContractResolution.js";
66
+ import { attachWorkItemExecutionGroup, createWorkItem, currentWorkItemCandidate, currentWorkItemExecutionGroup, editWorkItemDefinition, prepareWorkItemDispatch, retireWorkItem, submitWorkItemCandidate, updateWorkItemExecutionGroup, updateWorkItemStatus, updateWorkItemWriteProjects, workItemExecutionGroupById } from "../workItem/workItem.js";
67
+ import { CleanupInspectionError } from "../workspace/cleanupInspection.js";
65
68
  import { managedWorkspaceKey } from "../worktree/managedWorkspace.js";
69
+ import { runGrantCommand } from "./grantCommands.js";
66
70
  import { hasAgentConfigOptions, hasNoRoleMutation, parseRoleOptions, patchRoleAgentBinding, roleOptionSpecs, roleProfilePatch } from "./roleConfiguration.js";
67
- import { hasRoleLaunchContextOptions, validateConfiguredRoleSkills } from "./roleSkillValidation.js";
68
71
  import { assertRoleRuntimeMutationAllowed } from "./roleRuntimeGuard.js";
72
+ import { hasRoleLaunchContextOptions, validateConfiguredRoleSkills } from "./roleSkillValidation.js";
73
+ import { nonLeaderActivationIdentity, runTaskActivationCommand } from "./taskActivationCommands.js";
74
+ import { assertTaskOpen, clock, exactPositionals, leaderActionEventPayload, leaderMailbox, notifyMailbox, optionalNonEmptyOption, output, parseMultiValueTail, parseTail, presentTime, recordTaskEvent, recordTaskEventRecord, requiredOption, requiredText, requireTask, roleMailbox, taskActor, taskMailbox, taskRef, trimmed } from "./taskCommandSupport.js";
75
+ import { assertTaskCompletionPublishedTreeProof } from "./taskCompletionGate.js";
69
76
  import { runTaskContextCommand } from "./taskContextCommand.js";
70
- import { listContextMessages } from "../context/taskContext.js";
71
- import { createProjectResources } from "../resources/projectResourceService.js";
72
- import { isGitArtifactRefString, parseGitArtifactRef } from "../artifacts/gitArtifactRef.js";
73
- import { runTaskNextActionCommand } from "./taskNextActionCommand.js";
74
- import { runDeliveryGuardPreflight, withGuardWarnings } from "./deliveryGuardPreflight.js";
75
- import { inspectTaskRoleRuntimeStatuses, renderTaskRoleRuntimeStatus, taskRoleActiveWorkLabel, taskRoleLastRunLabel, taskRoleNativeSessionLabel, taskRoleOpenInputLabel, taskRoleTmuxLabel, withTaskRoleHostObservation, taskRoleHostDiagnostic } from "./taskRoleRuntimeStatus.js";
77
+ import { taskBriefCommand, taskDecisionCommand, taskEventCommand, taskMilestoneCommand } from "./taskFactCommands.js";
76
78
  import { openInputRequestCount, runTaskInputCommand } from "./taskInputCommands.js";
77
- import { runGrantCommand } from "./grantCommands.js";
79
+ import { runTaskNextActionCommand } from "./taskNextActionCommand.js";
80
+ import { runPublicationCommand } from "./taskPublicationCommands.js";
81
+ import { renderTaskRemoteDelivery, runTaskRemoteDeliveryCommand } from "./taskRemoteDeliveryCommand.js";
82
+ import { inspectTaskRoleRuntimeStatuses, renderTaskRoleRuntimeStatus, taskRoleActiveWorkLabel, taskRoleHostDiagnostic, taskRoleLastRunLabel, taskRoleNativeSessionLabel, taskRoleOpenInputLabel, taskRoleTmuxLabel, withTaskRoleHostObservation } from "./taskRoleRuntimeStatus.js";
83
+ import { readCommandText } from "./textInput.js";
78
84
  import { runWorkflowCommand } from "./workflowCommands.js";
79
- import { taskLocalActor as resolveTaskLocalActor, assertTaskDeliveryAuthority, assertTaskInputControlAuthority } from "./taskActor.js";
80
- import { currentManagedRuntime, resolveManagedTaskReader } from "../runtime/managedCaller.js";
81
- import { parseTaskCatalogOptions, readTaskCatalog, renderTaskCatalog, taskCatalogScope } from "../context/taskCatalog.js";
82
- import { resolveMessageRecipient, messageContinuationBlocker } from "../message/messageContinuation.js";
83
- import { findTaskInterrupt, reserveTaskInterrupt, taskInterruptReceipt, taskInterruptWasRejected } from "../message/taskInterrupt.js";
84
- import { resolveTaskInputControl } from "../message/inputControlResolution.js";
85
- import { enqueueOperatorEvent } from "../scheduler/operatorEvent.js";
86
- import { queueLeaderWakeup } from "../scheduler/wakeupQueue.js";
87
- import { renderWakeReason, wakeReason } from "../scheduler/wakeReason.js";
88
- import { buildTaskOverview, parseTaskListOptions, renderTaskOverview } from "./taskOverviewCommand.js";
89
85
  const LEADER_ROLE = "leader";
90
86
  /** Exact Task-final identity or evidence changed between queueing and dispatch. */
91
87
  export class TaskFinalReviewDispatchDriftError extends CliError {
@@ -254,7 +250,7 @@ export function parseTaskCompletionRequest(args, summaryOverride) {
254
250
  * terminalization precondition before attempting completion. All blockers
255
251
  * are reported in one error instead of one per attempt.
256
252
  */
257
- export function preflightTaskCompletion(taskId, store, options = {}, request = {}) {
253
+ export function preflightTaskCompletion(taskId, store, options = {}, _request = {}) {
258
254
  const task = requireTask(store, taskId);
259
255
  const actor = taskActor(store, options, task.id);
260
256
  assertTaskDeliveryAuthority(store, options.environment, task.id);
@@ -269,7 +265,7 @@ export function preflightTaskCompletion(taskId, store, options = {}, request = {
269
265
  // Integration write. Historical control-plane identity is audit evidence,
270
266
  // not a capability that every compatible CLI must reproduce.
271
267
  const taskFinalReviewContract = taskFinalReviewContractForMutation(store, task.id, options);
272
- const activeTaskReview = store.listReviewRounds(task.id).some((round) => ((round.scope ?? "work-item") === "task"
268
+ const activeTaskReview = store.listReviewRounds(task.id).some((round) => (round.scope === "task"
273
269
  && (round.status === "pending" || round.status === "running")));
274
270
  // Issue 06: one shared readiness projection enumerates every blocker.
275
271
  const readinessFacts = store.readCompletionReadinessFacts(task.id);
@@ -307,7 +303,7 @@ export function runTaskCommand(args, store, options = {}) {
307
303
  const delivery = command === "complete"
308
304
  || (command === "work" && ["dispatch", "synthesize", "review", "accept"].includes(rest[0] ?? ""))
309
305
  || (command === "review" && !["list", "show"].includes(rest[0] ?? ""))
310
- || ((command === "run" || command === "run") && rest[0] === "retry");
306
+ || (command === "run" && rest[0] === "retry");
311
307
  if (delivery && options.environment?.YUI_SESSION_SCOPE === "task"
312
308
  && options.environment.YUI_TASK_ID !== undefined) {
313
309
  assertTaskDeliveryAuthority(store, options.environment, options.environment.YUI_TASK_ID);
@@ -341,12 +337,11 @@ export function runTaskCommand(args, store, options = {}) {
341
337
  case "role": return taskRoleCommand(rest, store, options);
342
338
  case "work": return taskWorkCommand(rest, store, options);
343
339
  case "review": return taskReviewCommand(rest, store, options);
344
- case "run":
345
340
  case "run": return taskRunCommand(rest, store, options);
346
341
  case "brief": return taskBriefCommand(rest, store, options);
347
342
  case "decision": return taskDecisionCommand(rest, store, options);
348
343
  case "milestone": return taskMilestoneCommand(rest, store, options);
349
- case "event": return taskEventCommand(rest, store);
344
+ case "event": return taskEventCommand(rest, store, options);
350
345
  case "continuation": return taskContinuationCommand(rest, store);
351
346
  default:
352
347
  throw usageError(command === undefined
@@ -470,9 +465,9 @@ function taskProjectCommand(args, store, options) {
470
465
  }
471
466
  return next;
472
467
  });
473
- notifyMailbox(options.runtime, taskMailbox(updated.id), updated.id);
468
+ notifyMailbox(options.runtime, taskMailbox(updated.id));
474
469
  if (updated.status === "active") {
475
- notifyMailbox(options.runtime, leaderMailbox(updated.id), updated.id);
470
+ notifyMailbox(options.runtime, leaderMailbox(updated.id));
476
471
  }
477
472
  return output(`Added Project to ${updated.id}\n`, { task: updated });
478
473
  }
@@ -527,7 +522,7 @@ function updateTaskCommand(args, store, options) {
527
522
  }, options);
528
523
  return `Updated task ${result.id}\n`;
529
524
  }
530
- /** Shared domain transaction for structured capabilities and the legacy CLI.
525
+ /** Shared domain transaction for structured capabilities and the CLI.
531
526
  * Parsing text flags must not become an alternate business write path. */
532
527
  export function updateTaskMetadataCommand(store, taskId, patch, options = {}) {
533
528
  if (Object.keys(patch).length === 0)
@@ -549,7 +544,7 @@ export function updateTaskMetadataCommand(store, taskId, patch, options = {}) {
549
544
  enqueueWork(tx, taskMailbox(updated.id), "task-updated", now, [taskRef(updated.id)]);
550
545
  return updated;
551
546
  });
552
- notifyMailbox(options.runtime, taskMailbox(result.id), result.id);
547
+ notifyMailbox(options.runtime, taskMailbox(result.id));
553
548
  return result;
554
549
  }
555
550
  function routeUserSubmission(tx, task, actor, body, intent, now, submissionKey, target, inputControl) {
@@ -632,8 +627,7 @@ function routeUserSubmission(tx, task, actor, body, intent, now, submissionKey,
632
627
  requestId: `submit-${message.id}`,
633
628
  actorId: identity.actorId,
634
629
  authorityRef: identity.authorityRef,
635
- environmentPlan: routing.environmentPlan,
636
- origin: "submit-develop"
630
+ environmentPlan: routing.environmentPlan
637
631
  }, now);
638
632
  activationRef = taskActivationOperationRef(task.id, `submit-${message.id}`);
639
633
  enqueueWork(tx, taskMailbox(task.id), "activation-requested", now, [taskRef(task.id)]);
@@ -685,7 +679,7 @@ function replayKeyedSubmission(task, prior, kind, body, intent, target) {
685
679
  const receipt = prior.submissionReceipt;
686
680
  if (prior.kind !== kind
687
681
  || prior.body !== body
688
- || normalizeSubmissionIntent(prior.intent) !== intent
682
+ || prior.intent !== intent
689
683
  || receipt === undefined
690
684
  || (target !== undefined && !sameSubmissionTarget(receipt.target, target))) {
691
685
  throw new StorageConflictError(`Submission key ${prior.submissionKey} was already used for a different submission on ${task.id}/${prior.id}.`);
@@ -747,7 +741,7 @@ const SUBMISSION_ACTIVATION_LABEL = {
747
741
  function renderSubmissionNextStep(step) {
748
742
  switch (step.kind) {
749
743
  case "activate-manually":
750
- return `activate it explicitly with "yui task activate ${step.taskId}".`;
744
+ return `request activation with "yui task activation request ${step.taskId} --request-id <id> --environment <plan>".`;
751
745
  case "start-execution":
752
746
  return `start execution with "yui task execution start ${step.taskId}", then submit develop again.`;
753
747
  case "await-pending-activation":
@@ -801,7 +795,7 @@ export function submitOperatorMessage(body, taskId, store, options = {}, intent,
801
795
  const routed = routeUserSubmission(tx, createdAgg.task, "operator", body, effectiveIntent, now, submissionKey, { kind: "create" });
802
796
  return { ...routed, task: createdAgg.task, created: true };
803
797
  });
804
- notifyMailbox(options.runtime, result.queuedForLeader ? leaderMailbox(result.task.id) : taskMailbox(result.task.id), result.task.id);
798
+ notifyMailbox(options.runtime, result.queuedForLeader ? leaderMailbox(result.task.id) : taskMailbox(result.task.id));
805
799
  const header = result.created
806
800
  ? `Created Draft task ${result.task.id}: ${result.task.title}\n`
807
801
  : "";
@@ -828,7 +822,7 @@ function createTaskCommand(args, store, options) {
828
822
  projectBindings: parsed.projectBindings,
829
823
  ...(parsed.type === undefined ? {} : { type: parsed.type })
830
824
  }, now, parsed.defaultProjectIds));
831
- notifyMailbox(options.runtime, taskMailbox(created.task.id), created.task.id);
825
+ notifyMailbox(options.runtime, taskMailbox(created.task.id));
832
826
  return output(`Created Draft task ${created.task.id}: ${created.task.title}\n`
833
827
  + `Assigned role: ${created.leader.name}\n`
834
828
  + `Type: ${created.task.type ?? "unspecified"}\n`
@@ -909,18 +903,8 @@ function createTaskAggregate(store, title, metadata, now, defaultProjectIds = []
909
903
  return { task, leader };
910
904
  }
911
905
  function listTaskCommand(args, store, environment = {}) {
912
- if (args.includes("--view")) {
913
- const result = readTaskCatalog(store, parseTaskCatalogOptions(args), environment);
914
- return output(renderTaskCatalog(result), result);
915
- }
916
- const taskId = taskCatalogScope(store, environment);
917
- const options = parseTaskListOptions(args);
918
- const snapshot = store.transaction((reader) => ({
919
- result: buildTaskOverview(reader, options, new Date(), taskId),
920
- timeZone: reader.getConfig().timeZone
921
- }));
922
- const rendered = renderTaskOverview(snapshot.result, options, snapshot.timeZone, defaultTableWidth());
923
- return output(rendered, snapshot.result);
906
+ const result = readTaskCatalog(store, parseTaskCatalogOptions(args), environment);
907
+ return output(renderTaskCatalog(result), result);
924
908
  }
925
909
  function showTaskCommand(args, store, currentTaskCandidate) {
926
910
  const [taskId] = args;
@@ -1053,8 +1037,8 @@ function activateTaskCommand(args, store, options) {
1053
1037
  throw usageError(`Task ${task.id} activation requires atomic workspace adoption through the CLI preflight.`);
1054
1038
  });
1055
1039
  if (result.changed) {
1056
- notifyMailbox(options.runtime, taskMailbox(result.task.id), result.task.id);
1057
- notifyMailbox(options.runtime, leaderMailbox(result.task.id), result.task.id);
1040
+ notifyMailbox(options.runtime, taskMailbox(result.task.id));
1041
+ notifyMailbox(options.runtime, leaderMailbox(result.task.id));
1058
1042
  }
1059
1043
  return result.changed
1060
1044
  ? `Activated task ${result.task.id}\n`
@@ -1188,7 +1172,7 @@ function completeTaskCommand(args, store, options) {
1188
1172
  };
1189
1173
  });
1190
1174
  if (result.changed) {
1191
- notifyMailbox(options.runtime, { kind: "operator" }, result.task.id);
1175
+ notifyMailbox(options.runtime, { kind: "operator" });
1192
1176
  }
1193
1177
  if (result.finalReview !== undefined) {
1194
1178
  const status = result.finalReview.status === "pending"
@@ -1249,9 +1233,9 @@ function reopenTaskCommand(args, store, options) {
1249
1233
  return { task: active, changed: true, wakeLeader: actor !== "leader" };
1250
1234
  });
1251
1235
  if (result.changed) {
1252
- notifyMailbox(options.runtime, taskMailbox(result.task.id), result.task.id);
1236
+ notifyMailbox(options.runtime, taskMailbox(result.task.id));
1253
1237
  if (result.wakeLeader) {
1254
- notifyMailbox(options.runtime, leaderMailbox(result.task.id), result.task.id);
1238
+ notifyMailbox(options.runtime, leaderMailbox(result.task.id));
1255
1239
  }
1256
1240
  }
1257
1241
  return result.changed
@@ -1342,7 +1326,7 @@ function archiveTaskCommand(args, store, options) {
1342
1326
  return { task: archived, changed: true };
1343
1327
  });
1344
1328
  if (result.changed && !request.force)
1345
- options.runtime?.notifyStateChanged(result.task.id);
1329
+ options.runtime?.notifyMailboxChanged({ kind: "task", taskId: result.task.id });
1346
1330
  const diagnostics = taskArchiveDiagnostics(store, result.task);
1347
1331
  return output((result.changed
1348
1332
  ? `Archived task ${result.task.id}\n`
@@ -1375,8 +1359,8 @@ function cancelTaskCommand(args, store, options) {
1375
1359
  // AgentRuns, inputs, WorkItems and their results remain independently readable.
1376
1360
  return cancelled;
1377
1361
  });
1378
- options.runtime?.notifyStateChanged(result.id);
1379
- notifyMailbox(options.runtime, { kind: "operator" }, result.id);
1362
+ options.runtime?.notifyMailboxChanged({ kind: "task", taskId: result.id });
1363
+ notifyMailbox(options.runtime, { kind: "operator" });
1380
1364
  return output(`Cancelled task ${result.id}\n`, { task: result });
1381
1365
  }
1382
1366
  /** Historical evidence only; these snapshots are never dispatch input. */
@@ -1477,8 +1461,8 @@ function retireTaskCommand(args, store, options) {
1477
1461
  return { task: retired, changed: true };
1478
1462
  });
1479
1463
  if (result.changed) {
1480
- options.runtime?.notifyStateChanged(result.task.id);
1481
- notifyMailbox(options.runtime, { kind: "operator" }, result.task.id);
1464
+ options.runtime?.notifyMailboxChanged({ kind: "task", taskId: result.task.id });
1465
+ notifyMailbox(options.runtime, { kind: "operator" });
1482
1466
  }
1483
1467
  return output(result.changed
1484
1468
  ? `Retired task ${result.task.id}\n`
@@ -1590,7 +1574,7 @@ function taskMessageCommand(args, store, options) {
1590
1574
  enqueueWork(tx, taskMailbox(ref.taskId), "message-continuation", now, [messageRef(ref.taskId, current.id)]);
1591
1575
  return updated;
1592
1576
  });
1593
- notifyMailbox(options.runtime, taskMailbox(ref.taskId), ref.taskId);
1577
+ notifyMailbox(options.runtime, taskMailbox(ref.taskId));
1594
1578
  return output(`Handed off Message ${ref.localId} to ${message.recipient.roleName}.\n`, message);
1595
1579
  }
1596
1580
  if (command === "show") {
@@ -1608,22 +1592,11 @@ function taskMessageCommand(args, store, options) {
1608
1592
  return { kind: "output", output: `${JSON.stringify(expanded, null, 2)}\n`, data: expanded };
1609
1593
  }
1610
1594
  if (command === "send") {
1611
- const usage = "Task message send usage: yui task message send <id> (<body>|--body-file <path|->) [--intent record|discuss|develop] [--request-id <key>] [--wake-policy leader|none] [--to <role> --work-item <id>|--review-round <id>].";
1612
- const parsed = parseTail(rest, new Set(["--body-file", "--intent", "--request-id", "--wake-policy", "--to", "--work-item", "--review-round"]), usage);
1595
+ const usage = "Task message send usage: yui task message send <id> (<body>|--body-file <path|->) [--intent record|discuss|develop] [--request-id <key>] [--to <role> --work-item <id>|--review-round <id>].";
1596
+ const parsed = parseTail(rest, new Set(["--body-file", "--intent", "--request-id", "--to", "--work-item", "--review-round"]), usage);
1613
1597
  if (parsed.positionals.length < 1 || parsed.positionals.length > 2)
1614
1598
  throw usageError(usage);
1615
1599
  const body = readCommandText(parsed.positionals[1], parsed.options.get("--body-file"), "--body", usage);
1616
- const wakePolicyRaw = parsed.options.get("--wake-policy");
1617
- let wakePolicy;
1618
- if (wakePolicyRaw === undefined) {
1619
- wakePolicy = undefined;
1620
- }
1621
- else if (wakePolicyRaw === "leader" || wakePolicyRaw === "none") {
1622
- wakePolicy = wakePolicyRaw;
1623
- }
1624
- else {
1625
- throw usageError(`--wake-policy must be 'leader' or 'none': ${wakePolicyRaw}.`);
1626
- }
1627
1600
  const intent = parseSubmissionIntentOption(parsed.options.get("--intent"), usage);
1628
1601
  const submissionKey = parsed.options.get("--request-id");
1629
1602
  if (submissionKey !== undefined && submissionKey.trim().length === 0) {
@@ -1634,7 +1607,7 @@ function taskMessageCommand(args, store, options) {
1634
1607
  const reviewRoundId = parsed.options.get("--review-round");
1635
1608
  if (recipientRole === undefined && (workItemId !== undefined || reviewRoundId !== undefined))
1636
1609
  throw usageError("--to is required for scoped Message delivery.");
1637
- const result = sendTaskMessageCommand(store, parsed.positionals[0], body, wakePolicy, options, recipientRole === undefined ? undefined : { roleName: recipientRole, workItemId, reviewRoundId }, intent, submissionKey);
1610
+ const result = sendTaskMessageCommand(store, parsed.positionals[0], body, options, recipientRole === undefined ? undefined : { roleName: recipientRole, workItemId, reviewRoundId }, intent, submissionKey);
1638
1611
  // A user/operator submission returns the unified §2.5 feedback; render each
1639
1612
  // facet on its own line and expose the structure to non-text callers.
1640
1613
  if (result.feedback !== undefined) {
@@ -1713,6 +1686,13 @@ function taskMessageCommand(args, store, options) {
1713
1686
  * reusing the requestId with different content is a conflict, never a second
1714
1687
  * input (decision-3 §5/§6).
1715
1688
  */
1689
+ export function applyTaskInputControl(taskId, input, store, options) {
1690
+ if (input.action === "queue")
1691
+ return queueTaskInput(taskId, input, store, options);
1692
+ if (input.action === "steer")
1693
+ return steerTaskInput(taskId, input, store, options);
1694
+ return interruptTaskInput(taskId, input, store, options);
1695
+ }
1716
1696
  function queueTaskMessage(args, store, options) {
1717
1697
  const usage = "Task message queue usage: yui task message queue <id> (<body>|--body-file <path|->) --request-id <id> [--to <role> --work-item <id>|--review-round <id>].";
1718
1698
  const parsed = parseTail(args, new Set(["--body-file", "--request-id", "--to", "--work-item", "--review-round"]), usage);
@@ -1723,10 +1703,16 @@ function queueTaskMessage(args, store, options) {
1723
1703
  const recipientRole = parsed.options.get("--to");
1724
1704
  const workItemId = parsed.options.get("--work-item");
1725
1705
  const reviewRoundId = parsed.options.get("--review-round");
1706
+ return applyTaskInputControl(parsed.positionals[0], {
1707
+ action: "queue", body, requestId, to: recipientRole, workItem: workItemId, reviewRound: reviewRoundId
1708
+ }, store, options);
1709
+ }
1710
+ function queueTaskInput(taskId, input, store, options) {
1711
+ const { body, requestId, to: recipientRole, workItem: workItemId, reviewRound: reviewRoundId } = input;
1726
1712
  if (recipientRole === undefined && (workItemId !== undefined || reviewRoundId !== undefined)) {
1727
1713
  throw usageError("--to is required for scoped Message delivery.");
1728
1714
  }
1729
- const result = sendTaskMessageCommand(store, parsed.positionals[0], body, undefined, options, recipientRole === undefined ? undefined : { roleName: recipientRole, workItemId, reviewRoundId }, undefined, undefined, { action: "queue", requestId });
1715
+ const result = sendTaskMessageCommand(store, taskId, body, options, recipientRole === undefined ? undefined : { roleName: recipientRole, workItemId, reviewRoundId }, undefined, undefined, { action: "queue", requestId });
1730
1716
  const reason = result.message.continuation?.notDeliveredReason;
1731
1717
  const delivery = result.idempotentReplay ? { state: "idempotent-replay" }
1732
1718
  : reason !== undefined ? { state: "not-delivered", reason }
@@ -1757,6 +1743,13 @@ function steerTaskMessage(args, store, options) {
1757
1743
  if (recipientRole === undefined) {
1758
1744
  throw usageError("steer requires --to <role>; it targets that Role's exact current Turn.");
1759
1745
  }
1746
+ return applyTaskInputControl(parsed.positionals[0], {
1747
+ action: "steer", body, requestId, expectedTarget, to: recipientRole,
1748
+ workItem: workItemId, reviewRound: reviewRoundId
1749
+ }, store, options);
1750
+ }
1751
+ function steerTaskInput(taskId, input, store, options) {
1752
+ const { body, requestId, expectedTarget, to: recipientRole, workItem: workItemId, reviewRound: reviewRoundId } = input;
1760
1753
  // decision-3 §9: a Task Leader's current native turn (including a Draft's
1761
1754
  // planning turn) is a real turn but NOT an implicit AgentRun, so steering it
1762
1755
  // never establishes a Worker-style Assignment. It is persisted as an ordinary
@@ -1768,8 +1761,8 @@ function steerTaskMessage(args, store, options) {
1768
1761
  throw usageError("Steering the Leader targets its current turn directly; it takes no --work-item/--review-round Assignment.");
1769
1762
  }
1770
1763
  const result = leaderTarget
1771
- ? sendTaskMessageCommand(store, parsed.positionals[0], body, "none", options, undefined, undefined, undefined, { action: "steer", requestId, expectedTarget })
1772
- : sendTaskMessageCommand(store, parsed.positionals[0], body, undefined, options, { roleName: recipientRole, workItemId, reviewRoundId }, undefined, undefined, { action: "steer", requestId, expectedTarget });
1764
+ ? sendTaskMessageCommand(store, taskId, body, options, undefined, undefined, undefined, { action: "steer", requestId, expectedTarget })
1765
+ : sendTaskMessageCommand(store, taskId, body, options, { roleName: recipientRole, workItemId, reviewRoundId }, undefined, undefined, { action: "steer", requestId, expectedTarget });
1773
1766
  const roleName = result.message.recipient?.roleName ?? recipientRole;
1774
1767
  if (result.idempotentReplay) {
1775
1768
  // A replay is a later reader (another CLI invocation): surface the durable
@@ -1864,12 +1857,9 @@ function steerInputDelivery(taskId, messageId, roleName, body) {
1864
1857
  * execution is decided by the Controller from the Task's own status, so this
1865
1858
  * function never names a purpose and no second planning path exists.
1866
1859
  */
1867
- export function sendTaskMessageCommand(store, taskId, body, wakePolicy, options = {}, recipient, intent, submissionKey, inputControl) {
1860
+ export function sendTaskMessageCommand(store, taskId, body, options = {}, recipient, intent, submissionKey, inputControl) {
1868
1861
  if (!body.trim())
1869
1862
  throw usageError("Message body is required.");
1870
- if (recipient !== undefined && wakePolicy !== undefined) {
1871
- throw usageError("--wake-policy applies only to unaddressed Leader Messages; an owner-directed Message uses its exact continuation boundary.");
1872
- }
1873
1863
  if (recipient !== undefined && intent !== undefined) {
1874
1864
  throw usageError("A submission intent applies only to unaddressed Leader Messages; an owner-directed Message uses its exact continuation boundary.");
1875
1865
  }
@@ -1924,7 +1914,7 @@ export function sendTaskMessageCommand(store, taskId, body, wakePolicy, options
1924
1914
  // owner-directed continuations keep their exact existing boundary and never
1925
1915
  // gain develop authority (task-32 §2.5).
1926
1916
  if (recipient === undefined && (actor === "user" || actor === "operator")) {
1927
- const effectiveIntent = normalizeSubmissionIntent(intent, wakePolicy);
1917
+ const effectiveIntent = inputControl?.action === "steer" ? "record" : normalizeSubmissionIntent(intent);
1928
1918
  const routed = routeUserSubmission(tx, task, actor, body, effectiveIntent, now, submissionKey, { kind: "task", taskId: task.id }, inputControl);
1929
1919
  return {
1930
1920
  task: routed.task, message: routed.message, actor,
@@ -1979,11 +1969,11 @@ export function sendTaskMessageCommand(store, taskId, body, wakePolicy, options
1979
1969
  if (result.idempotentReplay)
1980
1970
  return result;
1981
1971
  if (recipient !== undefined) {
1982
- notifyMailbox(options.runtime, taskMailbox(result.task.id), result.task.id);
1972
+ notifyMailbox(options.runtime, taskMailbox(result.task.id));
1983
1973
  }
1984
1974
  else if (result.actor !== "leader") {
1985
1975
  notifyMailbox(options.runtime, result.queuedForLeader
1986
- ? leaderMailbox(result.task.id) : taskMailbox(result.task.id), result.task.id);
1976
+ ? leaderMailbox(result.task.id) : taskMailbox(result.task.id));
1987
1977
  }
1988
1978
  return result;
1989
1979
  }
@@ -2004,19 +1994,11 @@ export function leaderWakingTaskStatus(status) {
2004
1994
  return status === "active" || status === "draft";
2005
1995
  }
2006
1996
  function updateMessage(args, store, options) {
2007
- const usage = "Task message update usage: yui task message update <task>/<message> (<body>|--body-file <path|->) [--wake-policy leader|none].";
2008
- const parsed = parseTail(args, new Set(["--body-file", "--wake-policy"]), usage);
1997
+ const usage = "Task message update usage: yui task message update <task>/<message> (<body>|--body-file <path|->).";
1998
+ const parsed = parseTail(args, new Set(["--body-file"]), usage);
2009
1999
  if (parsed.positionals.length < 1 || parsed.positionals.length > 2)
2010
2000
  throw usageError(usage);
2011
2001
  const body = readCommandText(parsed.positionals[1], parsed.options.get("--body-file"), "--body", usage);
2012
- const wakePolicyRaw = parsed.options.get("--wake-policy");
2013
- const wakePolicy = wakePolicyRaw === undefined
2014
- ? undefined
2015
- : wakePolicyRaw === "leader" || wakePolicyRaw === "none"
2016
- ? wakePolicyRaw
2017
- : (() => {
2018
- throw usageError(`--wake-policy must be 'leader' or 'none': ${wakePolicyRaw}.`);
2019
- })();
2020
2002
  const reference = taskRecordReference(parsed.positionals[0], "message", "Message reference", options);
2021
2003
  const now = clock(options);
2022
2004
  const result = store.transaction((tx) => {
@@ -2037,24 +2019,42 @@ function updateMessage(args, store, options) {
2037
2019
  throw usageError(`Task Message is retired: ${task.id}/${message.id}.`);
2038
2020
  }
2039
2021
  const updated = updateDraftTaskMessage(message, {
2040
- body,
2041
- ...(wakePolicy === undefined ? {} : { wakePolicy })
2022
+ body
2042
2023
  });
2024
+ if (updated === message)
2025
+ return { task, message, queuedForLeader: false, changed: false };
2043
2026
  tx.updateMessage(task.id, updated);
2044
2027
  recordTaskEvent(tx, task.id, "message.updated", {
2045
2028
  messageId: updated.id,
2046
- updatedBy: actor,
2047
- ...(wakePolicy === undefined ? {} : { wakePolicy })
2029
+ updatedBy: actor
2048
2030
  }, now);
2049
- const queuedForLeader = updated.wakePolicy !== "none";
2031
+ // An edit can continue a discussion, but it is not a new develop request.
2032
+ // Use the submission router's current activation/planning facts so pending
2033
+ // or failed activation cannot be turned into a planning wake by an edit.
2034
+ const routing = decideSubmissionRouting({
2035
+ intent: updated.intent,
2036
+ status: task.status,
2037
+ enteredPlanning: draftHasEnteredPlanning(tx, task),
2038
+ activation: draftActivationState(task.activationRequest),
2039
+ executionEnabled: task.executionGate.state === "enabled",
2040
+ developEnvironmentPlan: { kind: "empty" }
2041
+ });
2042
+ const queuedForLeader = routing.kind === "enter-planning" || routing.kind === "continue-planning";
2043
+ if (routing.kind === "enter-planning") {
2044
+ recordTaskEvent(tx, task.id, TASK_PLANNING_ENTERED_EVENT, {
2045
+ messageId: updated.id, intent: updated.intent
2046
+ }, now);
2047
+ }
2050
2048
  if (queuedForLeader) {
2051
2049
  enqueueWork(tx, leaderMailbox(task.id), actor === "operator" ? "operator-input" : "user-message", now, [messageRef(task.id, updated.id)], { source: actor });
2052
2050
  }
2053
- return { task, message: updated, queuedForLeader };
2051
+ return { task, message: updated, queuedForLeader, changed: true };
2054
2052
  });
2055
- notifyMailbox(options.runtime, result.queuedForLeader
2056
- ? leaderMailbox(result.task.id) : taskMailbox(result.task.id), result.task.id);
2057
- return output(`Updated Task Message ${result.task.id}/${result.message.id}\n`, {
2053
+ if (result.changed) {
2054
+ notifyMailbox(options.runtime, result.queuedForLeader
2055
+ ? leaderMailbox(result.task.id) : taskMailbox(result.task.id));
2056
+ }
2057
+ return output(`${result.changed ? "Updated" : "Unchanged"} Task Message ${result.task.id}/${result.message.id}\n`, {
2058
2058
  message: result.message
2059
2059
  });
2060
2060
  }
@@ -2101,32 +2101,58 @@ function retireMessage(args, store, options) {
2101
2101
  return { task, message, changed: true };
2102
2102
  });
2103
2103
  if (result.changed)
2104
- options.runtime?.notifyStateChanged(result.task.id);
2104
+ options.runtime?.notifyMailboxChanged({ kind: "task", taskId: result.task.id });
2105
2105
  return `Retired Task Message ${result.task.id}/${result.message.id}\n`;
2106
2106
  }
2107
- /**
2108
- * Issue 05: force-wake escape hatch. Bypasses the actionability digest and
2109
- * enqueues exactly one Leader wakeup with an auditable reason. The reason is
2110
- * truncated to keep the event payload compact.
2111
- */
2112
- function taskWakeForceCommand(args, store, options) {
2113
- const usage = "Task wake usage: yui task wake <id> --force --reason <text>.";
2114
- const parsed = parseTail(args, new Set(["--reason"]), usage, new Set(["--force"]));
2115
- exactPositionals(parsed.positionals, 1, usage);
2116
- if (!parsed.options.has("--force")) {
2117
- throw usageError("--force is required to wake a Task.", usage);
2118
- }
2107
+ /** Explicitly retry one proven-rejected notification, preserving its inputs. */
2108
+ function taskWakeRetryCommand(args, store, options) {
2109
+ const usage = "Task wake retry usage: yui task wake retry <task> <wake> --reason <correction>.";
2110
+ const parsed = parseTail(args, new Set(["--reason"]), usage);
2111
+ exactPositionals(parsed.positionals, 2, usage);
2119
2112
  const reason = requiredOption(parsed.options, "--reason");
2120
2113
  const now = clock(options);
2121
- const task = requireTask(store, parsed.positionals[0]);
2122
- assertTaskOpen(task);
2123
- const wakeReasonTag = wakeReason("force-wake", truncateEventNote(reason));
2124
- store.transaction((tx) => {
2125
- queueLeaderWakeup(tx, task.id, wakeReasonTag, now);
2126
- recordTaskEvent(tx, task.id, "task.wake-forced", { reason: wakeReasonTag }, now);
2114
+ const result = store.transaction((tx) => {
2115
+ const task = requireTask(tx, parsed.positionals[0]);
2116
+ assertTaskOpen(task);
2117
+ taskActor(tx, options, task.id);
2118
+ const wakeId = parsed.positionals[1];
2119
+ const wake = tx.getTaskWake(task.id, wakeId);
2120
+ if (wake === null)
2121
+ throw dataError(`Wake not found: ${wakeId}.`);
2122
+ if (wake.status === "consumed")
2123
+ throw usageError("An accepted notification cannot be retried.");
2124
+ const mailbox = tx.getWorkMailbox(leaderMailbox(task.id));
2125
+ const claim = mailbox?.processing;
2126
+ if (claim == null || claim.owner !== `leader-notification:${wakeId}`) {
2127
+ throw usageError("This wake has no rejected notification claim.");
2128
+ }
2129
+ const events = tx.listEvents(task.id);
2130
+ const previous = events.filter(event => event.type === "notification.delivery" && event.payload.attemptId === claim.batchId).at(-1);
2131
+ if (previous?.payload.outcome !== "rejected") {
2132
+ throw usageError("Only a rejected notification can be retried; unknown acceptance must not be replayed.");
2133
+ }
2134
+ const provider = tx.getTaskRoleSessionSet(task.id, "leader")?.providerBinding;
2135
+ const accepted = events.some(event => {
2136
+ const observation = runtimeObservationFromTaskEvent(event);
2137
+ return observation?.fence.roleName === "leader" && observation.fence.receiptId === claim.batchId
2138
+ && ((observation.kind === "turn.accepted" && observation.authority !== "transport")
2139
+ || ["turn.completed", "turn.failed", "turn.cancelled"].includes(observation.kind));
2140
+ });
2141
+ if (accepted || tx.getActiveRun(task.id, "leader") !== null
2142
+ || provider?.authority.owner === "human" || provider?.authority.owner === "unknown"
2143
+ || (provider?.run != null && (["submitting", "accepted", "delivery-unknown"].includes(provider.run.status)
2144
+ || provider.run.attemptId === claim.batchId && provider.run.status !== "rejected"))) {
2145
+ throw usageError("Native execution is not proven unaccepted and quiescent; this notification cannot be replayed.");
2146
+ }
2147
+ tx.saveWorkMailbox(releaseProcessing(mailbox, claim.batchId));
2148
+ queueLeaderWakeup(tx, task.id, wakeReason("notification-retry", wakeId), now);
2149
+ recordTaskEvent(tx, task.id, "notification.retry-requested", {
2150
+ wakeId, attemptId: claim.batchId, reason
2151
+ }, now);
2152
+ return { taskId: task.id, wakeId, outcome: "queued" };
2127
2153
  });
2128
- notifyMailbox(options.runtime, leaderMailbox(task.id), task.id);
2129
- return `Woke ${task.id} (${wakeReasonTag})\n`;
2154
+ notifyMailbox(options.runtime, leaderMailbox(result.taskId));
2155
+ return output(`Queued rejected ${result.wakeId} for retry; original input was preserved.\n`, result);
2130
2156
  }
2131
2157
  function taskRoleCommand(args, store, options) {
2132
2158
  const [command, ...rest] = args;
@@ -2183,9 +2209,15 @@ function interruptTaskRole(args, store, options) {
2183
2209
  const expectedTarget = requiredOption(parsed.options, "--expected-target");
2184
2210
  const thenMessageRef = optionalNonEmptyOption(parsed.options, "--then-message");
2185
2211
  const requestId = optionalNonEmptyOption(parsed.options, "--request-id");
2212
+ return applyTaskInputControl(parsed.positionals[0], {
2213
+ action: "interrupt", expectedTarget, role: parsed.positionals[1], thenMessage: thenMessageRef, requestId
2214
+ }, store, options);
2215
+ }
2216
+ function interruptTaskInput(taskId, input, store, options) {
2217
+ const { expectedTarget, thenMessage: thenMessageRef, requestId } = input;
2186
2218
  const now = clock(options);
2187
- const task = requireTask(store, parsed.positionals[0]);
2188
- const role = requireRole(store, task.id, parsed.positionals[1]);
2219
+ const task = requireTask(store, taskId);
2220
+ const role = requireRole(store, task.id, input.role);
2189
2221
  const fingerprint = createHash("sha256").update(JSON.stringify({
2190
2222
  roleName: role.name, expectedTarget, thenMessageRef: thenMessageRef ?? null
2191
2223
  })).digest("hex");
@@ -2362,7 +2394,7 @@ function registerInterruptThen(store, taskId, roleName, thenMessageRef, target,
2362
2394
  // AgentRun's terminal — no extra wake is needed. A no-Run Leader turn owns no
2363
2395
  // AgentRun and is never surfaced by that push path; it is delivered only by
2364
2396
  // being woken to read its own Context. The interrupt itself (and, when the
2365
- // handoff reuses a Leader self-steer, wakePolicy "none") enqueues no wake, so
2397
+ // handoff reuses a Leader self-steer with record intent) enqueues no wake, so
2366
2398
  // without this the claim would be structurally unreleasable: listPendingWakeups
2367
2399
  // never selects the Task and the busy-gated leader mailbox is never consulted.
2368
2400
  // Enqueue that wake now, keyed to the claimed Message so an idempotent repeat of
@@ -2483,7 +2515,7 @@ function taskRoleSessionCommand(args, store, options) {
2483
2515
  enqueueWork(tx, target, RUNTIME_SESSION_REPLACE_REQUIRED_REASON, now, [{ type: "task", id: task.id }]);
2484
2516
  return { taskId: task.id, roleName: role.name, target, alreadyRequested: false };
2485
2517
  });
2486
- notifyMailbox(options.runtime, result.target, result.taskId);
2518
+ notifyMailbox(options.runtime, result.target);
2487
2519
  return output(`Requested Session replacement for ${result.taskId}/${result.roleName}. `
2488
2520
  + "Yui will stop the old execution, retain its history and workspaces, and select a fresh Session. "
2489
2521
  + "If replacing your own Session, end this turn; the successor reads durable Task context.\n", result);
@@ -2602,7 +2634,7 @@ function addTaskRole(args, store, options) {
2602
2634
  }, now);
2603
2635
  return { role: created, binding };
2604
2636
  });
2605
- notifyMailbox(options.runtime, taskMailbox(result.role.taskId), result.role.taskId);
2637
+ notifyMailbox(options.runtime, taskMailbox(result.role.taskId));
2606
2638
  const profileId = parsed.one("--profile");
2607
2639
  const runtimeSource = profileId !== undefined
2608
2640
  ? `Agent Profile ${profileId}`
@@ -2742,7 +2774,7 @@ function updateTaskRole(args, store, options) {
2742
2774
  });
2743
2775
  return next;
2744
2776
  });
2745
- notifyMailbox(options.runtime, taskMailbox(updated.taskId), updated.taskId);
2777
+ notifyMailbox(options.runtime, taskMailbox(updated.taskId));
2746
2778
  const sessions = store.getTaskRoleSessionSet(updated.taskId, updated.name);
2747
2779
  return output(renderRoleDetails(`Updated Task Role: ${updated.name}`, updated, {
2748
2780
  kind: "task",
@@ -2784,7 +2816,7 @@ function removeTaskRole(args, store, options) {
2784
2816
  enqueueWork(tx, taskMailbox(task.id), "role-removed", now, [taskRef(task.id)]);
2785
2817
  return role;
2786
2818
  });
2787
- notifyMailbox(options.runtime, taskMailbox(removed.taskId), removed.taskId);
2819
+ notifyMailbox(options.runtime, taskMailbox(removed.taskId));
2788
2820
  return `Removed role ${removed.name} from ${removed.taskId}\n`;
2789
2821
  }
2790
2822
  function bindTaskRole(args, store, options) {
@@ -2843,7 +2875,7 @@ function bindTaskRole(args, store, options) {
2843
2875
  }, now);
2844
2876
  return { role: switched.role, mode: switched.mode };
2845
2877
  });
2846
- notifyMailbox(options.runtime, taskMailbox(result.role.taskId), result.role.taskId);
2878
+ notifyMailbox(options.runtime, taskMailbox(result.role.taskId));
2847
2879
  return `Bound ${result.role.taskId}/${result.role.name} to ${result.role.activeAgentId} (${result.mode})\n`;
2848
2880
  }
2849
2881
  function unbindTaskRole(args, store, options) {
@@ -3113,7 +3145,7 @@ function editWork(args, store, options) {
3113
3145
  }
3114
3146
  return { task, item: updated };
3115
3147
  });
3116
- options.runtime?.notifyStateChanged(result.task.id);
3148
+ options.runtime?.notifyMailboxChanged({ kind: "task", taskId: result.task.id });
3117
3149
  return output(`Edited Work Item ${result.task.id}/${result.item.id}\n`, {
3118
3150
  workItem: result.item
3119
3151
  });
@@ -3153,15 +3185,6 @@ function createWork(args, store, options) {
3153
3185
  if (new Set(baseRefs.map(({ projectId }) => projectId)).size !== baseRefs.length) {
3154
3186
  throw usageError("Each Work Item Project may specify at most one base ref.");
3155
3187
  }
3156
- const guard = runDeliveryGuardPreflight(tx, task.id, {
3157
- kind: "create-work-item",
3158
- scope: {
3159
- title: parsed.positionals[1],
3160
- objective: parsed.objective ?? parsed.positionals[1],
3161
- acceptance: parsed.acceptance,
3162
- writeProjectIds
3163
- }
3164
- }, { environment: options.environment, budget: true });
3165
3188
  const created = createWorkItem(tx.nextWorkItemId(task.id), task.id, {
3166
3189
  title: parsed.positionals[1],
3167
3190
  objective: parsed.objective ?? parsed.positionals[1],
@@ -3173,10 +3196,10 @@ function createWork(args, store, options) {
3173
3196
  }, now);
3174
3197
  tx.saveWorkItem(task.id, created);
3175
3198
  enqueueWork(tx, taskMailbox(task.id), "work-created", now, [workItemRef(task.id, created.id)]);
3176
- return { item: created, guard };
3199
+ return created;
3177
3200
  });
3178
- notifyMailbox(options.runtime, taskMailbox(item.item.taskId), item.item.taskId);
3179
- return output(withGuardWarnings(item.guard, `Created work item ${item.item.id} for ${item.item.taskId}\n`), { workItem: item.item });
3201
+ notifyMailbox(options.runtime, taskMailbox(item.taskId));
3202
+ return output(`Created work item ${item.id} for ${item.taskId}\n`, { workItem: item });
3180
3203
  }
3181
3204
  function updateWorkScope(args, store, options) {
3182
3205
  const usage = "Task work scope usage: yui task work scope <task>/<work> [--project <project> ...].";
@@ -3213,7 +3236,7 @@ function updateWorkScope(args, store, options) {
3213
3236
  return { item: next, changed: true };
3214
3237
  });
3215
3238
  if (updated.changed) {
3216
- notifyMailbox(options.runtime, taskMailbox(updated.item.taskId), updated.item.taskId);
3239
+ notifyMailbox(options.runtime, taskMailbox(updated.item.taskId));
3217
3240
  }
3218
3241
  return `${updated.changed ? "Updated" : "Unchanged"} Work Item Project scope ${updated.item.id}: ${updated.item.writeProjectIds.join(", ") || "read-only"}\n`;
3219
3242
  }
@@ -3380,7 +3403,7 @@ function updateWork(args, store, options) {
3380
3403
  reviewTrigger: candidatePolicy?.trigger ?? null
3381
3404
  };
3382
3405
  });
3383
- notifyMailbox(options.runtime, taskMailbox(result.item.taskId), result.item.taskId);
3406
+ notifyMailbox(options.runtime, taskMailbox(result.item.taskId));
3384
3407
  if ((result.item.status === "open" && result.item.candidates.length > 0) && status === "completed") {
3385
3408
  const failure = result.reviewDispatch?.round.status === "failed"
3386
3409
  ? `Review could not start: ${result.reviewDispatch.round.failure?.message ?? result.reviewDispatch.round.id}\n`
@@ -3611,7 +3634,7 @@ function dispatchWork(args, store, options) {
3611
3634
  return { kind: "replicated", runs };
3612
3635
  });
3613
3636
  for (const run of dispatch.runs) {
3614
- notifyMailbox(options.runtime, roleMailbox(run.taskId, run.roleName), run.taskId);
3637
+ notifyMailbox(options.runtime, roleMailbox(run.taskId, run.roleName));
3615
3638
  }
3616
3639
  return dispatch.kind === "direct"
3617
3640
  ? `Direct WorkItem AgentRun queued as ${dispatch.runs[0].id}\n`
@@ -3855,7 +3878,7 @@ function retireWork(args, store, options) {
3855
3878
  }
3856
3879
  return next;
3857
3880
  });
3858
- options.runtime?.notifyStateChanged(retired.taskId);
3881
+ options.runtime?.notifyMailboxChanged({ kind: "task", taskId: retired.taskId });
3859
3882
  return output(`Retired Work Item ${retired.id}\n`, { workItem: retired });
3860
3883
  }
3861
3884
  function listWork(args, store) {
@@ -4061,7 +4084,7 @@ function synthesizeRuns(args, kind, store, options) {
4061
4084
  }, now);
4062
4085
  return created;
4063
4086
  });
4064
- notifyMailbox(options.runtime, roleMailbox(run.taskId, run.roleName), run.taskId);
4087
+ notifyMailbox(options.runtime, roleMailbox(run.taskId, run.roleName));
4065
4088
  return output(`Dispatched synthesis AgentRun ${run.taskId}/${run.id}\n`, { run });
4066
4089
  }
4067
4090
  function taskReviewCommand(args, store, options) {
@@ -4111,7 +4134,7 @@ function requestTaskReviewRound(args, store, options) {
4111
4134
  throw usageError(producerCollision);
4112
4135
  }
4113
4136
  const taskRounds = reviewRoundsByIdentity(tx.listReviewRounds(task.id))
4114
- .filter((entry) => (entry.scope ?? "work-item") === "task");
4137
+ .filter((entry) => entry.scope === "task");
4115
4138
  const exact = taskRounds.filter((entry) => (entry.reviewerRoleName === reviewerRoleName
4116
4139
  && (deltaRecheckRequested
4117
4140
  ? entry.deltaRecheck !== undefined
@@ -4305,7 +4328,7 @@ function retryFailedTaskReviewRound(args, store, options) {
4305
4328
  if (task.status !== "active")
4306
4329
  throw usageError(`Task is not active: ${task.id}.`);
4307
4330
  const requestedBy = taskActor(tx, options, task.id);
4308
- if ((round.scope ?? "work-item") !== "task") {
4331
+ if (round.scope !== "task") {
4309
4332
  throw usageError(`ReviewRound ${round.id} is not a failed Task-final ReviewRound.`);
4310
4333
  }
4311
4334
  if (round.reviewerRunId !== undefined) {
@@ -4392,11 +4415,11 @@ function taskRunCommand(args, store, options) {
4392
4415
  if (command === "retire")
4393
4416
  return retireRun(rest, store, options);
4394
4417
  throw usageError(command === undefined
4395
- ? "Task turn command is required."
4418
+ ? "Task run command is required."
4396
4419
  : `Unknown command: task run ${command}`);
4397
4420
  }
4398
4421
  function settleRun(args, store, options) {
4399
- exactPositionals(args, 1, "Task turn settle usage: yui task run settle <task>/<run>.");
4422
+ exactPositionals(args, 1, "Task run settle usage: yui task run settle <task>/<run>.");
4400
4423
  const previous = store.transaction((tx) => requireRun(tx, args[0], options));
4401
4424
  if (previous.purpose === "review") {
4402
4425
  if (previous.executionGroupId !== undefined
@@ -4477,7 +4500,7 @@ function settleFailedReviewExecutionLaneRun(previous, store, options) {
4477
4500
  };
4478
4501
  });
4479
4502
  for (const run of result.mainRuns) {
4480
- notifyMailbox(options.runtime, roleMailbox(run.taskId, run.roleName), run.taskId);
4503
+ notifyMailbox(options.runtime, roleMailbox(run.taskId, run.roleName));
4481
4504
  }
4482
4505
  return output(result.changed
4483
4506
  ? `Settled failed Review Producer Lane from AgentRun ${result.run.id}\n`
@@ -4552,7 +4575,7 @@ function settleFailedExecutionLaneRun(previous, store, options) {
4552
4575
  };
4553
4576
  });
4554
4577
  for (const run of result.mainRuns) {
4555
- notifyMailbox(options.runtime, roleMailbox(run.taskId, run.roleName), run.taskId);
4578
+ notifyMailbox(options.runtime, roleMailbox(run.taskId, run.roleName));
4556
4579
  }
4557
4580
  return output(result.changed
4558
4581
  ? `Settled failed Execution Lane from AgentRun ${result.run.id}\n`
@@ -4563,7 +4586,7 @@ function settleFailedExecutionLaneRun(previous, store, options) {
4563
4586
  });
4564
4587
  }
4565
4588
  function retireRun(args, store, options) {
4566
- const usage = "Task turn retire usage: yui task run retire <task>/<run> --reason <text> [--expected-progress-at <timestamp>] [--agent-id <id>] [--adapter-id <id>] [--native-session-id <id>].";
4589
+ const usage = "Task run retire usage: yui task run retire <task>/<run> --reason <text> [--expected-progress-at <timestamp>] [--agent-id <id>] [--adapter-id <id>] [--native-session-id <id>].";
4567
4590
  const parsed = parseTail(args, new Set([
4568
4591
  "--reason",
4569
4592
  "--expected-progress-at",
@@ -4647,7 +4670,7 @@ function retireRun(args, store, options) {
4647
4670
  return { task, run: run, changed: true };
4648
4671
  });
4649
4672
  if (result.changed)
4650
- options.runtime?.notifyStateChanged(result.task.id);
4673
+ options.runtime?.notifyMailboxChanged({ kind: "task", taskId: result.task.id });
4651
4674
  return output(`Retired AgentRun ${result.task.id}/${result.run.id}\n`, {
4652
4675
  run: result.run,
4653
4676
  retired: true
@@ -4656,7 +4679,7 @@ function retireRun(args, store, options) {
4656
4679
  function runContextCommand(args, store, options) {
4657
4680
  const [first, ...rest] = args;
4658
4681
  if (first === "expand") {
4659
- const usage = "Task turn context expand usage: yui task run context expand <task>/<run> <ref-id> [--store <store>] [--mode full].";
4682
+ const usage = "Task run context expand usage: yui task run context expand <task>/<run> <ref-id> [--store <store>] [--mode full].";
4660
4683
  const parsed = parseTail(rest, new Set(["--store", "--mode"]), usage);
4661
4684
  exactPositionals(parsed.positionals, 2, usage);
4662
4685
  const mode = parsed.options.get("--mode");
@@ -4670,7 +4693,7 @@ function runContextCommand(args, store, options) {
4670
4693
  }
4671
4694
  if (first === "delta") {
4672
4695
  if (rest.length !== 3 || rest[1] !== "--after") {
4673
- throw usageError("Task turn context delta usage: yui task run context delta <task>/<run> --after <cursor>.");
4696
+ throw usageError("Task run context delta usage: yui task run context delta <task>/<run> --after <cursor>.");
4674
4697
  }
4675
4698
  const { taskId, runId } = parseRunContextReference(rest[0]);
4676
4699
  authorizeRunContext(store, taskId, runId, options.environment);
@@ -4678,7 +4701,7 @@ function runContextCommand(args, store, options) {
4678
4701
  return output(`${JSON.stringify(delta, null, 2)}\n`, { contextDelta: delta });
4679
4702
  }
4680
4703
  if (first === undefined || rest.length !== 0) {
4681
- throw usageError("Task turn context usage: yui task run context <task>/<run>.");
4704
+ throw usageError("Task run context usage: yui task run context <task>/<run>.");
4682
4705
  }
4683
4706
  const { taskId, runId } = parseRunContextReference(first);
4684
4707
  authorizeRunContext(store, taskId, runId, options.environment);
@@ -4719,7 +4742,7 @@ function authorizeRunContext(store, taskId, runId, environment) {
4719
4742
  }
4720
4743
  }
4721
4744
  function listRuns(args, store, options) {
4722
- const usage = "Task turn list usage: yui task run list <task|task/work>.";
4745
+ const usage = "Task run list usage: yui task run list <task|task/work>.";
4723
4746
  exactPositionals(args, 1, usage);
4724
4747
  const reference = args[0];
4725
4748
  const task = store.getTask(reference);
@@ -4764,7 +4787,7 @@ function listRuns(args, store, options) {
4764
4787
  * creates one fresh Round over the newer frozen Task heads.
4765
4788
  */
4766
4789
  function settleStaleFinalReviewRun(args, store, options) {
4767
- exactPositionals(args, 1, "Task turn settle usage: yui task run settle <task>/<run>.");
4790
+ exactPositionals(args, 1, "Task run settle usage: yui task run settle <task>/<run>.");
4768
4791
  const now = clock(options);
4769
4792
  const previous = store.transaction((tx) => requireRun(tx, args[0], options));
4770
4793
  const result = store.transaction((tx) => {
@@ -4783,7 +4806,7 @@ function settleStaleFinalReviewRun(args, store, options) {
4783
4806
  if (round === null) {
4784
4807
  throw dataError(`ReviewRound not found for AgentRun ${run.id}: ${run.reviewRoundId}.`);
4785
4808
  }
4786
- if ((round.scope ?? "work-item") !== "task") {
4809
+ if (round.scope !== "task") {
4787
4810
  throw usageError(`Review AgentRun ${run.id} is not a Task-final review; request a new WorkItem review `
4788
4811
  + "for a new Candidate.");
4789
4812
  }
@@ -4803,7 +4826,7 @@ function settleStaleFinalReviewRun(args, store, options) {
4803
4826
  throw usageError(`${task.id}/${round.reviewerRoleName} already has active AgentRun ${activeRoleRun.id}.`);
4804
4827
  }
4805
4828
  const taskRounds = reviewRoundsByIdentity(tx.listReviewRounds(task.id)
4806
- .filter((entry) => (entry.scope ?? "work-item") === "task"));
4829
+ .filter((entry) => entry.scope === "task"));
4807
4830
  const roundIndex = taskRounds.findIndex(({ id }) => id === round.id);
4808
4831
  if (roundIndex < 0) {
4809
4832
  throw dataError(`Final ReviewRound is not in Task history: ${round.id}.`);
@@ -4883,7 +4906,7 @@ function retryRun(args, store, options) {
4883
4906
  });
4884
4907
  }
4885
4908
  function retryRunOperation(args, store, options) {
4886
- exactPositionals(args, 1, "Task turn retry usage: yui task run retry <task>/<run>.");
4909
+ exactPositionals(args, 1, "Task run retry usage: yui task run retry <task>/<run>.");
4887
4910
  const now = clock(options);
4888
4911
  const previous = store.transaction((tx) => requireRun(tx, args[0], options));
4889
4912
  if (previous.purpose === "review") {
@@ -5147,10 +5170,10 @@ function retryRunOperation(args, store, options) {
5147
5170
  }, now);
5148
5171
  return { kind: "run", run: created };
5149
5172
  });
5150
- notifyMailbox(options.runtime, roleMailbox(retried.run.taskId, retried.run.roleName), retried.run.taskId);
5173
+ notifyMailbox(options.runtime, roleMailbox(retried.run.taskId, retried.run.roleName));
5151
5174
  return output(`Retry queued as ${retried.run.id} for ${retried.run.taskId}/${retried.run.roleName}\n`);
5152
5175
  }
5153
- function actualTaskReviewCandidateForMutation(store, task, options) {
5176
+ function actualTaskReviewCandidateForMutation(_store, task, options) {
5154
5177
  if (options.actualTaskReviewCandidate === undefined) {
5155
5178
  throw usageError(`Actual Task Project heads were not verified for delivery: ${task.id}.`);
5156
5179
  }
@@ -5286,7 +5309,7 @@ function isSameTaskReviewCandidate(left, right) {
5286
5309
  function assertNoConflictingTaskReviewRound(rounds, reusableRoundIds = [], reviewerRoleName) {
5287
5310
  const reusable = new Set(typeof reusableRoundIds === "string" ? [reusableRoundIds] : reusableRoundIds);
5288
5311
  const conflicting = rounds.find((entry) => (!reusable.has(entry.id)
5289
- && (entry.scope ?? "work-item") === "task"
5312
+ && entry.scope === "task"
5290
5313
  && (entry.status === "pending" || entry.status === "running")
5291
5314
  && (reviewerRoleName === undefined || entry.reviewerRoleName === reviewerRoleName)));
5292
5315
  if (conflicting !== undefined) {
@@ -5341,7 +5364,7 @@ function prepareFinalTaskReview(store, task, now, taskFinalContract, options) {
5341
5364
  if (taskFinalContract === undefined || task.projectBindings.length === 0)
5342
5365
  return null;
5343
5366
  const taskRounds = reviewRoundsByIdentity(store.listReviewRounds(task.id))
5344
- .filter((round) => ((round.scope ?? "work-item") === "task"
5367
+ .filter((round) => (round.scope === "task"
5345
5368
  && sameTaskFinalReviewContract(round.taskFinalReviewContract, taskFinalContract)));
5346
5369
  const establishedRound = taskRounds.at(-1);
5347
5370
  const config = taskFinalReviewConfig(taskFinalContract);
@@ -5368,7 +5391,7 @@ function prepareFinalTaskReview(store, task, now, taskFinalContract, options) {
5368
5391
  }
5369
5392
  return queueTaskReviewRound(store, task, config, taskCandidate, options, now, establishedRound?.requestedBy ?? "policy", taskFinalContract);
5370
5393
  }
5371
- function resumablePendingFinalTaskReview(store, task, round, config, taskCandidate, taskFinalContract, options) {
5394
+ function resumablePendingFinalTaskReview(store, task, round, config, _taskCandidate, taskFinalContract, _options) {
5372
5395
  if (taskFinalContract === undefined || round.taskFinalReviewContract === undefined) {
5373
5396
  throw usageError(`Final Task Review is still active: ${round.id}/${round.status}.`);
5374
5397
  }
@@ -5447,7 +5470,7 @@ function retryFailedReviewRun(previous, store, options, now) {
5447
5470
  if (round === null) {
5448
5471
  throw dataError(`ReviewRound not found for run ${run.id}: ${run.reviewRoundId}.`);
5449
5472
  }
5450
- const taskScope = (round.scope ?? "work-item") === "task";
5473
+ const taskScope = round.scope === "task";
5451
5474
  const retryLane = run.executionLaneId === undefined
5452
5475
  ? undefined
5453
5476
  : round.executionGroup?.lanes.find(({ id }) => id === run.executionLaneId);
@@ -5482,7 +5505,7 @@ function retryFailedReviewRun(previous, store, options, now) {
5482
5505
  throw usageError(`Task-final ReviewRound ${round.id} no longer matches the frozen Task heads.`);
5483
5506
  }
5484
5507
  const taskRounds = reviewRoundsByIdentity(allRounds
5485
- .filter((entry) => (entry.scope ?? "work-item") === "task"));
5508
+ .filter((entry) => entry.scope === "task"));
5486
5509
  const roundIndex = taskRounds.findIndex(({ id }) => id === round.id);
5487
5510
  if (roundIndex < 0) {
5488
5511
  throw dataError(`Final ReviewRound is not in Task history: ${round.id}.`);
@@ -5650,7 +5673,7 @@ function retryFailedReviewRun(previous, store, options, now) {
5650
5673
  return { round: resetRound, previousRun: run, created: true };
5651
5674
  });
5652
5675
  if ("run" in result && result.run !== undefined) {
5653
- notifyMailbox(options.runtime, roleMailbox(result.run.taskId, result.run.roleName), result.run.taskId);
5676
+ notifyMailbox(options.runtime, roleMailbox(result.run.taskId, result.run.roleName));
5654
5677
  }
5655
5678
  return output(result.created
5656
5679
  ? `Review retry requested as ${result.round.id}\n`
@@ -5658,7 +5681,7 @@ function retryFailedReviewRun(previous, store, options, now) {
5658
5681
  }
5659
5682
  /** AgentRun details are retained audit evidence; continuation uses durable Task state. */
5660
5683
  function showRun(args, store, options) {
5661
- const usage = "Task turn show usage: yui task run show <task>/<run> [--json].";
5684
+ const usage = "Task run show usage: yui task run show <task>/<run> [--json].";
5662
5685
  const asJson = args.includes("--json");
5663
5686
  const positionals = args.filter((arg) => arg !== "--json");
5664
5687
  exactPositionals(positionals, 1, usage);
@@ -5710,7 +5733,7 @@ function renderRunShow(run, retirement) {
5710
5733
  * Leader.
5711
5734
  */
5712
5735
  function checkpointRun(args, store, options) {
5713
- const usage = "Task turn checkpoint usage: yui task run checkpoint <run> (--note <text>|--note-file <path|->).";
5736
+ const usage = "Task run checkpoint usage: yui task run checkpoint <run> (--note <text>|--note-file <path|->).";
5714
5737
  const parsed = parseTail(args, new Set(["--note", "--note-file"]), usage);
5715
5738
  exactPositionals(parsed.positionals, 1, usage);
5716
5739
  const note = readCommandText(parsed.options.get("--note"), parsed.options.get("--note-file"), "--note", usage);
@@ -5876,12 +5899,12 @@ export function dispatchPreparedReviewRound(taskId, reviewRoundId, store, option
5876
5899
  throw usageError(`ReviewRound is not dispatchable: ${round.id}/${round.status}.`);
5877
5900
  }
5878
5901
  if (round.workspace === undefined) {
5879
- if ((round.scope ?? "work-item") === "task") {
5902
+ if (round.scope === "task") {
5880
5903
  throw new TaskFinalReviewDispatchDriftError(`ReviewRound workspace is not ready: ${round.id}.`);
5881
5904
  }
5882
5905
  throw usageError(`ReviewRound workspace is not ready: ${round.id}.`);
5883
5906
  }
5884
- const taskScope = (round.scope ?? "work-item") === "task";
5907
+ const taskScope = round.scope === "task";
5885
5908
  let item;
5886
5909
  let candidate;
5887
5910
  if (taskScope) {
@@ -5914,7 +5937,7 @@ export function dispatchPreparedReviewRound(taskId, reviewRoundId, store, option
5914
5937
  if (task.status !== "active")
5915
5938
  throw usageError(`Task is not active: ${task.id}.`);
5916
5939
  assertTaskExecutionEnabled(task, "dispatching a Review");
5917
- if ((round.scope ?? "work-item") === "task") {
5940
+ if (round.scope === "task") {
5918
5941
  let taskFinalContract;
5919
5942
  try {
5920
5943
  taskFinalContract = taskFinalReviewContractForMutation(tx, task.id, options);
@@ -5955,7 +5978,7 @@ export function dispatchPreparedReviewRound(taskId, reviewRoundId, store, option
5955
5978
  }
5956
5979
  const reviewer = tx.getRole(taskId, round.reviewerRoleName);
5957
5980
  if (reviewer === null) {
5958
- if ((round.scope ?? "work-item") === "task") {
5981
+ if (round.scope === "task") {
5959
5982
  throw new TaskFinalReviewDispatchDriftError(`Reviewer Role not found: ${taskId}/${round.reviewerRoleName}.`);
5960
5983
  }
5961
5984
  throw roleNotFound(round.reviewerRoleName);
@@ -5966,7 +5989,7 @@ export function dispatchPreparedReviewRound(taskId, reviewRoundId, store, option
5966
5989
  || storedWorkspace.owner.type !== "review-round"
5967
5990
  || storedWorkspace.owner.reviewRoundId !== round.id) {
5968
5991
  const message = `ReviewRound workspace ownership changed: ${round.id}.`;
5969
- if ((round.scope ?? "work-item") === "task") {
5992
+ if (round.scope === "task") {
5970
5993
  throw new TaskFinalReviewDispatchDriftError(message);
5971
5994
  }
5972
5995
  throw usageError(message);
@@ -5977,7 +6000,7 @@ export function dispatchPreparedReviewRound(taskId, reviewRoundId, store, option
5977
6000
  ...(round.executionGroup?.lanes.map(({ roleName }) => roleName) ?? [])
5978
6001
  ]);
5979
6002
  const conflicting = tx.listReviewRounds(task.id).find((entry) => (entry.id !== round.id
5980
- && (entry.scope ?? "work-item") === "task"
6003
+ && entry.scope === "task"
5981
6004
  && (entry.status === "pending" || entry.status === "running")
5982
6005
  && (requestedReviewers.has(entry.reviewerRoleName)
5983
6006
  || entry.executionGroup?.lanes.some(({ roleName }) => (requestedReviewers.has(roleName))) === true)
@@ -6229,7 +6252,7 @@ export function dispatchPreparedReviewRound(taskId, reviewRoundId, store, option
6229
6252
  return createdRuns;
6230
6253
  });
6231
6254
  for (const run of runs) {
6232
- notifyMailbox(options.runtime, roleMailbox(run.taskId, run.roleName), run.taskId);
6255
+ notifyMailbox(options.runtime, roleMailbox(run.taskId, run.roleName));
6233
6256
  }
6234
6257
  return runs[0] ?? null;
6235
6258
  }
@@ -6256,7 +6279,7 @@ export function failPendingReviewRound(taskId, reviewRoundId, summary, store, op
6256
6279
  ]);
6257
6280
  return terminal;
6258
6281
  });
6259
- notifyMailbox(options.runtime, leaderMailbox(taskId), taskId);
6282
+ notifyMailbox(options.runtime, leaderMailbox(taskId));
6260
6283
  return failed;
6261
6284
  }
6262
6285
  export function preserveReviewRoundWorkspace(taskId, reviewRoundId, store, options = {}) {
@@ -6440,20 +6463,6 @@ function appendMessage(store, taskId, body, kind, author, now, context = {}) {
6440
6463
  }, now);
6441
6464
  return message;
6442
6465
  }
6443
- function recordTaskEvent(store, taskId, type, payload, now) {
6444
- return recordTaskEventRecord(store, taskId, type, payload, now);
6445
- }
6446
- function leaderActionEventPayload(store, taskId, options) {
6447
- const caller = currentManagedRuntime(store, options.environment, taskId, "leader");
6448
- // A long-lived Session may be handling direct input while another request
6449
- // awaits admission. The Role's active pointer cannot prove command origin.
6450
- return caller === undefined ? {} : { leaderNativeSessionId: caller.nativeSessionId };
6451
- }
6452
- function recordTaskEventRecord(store, taskId, type, payload, now) {
6453
- const event = createTaskEvent(store.nextEventId(taskId), taskId, type, payload, now);
6454
- store.saveEvent(taskId, event);
6455
- return event;
6456
- }
6457
6466
  /** Keeps a free-text AgentRun-fact note bounded so an event payload stays compact. */
6458
6467
  function truncateEventNote(note) {
6459
6468
  const normalized = note.trim();
@@ -6488,13 +6497,6 @@ function runLaunchEventPayload(run) {
6488
6497
  })
6489
6498
  };
6490
6499
  }
6491
- function requireTask(store, taskId) {
6492
- const id = requiredText(taskId, "Task id");
6493
- const task = store.getTask(id);
6494
- if (task === null)
6495
- throw taskNotFound(id);
6496
- return task;
6497
- }
6498
6500
  function requireRole(store, taskId, roleName) {
6499
6501
  const name = requiredText(roleName, "Role name");
6500
6502
  const role = store.getRole(taskId, name);
@@ -6536,14 +6538,6 @@ function activeRunPointer(store, run) {
6536
6538
  ? store.getActiveExecutionLaneRun(run.taskId, run.executionGroupId, run.executionLaneId)
6537
6539
  : store.getActiveRun(run.taskId, run.roleName);
6538
6540
  }
6539
- function requireReviewRound(store, reviewRoundId, options) {
6540
- const reference = taskRecordReference(reviewRoundId, "reviewRound", "ReviewRound reference", options);
6541
- const round = store.getReviewRound(reference.taskId, reference.localId);
6542
- if (round === null) {
6543
- throw usageError(`ReviewRound not found: ${reference.taskId}/${reference.localId}.`);
6544
- }
6545
- return round;
6546
- }
6547
6541
  function taskRecordReference(value, kind, label, options) {
6548
6542
  try {
6549
6543
  return resolveTaskRecordReference(requiredText(value, label), {
@@ -6576,23 +6570,11 @@ function chronologicalRuns(runs) {
6576
6570
  function isTerminalWorkItemStatus(status) {
6577
6571
  return ["accepted", "retired"].includes(status);
6578
6572
  }
6579
- function assertTaskOpen(task) {
6580
- if (task.status === "completed") {
6581
- throw usageError(`Task ${task.id} is completed; reopen it before continuing.`);
6582
- }
6583
- if (task.status === "archived")
6584
- throw usageError(`Task is archived: ${task.id}.`);
6585
- if (task.status === "cancelled")
6586
- throw usageError(`Task is retired: ${task.id}.`);
6587
- }
6588
6573
  function assertTaskExecutionEnabled(task, action) {
6589
6574
  if (task.executionGate.state === "enabled")
6590
6575
  return;
6591
6576
  throw usageError(`Task execution is stopped: ${task.id}. Run "yui task execution start ${task.id}" before ${action}.`);
6592
6577
  }
6593
- function taskActor(store, options, taskId) {
6594
- return resolveTaskLocalActor(store, options.environment, taskId);
6595
- }
6596
6578
  function inactiveTaskMessage(task, action) {
6597
6579
  if (task.status === "draft") {
6598
6580
  return `Task ${task.id} is a Draft; activate it before ${action}.`;
@@ -6734,317 +6716,12 @@ function parseIsoTimestamp(value, label) {
6734
6716
  }
6735
6717
  return timestamp.toISOString();
6736
6718
  }
6737
- function taskBriefCommand(args, store, options) {
6738
- const [command, ...rest] = args;
6739
- if (command === "show") {
6740
- exactPositionals(rest, 1, "Task brief show usage: yui task brief show <task>.");
6741
- const task = requireTask(store, rest[0]);
6742
- const brief = store.getTaskBrief(task.id);
6743
- if (brief === null) {
6744
- return output(`Task ${task.id} has no brief.\n`, { taskId: task.id, brief: null });
6745
- }
6746
- const timeZone = store.getConfig().timeZone;
6747
- return output([
6748
- `Task: ${task.id}`,
6749
- `Objective: ${brief.objective}`,
6750
- `Boundaries:`,
6751
- ...(brief.boundaries.length === 0 ? [" (none)"] : brief.boundaries.map((b) => ` - ${b}`)),
6752
- `Technical approach: ${brief.technicalApproach || "(not defined)"}`,
6753
- `Current focus: ${brief.currentFocus}`,
6754
- `Leader summary: ${brief.leaderSummary}`,
6755
- `Updated by: ${brief.updatedBy}`,
6756
- `Updated at: ${presentTime(brief.updatedAt, timeZone)}`
6757
- ].join("\n").concat("\n"), { taskId: task.id, brief });
6758
- }
6759
- if (command === "update") {
6760
- const usage = "Task brief update usage: yui task brief update <task> [--objective <text>] [--boundary <text> ...] [--approach <text>] [--focus <text>] [--leader-summary <text>].";
6761
- const parsed = parseMultiValueTail(rest, new Set(["--objective", "--approach", "--focus", "--leader-summary"]), new Set(["--boundary"]), usage);
6762
- exactPositionals(parsed.positionals, 1, usage);
6763
- const hasObjective = parsed.options.has("--objective");
6764
- const hasApproach = parsed.options.has("--approach");
6765
- const hasFocus = parsed.options.has("--focus");
6766
- const hasSummary = parsed.options.has("--leader-summary");
6767
- const boundaries = parsed.multiOptions.get("--boundary") ?? [];
6768
- if (!hasObjective && !hasApproach && !hasFocus && !hasSummary && boundaries.length === 0) {
6769
- throw usageError("At least one brief field is required.", usage);
6770
- }
6771
- const now = clock(options);
6772
- const result = store.transaction((tx) => {
6773
- const task = requireTask(tx, parsed.positionals[0]);
6774
- assertTaskOpen(task);
6775
- const existing = tx.getTaskBrief(task.id);
6776
- const updatedBy = taskActor(tx, options, task.id);
6777
- const brief = existing === null
6778
- ? createTaskBrief({
6779
- objective: requiredText(parsed.options.get("--objective"), "--objective"),
6780
- boundaries,
6781
- ...(hasApproach
6782
- ? { technicalApproach: requiredText(parsed.options.get("--approach"), "--approach") }
6783
- : {}),
6784
- currentFocus: requiredText(parsed.options.get("--focus"), "--focus"),
6785
- leaderSummary: requiredText(parsed.options.get("--leader-summary"), "--leader-summary"),
6786
- updatedBy
6787
- }, now)
6788
- : updateTaskBrief(existing, {
6789
- ...(hasObjective ? { objective: parsed.options.get("--objective") } : {}),
6790
- ...(boundaries.length > 0 ? { boundaries } : {}),
6791
- ...(hasApproach
6792
- ? { technicalApproach: parsed.options.get("--approach") }
6793
- : {}),
6794
- ...(hasFocus ? { currentFocus: parsed.options.get("--focus") } : {}),
6795
- ...(hasSummary ? { leaderSummary: parsed.options.get("--leader-summary") } : {})
6796
- }, updatedBy, now);
6797
- tx.saveTaskBrief(task.id, brief);
6798
- recordTaskEvent(tx, task.id, "brief.updated", {
6799
- updatedBy,
6800
- previous: JSON.stringify(existing), current: JSON.stringify(brief)
6801
- }, now);
6802
- enqueueWork(tx, taskMailbox(task.id), "brief-updated", now, [taskRef(task.id)]);
6803
- if (task.status === "active" && updatedBy !== "leader") {
6804
- enqueueWork(tx, leaderMailbox(task.id), "brief-updated", now, [taskRef(task.id)]);
6805
- }
6806
- return { task, brief };
6807
- });
6808
- notifyMailbox(options.runtime, taskMailbox(result.task.id), result.task.id);
6809
- if (result.task.status === "active") {
6810
- notifyMailbox(options.runtime, leaderMailbox(result.task.id), result.task.id);
6811
- }
6812
- return output(`Updated brief for ${result.task.id}\n`, { taskId: result.task.id, brief: result.brief });
6813
- }
6814
- throw usageError(command === undefined
6815
- ? "Task brief command is required."
6816
- : `Unknown command: task brief ${command}`);
6817
- }
6818
6719
  /** Persist only edited fields, not another copy of aggregate execution history.
6819
6720
  * Null records an absent optional field so clearing it remains observable. */
6820
6721
  function editedFieldValues(record, fields) {
6821
6722
  const values = record;
6822
6723
  return JSON.stringify(Object.fromEntries(fields.map((field) => [field, values[field] ?? null])));
6823
6724
  }
6824
- function taskDecisionCommand(args, store, options) {
6825
- const [command, ...rest] = args;
6826
- if (command === "record") {
6827
- const usage = "Task decision record usage: yui task decision record <task> --title <text> --rationale <text>.";
6828
- const parsed = parseTail(rest, new Set(["--title", "--rationale"]), usage);
6829
- exactPositionals(parsed.positionals, 1, usage);
6830
- const title = requiredOption(parsed.options, "--title");
6831
- const rationale = requiredOption(parsed.options, "--rationale");
6832
- const now = clock(options);
6833
- const result = store.transaction((tx) => {
6834
- const task = requireTask(tx, parsed.positionals[0]);
6835
- assertTaskOpen(task);
6836
- const actor = taskActor(tx, options, task.id);
6837
- const decision = createDecision(tx.nextDecisionId(task.id), task.id, title, rationale, now);
6838
- tx.saveDecision(task.id, decision);
6839
- recordTaskEvent(tx, task.id, "decision.recorded", {
6840
- decisionId: decision.id,
6841
- title,
6842
- ...leaderActionEventPayload(tx, task.id, options)
6843
- }, now);
6844
- enqueueWork(tx, taskMailbox(task.id), "decision-recorded", now, [taskRef(task.id)]);
6845
- if (task.status === "active" && actor !== "leader") {
6846
- enqueueWork(tx, leaderMailbox(task.id), "decision-recorded", now, [taskRef(task.id)]);
6847
- }
6848
- return { task, decision };
6849
- });
6850
- notifyMailbox(options.runtime, taskMailbox(result.task.id), result.task.id);
6851
- if (result.task.status === "active")
6852
- notifyMailbox(options.runtime, leaderMailbox(result.task.id), result.task.id);
6853
- return output(`Recorded decision ${result.decision.id} for ${result.task.id}\n`);
6854
- }
6855
- if (command === "list") {
6856
- const usage = "Task decision list usage: yui task decision list <task> [--status active|superseded].";
6857
- const parsed = parseTail(rest, new Set(["--status"]), usage);
6858
- exactPositionals(parsed.positionals, 1, usage);
6859
- const task = requireTask(store, parsed.positionals[0]);
6860
- let decisions = store.listDecisions(task.id);
6861
- const status = parsed.options.get("--status");
6862
- if (status !== undefined) {
6863
- if (status !== "active" && status !== "superseded") {
6864
- throw usageError("--status must be active or superseded.", usage);
6865
- }
6866
- decisions = decisions.filter((d) => d.status === status);
6867
- }
6868
- if (decisions.length === 0) {
6869
- return output(`No decisions found for ${task.id}.\n`, { taskId: task.id, decisions: [] });
6870
- }
6871
- const timeZone = store.getConfig().timeZone;
6872
- return output(`${renderTable(`Decisions: ${task.id}`, [
6873
- { header: "Decision", minWidth: 8, maxWidth: 18 },
6874
- { header: "Status", minWidth: 6, maxWidth: 12 },
6875
- { header: "Title", minWidth: 8, maxWidth: 64 },
6876
- { header: "Created", minWidth: 10, maxWidth: 28 }
6877
- ], decisions.map((d) => [d.id, d.status, d.title, presentTime(d.createdAt, timeZone)]), defaultTableWidth())}\n`, { taskId: task.id, decisions });
6878
- }
6879
- if (command === "show") {
6880
- exactPositionals(rest, 2, "Task decision show usage: yui task decision show <task> <decision>.");
6881
- const task = requireTask(store, rest[0]);
6882
- const decision = store.getDecision(task.id, rest[1]);
6883
- if (decision === null)
6884
- throw dataError(`Decision not found: ${rest[1]}.`);
6885
- const timeZone = store.getConfig().timeZone;
6886
- return output([
6887
- `Decision: ${decision.id}`,
6888
- `Task: ${task.id}`,
6889
- `Title: ${decision.title}`,
6890
- `Rationale: ${decision.rationale}`,
6891
- `Status: ${decision.status}`,
6892
- ...(decision.supersededReason === undefined ? [] : [`Superseded reason: ${decision.supersededReason}`]),
6893
- ...(decision.supersededAt === undefined ? [] : [`Superseded at: ${presentTime(decision.supersededAt, timeZone)}`]),
6894
- `Created: ${presentTime(decision.createdAt, timeZone)}`,
6895
- `Updated: ${presentTime(decision.updatedAt, timeZone)}`
6896
- ].join("\n").concat("\n"), { taskId: task.id, decision });
6897
- }
6898
- if (command === "supersede") {
6899
- const usage = "Task decision supersede usage: yui task decision supersede <task> <decision> --reason <text>.";
6900
- const parsed = parseTail(rest, new Set(["--reason"]), usage);
6901
- exactPositionals(parsed.positionals, 2, usage);
6902
- const reason = requiredOption(parsed.options, "--reason");
6903
- const now = clock(options);
6904
- const result = store.transaction((tx) => {
6905
- const task = requireTask(tx, parsed.positionals[0]);
6906
- assertTaskOpen(task);
6907
- const actor = taskActor(tx, options, task.id);
6908
- const existing = tx.getDecision(task.id, parsed.positionals[1]);
6909
- if (existing === null)
6910
- throw dataError(`Decision not found: ${parsed.positionals[1]}.`);
6911
- const decision = supersedeDecision(existing, reason, now);
6912
- tx.saveDecision(task.id, decision);
6913
- recordTaskEvent(tx, task.id, "decision.superseded", {
6914
- decisionId: decision.id,
6915
- reason,
6916
- ...leaderActionEventPayload(tx, task.id, options)
6917
- }, now);
6918
- enqueueWork(tx, taskMailbox(task.id), "decision-superseded", now, [taskRef(task.id)]);
6919
- if (task.status === "active" && actor !== "leader") {
6920
- enqueueWork(tx, leaderMailbox(task.id), "decision-superseded", now, [taskRef(task.id)]);
6921
- }
6922
- return { task, decision };
6923
- });
6924
- notifyMailbox(options.runtime, taskMailbox(result.task.id), result.task.id);
6925
- if (result.task.status === "active")
6926
- notifyMailbox(options.runtime, leaderMailbox(result.task.id), result.task.id);
6927
- return output(`Superseded decision ${result.decision.id} for ${result.task.id}\n`);
6928
- }
6929
- throw usageError(command === undefined
6930
- ? "Task decision command is required."
6931
- : `Unknown command: task decision ${command}`);
6932
- }
6933
- function taskMilestoneCommand(args, store, options) {
6934
- const [command, ...rest] = args;
6935
- if (command === "add") {
6936
- const usage = "Task milestone add usage: yui task milestone add <task> --title <text> --summary <text>.";
6937
- const parsed = parseTail(rest, new Set(["--title", "--summary"]), usage);
6938
- exactPositionals(parsed.positionals, 1, usage);
6939
- const title = requiredOption(parsed.options, "--title");
6940
- const summary = requiredOption(parsed.options, "--summary");
6941
- const now = clock(options);
6942
- const result = store.transaction((tx) => {
6943
- const task = requireTask(tx, parsed.positionals[0]);
6944
- assertTaskOpen(task);
6945
- const actor = taskActor(tx, options, task.id);
6946
- const milestone = createMilestone(tx.nextMilestoneId(task.id), task.id, title, summary, actor, now);
6947
- tx.saveMilestone(task.id, milestone);
6948
- recordTaskEvent(tx, task.id, "milestone.added", {
6949
- milestoneId: milestone.id,
6950
- title,
6951
- ...leaderActionEventPayload(tx, task.id, options)
6952
- }, now);
6953
- enqueueWork(tx, taskMailbox(task.id), "milestone-added", now, [taskRef(task.id)]);
6954
- return { task, milestone };
6955
- });
6956
- notifyMailbox(options.runtime, taskMailbox(result.task.id), result.task.id);
6957
- return output(`Added milestone ${result.milestone.id} for ${result.task.id}\n`);
6958
- }
6959
- if (command === "list") {
6960
- exactPositionals(rest, 1, "Task milestone list usage: yui task milestone list <task>.");
6961
- const task = requireTask(store, rest[0]);
6962
- const milestones = store.listMilestones(task.id);
6963
- if (milestones.length === 0) {
6964
- return output(`No milestones found for ${task.id}.\n`, { taskId: task.id, milestones: [] });
6965
- }
6966
- const timeZone = store.getConfig().timeZone;
6967
- return output(`${renderTable(`Milestones: ${task.id}`, [
6968
- { header: "Milestone", minWidth: 9, maxWidth: 18 },
6969
- { header: "Title", minWidth: 8, maxWidth: 64 },
6970
- { header: "Created", minWidth: 10, maxWidth: 28 }
6971
- ], milestones.map((m) => [m.id, m.title, presentTime(m.createdAt, timeZone)]), defaultTableWidth())}\n`, { taskId: task.id, milestones });
6972
- }
6973
- if (command === "show") {
6974
- exactPositionals(rest, 2, "Task milestone show usage: yui task milestone show <task> <milestone>.");
6975
- const task = requireTask(store, rest[0]);
6976
- const milestone = store.getMilestone(task.id, rest[1]);
6977
- if (milestone === null)
6978
- throw dataError(`Milestone not found: ${rest[1]}.`);
6979
- const timeZone = store.getConfig().timeZone;
6980
- return output([
6981
- `Milestone: ${milestone.id}`,
6982
- `Task: ${task.id}`,
6983
- `Title: ${milestone.title}`,
6984
- `Summary: ${milestone.summary}`,
6985
- `Created by: ${milestone.createdBy}`,
6986
- `Created: ${presentTime(milestone.createdAt, timeZone)}`
6987
- ].join("\n").concat("\n"), { taskId: task.id, milestone });
6988
- }
6989
- throw usageError(command === undefined
6990
- ? "Task milestone command is required."
6991
- : `Unknown command: task milestone ${command}`);
6992
- }
6993
- function taskEventCommand(args, store) {
6994
- const [command, ...rest] = args;
6995
- if (command === "list") {
6996
- const eventListUsage = "Task event list usage: yui task event list <task> [--after <timestamp>] [--limit <n>].";
6997
- const parsed = parseTail(rest, new Set(["--after", "--limit"]), eventListUsage);
6998
- exactPositionals(parsed.positionals, 1, eventListUsage);
6999
- const task = requireTask(store, parsed.positionals[0]);
7000
- let events = store.listEvents(task.id);
7001
- const after = optionalNonEmptyOption(parsed.options, "--after");
7002
- if (after !== undefined) {
7003
- const afterMs = Date.parse(after);
7004
- if (!Number.isFinite(afterMs))
7005
- throw usageError("--after must be a valid timestamp.", eventListUsage);
7006
- events = events.filter((e) => Date.parse(e.createdAt) > afterMs);
7007
- }
7008
- const limit = optionalNonEmptyOption(parsed.options, "--limit");
7009
- if (limit !== undefined) {
7010
- const n = Number(limit);
7011
- if (!Number.isSafeInteger(n) || n <= 0)
7012
- throw usageError("--limit must be a positive integer.", eventListUsage);
7013
- events = events.slice(-n);
7014
- }
7015
- if (events.length === 0) {
7016
- return output(`No events found for ${task.id}.\n`, { taskId: task.id, events: [] });
7017
- }
7018
- const timeZone = store.getConfig().timeZone;
7019
- return output(`${renderTable(`Events: ${task.id}`, [
7020
- { header: "Event", minWidth: 8, maxWidth: 18 },
7021
- { header: "Type", minWidth: 8, maxWidth: 28 },
7022
- { header: "Created", minWidth: 10, maxWidth: 28 }
7023
- ], events.map((e) => [e.id, e.type, presentTime(e.createdAt, timeZone)]), defaultTableWidth())}\n`, { taskId: task.id, events });
7024
- }
7025
- if (command === "show") {
7026
- exactPositionals(rest, 2, "Task event show usage: yui task event show <task> <event>.");
7027
- const task = requireTask(store, rest[0]);
7028
- const events = store.listEvents(task.id);
7029
- const event = events.find((e) => e.id === rest[1]) ?? null;
7030
- if (event === null)
7031
- throw dataError(`Event not found: ${rest[1]}.`);
7032
- const timeZone = store.getConfig().timeZone;
7033
- return output([
7034
- `Event: ${event.id}`,
7035
- `Task: ${task.id}`,
7036
- `Type: ${event.type}`,
7037
- `Created: ${presentTime(event.createdAt, timeZone)}`,
7038
- `Payload:`,
7039
- ...(Object.keys(event.payload).length === 0
7040
- ? [" (none)"]
7041
- : Object.entries(event.payload).map(([k, v]) => ` ${k}: ${v}`))
7042
- ].join("\n").concat("\n"), { taskId: task.id, event });
7043
- }
7044
- throw usageError(command === undefined
7045
- ? "Task event command is required."
7046
- : `Unknown command: task event ${command}`);
7047
- }
7048
6725
  /**
7049
6726
  * Issue 13: native child durability visibility. A native Provider subagent is
7050
6727
  * best-effort until Yui persists its result content; once a continuation
@@ -7137,6 +6814,8 @@ function continuationReportEvents(events) {
7137
6814
  */
7138
6815
  function taskWakeDispatch(args, store, options) {
7139
6816
  const [subcommand] = args;
6817
+ if (subcommand === "retry")
6818
+ return taskWakeRetryCommand(args.slice(1), store, options);
7140
6819
  if (subcommand === "resolve") {
7141
6820
  const usage = "Task wake resolve usage: yui task wake resolve <task> <wake> --reason <quiescence-evidence>.";
7142
6821
  const parsed = parseTail(args.slice(1), new Set(["--reason"]), usage);
@@ -7176,13 +6855,15 @@ function taskWakeDispatch(args, store, options) {
7176
6855
  tx.saveWorkMailbox(completeProcessing(mailbox, claim.batchId));
7177
6856
  return { taskId: task.id, wakeId: wake.id, outcome: "released-without-replay" };
7178
6857
  });
7179
- notifyMailbox(options.runtime, leaderMailbox(result.taskId), result.taskId);
6858
+ notifyMailbox(options.runtime, leaderMailbox(result.taskId));
7180
6859
  return output(`Released ${result.wakeId} without replay; original acceptance remains unknown.\n`, result);
7181
6860
  }
7182
6861
  if (subcommand === "list" || subcommand === "show") {
7183
6862
  return taskWakeInspectionCommand(args, store);
7184
6863
  }
7185
- return output(taskWakeForceCommand(args, store, options));
6864
+ throw usageError(subcommand === undefined
6865
+ ? "Task wake command is required."
6866
+ : `Unknown command: task wake ${subcommand}`);
7186
6867
  }
7187
6868
  /**
7188
6869
  * Issue 04 (long-term): the durable wake ledger. `wake list` shows the
@@ -7205,13 +6886,11 @@ function taskWakeInspectionCommand(args, store) {
7205
6886
  { header: "Wake", minWidth: 8, maxWidth: 18 },
7206
6887
  { header: "Status", minWidth: 8, maxWidth: 12 },
7207
6888
  { header: "Reasons", minWidth: 10, maxWidth: 40 },
7208
- { header: "AgentRun", minWidth: 10, maxWidth: 20 },
7209
6889
  { header: "Dispatched", minWidth: 10, maxWidth: 28 }
7210
6890
  ], wakes.map((wake) => [
7211
6891
  wake.id,
7212
6892
  wake.status,
7213
6893
  wake.reasons.map(renderWakeReason).join(", "),
7214
- wake.runId ?? "-",
7215
6894
  presentTime(wake.createdAt, timeZone)
7216
6895
  ]), defaultTableWidth())}\n`, { taskId: task.id, wakes });
7217
6896
  }
@@ -7233,6 +6912,8 @@ function taskWakeInspectionCommand(args, store) {
7233
6912
  const deliveryEvents = allEvents.filter((event) => (event.type === "notification.delivery" || event.type === "notification.resolved")
7234
6913
  && (event.payload.wakeId === wake.id
7235
6914
  || event.payload.attemptId?.startsWith(`notification:${task.id}/${wake.id}/`)));
6915
+ const lastDelivery = deliveryEvents.at(-1);
6916
+ const currentClaim = store.getWorkMailbox(leaderMailbox(task.id))?.processing;
7236
6917
  const referenced = (type, id) => wake.refs?.some(ref => ref.type === type && ref.id === id
7237
6918
  && (!("taskId" in ref) || ref.taskId === task.id)) === true;
7238
6919
  const events = allEvents.filter((e) => inWindow(e.createdAt) || referenced("event", e.id));
@@ -7250,10 +6931,18 @@ function taskWakeInspectionCommand(args, store) {
7250
6931
  `Wake: ${wake.id}`,
7251
6932
  `Task: ${task.id}`,
7252
6933
  `Status: ${wake.status}`,
7253
- `Notification: ${deliveryEvents.at(-1)?.payload.outcome ?? "unobserved"}`,
6934
+ `Notification: ${lastDelivery?.payload.outcome ?? "unobserved"}`,
6935
+ ...(lastDelivery?.payload.detail === undefined ? [] : [`Failure: ${lastDelivery.payload.detail}`]),
6936
+ ...(lastDelivery?.payload.errorEventId === undefined ? [] : [
6937
+ `Failure record: ${task.id}/${lastDelivery.payload.errorEventId}`,
6938
+ `Inspect capabilities: ${failureCapabilitiesCommand(task.id, "leader", lastDelivery.payload.errorEventId)}`
6939
+ ]),
6940
+ ...(lastDelivery?.payload.outcome !== "rejected"
6941
+ || currentClaim?.batchId !== lastDelivery.payload.attemptId ? [] : [
6942
+ `Recovery: correct the cause, then yui task wake retry ${task.id} ${wake.id} --reason <correction>.`
6943
+ ]),
7254
6944
  `Reasons: ${wake.reasons.map(renderWakeReason).join(", ")}`,
7255
6945
  `Delta window: ${wake.fromCursor} → ${wake.toCursor}`,
7256
- ...(wake.runId === undefined ? [] : [`AgentRun: ${wake.runId}`]),
7257
6946
  `Dispatched: ${presentTime(wake.createdAt, timeZone)}`,
7258
6947
  ...(wake.consumedAt === undefined
7259
6948
  ? []
@@ -7282,130 +6971,13 @@ function taskWakeInspectionCommand(args, store) {
7282
6971
  ? "Task wake command is required."
7283
6972
  : `Unknown command: task wake ${command}`);
7284
6973
  }
7285
- function parseMultiValueTail(args, valueOptions, repeatOptions, usage, flagOptions = new Set()) {
7286
- const positionals = [];
7287
- const options = new Map();
7288
- const multiOptions = new Map();
7289
- for (let index = 0; index < args.length; index += 1) {
7290
- const value = args[index];
7291
- if (!value.startsWith("--")) {
7292
- positionals.push(value);
7293
- continue;
7294
- }
7295
- if (!valueOptions.has(value) && !repeatOptions.has(value) && !flagOptions.has(value)) {
7296
- throw usageError(`Unsupported option: ${value}.`, usage);
7297
- }
7298
- if (flagOptions.has(value)) {
7299
- if (options.has(value))
7300
- throw usageError(`Option may only be specified once: ${value}.`, usage);
7301
- options.set(value, "");
7302
- continue;
7303
- }
7304
- if (repeatOptions.has(value)) {
7305
- const optionValue = args[index + 1];
7306
- if (optionValue === undefined || optionValue.startsWith("--")) {
7307
- throw usageError(`${value} is required.`, usage);
7308
- }
7309
- const existing = multiOptions.get(value) ?? [];
7310
- multiOptions.set(value, [...existing, optionValue]);
7311
- index += 1;
7312
- continue;
7313
- }
7314
- if (options.has(value))
7315
- throw usageError(`Option may only be specified once: ${value}.`, usage);
7316
- const optionValue = args[index + 1];
7317
- if (optionValue === undefined || optionValue.startsWith("--")) {
7318
- throw usageError(`${value} is required.`, usage);
7319
- }
7320
- options.set(value, optionValue);
7321
- index += 1;
7322
- }
7323
- return { positionals, options, multiOptions };
7324
- }
7325
- function parseTail(args, valueOptions, usage, flagOptions = new Set()) {
7326
- const positionals = [];
7327
- const options = new Map();
7328
- for (let index = 0; index < args.length; index += 1) {
7329
- const value = args[index];
7330
- if (!value.startsWith("--")) {
7331
- positionals.push(value);
7332
- continue;
7333
- }
7334
- if (!valueOptions.has(value) && !flagOptions.has(value)) {
7335
- throw usageError(`Unsupported option: ${value}.`, usage);
7336
- }
7337
- if (options.has(value))
7338
- throw usageError(`Option may only be specified once: ${value}.`, usage);
7339
- if (flagOptions.has(value)) {
7340
- options.set(value, "");
7341
- continue;
7342
- }
7343
- const optionValue = args[index + 1];
7344
- if (optionValue === undefined || optionValue.startsWith("--")) {
7345
- throw usageError(`${value} is required.`, usage);
7346
- }
7347
- options.set(value, optionValue);
7348
- index += 1;
7349
- }
7350
- return { positionals, options };
7351
- }
7352
- function requiredOption(options, name) {
7353
- return requiredText(options.get(name), name);
7354
- }
7355
- function optionalNonEmptyOption(options, name) {
7356
- if (!options.has(name))
7357
- return undefined;
7358
- return requiredText(options.get(name), name);
7359
- }
7360
- function exactPositionals(values, count, usage) {
7361
- if (values.length !== count || values.some((value) => value.trim().length === 0)) {
7362
- throw usageError(usage);
7363
- }
7364
- }
7365
- function assertNoArguments(args, usage) {
7366
- if (args.length > 0)
7367
- throw usageError(usage);
7368
- }
7369
- function requiredText(value, label) {
7370
- const normalized = value?.trim();
7371
- if (normalized === undefined || normalized.length === 0)
7372
- throw usageError(`${label} is required.`);
7373
- return normalized;
7374
- }
7375
- function trimmed(value) {
7376
- const normalized = value?.trim();
7377
- return normalized === undefined || normalized.length === 0 ? undefined : normalized;
7378
- }
7379
6974
  function titleFrom(body) {
7380
6975
  const oneLine = requiredText(body, "Message body").replace(/\s+/g, " ");
7381
6976
  return oneLine.length <= 80 ? oneLine : `${oneLine.slice(0, 77)}...`;
7382
6977
  }
7383
- function presentTime(value, timeZone) {
7384
- return formatTimestamp(value, timeZone);
7385
- }
7386
- function output(value, data) {
7387
- return data === undefined
7388
- ? { kind: "output", output: value }
7389
- : { kind: "output", output: value, data };
7390
- }
7391
- function clock(options) {
7392
- return options.now?.() ?? new Date();
7393
- }
7394
6978
  function messageOf(error) {
7395
6979
  return error instanceof Error ? error.message : String(error);
7396
6980
  }
7397
- function taskMailbox(taskId) {
7398
- return { kind: "task", taskId };
7399
- }
7400
- function roleMailbox(taskId, roleName) {
7401
- return { kind: "role", taskId, roleName };
7402
- }
7403
- function leaderMailbox(taskId) {
7404
- return roleMailbox(taskId, LEADER_ROLE);
7405
- }
7406
- function taskRef(id) {
7407
- return { type: "task", id };
7408
- }
7409
6981
  function runRef(taskId, id) {
7410
6982
  return { type: "run", taskId, id };
7411
6983
  }
@@ -7418,14 +6990,3 @@ function messageRef(taskId, id) {
7418
6990
  function eventRef(taskId, id) {
7419
6991
  return { type: "event", taskId, id };
7420
6992
  }
7421
- function notifyMailbox(runtime, target, compatibilityTaskId) {
7422
- if (runtime?.notifyMailboxChanged !== undefined) {
7423
- runtime.notifyMailboxChanged(target);
7424
- }
7425
- else {
7426
- runtime?.notifyStateChanged(compatibilityTaskId);
7427
- }
7428
- }
7429
- function notifyReviewMailbox(_options, runtime, target, compatibilityTaskId) {
7430
- notifyMailbox(runtime, target, compatibilityTaskId);
7431
- }