@gkorepanov/ccodex 0.4.20 → 0.4.23

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 (248) 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 +40 -0
  11. package/dist/claude/service.js +153 -65
  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/repository.d.ts +3 -0
  18. package/dist/claude/session/repository.js +2 -0
  19. package/dist/claude/session/repository.js.map +1 -1
  20. package/dist/claude/session/runtime.js +1 -1
  21. package/dist/claude/session/runtime.js.map +1 -1
  22. package/dist/claude/session/scopeState.js +1 -0
  23. package/dist/claude/session/scopeState.js.map +1 -1
  24. package/dist/claude/session/session.d.ts +1 -0
  25. package/dist/claude/session/session.js +132 -36
  26. package/dist/claude/session/session.js.map +1 -1
  27. package/dist/claude/skillCatalog.js +1 -0
  28. package/dist/claude/skillCatalog.js.map +1 -1
  29. package/dist/claude/statusCommand.js +1 -2
  30. package/dist/claude/statusCommand.js.map +1 -1
  31. package/dist/codex/generated/AuthMode.d.ts +1 -1
  32. package/dist/codex/generated/ClientRequest.d.ts +25 -0
  33. package/dist/codex/generated/InternalSessionSource.d.ts +1 -1
  34. package/dist/codex/generated/ResponseItem.d.ts +3 -1
  35. package/dist/codex/generated/ResponseItemRuntimeSchema.js +2 -2
  36. package/dist/codex/generated/ResponseItemRuntimeSchema.js.map +1 -1
  37. package/dist/codex/generated/ServerNotification.d.ts +23 -0
  38. package/dist/codex/generated/ServerNotificationEnvelope.d.ts +23 -0
  39. package/dist/codex/generated/v2/AllowDenyRequirement.d.ts +1 -0
  40. package/dist/codex/generated/v2/AllowDenyRequirement.js +3 -0
  41. package/dist/codex/generated/v2/AllowDenyRequirement.js.map +1 -0
  42. package/dist/codex/generated/v2/AppLinksConfig.d.ts +11 -0
  43. package/dist/codex/generated/v2/AppLinksConfig.js +3 -0
  44. package/dist/codex/generated/v2/AppLinksConfig.js.map +1 -0
  45. package/dist/codex/generated/v2/AppsConfig.d.ts +5 -0
  46. package/dist/codex/generated/v2/AsyncUserInputQuestion.d.ts +4 -0
  47. package/dist/codex/generated/v2/AsyncUserInputQuestion.js +3 -0
  48. package/dist/codex/generated/v2/AsyncUserInputQuestion.js.map +1 -0
  49. package/dist/codex/generated/v2/AuthRecoveryNotification.d.ts +6 -0
  50. package/dist/codex/generated/v2/AuthRecoveryNotification.js +3 -0
  51. package/dist/codex/generated/v2/AuthRecoveryNotification.js.map +1 -0
  52. package/dist/codex/generated/v2/BedrockSetupParams.d.ts +0 -8
  53. package/dist/codex/generated/v2/BrowserUseAccessApprovalLifetime.d.ts +1 -0
  54. package/dist/codex/generated/v2/BrowserUseAccessApprovalLifetime.js +3 -0
  55. package/dist/codex/generated/v2/BrowserUseAccessApprovalLifetime.js.map +1 -0
  56. package/dist/codex/generated/v2/BrowserUseConfig.d.ts +8 -0
  57. package/dist/codex/generated/v2/BrowserUseConfig.js +3 -0
  58. package/dist/codex/generated/v2/BrowserUseConfig.js.map +1 -0
  59. package/dist/codex/generated/v2/BrowserUseOriginPolicy.d.ts +11 -0
  60. package/dist/codex/generated/v2/BrowserUseOriginPolicy.js +3 -0
  61. package/dist/codex/generated/v2/BrowserUseOriginPolicy.js.map +1 -0
  62. package/dist/codex/generated/v2/BrowserUseOriginPolicyConfig.d.ts +7 -0
  63. package/dist/codex/generated/v2/BrowserUseOriginPolicyConfig.js +3 -0
  64. package/dist/codex/generated/v2/BrowserUseOriginPolicyConfig.js.map +1 -0
  65. package/dist/codex/generated/v2/BrowserUseRequirements.d.ts +7 -0
  66. package/dist/codex/generated/v2/CodexErrorInfo.d.ts +1 -1
  67. package/dist/codex/generated/v2/CollabAgentTool.d.ts +1 -1
  68. package/dist/codex/generated/v2/CollabAgentToolCallStatus.d.ts +1 -1
  69. package/dist/codex/generated/v2/CommandExecutionApprovalKind.d.ts +4 -0
  70. package/dist/codex/generated/v2/CommandExecutionApprovalKind.js +3 -0
  71. package/dist/codex/generated/v2/CommandExecutionApprovalKind.js.map +1 -0
  72. package/dist/codex/generated/v2/CommandExecutionRequestApprovalParams.d.ts +6 -0
  73. package/dist/codex/generated/v2/ComputerUseConfig.d.ts +8 -0
  74. package/dist/codex/generated/v2/ComputerUseConfig.js +3 -0
  75. package/dist/codex/generated/v2/ComputerUseConfig.js.map +1 -0
  76. package/dist/codex/generated/v2/ComputerUseMacosConfig.d.ts +6 -0
  77. package/dist/codex/generated/v2/ComputerUseMacosConfig.js +3 -0
  78. package/dist/codex/generated/v2/ComputerUseMacosConfig.js.map +1 -0
  79. package/dist/codex/generated/v2/ComputerUseMacosRequirements.d.ts +6 -0
  80. package/dist/codex/generated/v2/ComputerUseMacosRequirements.js +3 -0
  81. package/dist/codex/generated/v2/ComputerUseMacosRequirements.js.map +1 -0
  82. package/dist/codex/generated/v2/ComputerUseRequirements.d.ts +7 -0
  83. package/dist/codex/generated/v2/ComputerUseWindowsConfig.d.ts +8 -0
  84. package/dist/codex/generated/v2/ComputerUseWindowsConfig.js +3 -0
  85. package/dist/codex/generated/v2/ComputerUseWindowsConfig.js.map +1 -0
  86. package/dist/codex/generated/v2/ComputerUseWindowsExeConfig.d.ts +7 -0
  87. package/dist/codex/generated/v2/ComputerUseWindowsExeConfig.js +3 -0
  88. package/dist/codex/generated/v2/ComputerUseWindowsExeConfig.js.map +1 -0
  89. package/dist/codex/generated/v2/ComputerUseWindowsExeRequirement.d.ts +7 -0
  90. package/dist/codex/generated/v2/ComputerUseWindowsExeRequirement.js +3 -0
  91. package/dist/codex/generated/v2/ComputerUseWindowsExeRequirement.js.map +1 -0
  92. package/dist/codex/generated/v2/ComputerUseWindowsRequirements.d.ts +8 -0
  93. package/dist/codex/generated/v2/ComputerUseWindowsRequirements.js +3 -0
  94. package/dist/codex/generated/v2/ComputerUseWindowsRequirements.js.map +1 -0
  95. package/dist/codex/generated/v2/Config.d.ts +4 -0
  96. package/dist/codex/generated/v2/ConfigRequirements.d.ts +4 -0
  97. package/dist/codex/generated/v2/CyberAccessProgram.d.ts +5 -0
  98. package/dist/codex/generated/v2/CyberAccessProgram.js +3 -0
  99. package/dist/codex/generated/v2/CyberAccessProgram.js.map +1 -0
  100. package/dist/codex/generated/v2/GetAccountRateLimitsResponse.d.ts +10 -0
  101. package/dist/codex/generated/v2/GuardianApprovalReviewAction.d.ts +7 -0
  102. package/dist/codex/generated/v2/HookEventName.d.ts +1 -1
  103. package/dist/codex/generated/v2/InAppBrowserRequirements.d.ts +3 -0
  104. package/dist/codex/generated/v2/InAppBrowserRequirements.js +3 -0
  105. package/dist/codex/generated/v2/InAppBrowserRequirements.js.map +1 -0
  106. package/dist/codex/generated/v2/ItemGuardianApprovalReviewCompletedNotification.d.ts +2 -0
  107. package/dist/codex/generated/v2/ItemGuardianApprovalReviewStartedNotification.d.ts +2 -0
  108. package/dist/codex/generated/v2/LoginAccountParams.d.ts +6 -0
  109. package/dist/codex/generated/v2/ManagedHooksRequirements.d.ts +1 -0
  110. package/dist/codex/generated/v2/McpServerConnectionStatus.d.ts +1 -0
  111. package/dist/codex/generated/v2/McpServerConnectionStatus.js +3 -0
  112. package/dist/codex/generated/v2/McpServerConnectionStatus.js.map +1 -0
  113. package/dist/codex/generated/v2/McpServerElicitationRequestParams.d.ts +5 -0
  114. package/dist/codex/generated/v2/McpServerEventNotification.d.ts +5 -0
  115. package/dist/codex/generated/v2/McpServerEventNotification.js +3 -0
  116. package/dist/codex/generated/v2/McpServerEventNotification.js.map +1 -0
  117. package/dist/codex/generated/v2/McpServerEventStreamNotification.d.ts +5 -0
  118. package/dist/codex/generated/v2/McpServerEventStreamNotification.js +3 -0
  119. package/dist/codex/generated/v2/McpServerEventStreamNotification.js.map +1 -0
  120. package/dist/codex/generated/v2/McpServerEventStreamStartParams.d.ts +9 -0
  121. package/dist/codex/generated/v2/McpServerEventStreamStartParams.js +3 -0
  122. package/dist/codex/generated/v2/McpServerEventStreamStartParams.js.map +1 -0
  123. package/dist/codex/generated/v2/McpServerEventStreamStartResponse.d.ts +1 -0
  124. package/dist/codex/generated/v2/McpServerEventStreamStartResponse.js +3 -0
  125. package/dist/codex/generated/v2/McpServerEventStreamStartResponse.js.map +1 -0
  126. package/dist/codex/generated/v2/McpServerEventStreamStopParams.d.ts +3 -0
  127. package/dist/codex/generated/v2/McpServerEventStreamStopParams.js +3 -0
  128. package/dist/codex/generated/v2/McpServerEventStreamStopParams.js.map +1 -0
  129. package/dist/codex/generated/v2/McpServerEventStreamStopResponse.d.ts +1 -0
  130. package/dist/codex/generated/v2/McpServerEventStreamStopResponse.js +3 -0
  131. package/dist/codex/generated/v2/McpServerEventStreamStopResponse.js.map +1 -0
  132. package/dist/codex/generated/v2/McpServerStatus.d.ts +5 -0
  133. package/dist/codex/generated/v2/MisalignmentErrorDetails.d.ts +15 -0
  134. package/dist/codex/generated/v2/MisalignmentErrorDetails.js +3 -0
  135. package/dist/codex/generated/v2/MisalignmentErrorDetails.js.map +1 -0
  136. package/dist/codex/generated/v2/MisalignmentSteer.d.ts +3 -0
  137. package/dist/codex/generated/v2/MisalignmentSteer.js +3 -0
  138. package/dist/codex/generated/v2/MisalignmentSteer.js.map +1 -0
  139. package/dist/codex/generated/v2/PluginReconcileChangedPlugin.d.ts +19 -0
  140. package/dist/codex/generated/v2/PluginReconcileChangedPlugin.js +3 -0
  141. package/dist/codex/generated/v2/PluginReconcileChangedPlugin.js.map +1 -0
  142. package/dist/codex/generated/v2/PluginReconcileParams.d.ts +6 -0
  143. package/dist/codex/generated/v2/PluginReconcileParams.js +3 -0
  144. package/dist/codex/generated/v2/PluginReconcileParams.js.map +1 -0
  145. package/dist/codex/generated/v2/PluginReconcileResponse.d.ts +23 -0
  146. package/dist/codex/generated/v2/PluginReconcileResponse.js +3 -0
  147. package/dist/codex/generated/v2/PluginReconcileResponse.js.map +1 -0
  148. package/dist/codex/generated/v2/Project.d.ts +4 -0
  149. package/dist/codex/generated/v2/ProjectListParams.d.ts +10 -0
  150. package/dist/codex/generated/v2/ProjectSortKey.d.ts +1 -0
  151. package/dist/codex/generated/v2/ProjectSortKey.js +3 -0
  152. package/dist/codex/generated/v2/ProjectSortKey.js.map +1 -0
  153. package/dist/codex/generated/v2/RawResponseCompletedNotification.d.ts +2 -0
  154. package/dist/codex/generated/v2/ResponseUsageMetadata.d.ts +8 -0
  155. package/dist/codex/generated/v2/ResponseUsageMetadata.js +3 -0
  156. package/dist/codex/generated/v2/ResponseUsageMetadata.js.map +1 -0
  157. package/dist/codex/generated/v2/SkillMetadata.d.ts +4 -0
  158. package/dist/codex/generated/v2/SubAgentActivityKind.d.ts +1 -1
  159. package/dist/codex/generated/v2/Thread.d.ts +11 -0
  160. package/dist/codex/generated/v2/ThreadForkParams.d.ts +3 -1
  161. package/dist/codex/generated/v2/ThreadItem.d.ts +9 -0
  162. package/dist/codex/generated/v2/ThreadReadParams.d.ts +3 -0
  163. package/dist/codex/generated/v2/ThreadRealtimeBemItemPresentation.d.ts +11 -0
  164. package/dist/codex/generated/v2/ThreadRealtimeBemItemPresentation.js +3 -0
  165. package/dist/codex/generated/v2/ThreadRealtimeBemItemPresentation.js.map +1 -0
  166. package/dist/codex/generated/v2/ThreadRealtimeItem.d.ts +24 -0
  167. package/dist/codex/generated/v2/ThreadRealtimeItem.js +3 -0
  168. package/dist/codex/generated/v2/ThreadRealtimeItem.js.map +1 -0
  169. package/dist/codex/generated/v2/ThreadRealtimeItemCompletedNotification.d.ts +8 -0
  170. package/dist/codex/generated/v2/ThreadRealtimeItemCompletedNotification.js +3 -0
  171. package/dist/codex/generated/v2/ThreadRealtimeItemCompletedNotification.js.map +1 -0
  172. package/dist/codex/generated/v2/ThreadRealtimeItemStartedNotification.d.ts +8 -0
  173. package/dist/codex/generated/v2/ThreadRealtimeItemStartedNotification.js +3 -0
  174. package/dist/codex/generated/v2/ThreadRealtimeItemStartedNotification.js.map +1 -0
  175. package/dist/codex/generated/v2/ThreadRealtimeItemTranscriptDeltaNotification.d.ts +8 -0
  176. package/dist/codex/generated/v2/ThreadRealtimeItemTranscriptDeltaNotification.js +3 -0
  177. package/dist/codex/generated/v2/ThreadRealtimeItemTranscriptDeltaNotification.js.map +1 -0
  178. package/dist/codex/generated/v2/ThreadRealtimeSessionOutcome.d.ts +1 -0
  179. package/dist/codex/generated/v2/ThreadRealtimeSessionOutcome.js +3 -0
  180. package/dist/codex/generated/v2/ThreadRealtimeSessionOutcome.js.map +1 -0
  181. package/dist/codex/generated/v2/ThreadRealtimeStartTransport.d.ts +6 -0
  182. package/dist/codex/generated/v2/ThreadRealtimeTranscriptRole.d.ts +1 -0
  183. package/dist/codex/generated/v2/ThreadRealtimeTranscriptRole.js +3 -0
  184. package/dist/codex/generated/v2/ThreadRealtimeTranscriptRole.js.map +1 -0
  185. package/dist/codex/generated/v2/ThreadResumeParams.d.ts +3 -1
  186. package/dist/codex/generated/v2/ThreadShellCommandParams.d.ts +6 -0
  187. package/dist/codex/generated/v2/ThreadTimelineEntry.d.ts +31 -0
  188. package/dist/codex/generated/v2/ThreadTimelineEntry.js +3 -0
  189. package/dist/codex/generated/v2/ThreadTimelineEntry.js.map +1 -0
  190. package/dist/codex/generated/v2/ThreadTimelineListParams.d.ts +8 -0
  191. package/dist/codex/generated/v2/ThreadTimelineListParams.js +3 -0
  192. package/dist/codex/generated/v2/ThreadTimelineListParams.js.map +1 -0
  193. package/dist/codex/generated/v2/ThreadTimelineListResponse.d.ts +9 -0
  194. package/dist/codex/generated/v2/ThreadTimelineListResponse.js +3 -0
  195. package/dist/codex/generated/v2/ThreadTimelineListResponse.js.map +1 -0
  196. package/dist/codex/generated/v2/TurnError.d.ts +5 -0
  197. package/dist/codex/generated/v2/TurnSettingsUpdateParams.d.ts +34 -0
  198. package/dist/codex/generated/v2/TurnSettingsUpdateParams.js +3 -0
  199. package/dist/codex/generated/v2/TurnSettingsUpdateParams.js.map +1 -0
  200. package/dist/codex/generated/v2/TurnSettingsUpdateResponse.d.ts +4 -0
  201. package/dist/codex/generated/v2/TurnSettingsUpdateResponse.js +3 -0
  202. package/dist/codex/generated/v2/TurnSettingsUpdateResponse.js.map +1 -0
  203. package/dist/codex/generated/v2/TurnSettingsUpdateStatus.d.ts +1 -0
  204. package/dist/codex/generated/v2/TurnSettingsUpdateStatus.js +3 -0
  205. package/dist/codex/generated/v2/TurnSettingsUpdateStatus.js.map +1 -0
  206. package/dist/codex/generated/v2/TurnStartParams.d.ts +19 -0
  207. package/dist/codex/generated/v2/TurnToolOutput.d.ts +6 -0
  208. package/dist/codex/generated/v2/TurnToolOutput.js +3 -0
  209. package/dist/codex/generated/v2/TurnToolOutput.js.map +1 -0
  210. package/dist/codex/generated/v2/index.d.ts +46 -0
  211. package/dist/daemon/probe.js +1 -1
  212. package/dist/gateway/clientConnection.js +84 -7
  213. package/dist/gateway/clientConnection.js.map +1 -1
  214. package/dist/gateway/remoteRelay.js +2 -2
  215. package/dist/gateway/remoteRelay.js.map +1 -1
  216. package/dist/gateway/threadList.d.ts +6 -0
  217. package/dist/gateway/threadList.js +51 -10
  218. package/dist/gateway/threadList.js.map +1 -1
  219. package/dist/gateway/transientNotice.js +4 -4
  220. package/dist/gateway/transientNotice.js.map +1 -1
  221. package/dist/handoff/service.d.ts +10 -2
  222. package/dist/handoff/service.js +163 -106
  223. package/dist/handoff/service.js.map +1 -1
  224. package/dist/handoff/titleGeneration.d.ts +1 -0
  225. package/dist/handoff/titleGeneration.js.map +1 -1
  226. package/dist/management/setup.d.ts +6 -0
  227. package/dist/management/setup.js +11 -3
  228. package/dist/management/setup.js.map +1 -1
  229. package/dist/protocol/search.d.ts +24 -0
  230. package/dist/protocol/search.js +105 -0
  231. package/dist/protocol/search.js.map +1 -0
  232. package/dist/protocol/turnPagination.d.ts +16 -0
  233. package/dist/protocol/turnPagination.js +75 -35
  234. package/dist/protocol/turnPagination.js.map +1 -1
  235. package/dist/runtime/dependencies.js +1 -1
  236. package/dist/store/HybridStore.d.ts +4 -0
  237. package/dist/store/HybridStore.js +1 -1
  238. package/dist/store/HybridStore.js.map +1 -1
  239. package/dist/store/memoryStore.d.ts +6 -0
  240. package/dist/store/memoryStore.js +16 -0
  241. package/dist/store/memoryStore.js.map +1 -1
  242. package/dist/store/sqliteStore.d.ts +3 -0
  243. package/dist/store/sqliteStore.js +57 -0
  244. package/dist/store/sqliteStore.js.map +1 -1
  245. package/legal/THIRD_PARTY_NOTICES.md +187 -140
  246. package/package.json +6 -6
  247. package/scripts/install-claude-stack.sh +27 -4
  248. package/vendor/codex/continuation.md +5 -0
@@ -7,8 +7,9 @@ import { SqliteHybridStore } from "../store/sqliteStore.js";
7
7
  import { LayeredHybridStore } from "../store/memoryStore.js";
8
8
  import { createClaudeQuery } from "./queryFactory.js";
9
9
  import { claudeEnvironment } from "./environment.js";
10
- import { invalidParams } from "../protocol/errors.js";
11
- import { paginateTurns, turnCursor } from "../protocol/turnPagination.js";
10
+ import { invalidParams, invalidRequest } from "../protocol/errors.js";
11
+ import { historyCursors, paginateItems, paginateTurns, startedTurn } from "../protocol/turnPagination.js";
12
+ import { searchTurnOccurrences, threadSearchSnippet } from "../protocol/search.js";
12
13
  import { MetricsRegistry } from "../observability/metrics.js";
13
14
  import { SdkTranscriptBrancher, } from "./transcriptBrancher.js";
14
15
  import { ClaudeRateLimitCoordinator, } from "./rateLimits.js";
@@ -257,6 +258,8 @@ export class ClaudeService {
257
258
  nativeSessionCatalog;
258
259
  ephemeralReleases = new Map();
259
260
  ephemeralReleaseTimers = new Map();
261
+ /** Root threads whose last turn completed or failed and whose queue drains once the session is quiescent. */
262
+ queueDrainPending = new Set();
260
263
  removalRetries = new Map();
261
264
  terminalAdmins = new Map();
262
265
  settingsUpdates = new Map();
@@ -292,7 +295,7 @@ export class ClaudeService {
292
295
  const sessionRepository = new ClaudeSessionRepository(this.store);
293
296
  this.sessionOutput = new ClaudeOutputAdapter(hub);
294
297
  this.rateLimits = new ClaudeRateLimitCoordinator(logger);
295
- this.sessions = new ClaudeSessionRegistry((threadId) => new ClaudeSession(threadId, sessionRepository, this.sessionOutput, undefined, metrics, undefined, (childThreadId) => this.sessions.registerChild(childThreadId, threadId), (childThreadId) => this.sessions.unregisterChild(childThreadId), shellRunner, undefined, {
298
+ this.sessions = new ClaudeSessionRegistry((threadId) => new ClaudeSession(threadId, sessionRepository, this.sessionOutput, undefined, metrics, (update) => this.onSessionLifecycle(threadId, update), (childThreadId) => this.sessions.registerChild(childThreadId, threadId), (childThreadId) => this.sessions.unregisterChild(childThreadId), shellRunner, undefined, {
296
299
  claudeBinary: this.config.claudeBinary,
297
300
  logger: this.logger,
298
301
  queryFactory: this.queryFactory,
@@ -548,10 +551,10 @@ export class ClaudeService {
548
551
  throw invalidParams(`Unknown Claude thread '${threadId}'.`);
549
552
  if (record.thread.parentThreadId) {
550
553
  record = this.withCatalogModel(record);
554
+ record = { ...record, thread: this.withNativeMetadata(record) };
551
555
  return {
552
556
  ...threadResponse(record, !resume.excludeTurns),
553
- turnsBackwardsCursor: record.thread.turns.length ? turnCursor(record.thread.turns.at(-1).id, true) : null,
554
- itemsBackwardsCursor: record.thread.turns.some((turn) => turn.items.length) ? "hyb-item:0" : null,
557
+ ...historyCursors(record.thread.turns),
555
558
  initialTurnsPage: resume.initialTurnsPage
556
559
  ? this.turnsPage({
557
560
  threadId,
@@ -575,10 +578,12 @@ export class ClaudeService {
575
578
  await (await this.sessions.getOrCreate(threadId)).materializeRuntime();
576
579
  record = await this.sessions.submit(threadId, { type: "readThread", includeTurns: true });
577
580
  record = this.withCatalogModel(record);
581
+ record = { ...record, thread: this.withNativeMetadata(record) };
582
+ if (this.store.listQueuedSubmissions(threadId).length)
583
+ this.scheduleQueueDrain(threadId);
578
584
  return {
579
585
  ...threadResponse(record, !resume.excludeTurns),
580
- turnsBackwardsCursor: record.thread.turns.length ? turnCursor(record.thread.turns.at(-1).id, true) : null,
581
- itemsBackwardsCursor: record.thread.turns.some((turn) => turn.items.length) ? "hyb-item:0" : null,
586
+ ...historyCursors(record.thread.turns),
582
587
  initialTurnsPage: resume.initialTurnsPage
583
588
  ? this.turnsPage({
584
589
  threadId,
@@ -629,6 +634,10 @@ export class ClaudeService {
629
634
  }
630
635
  async prepareTurn(params, review) {
631
636
  this.requireIndependentThread(params.threadId, "start a turn in");
637
+ if (params.toolOutput)
638
+ throw invalidParams("Claude threads do not support toolOutput.");
639
+ if (params.serviceTierForTurn != null)
640
+ this.logger.warn("claude.turn.service-tier-for-turn.ignored", { threadId: params.threadId, serviceTierForTurn: params.serviceTierForTurn });
632
641
  const availability = await this.availabilityProbe();
633
642
  if (availability.state !== "ready")
634
643
  throw invalidParams(providerUnavailableMessage(availability));
@@ -655,7 +664,8 @@ export class ClaudeService {
655
664
  let announcement;
656
665
  const startAndWait = () => announcement ? announcement.then(startRuntime) : startRuntime();
657
666
  return {
658
- response: { turn: prepared.turn },
667
+ response: { turn: startedTurn(prepared.turn) },
668
+ turn: prepared.turn,
659
669
  announce: () => announcement ??= this.sessions.submit(params.threadId, { type: "announceTurn", turnId: prepared.turn.id }),
660
670
  start: () => {
661
671
  void startAndWait().catch((error) => this.logger.error("claude.turn.start-failed", { threadId: params.threadId, error: String(error) }));
@@ -891,7 +901,10 @@ export class ClaudeService {
891
901
  }
892
902
  async shellCommand(params) {
893
903
  this.requireIndependentThread(params.threadId, "run a shell command in");
894
- await this.sessions.submit(params.threadId, { type: "runShell", command: params.command });
904
+ const timeoutMs = params.timeoutMs ?? 3_600_000;
905
+ if (timeoutMs < 0)
906
+ throw invalidParams(`thread/shellCommand timeoutMs must be non-negative, got ${timeoutMs}`);
907
+ await this.sessions.submit(params.threadId, { type: "runShell", command: params.command, timeoutMs });
895
908
  return {};
896
909
  }
897
910
  async prepareReview(params) {
@@ -914,6 +927,8 @@ export class ClaudeService {
914
927
  let reviewThreadId = params.threadId;
915
928
  let forkedThread;
916
929
  if (params.delivery === "detached") {
930
+ if (this.requireRecord(params.threadId, false).thread.historyMode === "paginated")
931
+ throw invalidRequest("paginated threads do not support detached review");
917
932
  const fork = await this.forkThread({ threadId: params.threadId, excludeTurns: false });
918
933
  reviewThreadId = fork.thread.id;
919
934
  forkedThread = fork.thread;
@@ -923,7 +938,7 @@ export class ClaudeService {
923
938
  threadId: reviewThreadId,
924
939
  input: [{ type: "text", text: prompt, text_elements: [] }],
925
940
  }, { label: review, display: review });
926
- const userItem = prepared.response.turn.items.find((item) => item.type === "userMessage");
941
+ const userItem = prepared.turn.items.find((item) => item.type === "userMessage");
927
942
  return {
928
943
  response: {
929
944
  turn: {
@@ -982,6 +997,15 @@ export class ClaudeService {
982
997
  this.nativeMetadataRead = read;
983
998
  return read;
984
999
  }
1000
+ async setGeneratedThreadName(params, userPrompt) {
1001
+ const record = this.requireRecord(params.threadId, false);
1002
+ if (record.thread.parentThreadId || this.nativeMetadata.get(record.claudeSessionId)?.customTitle)
1003
+ return;
1004
+ await this.sessions.submit(params.threadId, {
1005
+ type: "threadAdmin",
1006
+ command: { kind: "generatedName", name: params.name, userPrompt },
1007
+ });
1008
+ }
985
1009
  async setThreadName(params) {
986
1010
  const record = this.requireRecord(params.threadId, false);
987
1011
  if (record.thread.parentThreadId) {
@@ -1125,61 +1149,21 @@ export class ClaudeService {
1125
1149
  }
1126
1150
  listItems(params) {
1127
1151
  this.assertThreadAvailable(params.threadId);
1128
- const items = this.store.listTurns(params.threadId)
1129
- .flatMap((turn) => params.turnId && turn.id !== params.turnId
1130
- ? []
1131
- : turn.items.map((item) => ({ turnId: turn.id, item })));
1132
- const ordered = params.sortDirection === "desc" ? [...items].reverse() : items;
1133
- if (params.cursor && !params.cursor.startsWith("hyb-item:"))
1134
- throw invalidParams("Invalid Claude item cursor.");
1135
- const offset = params.cursor?.startsWith("hyb-item:") ? Number(params.cursor.slice("hyb-item:".length)) : 0;
1136
- if (!Number.isInteger(offset) || offset < 0)
1137
- throw invalidParams("Invalid Claude item cursor.");
1138
- const limit = Math.max(1, Math.min(params.limit ?? 50, 100));
1139
- const data = ordered.slice(offset, offset + limit);
1140
- return {
1141
- data,
1142
- nextCursor: offset + data.length < ordered.length ? `hyb-item:${offset + data.length}` : null,
1143
- backwardsCursor: data.length > 0 ? `hyb-item:${Math.max(0, offset - limit)}` : null,
1144
- };
1152
+ return paginateItems(this.store.listTurns(params.threadId), params, ["hyb-item:"]);
1145
1153
  }
1146
1154
  searchOccurrences(params) {
1147
1155
  this.assertThreadAvailable(params.threadId);
1156
+ return searchTurnOccurrences(params.threadId, this.store.listTurns(params.threadId), params);
1157
+ }
1158
+ /** `thread/search` over durable Claude threads: one result per thread with the first matching snippet. */
1159
+ searchThreads(params) {
1148
1160
  const searchTerm = params.searchTerm.trim();
1149
- if (!searchTerm)
1150
- throw invalidParams("thread/searchOccurrences requires a non-empty searchTerm.");
1151
- if (params.cursor && !params.cursor.startsWith("hyb-search:"))
1152
- throw invalidParams("Invalid Claude search cursor.");
1153
- const offset = params.cursor ? Number(params.cursor.slice("hyb-search:".length)) : 0;
1154
- if (!Number.isInteger(offset) || offset < 0)
1155
- throw invalidParams("Invalid Claude search cursor.");
1156
- const turns = this.store.listTurns(params.threadId);
1157
- const needle = searchTerm.toLocaleLowerCase();
1158
- const occurrences = turns.flatMap((turn) => turn.items.flatMap((item) => {
1159
- const text = item.type === "userMessage"
1160
- ? item.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("\n")
1161
- : item.type === "agentMessage" && item.phase !== "commentary" ? item.text : undefined;
1162
- if (text === undefined)
1161
+ return this.listThreads({ archived: params.archived ?? false }).flatMap((thread) => {
1162
+ if (thread.ephemeral)
1163
1163
  return [];
1164
- const haystack = text.toLocaleLowerCase();
1165
- const matches = [];
1166
- for (let start = haystack.indexOf(needle); start >= 0; start = haystack.indexOf(needle, start + needle.length)) {
1167
- matches.push({
1168
- turnId: turn.id,
1169
- itemId: item.id,
1170
- snippet: text,
1171
- snippetMatchRange: { start, end: start + needle.length },
1172
- turnCursor: turnCursor(turn.id, true),
1173
- });
1174
- }
1175
- return matches;
1176
- }));
1177
- const limit = Math.max(1, Math.min(params.limit ?? 50, 100));
1178
- const data = occurrences.slice(offset, offset + limit);
1179
- return {
1180
- data,
1181
- nextCursor: offset + data.length < occurrences.length ? `hyb-search:${offset + data.length}` : null,
1182
- };
1164
+ const snippet = threadSearchSnippet(this.store.listTurns(thread.id), searchTerm);
1165
+ return snippet === undefined ? [] : [{ thread: { ...thread, turns: [] }, snippet }];
1166
+ });
1183
1167
  }
1184
1168
  async forkThread(params, visibleForkedFromId = params.threadId) {
1185
1169
  if (params.path)
@@ -1194,6 +1178,8 @@ export class ClaudeService {
1194
1178
  : undefined;
1195
1179
  const source = await this.sessions.submit(params.threadId, { type: "snapshotBranch" });
1196
1180
  const sourceRecord = source.record;
1181
+ if (sourceRecord.thread.historyMode === "paginated" && params.ephemeral && !params.excludeTurns)
1182
+ throw invalidRequest("ephemeral paginated thread/fork requires `excludeTurns: true`");
1197
1183
  const sidePromotion = Boolean((this.config.features?.sideChatPromotion ?? true)
1198
1184
  && sourceRecord.thread.ephemeral
1199
1185
  && sourceRecord.thread.threadSource === "user"
@@ -1276,7 +1262,8 @@ export class ClaudeService {
1276
1262
  ...sourceRecord.thread, id: threadId, ephemeral: params.ephemeral ?? false,
1277
1263
  section: null, sectionEnteredAt: null, projectId: null,
1278
1264
  sessionId: threadId, forkedFromId: visibleForkedFromId,
1279
- cwd, modelProvider: "claude", createdAt, updatedAt: createdAt, recencyAt: createdAt,
1265
+ cwd, modelProvider: "claude", model: modelPickerId, reasoningEffort,
1266
+ createdAt, updatedAt: createdAt, recencyAt: createdAt,
1280
1267
  status: params.ephemeral ? { type: "idle" } : { type: "notLoaded" },
1281
1268
  canAcceptDirectInput: true,
1282
1269
  name: params.ephemeral
@@ -1336,6 +1323,8 @@ export class ClaudeService {
1336
1323
  }
1337
1324
  async rollbackThread(params) {
1338
1325
  const source = await this.truncationSource(params.threadId, "roll back");
1326
+ if (source.record.thread.historyMode === "paginated")
1327
+ throw invalidRequest("paginated threads do not support thread/rollback");
1339
1328
  if (!Number.isInteger(params.numTurns) || params.numTurns < 1)
1340
1329
  throw invalidParams("numTurns must be at least 1.");
1341
1330
  if (params.numTurns > source.record.thread.turns.length)
@@ -1352,8 +1341,7 @@ export class ClaudeService {
1352
1341
  const retained = (await this.truncateThread(source, keepCount)).thread;
1353
1342
  return {
1354
1343
  thread: { ...retained, turns: [] },
1355
- turnsBackwardsCursor: retained.turns.length ? turnCursor(retained.turns.at(-1).id, true) : null,
1356
- itemsBackwardsCursor: retained.turns.some((turn) => turn.items.length) ? "hyb-item:0" : null,
1344
+ ...historyCursors(retained.turns),
1357
1345
  };
1358
1346
  }
1359
1347
  async truncationSource(threadId, verb) {
@@ -1399,6 +1387,106 @@ export class ClaudeService {
1399
1387
  this.requireIndependentThread(params.threadId, "set a goal on");
1400
1388
  return this.sessions.submit(params.threadId, { type: "goal", command: { kind: "prepareSet", params } }).then((mutation) => this.goalHandle(params.threadId, mutation));
1401
1389
  }
1390
+ async addQueuedSubmission(params) {
1391
+ this.requireIndependentThread(params.threadId, "queue a submission in");
1392
+ const queuedSubmission = await this.sessions.submit(params.threadId, {
1393
+ type: "queue",
1394
+ command: { kind: "add", input: params.input, clientUserMessageId: params.clientUserMessageId },
1395
+ });
1396
+ return { response: { queuedSubmission }, after: () => this.drainQueue(params.threadId) };
1397
+ }
1398
+ /** Offset pagination over the durable per-thread queue; the cursor is the base-10 offset, as in stock. */
1399
+ listQueue(params) {
1400
+ this.requireRecord(params.threadId, false);
1401
+ const cursor = params.cursor ?? null;
1402
+ if (cursor !== null && !/^\d+$/u.test(cursor))
1403
+ throw invalidRequest(`invalid queue pagination cursor: ${cursor}`);
1404
+ const offset = cursor === null ? 0 : Number(cursor);
1405
+ const limit = Math.min(Math.max(params.limit ?? 25, 1), 100);
1406
+ const queue = this.store.listQueuedSubmissions(params.threadId);
1407
+ return {
1408
+ data: queue.slice(offset, offset + limit),
1409
+ nextCursor: offset + limit < queue.length ? String(offset + limit) : null,
1410
+ };
1411
+ }
1412
+ async updateQueuedSubmission(params) {
1413
+ this.requireIndependentThread(params.threadId, "update a queued submission in");
1414
+ const queuedSubmission = await this.sessions.submit(params.threadId, {
1415
+ type: "queue",
1416
+ command: { kind: "update", queuedSubmissionId: params.queuedSubmissionId, input: params.input },
1417
+ });
1418
+ return { queuedSubmission };
1419
+ }
1420
+ async deleteQueuedSubmission(params) {
1421
+ this.requireIndependentThread(params.threadId, "delete a queued submission from");
1422
+ const deleted = await this.sessions.submit(params.threadId, {
1423
+ type: "queue", command: { kind: "delete", queuedSubmissionId: params.queuedSubmissionId },
1424
+ });
1425
+ return { deleted };
1426
+ }
1427
+ async reorderQueue(params) {
1428
+ this.requireIndependentThread(params.threadId, "reorder the queue of");
1429
+ await this.sessions.submit(params.threadId, {
1430
+ type: "queue", command: { kind: "reorder", queuedSubmissionIds: params.queuedSubmissionIds },
1431
+ });
1432
+ return {};
1433
+ }
1434
+ async prepareQueueStart(params) {
1435
+ this.requireIndependentThread(params.threadId, "start a queued submission in");
1436
+ const entry = await this.sessions.submit(params.threadId, {
1437
+ type: "queue",
1438
+ command: {
1439
+ kind: "take",
1440
+ manual: true,
1441
+ ...(params.queuedSubmissionId == null ? {} : { queuedSubmissionId: params.queuedSubmissionId }),
1442
+ },
1443
+ });
1444
+ return this.startQueuedSubmission(params.threadId, entry);
1445
+ }
1446
+ async startQueuedSubmission(threadId, entry) {
1447
+ try {
1448
+ return await this.prepareTurn({ threadId, input: entry.input, clientUserMessageId: entry.clientUserMessageId });
1449
+ }
1450
+ catch (error) {
1451
+ await this.sessions.submit(threadId, { type: "queue", command: { kind: "restore", entry } });
1452
+ throw error;
1453
+ }
1454
+ }
1455
+ /** Starts the head of the queue when the thread is idle and its last turn was not interrupted. */
1456
+ async drainQueue(threadId) {
1457
+ if (this.closing || this.store.listQueuedSubmissions(threadId).length === 0)
1458
+ return;
1459
+ const entry = await this.sessions.submit(threadId, {
1460
+ type: "queue", command: { kind: "take", manual: false },
1461
+ });
1462
+ if (!entry)
1463
+ return;
1464
+ let prepared;
1465
+ try {
1466
+ prepared = await this.startQueuedSubmission(threadId, entry);
1467
+ }
1468
+ catch (error) {
1469
+ this.logger[error instanceof ActiveClaudeTurnError ? "info" : "warn"]("claude.queue.drain-skipped", {
1470
+ threadId, queuedSubmissionId: entry.id, error: String(error),
1471
+ });
1472
+ return;
1473
+ }
1474
+ await prepared.announce();
1475
+ prepared.start();
1476
+ }
1477
+ scheduleQueueDrain(threadId) {
1478
+ queueMicrotask(() => {
1479
+ void this.drainQueue(threadId).catch((error) => {
1480
+ this.logger.warn("claude.queue.drain-failed", { threadId, error: String(error) });
1481
+ });
1482
+ });
1483
+ }
1484
+ onSessionLifecycle(threadId, update) {
1485
+ if (update.completed && update.completed.turn.status !== "interrupted")
1486
+ this.queueDrainPending.add(threadId);
1487
+ if (update.quiescent && this.queueDrainPending.delete(threadId))
1488
+ this.scheduleQueueDrain(threadId);
1489
+ }
1402
1490
  async getGoal(threadId) {
1403
1491
  if (this.requireRecord(threadId, false).thread.parentThreadId)
1404
1492
  return { goal: null };
@@ -1807,8 +1895,8 @@ export class ClaudeService {
1807
1895
  section: null,
1808
1896
  sectionEnteredAt: null,
1809
1897
  projectId: null,
1810
- historyMode: params.historyMode ?? "legacy",
1811
- modelProvider: "claude",
1898
+ historyMode: params.historyMode ?? (params.ephemeral ? "legacy" : "paginated"),
1899
+ modelProvider: "claude", model: modelPickerId, reasoningEffort,
1812
1900
  createdAt,
1813
1901
  updatedAt: createdAt,
1814
1902
  recencyAt: createdAt,