@gkorepanov/ccodex 0.4.20 → 0.4.24

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 (264) hide show
  1. package/README.md +4 -2
  2. package/agents/codex-wrapper.md +1 -0
  3. package/config/compatibility.json +5 -5
  4. package/dist/claude/inputMapper.d.ts +5 -0
  5. package/dist/claude/inputMapper.js +9 -0
  6. package/dist/claude/inputMapper.js.map +1 -1
  7. package/dist/claude/rateLimits.d.ts +2 -1
  8. package/dist/claude/rateLimits.js +12 -16
  9. package/dist/claude/rateLimits.js.map +1 -1
  10. package/dist/claude/service.d.ts +41 -1
  11. package/dist/claude/service.js +166 -69
  12. package/dist/claude/service.js.map +1 -1
  13. package/dist/claude/session/commands.d.ts +36 -0
  14. package/dist/claude/session/goalState.d.ts +5 -0
  15. package/dist/claude/session/goalState.js +22 -0
  16. package/dist/claude/session/goalState.js.map +1 -1
  17. package/dist/claude/session/providerRuntimeFactory.js +15 -7
  18. package/dist/claude/session/providerRuntimeFactory.js.map +1 -1
  19. package/dist/claude/session/repository.d.ts +3 -0
  20. package/dist/claude/session/repository.js +2 -0
  21. package/dist/claude/session/repository.js.map +1 -1
  22. package/dist/claude/session/runtime.d.ts +10 -0
  23. package/dist/claude/session/runtime.js +45 -3
  24. package/dist/claude/session/runtime.js.map +1 -1
  25. package/dist/claude/session/scopeState.js +1 -0
  26. package/dist/claude/session/scopeState.js.map +1 -1
  27. package/dist/claude/session/session.d.ts +1 -0
  28. package/dist/claude/session/session.js +162 -55
  29. package/dist/claude/session/session.js.map +1 -1
  30. package/dist/claude/skillCatalog.js +1 -0
  31. package/dist/claude/skillCatalog.js.map +1 -1
  32. package/dist/claude/statusCommand.js +1 -2
  33. package/dist/claude/statusCommand.js.map +1 -1
  34. package/dist/codex/generated/AuthMode.d.ts +1 -1
  35. package/dist/codex/generated/ClientRequest.d.ts +25 -0
  36. package/dist/codex/generated/InternalSessionSource.d.ts +1 -1
  37. package/dist/codex/generated/ResponseItem.d.ts +3 -1
  38. package/dist/codex/generated/ResponseItemRuntimeSchema.js +2 -2
  39. package/dist/codex/generated/ResponseItemRuntimeSchema.js.map +1 -1
  40. package/dist/codex/generated/ServerNotification.d.ts +23 -0
  41. package/dist/codex/generated/ServerNotificationEnvelope.d.ts +23 -0
  42. package/dist/codex/generated/v2/AllowDenyRequirement.d.ts +1 -0
  43. package/dist/codex/generated/v2/AllowDenyRequirement.js +3 -0
  44. package/dist/codex/generated/v2/AllowDenyRequirement.js.map +1 -0
  45. package/dist/codex/generated/v2/AppLinksConfig.d.ts +11 -0
  46. package/dist/codex/generated/v2/AppLinksConfig.js +3 -0
  47. package/dist/codex/generated/v2/AppLinksConfig.js.map +1 -0
  48. package/dist/codex/generated/v2/AppsConfig.d.ts +5 -0
  49. package/dist/codex/generated/v2/AsyncUserInputQuestion.d.ts +4 -0
  50. package/dist/codex/generated/v2/AsyncUserInputQuestion.js +3 -0
  51. package/dist/codex/generated/v2/AsyncUserInputQuestion.js.map +1 -0
  52. package/dist/codex/generated/v2/AuthRecoveryNotification.d.ts +6 -0
  53. package/dist/codex/generated/v2/AuthRecoveryNotification.js +3 -0
  54. package/dist/codex/generated/v2/AuthRecoveryNotification.js.map +1 -0
  55. package/dist/codex/generated/v2/BedrockSetupParams.d.ts +0 -8
  56. package/dist/codex/generated/v2/BrowserUseAccessApprovalLifetime.d.ts +1 -0
  57. package/dist/codex/generated/v2/BrowserUseAccessApprovalLifetime.js +3 -0
  58. package/dist/codex/generated/v2/BrowserUseAccessApprovalLifetime.js.map +1 -0
  59. package/dist/codex/generated/v2/BrowserUseConfig.d.ts +8 -0
  60. package/dist/codex/generated/v2/BrowserUseConfig.js +3 -0
  61. package/dist/codex/generated/v2/BrowserUseConfig.js.map +1 -0
  62. package/dist/codex/generated/v2/BrowserUseOriginPolicy.d.ts +11 -0
  63. package/dist/codex/generated/v2/BrowserUseOriginPolicy.js +3 -0
  64. package/dist/codex/generated/v2/BrowserUseOriginPolicy.js.map +1 -0
  65. package/dist/codex/generated/v2/BrowserUseOriginPolicyConfig.d.ts +7 -0
  66. package/dist/codex/generated/v2/BrowserUseOriginPolicyConfig.js +3 -0
  67. package/dist/codex/generated/v2/BrowserUseOriginPolicyConfig.js.map +1 -0
  68. package/dist/codex/generated/v2/BrowserUseRequirements.d.ts +7 -0
  69. package/dist/codex/generated/v2/CodexErrorInfo.d.ts +1 -1
  70. package/dist/codex/generated/v2/CollabAgentTool.d.ts +1 -1
  71. package/dist/codex/generated/v2/CollabAgentToolCallStatus.d.ts +1 -1
  72. package/dist/codex/generated/v2/CommandExecutionApprovalKind.d.ts +4 -0
  73. package/dist/codex/generated/v2/CommandExecutionApprovalKind.js +3 -0
  74. package/dist/codex/generated/v2/CommandExecutionApprovalKind.js.map +1 -0
  75. package/dist/codex/generated/v2/CommandExecutionRequestApprovalParams.d.ts +6 -0
  76. package/dist/codex/generated/v2/ComputerUseConfig.d.ts +8 -0
  77. package/dist/codex/generated/v2/ComputerUseConfig.js +3 -0
  78. package/dist/codex/generated/v2/ComputerUseConfig.js.map +1 -0
  79. package/dist/codex/generated/v2/ComputerUseMacosConfig.d.ts +6 -0
  80. package/dist/codex/generated/v2/ComputerUseMacosConfig.js +3 -0
  81. package/dist/codex/generated/v2/ComputerUseMacosConfig.js.map +1 -0
  82. package/dist/codex/generated/v2/ComputerUseMacosRequirements.d.ts +6 -0
  83. package/dist/codex/generated/v2/ComputerUseMacosRequirements.js +3 -0
  84. package/dist/codex/generated/v2/ComputerUseMacosRequirements.js.map +1 -0
  85. package/dist/codex/generated/v2/ComputerUseRequirements.d.ts +7 -0
  86. package/dist/codex/generated/v2/ComputerUseWindowsConfig.d.ts +8 -0
  87. package/dist/codex/generated/v2/ComputerUseWindowsConfig.js +3 -0
  88. package/dist/codex/generated/v2/ComputerUseWindowsConfig.js.map +1 -0
  89. package/dist/codex/generated/v2/ComputerUseWindowsExeConfig.d.ts +7 -0
  90. package/dist/codex/generated/v2/ComputerUseWindowsExeConfig.js +3 -0
  91. package/dist/codex/generated/v2/ComputerUseWindowsExeConfig.js.map +1 -0
  92. package/dist/codex/generated/v2/ComputerUseWindowsExeRequirement.d.ts +7 -0
  93. package/dist/codex/generated/v2/ComputerUseWindowsExeRequirement.js +3 -0
  94. package/dist/codex/generated/v2/ComputerUseWindowsExeRequirement.js.map +1 -0
  95. package/dist/codex/generated/v2/ComputerUseWindowsRequirements.d.ts +8 -0
  96. package/dist/codex/generated/v2/ComputerUseWindowsRequirements.js +3 -0
  97. package/dist/codex/generated/v2/ComputerUseWindowsRequirements.js.map +1 -0
  98. package/dist/codex/generated/v2/Config.d.ts +4 -0
  99. package/dist/codex/generated/v2/ConfigRequirements.d.ts +4 -0
  100. package/dist/codex/generated/v2/CyberAccessProgram.d.ts +5 -0
  101. package/dist/codex/generated/v2/CyberAccessProgram.js +3 -0
  102. package/dist/codex/generated/v2/CyberAccessProgram.js.map +1 -0
  103. package/dist/codex/generated/v2/GetAccountRateLimitsResponse.d.ts +10 -0
  104. package/dist/codex/generated/v2/GuardianApprovalReviewAction.d.ts +7 -0
  105. package/dist/codex/generated/v2/HookEventName.d.ts +1 -1
  106. package/dist/codex/generated/v2/InAppBrowserRequirements.d.ts +3 -0
  107. package/dist/codex/generated/v2/InAppBrowserRequirements.js +3 -0
  108. package/dist/codex/generated/v2/InAppBrowserRequirements.js.map +1 -0
  109. package/dist/codex/generated/v2/ItemGuardianApprovalReviewCompletedNotification.d.ts +2 -0
  110. package/dist/codex/generated/v2/ItemGuardianApprovalReviewStartedNotification.d.ts +2 -0
  111. package/dist/codex/generated/v2/LoginAccountParams.d.ts +6 -0
  112. package/dist/codex/generated/v2/ManagedHooksRequirements.d.ts +1 -0
  113. package/dist/codex/generated/v2/McpServerConnectionStatus.d.ts +1 -0
  114. package/dist/codex/generated/v2/McpServerConnectionStatus.js +3 -0
  115. package/dist/codex/generated/v2/McpServerConnectionStatus.js.map +1 -0
  116. package/dist/codex/generated/v2/McpServerElicitationRequestParams.d.ts +5 -0
  117. package/dist/codex/generated/v2/McpServerEventNotification.d.ts +5 -0
  118. package/dist/codex/generated/v2/McpServerEventNotification.js +3 -0
  119. package/dist/codex/generated/v2/McpServerEventNotification.js.map +1 -0
  120. package/dist/codex/generated/v2/McpServerEventStreamNotification.d.ts +5 -0
  121. package/dist/codex/generated/v2/McpServerEventStreamNotification.js +3 -0
  122. package/dist/codex/generated/v2/McpServerEventStreamNotification.js.map +1 -0
  123. package/dist/codex/generated/v2/McpServerEventStreamStartParams.d.ts +9 -0
  124. package/dist/codex/generated/v2/McpServerEventStreamStartParams.js +3 -0
  125. package/dist/codex/generated/v2/McpServerEventStreamStartParams.js.map +1 -0
  126. package/dist/codex/generated/v2/McpServerEventStreamStartResponse.d.ts +1 -0
  127. package/dist/codex/generated/v2/McpServerEventStreamStartResponse.js +3 -0
  128. package/dist/codex/generated/v2/McpServerEventStreamStartResponse.js.map +1 -0
  129. package/dist/codex/generated/v2/McpServerEventStreamStopParams.d.ts +3 -0
  130. package/dist/codex/generated/v2/McpServerEventStreamStopParams.js +3 -0
  131. package/dist/codex/generated/v2/McpServerEventStreamStopParams.js.map +1 -0
  132. package/dist/codex/generated/v2/McpServerEventStreamStopResponse.d.ts +1 -0
  133. package/dist/codex/generated/v2/McpServerEventStreamStopResponse.js +3 -0
  134. package/dist/codex/generated/v2/McpServerEventStreamStopResponse.js.map +1 -0
  135. package/dist/codex/generated/v2/McpServerStatus.d.ts +5 -0
  136. package/dist/codex/generated/v2/MisalignmentErrorDetails.d.ts +15 -0
  137. package/dist/codex/generated/v2/MisalignmentErrorDetails.js +3 -0
  138. package/dist/codex/generated/v2/MisalignmentErrorDetails.js.map +1 -0
  139. package/dist/codex/generated/v2/MisalignmentSteer.d.ts +3 -0
  140. package/dist/codex/generated/v2/MisalignmentSteer.js +3 -0
  141. package/dist/codex/generated/v2/MisalignmentSteer.js.map +1 -0
  142. package/dist/codex/generated/v2/PluginReconcileChangedPlugin.d.ts +19 -0
  143. package/dist/codex/generated/v2/PluginReconcileChangedPlugin.js +3 -0
  144. package/dist/codex/generated/v2/PluginReconcileChangedPlugin.js.map +1 -0
  145. package/dist/codex/generated/v2/PluginReconcileParams.d.ts +6 -0
  146. package/dist/codex/generated/v2/PluginReconcileParams.js +3 -0
  147. package/dist/codex/generated/v2/PluginReconcileParams.js.map +1 -0
  148. package/dist/codex/generated/v2/PluginReconcileResponse.d.ts +23 -0
  149. package/dist/codex/generated/v2/PluginReconcileResponse.js +3 -0
  150. package/dist/codex/generated/v2/PluginReconcileResponse.js.map +1 -0
  151. package/dist/codex/generated/v2/Project.d.ts +4 -0
  152. package/dist/codex/generated/v2/ProjectListParams.d.ts +10 -0
  153. package/dist/codex/generated/v2/ProjectSortKey.d.ts +1 -0
  154. package/dist/codex/generated/v2/ProjectSortKey.js +3 -0
  155. package/dist/codex/generated/v2/ProjectSortKey.js.map +1 -0
  156. package/dist/codex/generated/v2/RawResponseCompletedNotification.d.ts +2 -0
  157. package/dist/codex/generated/v2/ResponseUsageMetadata.d.ts +8 -0
  158. package/dist/codex/generated/v2/ResponseUsageMetadata.js +3 -0
  159. package/dist/codex/generated/v2/ResponseUsageMetadata.js.map +1 -0
  160. package/dist/codex/generated/v2/SkillMetadata.d.ts +4 -0
  161. package/dist/codex/generated/v2/SubAgentActivityKind.d.ts +1 -1
  162. package/dist/codex/generated/v2/Thread.d.ts +11 -0
  163. package/dist/codex/generated/v2/ThreadForkParams.d.ts +3 -1
  164. package/dist/codex/generated/v2/ThreadItem.d.ts +9 -0
  165. package/dist/codex/generated/v2/ThreadReadParams.d.ts +3 -0
  166. package/dist/codex/generated/v2/ThreadRealtimeBemItemPresentation.d.ts +11 -0
  167. package/dist/codex/generated/v2/ThreadRealtimeBemItemPresentation.js +3 -0
  168. package/dist/codex/generated/v2/ThreadRealtimeBemItemPresentation.js.map +1 -0
  169. package/dist/codex/generated/v2/ThreadRealtimeItem.d.ts +24 -0
  170. package/dist/codex/generated/v2/ThreadRealtimeItem.js +3 -0
  171. package/dist/codex/generated/v2/ThreadRealtimeItem.js.map +1 -0
  172. package/dist/codex/generated/v2/ThreadRealtimeItemCompletedNotification.d.ts +8 -0
  173. package/dist/codex/generated/v2/ThreadRealtimeItemCompletedNotification.js +3 -0
  174. package/dist/codex/generated/v2/ThreadRealtimeItemCompletedNotification.js.map +1 -0
  175. package/dist/codex/generated/v2/ThreadRealtimeItemStartedNotification.d.ts +8 -0
  176. package/dist/codex/generated/v2/ThreadRealtimeItemStartedNotification.js +3 -0
  177. package/dist/codex/generated/v2/ThreadRealtimeItemStartedNotification.js.map +1 -0
  178. package/dist/codex/generated/v2/ThreadRealtimeItemTranscriptDeltaNotification.d.ts +8 -0
  179. package/dist/codex/generated/v2/ThreadRealtimeItemTranscriptDeltaNotification.js +3 -0
  180. package/dist/codex/generated/v2/ThreadRealtimeItemTranscriptDeltaNotification.js.map +1 -0
  181. package/dist/codex/generated/v2/ThreadRealtimeSessionOutcome.d.ts +1 -0
  182. package/dist/codex/generated/v2/ThreadRealtimeSessionOutcome.js +3 -0
  183. package/dist/codex/generated/v2/ThreadRealtimeSessionOutcome.js.map +1 -0
  184. package/dist/codex/generated/v2/ThreadRealtimeStartTransport.d.ts +6 -0
  185. package/dist/codex/generated/v2/ThreadRealtimeTranscriptRole.d.ts +1 -0
  186. package/dist/codex/generated/v2/ThreadRealtimeTranscriptRole.js +3 -0
  187. package/dist/codex/generated/v2/ThreadRealtimeTranscriptRole.js.map +1 -0
  188. package/dist/codex/generated/v2/ThreadResumeParams.d.ts +3 -1
  189. package/dist/codex/generated/v2/ThreadShellCommandParams.d.ts +6 -0
  190. package/dist/codex/generated/v2/ThreadTimelineEntry.d.ts +31 -0
  191. package/dist/codex/generated/v2/ThreadTimelineEntry.js +3 -0
  192. package/dist/codex/generated/v2/ThreadTimelineEntry.js.map +1 -0
  193. package/dist/codex/generated/v2/ThreadTimelineListParams.d.ts +8 -0
  194. package/dist/codex/generated/v2/ThreadTimelineListParams.js +3 -0
  195. package/dist/codex/generated/v2/ThreadTimelineListParams.js.map +1 -0
  196. package/dist/codex/generated/v2/ThreadTimelineListResponse.d.ts +9 -0
  197. package/dist/codex/generated/v2/ThreadTimelineListResponse.js +3 -0
  198. package/dist/codex/generated/v2/ThreadTimelineListResponse.js.map +1 -0
  199. package/dist/codex/generated/v2/TurnError.d.ts +5 -0
  200. package/dist/codex/generated/v2/TurnSettingsUpdateParams.d.ts +34 -0
  201. package/dist/codex/generated/v2/TurnSettingsUpdateParams.js +3 -0
  202. package/dist/codex/generated/v2/TurnSettingsUpdateParams.js.map +1 -0
  203. package/dist/codex/generated/v2/TurnSettingsUpdateResponse.d.ts +4 -0
  204. package/dist/codex/generated/v2/TurnSettingsUpdateResponse.js +3 -0
  205. package/dist/codex/generated/v2/TurnSettingsUpdateResponse.js.map +1 -0
  206. package/dist/codex/generated/v2/TurnSettingsUpdateStatus.d.ts +1 -0
  207. package/dist/codex/generated/v2/TurnSettingsUpdateStatus.js +3 -0
  208. package/dist/codex/generated/v2/TurnSettingsUpdateStatus.js.map +1 -0
  209. package/dist/codex/generated/v2/TurnStartParams.d.ts +19 -0
  210. package/dist/codex/generated/v2/TurnToolOutput.d.ts +6 -0
  211. package/dist/codex/generated/v2/TurnToolOutput.js +3 -0
  212. package/dist/codex/generated/v2/TurnToolOutput.js.map +1 -0
  213. package/dist/codex/generated/v2/index.d.ts +46 -0
  214. package/dist/daemon/ownership.js +9 -1
  215. package/dist/daemon/ownership.js.map +1 -1
  216. package/dist/daemon/probe.js +1 -1
  217. package/dist/gateway/clientConnection.js +105 -19
  218. package/dist/gateway/clientConnection.js.map +1 -1
  219. package/dist/gateway/optimisticSideThreads.d.ts +11 -5
  220. package/dist/gateway/optimisticSideThreads.js +103 -47
  221. package/dist/gateway/optimisticSideThreads.js.map +1 -1
  222. package/dist/gateway/remoteRelay.js +2 -2
  223. package/dist/gateway/remoteRelay.js.map +1 -1
  224. package/dist/gateway/server.js +31 -1
  225. package/dist/gateway/server.js.map +1 -1
  226. package/dist/gateway/stockSideThreads.d.ts +3 -6
  227. package/dist/gateway/stockSideThreads.js +38 -43
  228. package/dist/gateway/stockSideThreads.js.map +1 -1
  229. package/dist/gateway/threadList.d.ts +9 -3
  230. package/dist/gateway/threadList.js +66 -15
  231. package/dist/gateway/threadList.js.map +1 -1
  232. package/dist/gateway/transientNotice.js +4 -4
  233. package/dist/gateway/transientNotice.js.map +1 -1
  234. package/dist/handoff/service.d.ts +10 -2
  235. package/dist/handoff/service.js +164 -106
  236. package/dist/handoff/service.js.map +1 -1
  237. package/dist/handoff/store.d.ts +21 -0
  238. package/dist/handoff/store.js +15 -0
  239. package/dist/handoff/store.js.map +1 -1
  240. package/dist/handoff/titleGeneration.d.ts +1 -0
  241. package/dist/handoff/titleGeneration.js.map +1 -1
  242. package/dist/management/setup.d.ts +6 -0
  243. package/dist/management/setup.js +11 -3
  244. package/dist/management/setup.js.map +1 -1
  245. package/dist/protocol/search.d.ts +24 -0
  246. package/dist/protocol/search.js +105 -0
  247. package/dist/protocol/search.js.map +1 -0
  248. package/dist/protocol/turnPagination.d.ts +16 -0
  249. package/dist/protocol/turnPagination.js +75 -35
  250. package/dist/protocol/turnPagination.js.map +1 -1
  251. package/dist/runtime/dependencies.js +1 -1
  252. package/dist/store/HybridStore.d.ts +4 -0
  253. package/dist/store/HybridStore.js +1 -1
  254. package/dist/store/HybridStore.js.map +1 -1
  255. package/dist/store/memoryStore.d.ts +6 -0
  256. package/dist/store/memoryStore.js +16 -0
  257. package/dist/store/memoryStore.js.map +1 -1
  258. package/dist/store/sqliteStore.d.ts +3 -0
  259. package/dist/store/sqliteStore.js +57 -0
  260. package/dist/store/sqliteStore.js.map +1 -1
  261. package/legal/THIRD_PARTY_NOTICES.md +160 -140
  262. package/package.json +6 -6
  263. package/scripts/install-claude-stack.sh +27 -4
  264. package/vendor/codex/continuation.md +5 -0
@@ -1,7 +1,8 @@
1
1
  import { v7 as uuidv7 } from "uuid";
2
2
  import { AsyncLocalStorage } from "node:async_hooks";
3
+ import { startedTurn } from "../../protocol/turnPagination.js";
3
4
  import { MetricsRegistry } from "../../observability/metrics.js";
4
- import { invalidParams, RpcError } from "../../protocol/errors.js";
5
+ import { invalidParams, invalidRequest, RpcError } from "../../protocol/errors.js";
5
6
  import { classifyClaudeResult, classifyClaudeRuntimeError, } from "../resultClassifier.js";
6
7
  import { runtimeWorkspaceRoots, settingsGeneration, withSettingsFrom } from "../../store/HybridStore.js";
7
8
  import { addUsage } from "./usage.js";
@@ -21,7 +22,7 @@ import { stat } from "node:fs/promises";
21
22
  import { readBackgroundOutput } from "./backgroundOutput.js";
22
23
  import { CODEX_MCP_MESSAGE_LABEL, CODEX_MCP_PROMPT_LABEL, CODEX_MCP_REASONING_LABEL, CODEX_MCP_TOOLS, defaultCodexRolloutLocator, parseRolloutChunk, } from "./codexRollout.js";
23
24
  import { createGoalMcpServer } from "../goalTools.js";
24
- import { mapUserInput } from "../inputMapper.js";
25
+ import { mapUserInput, normalizeUserInput } from "../inputMapper.js";
25
26
  import { bashCommandActions } from "../commandActions.js";
26
27
  import { safeSessionPermissionUpdates } from "./permissionUpdates.js";
27
28
  import { threadSettings } from "../threadSettings.js";
@@ -84,6 +85,8 @@ function childProjectionIds(turns) {
84
85
  return [];
85
86
  })));
86
87
  }
88
+ /** Stock app-server caps the per-thread submission queue at 100 entries. */
89
+ const MAX_QUEUED_SUBMISSIONS = 100;
87
90
  function commandLane(command) {
88
91
  if (command.type === "runtimeLineage"
89
92
  || command.type === "completeSynthetic" || command.type === "resolveInteraction"
@@ -670,7 +673,7 @@ export class ClaudeSession {
670
673
  runtimeGeneration: startup.runtimeGeneration,
671
674
  fact: { type: "sync" },
672
675
  source: { providerEventId: null, providerEventType: null },
673
- });
676
+ }).catch(() => undefined);
674
677
  return candidate;
675
678
  }
676
679
  catch (error) {
@@ -1214,13 +1217,23 @@ export class ClaudeSession {
1214
1217
  });
1215
1218
  }
1216
1219
  if (failure) {
1220
+ this.runtimeDependencies?.logger.error("claude.provider.projection-failed", {
1221
+ threadId: this.threadId, providerEventType: fact.providerEventType, error: failure,
1222
+ });
1217
1223
  await this.submitProviderProjection(fact.runtimeGeneration, {
1218
- type: "runtimeExited",
1224
+ type: "runtimeFailed",
1219
1225
  runtimeGeneration: fact.runtimeGeneration,
1220
1226
  message: `Claude provider projection failed: ${failure}`,
1221
1227
  codexErrorInfo: null,
1222
1228
  });
1223
1229
  runtime.beginClose();
1230
+ // Retire outside the provider consumer: close() drains that same
1231
+ // consumer, so awaiting it here would deadlock.
1232
+ void this.retireRuntime(`Claude provider projection failed: ${failure}`).catch((error) => {
1233
+ this.runtimeDependencies?.logger.error("claude.runtime.retirement-failed", {
1234
+ threadId: this.threadId, error: String(error),
1235
+ });
1236
+ });
1224
1237
  }
1225
1238
  });
1226
1239
  }
@@ -1452,7 +1465,7 @@ export class ClaudeSession {
1452
1465
  type: "runtimeLineage",
1453
1466
  action: "catalogInvalidated",
1454
1467
  runtimeGeneration,
1455
- });
1468
+ }).catch(() => undefined);
1456
1469
  }
1457
1470
  }
1458
1471
  await this.submitProviderProjection(runtimeGeneration, {
@@ -1530,7 +1543,7 @@ export class ClaudeSession {
1530
1543
  type: "runtimeLineage",
1531
1544
  action: "catalogInvalidated",
1532
1545
  runtimeGeneration,
1533
- });
1546
+ }).catch(() => undefined);
1534
1547
  }
1535
1548
  if (result.status === "completed" && message.subtype === "success") {
1536
1549
  if (message.structured_output !== undefined) {
@@ -1582,7 +1595,7 @@ export class ClaudeSession {
1582
1595
  action: "authFailure",
1583
1596
  runtimeGeneration,
1584
1597
  reason: message.error,
1585
- });
1598
+ }).catch(() => undefined);
1586
1599
  await this.providerSystemMessage(projection, runtimeGeneration, `Claude authentication failed: ${message.error}`, "error");
1587
1600
  }
1588
1601
  else if (message.output.length > 0) {
@@ -1902,6 +1915,7 @@ export class ClaudeSession {
1902
1915
  method = "item/commandExecution/requestApproval";
1903
1916
  params = {
1904
1917
  ...common,
1918
+ kind: "command",
1905
1919
  environmentId: null,
1906
1920
  reason: options.decisionReason ?? options.description ?? null,
1907
1921
  command: typeof input.command === "string" ? input.command : null,
@@ -3437,6 +3451,8 @@ export class ClaudeSession {
3437
3451
  + `retry the ${this.adminOperation.kind} request after cleanup completes.`);
3438
3452
  }
3439
3453
  return dispatchGoal(this.goal, this.goalContext(), command.command);
3454
+ case "queue":
3455
+ return this.handleQueue(command.command);
3440
3456
  case "runtimeDetached": {
3441
3457
  const detached = this.runtimeGeneration === command.runtimeGeneration;
3442
3458
  if (detached && command.requireQuiescent && !this.isQuiescent()) {
@@ -3572,7 +3588,7 @@ export class ClaudeSession {
3572
3588
  type: "userMessage",
3573
3589
  id: command.review ? turnId : uuidv7(),
3574
3590
  clientId: command.params.clientUserMessageId ?? null,
3575
- content: command.params.input,
3591
+ content: normalizeUserInput(command.params.input),
3576
3592
  };
3577
3593
  const reviewItem = command.review
3578
3594
  ? { type: "enteredReviewMode", id: uuidv7(), review: command.review }
@@ -3781,7 +3797,9 @@ export class ClaudeSession {
3781
3797
  ...record,
3782
3798
  thread: {
3783
3799
  ...record.thread,
3784
- status: { type: command.type === "runtimeFailed" ? "systemError" : "notLoaded" },
3800
+ status: { type: command.type === "runtimeFailed" ? "systemError"
3801
+ : record.thread.ephemeral && record.thread.threadSource === "user" && !record.thread.parentThreadId
3802
+ ? "idle" : "notLoaded" },
3785
3803
  updatedAt: Math.floor(Date.now() / 1_000),
3786
3804
  },
3787
3805
  };
@@ -4077,7 +4095,7 @@ export class ClaudeSession {
4077
4095
  type: "userMessage",
4078
4096
  id: uuidv7(),
4079
4097
  clientId: command.clientUserMessageId ?? null,
4080
- content: command.input,
4098
+ content: normalizeUserInput(command.input),
4081
4099
  };
4082
4100
  turn.items.push(item);
4083
4101
  this.publishTurn(turn, "item/started", {
@@ -4449,7 +4467,7 @@ export class ClaudeSession {
4449
4467
  type: "cancelInteraction",
4450
4468
  runtimeGeneration: command.runtimeGeneration,
4451
4469
  requestId: command.requestId,
4452
- });
4470
+ }).catch(() => undefined);
4453
4471
  };
4454
4472
  if (command.signal?.aborted)
4455
4473
  queueMicrotask(cancel);
@@ -4489,7 +4507,7 @@ export class ClaudeSession {
4489
4507
  case "threadAdmin":
4490
4508
  return this.dispatchThreadAdmin(command.command);
4491
4509
  case "runShell":
4492
- return this.runShell(command.command);
4510
+ return this.runShell(command.command, command.timeoutMs);
4493
4511
  case "startShell":
4494
4512
  return this.startShell(command.command);
4495
4513
  case "admitShellEffect":
@@ -4670,10 +4688,12 @@ export class ClaudeSession {
4670
4688
  this.emitLifecycle();
4671
4689
  return { operationId, turnId: turn.id, cwd: record.thread.cwd };
4672
4690
  }
4673
- runShell(command) {
4691
+ runShell(command, timeoutMs) {
4674
4692
  const started = this.startShell(command);
4675
4693
  const shell = this.shell;
4676
4694
  let processHandle;
4695
+ let timer;
4696
+ let timedOut = false;
4677
4697
  try {
4678
4698
  processHandle = this.shellRunner.launch(started.cwd, command, {
4679
4699
  ready: () => {
@@ -4682,7 +4702,8 @@ export class ClaudeSession {
4682
4702
  operationId: started.operationId,
4683
4703
  }).then((admitted) => {
4684
4704
  if (!admitted)
4685
- processHandle.kill();
4705
+ return processHandle.kill();
4706
+ timer = setTimeout(() => { timedOut = true; processHandle.kill(); }, timeoutMs);
4686
4707
  }, () => processHandle.kill());
4687
4708
  },
4688
4709
  output: (bytes) => {
@@ -4693,11 +4714,13 @@ export class ClaudeSession {
4693
4714
  }).catch(() => undefined);
4694
4715
  },
4695
4716
  terminal: (exitCode, errorMessage) => {
4717
+ clearTimeout(timer);
4718
+ const message = errorMessage ?? (timedOut ? `command timed out after ${timeoutMs}ms` : undefined);
4696
4719
  void this.submit({
4697
4720
  type: "finishShell",
4698
4721
  operationId: started.operationId,
4699
4722
  exitCode,
4700
- ...(errorMessage ? { errorMessage } : {}),
4723
+ ...(message ? { errorMessage: message } : {}),
4701
4724
  }).catch(() => shell.resolve());
4702
4725
  },
4703
4726
  });
@@ -4762,7 +4785,7 @@ export class ClaudeSession {
4762
4785
  items: active.items.map((candidate) => candidate.id === item.id ? updatedItem : candidate),
4763
4786
  }, status, errorMessage ?? (status === "failed" ? `Shell command exited with code ${exitCode}.` : undefined), null);
4764
4787
  this.shell = undefined;
4765
- this.finishTurn(turn, nullSource, false, [{
4788
+ const completed = this.finishTurn(turn, nullSource, false, [{
4766
4789
  turnId: turn.id,
4767
4790
  method: "item/completed",
4768
4791
  params: {
@@ -4772,7 +4795,7 @@ export class ClaudeSession {
4772
4795
  completedAtMs: Date.now(),
4773
4796
  },
4774
4797
  }]);
4775
- this.emitLifecycle();
4798
+ this.emitLifecycle(completed);
4776
4799
  shell.resolve();
4777
4800
  return true;
4778
4801
  }
@@ -4840,7 +4863,7 @@ export class ClaudeSession {
4840
4863
  items: active.items.map((candidate) => candidate.id === item.id ? updatedItem : candidate),
4841
4864
  }, "interrupted", undefined, null);
4842
4865
  this.shell = undefined;
4843
- this.finishTurn(turn, nullSource, false, [{
4866
+ const completed = this.finishTurn(turn, nullSource, false, [{
4844
4867
  turnId: turn.id,
4845
4868
  method: "item/completed",
4846
4869
  params: {
@@ -4850,7 +4873,7 @@ export class ClaudeSession {
4850
4873
  completedAtMs: Date.now(),
4851
4874
  },
4852
4875
  }]);
4853
- this.emitLifecycle();
4876
+ this.emitLifecycle(completed);
4854
4877
  shell.resolve();
4855
4878
  return true;
4856
4879
  }
@@ -5015,7 +5038,7 @@ export class ClaudeSession {
5015
5038
  const active = this.repository.readTurn(this.threadId, operation.turnId);
5016
5039
  const item = active.items[0];
5017
5040
  const turn = this.terminalTurn(active, status, errorMessage, codexErrorInfo);
5018
- this.finishTurn(turn, source, true, [
5041
+ const completed = this.finishTurn(turn, source, true, [
5019
5042
  {
5020
5043
  turnId: turn.id,
5021
5044
  method: "item/completed",
@@ -5041,7 +5064,7 @@ export class ClaudeSession {
5041
5064
  operation.hidden.completion.reject(new Error(errorMessage ?? `Claude compaction ${status}.`));
5042
5065
  }
5043
5066
  }
5044
- this.emitLifecycle();
5067
+ this.emitLifecycle(operation.hidden ? undefined : completed, Boolean(operation.hidden));
5045
5068
  return { turnId: turn.id, terminal: true, ...(operation.hidden ? { hidden: true } : {}) };
5046
5069
  }
5047
5070
  compactionProjection(terminal = false, cancelOperationId, transportAction) {
@@ -5141,7 +5164,7 @@ export class ClaudeSession {
5141
5164
  delivery: null,
5142
5165
  text: systemNoticeText(`Gateway restarted while the CCodex ${state ? "state" : "status"} request was active.`, "error"),
5143
5166
  phase: "final_answer",
5144
- memoryCitation: null,
5167
+ memoryCitation: null, questions: null,
5145
5168
  });
5146
5169
  }
5147
5170
  if (items.some((item) => item.type === "enteredReviewMode")
@@ -5162,7 +5185,7 @@ export class ClaudeSession {
5162
5185
  error: {
5163
5186
  message: "Gateway restarted while the Claude turn was active.",
5164
5187
  codexErrorInfo: { responseStreamDisconnected: { httpStatusCode: null } },
5165
- additionalDetails: null,
5188
+ additionalDetails: null, misalignment: null,
5166
5189
  },
5167
5190
  };
5168
5191
  }
@@ -5194,7 +5217,7 @@ export class ClaudeSession {
5194
5217
  if (this.announcedTurns.has(turn.id))
5195
5218
  return;
5196
5219
  this.announcedTurns.add(turn.id);
5197
- this.publish(turn.id, "turn/started", { threadId: this.threadId, turn }, `turn/started:${turn.id}`);
5220
+ this.publish(turn.id, "turn/started", { threadId: this.threadId, turn: startedTurn(turn) }, `turn/started:${turn.id}`);
5198
5221
  for (const item of turn.items) {
5199
5222
  this.publish(turn.id, "item/started", {
5200
5223
  item, threadId: this.threadId, turnId: turn.id, startedAtMs: Date.now(),
@@ -5211,7 +5234,7 @@ export class ClaudeSession {
5211
5234
  ...active, status, completedAt,
5212
5235
  durationMs: Math.max(0, (completedAt - (active.startedAt ?? completedAt)) * 1_000),
5213
5236
  error: status === "failed"
5214
- ? { message: errorMessage ?? "Claude turn failed.", codexErrorInfo, additionalDetails: null }
5237
+ ? { message: errorMessage ?? "Claude turn failed.", codexErrorInfo, additionalDetails: null, misalignment: null }
5215
5238
  : null,
5216
5239
  };
5217
5240
  }
@@ -5359,26 +5382,21 @@ export class ClaudeSession {
5359
5382
  }
5360
5383
  else if (fact.type === "taskNotification" && active) {
5361
5384
  active.notifications += 1;
5362
- if (active.request && !active.request.started)
5363
- active.request.covers = active.notifications;
5364
5385
  if (active.result && (!active.commandObserved || active.commandCompleted))
5365
5386
  this.scheduleContinuation(true);
5366
5387
  }
5367
5388
  else if (fact.type === "request" && active) {
5368
- if (!fact.messageStarted && active.request?.started
5369
- && active.notifications > active.request.covers) {
5370
- active.request = { covers: active.notifications, started: false };
5371
- this.cancelContinuation();
5372
- }
5373
- else if (!active.request && (this.hasNotifications() || active.result)) {
5374
- active.request = { covers: active.notifications, started: false };
5389
+ if (!fact.messageStarted || !active.request) {
5390
+ active.request = { covers: active.notifications, beforeFirstToken: active.notifications, started: false };
5375
5391
  this.cancelContinuation();
5376
5392
  }
5377
5393
  if (fact.messageStarted) {
5378
5394
  if (active.result && (this.hasNotifications() || active.goals > 0))
5379
5395
  delete active.result;
5380
- if (active.request)
5396
+ if (active.request && !active.request.started) {
5397
+ active.request.beforeFirstToken = active.notifications;
5381
5398
  active.request.started = true;
5399
+ }
5382
5400
  active.goalInFlight = active.goals > 0;
5383
5401
  this.cancelContinuation();
5384
5402
  }
@@ -5402,7 +5420,11 @@ export class ClaudeSession {
5402
5420
  active.goalInFlight = false;
5403
5421
  }
5404
5422
  if (active.request) {
5405
- active.acknowledged = Math.max(active.acknowledged, active.request.covers);
5423
+ // A human request cannot consume notifications that arrive while it is
5424
+ // already in flight. A task-notification request may announce its own
5425
+ // notification after requesting, but before its first streamed token.
5426
+ const covers = fact.origin === "task-notification" ? active.request.beforeFirstToken : active.request.covers;
5427
+ active.acknowledged = Math.max(active.acknowledged, covers);
5406
5428
  delete active.request;
5407
5429
  }
5408
5430
  else if (fact.origin === "task-notification")
@@ -5496,10 +5518,7 @@ export class ClaudeSession {
5496
5518
  this.lifecycle = undefined;
5497
5519
  this.cancelContinuation();
5498
5520
  this.metrics.turnCompleted(active.result.status);
5499
- if (active.synthetic)
5500
- this.emitLifecycle(undefined, true);
5501
- else
5502
- this.emitLifecycle(completed);
5521
+ this.emitLifecycle(completed, Boolean(active.synthetic));
5503
5522
  }
5504
5523
  hasNotifications() {
5505
5524
  return Boolean(this.lifecycle && this.lifecycle.notifications > this.lifecycle.acknowledged);
@@ -5707,6 +5726,81 @@ export class ClaudeSession {
5707
5726
  }).catch(() => undefined);
5708
5727
  }
5709
5728
  }
5729
+ handleQueue(command) {
5730
+ const queue = this.repository.listQueue(this.threadId);
5731
+ const changed = (items) => {
5732
+ this.repository.setQueue(this.threadId, items);
5733
+ this.output.emit(this.threadId, "thread/queue/changed", { threadId: this.threadId });
5734
+ };
5735
+ const find = (id) => {
5736
+ const index = queue.findIndex((entry) => entry.id === id);
5737
+ if (index < 0)
5738
+ throw invalidRequest(`queued submission not found: ${id}`);
5739
+ return index;
5740
+ };
5741
+ const validInput = (input) => {
5742
+ if (input.length === 0)
5743
+ throw invalidRequest("only user input can be added to the user-message queue");
5744
+ return normalizeUserInput(input);
5745
+ };
5746
+ switch (command.kind) {
5747
+ case "add": {
5748
+ if (this.requireRecord(false).thread.ephemeral) {
5749
+ throw invalidRequest(`ephemeral thread does not support queued submissions: ${this.threadId}`);
5750
+ }
5751
+ if (queue.length >= MAX_QUEUED_SUBMISSIONS) {
5752
+ throw invalidRequest(`queue cannot contain more than ${MAX_QUEUED_SUBMISSIONS} submissions`);
5753
+ }
5754
+ const entry = {
5755
+ id: uuidv7(), input: validInput(command.input), clientUserMessageId: command.clientUserMessageId,
5756
+ };
5757
+ changed([...queue, entry]);
5758
+ return entry;
5759
+ }
5760
+ case "update": {
5761
+ const index = find(command.queuedSubmissionId);
5762
+ const entry = { ...queue[index], input: validInput(command.input) };
5763
+ changed(queue.with(index, entry));
5764
+ return entry;
5765
+ }
5766
+ case "delete": {
5767
+ const remaining = queue.filter((entry) => entry.id !== command.queuedSubmissionId);
5768
+ if (remaining.length !== queue.length)
5769
+ changed(remaining);
5770
+ return remaining.length !== queue.length;
5771
+ }
5772
+ case "reorder": {
5773
+ const ids = new Set(command.queuedSubmissionIds);
5774
+ if (ids.size !== command.queuedSubmissionIds.length || ids.size !== queue.length
5775
+ || !queue.every((entry) => ids.has(entry.id))) {
5776
+ throw invalidRequest("queue reorder must include every queued submission exactly once");
5777
+ }
5778
+ changed(command.queuedSubmissionIds.map((id) => queue[find(id)]));
5779
+ return undefined;
5780
+ }
5781
+ case "take": {
5782
+ const idle = this.isQuiescent() && this.goal.pendingTurns === 0;
5783
+ let index = 0;
5784
+ if (command.manual) {
5785
+ if (queue.length === 0)
5786
+ throw invalidRequest("queue is empty");
5787
+ index = command.queuedSubmissionId === undefined ? 0 : find(command.queuedSubmissionId);
5788
+ if (!idle)
5789
+ throw invalidRequest("thread already has an active or pending turn");
5790
+ }
5791
+ else if (queue.length === 0 || !idle
5792
+ || this.requireRecord(true).thread.turns.at(-1)?.status === "interrupted") {
5793
+ return undefined;
5794
+ }
5795
+ changed(queue.toSpliced(index, 1));
5796
+ return queue[index];
5797
+ }
5798
+ case "restore": {
5799
+ changed([command.entry, ...queue]);
5800
+ return undefined;
5801
+ }
5802
+ }
5803
+ }
5710
5804
  isQuiescent() {
5711
5805
  return !this.lifecycle && !this.compaction && !this.interruptFence && !this.transportStopFence
5712
5806
  && this.pendingNoQuery === 0 && this.pendingInputs === 0 && !this.hasOutputDrains()
@@ -5722,7 +5816,7 @@ export class ClaudeSession {
5722
5816
  const generation = this.lifecycle.notifications;
5723
5817
  this.continuationTimer = setTimeout(() => {
5724
5818
  void this.submit({ type: "lifecycle", runtimeGeneration: this.runtimeGeneration,
5725
- fact: { type: "timer", generation }, source: nullSource });
5819
+ fact: { type: "timer", generation }, source: nullSource }).catch(() => undefined);
5726
5820
  }, 5_000);
5727
5821
  this.continuationTimer.unref();
5728
5822
  }
@@ -5783,6 +5877,24 @@ export class ClaudeSession {
5783
5877
  return waiter;
5784
5878
  }
5785
5879
  dispatchThreadAdmin(command) {
5880
+ if (command.kind === "generatedName") {
5881
+ const record = this.requireRecord(false);
5882
+ if (record.thread.name || record.thread.ephemeral || this.adminOperation)
5883
+ return;
5884
+ const user = this.requireRecord(true).thread.turns[0]?.items.find((item) => item.type === "userMessage");
5885
+ const text = user?.content.flatMap((input) => input.type === "text" ? [input.text] : []).join("\n").trim();
5886
+ // iOS truncates the title worker's user prompt to 2,000 characters.
5887
+ const prompt = command.userPrompt.trim();
5888
+ if (!prompt || (text !== prompt && !(command.userPrompt.length >= 2_000 && text?.startsWith(prompt))))
5889
+ return;
5890
+ const updated = {
5891
+ ...record,
5892
+ thread: { ...record.thread, name: command.name, updatedAt: Math.floor(Date.now() / 1_000) },
5893
+ };
5894
+ const params = { threadId: this.threadId, threadName: command.name };
5895
+ this.commitState(updated, [{ turnId: null, method: "thread/name/updated", params }]);
5896
+ return;
5897
+ }
5786
5898
  if (command.kind === "renameProjection") {
5787
5899
  const record = this.repository.read(command.threadId, false);
5788
5900
  if (!record?.thread.parentThreadId
@@ -6363,7 +6475,7 @@ export class ClaudeSession {
6363
6475
  id: uuidv7(),
6364
6476
  text: value,
6365
6477
  phase: null,
6366
- memoryCitation: null,
6478
+ memoryCitation: null, questions: null,
6367
6479
  delivery: null,
6368
6480
  };
6369
6481
  const turn = {
@@ -6382,13 +6494,7 @@ export class ClaudeSession {
6382
6494
  lastCompletedTurnId: turn.id,
6383
6495
  thread: { ...record.thread, updatedAt: now, recencyAt: now },
6384
6496
  };
6385
- const started = {
6386
- ...turn,
6387
- items: [],
6388
- status: "inProgress",
6389
- completedAt: null,
6390
- durationMs: null,
6391
- };
6497
+ const started = startedTurn({ ...turn, status: "inProgress", completedAt: null, durationMs: null });
6392
6498
  this.commitState(updated, [
6393
6499
  { turnId: turn.id, method: "turn/started", params: { threadId: this.threadId, turn: started } },
6394
6500
  {
@@ -6467,7 +6573,7 @@ export class ClaudeSession {
6467
6573
  id: uuidv7(),
6468
6574
  text: fact.text,
6469
6575
  phase: null,
6470
- memoryCitation: null,
6576
+ memoryCitation: null, questions: null,
6471
6577
  delivery: null,
6472
6578
  };
6473
6579
  turn.items.push(item);
@@ -7093,7 +7199,7 @@ export class ClaudeSession {
7093
7199
  state.completedItems.add(item.id);
7094
7200
  this.scopes.set(childThreadId, state);
7095
7201
  this.publishAt(childThreadId, turn.id, "thread/started", { thread }, source);
7096
- this.publishAt(childThreadId, turn.id, "turn/started", { threadId: childThreadId, turn }, source);
7202
+ this.publishAt(childThreadId, turn.id, "turn/started", { threadId: childThreadId, turn: startedTurn(turn) }, source);
7097
7203
  this.publishAt(childThreadId, turn.id, "item/started", { item, threadId: childThreadId, turnId: turn.id, startedAtMs: Date.now() }, source);
7098
7204
  this.publishAt(childThreadId, turn.id, "item/completed", { item, threadId: childThreadId, turnId: turn.id, completedAtMs: Date.now() }, source);
7099
7205
  return thread;
@@ -7133,7 +7239,7 @@ export class ClaudeSession {
7133
7239
  const state = newMainStreamState(childThreadId, turn.id, updated);
7134
7240
  state.completedItems.add(item.id);
7135
7241
  this.scopes.set(childThreadId, state);
7136
- this.publishAt(childThreadId, turn.id, "turn/started", { threadId: childThreadId, turn }, source);
7242
+ this.publishAt(childThreadId, turn.id, "turn/started", { threadId: childThreadId, turn: startedTurn(turn) }, source);
7137
7243
  this.publishAt(childThreadId, turn.id, "item/started", {
7138
7244
  item, threadId: childThreadId, turnId: turn.id, startedAtMs: Date.now(),
7139
7245
  }, source);
@@ -7160,7 +7266,7 @@ export class ClaudeSession {
7160
7266
  turn.status = status === "completed" ? "completed" : status === "stopped" ? "interrupted" : "failed";
7161
7267
  turn.completedAt = completedAt;
7162
7268
  turn.durationMs = Math.max(0, (completedAt - (turn.startedAt ?? completedAt)) * 1_000);
7163
- turn.error = status === "failed" ? { message: summary, codexErrorInfo: null, additionalDetails: null } : null;
7269
+ turn.error = status === "failed" ? { message: summary, codexErrorInfo: null, additionalDetails: null, misalignment: null } : null;
7164
7270
  const updated = { ...record, lastCompletedTurnId: turn.id,
7165
7271
  thread: { ...record.thread, status: { type: "idle" }, updatedAt: completedAt } };
7166
7272
  this.commitState(updated, [
@@ -7204,7 +7310,7 @@ export class ClaudeSession {
7204
7310
  }
7205
7311
  }
7206
7312
  if (item.type === "agentMessage") {
7207
- item.phase = completeAsCommentary ? "commentary" : null;
7313
+ item.phase = completeAsCommentary ? "commentary" : "final_answer";
7208
7314
  if (completeAsCommentary) {
7209
7315
  state.pendingAgentItemIds.delete(item.id);
7210
7316
  this.completeStreamItem(turn, state, item.id, source);
@@ -7240,7 +7346,8 @@ export class ClaudeSession {
7240
7346
  state.blockItems.delete(index);
7241
7347
  if (block === "text") {
7242
7348
  const item = {
7243
- type: "agentMessage", id: uuidv7(), text: "", phase: null, memoryCitation: null, delivery: null,
7349
+ // Stock never announces a phase-less message; stream as the answer and relabel to commentary if tools follow.
7350
+ type: "agentMessage", id: uuidv7(), text: "", phase: "final_answer", memoryCitation: null, questions: null, delivery: null,
7244
7351
  };
7245
7352
  state.blockItems.set(index, item.id);
7246
7353
  turn.items.push(item);