@zq-silk/yui 0.15.11 → 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 (280) hide show
  1. package/ARCHITECTURE.md +11 -6
  2. package/ARCHITECTURE.zh-CN.md +8 -4
  3. package/README.md +13 -5
  4. package/dist/agentRun/agentRun.js +3 -0
  5. package/dist/artifacts/artifactCommitLock.js +16 -55
  6. package/dist/artifacts/taskArtifactRepository.js +3 -3
  7. package/dist/cli/agentConfigurationPicker.js +1 -1
  8. package/dist/cli/commandCatalog.js +92 -48
  9. package/dist/cli/completion.js +18 -18
  10. package/dist/cli/completionWizard.js +1 -1
  11. package/dist/cli/dynamicCompletion.js +1 -1
  12. package/dist/cli/interactionPolicy.js +11 -3
  13. package/dist/cli/invocationAuthority.js +64 -0
  14. package/dist/cli/managedDiagnostics.js +2 -2
  15. package/dist/cli/parseRepeatable.js +35 -0
  16. package/dist/cli/updatePorts.js +26 -5
  17. package/dist/cli.js +1303 -1235
  18. package/dist/commands/agentCommands.js +4 -4
  19. package/dist/commands/capabilityCommands.js +1 -1
  20. package/dist/commands/configCommands.js +6 -57
  21. package/dist/commands/configOverview.js +2 -2
  22. package/dist/commands/durableJobCommands.js +12 -6
  23. package/dist/commands/executionAuditCommands.js +10 -0
  24. package/dist/commands/globalRoleCommands.js +78 -29
  25. package/dist/commands/grantCommands.js +0 -3
  26. package/dist/commands/jobCommands.js +1 -4
  27. package/dist/commands/operatorCommands.js +3 -3
  28. package/dist/commands/projectCommands.js +45 -25
  29. package/dist/commands/resourcesCommands.js +10 -40
  30. package/dist/commands/roleConfiguration.js +2 -6
  31. package/dist/commands/taskActivationCommands.js +4 -8
  32. package/dist/commands/taskAgentCapabilities.js +9 -0
  33. package/dist/commands/taskCommandSupport.js +155 -0
  34. package/dist/commands/taskCommandTypes.js +1 -0
  35. package/dist/commands/taskCommands.js +355 -732
  36. package/dist/commands/taskCompletionGate.js +1 -1
  37. package/dist/commands/taskExecutionCommands.js +1 -1
  38. package/dist/commands/taskFactCommands.js +325 -0
  39. package/dist/commands/taskInputCommands.js +12 -42
  40. package/dist/commands/taskIntegrationCommands.js +20 -58
  41. package/dist/commands/taskNextActionCommand.js +7 -6
  42. package/dist/commands/taskPublicationAdoptCommand.js +127 -0
  43. package/dist/commands/taskPublicationCommands.js +12 -3
  44. package/dist/commands/taskPublicationVerifyCommand.js +24 -40
  45. package/dist/commands/taskRemoteDeliveryCommand.js +5 -86
  46. package/dist/commands/taskUpstreamCommands.js +19 -8
  47. package/dist/commands/workflowCommands.js +6 -1
  48. package/dist/completion/completionInstaller.js +26 -26
  49. package/dist/completion/completionState.js +26 -26
  50. package/dist/completion/fileCompletionManager.js +6 -11
  51. package/dist/config/configCatalog.js +0 -2
  52. package/dist/config/timeZone.js +14 -0
  53. package/dist/config/yuiConfig.js +0 -29
  54. package/dist/context/runContextPack.js +5 -3
  55. package/dist/context/taskCatalog.js +185 -0
  56. package/dist/context/taskContext.js +152 -151
  57. package/dist/context/wakeRunReferences.js +11 -0
  58. package/dist/controller/agentCapabilities.js +58 -0
  59. package/dist/controller/agentRuntimeObserver.js +6 -11
  60. package/dist/controller/clientRuntime.js +22 -14
  61. package/dist/controller/controller.js +20 -24
  62. package/dist/controller/fileSchedulerStoreAdapter.js +191 -225
  63. package/dist/controller/globalInputDelivery.js +13 -0
  64. package/dist/controller/jobClient.js +4 -4
  65. package/dist/controller/jobControl.js +60 -25
  66. package/dist/controller/jobSupervisor.js +4 -4
  67. package/dist/controller/providerRetryAdmission.js +100 -0
  68. package/dist/controller/providerRetryDelivery.js +218 -0
  69. package/dist/controller/runtime.js +85 -43
  70. package/dist/controller/runtimeEventProcessor.js +0 -5
  71. package/dist/controller/sessionOwnerReconciliation.js +5 -0
  72. package/dist/controller/taskAgentError.js +35 -0
  73. package/dist/coordination/workMailboxQueue.js +2 -24
  74. package/dist/core/controllerClient.js +2 -2
  75. package/dist/core/fileLockOwner.js +74 -0
  76. package/dist/decision/decision.js +17 -0
  77. package/dist/doctor/doctor.js +18 -9
  78. package/dist/event/taskEvent.js +12 -0
  79. package/dist/execution/workItemExecutionProjection.js +2 -2
  80. package/dist/executor/agentCapabilityConfig.js +43 -0
  81. package/dist/executor/agentConfigurationCatalog.js +49 -11
  82. package/dist/executor/agentExecutor.js +5 -8
  83. package/dist/executor/fileRoleLaunchPlanner.js +11 -53
  84. package/dist/executor/taskAgentCapabilities.js +64 -0
  85. package/dist/integration/deliveryObligation.js +1 -69
  86. package/dist/integration/gitIntegrationService.js +79 -90
  87. package/dist/integration/integrationAttempt.js +3 -14
  88. package/dist/integration/integrationSourceApplication.js +4 -12
  89. package/dist/integration/manifestTags.js +2 -2
  90. package/dist/job/durableJob.js +4 -25
  91. package/dist/job/jobAssignmentScope.js +22 -0
  92. package/dist/job/jobOperation.js +16 -0
  93. package/dist/job/jobRunner.js +2 -1
  94. package/dist/job/stepDirectory.js +15 -0
  95. package/dist/kernel/builtinCapabilities.js +15 -11
  96. package/dist/kernel/kernelPorts.js +1 -17
  97. package/dist/lifecycle/exactRunTerminalization.js +5 -10
  98. package/dist/message/globalProviderRetry.js +15 -0
  99. package/dist/message/inputControlResolution.js +3 -4
  100. package/dist/message/message.js +17 -20
  101. package/dist/message/messageContinuation.js +1 -1
  102. package/dist/milestone/milestone.js +11 -0
  103. package/dist/observability/executionAudit.js +19 -0
  104. package/dist/observability/orchestrationMetrics.js +24 -1
  105. package/dist/observability/runtimeIdentity.js +1 -17
  106. package/dist/output/agentConfigurationPresentation.js +2 -0
  107. package/dist/output/timePresentation.js +1 -14
  108. package/dist/plugins/pluginService.js +12 -4
  109. package/dist/release/releaseWorkflowPorts.js +45 -96
  110. package/dist/release/runtimeRelease.js +9 -15
  111. package/dist/repository/gitWorkspace.js +371 -105
  112. package/dist/repository/projectMaintenanceLock.js +98 -82
  113. package/dist/repository/taskBaseFreshness.js +1 -1
  114. package/dist/repository/taskWorkspaceCoordinator.js +82 -144
  115. package/dist/repository/taskWorkspacePreparer.js +113 -47
  116. package/dist/repository/workspaceCleanupInspection.js +187 -0
  117. package/dist/resources/autoResourceGc.js +4 -77
  118. package/dist/resources/liveReferences.js +7 -54
  119. package/dist/resources/resourceDiscovery.js +5 -118
  120. package/dist/resources/resourceGc.js +233 -181
  121. package/dist/resources/resourceRegistrar.js +5 -4
  122. package/dist/resources/resourceRegistry.js +3 -37
  123. package/dist/resources/resourceRegistryStore.js +13 -36
  124. package/dist/resources/sqliteResourceRegistry.js +43 -26
  125. package/dist/review/deltaRecheck.js +1 -1
  126. package/dist/review/reviewAcceptance.js +1 -1
  127. package/dist/review/reviewDecision.js +1 -1
  128. package/dist/review/reviewRound.js +8 -7
  129. package/dist/review/taskFinalReviewContractResolution.js +1 -1
  130. package/dist/runtime/acpProtocol.js +4 -51
  131. package/dist/runtime/acpSession.js +10 -75
  132. package/dist/runtime/acpSessionConfiguration.js +1 -8
  133. package/dist/runtime/agentEndpoint.js +3 -2
  134. package/dist/runtime/agentError.js +5 -3
  135. package/dist/runtime/agentFailureContext.js +43 -0
  136. package/dist/runtime/agentHost.js +42 -25
  137. package/dist/runtime/builtinAgentErrorMappers.js +91 -0
  138. package/dist/runtime/codexAppServerRuntime.js +34 -3
  139. package/dist/runtime/codexInteractiveHost.js +2 -2
  140. package/dist/runtime/index.js +0 -1
  141. package/dist/runtime/managedCaller.js +21 -1
  142. package/dist/runtime/providerControl.js +5 -1
  143. package/dist/runtime/providerErrors.js +38 -0
  144. package/dist/runtime/providerRetry.js +198 -0
  145. package/dist/runtime/providerRuntimeIdentity.js +28 -2
  146. package/dist/runtime/runtimeObservation.js +0 -5
  147. package/dist/runtime/runtimeSessionCandidate.js +2 -3
  148. package/dist/runtime/sessionOwnerIdentity.js +1 -1
  149. package/dist/runtime/sessionTokenMetrics.js +15 -5
  150. package/dist/runtime/structuredProviderHost.js +10 -43
  151. package/dist/runtime/taskUsageMetrics.js +275 -0
  152. package/dist/runtime/tmuxAdapters.js +6 -8
  153. package/dist/scheduler/activeRoleRunDelivery.js +19 -7
  154. package/dist/scheduler/leaderWakeupProcessor.js +24 -6
  155. package/dist/scheduler/operatorEvent.js +12 -20
  156. package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
  157. package/dist/scheduler/ports.js +5 -8
  158. package/dist/scheduler/roleRunLiveness.js +4 -4
  159. package/dist/scheduler/roleRunStall.js +16 -23
  160. package/dist/scheduler/taskExecutionProjection.js +49 -36
  161. package/dist/scheduler/taskObservabilityProjection.js +6 -45
  162. package/dist/scheduler/taskWake.js +5 -10
  163. package/dist/scheduler/wakeReason.js +2 -0
  164. package/dist/scheduler/wakeupQueue.js +2 -4
  165. package/dist/setup/setupCommand.js +1 -1
  166. package/dist/storage/contextRecords.js +106 -0
  167. package/dist/storage/currentTaskStore.js +1 -1
  168. package/dist/storage/homeLayout.js +13 -17
  169. package/dist/storage/migrations/agentFailureContext.js +22 -0
  170. package/dist/storage/migrations/currentInputContract.js +86 -0
  171. package/dist/storage/migrations/currentRuntimeContract.js +228 -0
  172. package/dist/storage/migrations/historicalVerificationPlan.js +35 -0
  173. package/dist/storage/migrations/integrationContinuation.js +5 -4
  174. package/dist/storage/migrations/narrowAgentFailureContext.js +65 -0
  175. package/dist/storage/migrations/notificationOnlyWakes.js +74 -0
  176. package/dist/storage/migrations/verificationPlanV1.js +162 -0
  177. package/dist/storage/migrations/verificationPolicy.js +74 -0
  178. package/dist/storage/migrations/workItemHistory.js +46 -0
  179. package/dist/storage/persistenceWorker.js +12 -4
  180. package/dist/storage/recordValidation.js +87 -0
  181. package/dist/storage/sqliteSchema.js +173 -1
  182. package/dist/storage/sqliteStore.js +172 -161
  183. package/dist/storage/storageSchema.js +2 -14
  184. package/dist/storage/storageVersions.js +1 -1
  185. package/dist/storage/storeRpc.js +16 -7
  186. package/dist/storage/taskCatalog.js +123 -0
  187. package/dist/storage/taskStore.js +5 -7
  188. package/dist/storage/upgrade/upgradeOrchestrator.js +25 -37
  189. package/dist/task/archiveDiagnostics.js +1 -0
  190. package/dist/task/archivePreflight.js +124 -0
  191. package/dist/task/completionReadiness.js +5 -24
  192. package/dist/task/draftPlan.js +0 -53
  193. package/dist/task/nextAction.js +7 -13
  194. package/dist/task/publicationAdoption.js +56 -0
  195. package/dist/task/publicationReference.js +10 -0
  196. package/dist/task/remoteDelivery.js +31 -16
  197. package/dist/task/remoteDeliveryService.js +89 -0
  198. package/dist/task/taskActivation.js +2 -25
  199. package/dist/task/taskActivationService.js +0 -2
  200. package/dist/task/taskRecordReference.js +0 -1
  201. package/dist/task/taskSubmission.js +3 -14
  202. package/dist/telemetry/sqliteTelemetryBatch.js +29 -0
  203. package/dist/telemetry/sqliteTelemetryStore.js +49 -49
  204. package/dist/telemetry/telemetryWiring.js +4 -3
  205. package/dist/tmux/tmuxManager.js +29 -20
  206. package/dist/verification/gateArtifact.js +15 -24
  207. package/dist/verification/gateArtifactStore.js +14 -7
  208. package/dist/verification/verificationGateService.js +29 -88
  209. package/dist/verification/verificationPlan.js +27 -72
  210. package/dist/web/assets/client/app.js +92 -17
  211. package/dist/web/assets/client/components.js +55 -13
  212. package/dist/web/assets/client/i18n.js +72 -4
  213. package/dist/web/assets/client/taskSurface.js +6 -5
  214. package/dist/web/assets/client/view.js +35 -7
  215. package/dist/web/assets/shell.js +6 -0
  216. package/dist/web/assets/styles/layout.js +7 -0
  217. package/dist/web/webServer.js +12 -3
  218. package/dist/web/webSnapshot.js +14 -85
  219. package/dist/web/webTaskSurface.js +17 -46
  220. package/dist/workItem/workItem.js +1 -12
  221. package/dist/workspace/cleanupInspection.js +63 -0
  222. package/dist/workspace/workItemChangeSetManager.js +110 -50
  223. package/docs/agent-result-consumption.md +4 -0
  224. package/docs/agent-result-consumption.zh-CN.md +3 -0
  225. package/docs/agent-runtime-drivers.md +7 -0
  226. package/docs/agent-runtime-drivers.zh-CN.md +5 -0
  227. package/docs/architecture/README.md +2 -0
  228. package/docs/architecture/README.zh-CN.md +3 -1
  229. package/docs/architecture/capabilities-and-resources.md +42 -5
  230. package/docs/architecture/capabilities-and-resources.zh-CN.md +33 -3
  231. package/docs/managed-turn-and-session-runtime.md +121 -1
  232. package/docs/managed-turn-and-session-runtime.zh-CN.md +96 -2
  233. package/docs/observability/README.md +62 -0
  234. package/docs/observability/README.zh-CN.md +47 -0
  235. package/docs/plugin-sdk.md +4 -2
  236. package/docs/project-refresh.md +77 -0
  237. package/docs/project-refresh.zh-CN.md +59 -0
  238. package/docs/provider-retry.md +70 -0
  239. package/docs/provider-runtime.md +3 -1
  240. package/docs/provider-runtime.zh-CN.md +4 -2
  241. package/docs/release-workflow.md +190 -7
  242. package/docs/release-workflow.zh-CN.md +139 -5
  243. package/docs/roles-and-configuration.md +29 -0
  244. package/docs/roles-and-configuration.zh-CN.md +21 -0
  245. package/docs/sqlite-control-plane-design.md +16 -3
  246. package/docs/sqlite-control-plane-design.zh-CN.md +13 -2
  247. package/docs/task-dag-semantics.md +3 -3
  248. package/docs/task-dag-semantics.zh-CN.md +2 -2
  249. package/docs/task-delivery.md +223 -17
  250. package/docs/task-delivery.zh-CN.md +171 -14
  251. package/docs/task-discovery.md +101 -0
  252. package/docs/task-discovery.zh-CN.md +85 -0
  253. package/docs/testing/verification-levels.md +161 -9
  254. package/docs/testing/verification-levels.zh-CN.md +116 -9
  255. package/i18n/README.zh-CN.md +13 -7
  256. package/package.json +1 -1
  257. package/skills/yui-leader/SKILL.md +5 -0
  258. package/skills/yui-leader/references/execution.md +3 -2
  259. package/skills/yui-leader/references/integration.md +9 -5
  260. package/skills/yui-leader/references/planning.md +9 -3
  261. package/skills/yui-operator/SKILL.md +24 -8
  262. package/skills/yui-reviewer/SKILL.md +4 -0
  263. package/skills/yui-runtime/SKILL.md +17 -2
  264. package/skills/yui-runtime/references/publication.md +26 -4
  265. package/skills/yui-runtime/references/recovery.md +71 -0
  266. package/dist/agent/agentRegistry.js +0 -10
  267. package/dist/agentRun/runIdentity.js +0 -22
  268. package/dist/commands/deliveryGuardPreflight.js +0 -30
  269. package/dist/commands/taskIntegrationQueueCommands.js +0 -226
  270. package/dist/commands/taskOverviewCommand.js +0 -376
  271. package/dist/completion/completionWizard.js +0 -125
  272. package/dist/context/dispatchContext.js +0 -110
  273. package/dist/context/wakeNotification.js +0 -144
  274. package/dist/integration/integrationCheckEvidenceReuse.js +0 -53
  275. package/dist/integration/integrationQueueEntry.js +0 -191
  276. package/dist/integration/integrationQueueService.js +0 -810
  277. package/dist/release/fakeReleasePorts.js +0 -55
  278. package/dist/runtime/sessionOwnerRegistry.js +0 -137
  279. package/dist/task/deliveryGuard.js +0 -226
  280. /package/dist/{commands/taskActor.js → task/taskAuthority.js} +0 -0
@@ -1,29 +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 { readAgentRunConfigurationObservation, unknownAgentRunConfiguration } from "./agentRunConfiguration.js";
22
27
  import { createSessionOwnerIdentity, readLinuxProcessIdentity } from "./sessionOwnerIdentity.js";
23
- import { yuiTmuxServerName, yuiTmuxSessionName } from "../tmux/tmuxManager.js";
24
- import { tmuxSocketDirectory } from "../tmux/tmuxSocketEndpoint.js";
25
- import { AGENT_HOST_CONTROL_PROTOCOL, AGENT_HOST_EVENT_PROTOCOL } from "./agentHostProtocol.js";
26
- import { FILE_TASK_CONTROLLER_PROTOCOL_VERSION } from "../core/protocol.js";
27
28
  export { AGENT_HOST_CONTROL_PROTOCOL } from "./agentHostProtocol.js";
28
29
  const HOST_CONTROL_MAX_BYTES = 32 * 1024;
29
30
  const CODEX_CLIENT_STABLE_MS = 5_000;
@@ -76,7 +77,7 @@ export async function runAgentHost(input) {
76
77
  if (payload.environment.YUI_SESSION_SCOPE === "global"
77
78
  && payload.environment.YUI_ADAPTER_ID === "codex"
78
79
  && payload.providerControl === undefined) {
79
- return runCodexInteractiveHost(input.home, payload);
80
+ return runCodexInteractiveHost(input.home, payload, openAgentHostControl);
80
81
  }
81
82
  let session;
82
83
  // This process really holds the Endpoint code its Session runs on. The lease
@@ -767,13 +768,25 @@ export async function runAgentHost(input) {
767
768
  attemptId: request.run.attemptId,
768
769
  ...authorityFields()
769
770
  }));
770
- const durableRun = hostRunControlParams(sessionPayload, session.nativeSessionId, request.authority, request.run.attemptId, request.runId);
771
+ const durableRun = { ...hostRunControlParams(sessionPayload, session.nativeSessionId, request.authority, request.run.attemptId, request.runId), boundedText: request.run.boundedText,
772
+ retrySupport: session.adapterId === "codex" ? "codex-failed-turn-v1" : "unsupported" };
773
+ let recoveryInput;
771
774
  // Registration precedes the Provider write, so its failure modes are not
772
775
  // the Provider's. A definite failure means the Provider never saw this
773
776
  // input and the occupancy must be released; anything unconfirmed leaves
774
777
  // durable state ambiguous and keeps it held.
775
778
  try {
776
- await beginDurableProviderTurn(input.home, durableRun);
779
+ const admitted = await beginDurableProviderTurn(input.home, durableRun);
780
+ if (admitted !== null && typeof admitted === "object" && !Array.isArray(admitted)) {
781
+ const retry = admitted.retryInput;
782
+ if (retry !== null && typeof retry === "object" && !Array.isArray(retry)
783
+ && typeof retry.text === "string")
784
+ recoveryInput = {
785
+ text: retry.text,
786
+ ...(typeof retry.expectedFailedNativeTurnId === "string"
787
+ ? { expectedFailedNativeTurnId: retry.expectedFailedNativeTurnId } : {})
788
+ };
789
+ }
777
790
  }
778
791
  catch (error) {
779
792
  // Registration ends in one of three states and they are not
@@ -831,7 +844,11 @@ export async function runAgentHost(input) {
831
844
  // authority and Session identity before this native write.
832
845
  const receipt = endpointReceipt(await session.submit({
833
846
  ...request.run,
834
- boundedText: withSessionContextPointer(request.run.boundedText, activeRunPayload.environment),
847
+ boundedText: withSessionContextPointer(recoveryInput?.text ?? request.run.boundedText, activeRunPayload.environment),
848
+ ...(recoveryInput === undefined ? {} : { requireQuiescent: true }),
849
+ ...(recoveryInput?.expectedFailedNativeTurnId === undefined ? {} : {
850
+ expectedFailedNativeTurnId: recoveryInput.expectedFailedNativeTurnId
851
+ }),
835
852
  inputRef: request.runId ?? request.run.attemptId
836
853
  }), request.run.attemptId);
837
854
  transportAccepted = true;
@@ -1852,7 +1869,7 @@ function hostRunControlParams(payload, nativeSessionId, authority, attemptId, ru
1852
1869
  }
1853
1870
  async function beginDurableProviderTurn(home, durableRun) {
1854
1871
  try {
1855
- await callControllerIdempotently(home, "runtime.provider-turn-begin", durableRun);
1872
+ return await callControllerIdempotently(home, "runtime.provider-turn-begin", durableRun);
1856
1873
  }
1857
1874
  catch (error) {
1858
1875
  if (error instanceof ControllerClientError && error.code === "SESSION_BUSY") {
@@ -1860,7 +1877,7 @@ async function beginDurableProviderTurn(home, durableRun) {
1860
1877
  }
1861
1878
  if (!(error instanceof ControllerAcknowledgementUnknownError))
1862
1879
  throw error;
1863
- await resolveProviderTurnSubmission(home, durableRun, new Error(`Provider Turn intent acknowledgement failed before Provider write: ${errorText(error)}`, { cause: error }));
1880
+ await resolveProviderTurnSubmission(home, durableRun, new Error(`Provider Turn intent acknowledgement failed before Provider write: ${errorText(error)}`, { cause: error }), true);
1864
1881
  // The resolve is fenced on this exact attempt id, so its success proves
1865
1882
  // the registration did commit and is now settled with nothing written to
1866
1883
  // the Provider. That is a known outcome; reporting it as unknown would
@@ -1871,7 +1888,7 @@ async function beginDurableProviderTurn(home, durableRun) {
1871
1888
  }
1872
1889
  async function callControllerIdempotently(home, method, request) {
1873
1890
  try {
1874
- await callAgentController(home, method, request);
1891
+ return await callAgentController(home, method, request);
1875
1892
  }
1876
1893
  catch (error) {
1877
1894
  if (!(error instanceof ControllerClientError)
@@ -1882,7 +1899,7 @@ async function callControllerIdempotently(home, method, request) {
1882
1899
  // These methods carry exact attempt, launch, and authority fences. A
1883
1900
  // bounded replay confirms a commit whose acknowledgement may have been lost.
1884
1901
  try {
1885
- await callAgentController(home, method, request);
1902
+ return await callAgentController(home, method, request);
1886
1903
  }
1887
1904
  catch (replayError) {
1888
1905
  if (firstCallMayHaveApplied || controllerCallMayHaveApplied(replayError)) {
@@ -1903,7 +1920,7 @@ class ControllerAcknowledgementUnknownError extends Error {
1903
1920
  class ProviderTurnRegistrationSettledError extends Error {
1904
1921
  name = "ProviderTurnRegistrationSettledError";
1905
1922
  }
1906
- async function resolveProviderTurnSubmission(home, durableRun, error) {
1923
+ async function resolveProviderTurnSubmission(home, durableRun, error, noProviderWrite = false) {
1907
1924
  const attemptId = durableRun.attemptId;
1908
1925
  if (typeof attemptId !== "string") {
1909
1926
  throw new Error("Provider Turn resolution has no attempt id.");
@@ -1915,6 +1932,7 @@ async function resolveProviderTurnSubmission(home, durableRun, error) {
1915
1932
  : error instanceof ProviderTurnBusyError ? "deferred" : "rejected",
1916
1933
  reason: errorText(error),
1917
1934
  raw: serializeAgentErrorRaw(error),
1935
+ ...(noProviderWrite || error instanceof CodexPreSubmissionError ? { providerWrite: "not-issued" } : {}),
1918
1936
  observedAt: new Date().toISOString()
1919
1937
  };
1920
1938
  try {
@@ -1935,8 +1953,7 @@ async function resolveProviderTurnSubmission(home, durableRun, error) {
1935
1953
  */
1936
1954
  async function callAgentController(home, method, params) {
1937
1955
  try {
1938
- await callController(home, method, params);
1939
- return;
1956
+ return await callController(home, method, params);
1940
1957
  }
1941
1958
  catch (error) {
1942
1959
  if (!isControllerUnavailable(error) || !isForeignHandoverLockHeld(home)) {
@@ -1948,7 +1965,7 @@ async function callAgentController(home, method, params) {
1948
1965
  await delay(50);
1949
1966
  // The pinned Host can rediscover a replacement, but must never start a
1950
1967
  // Controller using its own old implementation or open the Home's database.
1951
- await callController(home, method, params);
1968
+ return await callController(home, method, params);
1952
1969
  }
1953
1970
  function isControllerUnavailable(error) {
1954
1971
  return error instanceof ControllerClientError
@@ -1,5 +1,8 @@
1
1
  /** Provider-specific Claude Code failure recognition. */
2
2
  export function mapClaudeAgentError(input) {
3
+ return withTransientEvidence(mapClaudeDisplayError(input), input);
4
+ }
5
+ function mapClaudeDisplayError(input) {
3
6
  const text = `${input.message}\n${input.raw}`;
4
7
  if (/^No conversation found with session ID: [A-Za-z0-9-]+\.?$/imu.test(input.message)) {
5
8
  return sessionUnavailable("provider.session-not-found");
@@ -23,6 +26,9 @@ export function mapClaudeAgentError(input) {
23
26
  }
24
27
  /** Provider-specific Codex failure recognition. */
25
28
  export function mapCodexAgentError(input) {
29
+ return withTransientEvidence(mapCodexDisplayError(input), input);
30
+ }
31
+ function mapCodexDisplayError(input) {
26
32
  const text = `${input.message}\n${input.raw}`;
27
33
  if (/^server_error$/iu.test(input.message)) {
28
34
  return recoverable("availability", "provider.server-error");
@@ -200,3 +206,88 @@ function sessionUnavailable(code) {
200
206
  sessionDisposition: "unrecoverable"
201
207
  });
202
208
  }
209
+ /** Replay qualification is stricter than the readable, best-effort category.
210
+ * Never promote a number occurring in provider prose to submission safety. */
211
+ function structuredTransientError(input) {
212
+ if (/insufficient[_ -]quota|quota.{0,25}(exhaust|exceed)|billing[_ -]hard[_ -]limit|usageLimitExceeded|credits?.{0,20}(exhaust|insufficient)/iu.test(`${input.message}\n${input.raw}`))
213
+ return { category: "access", code: "provider.quota-exhausted", retryable: false };
214
+ const nodes = [];
215
+ const visit = (value, depth) => {
216
+ if (depth > 8 || value === null || typeof value !== "object" || Array.isArray(value))
217
+ return;
218
+ const node = value;
219
+ nodes.push(node);
220
+ for (const key of ["cause", "error", "data", "codexErrorInfo", "responseTooManyFailedAttempts",
221
+ "httpConnectionFailed", "responseStreamConnectionFailed", "responseStreamDisconnected", "error_details"]) {
222
+ visit(node[key], depth + 1);
223
+ }
224
+ };
225
+ try {
226
+ visit(JSON.parse(input.raw), 0);
227
+ }
228
+ catch { /* Display classification may still use prose. */ }
229
+ const codes = nodes.flatMap(n => [n.code, n.type, n.error, n.codexErrorInfo]).filter(v => typeof v === "string");
230
+ if (codes.some(c => ["authentication_error", "permission_error", "invalid_api_key", "invalid_model",
231
+ "model_not_found", "usage_limit_exceeded", "insufficient_quota"].includes(c))) {
232
+ return { category: "access", code: "provider.access-denied", retryable: false };
233
+ }
234
+ const statuses = nodes.flatMap(n => [n.httpStatusCode, n.statusCode, n.status]).filter(v => typeof v === "number");
235
+ if (statuses.some(s => s === 401 || s === 403 || s === 400 || s === 404)) {
236
+ return { category: "invalid-request", code: "provider.http-4xx", retryable: false };
237
+ }
238
+ const nativeCode = input.message.trim();
239
+ let result;
240
+ if (statuses.includes(429) || codes.includes("rate_limit_error") || nativeCode === "rate_limit_error") {
241
+ result = recoverable("rate-limit", "provider.rate-limit");
242
+ }
243
+ else if (statuses.some(s => [500, 502, 503, 504].includes(s))
244
+ || codes.some(c => ["server_error", "overloaded_error"].includes(c))
245
+ || ["server_error", "overloaded_error"].includes(nativeCode)) {
246
+ result = recoverable("availability", "provider.server-error");
247
+ }
248
+ else if (codes.some(c => ["ECONNRESET", "ECONNREFUSED", "EAI_AGAIN", "ETIMEDOUT", "EPIPE"].includes(c))) {
249
+ result = recoverable("transport", "transport.temporary-failure");
250
+ }
251
+ if (result === undefined)
252
+ return undefined;
253
+ const waits = [];
254
+ for (const node of nodes) {
255
+ for (const value of [node.retry_after_ms, node.retryAfterMs]) {
256
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0)
257
+ waits.push(value);
258
+ }
259
+ const headers = node.headers;
260
+ if (headers === null || typeof headers !== "object" || Array.isArray(headers))
261
+ continue;
262
+ const entries = Object.entries(headers);
263
+ const value = entries.find(([k]) => k.toLowerCase() === "retry-after")?.[1];
264
+ if (typeof value !== "string")
265
+ continue;
266
+ if (/^\d+(?:\.\d+)?$/u.test(value.trim()))
267
+ waits.push(Math.ceil(Number(value) * 1_000));
268
+ else {
269
+ const date = Date.parse(value);
270
+ if (Number.isFinite(date))
271
+ waits.push(Math.max(0, date - Date.now()));
272
+ }
273
+ }
274
+ const retryAfterMs = Math.max(...waits.filter(Number.isSafeInteger));
275
+ return { ...result, retryable: true,
276
+ ...(Number.isFinite(retryAfterMs) ? { retryAfterMs } : {}) };
277
+ }
278
+ /** Add positive evidence without renaming established diagnostics or letting
279
+ * a transient nested cause override a known fatal Session/request failure. */
280
+ function withTransientEvidence(base, input) {
281
+ const evidence = structuredTransientError(input);
282
+ if (evidence === undefined)
283
+ return base;
284
+ const possiblyTransient = ["rate-limit", "availability", "transport", "unknown"].includes(base.category);
285
+ if (evidence.retryable === false)
286
+ return possiblyTransient ? evidence : { ...base, retryable: false };
287
+ if (!possiblyTransient || base.sessionDisposition === "unrecoverable")
288
+ return base;
289
+ return {
290
+ ...(base.category === "unknown" ? evidence : base), retryable: true,
291
+ ...(evidence.retryAfterMs === undefined ? {} : { retryAfterMs: evidence.retryAfterMs })
292
+ };
293
+ }
@@ -1,4 +1,5 @@
1
1
  import { YUI_VERSION } from "../version.js";
2
+ import { serializeAgentErrorRaw } from "./agentError.js";
2
3
  /**
3
4
  * Preserve the native non-interactive Codex identity used by our historical
4
5
  * execution adapter. A proxy's environment cannot set the daemon's originator;
@@ -94,6 +95,10 @@ export class CodexAppServerRuntime {
94
95
  conversationId: input.conversationId,
95
96
  text: input.text,
96
97
  expectedNoActiveTurn: input.expectedNoActiveTurn,
98
+ ...(input.requireQuiescent ? { requireQuiescent: true } : {}),
99
+ ...(input.expectedFailedNativeTurnId === undefined ? {} : {
100
+ expectedFailedNativeTurnId: input.expectedFailedNativeTurnId
101
+ }),
97
102
  clientUserMessageId: input.attemptId
98
103
  });
99
104
  }
@@ -101,11 +106,13 @@ export class CodexAppServerRuntime {
101
106
  const requestedThreadId = text(input.conversationId, "Codex thread id");
102
107
  let threadId = requestedThreadId;
103
108
  try {
109
+ const expectedFailedTurn = input.expectedFailedNativeTurnId === undefined ? undefined
110
+ : text(input.expectedFailedNativeTurnId, "Expected failed Codex Turn id");
104
111
  // Submission needs current availability, not historical Turns. Some
105
112
  // App Server transports expose status without supporting history reads.
106
113
  const snapshot = await this.readConversation(requestedThreadId, { includeTurns: false });
107
114
  threadId = snapshot.threadId;
108
- if (input.expectedNoActiveTurn
115
+ if ((input.expectedNoActiveTurn || expectedFailedTurn !== undefined || input.requireQuiescent)
109
116
  && (snapshot.status === "active" || snapshot.activeTurnId !== undefined)) {
110
117
  return {
111
118
  status: "busy",
@@ -115,9 +122,30 @@ export class CodexAppServerRuntime {
115
122
  : `active-turn:${snapshot.activeTurnId}`
116
123
  };
117
124
  }
118
- if (snapshot.status !== "idle" && snapshot.status !== "active") {
125
+ if (snapshot.status !== "idle" && snapshot.status !== "active"
126
+ && !(snapshot.status === "systemError" && expectedFailedTurn !== undefined)) {
119
127
  throw new Error(`Codex Session availability is ${snapshot.status}; no input was submitted.`);
120
128
  }
129
+ if (expectedFailedTurn !== undefined) {
130
+ // systemError alone proves neither terminal execution nor permission
131
+ // to replay. Only the exact latest failed Turn permits this recovery.
132
+ const page = await this.transport.request("thread/turns/list", {
133
+ threadId, limit: 1, sortDirection: "desc", itemsView: "notLoaded"
134
+ });
135
+ const latest = object(arrayMember(page, "data")[0]);
136
+ if (latest?.id !== expectedFailedTurn || latest.status !== "failed") {
137
+ throw new Error("Codex retry has no exact failed latest Turn proof; no input was submitted.");
138
+ }
139
+ }
140
+ if (expectedFailedTurn !== undefined || input.requireQuiescent) {
141
+ const backgrounds = await this.transport.request("thread/backgroundTerminals/list", {
142
+ threadId, limit: 1
143
+ });
144
+ if (!Array.isArray(backgrounds.data) || backgrounds.data.length !== 0
145
+ || backgrounds.nextCursor !== null) {
146
+ throw new Error("Codex retry background execution is not proven empty; no input was submitted.");
147
+ }
148
+ }
121
149
  }
122
150
  catch (error) {
123
151
  throw new CodexPreSubmissionError("Codex Session inspection failed before input submission.", { cause: error });
@@ -304,7 +332,10 @@ function parseThreadSnapshot(result, expectedThreadId, loaded) {
304
332
  turnId,
305
333
  ...(status === undefined ? {} : { status }),
306
334
  ...(output === undefined ? {} : { output }),
307
- ...(error === undefined ? {} : { error })
335
+ ...(error === undefined ? {} : { error }),
336
+ ...(turn.error === undefined || turn.error === null ? {} : {
337
+ rawError: serializeAgentErrorRaw(turn.error)
338
+ })
308
339
  }];
309
340
  });
310
341
  return {
@@ -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
  }
@@ -14,7 +14,11 @@ export class FencedProviderControl {
14
14
  conversationId: input.fence.conversationId,
15
15
  attemptId: identity(input.attemptId, "Provider input attempt id"),
16
16
  text: text(input.text, "Provider Turn input"),
17
- expectedNoActiveTurn: input.expectedNoActiveTurn ?? true
17
+ expectedNoActiveTurn: input.expectedNoActiveTurn ?? true,
18
+ ...(input.requireQuiescent ? { requireQuiescent: true } : {}),
19
+ ...(input.expectedFailedNativeTurnId === undefined ? {} : {
20
+ expectedFailedNativeTurnId: identity(input.expectedFailedNativeTurnId, "Expected failed Provider Turn id")
21
+ })
18
22
  });
19
23
  }
20
24
  async interruptTurn(input) {
@@ -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
+ }