@zq-silk/yui 0.15.7 → 0.15.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. package/ARCHITECTURE.md +194 -399
  2. package/ARCHITECTURE.zh-CN.md +151 -0
  3. package/README.md +306 -1131
  4. package/dist/agent/adapterCatalog.js +15 -2
  5. package/dist/agent/agent.js +23 -3
  6. package/dist/agent/argumentPolicy.js +7 -1
  7. package/dist/agent/connectionPlan.js +62 -0
  8. package/dist/agent/executionComponents.js +158 -0
  9. package/dist/agent/launchEnvironment.js +31 -3
  10. package/dist/agent/managedRuntimeEnvironment.js +3 -5
  11. package/dist/{turn/turn.js → agentRun/agentRun.js} +166 -109
  12. package/dist/{turn/turnIdentity.js → agentRun/runIdentity.js} +4 -4
  13. package/dist/artifacts/artifactCapability.js +74 -0
  14. package/dist/artifacts/artifactCommitLock.js +249 -0
  15. package/dist/artifacts/artifactPaths.js +151 -0
  16. package/dist/artifacts/gitArtifactRef.js +146 -0
  17. package/dist/artifacts/managedGit.js +332 -0
  18. package/dist/artifacts/taskArtifactRepository.js +277 -0
  19. package/dist/brief/taskBrief.js +12 -0
  20. package/dist/cli/agentConfigurationPicker.js +13 -0
  21. package/dist/cli/commandCatalog.js +165 -74
  22. package/dist/cli/interactionCandidates.js +5 -5
  23. package/dist/cli/interactionPolicy.js +38 -8
  24. package/dist/cli/invocationRouter.js +1 -1
  25. package/dist/cli/managedDiagnostics.js +28 -0
  26. package/dist/cli/operatorWizard.js +1 -7
  27. package/dist/cli/roleOptionOrder.js +27 -0
  28. package/dist/cli/roleWizard.js +50 -14
  29. package/dist/cli/updateOrchestrator.js +1 -1
  30. package/dist/cli/updatePorts.js +3 -4
  31. package/dist/cli.js +245 -95
  32. package/dist/commands/agentCommands.js +72 -14
  33. package/dist/commands/capabilityCommands.js +9 -6
  34. package/dist/commands/configCommands.js +20 -20
  35. package/dist/commands/deliveryGuardPreflight.js +2 -2
  36. package/dist/commands/executionAuditCommands.js +24 -24
  37. package/dist/commands/globalRoleCommands.js +1 -1
  38. package/dist/commands/grantCommands.js +4 -4
  39. package/dist/commands/operatorCommands.js +34 -9
  40. package/dist/commands/projectCommands.js +4 -4
  41. package/dist/commands/resourcesCommands.js +2 -2
  42. package/dist/commands/roleConfiguration.js +25 -5
  43. package/dist/commands/roleRuntimeGuard.js +4 -5
  44. package/dist/commands/sessionCommands.js +3 -7
  45. package/dist/commands/taskActivationCommands.js +281 -0
  46. package/dist/commands/taskActor.js +28 -49
  47. package/dist/commands/taskCommands.js +1461 -720
  48. package/dist/commands/taskContextCommand.js +39 -583
  49. package/dist/commands/taskExecutionCommands.js +32 -32
  50. package/dist/commands/taskInputCommands.js +40 -104
  51. package/dist/commands/taskIntegrationCommands.js +3 -2
  52. package/dist/commands/taskIntegrationQueueCommands.js +1 -1
  53. package/dist/commands/taskNextActionCommand.js +8 -8
  54. package/dist/commands/taskOverviewCommand.js +33 -45
  55. package/dist/commands/taskRemoteDeliveryCommand.js +2 -2
  56. package/dist/commands/taskRoleRuntimeStatus.js +133 -102
  57. package/dist/commands/telemetryCommands.js +36 -38
  58. package/dist/config/configCatalog.js +4 -4
  59. package/dist/config/yuiConfig.js +8 -8
  60. package/dist/context/contextSnapshot.js +10 -10
  61. package/dist/context/dispatchContext.js +11 -11
  62. package/dist/context/roleSessionContext.js +6 -3
  63. package/dist/context/{turnContextPack.js → runContextPack.js} +158 -81
  64. package/dist/context/{turnInputContract.js → runInputContract.js} +73 -60
  65. package/dist/context/sessionBootstrapManifest.js +21 -2
  66. package/dist/context/sourceRunContext.js +30 -0
  67. package/dist/context/taskContext.js +481 -0
  68. package/dist/context/wakeNotification.js +27 -27
  69. package/dist/controller/agentRuntimeObserver.js +21 -24
  70. package/dist/controller/capabilityBridge.js +17 -6
  71. package/dist/controller/clientRuntime.js +65 -92
  72. package/dist/controller/controller.js +120 -188
  73. package/dist/controller/fileSchedulerStoreAdapter.js +787 -887
  74. package/dist/controller/jobControl.js +54 -85
  75. package/dist/controller/resourceInventory.js +8 -27
  76. package/dist/controller/resourceInventoryLinux.js +12 -13
  77. package/dist/controller/runtime.js +529 -479
  78. package/dist/controller/runtimeEventInbox.js +55 -25
  79. package/dist/controller/runtimeEventProcessor.js +22 -31
  80. package/dist/controller/{runtimeHookTurnFence.js → runtimeHookRunFence.js} +91 -115
  81. package/dist/controller/runtimeLaunchCoordinator.js +80 -426
  82. package/dist/controller/runtimeObservationHook.js +14 -18
  83. package/dist/controller/sessionNotify.js +16 -24
  84. package/dist/controller/sessionOwnerReconciliation.js +168 -50
  85. package/dist/controller/structuredProviderObservation.js +138 -99
  86. package/dist/coordination/workMailbox.js +3 -3
  87. package/dist/coordination/workMailboxQueue.js +36 -33
  88. package/dist/core/boundedRpc.js +8 -1
  89. package/dist/core/controllerClient.js +20 -1
  90. package/dist/core/controllerServer.js +4 -4
  91. package/dist/doctor/doctor.js +13 -2
  92. package/dist/domain/agentResultTransport.js +9 -9
  93. package/dist/execution/codexThreadNaming.js +2 -8
  94. package/dist/execution/executionHealth.js +51 -63
  95. package/dist/execution/reviewMainRun.js +137 -0
  96. package/dist/execution/workItemExecution.js +28 -29
  97. package/dist/execution/workItemExecutionProjection.js +99 -107
  98. package/dist/execution/workItemMainRun.js +141 -0
  99. package/dist/executor/agentAdapter.js +227 -20
  100. package/dist/executor/agentConfigurationCatalog.js +126 -4
  101. package/dist/executor/agentConfigurationProbe.js +162 -4
  102. package/dist/executor/agentExecutor.js +79 -78
  103. package/dist/executor/effectiveLaunch.js +105 -18
  104. package/dist/executor/executorRegistry.js +29 -44
  105. package/dist/executor/fileRoleLaunchPlanner.js +229 -154
  106. package/dist/executor/workspacePreflightClassification.js +16 -16
  107. package/dist/grant/capabilityGrant.js +6 -3
  108. package/dist/input/inputRequest.js +12 -10
  109. package/dist/integration/gitIntegrationService.js +4 -11
  110. package/dist/integration/integrationQueueService.js +4 -4
  111. package/dist/interaction/operatorPresentation.js +1 -1
  112. package/dist/kernel/builtinCapabilities.js +255 -12
  113. package/dist/kernel/capabilityRegistry.js +64 -18
  114. package/dist/kernel/instanceHost.js +12 -1
  115. package/dist/kernel/kernelPorts.js +2 -2
  116. package/dist/lifecycle/canonicalLifecycleEvent.js +44 -49
  117. package/dist/lifecycle/exactRunTerminalization.js +449 -0
  118. package/dist/message/message.js +118 -6
  119. package/dist/message/messageContinuation.js +204 -0
  120. package/dist/observability/executionAudit.js +70 -72
  121. package/dist/observability/faultClassification.js +2 -2
  122. package/dist/observability/orchestrationMetrics.js +8 -8
  123. package/dist/operator/operatorSessionHistory.js +1 -7
  124. package/dist/output/agentConfigurationPresentation.js +8 -3
  125. package/dist/output/agentRunConfigurationPresentation.js +128 -0
  126. package/dist/output/rolePresentation.js +54 -3
  127. package/dist/plugins/pluginChild.js +104 -0
  128. package/dist/plugins/pluginIntent.js +26 -0
  129. package/dist/plugins/pluginInterpreter.js +43 -0
  130. package/dist/plugins/pluginPackage.js +101 -0
  131. package/dist/plugins/pluginProcess.js +112 -0
  132. package/dist/plugins/pluginService.js +388 -0
  133. package/dist/profile/agentProfile.js +1 -1
  134. package/dist/repository/gitWorkspace.js +26 -4
  135. package/dist/repository/project.js +19 -4
  136. package/dist/repository/taskBaseFreshness.js +13 -13
  137. package/dist/repository/taskWorkspaceCoordinator.js +20 -27
  138. package/dist/repository/taskWorkspacePreparer.js +344 -83
  139. package/dist/resources/autoResourceGc.js +3 -3
  140. package/dist/resources/liveReferences.js +3 -3
  141. package/dist/resources/projectResource.js +75 -0
  142. package/dist/resources/projectResourceService.js +343 -0
  143. package/dist/resources/resourceDiscovery.js +6 -6
  144. package/dist/resources/resourceGc.js +1 -1
  145. package/dist/resources/resourceRegistrar.js +1 -1
  146. package/dist/resources/resourceTypes.js +1 -1
  147. package/dist/review/deltaRecheck.js +3 -3
  148. package/dist/review/reviewAcceptance.js +16 -16
  149. package/dist/review/reviewDecision.js +7 -7
  150. package/dist/review/reviewRound.js +21 -20
  151. package/dist/review/reviewerAvailability.js +2 -2
  152. package/dist/role/role.js +51 -7
  153. package/dist/role/taskRoleUpdate.js +30 -0
  154. package/dist/runtime/acpProtocol.js +425 -0
  155. package/dist/runtime/acpSession.js +731 -0
  156. package/dist/runtime/acpSessionConfiguration.js +260 -0
  157. package/dist/runtime/agentDriver.js +30 -11
  158. package/dist/runtime/agentEndpoint.js +278 -0
  159. package/dist/runtime/agentEndpointIdentity.js +86 -0
  160. package/dist/runtime/agentEndpointOwnership.js +239 -0
  161. package/dist/runtime/agentError.js +2 -10
  162. package/dist/runtime/agentHost.js +565 -314
  163. package/dist/runtime/agentRunConfiguration.js +258 -0
  164. package/dist/runtime/builtinAgentDrivers.js +134 -18
  165. package/dist/runtime/builtinAgentErrorMappers.js +55 -3
  166. package/dist/runtime/builtinTranscriptUsage.js +1 -1
  167. package/dist/runtime/claude-process-owner +0 -0
  168. package/dist/runtime/codexAppServerRuntime.js +38 -30
  169. package/dist/runtime/codexInteractiveHost.js +41 -6
  170. package/dist/runtime/continuationManager.js +2 -6
  171. package/dist/runtime/executionEnvironment.js +30 -0
  172. package/dist/runtime/firstProgressAdvisory.js +11 -11
  173. package/dist/runtime/index.js +4 -3
  174. package/dist/runtime/jsonLineChannel.js +109 -0
  175. package/dist/runtime/launchBroker.js +91 -16
  176. package/dist/runtime/launchDiagnostics.js +2 -2
  177. package/dist/runtime/lifecycleReservation.js +10 -18
  178. package/dist/runtime/managedCaller.js +61 -17
  179. package/dist/runtime/nativeSessionControl.js +102 -0
  180. package/dist/runtime/ports.js +6 -21
  181. package/dist/runtime/processExitObservation.js +8 -7
  182. package/dist/runtime/promptEnvelope.js +17 -6
  183. package/dist/runtime/providerContinuation.js +3 -9
  184. package/dist/runtime/providerContinuationReconciliationService.js +4 -13
  185. package/dist/runtime/providerControl.js +2 -7
  186. package/dist/runtime/providerRuntimeIdentity.js +110 -222
  187. package/dist/runtime/providerRuntimeReconciler.js +5 -9
  188. package/dist/runtime/runtimeBinding.js +0 -1
  189. package/dist/runtime/runtimeContinuationProjection.js +4 -7
  190. package/dist/runtime/runtimeDeadlines.js +9 -0
  191. package/dist/runtime/runtimeHealthPolicy.js +1 -1
  192. package/dist/runtime/runtimeObservation.js +29 -65
  193. package/dist/runtime/runtimeProjection.js +43 -51
  194. package/dist/runtime/runtimeSessionCandidate.js +1 -3
  195. package/dist/runtime/sessionLaunchRequest.js +3 -7
  196. package/dist/runtime/sessionOwnerIdentity.js +7 -54
  197. package/dist/runtime/sessionOwnerRegistry.js +22 -17
  198. package/dist/runtime/sessionReconciliation.js +4 -8
  199. package/dist/runtime/sessionTerminationGuard.js +70 -259
  200. package/dist/runtime/sessionTokenMetrics.js +5 -16
  201. package/dist/runtime/structuredProviderHost.js +237 -117
  202. package/dist/runtime/taskRuntimeIsolation.js +39 -122
  203. package/dist/runtime/tmuxAdapters.js +39 -86
  204. package/dist/scheduler/activeRoleRunDelivery.js +354 -0
  205. package/dist/scheduler/leaderWakeupProcessor.js +75 -266
  206. package/dist/scheduler/operatorInputNotificationProcessor.js +1 -1
  207. package/dist/scheduler/ports.js +80 -9
  208. package/dist/scheduler/{roleTurnLiveness.js → roleRunLiveness.js} +26 -30
  209. package/dist/scheduler/{roleTurnStall.js → roleRunStall.js} +128 -139
  210. package/dist/scheduler/taskExecutionProjection.js +120 -124
  211. package/dist/scheduler/taskObservabilityProjection.js +29 -29
  212. package/dist/scheduler/taskWake.js +11 -4
  213. package/dist/scheduler/wakeReason.js +9 -1
  214. package/dist/setup/setupCommand.js +3 -7
  215. package/dist/storage/migrations/agentRunContract.js +159 -0
  216. package/dist/storage/migrations/artifactsToGit.js +338 -0
  217. package/dist/storage/migrations/removeRuntimeGeneration.js +207 -0
  218. package/dist/storage/migrations/submitIntent.js +126 -0
  219. package/dist/storage/sqliteSchema.js +467 -7
  220. package/dist/storage/sqliteStore.js +355 -220
  221. package/dist/storage/storageVersions.js +1 -1
  222. package/dist/storage/storeRpc.js +10 -5
  223. package/dist/storage/taskStore.js +13 -11
  224. package/dist/storage/upgrade/upgradeOrchestrator.js +5 -7
  225. package/dist/surface/surfaceContributions.js +102 -0
  226. package/dist/task/completionReadiness.js +32 -6
  227. package/dist/task/deliveryGuard.js +16 -16
  228. package/dist/task/draftPlan.js +72 -12
  229. package/dist/task/nextAction.js +144 -128
  230. package/dist/task/remoteDelivery.js +6 -6
  231. package/dist/task/task.js +184 -18
  232. package/dist/task/taskActivation.js +327 -0
  233. package/dist/task/taskActivationService.js +408 -0
  234. package/dist/task/taskRecordReference.js +5 -4
  235. package/dist/task/taskRecordRetirement.js +1 -1
  236. package/dist/task/taskSubmission.js +236 -0
  237. package/dist/telemetry/sqliteTelemetryStore.js +55 -68
  238. package/dist/telemetry/telemetryConfig.js +14 -14
  239. package/dist/telemetry/telemetryWiring.js +2 -2
  240. package/dist/web/assets/assetManifest.js +2 -0
  241. package/dist/web/assets/client/app.js +121 -20
  242. package/dist/web/assets/client/components.js +87 -54
  243. package/dist/web/assets/client/i18n.js +83 -41
  244. package/dist/web/assets/client/markdown.js +1 -1
  245. package/dist/web/assets/client/taskSurface.js +442 -0
  246. package/dist/web/assets/client/view.js +49 -44
  247. package/dist/web/assets/shell.js +1 -1
  248. package/dist/web/assets/styles/cards.js +22 -4
  249. package/dist/web/controllerWeb.js +60 -0
  250. package/dist/web/webMutation.js +28 -0
  251. package/dist/web/webServer.js +133 -8
  252. package/dist/web/webSnapshot.js +81 -74
  253. package/dist/web/webTaskSurface.js +64 -0
  254. package/dist/workItem/dependencyGate.js +1 -1
  255. package/dist/workItem/workItem.js +84 -48
  256. package/dist/workspace/workItemChangeSetManager.js +16 -9
  257. package/docs/agent-result-consumption.md +96 -0
  258. package/docs/agent-result-consumption.zh-CN.md +81 -0
  259. package/docs/agent-runtime-drivers.md +93 -0
  260. package/docs/agent-runtime-drivers.zh-CN.md +77 -0
  261. package/docs/architecture/README.md +50 -0
  262. package/docs/architecture/README.zh-CN.md +43 -0
  263. package/docs/architecture/capabilities-and-resources.md +118 -0
  264. package/docs/architecture/capabilities-and-resources.zh-CN.md +83 -0
  265. package/docs/managed-turn-and-session-runtime.md +224 -0
  266. package/docs/managed-turn-and-session-runtime.zh-CN.md +180 -0
  267. package/docs/observability/README.md +83 -0
  268. package/docs/observability/README.zh-CN.md +71 -0
  269. package/docs/plugin-sdk.md +393 -0
  270. package/docs/plugin-sdk.zh-CN.md +293 -0
  271. package/docs/provider-runtime.md +165 -0
  272. package/docs/provider-runtime.zh-CN.md +132 -0
  273. package/docs/release-workflow.md +305 -0
  274. package/docs/release-workflow.zh-CN.md +237 -0
  275. package/docs/roles-and-configuration.md +115 -0
  276. package/docs/roles-and-configuration.zh-CN.md +96 -0
  277. package/docs/sqlite-control-plane-design.md +78 -0
  278. package/docs/sqlite-control-plane-design.zh-CN.md +62 -0
  279. package/docs/task-dag-semantics.md +80 -0
  280. package/docs/task-dag-semantics.zh-CN.md +59 -0
  281. package/docs/task-delivery.md +105 -0
  282. package/docs/task-delivery.zh-CN.md +82 -0
  283. package/docs/task-local-identity.md +8 -6
  284. package/docs/task-local-identity.zh-CN.md +58 -0
  285. package/docs/testing/verification-levels.md +88 -0
  286. package/docs/testing/verification-levels.zh-CN.md +69 -0
  287. package/i18n/README.zh-CN.md +270 -722
  288. package/package.json +3 -2
  289. package/skills/yui-leader/SKILL.md +88 -304
  290. package/skills/yui-leader/references/execution.md +303 -0
  291. package/skills/yui-leader/references/integration.md +39 -0
  292. package/skills/yui-leader/references/planning.md +109 -0
  293. package/skills/yui-leader/references/replicated-execution.md +42 -0
  294. package/skills/yui-leader/references/task-plugins.md +37 -0
  295. package/skills/yui-operator/SKILL.md +46 -62
  296. package/skills/yui-reviewer/SKILL.md +35 -36
  297. package/skills/yui-runtime/SKILL.md +88 -24
  298. package/skills/yui-runtime/references/publication.md +22 -0
  299. package/skills/yui-runtime/references/recovery.md +64 -0
  300. package/skills/yui-worker/SKILL.md +37 -39
  301. package/dist/cli/roleOptionCatalog.js +0 -68
  302. package/dist/context/sourceTurnContext.js +0 -30
  303. package/dist/execution/reviewMainTurn.js +0 -161
  304. package/dist/execution/workItemMainTurn.js +0 -164
  305. package/dist/lifecycle/exactTurnTerminalization.js +0 -407
  306. package/dist/runtime/preallocatedNativeSession.js +0 -13
  307. package/dist/runtime/runtimeStopReceipt.js +0 -42
  308. package/dist/scheduler/activeRoleTurnDelivery.js +0 -315
@@ -0,0 +1,258 @@
1
+ /**
2
+ * What a live Agent Session can be asked about the run configuration it is
3
+ * actually operating under.
4
+ *
5
+ * Yui already records what a launch *requested*: a Role's model, reasoning
6
+ * effort and permission strategy resolve into an effective launch snapshot that
7
+ * every `show` surface prints. That snapshot is an expectation, and it is
8
+ * complete on its own terms. What it cannot answer is whether the Agent agreed:
9
+ * a requested model the Agent does not offer, a permission mode it silently
10
+ * substituted, or an axis it reset when a later call landed are all invisible to
11
+ * a record written before the process started.
12
+ *
13
+ * This is the read path for that second question, and it is deliberately
14
+ * separate from the first. Presenting configuration expectation as execution
15
+ * fact is the specific failure this vocabulary exists to prevent, so every
16
+ * value here carries how it was learned, and the three ways of not knowing stay
17
+ * distinct instead of collapsing into one blank:
18
+ *
19
+ * - `unknown` means nobody could be asked. There is no live Session, or the
20
+ * Session exists but could not be reached. It says nothing about the Agent.
21
+ * - `unsupported` means this Session implementation has no observation reader.
22
+ * It does not claim the underlying product can never report these facts.
23
+ * - `observed` carries what the Agent itself reported, and only that.
24
+ *
25
+ * Nothing here performs I/O or holds a product name. A Session that can answer
26
+ * projects its own protocol's report into this shape; a Session that cannot
27
+ * returns the `unsupported` branch. Reading it never sends a protocol message,
28
+ * because a query that configured or prompted the Agent would change the thing
29
+ * it claims to describe.
30
+ */
31
+ /**
32
+ * The answer when there is no live Session to ask, or it could not be reached.
33
+ *
34
+ * Kept apart from `unsupported` because the two would otherwise both render as
35
+ * "no data" while meaning opposite things: this one says Yui did not get an
36
+ * answer, the other says the Agent has none to give.
37
+ */
38
+ export function unknownAgentRunConfiguration(reason) {
39
+ return Object.freeze({ status: "unknown", reason });
40
+ }
41
+ /**
42
+ * The answer for a Session implementation without a run-configuration reader.
43
+ *
44
+ * Stated once so the two implementations that share this position cannot drift
45
+ * into describing it differently, and so the reason travels with the status
46
+ * instead of being reconstructed by whoever renders it.
47
+ */
48
+ export function unsupportedAgentRunConfiguration(protocolDescription) {
49
+ return Object.freeze({
50
+ status: "unsupported",
51
+ reason: `${protocolDescription}: this Yui Session implementation exposes no run configuration observation, so Yui cannot `
52
+ + `confirm which model, reasoning effort or permission mode this Session is `
53
+ + `operating under. See the Session's pinned launch request; current Role settings may differ.`
54
+ });
55
+ }
56
+ /**
57
+ * Project a negotiated capability exchange into the shared handshake shape.
58
+ *
59
+ * The parameter is described structurally rather than by naming a protocol type,
60
+ * so this module stays free of any one protocol while still being the single
61
+ * place the projection happens. That matters because the two callers learn the
62
+ * same facts at different moments — a capability probe before any Session
63
+ * exists, and a live Session at launch — and a second copy of this mapping would
64
+ * let `yui config agent capabilities` and a Session inspect disagree about the
65
+ * same Agent's advertised capabilities.
66
+ *
67
+ * Only enabled capabilities are listed, and a silent Agent stays `unknown`
68
+ * rather than being resolved into a product by anything Yui knows about the
69
+ * command it ran.
70
+ */
71
+ export function handshakeObservationFrom(negotiated) {
72
+ return Object.freeze({
73
+ status: "observed",
74
+ protocolVersion: negotiated.protocolVersion,
75
+ agentName: negotiated.agentName ?? "unknown",
76
+ agentVersion: negotiated.agentVersion ?? "unknown",
77
+ capabilities: Object.freeze(Object.entries(negotiated.capabilities)
78
+ .filter(([, enabled]) => enabled)
79
+ .map(([name]) => name)
80
+ .sort()),
81
+ authMethods: Object.freeze(negotiated.authMethods.map((method) => method.id).sort())
82
+ });
83
+ }
84
+ /**
85
+ * Read an observation back from a parsed control response.
86
+ *
87
+ * This value is produced inside the Agent Host and read by a CLI process, so it
88
+ * arrives as untyped JSON from another program. A malformed one must not
89
+ * degrade into a confident-looking partial reading: an entry missing its
90
+ * confirmation would render as a blank cell that looks like agreement. So
91
+ * anything that does not parse becomes `unknown` with the reason saying so,
92
+ * which is the same answer as a Session that could not be reached — because
93
+ * that is exactly what it is.
94
+ */
95
+ export function readAgentRunConfigurationObservation(value) {
96
+ const malformed = unknownAgentRunConfiguration("The Agent Host reported run configuration in a shape this build does not "
97
+ + "recognize, so nothing about the live Session's configuration can be shown.");
98
+ const observation = asRecord(value);
99
+ if (observation === undefined)
100
+ return malformed;
101
+ if (observation.status === "unknown" || observation.status === "unsupported") {
102
+ const reason = text(observation.reason);
103
+ if (reason === undefined)
104
+ return malformed;
105
+ return Object.freeze({ status: observation.status, reason });
106
+ }
107
+ if (observation.status !== "observed")
108
+ return malformed;
109
+ const observedAt = text(observation.observedAt);
110
+ const handshake = readHandshake(observation.handshake);
111
+ if (observedAt === undefined || !Number.isFinite(Date.parse(observedAt))
112
+ || handshake === undefined)
113
+ return malformed;
114
+ if (!Array.isArray(observation.requested) || !Array.isArray(observation.axes))
115
+ return malformed;
116
+ const requested = [];
117
+ for (const entry of observation.requested) {
118
+ const request = readRequest(entry);
119
+ // One unreadable entry cannot be skipped: the list would then look complete
120
+ // while silently omitting a requested value, which is the difference between
121
+ // "not requested" and "requested, outcome lost".
122
+ if (request === undefined)
123
+ return malformed;
124
+ requested.push(request);
125
+ }
126
+ const axes = [];
127
+ for (const entry of observation.axes) {
128
+ const axis = readAxis(entry);
129
+ if (axis === undefined)
130
+ return malformed;
131
+ axes.push(axis);
132
+ }
133
+ return Object.freeze({
134
+ status: "observed",
135
+ observedAt,
136
+ handshake,
137
+ requested: Object.freeze(requested),
138
+ axes: Object.freeze(axes)
139
+ });
140
+ }
141
+ function readRequest(value) {
142
+ const entry = asRecord(value);
143
+ if (entry === undefined)
144
+ return undefined;
145
+ const field = entry.field;
146
+ const key = text(entry.key);
147
+ const requestedValue = text(entry.value);
148
+ const confirmation = entry.confirmation;
149
+ if (field !== "model" && field !== "effort" && field !== "permission")
150
+ return undefined;
151
+ if (key === undefined || requestedValue === undefined)
152
+ return undefined;
153
+ if (confirmation !== "already" && confirmation !== "observed" && confirmation !== "acknowledged") {
154
+ return undefined;
155
+ }
156
+ const current = readCurrentValue(entry.current);
157
+ if (current === undefined)
158
+ return undefined;
159
+ return Object.freeze({ field, key, value: requestedValue, confirmation, current });
160
+ }
161
+ /**
162
+ * Read the current value and its evidence, shared by both tables.
163
+ *
164
+ * One reader because one shape: an axis and a requested value answer the same
165
+ * question about evidence, and a second implementation is where the two would
166
+ * eventually come to disagree about what counts as observed.
167
+ */
168
+ function readCurrentValue(value) {
169
+ const current = asRecord(value);
170
+ if (current === undefined)
171
+ return undefined;
172
+ if (current.status === "observed") {
173
+ const observed = text(current.value);
174
+ return observed === undefined
175
+ ? undefined
176
+ : Object.freeze({ status: "observed", value: observed });
177
+ }
178
+ if (current.status !== "unobserved")
179
+ return undefined;
180
+ const reason = text(current.reason);
181
+ return reason === undefined ? undefined : Object.freeze({ status: "unobserved", reason });
182
+ }
183
+ function readAxis(value) {
184
+ const entry = asRecord(value);
185
+ if (entry === undefined)
186
+ return undefined;
187
+ const key = text(entry.key);
188
+ const current = readCurrentValue(entry.current);
189
+ if (key === undefined || current === undefined)
190
+ return undefined;
191
+ if (!Array.isArray(entry.offered))
192
+ return undefined;
193
+ const offered = [];
194
+ for (const candidate of entry.offered) {
195
+ const offer = text(candidate);
196
+ if (offer === undefined)
197
+ return undefined;
198
+ offered.push(offer);
199
+ }
200
+ const category = text(entry.category);
201
+ return Object.freeze({
202
+ key,
203
+ ...(category === undefined ? {} : { category }),
204
+ current,
205
+ offered: Object.freeze(offered)
206
+ });
207
+ }
208
+ function readHandshake(value) {
209
+ const handshake = asRecord(value);
210
+ if (handshake === undefined)
211
+ return undefined;
212
+ if (handshake.status === "unsupported") {
213
+ const reason = text(handshake.reason);
214
+ return reason === undefined ? undefined : Object.freeze({ status: "unsupported", reason });
215
+ }
216
+ if (handshake.status !== "observed")
217
+ return undefined;
218
+ const protocolVersion = handshake.protocolVersion;
219
+ const agentName = text(handshake.agentName);
220
+ const agentVersion = text(handshake.agentVersion);
221
+ if (typeof protocolVersion !== "number" || !Number.isSafeInteger(protocolVersion))
222
+ return undefined;
223
+ if (agentName === undefined || agentVersion === undefined)
224
+ return undefined;
225
+ if (!Array.isArray(handshake.capabilities) || !Array.isArray(handshake.authMethods)) {
226
+ return undefined;
227
+ }
228
+ const capabilities = [];
229
+ for (const candidate of handshake.capabilities) {
230
+ const capability = text(candidate);
231
+ if (capability === undefined)
232
+ return undefined;
233
+ capabilities.push(capability);
234
+ }
235
+ const authMethods = [];
236
+ for (const candidate of handshake.authMethods) {
237
+ const method = text(candidate);
238
+ if (method === undefined)
239
+ return undefined;
240
+ authMethods.push(method);
241
+ }
242
+ return Object.freeze({
243
+ status: "observed",
244
+ protocolVersion,
245
+ agentName,
246
+ agentVersion,
247
+ capabilities: Object.freeze(capabilities),
248
+ authMethods: Object.freeze(authMethods)
249
+ });
250
+ }
251
+ function asRecord(value) {
252
+ return value !== null && typeof value === "object" && !Array.isArray(value)
253
+ ? value
254
+ : undefined;
255
+ }
256
+ function text(value) {
257
+ return typeof value === "string" && value.length > 0 ? value : undefined;
258
+ }
@@ -1,10 +1,16 @@
1
1
  import { AgentDriverRegistry } from "./agentDriver.js";
2
2
  import { claudeTranscriptObserver, codexTranscriptObserver, transcriptObserverSource } from "./builtinTranscriptObserver.js";
3
- import { mapClaudeAgentError, mapCodexAgentError } from "./builtinAgentErrorMappers.js";
3
+ import { mapAcpAgentError, mapClaudeAgentError, mapCodexAgentError } from "./builtinAgentErrorMappers.js";
4
4
  import { serializeAgentErrorRaw, standardAgentError } from "./agentError.js";
5
5
  import { transportAgentResult } from "../domain/agentResultTransport.js";
6
6
  export const CODEX_DRIVER_ID = "openai/codex";
7
7
  export const CLAUDE_CODE_DRIVER_ID = "anthropic/claude-code";
8
+ /**
9
+ * The Agent Client Protocol Driver is named after the protocol, not a product:
10
+ * every ACP Agent is observed through this one entry, so adding a second ACP
11
+ * CLI needs a launch descriptor and no new Driver.
12
+ */
13
+ export const ACP_DRIVER_ID = "acp/agent-client-protocol";
8
14
  export function builtinDriverIdForAdapter(adapterId) {
9
15
  return builtinAgentDriverRegistry().requireByAdapterId(adapterId).id;
10
16
  }
@@ -27,6 +33,9 @@ const STRUCTURED_CLI_CAPABILITIES = Object.freeze({
27
33
  resume: true,
28
34
  sendTurn: true,
29
35
  interrupt: true,
36
+ // Conservative default: a Driver that has not stated otherwise is assumed
37
+ // to cancel by stopping the process Yui owns.
38
+ interruptDelivery: "owned-process",
30
39
  stop: true
31
40
  }),
32
41
  conversation: Object.freeze({
@@ -94,7 +103,6 @@ export const BUILTIN_AGENT_DRIVERS = Object.freeze([
94
103
  terminal: isTerminalHook(hookEventName),
95
104
  ...(hookEventName !== "SubagentStop" ? {} : {
96
105
  continuationId: subagentId(payload),
97
- continuationGeneration: continuationGeneration(payload)
98
106
  })
99
107
  }),
100
108
  observer: Object.freeze({
@@ -123,6 +131,12 @@ export const BUILTIN_AGENT_DRIVERS = Object.freeze([
123
131
  acceptance: "exact",
124
132
  idempotency: "unavailable"
125
133
  }),
134
+ control: Object.freeze({
135
+ ...STRUCTURED_CLI_CAPABILITIES.control,
136
+ // Managed Codex interrupts its Turn through the App Server, which
137
+ // leaves the Session (and its process) alive.
138
+ interruptDelivery: "native"
139
+ }),
126
140
  descendants: Object.freeze({
127
141
  lineage: "partial",
128
142
  detachedQuery: "partial",
@@ -152,7 +166,6 @@ export const BUILTIN_AGENT_DRIVERS = Object.freeze([
152
166
  terminal: isTerminalHook(hookEventName),
153
167
  ...(hookEventName !== "SubagentStop" ? {} : {
154
168
  continuationId: subagentId(payload),
155
- continuationGeneration: continuationGeneration(payload)
156
169
  })
157
170
  }),
158
171
  observer: Object.freeze({
@@ -160,6 +173,119 @@ export const BUILTIN_AGENT_DRIVERS = Object.freeze([
160
173
  sample: codexTranscriptObserver
161
174
  })
162
175
  })
176
+ }),
177
+ Object.freeze({
178
+ id: ACP_DRIVER_ID,
179
+ label: "Agent Client Protocol",
180
+ protocolVersion: 1,
181
+ adapterId: "acp",
182
+ /**
183
+ * Declared from ACP v1 itself, not from any product's abilities.
184
+ *
185
+ * ACP is a client-driven JSON-RPC protocol: Yui owns the pipe and learns
186
+ * everything from request/response pairs, so there is no Hook ingress and
187
+ * no transcript file to sample. Several capabilities are therefore
188
+ * genuinely unavailable rather than merely unimplemented, and saying so is
189
+ * what keeps managed admission fail-closed.
190
+ */
191
+ capabilities: Object.freeze({
192
+ // No interactive surface: `acp` mode is a machine protocol on stdio.
193
+ surfaces: Object.freeze(["managed-protocol"]),
194
+ lifecycle: Object.freeze({
195
+ host: "persistent",
196
+ providerProcess: "persistent",
197
+ // `session/load` is ACP's exact Conversation resume, so the protocol
198
+ // does define one and managed admission — which runs adapter-wide,
199
+ // before any connection exists — is right to see it here. What a
200
+ // *given* Agent implements is negotiated per connection via
201
+ // `agentCapabilities.loadSession`, and that answer cannot be predicted
202
+ // by a static table. The live Session therefore reports its own
203
+ // recoverability after the handshake, and that value, not this one, is
204
+ // what gets published and stored. An Agent that never advertised
205
+ // `loadSession` also fails loudly inside `session/load` rather than
206
+ // silently degrading a running Turn.
207
+ nativeConversationResume: "exact",
208
+ compaction: "unknown",
209
+ compactionEvents: "unavailable",
210
+ contextUsage: "unavailable",
211
+ inSessionContinuation: true,
212
+ deliveryDeduplication: "unsupported"
213
+ }),
214
+ control: Object.freeze({
215
+ start: true,
216
+ resume: true,
217
+ sendTurn: true,
218
+ // `session/cancel` is a notification the Agent MUST answer with the
219
+ // `cancelled` stop reason, but halting the work is only a SHOULD.
220
+ interrupt: true,
221
+ interruptDelivery: "native",
222
+ stop: true
223
+ }),
224
+ conversation: Object.freeze({
225
+ // `session/new` returns the Agent's own Session id.
226
+ persistentIdentity: "exact",
227
+ // Same as `nativeConversationResume`: `session/load` is how ACP carries
228
+ // a Conversation across processes, so the capability exists. Whether
229
+ // this Agent honours it is the live Session's answer, not this table's.
230
+ crossProcessResume: true,
231
+ // `session/load` replays the Conversation, but ACP exposes no way to
232
+ // read back a Session's history without reloading it.
233
+ readback: "unavailable"
234
+ }),
235
+ input: Object.freeze({
236
+ startTurn: true,
237
+ // One Turn is one `session/prompt` request; ACP defines no way to add
238
+ // input to a Turn already in flight.
239
+ steer: "unavailable",
240
+ inject: "unavailable",
241
+ // The prompt response IS the terminal, so ACP defines no separate
242
+ // acceptance message. This is a permanent protocol fact, not a
243
+ // per-Agent gap: a completed pipe write is all that can be observed
244
+ // before the Turn's own result arrives.
245
+ acceptance: "unavailable",
246
+ idempotency: "unavailable"
247
+ }),
248
+ descendants: Object.freeze({
249
+ lineage: "unavailable",
250
+ detachedQuery: "unavailable",
251
+ resultRouting: "unavailable"
252
+ }),
253
+ // The prompt response carries an explicit stopReason, which is an exact
254
+ // structured terminal for the Turn that requested it.
255
+ bounded: Object.freeze({ structuredTerminal: true }),
256
+ observation: Object.freeze({
257
+ sessionIdentity: "exact",
258
+ sessionBootstrap: "discovered",
259
+ // ACP has no "ready" signal beyond `initialize` answering.
260
+ preInputReadiness: "unavailable",
261
+ promptAcceptance: "unavailable",
262
+ // The terminal status and its correlation to the exact request are
263
+ // both exact. What ACP lacks is intermediate progress, which is
264
+ // recorded as absent operations and usage rather than by understating
265
+ // the lifecycle Yui does observe.
266
+ turnLifecycle: "exact",
267
+ goalLifecycle: "unavailable",
268
+ operations: Object.freeze([]),
269
+ waiting: Object.freeze([]),
270
+ usage: "unavailable",
271
+ delivery: "host-only"
272
+ })
273
+ }),
274
+ runtime: Object.freeze({
275
+ // ACP delivers no Hooks. Identity comes from the protocol Session the
276
+ // managed Endpoint already holds, so there is no payload to mine here —
277
+ // and inventing a Turn id from a JSON-RPC request id would present a
278
+ // Yui-owned value as a Provider identity.
279
+ nativeSessionId: ({ payload }) => (optionalIdentityFrom(payload, ["sessionId"])),
280
+ nativeTurnId: () => undefined,
281
+ mapError: mapAcpAgentError,
282
+ mapHook: ({ hookEventName }) => {
283
+ throw new Error(`ACP Driver receives no native Hooks: ${hookEventName}.`);
284
+ },
285
+ classifyHook: ({ hookEventName }) => {
286
+ throw new Error(`ACP Driver receives no native Hooks: ${hookEventName}.`);
287
+ }
288
+ })
163
289
  })
164
290
  ]);
165
291
  export function builtinAgentDriverRegistry() {
@@ -185,8 +311,7 @@ function mapClaudeLifecycleHook(name, payload, occurrenceId) {
185
311
  payload.source === "startup"
186
312
  ? mapped("session.ready")
187
313
  : mapped("session.started"),
188
- mapped("conversation.observed", { recoverability: "recoverable" }),
189
- mapped("activation.started")
314
+ mapped("conversation.observed", { recoverability: "recoverable" })
190
315
  ];
191
316
  case "UserPromptSubmit":
192
317
  return mapped("turn.accepted");
@@ -261,7 +386,7 @@ function mapClaudeLifecycleHook(name, payload, occurrenceId) {
261
386
  // Native CLI exit ends this local Provider attachment, not the
262
387
  // resumable Conversation. Durable Session end is an explicit Yui
263
388
  // mutation or a Provider fact that the Conversation is unrecoverable.
264
- return mapped("activation.ended");
389
+ return [];
265
390
  default:
266
391
  throw new Error(`Claude Code Driver does not support Hook event: ${name}.`);
267
392
  }
@@ -336,8 +461,7 @@ function mapCodexHook(name, payload, occurrenceId) {
336
461
  case "SessionStart":
337
462
  return [
338
463
  mapped("session.started"),
339
- mapped("conversation.observed", { recoverability: "recoverable" }),
340
- mapped("activation.started")
464
+ mapped("conversation.observed", { recoverability: "recoverable" })
341
465
  ];
342
466
  case "UserPromptSubmit":
343
467
  return mapped("turn.accepted");
@@ -380,7 +504,7 @@ function mapCodexHook(name, payload, occurrenceId) {
380
504
  case "Stop":
381
505
  return mapped("turn.completed", optionalResultOutput(payload));
382
506
  case "SessionEnd":
383
- return mapped("activation.ended");
507
+ return [];
384
508
  default:
385
509
  throw new Error(`Codex Driver does not support Hook event: ${name}.`);
386
510
  }
@@ -394,10 +518,8 @@ function mapped(kind, payload = {}, fence) {
394
518
  }
395
519
  function continuationObservation(kind, native, payload) {
396
520
  const continuationId = subagentId(native);
397
- const generation = continuationGeneration(native);
398
521
  return mapped(kind, payload, {
399
522
  continuationId,
400
- continuationGeneration: generation,
401
523
  ...(optionalIdentityFrom(native, ["parent_agent_id", "parent_subagent_id"]) === undefined
402
524
  ? {}
403
525
  : {
@@ -405,12 +527,6 @@ function continuationObservation(kind, native, payload) {
405
527
  })
406
528
  });
407
529
  }
408
- function continuationGeneration(native) {
409
- return typeof native.generation === "number"
410
- && Number.isSafeInteger(native.generation) && native.generation >= 1
411
- ? native.generation
412
- : 1;
413
- }
414
530
  function reportId(payload) {
415
531
  return optionalIdentityFrom(payload, ["report_id", "message_id", "agent_id", "subagent_id"])
416
532
  ?? subagentId(payload);
@@ -491,7 +607,7 @@ function claudeFailure(payload) {
491
607
  }),
492
608
  ...(lastOutput === undefined ? {} : { lastOutput }),
493
609
  ...(payload.run_terminal === true || payload.unrecoverable === true
494
- ? { turnTerminal: true }
610
+ ? { runTerminal: true }
495
611
  : {})
496
612
  },
497
613
  summary: [
@@ -1,6 +1,9 @@
1
1
  /** Provider-specific Claude Code failure recognition. */
2
2
  export function mapClaudeAgentError(input) {
3
3
  const text = `${input.message}\n${input.raw}`;
4
+ if (/^No conversation found with session ID: [A-Za-z0-9-]+\.?$/imu.test(input.message)) {
5
+ return sessionUnavailable("provider.session-not-found");
6
+ }
4
7
  if (/^server_error$/iu.test(input.message) || /\bapi_error\b/iu.test(text)) {
5
8
  return recoverable("availability", "provider.server-error");
6
9
  }
@@ -44,6 +47,49 @@ export function mapCodexAgentError(input) {
44
47
  }
45
48
  return mapSharedAgentError(text, "codex");
46
49
  }
50
+ /**
51
+ * Agent Client Protocol failure recognition.
52
+ *
53
+ * ACP rides on JSON-RPC 2.0, so its failures arrive as numeric codes rather
54
+ * than provider prose. The codes are recognized first because they are the
55
+ * protocol's own exact vocabulary; only then does the shared text matcher run,
56
+ * which is what catches the transport failures underneath the protocol.
57
+ */
58
+ export function mapAcpAgentError(input) {
59
+ const text = `${input.message}\n${input.raw}`;
60
+ // -32800 is ACP's own "request cancelled". It is the expected answer to
61
+ // `session/cancel`, not a fault.
62
+ if (/-32800/u.test(text) || /request[\s_-]?cancell?ed/iu.test(text)) {
63
+ return Object.freeze({
64
+ category: "cancelled",
65
+ code: "acp.request-cancelled",
66
+ sessionDisposition: "recoverable"
67
+ });
68
+ }
69
+ // -32601 method not found / -32602 invalid params: Yui asked for something
70
+ // this Agent does not implement, or asked for it wrongly. Either way the
71
+ // request is at fault, and retrying it unchanged cannot help.
72
+ if (/-32601/u.test(text)) {
73
+ return classification("invalid-request", "acp.method-not-found");
74
+ }
75
+ if (/-32602/u.test(text)) {
76
+ return classification("invalid-request", "acp.invalid-params");
77
+ }
78
+ if (/-3270[01]/u.test(text)) {
79
+ return classification("invalid-request", "acp.invalid-request");
80
+ }
81
+ // -32603 is the catch-all internal error: the Agent failed, but the protocol
82
+ // says nothing about whether this Session survived.
83
+ if (/-32603/u.test(text)) {
84
+ return recoverable("runtime", "acp.internal-error");
85
+ }
86
+ // ACP's authentication path: the Agent requires `authenticate` first. Yui
87
+ // never performs it on the user's behalf, so this is a genuine access fact.
88
+ if (/auth[\s_-]?required|requires? authentication|-32000/iu.test(text)) {
89
+ return classification("access", "acp.authentication-required");
90
+ }
91
+ return mapSharedAgentError(text, "acp");
92
+ }
47
93
  function mapSharedAgentError(text, namespace) {
48
94
  if (/stream error:.*INTERNAL_ERROR/iu.test(text)) {
49
95
  return recoverable("transport", "transport.stream-internal-error");
@@ -124,13 +170,19 @@ function mapSharedAgentError(text, namespace) {
124
170
  return recoverable("runtime", "runtime.process-exited");
125
171
  }
126
172
  if (/invalid[\s_-]?request|validation[\s_-]?error|bad[\s_-]?request|unknown[\s_-]?(?:flag|tool|argument)|unexpected argument|invalid schema/iu.test(text)
127
- || (namespace === "codex"
128
- ? /\[codex:(?:unrecognized_model|invalid_model|model_not_found)\]/iu.test(text)
129
- : /\[claude-code:(?:unrecognized_model|invalid_model|model_not_found)\]/iu.test(text))) {
173
+ || namespacedModelError(namespace).test(text)) {
130
174
  return classification("invalid-request", "provider.invalid-request");
131
175
  }
132
176
  return classification("unknown", "unknown");
133
177
  }
178
+ /**
179
+ * The `[<namespace>:<code>]` model-error tag, built from the caller's own
180
+ * namespace. Enumerating the namespaces here instead would silently test one
181
+ * provider's tag against another provider's text.
182
+ */
183
+ function namespacedModelError(namespace) {
184
+ return new RegExp(String.raw `\[${namespace}:(?:unrecognized_model|invalid_model|model_not_found)\]`, "iu");
185
+ }
134
186
  function classification(category, code) {
135
187
  return Object.freeze({ category, code });
136
188
  }
@@ -14,7 +14,7 @@ export function codexTranscriptUsage(transcript) {
14
14
  export function codexTranscriptUsageReport(transcript) {
15
15
  // Codex token_count events are cumulative Session snapshots. Per-request
16
16
  // input is the non-negative delta between consecutive snapshots; the first
17
- // snapshot only establishes the generation baseline.
17
+ // snapshot only establishes the Session baseline.
18
18
  let latestInput = 0;
19
19
  let latestCached = 0;
20
20
  let latestOutput = 0;