@zq-silk/yui 0.15.7 → 0.15.8

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