@zq-silk/yui 0.15.7 → 0.15.9

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 (308) hide show
  1. package/ARCHITECTURE.md +194 -399
  2. package/ARCHITECTURE.zh-CN.md +151 -0
  3. package/README.md +306 -1131
  4. package/dist/agent/adapterCatalog.js +15 -2
  5. package/dist/agent/agent.js +23 -3
  6. package/dist/agent/argumentPolicy.js +7 -1
  7. package/dist/agent/connectionPlan.js +62 -0
  8. package/dist/agent/executionComponents.js +158 -0
  9. package/dist/agent/launchEnvironment.js +31 -3
  10. package/dist/agent/managedRuntimeEnvironment.js +3 -5
  11. package/dist/{turn/turn.js → agentRun/agentRun.js} +166 -109
  12. package/dist/{turn/turnIdentity.js → agentRun/runIdentity.js} +4 -4
  13. package/dist/artifacts/artifactCapability.js +74 -0
  14. package/dist/artifacts/artifactCommitLock.js +249 -0
  15. package/dist/artifacts/artifactPaths.js +151 -0
  16. package/dist/artifacts/gitArtifactRef.js +146 -0
  17. package/dist/artifacts/managedGit.js +332 -0
  18. package/dist/artifacts/taskArtifactRepository.js +277 -0
  19. package/dist/brief/taskBrief.js +12 -0
  20. package/dist/cli/agentConfigurationPicker.js +13 -0
  21. package/dist/cli/commandCatalog.js +165 -74
  22. package/dist/cli/interactionCandidates.js +5 -5
  23. package/dist/cli/interactionPolicy.js +38 -8
  24. package/dist/cli/invocationRouter.js +1 -1
  25. package/dist/cli/managedDiagnostics.js +28 -0
  26. package/dist/cli/operatorWizard.js +1 -7
  27. package/dist/cli/roleOptionOrder.js +27 -0
  28. package/dist/cli/roleWizard.js +50 -14
  29. package/dist/cli/updateOrchestrator.js +1 -1
  30. package/dist/cli/updatePorts.js +3 -4
  31. package/dist/cli.js +245 -95
  32. package/dist/commands/agentCommands.js +72 -14
  33. package/dist/commands/capabilityCommands.js +9 -6
  34. package/dist/commands/configCommands.js +20 -20
  35. package/dist/commands/deliveryGuardPreflight.js +2 -2
  36. package/dist/commands/executionAuditCommands.js +24 -24
  37. package/dist/commands/globalRoleCommands.js +1 -1
  38. package/dist/commands/grantCommands.js +4 -4
  39. package/dist/commands/operatorCommands.js +34 -9
  40. package/dist/commands/projectCommands.js +4 -4
  41. package/dist/commands/resourcesCommands.js +2 -2
  42. package/dist/commands/roleConfiguration.js +25 -5
  43. package/dist/commands/roleRuntimeGuard.js +4 -5
  44. package/dist/commands/sessionCommands.js +3 -7
  45. package/dist/commands/taskActivationCommands.js +281 -0
  46. package/dist/commands/taskActor.js +28 -49
  47. package/dist/commands/taskCommands.js +1461 -720
  48. package/dist/commands/taskContextCommand.js +39 -583
  49. package/dist/commands/taskExecutionCommands.js +32 -32
  50. package/dist/commands/taskInputCommands.js +40 -104
  51. package/dist/commands/taskIntegrationCommands.js +3 -2
  52. package/dist/commands/taskIntegrationQueueCommands.js +1 -1
  53. package/dist/commands/taskNextActionCommand.js +8 -8
  54. package/dist/commands/taskOverviewCommand.js +33 -45
  55. package/dist/commands/taskRemoteDeliveryCommand.js +2 -2
  56. package/dist/commands/taskRoleRuntimeStatus.js +133 -102
  57. package/dist/commands/telemetryCommands.js +36 -38
  58. package/dist/config/configCatalog.js +4 -4
  59. package/dist/config/yuiConfig.js +8 -8
  60. package/dist/context/contextSnapshot.js +10 -10
  61. package/dist/context/dispatchContext.js +11 -11
  62. package/dist/context/roleSessionContext.js +6 -3
  63. package/dist/context/{turnContextPack.js → runContextPack.js} +158 -81
  64. package/dist/context/{turnInputContract.js → runInputContract.js} +73 -60
  65. package/dist/context/sessionBootstrapManifest.js +21 -2
  66. package/dist/context/sourceRunContext.js +30 -0
  67. package/dist/context/taskContext.js +481 -0
  68. package/dist/context/wakeNotification.js +27 -27
  69. package/dist/controller/agentRuntimeObserver.js +21 -24
  70. package/dist/controller/capabilityBridge.js +17 -6
  71. package/dist/controller/clientRuntime.js +65 -92
  72. package/dist/controller/controller.js +120 -188
  73. package/dist/controller/fileSchedulerStoreAdapter.js +787 -887
  74. package/dist/controller/jobControl.js +54 -85
  75. package/dist/controller/resourceInventory.js +8 -27
  76. package/dist/controller/resourceInventoryLinux.js +12 -13
  77. package/dist/controller/runtime.js +529 -479
  78. package/dist/controller/runtimeEventInbox.js +55 -25
  79. package/dist/controller/runtimeEventProcessor.js +22 -31
  80. package/dist/controller/{runtimeHookTurnFence.js → runtimeHookRunFence.js} +91 -115
  81. package/dist/controller/runtimeLaunchCoordinator.js +80 -426
  82. package/dist/controller/runtimeObservationHook.js +14 -18
  83. package/dist/controller/sessionNotify.js +16 -24
  84. package/dist/controller/sessionOwnerReconciliation.js +168 -50
  85. package/dist/controller/structuredProviderObservation.js +138 -99
  86. package/dist/coordination/workMailbox.js +3 -3
  87. package/dist/coordination/workMailboxQueue.js +36 -33
  88. package/dist/core/boundedRpc.js +8 -1
  89. package/dist/core/controllerClient.js +20 -1
  90. package/dist/core/controllerServer.js +4 -4
  91. package/dist/doctor/doctor.js +13 -2
  92. package/dist/domain/agentResultTransport.js +9 -9
  93. package/dist/execution/codexThreadNaming.js +2 -8
  94. package/dist/execution/executionHealth.js +51 -63
  95. package/dist/execution/reviewMainRun.js +137 -0
  96. package/dist/execution/workItemExecution.js +28 -29
  97. package/dist/execution/workItemExecutionProjection.js +99 -107
  98. package/dist/execution/workItemMainRun.js +141 -0
  99. package/dist/executor/agentAdapter.js +227 -20
  100. package/dist/executor/agentConfigurationCatalog.js +126 -4
  101. package/dist/executor/agentConfigurationProbe.js +162 -4
  102. package/dist/executor/agentExecutor.js +79 -78
  103. package/dist/executor/effectiveLaunch.js +105 -18
  104. package/dist/executor/executorRegistry.js +29 -44
  105. package/dist/executor/fileRoleLaunchPlanner.js +229 -154
  106. package/dist/executor/workspacePreflightClassification.js +16 -16
  107. package/dist/grant/capabilityGrant.js +6 -3
  108. package/dist/input/inputRequest.js +12 -10
  109. package/dist/integration/gitIntegrationService.js +4 -11
  110. package/dist/integration/integrationQueueService.js +4 -4
  111. package/dist/interaction/operatorPresentation.js +1 -1
  112. package/dist/kernel/builtinCapabilities.js +255 -12
  113. package/dist/kernel/capabilityRegistry.js +64 -18
  114. package/dist/kernel/instanceHost.js +12 -1
  115. package/dist/kernel/kernelPorts.js +2 -2
  116. package/dist/lifecycle/canonicalLifecycleEvent.js +44 -49
  117. package/dist/lifecycle/exactRunTerminalization.js +449 -0
  118. package/dist/message/message.js +118 -6
  119. package/dist/message/messageContinuation.js +204 -0
  120. package/dist/observability/executionAudit.js +70 -72
  121. package/dist/observability/faultClassification.js +2 -2
  122. package/dist/observability/orchestrationMetrics.js +8 -8
  123. package/dist/operator/operatorSessionHistory.js +1 -7
  124. package/dist/output/agentConfigurationPresentation.js +8 -3
  125. package/dist/output/agentRunConfigurationPresentation.js +128 -0
  126. package/dist/output/rolePresentation.js +54 -3
  127. package/dist/plugins/pluginChild.js +104 -0
  128. package/dist/plugins/pluginIntent.js +26 -0
  129. package/dist/plugins/pluginInterpreter.js +43 -0
  130. package/dist/plugins/pluginPackage.js +101 -0
  131. package/dist/plugins/pluginProcess.js +112 -0
  132. package/dist/plugins/pluginService.js +388 -0
  133. package/dist/profile/agentProfile.js +1 -1
  134. package/dist/repository/gitWorkspace.js +26 -4
  135. package/dist/repository/project.js +19 -4
  136. package/dist/repository/taskBaseFreshness.js +13 -13
  137. package/dist/repository/taskWorkspaceCoordinator.js +20 -27
  138. package/dist/repository/taskWorkspacePreparer.js +344 -83
  139. package/dist/resources/autoResourceGc.js +3 -3
  140. package/dist/resources/liveReferences.js +3 -3
  141. package/dist/resources/projectResource.js +75 -0
  142. package/dist/resources/projectResourceService.js +343 -0
  143. package/dist/resources/resourceDiscovery.js +6 -6
  144. package/dist/resources/resourceGc.js +1 -1
  145. package/dist/resources/resourceRegistrar.js +1 -1
  146. package/dist/resources/resourceTypes.js +1 -1
  147. package/dist/review/deltaRecheck.js +3 -3
  148. package/dist/review/reviewAcceptance.js +16 -16
  149. package/dist/review/reviewDecision.js +7 -7
  150. package/dist/review/reviewRound.js +21 -20
  151. package/dist/review/reviewerAvailability.js +2 -2
  152. package/dist/role/role.js +51 -7
  153. package/dist/role/taskRoleUpdate.js +30 -0
  154. package/dist/runtime/acpProtocol.js +425 -0
  155. package/dist/runtime/acpSession.js +731 -0
  156. package/dist/runtime/acpSessionConfiguration.js +260 -0
  157. package/dist/runtime/agentDriver.js +30 -11
  158. package/dist/runtime/agentEndpoint.js +278 -0
  159. package/dist/runtime/agentEndpointIdentity.js +86 -0
  160. package/dist/runtime/agentEndpointOwnership.js +239 -0
  161. package/dist/runtime/agentError.js +2 -10
  162. package/dist/runtime/agentHost.js +565 -314
  163. package/dist/runtime/agentRunConfiguration.js +258 -0
  164. package/dist/runtime/builtinAgentDrivers.js +134 -18
  165. package/dist/runtime/builtinAgentErrorMappers.js +55 -3
  166. package/dist/runtime/builtinTranscriptUsage.js +1 -1
  167. package/dist/runtime/claude-process-owner +0 -0
  168. package/dist/runtime/codexAppServerRuntime.js +38 -30
  169. package/dist/runtime/codexInteractiveHost.js +41 -6
  170. package/dist/runtime/continuationManager.js +2 -6
  171. package/dist/runtime/executionEnvironment.js +30 -0
  172. package/dist/runtime/firstProgressAdvisory.js +11 -11
  173. package/dist/runtime/index.js +4 -3
  174. package/dist/runtime/jsonLineChannel.js +109 -0
  175. package/dist/runtime/launchBroker.js +91 -16
  176. package/dist/runtime/launchDiagnostics.js +2 -2
  177. package/dist/runtime/lifecycleReservation.js +10 -18
  178. package/dist/runtime/managedCaller.js +61 -17
  179. package/dist/runtime/nativeSessionControl.js +102 -0
  180. package/dist/runtime/ports.js +6 -21
  181. package/dist/runtime/processExitObservation.js +8 -7
  182. package/dist/runtime/promptEnvelope.js +17 -6
  183. package/dist/runtime/providerContinuation.js +3 -9
  184. package/dist/runtime/providerContinuationReconciliationService.js +4 -13
  185. package/dist/runtime/providerControl.js +2 -7
  186. package/dist/runtime/providerRuntimeIdentity.js +110 -222
  187. package/dist/runtime/providerRuntimeReconciler.js +5 -9
  188. package/dist/runtime/runtimeBinding.js +0 -1
  189. package/dist/runtime/runtimeContinuationProjection.js +4 -7
  190. package/dist/runtime/runtimeDeadlines.js +9 -0
  191. package/dist/runtime/runtimeHealthPolicy.js +1 -1
  192. package/dist/runtime/runtimeObservation.js +29 -65
  193. package/dist/runtime/runtimeProjection.js +43 -51
  194. package/dist/runtime/runtimeSessionCandidate.js +1 -3
  195. package/dist/runtime/sessionLaunchRequest.js +3 -7
  196. package/dist/runtime/sessionOwnerIdentity.js +7 -54
  197. package/dist/runtime/sessionOwnerRegistry.js +22 -17
  198. package/dist/runtime/sessionReconciliation.js +4 -8
  199. package/dist/runtime/sessionTerminationGuard.js +70 -259
  200. package/dist/runtime/sessionTokenMetrics.js +5 -16
  201. package/dist/runtime/structuredProviderHost.js +237 -117
  202. package/dist/runtime/taskRuntimeIsolation.js +39 -122
  203. package/dist/runtime/tmuxAdapters.js +39 -86
  204. package/dist/scheduler/activeRoleRunDelivery.js +354 -0
  205. package/dist/scheduler/leaderWakeupProcessor.js +75 -266
  206. package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
  207. package/dist/scheduler/ports.js +80 -9
  208. package/dist/scheduler/{roleTurnLiveness.js → roleRunLiveness.js} +26 -30
  209. package/dist/scheduler/{roleTurnStall.js → roleRunStall.js} +128 -139
  210. package/dist/scheduler/taskExecutionProjection.js +120 -124
  211. package/dist/scheduler/taskObservabilityProjection.js +29 -29
  212. package/dist/scheduler/taskWake.js +11 -4
  213. package/dist/scheduler/wakeReason.js +9 -1
  214. package/dist/setup/setupCommand.js +3 -7
  215. package/dist/storage/migrations/agentRunContract.js +159 -0
  216. package/dist/storage/migrations/artifactsToGit.js +338 -0
  217. package/dist/storage/migrations/removeRuntimeGeneration.js +207 -0
  218. package/dist/storage/migrations/submitIntent.js +126 -0
  219. package/dist/storage/sqliteSchema.js +467 -7
  220. package/dist/storage/sqliteStore.js +355 -220
  221. package/dist/storage/storageVersions.js +1 -1
  222. package/dist/storage/storeRpc.js +10 -5
  223. package/dist/storage/taskStore.js +13 -11
  224. package/dist/storage/upgrade/upgradeOrchestrator.js +5 -7
  225. package/dist/surface/surfaceContributions.js +102 -0
  226. package/dist/task/completionReadiness.js +32 -6
  227. package/dist/task/deliveryGuard.js +16 -16
  228. package/dist/task/draftPlan.js +72 -12
  229. package/dist/task/nextAction.js +144 -128
  230. package/dist/task/remoteDelivery.js +6 -6
  231. package/dist/task/task.js +184 -18
  232. package/dist/task/taskActivation.js +327 -0
  233. package/dist/task/taskActivationService.js +408 -0
  234. package/dist/task/taskRecordReference.js +5 -4
  235. package/dist/task/taskRecordRetirement.js +1 -1
  236. package/dist/task/taskSubmission.js +236 -0
  237. package/dist/telemetry/sqliteTelemetryStore.js +55 -68
  238. package/dist/telemetry/telemetryConfig.js +14 -14
  239. package/dist/telemetry/telemetryWiring.js +2 -2
  240. package/dist/web/assets/assetManifest.js +2 -0
  241. package/dist/web/assets/client/app.js +121 -20
  242. package/dist/web/assets/client/components.js +87 -54
  243. package/dist/web/assets/client/i18n.js +83 -41
  244. package/dist/web/assets/client/markdown.js +1 -1
  245. package/dist/web/assets/client/taskSurface.js +442 -0
  246. package/dist/web/assets/client/view.js +49 -44
  247. package/dist/web/assets/shell.js +1 -1
  248. package/dist/web/assets/styles/cards.js +22 -4
  249. package/dist/web/controllerWeb.js +60 -0
  250. package/dist/web/webMutation.js +28 -0
  251. package/dist/web/webServer.js +133 -8
  252. package/dist/web/webSnapshot.js +81 -74
  253. package/dist/web/webTaskSurface.js +64 -0
  254. package/dist/workItem/dependencyGate.js +1 -1
  255. package/dist/workItem/workItem.js +84 -48
  256. package/dist/workspace/workItemChangeSetManager.js +16 -9
  257. package/docs/agent-result-consumption.md +96 -0
  258. package/docs/agent-result-consumption.zh-CN.md +81 -0
  259. package/docs/agent-runtime-drivers.md +93 -0
  260. package/docs/agent-runtime-drivers.zh-CN.md +77 -0
  261. package/docs/architecture/README.md +50 -0
  262. package/docs/architecture/README.zh-CN.md +43 -0
  263. package/docs/architecture/capabilities-and-resources.md +118 -0
  264. package/docs/architecture/capabilities-and-resources.zh-CN.md +83 -0
  265. package/docs/managed-turn-and-session-runtime.md +224 -0
  266. package/docs/managed-turn-and-session-runtime.zh-CN.md +180 -0
  267. package/docs/observability/README.md +83 -0
  268. package/docs/observability/README.zh-CN.md +71 -0
  269. package/docs/plugin-sdk.md +393 -0
  270. package/docs/plugin-sdk.zh-CN.md +293 -0
  271. package/docs/provider-runtime.md +165 -0
  272. package/docs/provider-runtime.zh-CN.md +132 -0
  273. package/docs/release-workflow.md +305 -0
  274. package/docs/release-workflow.zh-CN.md +237 -0
  275. package/docs/roles-and-configuration.md +115 -0
  276. package/docs/roles-and-configuration.zh-CN.md +96 -0
  277. package/docs/sqlite-control-plane-design.md +78 -0
  278. package/docs/sqlite-control-plane-design.zh-CN.md +62 -0
  279. package/docs/task-dag-semantics.md +80 -0
  280. package/docs/task-dag-semantics.zh-CN.md +59 -0
  281. package/docs/task-delivery.md +105 -0
  282. package/docs/task-delivery.zh-CN.md +82 -0
  283. package/docs/task-local-identity.md +8 -6
  284. package/docs/task-local-identity.zh-CN.md +58 -0
  285. package/docs/testing/verification-levels.md +88 -0
  286. package/docs/testing/verification-levels.zh-CN.md +69 -0
  287. package/i18n/README.zh-CN.md +270 -722
  288. package/package.json +3 -2
  289. package/skills/yui-leader/SKILL.md +88 -304
  290. package/skills/yui-leader/references/execution.md +303 -0
  291. package/skills/yui-leader/references/integration.md +39 -0
  292. package/skills/yui-leader/references/planning.md +109 -0
  293. package/skills/yui-leader/references/replicated-execution.md +42 -0
  294. package/skills/yui-leader/references/task-plugins.md +37 -0
  295. package/skills/yui-operator/SKILL.md +46 -62
  296. package/skills/yui-reviewer/SKILL.md +35 -36
  297. package/skills/yui-runtime/SKILL.md +88 -24
  298. package/skills/yui-runtime/references/publication.md +22 -0
  299. package/skills/yui-runtime/references/recovery.md +64 -0
  300. package/skills/yui-worker/SKILL.md +37 -39
  301. package/dist/cli/roleOptionCatalog.js +0 -68
  302. package/dist/context/sourceTurnContext.js +0 -30
  303. package/dist/execution/reviewMainTurn.js +0 -161
  304. package/dist/execution/workItemMainTurn.js +0 -164
  305. package/dist/lifecycle/exactTurnTerminalization.js +0 -407
  306. package/dist/runtime/preallocatedNativeSession.js +0 -13
  307. package/dist/runtime/runtimeStopReceipt.js +0 -42
  308. package/dist/scheduler/activeRoleTurnDelivery.js +0 -315
@@ -0,0 +1,408 @@
1
+ import { createTaskEvent } from "../event/taskEvent.js";
2
+ import { enqueueWork } from "../coordination/workMailboxQueue.js";
3
+ import { createProjectResources } from "../resources/projectResourceService.js";
4
+ import { admitTaskActivationRequest, adoptTaskActivationRequest, cancelTaskActivationRequest, canonicalEnvironmentPlan, createTaskActivationRequest, describeEnvironmentPlan, failTaskActivationRequest, settledActivationFromEvents, taskActivationInputDigest, TASK_ACTIVATION_EVENT } from "./taskActivation.js";
5
+ import { setTaskActivationRequest, recordTaskActivationRequestEvidence } from "./task.js";
6
+ /**
7
+ * The terminal outcome already recorded for a requestId, or `undefined` if it
8
+ * was never cancelled or adopted.
9
+ *
10
+ * The authority is the durable activation event ledger, which is never
11
+ * compacted, so a decided outcome survives the bounded display payload evicting
12
+ * its record. The live slot is consulted first only as a fast path for the id
13
+ * that still occupies it; the two always agree, because every terminal
14
+ * transition writes its event in the same transaction that mutates the slot.
15
+ */
16
+ function settledActivationRequest(reader, task, requestId) {
17
+ const current = task.activationRequest;
18
+ if (current?.operation.requestId === requestId
19
+ && (current.disposition === "cancelled" || current.disposition === "adopted")) {
20
+ return {
21
+ disposition: current.disposition,
22
+ ...(current.outcome === undefined ? {} : { outcome: current.outcome })
23
+ };
24
+ }
25
+ return settledActivationFromEvents(reader.listEvents(task.id), requestId);
26
+ }
27
+ export function taskActivationOperationRef(taskId, requestId) {
28
+ return `task-activation:${taskId}/${requestId}`;
29
+ }
30
+ /**
31
+ * Records an explicit activation request and returns its operation reference.
32
+ *
33
+ * This never prepares resources and never waits. When the caller is the Task's
34
+ * own running planning Turn, the request is stored with `afterPlanningRun` set
35
+ * to that Turn — expressing the deferral in the same operation facts the
36
+ * request already carries, rather than blocking a synchronous tool on the Turn
37
+ * it is running inside (S40).
38
+ *
39
+ * A repeated requestId with the same inputs returns the existing request
40
+ * unchanged, so a retried tool call cannot produce a second activation.
41
+ */
42
+ export function requestTaskActivation(store, input, now) {
43
+ return store.transaction((tx) => recordTaskActivationRequestInTransaction(tx, input, now));
44
+ }
45
+ /**
46
+ * The transactional core of {@link requestTaskActivation}, callable from inside
47
+ * a caller's own open transaction.
48
+ *
49
+ * The shared submission service (task-32 §2.3) records a develop route's
50
+ * activation request in the very transaction that saves the message, so the
51
+ * message and its activation intent commit together and no "submit then
52
+ * activate" two-command window exists. It reuses this exact logic rather than a
53
+ * second activation queue: the same idempotency, settled-id refusal and
54
+ * pending-collision rules apply whether the request arrives from the explicit
55
+ * boundary or from a develop submission. The caller owns transaction lifetime
56
+ * and any post-commit mailbox notification.
57
+ */
58
+ export function recordTaskActivationRequestInTransaction(tx, input, now) {
59
+ const task = requireOpenDraft(tx, input.taskId);
60
+ const plan = canonicalEnvironmentPlan(input.environmentPlan);
61
+ const planningRun = resolveCallerPlanningRun(tx, task.id, input.callerRunId);
62
+ const startMode = planningRun === undefined
63
+ ? "immediate"
64
+ : "after-planning-turn";
65
+ const existing = task.activationRequest;
66
+ // A requestId whose outcome was already decided is never re-opened, whether
67
+ // it still holds the slot or a later request displaced it. Cancelling A,
68
+ // requesting B and then retrying A must not resurrect A: the withdrawal is
69
+ // explicit authority, and adoption is exactly the effect it withdrew. An
70
+ // adopted id is equally final — its environment and status change happened.
71
+ // Only `failed` stays replayable, which is its documented contract.
72
+ //
73
+ // The authority is the durable activation event ledger, not the bounded
74
+ // display payload: the payload trims its oldest entries once it overflows,
75
+ // but the terminal events are never compacted, so an evicted cancellation is
76
+ // still refused with its original outcome instead of silently resurrecting.
77
+ const settled = settledActivationRequest(tx, task, input.requestId);
78
+ if (settled !== undefined) {
79
+ throw new Error(`Activation request ${input.requestId} was already ${settled.disposition} for ${task.id}`
80
+ + `${settled.outcome === undefined ? "" : ` (${settled.outcome})`}. `
81
+ + "Use a new requestId.");
82
+ }
83
+ if (existing?.operation.requestId === input.requestId) {
84
+ const digest = taskActivationInputDigest(task.id, {
85
+ startMode,
86
+ ...(planningRun === undefined ? {} : { afterPlanningRun: planningRun }),
87
+ environmentPlan: plan
88
+ });
89
+ if (existing.operation.inputDigest !== digest) {
90
+ throw new Error(`Activation requestId ${input.requestId} was already used for different inputs.`);
91
+ }
92
+ return {
93
+ operationRef: taskActivationOperationRef(task.id, existing.operation.requestId),
94
+ request: existing,
95
+ startMode: existing.startMode,
96
+ created: false,
97
+ ...(existing.afterPlanningRun === undefined
98
+ ? {}
99
+ : { afterPlanningRun: existing.afterPlanningRun })
100
+ };
101
+ }
102
+ if (existing?.disposition === "pending") {
103
+ throw new Error(`Task already has a pending activation request: ${task.id}/${existing.operation.requestId}. `
104
+ + "Cancel it before requesting different inputs.");
105
+ }
106
+ const request = createTaskActivationRequest(task.id, {
107
+ requestId: input.requestId,
108
+ actorId: input.actorId,
109
+ authorityRef: input.authorityRef,
110
+ startMode,
111
+ ...(input.origin === undefined ? {} : { origin: input.origin }),
112
+ ...(planningRun === undefined ? {} : { afterPlanningRun: planningRun }),
113
+ environmentPlan: plan
114
+ }, now);
115
+ tx.saveTask(setTaskActivationRequest(task, request, now));
116
+ tx.saveEvent(task.id, createTaskEvent(tx.nextEventId(task.id), task.id, TASK_ACTIVATION_EVENT.requested, {
117
+ requestId: request.operation.requestId,
118
+ startMode: request.startMode,
119
+ environmentPlan: describeEnvironmentPlan(request.environmentPlan),
120
+ actor: request.operation.actorId,
121
+ ...(request.origin === undefined ? {} : { origin: request.origin }),
122
+ ...(request.afterPlanningRun === undefined
123
+ ? {}
124
+ : { afterPlanningRun: request.afterPlanningRun })
125
+ }, now));
126
+ return {
127
+ operationRef: taskActivationOperationRef(task.id, request.operation.requestId),
128
+ request,
129
+ startMode,
130
+ created: true,
131
+ ...(planningRun === undefined ? {} : { afterPlanningRun: planningRun })
132
+ };
133
+ }
134
+ /** Explicit user or Operator cancellation. A cancelled request never adopts. */
135
+ export function cancelTaskActivation(store, taskId, requestId, reason, now) {
136
+ return store.transaction((tx) => {
137
+ const task = tx.getTask(taskId);
138
+ if (task === null)
139
+ throw new Error(`Task not found: ${taskId}.`);
140
+ const existing = task.activationRequest;
141
+ if (existing === undefined || existing.operation.requestId !== requestId) {
142
+ throw new Error(`Activation request not found: ${taskId}/${requestId}.`);
143
+ }
144
+ if (existing.disposition === "adopted") {
145
+ throw new Error(`Activation ${requestId} was already adopted for ${taskId}; its environment and active `
146
+ + "status are established facts. Stop execution or retire the Task instead.");
147
+ }
148
+ const cancelled = cancelTaskActivationRequest(existing, reason, now);
149
+ if (cancelled !== existing) {
150
+ tx.saveTask(setTaskActivationRequest(task, cancelled, now));
151
+ tx.saveEvent(taskId, createTaskEvent(tx.nextEventId(taskId), taskId, TASK_ACTIVATION_EVENT.cancelled, { requestId, reason: cancelled.outcome ?? reason }, now));
152
+ }
153
+ return cancelled;
154
+ });
155
+ }
156
+ /**
157
+ * Re-reads the stored request and decides whether it may be adopted now.
158
+ *
159
+ * Called immediately before the adoption boundary, so a Task retired, stopped,
160
+ * or a request cancelled while the planning Turn was still running is caught
161
+ * here rather than replayed as historical intent.
162
+ */
163
+ export function admitStoredTaskActivation(store, taskId) {
164
+ const task = store.getTask(taskId);
165
+ if (task === null)
166
+ throw new Error(`Task not found: ${taskId}.`);
167
+ const admission = admitTaskActivationRequest(task, task.activationRequest, (runId) => store.getRun(taskId, runId)?.status === "active");
168
+ if (admission === undefined)
169
+ return { disposition: "absent" };
170
+ return admission.disposition === "ready"
171
+ ? {
172
+ disposition: "ready",
173
+ request: admission.request,
174
+ plan: admission.request.environmentPlan
175
+ }
176
+ : admission;
177
+ }
178
+ /**
179
+ * Prepares and adopts the request's resource configuration.
180
+ *
181
+ * An empty plan is legal and adopts nothing physical. On failure the request is
182
+ * recorded as failed, the Task remains a continuable Draft, and only resources
183
+ * this call can confirm were never adopted are released — a prepared-but-not
184
+ * adopted scratch directory. Anything whose disposition cannot be proven is
185
+ * retained for its owner to inspect and reported as a `possible` effect.
186
+ *
187
+ * A successful adoption is recorded on the request immediately, against its own
188
+ * requestId. The resources are adopted the moment `adopt` commits, so the effect
189
+ * cannot wait for the Task-status transaction: a cancel or a replacement landing
190
+ * in between must not be able to leave an adopted environment described as
191
+ * `none`, nor attach it to whichever request now holds the slot.
192
+ */
193
+ export function adoptTaskActivationResources(store, taskId, now = () => new Date()) {
194
+ const admission = admitStoredTaskActivation(store, taskId);
195
+ if (admission.disposition !== "ready") {
196
+ throw new Error(`Task activation is not adoptable: ${taskId}/${admission.disposition}`
197
+ + (admission.disposition === "unavailable" ? ` (${admission.reason})` : "")
198
+ + ".");
199
+ }
200
+ const resources = createProjectResources(store, now);
201
+ const plan = admission.plan;
202
+ const requestId = admission.request.operation.requestId;
203
+ if (plan.kind === "empty") {
204
+ // An empty plan owns no physical environment. Nothing is prepared, so
205
+ // nothing can be left half-adopted, and no worktree is created to satisfy
206
+ // the framework's own model.
207
+ return { request: admission.request };
208
+ }
209
+ let prepared;
210
+ try {
211
+ prepared = resources.prepare(taskId, plan);
212
+ const adopted = resources.adopt(taskId, prepared.id);
213
+ // The environment is adopted now. Persist that as a confirmed effect of this
214
+ // requestId before returning, so a cancellation or replacement that races
215
+ // the rest of activation still finds the truth on the request that caused it.
216
+ return {
217
+ request: recordTaskActivationResourceEffect(store, taskId, requestId, adopted.id, now()),
218
+ preparation: adopted
219
+ };
220
+ }
221
+ catch (error) {
222
+ const message = error instanceof Error ? error.message : String(error);
223
+ const released = releaseUnadoptedPreparation(store, taskId, prepared, now);
224
+ recordFailedTaskActivation(store, taskId, admission.request, message, {
225
+ // Preparation that could not be confirmed unadopted is retained, and its
226
+ // possible effect is recorded rather than erased.
227
+ effect: prepared === undefined ? "none" : released ? "none" : "possible",
228
+ ...(prepared === undefined ? {} : { partialResultRefs: [`${taskId}/${prepared.id}`] })
229
+ }, now());
230
+ throw error;
231
+ }
232
+ }
233
+ /**
234
+ * Attaches the adopted environment to the exact request that adopted it.
235
+ *
236
+ * The request keeps its `pending` disposition: resources are adopted, the Task
237
+ * is not active yet, and only the activation transaction may say otherwise. The
238
+ * effect and the preparation ref are recorded by id, so they stay with this
239
+ * request even if it loses the slot before activation completes.
240
+ */
241
+ function recordTaskActivationResourceEffect(store, taskId, requestId, preparationId, now) {
242
+ return store.transaction((tx) => {
243
+ const task = tx.getTask(taskId);
244
+ if (task === null)
245
+ throw new Error(`Task not found: ${taskId}.`);
246
+ const updated = recordTaskActivationRequestEvidence(task, requestId, {
247
+ effect: "confirmed",
248
+ partialResultRefs: [`${taskId}/${preparationId}`]
249
+ }, now);
250
+ tx.saveTask(updated);
251
+ const request = updated.activationRequest?.operation.requestId === requestId
252
+ ? updated.activationRequest
253
+ : updated.settledActivationRequests?.find(({ operation }) => operation.requestId === requestId);
254
+ if (request === undefined) {
255
+ throw new Error(`Activation request disappeared while adopting it: ${taskId}/${requestId}.`);
256
+ }
257
+ return request;
258
+ });
259
+ }
260
+ /**
261
+ * Records the adopted request inside the caller's activation transaction, so
262
+ * the confirmed operation effect commits with the Task's active status and its
263
+ * environment facts. A later launch failure is reported separately and never
264
+ * rewrites this record.
265
+ *
266
+ * `expected` is the request identity resource adoption actually ran for. It is
267
+ * re-checked here because the slot can change while the workspace is being
268
+ * prepared: a cancelled or replaced request must fail this transaction rather
269
+ * than have someone else's preparation recorded against it. The plan is compared
270
+ * too, so an `empty` request can never inherit a directory it never asked for.
271
+ *
272
+ * Recording a `preparationId` therefore requires `expected`: a preparation only
273
+ * exists because some specific request produced it, so naming one without saying
274
+ * which request it belongs to is never a legal call. It stays optional only for
275
+ * the no-preparation case, where there is no environment to misattribute.
276
+ */
277
+ export function recordAdoptedTaskActivation(store, task, evidence, now) {
278
+ const existing = task.activationRequest;
279
+ if (existing === undefined)
280
+ return task;
281
+ const expected = evidence.expected;
282
+ if (expected === undefined && evidence.preparationId !== undefined) {
283
+ throw new Error(`Activation adoption must name the request its preparation belongs to: `
284
+ + `${task.id}/${evidence.preparationId}.`);
285
+ }
286
+ if (expected !== undefined) {
287
+ if (existing.operation.requestId !== expected.operation.requestId) {
288
+ throw new Error(`Activation request changed while activating ${task.id}: prepared `
289
+ + `${expected.operation.requestId}, found ${existing.operation.requestId}.`);
290
+ }
291
+ if (existing.operation.inputDigest !== expected.operation.inputDigest) {
292
+ throw new Error(`Activation request inputs changed while activating ${task.id}: `
293
+ + `${existing.operation.requestId}.`);
294
+ }
295
+ if (existing.disposition !== "pending" && existing.disposition !== "adopted") {
296
+ throw new Error(`Activation request is no longer adoptable for ${task.id}: `
297
+ + `${existing.operation.requestId}/${existing.disposition}`
298
+ + `${existing.outcome === undefined ? "" : ` (${existing.outcome})`}.`);
299
+ }
300
+ }
301
+ const adopted = adoptTaskActivationRequest(existing, {
302
+ ...(evidence.preparationId === undefined
303
+ ? {}
304
+ : { preparationId: evidence.preparationId }),
305
+ receiptRefs: [taskActivationOperationRef(task.id, existing.operation.requestId)]
306
+ }, now);
307
+ store.saveEvent(task.id, createTaskEvent(store.nextEventId(task.id), task.id, TASK_ACTIVATION_EVENT.adopted, {
308
+ requestId: adopted.operation.requestId,
309
+ environmentPlan: describeEnvironmentPlan(adopted.environmentPlan),
310
+ ...(adopted.preparationId === undefined
311
+ ? {}
312
+ : { preparationId: adopted.preparationId })
313
+ }, now));
314
+ return setTaskActivationRequest(task, adopted, now);
315
+ }
316
+ /**
317
+ * Records that an activation attempt did not adopt. The Task is untouched: it
318
+ * stays a Draft the Leader can keep planning in, with the real preparation
319
+ * evidence preserved.
320
+ */
321
+ export function recordFailedTaskActivation(store, taskId, request, outcome, evidence, now) {
322
+ return store.transaction((tx) => {
323
+ const task = tx.getTask(taskId);
324
+ if (task === null)
325
+ throw new Error(`Task not found: ${taskId}.`);
326
+ const current = task.activationRequest;
327
+ if (current === undefined
328
+ || current.operation.requestId !== request.operation.requestId
329
+ || current.disposition === "adopted"
330
+ || current.disposition === "cancelled") {
331
+ return current ?? request;
332
+ }
333
+ const failed = failTaskActivationRequest(current, outcome, now, evidence);
334
+ tx.saveTask(setTaskActivationRequest(task, failed, now));
335
+ tx.saveEvent(taskId, createTaskEvent(tx.nextEventId(taskId), taskId, TASK_ACTIVATION_EVENT.failed, {
336
+ requestId: failed.operation.requestId,
337
+ outcome: failed.outcome ?? outcome,
338
+ effect: failed.operation.effect
339
+ }, now));
340
+ if (task.status === "draft") {
341
+ // This is a Core operation result, not a Leader-local planning edit.
342
+ // The Leader must learn the failed disposition and choose a legal next
343
+ // action; merely stopping automatic retries would otherwise strand it.
344
+ enqueueWork(tx, { kind: "role", taskId, roleName: "leader" }, "activation-failed", now, [{ type: "task", id: taskId }]);
345
+ }
346
+ return failed;
347
+ });
348
+ }
349
+ /**
350
+ * Releases a preparation only when this process can confirm it was never
351
+ * adopted. Returns false when the disposition is unprovable or release itself
352
+ * failed, so the caller records a `possible` effect instead of claiming the
353
+ * resource is clean.
354
+ */
355
+ function releaseUnadoptedPreparation(store, taskId, prepared, now) {
356
+ if (prepared === undefined)
357
+ return true;
358
+ const current = store.getEnvironmentPreparation(taskId, prepared.id);
359
+ if (current === null)
360
+ return false;
361
+ if (current.disposition === "released")
362
+ return true;
363
+ if (current.disposition !== "prepared")
364
+ return false;
365
+ try {
366
+ createProjectResources(store, now).release(taskId, prepared.id);
367
+ return true;
368
+ }
369
+ catch {
370
+ // The directory is retained for its owner to inspect. Never force-remove
371
+ // an environment whose contents or use cannot be proven.
372
+ return false;
373
+ }
374
+ }
375
+ function requireOpenDraft(store, taskId) {
376
+ const task = store.getTask(taskId);
377
+ if (task === null)
378
+ throw new Error(`Task not found: ${taskId}.`);
379
+ if (task.status !== "draft") {
380
+ throw new Error(`Only a Draft Task can request activation: ${taskId}/${task.status}.`);
381
+ }
382
+ if (task.executionGate.state !== "enabled") {
383
+ throw new Error(`Task execution is stopped: ${taskId}.`);
384
+ }
385
+ return task;
386
+ }
387
+ /**
388
+ * Resolves the caller's own planning Turn, which is what turns this request
389
+ * into a deferred one. Any other Turn id is rejected rather than silently
390
+ * treated as immediate: a caller that names a Turn is asserting it runs inside
391
+ * it, and a wrong assertion must not quietly change the start mode.
392
+ */
393
+ function resolveCallerPlanningRun(store, taskId, callerRunId) {
394
+ if (callerRunId === undefined)
395
+ return undefined;
396
+ const run = store.getRun(taskId, callerRunId);
397
+ if (run === null)
398
+ throw new Error(`AgentRun not found: ${taskId}/${callerRunId}.`);
399
+ if (run.purpose !== "planning") {
400
+ throw new Error(`Activation deferral requires a planning AgentRun: ${taskId}/${callerRunId}/${run.purpose}.`);
401
+ }
402
+ if (run.status !== "active") {
403
+ // A terminated planning Turn no longer needs deferral; the request is
404
+ // adoptable now and says so, rather than waiting for a finished Turn.
405
+ return undefined;
406
+ }
407
+ return run.id;
408
+ }
@@ -2,7 +2,7 @@ import { requireIdentity } from "../domain/validation.js";
2
2
  export const TASK_RECORD_ID_PREFIXES = {
3
3
  workItem: "work-item",
4
4
  contextSnapshot: "context-snapshot",
5
- turn: "turn",
5
+ run: "run",
6
6
  reviewRound: "review-round",
7
7
  changeSet: "change-set",
8
8
  integrationAttempt: "integration",
@@ -22,8 +22,8 @@ export function formatTaskRecordReference(taskId, localId, kind) {
22
22
  const reference = validateTaskRecordReference({ taskId, localId }, kind);
23
23
  return `${reference.taskId}/${reference.localId}`;
24
24
  }
25
- export function formatTurnReceiptId(taskId, turnId) {
26
- return `turn:${formatTaskRecordReference(taskId, turnId, "turn")}`;
25
+ export function formatRunReceiptId(taskId, runId) {
26
+ return `turn:${formatTaskRecordReference(taskId, runId, "run")}`;
27
27
  }
28
28
  export function formatInputRequestReceiptId(taskId, requestId) {
29
29
  return `input-request:${formatTaskRecordReference(taskId, requestId, "inputRequest")}`;
@@ -54,7 +54,8 @@ export function resolveTaskRecordReference(value, options) {
54
54
  export function validateTaskRecordReference(value, kind) {
55
55
  const taskId = requireIdentity(value.taskId, "Task id");
56
56
  const localId = requireIdentity(value.localId, `${TASK_RECORD_ID_PREFIXES[kind]} local id`);
57
- const match = new RegExp(`^${TASK_RECORD_ID_PREFIXES[kind]}-([1-9]\\d*)$`).exec(localId);
57
+ const prefix = kind === "run" ? "(?:run|turn)" : TASK_RECORD_ID_PREFIXES[kind];
58
+ const match = new RegExp(`^${prefix}-([1-9]\\d*)$`).exec(localId);
58
59
  if (match === null || !Number.isSafeInteger(Number(match[1]))) {
59
60
  throw new Error(`${TASK_RECORD_ID_PREFIXES[kind]} local id is invalid: ${localId}.`);
60
61
  }
@@ -3,7 +3,7 @@ export const TASK_RECORD_RETIRED_EVENT = "task.record-retired";
3
3
  export const RETIRABLE_TASK_RECORD_KINDS = [
4
4
  "work-item",
5
5
  "message",
6
- "turn"
6
+ "run"
7
7
  ];
8
8
  /**
9
9
  * Appends a tombstone fact without rewriting the original record. Operational