@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,30 +1,30 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
2
  import { chmodSync, mkdirSync, rmSync } from "node:fs";
3
- import { tmpdir, homedir } from "node:os";
4
- import { dirname, join, resolve } from "node:path";
5
3
  import { createConnection, createServer } from "node:net";
4
+ import { homedir, tmpdir } from "node:os";
5
+ import { dirname, join, resolve } from "node:path";
6
6
  import { createInterface } from "node:readline";
7
7
  import { withSessionContextPointer } from "../context/sessionBootstrapManifest.js";
8
+ import { publishStructuredConversationRecoverability, publishStructuredProviderAccepted, publishStructuredProviderActivity, publishStructuredProviderAttachmentExit, publishStructuredProviderConnection, publishStructuredProviderGoal, publishStructuredProviderInputObserved, publishStructuredProviderInputSettlement, publishStructuredProviderOpened, publishStructuredProviderStarted, publishStructuredProviderTerminal, structuredProviderEventDelivery } from "../controller/structuredProviderObservation.js";
8
9
  import { callController, controllerCallMayHaveApplied, ControllerClientError } from "../core/controllerClient.js";
9
10
  import { readHomeFilesystemId } from "../core/homeFilesystemIdentity.js";
11
+ import { FILE_TASK_CONTROLLER_PROTOCOL_VERSION } from "../core/protocol.js";
10
12
  import { isForeignHandoverLockHeld } from "../release/runtimeRelease.js";
11
- import { publishStructuredProviderAccepted, publishStructuredProviderAttachmentExit, publishStructuredProviderActivity, publishStructuredProviderInputSettlement, publishStructuredProviderInputObserved, publishStructuredProviderGoal, publishStructuredConversationRecoverability, publishStructuredProviderOpened, publishStructuredProviderStarted, publishStructuredProviderTerminal, publishStructuredProviderConnection, structuredProviderEventDelivery } from "../controller/structuredProviderObservation.js";
12
- import { validateAgentHostLaunchPayload } from "./launchBroker.js";
13
- import { ProviderDeliveryUnknownError, ProviderConversationMissingError, ProviderTurnBusyError, ProviderTurnRejectedError } from "./structuredProviderHost.js";
13
+ import { yuiTmuxServerName, yuiTmuxSessionName } from "../tmux/tmuxManager.js";
14
+ import { tmuxSocketDirectory } from "../tmux/tmuxSocketEndpoint.js";
14
15
  import { createAgentEndpointOwner } from "./agentEndpointOwnership.js";
15
- import { sameProviderAuthorityFence, validateProviderAuthorityFence } from "./providerAuthorityFence.js";
16
+ import { providerDeliveryFailure, providerDeliveryFailureFrom, redactAgentErrorText, serializeAgentErrorRaw } from "./agentError.js";
17
+ import { AGENT_HOST_CONTROL_PROTOCOL, AGENT_HOST_EVENT_PROTOCOL } from "./agentHostProtocol.js";
18
+ import { readAgentRunConfigurationObservation, unknownAgentRunConfiguration } from "./agentRunConfiguration.js";
19
+ import { CodexPreSubmissionError } from "./codexAppServerRuntime.js";
20
+ import { runCodexInteractiveHost } from "./codexInteractiveHost.js";
21
+ import { validateAgentHostLaunchPayload } from "./launchBroker.js";
16
22
  import { validateRuntimeProcessExitObservation } from "./processExitObservation.js";
17
23
  import { persistRuntimeProcessExitObservation, replayRuntimeProcessExitOutbox } from "./processExitOutbox.js";
24
+ import { sameProviderAuthorityFence, validateProviderAuthorityFence } from "./providerAuthorityFence.js";
25
+ import { ProviderConversationMissingError, ProviderDeliveryUnknownError, ProviderTurnBusyError, ProviderTurnRejectedError } from "./providerErrors.js";
18
26
  import { AGENT_HOST_CLIENT_EXIT_GRACE_MS, AGENT_HOST_CONTROL_TIMEOUT_MS, AGENT_HOST_READY_TIMEOUT_MS, ENDPOINT_DRAIN_TIMEOUT_MS, PROVIDER_ACCEPT_TIMEOUT_MS } from "./runtimeDeadlines.js";
19
- import { providerDeliveryFailure, providerDeliveryFailureFrom, redactAgentErrorText, serializeAgentErrorRaw } from "./agentError.js";
20
- import { runCodexInteractiveHost } from "./codexInteractiveHost.js";
21
- import { CodexPreSubmissionError } from "./codexAppServerRuntime.js";
22
- import { readAgentRunConfigurationObservation, unknownAgentRunConfiguration } from "./agentRunConfiguration.js";
23
27
  import { createSessionOwnerIdentity, readLinuxProcessIdentity } from "./sessionOwnerIdentity.js";
24
- import { yuiTmuxServerName, yuiTmuxSessionName } from "../tmux/tmuxManager.js";
25
- import { tmuxSocketDirectory } from "../tmux/tmuxSocketEndpoint.js";
26
- import { AGENT_HOST_CONTROL_PROTOCOL, AGENT_HOST_EVENT_PROTOCOL } from "./agentHostProtocol.js";
27
- import { FILE_TASK_CONTROLLER_PROTOCOL_VERSION } from "../core/protocol.js";
28
28
  export { AGENT_HOST_CONTROL_PROTOCOL } from "./agentHostProtocol.js";
29
29
  const HOST_CONTROL_MAX_BYTES = 32 * 1024;
30
30
  const CODEX_CLIENT_STABLE_MS = 5_000;
@@ -77,7 +77,7 @@ export async function runAgentHost(input) {
77
77
  if (payload.environment.YUI_SESSION_SCOPE === "global"
78
78
  && payload.environment.YUI_ADAPTER_ID === "codex"
79
79
  && payload.providerControl === undefined) {
80
- return runCodexInteractiveHost(input.home, payload);
80
+ return runCodexInteractiveHost(input.home, payload, openAgentHostControl);
81
81
  }
82
82
  let session;
83
83
  // This process really holds the Endpoint code its Session runs on. The lease
@@ -2,7 +2,7 @@ import { spawn } from "node:child_process";
2
2
  import { randomBytes } from "node:crypto";
3
3
  import { once } from "node:events";
4
4
  import WebSocket, { WebSocketServer } from "ws";
5
- import { AGENT_HOST_CONTROL_PROTOCOL, openAgentHostControl } from "./agentHost.js";
5
+ import { AGENT_HOST_CONTROL_PROTOCOL } from "./agentHostProtocol.js";
6
6
  import { openCodexInteractiveConnection } from "./structuredProviderHost.js";
7
7
  /**
8
8
  * Keep the native TUI and its transparent App Server attachment in one pane.
@@ -13,7 +13,7 @@ import { openCodexInteractiveConnection } from "./structuredProviderHost.js";
13
13
  * until its first message. Observing the TUI's own startup avoids creating a
14
14
  * second Thread or manufacturing a bootstrap message to materialize history.
15
15
  */
16
- export async function runCodexInteractiveHost(home, payload) {
16
+ export async function runCodexInteractiveHost(home, payload, openAgentHostControl) {
17
17
  const environment = payload.environment;
18
18
  if (environment.YUI_SESSION_SCOPE !== "global" || environment.YUI_ADAPTER_ID !== "codex"
19
19
  || payload.providerControl !== undefined) {
@@ -9,7 +9,6 @@ export { promptPushOutcome, RuntimeHostContentionError, RuntimeHostUnavailableEr
9
9
  export { AgentHostPromptPushAdapter, TmuxSessionHost } from "./tmuxAdapters.js";
10
10
  export { FileTaskRuntimeIsolation, YUI_TASK_RUNTIME_ISOLATION_DESCRIPTOR, YUI_TASK_RUNTIME_SERVICE_NAMESPACE, assertTaskRuntimeIsolationPreflight, createTaskRuntimeIsolationDescriptor, parseTaskRuntimeIsolationDescriptor, planTaskRuntimeCleanup, taskRuntimeIsolationEnvironment, taskRuntimeIsolationFingerprint } from "./taskRuntimeIsolation.js";
11
11
  export { createSessionOwnerIdentity, isLinuxProcessLive, listOwnedProcessTree, readLinuxProcessIdentity } from "./sessionOwnerIdentity.js";
12
- export { FileSessionOwnerRegistry } from "./sessionOwnerRegistry.js";
13
12
  export { formatRuntimeLaunchDiagnostic, redactLaunchArgument, redactLaunchText, RuntimeLaunchFailure, toRuntimeLaunchFailure } from "./launchDiagnostics.js";
14
13
  export { DEFAULT_FORCED_GRACE_MS, DEFAULT_GRACEFUL_GRACE_MS, terminateSessionOwners } from "./sessionTerminationGuard.js";
15
14
  export { ProviderContinuationReconciliationService } from "./providerContinuationReconciliationService.js";
@@ -2,6 +2,26 @@ import { activeRoleAgentBinding } from "../role/role.js";
2
2
  import { currentProviderConversation } from "./providerRuntimeIdentity.js";
3
3
  /** Native Session identity supplied by the Agent transport. */
4
4
  export const MANAGED_NATIVE_SESSION_ENV = "YUI_NATIVE_SESSION_ID";
5
+ /** Global writes use the same command-time native identity as Task writes.
6
+ * A Manifest locates context; it is not continuing mutation authority. */
7
+ export function requireManagedGlobalCaller(store, env) {
8
+ const name = identity(env.YUI_ROLE);
9
+ const role = name === undefined ? null : store.getGlobalRole(name);
10
+ const binding = role?.agentBindings[role.activeAgentId];
11
+ const set = name === undefined ? null : store.getGlobalRoleSessionSet(name);
12
+ const session = set?.sessions[set.activeAgentId];
13
+ const nativeSessionId = identity(binding?.adapterId === "codex"
14
+ ? env.CODEX_THREAD_ID ?? env.YUI_NATIVE_SESSION_ID : env.YUI_NATIVE_SESSION_ID);
15
+ if (env.YUI_SESSION_SCOPE !== "global" || env.YUI_TASK_ID !== undefined
16
+ || !role || !binding || !set || !session || session.status !== "active"
17
+ || set.activeAgentId !== role.activeAgentId || session.agentId !== binding.agentId
18
+ || session.adapterId !== binding.adapterId || nativeSessionId !== session.nativeSessionId
19
+ || (env.YUI_AGENT_ID !== undefined && env.YUI_AGENT_ID !== session.agentId)
20
+ || (env.YUI_ADAPTER_ID !== undefined && env.YUI_ADAPTER_ID !== session.adapterId)) {
21
+ throw new ManagedRuntimeDriftError("This command requires the current managed global native Session; the previous Session has no write authority.");
22
+ }
23
+ return { roleName: role.name, agentId: session.agentId, adapterId: session.adapterId, nativeSessionId };
24
+ }
5
25
  /**
6
26
  * A managed Session presented valid self-identity but is no longer the current
7
27
  * runtime of its Task Role. This is a bounded diagnosis rather than a bare
@@ -119,7 +139,7 @@ function requireCurrentRuntime(store, self) {
119
139
  throw new ManagedRuntimeDriftError(`This managed Session carries no native session id, so it cannot be recognized `
120
140
  + `as the current runtime of ${self.taskId}/${self.roleName}.`);
121
141
  }
122
- if (role.name === "leader" && store.listEvents(self.taskId).some((event) => event.type === "role.agent-bound" && event.payload.role === role.name
142
+ if (role.name === "leader" && store.listEventsByType(self.taskId, ["role.agent-bound"]).some((event) => event.type === "role.agent-bound" && event.payload.role === role.name
123
143
  && event.payload.revokedNativeSessionId === self.nativeSessionId)) {
124
144
  throw new ManagedRuntimeDriftError("This Leader native Session's management authority was explicitly revoked.");
125
145
  }
@@ -0,0 +1,38 @@
1
+ export class ProviderDeliveryUnknownError extends Error {
2
+ attemptId;
3
+ name = "ProviderDeliveryUnknownError";
4
+ constructor(message, attemptId,
5
+ // Wrapping must not become the end of the causal chain: the original
6
+ // transport or Controller failure is the reason a reader needs.
7
+ options) {
8
+ super(message, options);
9
+ this.attemptId = attemptId;
10
+ }
11
+ }
12
+ export class ProviderTurnRejectedError extends Error {
13
+ attemptId;
14
+ name = "ProviderTurnRejectedError";
15
+ constructor(message, attemptId, options) {
16
+ super(message, options);
17
+ this.attemptId = attemptId;
18
+ }
19
+ }
20
+ /** Another ordinary client currently owns the thread's active Turn. */
21
+ export class ProviderTurnBusyError extends Error {
22
+ attemptId;
23
+ activeTurnId;
24
+ name = "ProviderTurnBusyError";
25
+ constructor(message, attemptId, activeTurnId) {
26
+ super(message);
27
+ this.attemptId = attemptId;
28
+ this.activeTurnId = activeTurnId;
29
+ }
30
+ }
31
+ export class ProviderConversationMissingError extends Error {
32
+ conversationId;
33
+ name = "ProviderConversationMissingError";
34
+ constructor(conversationId, message) {
35
+ super(message);
36
+ this.conversationId = conversationId;
37
+ }
38
+ }
@@ -547,11 +547,6 @@ function requireTimestamp(value, label) {
547
547
  throw new Error(`${label} is invalid.`);
548
548
  return timestamp;
549
549
  }
550
- function requireNonNegativeInteger(value, minimum, label) {
551
- if (!Number.isSafeInteger(value) || value < minimum)
552
- throw new Error(`${label} is invalid.`);
553
- return value;
554
- }
555
550
  function requireIdentity(value, label) {
556
551
  const identity = requireText(value, label);
557
552
  if (identity.includes("/../") || identity === "__proto__")
@@ -18,11 +18,10 @@ export function projectRuntimeSessionCandidate(sessions) {
18
18
  sessionUpdatedAt: active.updatedAt
19
19
  };
20
20
  }
21
- /** Deterministic owner order shared by all storage backends. */
21
+ /** Deterministic owner order for current runtime discovery. */
22
22
  export function compareRuntimeSessionCandidates(left, right) {
23
23
  if (left.owner.scope !== right.owner.scope) {
24
- // Preserve the historical adapter contract: Task owners precede the
25
- // bounded global Role set.
24
+ // Task owners precede the bounded global Role set.
26
25
  return left.owner.scope === "task" ? -1 : 1;
27
26
  }
28
27
  if (left.owner.scope === "task" && right.owner.scope === "task") {
@@ -17,7 +17,7 @@ export function createSessionOwnerIdentity(input) {
17
17
  throw new TypeError("Global session owner must not carry a task id.");
18
18
  }
19
19
  const providerRoot = input.providerRoot;
20
- if (!["launch-env", "pane-pid", "owned-child"].includes(providerRoot.attribution)) {
20
+ if (!["pane-pid", "owned-child"].includes(providerRoot.attribution)) {
21
21
  throw new TypeError("Session owner process attribution is invalid.");
22
22
  }
23
23
  if (!Number.isSafeInteger(providerRoot.pid) || providerRoot.pid <= 0) {
@@ -2,13 +2,14 @@ import { spawn } from "node:child_process";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { Duplex } from "node:stream";
4
4
  import { fileURLToPath } from "node:url";
5
+ import { ProviderConversationMissingError, ProviderDeliveryUnknownError, ProviderTurnBusyError, ProviderTurnRejectedError } from "./providerErrors.js";
5
6
  import WebSocket from "ws";
6
- import { CodexAppServerRequestError, CodexAppServerRuntime, codexClientInitialization, codexGoalNotification, codexAppServerErrorIsMissing, codexTurnInput, codexTurnOutput } from "./codexAppServerRuntime.js";
7
- import { serializeAgentErrorRaw } from "./agentError.js";
7
+ import { YUI_VERSION } from "../version.js";
8
8
  import { AcpStructuredProviderSession } from "./acpSession.js";
9
9
  import { acpDesiredSessionConfiguration } from "./acpSessionConfiguration.js";
10
+ import { serializeAgentErrorRaw } from "./agentError.js";
10
11
  import { unsupportedAgentRunConfiguration } from "./agentRunConfiguration.js";
11
- import { YUI_VERSION } from "../version.js";
12
+ import { codexAppServerErrorIsMissing, CodexAppServerRequestError, CodexAppServerRuntime, codexClientInitialization, codexGoalNotification, codexTurnInput, codexTurnOutput } from "./codexAppServerRuntime.js";
12
13
  import { JsonLineChannel, PROVIDER_MESSAGE_MAX_BYTES, terminateProcessGroup } from "./jsonLineChannel.js";
13
14
  import { PROVIDER_ACCEPT_TIMEOUT_MS } from "./runtimeDeadlines.js";
14
15
  const CODEX_PROXY_HANDSHAKE_TIMEOUT_MS = 10_000;
@@ -18,44 +19,6 @@ const CODEX_PROXY_HANDSHAKE_TIMEOUT_MS = 10_000;
18
19
  */
19
20
  const CODEX_RUN_CONFIGURATION = unsupportedAgentRunConfiguration("The Codex app-server protocol");
20
21
  const CLAUDE_RUN_CONFIGURATION = unsupportedAgentRunConfiguration("Claude Code's stream-json interface");
21
- export class ProviderDeliveryUnknownError extends Error {
22
- attemptId;
23
- name = "ProviderDeliveryUnknownError";
24
- constructor(message, attemptId,
25
- // Wrapping must not become the end of the causal chain: the original
26
- // transport or Controller failure is the reason a reader needs.
27
- options) {
28
- super(message, options);
29
- this.attemptId = attemptId;
30
- }
31
- }
32
- export class ProviderTurnRejectedError extends Error {
33
- attemptId;
34
- name = "ProviderTurnRejectedError";
35
- constructor(message, attemptId, options) {
36
- super(message, options);
37
- this.attemptId = attemptId;
38
- }
39
- }
40
- /** Another ordinary client currently owns the thread's active Turn. */
41
- export class ProviderTurnBusyError extends Error {
42
- attemptId;
43
- activeTurnId;
44
- name = "ProviderTurnBusyError";
45
- constructor(message, attemptId, activeTurnId) {
46
- super(message);
47
- this.attemptId = attemptId;
48
- this.activeTurnId = activeTurnId;
49
- }
50
- }
51
- export class ProviderConversationMissingError extends Error {
52
- conversationId;
53
- name = "ProviderConversationMissingError";
54
- constructor(conversationId, message) {
55
- super(message);
56
- this.conversationId = conversationId;
57
- }
58
- }
59
22
  export async function startStructuredProviderSession(payload, input = {}) {
60
23
  const control = payload.providerControl;
61
24
  if (control === undefined) {
@@ -1,14 +1,14 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { fileURLToPath } from "node:url";
3
2
  import { resolve } from "node:path";
4
- import { createRuntimeBinding } from "./runtimeBinding.js";
5
- import { normalizeRuntimeOwner } from "./runtimeOwner.js";
6
- import { RuntimeHostContentionError, RuntimeHostUnavailableError, promptPushOutcome } from "./ports.js";
3
+ import { fileURLToPath } from "node:url";
7
4
  import { providerDeliveryFailureFrom } from "./agentError.js";
5
+ import { AGENT_HOST_CONTROL_PROTOCOL, sendAgentHostLaunchControl, sendAgentHostRunControl, sendAgentHostSteerControl, waitForAgentHostLaunchAck } from "./agentHost.js";
6
+ import { launchBrokerForHome } from "./launchBroker.js";
8
7
  import { toRuntimeLaunchFailure } from "./launchDiagnostics.js";
8
+ import { RuntimeHostContentionError, RuntimeHostUnavailableError, promptPushOutcome } from "./ports.js";
9
+ import { createRuntimeBinding } from "./runtimeBinding.js";
10
+ import { normalizeRuntimeOwner } from "./runtimeOwner.js";
9
11
  import { requireSafeIdentity } from "./validation.js";
10
- import { launchBrokerForHome } from "./launchBroker.js";
11
- import { AGENT_HOST_CONTROL_PROTOCOL, sendAgentHostLaunchControl, sendAgentHostRunControl, sendAgentHostSteerControl, waitForAgentHostLaunchAck } from "./agentHost.js";
12
12
  const DEFAULT_INACTIVITY_TIMEOUT_MS = 300_000;
13
13
  /**
14
14
  * Runtime lifecycle adapter for the current tmux host. The returned hostRef is
@@ -656,8 +656,6 @@ async function killRole(tmux, hostId, roleName) {
656
656
  await tmux.killRoleAsync(hostId, roleName);
657
657
  }
658
658
  async function stopExactRole(tmux, hostId, roleName) {
659
- if (await probeRoleStatus(tmux, hostId, roleName) !== "running")
660
- return;
661
659
  try {
662
660
  await killRole(tmux, hostId, roleName);
663
661
  }
@@ -25,7 +25,7 @@ export async function processActiveRoleRunDeliveries(store, delivery, now, selec
25
25
  for (const task of selectedActiveSchedulerTasks(store, selection, {
26
26
  includePlanningDrafts: true
27
27
  })) {
28
- store.prepareMessageContinuations?.(task.id, now);
28
+ store.prepareMessageContinuations(task.id, now);
29
29
  for (const role of selectedSchedulerRoles(store, task.id, selection)) {
30
30
  const run = store.getActiveRun(task.id, role.name);
31
31
  if (run === null)
@@ -49,7 +49,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
49
49
  roleName: role.name,
50
50
  runId: run.id
51
51
  });
52
- const sessionSet = store.getTaskRoleSessionSet?.(task.id, role.name) ?? null;
52
+ const sessionSet = store.getTaskRoleSessionSet(task.id, role.name);
53
53
  const binding = sessionSet?.providerBinding ?? null;
54
54
  if (binding?.retry !== undefined && (binding.retry.successorRunId === run.id
55
55
  || binding.retry.successorReviewRoundId !== undefined && binding.retry.successorReviewRoundId === run.reviewRoundId)
@@ -97,7 +97,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
97
97
  // report. Keep the exact input fenced; never submit it again.
98
98
  return { ...base, status: "skipped", reason: "delivery-uncertain", error: reason };
99
99
  }
100
- const lastSubmitError = (store.listEvents?.(task.id) ?? []).filter((event) => event.type === "runtime.agent-error" && event.payload.runId === run.id
100
+ const lastSubmitError = store.listEvents(task.id).filter((event) => event.type === "runtime.agent-error" && event.payload.runId === run.id
101
101
  && event.payload.roleName === role.name && event.payload.phase === "turn-submit").at(-1);
102
102
  if (currentProviderTurn === null && lastSubmitError?.payload.inputDisposition === "unknown") {
103
103
  return { ...base, status: "skipped", reason: "delivery-uncertain", error: lastSubmitError.payload.message };
@@ -114,7 +114,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
114
114
  // The first attempted admission may already have opened this fixed native
115
115
  // Session. A busy retry resumes it; it does not repeat the original launch.
116
116
  const preparedHere = existingSession?.nativeSessionId !== undefined
117
- && (store.listEvents?.(task.id) ?? []).some((event) => event.type === "run.session-prepared"
117
+ && store.listEvents(task.id).some((event) => event.type === "run.session-prepared"
118
118
  && event.payload.runId === run.id && event.payload.nativeSessionId === existingSession.nativeSessionId);
119
119
  const mode = (currentProviderTurn?.status === "deferred" || preparedHere) && existingSession?.nativeSessionId !== undefined
120
120
  ? "resume" : run.mode;
@@ -183,7 +183,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
183
183
  }
184
184
  if (outcome.status === "busy" || outcome.status === "unavailable") {
185
185
  if (outcome.status === "busy" && outcome.failure?.inputDisposition === "not-accepted") {
186
- store.recordAgentError?.({ taskId: task.id, roleName: role.name, runId: run.id,
186
+ store.recordAgentError({ taskId: task.id, roleName: role.name, runId: run.id,
187
187
  source: "host", phase: "turn-submit", message: outcome.failure.detail,
188
188
  raw: outcome.failure.raw ?? serializeAgentErrorRaw(outcome.failure),
189
189
  inputDisposition: "not-accepted", ...providerDeliveryFailureFacts(outcome.failure),
@@ -208,7 +208,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
208
208
  : formatProviderDeliveryFailure(failure);
209
209
  // This path is the common Provider write failure and previously left no
210
210
  // durable fact at all, so the cause was unrecoverable after the fact.
211
- store.recordAgentError?.({
211
+ store.recordAgentError({
212
212
  taskId: task.id,
213
213
  roleName: role.name,
214
214
  runId: run.id,
@@ -238,7 +238,7 @@ async function deliverActiveRun(store, delivery, task, role, run, now) {
238
238
  const message = error instanceof Error ? error.message : String(error);
239
239
  // Preserve the structured cause alongside the readable diagnosis.
240
240
  const causeName = innermostCauseName(error);
241
- store.recordAgentError?.({
241
+ store.recordAgentError({
242
242
  taskId: task.id,
243
243
  roleName: role.name,
244
244
  runId: run.id,
@@ -4,6 +4,9 @@ import { isSchedulerTaskWorkspaceReady } from "./ports.js";
4
4
  import { taskOwnsManagedWorkspace } from "../task/task.js";
5
5
  import { hasImmediateWakeReason } from "./wakeReason.js";
6
6
  import { providerRetryPending } from "../runtime/providerRetry.js";
7
+ import { RuntimeLaunchError } from "../runtime/ports.js";
8
+ import { RuntimeLifecycleBusyError } from "../runtime/lifecycleReservation.js";
9
+ import { redactAgentErrorText } from "../runtime/agentError.js";
7
10
  export const LEADER_WAKE_AGGREGATION_MS = 60_000;
8
11
  /** Deliver a durable mailbox notification, not an implicit execution assignment.
9
12
  * Acceptance settles only its claimed batch; no Agent report is required.
@@ -29,11 +32,11 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
29
32
  results.push({ ...base, status: "skipped", reason: "aggregating" });
30
33
  continue;
31
34
  }
32
- if (task.status === "draft" && store.prepareDraftPlanning?.(task.id, now)) {
35
+ if (task.status === "draft" && store.prepareDraftPlanning(task.id, now)) {
33
36
  results.push({ ...base, status: "skipped", reason: "not-ready" });
34
37
  continue;
35
38
  }
36
- const sessions = store.getTaskRoleSessionSet?.(task.id, role.name) ?? null;
39
+ const sessions = store.getTaskRoleSessionSet(task.id, role.name);
37
40
  const provider = sessions?.providerBinding;
38
41
  if (providerRetryPending(provider)) {
39
42
  results.push({ ...base, status: "skipped", reason: "not-ready" });
@@ -55,13 +58,17 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
55
58
  ...(notification.disposition === "unknown" ? {
56
59
  error: `Notification acceptance is unknown; the fixed wake is retained and will not be replayed. `
57
60
  + `After establishing native quiescence, release only this claim with yui task wake resolve ${task.id} ${notification.wakeId} --reason <evidence>.`
61
+ } : notification.disposition === "rejected" ? {
62
+ error: `Notification was rejected; inspect yui task wake show ${task.id} ${notification.wakeId}. `
63
+ + `After correcting the cause, retry with yui task wake retry ${task.id} ${notification.wakeId} --reason <correction>.`
58
64
  } : {}) });
59
65
  continue;
60
66
  }
61
67
  let attempted = false;
68
+ let effective = role.effective;
62
69
  try {
63
70
  const session = store.getRoleSession(task.id, role.name, role.effective.agentId);
64
- const effective = session?.status === "active" ? session.effective : role.effective;
71
+ effective = session?.status === "active" ? session.effective : role.effective;
65
72
  if (session?.status === "active" && !roleSessionMayContinue(session.effective, role.effective)) {
66
73
  throw new Error("Leader Session configuration changed; explicitly apply it before notification delivery.");
67
74
  }
@@ -96,12 +103,18 @@ export async function processLeaderWakeups(store, delivery, now, selection) {
96
103
  : outcome.status === "rejected" ? "rejected"
97
104
  : outcome.status === "pending" ? null : "deferred";
98
105
  if (disposition !== null)
99
- store.settleLeaderNotification(task.id, notification.attemptId, disposition, now, outcome.failure?.detail);
106
+ store.settleLeaderNotification(task.id, notification.attemptId, disposition, now, outcome.failure?.detail, { effective, raw: outcome.failure?.raw ?? outcome.failure?.detail ?? `Notification ${disposition}.`,
107
+ phase: "turn-submit" });
100
108
  results.push({ ...base, status: accepted ? "dispatched" : "skipped", reason: accepted ? undefined : "not-ready" });
101
109
  }
102
110
  catch (error) {
103
- const detail = error instanceof Error ? error.message : String(error);
104
- store.settleLeaderNotification(task.id, notification.attemptId, attempted ? "unknown" : "deferred", now, detail);
111
+ const detail = redactAgentErrorText(error instanceof Error ? error.message : String(error));
112
+ // Match explicit AgentRun admission: only positive, typed backpressure
113
+ // permits another automatic launch. A config/auth/executable failure
114
+ // needs correction; an exception after submit cannot authorize replay.
115
+ const retryable = error instanceof RuntimeLifecycleBusyError
116
+ || (error instanceof RuntimeLaunchError && error.retryable);
117
+ store.settleLeaderNotification(task.id, notification.attemptId, attempted ? "unknown" : retryable ? "deferred" : "rejected", now, detail, { effective, raw: detail, phase: attempted ? "turn-submit" : "session-start" });
105
118
  results.push({ ...base, status: "failed", reason: "not-ready", error: detail });
106
119
  }
107
120
  finally {
@@ -1,31 +1,23 @@
1
1
  import { enqueueWork } from "../coordination/workMailboxQueue.js";
2
2
  import { createTaskEvent } from "../event/taskEvent.js";
3
- import { queueLeaderWakeup } from "./wakeupQueue.js";
4
3
  export const LEADER_ATTENTION_REQUIRED_EVENT = "leader.attention-required";
5
- /** The sole Task-event boundary into the global Operator mailbox. */
6
- export function enqueueOperatorEvent(store, event, reason, now) {
7
- if (store.getTask?.(event.taskId)?.status === "archived")
4
+ /** One event, one supervisor signal; the Leader wake is this mailbox's projection. */
5
+ export function enqueueSupervisorEvent(store, event, recipient, reason, now) {
6
+ if (store.getTask(event.taskId)?.status === "archived")
8
7
  return;
9
- enqueueWork(store, { kind: "operator" }, reason, now, [
8
+ const target = recipient === "operator" ? { kind: "operator" }
9
+ : { kind: "role", taskId: event.taskId, roleName: "leader" };
10
+ enqueueWork(store, target, reason, now, [
10
11
  { type: "event", taskId: event.taskId, id: event.id }
11
- ], {
12
- source: "task-event",
13
- dedupeKey: `operator-event:${event.taskId}:${event.id}`
14
- });
12
+ ], { source: "task-event", dedupeKey: `${recipient}-event:${event.taskId}:${event.id}` });
13
+ }
14
+ /** The sole Task-event boundary into the global Operator mailbox. */
15
+ export function enqueueOperatorEvent(store, event, reason, now) {
16
+ enqueueSupervisorEvent(store, event, "operator", reason, now);
15
17
  }
16
18
  /** Routes one Role fact to its supervisor without exposing Provider details to Operator code. */
17
19
  export function routeRoleEvent(store, event, roleName, reason, now) {
18
- if (store.getTask?.(event.taskId)?.status === "archived")
19
- return;
20
- if (roleName === "leader") {
21
- enqueueOperatorEvent(store, event, reason, now);
22
- return;
23
- }
24
- enqueueWork(store, { kind: "role", taskId: event.taskId, roleName: "leader" }, reason, now, [{ type: "event", taskId: event.taskId, id: event.id }], {
25
- source: "task-event",
26
- dedupeKey: `leader-event:${event.taskId}:${event.id}`
27
- });
28
- queueLeaderWakeup(store, event.taskId, reason, now);
20
+ enqueueSupervisorEvent(store, event, roleName === "leader" ? "operator" : "leader", reason, now);
29
21
  }
30
22
  /** Records the semantic boundary used when a Leader can no longer continue. */
31
23
  export function recordLeaderAttentionRequired(store, input) {
@@ -26,7 +26,7 @@ export async function processOperatorInputNotifications(store, delivery, selecti
26
26
  ? [{ kind: "input", request }]
27
27
  : [];
28
28
  }
29
- if (ref.type !== "event" || store.listEvents === undefined)
29
+ if (ref.type !== "event")
30
30
  return [];
31
31
  const event = store.listEvents(ref.taskId).find(({ id }) => id === ref.id);
32
32
  return event === undefined ? [] : [{ kind: "event", event }];
@@ -1,5 +1,5 @@
1
- import { isTaskOwnedWorkspace } from "../worktree/managedWorkspace.js";
2
1
  import { taskOwnsManagedWorkspace } from "../task/task.js";
2
+ import { isTaskOwnedWorkspace } from "../worktree/managedWorkspace.js";
3
3
  /**
4
4
  * Whether the Task's workspace state admits a launch.
5
5
  *
@@ -72,14 +72,11 @@ export function selectedActiveSchedulerTasks(store, selection, options) {
72
72
  return planningDrafts && hasActivePlanningRun(store, task);
73
73
  };
74
74
  if (selection === undefined || selection.full) {
75
- const indexedTaskIds = store.listActiveTaskIds?.();
76
- if (indexedTaskIds === undefined) {
77
- return store.listTasks().filter((task) => (admits(task) && !selection?.blockedTaskIds?.has(task.id)));
78
- }
75
+ const indexedTaskIds = store.listActiveTaskIds();
79
76
  // The active index is bounded and authoritative for active Tasks; planning
80
77
  // Drafts come from their own bounded index rather than a full-history scan.
81
78
  const taskIds = planningDrafts
82
- ? [...indexedTaskIds, ...(store.listPlanningDraftTaskIds?.() ?? [])]
79
+ ? [...indexedTaskIds, ...store.listPlanningDraftTaskIds()]
83
80
  : [...indexedTaskIds];
84
81
  const seen = new Set();
85
82
  return taskIds.flatMap((taskId) => {
@@ -106,9 +103,9 @@ export function selectedActiveSchedulerTasks(store, selection, options) {
106
103
  function hasActivePlanningRun(store, task) {
107
104
  if (task.status !== "draft")
108
105
  return false;
109
- const roles = store.listRoles?.(task.id) ?? [];
106
+ const roles = store.listRoles(task.id);
110
107
  return roles.some((role) => {
111
- const run = store.getActiveRun?.(task.id, role.name) ?? null;
108
+ const run = store.getActiveRun(task.id, role.name);
112
109
  return run !== null
113
110
  && run.status === "active"
114
111
  && isSchedulerPlanningDraft(task, run.purpose);
@@ -1,6 +1,6 @@
1
- import { selectedSchedulerRoles, selectedActiveSchedulerTasks } from "./ports.js";
2
- import { formatTaskRecordReference } from "../task/taskRecordReference.js";
3
1
  import { runPurposeAdmitsTaskState } from "../agentRun/agentRun.js";
2
+ import { formatTaskRecordReference } from "../task/taskRecordReference.js";
3
+ import { selectedActiveSchedulerTasks, selectedSchedulerRoles } from "./ports.js";
4
4
  import { currentRoleRunProgressAt, DEFAULT_WORKFLOW_STALL_CANDIDATE_AGE_MS } from "./roleRunStall.js";
5
5
  /**
6
6
  * Lightweight liveness only. Pane/process loss is runtime-health evidence,
@@ -85,7 +85,7 @@ export async function reconcileExitedRoleRuns(store, delivery, now, selection, e
85
85
  }
86
86
  }
87
87
  }
88
- for (const { task, role, run, session, inspection } of eligible) {
88
+ for (const { task, role, run, session } of eligible) {
89
89
  const status = batchSnapshot.statuses.get(`${task.id}\0${role.name}`);
90
90
  if (status === undefined)
91
91
  throw new Error("Role liveness snapshot is incomplete.");
@@ -93,7 +93,7 @@ export async function reconcileExitedRoleRuns(store, delivery, now, selection, e
93
93
  continue;
94
94
  const hostExit = batchSnapshot.hostExits.get(`${task.id}\0${role.name}`);
95
95
  if (hostExit !== undefined) {
96
- store.saveRoleHostExitObservation?.({
96
+ store.saveRoleHostExitObservation({
97
97
  taskId: task.id,
98
98
  roleName: role.name,
99
99
  runId: run.id,