charness 0.0.0-stage → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1044) hide show
  1. package/.env.example +88 -0
  2. package/DEVELOPMENT.md +110 -0
  3. package/LICENSE +21 -0
  4. package/MIGRATION_1_TO_2.md +24 -0
  5. package/README.md +1196 -2
  6. package/dist/accessControl.d.ts +71 -0
  7. package/dist/accessControl.d.ts.map +1 -0
  8. package/dist/accessControl.js +108 -0
  9. package/dist/accessControl.js.map +1 -0
  10. package/dist/adapters/adapterEventRouting.d.ts +51 -0
  11. package/dist/adapters/adapterEventRouting.d.ts.map +1 -0
  12. package/dist/adapters/adapterEventRouting.js +74 -0
  13. package/dist/adapters/adapterEventRouting.js.map +1 -0
  14. package/dist/adapters/adapterNames.d.ts +19 -0
  15. package/dist/adapters/adapterNames.d.ts.map +1 -0
  16. package/dist/adapters/adapterNames.js +25 -0
  17. package/dist/adapters/adapterNames.js.map +1 -0
  18. package/dist/adapters/claudeCliAdapter.d.ts +1351 -0
  19. package/dist/adapters/claudeCliAdapter.d.ts.map +1 -0
  20. package/dist/adapters/claudeCliAdapter.js +4239 -0
  21. package/dist/adapters/claudeCliAdapter.js.map +1 -0
  22. package/dist/adapters/claudeConfigDir.d.ts +40 -0
  23. package/dist/adapters/claudeConfigDir.d.ts.map +1 -0
  24. package/dist/adapters/claudeConfigDir.js +3 -0
  25. package/dist/adapters/claudeConfigDir.js.map +1 -0
  26. package/dist/adapters/claudeJsonStreamAdapter.d.ts +580 -0
  27. package/dist/adapters/claudeJsonStreamAdapter.d.ts.map +1 -0
  28. package/dist/adapters/claudeJsonStreamAdapter.js +1891 -0
  29. package/dist/adapters/claudeJsonStreamAdapter.js.map +1 -0
  30. package/dist/adapters/claudePlatformFlags.d.ts +35 -0
  31. package/dist/adapters/claudePlatformFlags.d.ts.map +1 -0
  32. package/dist/adapters/claudePlatformFlags.js +46 -0
  33. package/dist/adapters/claudePlatformFlags.js.map +1 -0
  34. package/dist/adapters/createAdapter.d.ts +260 -0
  35. package/dist/adapters/createAdapter.d.ts.map +1 -0
  36. package/dist/adapters/createAdapter.js +512 -0
  37. package/dist/adapters/createAdapter.js.map +1 -0
  38. package/dist/adapters/openCodeAdapter.d.ts +1469 -0
  39. package/dist/adapters/openCodeAdapter.d.ts.map +1 -0
  40. package/dist/adapters/openCodeAdapter.js +4623 -0
  41. package/dist/adapters/openCodeAdapter.js.map +1 -0
  42. package/dist/adapters/sessionLaunchDefaults.d.ts +28 -0
  43. package/dist/adapters/sessionLaunchDefaults.d.ts.map +1 -0
  44. package/dist/adapters/sessionLaunchDefaults.js +15 -0
  45. package/dist/adapters/sessionLaunchDefaults.js.map +1 -0
  46. package/dist/adapters/terminalAdapter.d.ts +68 -0
  47. package/dist/adapters/terminalAdapter.d.ts.map +1 -0
  48. package/dist/adapters/terminalAdapter.js +371 -0
  49. package/dist/adapters/terminalAdapter.js.map +1 -0
  50. package/dist/agentLogin/agentLogin.d.ts +44 -0
  51. package/dist/agentLogin/agentLogin.d.ts.map +1 -0
  52. package/dist/agentLogin/agentLogin.js +530 -0
  53. package/dist/agentLogin/agentLogin.js.map +1 -0
  54. package/dist/agentTrigger.d.ts +28 -0
  55. package/dist/agentTrigger.d.ts.map +1 -0
  56. package/dist/agentTrigger.js +53 -0
  57. package/dist/agentTrigger.js.map +1 -0
  58. package/dist/apiErrorRetry.d.ts +214 -0
  59. package/dist/apiErrorRetry.d.ts.map +1 -0
  60. package/dist/apiErrorRetry.js +382 -0
  61. package/dist/apiErrorRetry.js.map +1 -0
  62. package/dist/apiRetryKick.d.ts +157 -0
  63. package/dist/apiRetryKick.d.ts.map +1 -0
  64. package/dist/apiRetryKick.js +174 -0
  65. package/dist/apiRetryKick.js.map +1 -0
  66. package/dist/bootClassifier.d.ts +46 -0
  67. package/dist/bootClassifier.d.ts.map +1 -0
  68. package/dist/bootClassifier.js +43 -0
  69. package/dist/bootClassifier.js.map +1 -0
  70. package/dist/bot.d.ts +207 -0
  71. package/dist/bot.d.ts.map +1 -0
  72. package/dist/bot.js +11226 -0
  73. package/dist/bot.js.map +1 -0
  74. package/dist/botFileStorage.d.ts +60 -0
  75. package/dist/botFileStorage.d.ts.map +1 -0
  76. package/dist/botFileStorage.js +205 -0
  77. package/dist/botFileStorage.js.map +1 -0
  78. package/dist/cli/applyDnsFix.d.ts +7 -0
  79. package/dist/cli/applyDnsFix.d.ts.map +1 -0
  80. package/dist/cli/applyDnsFix.js +46 -0
  81. package/dist/cli/applyDnsFix.js.map +1 -0
  82. package/dist/cli/bot.d.ts +27 -0
  83. package/dist/cli/bot.d.ts.map +1 -0
  84. package/dist/cli/bot.js +98 -0
  85. package/dist/cli/bot.js.map +1 -0
  86. package/dist/cli/botEntry.d.ts +3 -0
  87. package/dist/cli/botEntry.d.ts.map +1 -0
  88. package/dist/cli/botEntry.js +11 -0
  89. package/dist/cli/botEntry.js.map +1 -0
  90. package/dist/cli/claudeProfiles.d.ts +42 -0
  91. package/dist/cli/claudeProfiles.d.ts.map +1 -0
  92. package/dist/cli/claudeProfiles.js +106 -0
  93. package/dist/cli/claudeProfiles.js.map +1 -0
  94. package/dist/cli/connectorGuards.d.ts +31 -0
  95. package/dist/cli/connectorGuards.d.ts.map +1 -0
  96. package/dist/cli/connectorGuards.js +159 -0
  97. package/dist/cli/connectorGuards.js.map +1 -0
  98. package/dist/cli/envLoader.d.ts +34 -0
  99. package/dist/cli/envLoader.d.ts.map +1 -0
  100. package/dist/cli/envLoader.js +132 -0
  101. package/dist/cli/envLoader.js.map +1 -0
  102. package/dist/cli/hot.d.ts +82 -0
  103. package/dist/cli/hot.d.ts.map +1 -0
  104. package/dist/cli/hot.js +323 -0
  105. package/dist/cli/hot.js.map +1 -0
  106. package/dist/cli.d.ts +3 -0
  107. package/dist/cli.d.ts.map +1 -0
  108. package/dist/cli.js +140 -0
  109. package/dist/cli.js.map +1 -0
  110. package/dist/connectors/jira/adf.d.ts +74 -0
  111. package/dist/connectors/jira/adf.d.ts.map +1 -0
  112. package/dist/connectors/jira/adf.js +412 -0
  113. package/dist/connectors/jira/adf.js.map +1 -0
  114. package/dist/connectors/jira/agentBinaries.d.ts +14 -0
  115. package/dist/connectors/jira/agentBinaries.d.ts.map +1 -0
  116. package/dist/connectors/jira/agentBinaries.js +75 -0
  117. package/dist/connectors/jira/agentBinaries.js.map +1 -0
  118. package/dist/connectors/jira/answerSink.d.ts +59 -0
  119. package/dist/connectors/jira/answerSink.d.ts.map +1 -0
  120. package/dist/connectors/jira/answerSink.js +234 -0
  121. package/dist/connectors/jira/answerSink.js.map +1 -0
  122. package/dist/connectors/jira/attachmentDownload.d.ts +41 -0
  123. package/dist/connectors/jira/attachmentDownload.d.ts.map +1 -0
  124. package/dist/connectors/jira/attachmentDownload.js +92 -0
  125. package/dist/connectors/jira/attachmentDownload.js.map +1 -0
  126. package/dist/connectors/jira/attachmentTool.d.ts +50 -0
  127. package/dist/connectors/jira/attachmentTool.d.ts.map +1 -0
  128. package/dist/connectors/jira/attachmentTool.js +166 -0
  129. package/dist/connectors/jira/attachmentTool.js.map +1 -0
  130. package/dist/connectors/jira/client.d.ts +522 -0
  131. package/dist/connectors/jira/client.d.ts.map +1 -0
  132. package/dist/connectors/jira/client.js +491 -0
  133. package/dist/connectors/jira/client.js.map +1 -0
  134. package/dist/connectors/jira/config.d.ts +104 -0
  135. package/dist/connectors/jira/config.d.ts.map +1 -0
  136. package/dist/connectors/jira/config.js +323 -0
  137. package/dist/connectors/jira/config.js.map +1 -0
  138. package/dist/connectors/jira/configFile.d.ts +10 -0
  139. package/dist/connectors/jira/configFile.d.ts.map +1 -0
  140. package/dist/connectors/jira/configFile.js +50 -0
  141. package/dist/connectors/jira/configFile.js.map +1 -0
  142. package/dist/connectors/jira/connector.d.ts +71 -0
  143. package/dist/connectors/jira/connector.d.ts.map +1 -0
  144. package/dist/connectors/jira/connector.js +312 -0
  145. package/dist/connectors/jira/connector.js.map +1 -0
  146. package/dist/connectors/jira/contextLedger.d.ts +60 -0
  147. package/dist/connectors/jira/contextLedger.d.ts.map +1 -0
  148. package/dist/connectors/jira/contextLedger.js +196 -0
  149. package/dist/connectors/jira/contextLedger.js.map +1 -0
  150. package/dist/connectors/jira/contextPreamble.d.ts +18 -0
  151. package/dist/connectors/jira/contextPreamble.d.ts.map +1 -0
  152. package/dist/connectors/jira/contextPreamble.js +31 -0
  153. package/dist/connectors/jira/contextPreamble.js.map +1 -0
  154. package/dist/connectors/jira/inbound.d.ts +141 -0
  155. package/dist/connectors/jira/inbound.d.ts.map +1 -0
  156. package/dist/connectors/jira/inbound.js +331 -0
  157. package/dist/connectors/jira/inbound.js.map +1 -0
  158. package/dist/connectors/jira/issueBlocks.d.ts +74 -0
  159. package/dist/connectors/jira/issueBlocks.d.ts.map +1 -0
  160. package/dist/connectors/jira/issueBlocks.js +257 -0
  161. package/dist/connectors/jira/issueBlocks.js.map +1 -0
  162. package/dist/connectors/jira/issueContext.d.ts +31 -0
  163. package/dist/connectors/jira/issueContext.d.ts.map +1 -0
  164. package/dist/connectors/jira/issueContext.js +70 -0
  165. package/dist/connectors/jira/issueContext.js.map +1 -0
  166. package/dist/connectors/jira/issueDelta.d.ts +38 -0
  167. package/dist/connectors/jira/issueDelta.d.ts.map +1 -0
  168. package/dist/connectors/jira/issueDelta.js +59 -0
  169. package/dist/connectors/jira/issueDelta.js.map +1 -0
  170. package/dist/connectors/jira/mediaPlaceholders.d.ts +22 -0
  171. package/dist/connectors/jira/mediaPlaceholders.d.ts.map +1 -0
  172. package/dist/connectors/jira/mediaPlaceholders.js +105 -0
  173. package/dist/connectors/jira/mediaPlaceholders.js.map +1 -0
  174. package/dist/connectors/jira/outbound.d.ts +6 -0
  175. package/dist/connectors/jira/outbound.d.ts.map +1 -0
  176. package/dist/connectors/jira/outbound.js +38 -0
  177. package/dist/connectors/jira/outbound.js.map +1 -0
  178. package/dist/connectors/jira/prompt.d.ts +39 -0
  179. package/dist/connectors/jira/prompt.d.ts.map +1 -0
  180. package/dist/connectors/jira/prompt.js +102 -0
  181. package/dist/connectors/jira/prompt.js.map +1 -0
  182. package/dist/connectors/jira/promptSpill.d.ts +50 -0
  183. package/dist/connectors/jira/promptSpill.d.ts.map +1 -0
  184. package/dist/connectors/jira/promptSpill.js +157 -0
  185. package/dist/connectors/jira/promptSpill.js.map +1 -0
  186. package/dist/connectors/jira/promptText.d.ts +7 -0
  187. package/dist/connectors/jira/promptText.d.ts.map +1 -0
  188. package/dist/connectors/jira/promptText.js +26 -0
  189. package/dist/connectors/jira/promptText.js.map +1 -0
  190. package/dist/connectors/jira/sessionKeyCodec.d.ts +18 -0
  191. package/dist/connectors/jira/sessionKeyCodec.d.ts.map +1 -0
  192. package/dist/connectors/jira/sessionKeyCodec.js +106 -0
  193. package/dist/connectors/jira/sessionKeyCodec.js.map +1 -0
  194. package/dist/connectors/jira/trigger.d.ts +54 -0
  195. package/dist/connectors/jira/trigger.d.ts.map +1 -0
  196. package/dist/connectors/jira/trigger.js +101 -0
  197. package/dist/connectors/jira/trigger.js.map +1 -0
  198. package/dist/connectors/jira/triggerLog.d.ts +53 -0
  199. package/dist/connectors/jira/triggerLog.d.ts.map +1 -0
  200. package/dist/connectors/jira/triggerLog.js +78 -0
  201. package/dist/connectors/jira/triggerLog.js.map +1 -0
  202. package/dist/connectors/jira/trustedGroup.d.ts +54 -0
  203. package/dist/connectors/jira/trustedGroup.d.ts.map +1 -0
  204. package/dist/connectors/jira/trustedGroup.js +98 -0
  205. package/dist/connectors/jira/trustedGroup.js.map +1 -0
  206. package/dist/connectors/jira/unconfirmedPosts.d.ts +58 -0
  207. package/dist/connectors/jira/unconfirmedPosts.d.ts.map +1 -0
  208. package/dist/connectors/jira/unconfirmedPosts.js +105 -0
  209. package/dist/connectors/jira/unconfirmedPosts.js.map +1 -0
  210. package/dist/connectors/telegram/answerSink.d.ts +46 -0
  211. package/dist/connectors/telegram/answerSink.d.ts.map +1 -0
  212. package/dist/connectors/telegram/answerSink.js +71 -0
  213. package/dist/connectors/telegram/answerSink.js.map +1 -0
  214. package/dist/connectors/telegram/commands/autoContinueLimits.d.ts +34 -0
  215. package/dist/connectors/telegram/commands/autoContinueLimits.d.ts.map +1 -0
  216. package/dist/connectors/telegram/commands/autoContinueLimits.js +112 -0
  217. package/dist/connectors/telegram/commands/autoContinueLimits.js.map +1 -0
  218. package/dist/connectors/telegram/commands/botCore.d.ts +46 -0
  219. package/dist/connectors/telegram/commands/botCore.d.ts.map +1 -0
  220. package/dist/connectors/telegram/commands/botCore.js +3 -0
  221. package/dist/connectors/telegram/commands/botCore.js.map +1 -0
  222. package/dist/connectors/telegram/commands/callbackMessage.d.ts +12 -0
  223. package/dist/connectors/telegram/commands/callbackMessage.d.ts.map +1 -0
  224. package/dist/connectors/telegram/commands/callbackMessage.js +13 -0
  225. package/dist/connectors/telegram/commands/callbackMessage.js.map +1 -0
  226. package/dist/connectors/telegram/commands/claudeAccounts.d.ts +58 -0
  227. package/dist/connectors/telegram/commands/claudeAccounts.d.ts.map +1 -0
  228. package/dist/connectors/telegram/commands/claudeAccounts.js +591 -0
  229. package/dist/connectors/telegram/commands/claudeAccounts.js.map +1 -0
  230. package/dist/connectors/telegram/commands/compaction.d.ts +47 -0
  231. package/dist/connectors/telegram/commands/compaction.d.ts.map +1 -0
  232. package/dist/connectors/telegram/commands/compaction.js +868 -0
  233. package/dist/connectors/telegram/commands/compaction.js.map +1 -0
  234. package/dist/connectors/telegram/commands/displayModes.d.ts +13 -0
  235. package/dist/connectors/telegram/commands/displayModes.d.ts.map +1 -0
  236. package/dist/connectors/telegram/commands/displayModes.js +335 -0
  237. package/dist/connectors/telegram/commands/displayModes.js.map +1 -0
  238. package/dist/connectors/telegram/commands/fallbackChain.d.ts +49 -0
  239. package/dist/connectors/telegram/commands/fallbackChain.d.ts.map +1 -0
  240. package/dist/connectors/telegram/commands/fallbackChain.js +624 -0
  241. package/dist/connectors/telegram/commands/fallbackChain.js.map +1 -0
  242. package/dist/connectors/telegram/commands/modelProviders.d.ts +117 -0
  243. package/dist/connectors/telegram/commands/modelProviders.d.ts.map +1 -0
  244. package/dist/connectors/telegram/commands/modelProviders.js +966 -0
  245. package/dist/connectors/telegram/commands/modelProviders.js.map +1 -0
  246. package/dist/connectors/telegram/commands/reminders.d.ts +54 -0
  247. package/dist/connectors/telegram/commands/reminders.d.ts.map +1 -0
  248. package/dist/connectors/telegram/commands/reminders.js +624 -0
  249. package/dist/connectors/telegram/commands/reminders.js.map +1 -0
  250. package/dist/connectors/telegram/fileIntake.d.ts +166 -0
  251. package/dist/connectors/telegram/fileIntake.d.ts.map +1 -0
  252. package/dist/connectors/telegram/fileIntake.js +304 -0
  253. package/dist/connectors/telegram/fileIntake.js.map +1 -0
  254. package/dist/connectors/telegram/fileSendGateway.d.ts +57 -0
  255. package/dist/connectors/telegram/fileSendGateway.d.ts.map +1 -0
  256. package/dist/connectors/telegram/fileSendGateway.js +221 -0
  257. package/dist/connectors/telegram/fileSendGateway.js.map +1 -0
  258. package/dist/connectors/telegram/foreignKeyFallbacks.d.ts +52 -0
  259. package/dist/connectors/telegram/foreignKeyFallbacks.d.ts.map +1 -0
  260. package/dist/connectors/telegram/foreignKeyFallbacks.js +71 -0
  261. package/dist/connectors/telegram/foreignKeyFallbacks.js.map +1 -0
  262. package/dist/connectors/telegram/inbound.d.ts +131 -0
  263. package/dist/connectors/telegram/inbound.d.ts.map +1 -0
  264. package/dist/connectors/telegram/inbound.js +278 -0
  265. package/dist/connectors/telegram/inbound.js.map +1 -0
  266. package/dist/connectors/telegram/languagePicker.d.ts +32 -0
  267. package/dist/connectors/telegram/languagePicker.d.ts.map +1 -0
  268. package/dist/connectors/telegram/languagePicker.js +55 -0
  269. package/dist/connectors/telegram/languagePicker.js.map +1 -0
  270. package/dist/connectors/telegram/messageSplit.d.ts +62 -0
  271. package/dist/connectors/telegram/messageSplit.d.ts.map +1 -0
  272. package/dist/connectors/telegram/messageSplit.js +119 -0
  273. package/dist/connectors/telegram/messageSplit.js.map +1 -0
  274. package/dist/connectors/telegram/outbound.d.ts +62 -0
  275. package/dist/connectors/telegram/outbound.d.ts.map +1 -0
  276. package/dist/connectors/telegram/outbound.js +116 -0
  277. package/dist/connectors/telegram/outbound.js.map +1 -0
  278. package/dist/connectors/telegram/output/createOutputTransport.d.ts +34 -0
  279. package/dist/connectors/telegram/output/createOutputTransport.d.ts.map +1 -0
  280. package/dist/connectors/telegram/output/createOutputTransport.js +77 -0
  281. package/dist/connectors/telegram/output/createOutputTransport.js.map +1 -0
  282. package/dist/connectors/telegram/output/dmOutputTransport.d.ts +47 -0
  283. package/dist/connectors/telegram/output/dmOutputTransport.d.ts.map +1 -0
  284. package/dist/connectors/telegram/output/dmOutputTransport.js +412 -0
  285. package/dist/connectors/telegram/output/dmOutputTransport.js.map +1 -0
  286. package/dist/connectors/telegram/outputBacklogGlue.d.ts +38 -0
  287. package/dist/connectors/telegram/outputBacklogGlue.d.ts.map +1 -0
  288. package/dist/connectors/telegram/outputBacklogGlue.js +49 -0
  289. package/dist/connectors/telegram/outputBacklogGlue.js.map +1 -0
  290. package/dist/connectors/telegram/outputFlushPlan.d.ts +93 -0
  291. package/dist/connectors/telegram/outputFlushPlan.d.ts.map +1 -0
  292. package/dist/connectors/telegram/outputFlushPlan.js +120 -0
  293. package/dist/connectors/telegram/outputFlushPlan.js.map +1 -0
  294. package/dist/connectors/telegram/questionKeyboards.d.ts +30 -0
  295. package/dist/connectors/telegram/questionKeyboards.d.ts.map +1 -0
  296. package/dist/connectors/telegram/questionKeyboards.js +37 -0
  297. package/dist/connectors/telegram/questionKeyboards.js.map +1 -0
  298. package/dist/connectors/telegram/renderAgentHtml.d.ts +27 -0
  299. package/dist/connectors/telegram/renderAgentHtml.d.ts.map +1 -0
  300. package/dist/connectors/telegram/renderAgentHtml.js +97 -0
  301. package/dist/connectors/telegram/renderAgentHtml.js.map +1 -0
  302. package/dist/connectors/telegram/sessionKeyCodec.d.ts +28 -0
  303. package/dist/connectors/telegram/sessionKeyCodec.d.ts.map +1 -0
  304. package/dist/connectors/telegram/sessionKeyCodec.js +107 -0
  305. package/dist/connectors/telegram/sessionKeyCodec.js.map +1 -0
  306. package/dist/connectors/telegram/telegramCallGuard.d.ts +19 -0
  307. package/dist/connectors/telegram/telegramCallGuard.d.ts.map +1 -0
  308. package/dist/connectors/telegram/telegramCallGuard.js +35 -0
  309. package/dist/connectors/telegram/telegramCallGuard.js.map +1 -0
  310. package/dist/connectors/telegram/timezonePicker.d.ts +85 -0
  311. package/dist/connectors/telegram/timezonePicker.d.ts.map +1 -0
  312. package/dist/connectors/telegram/timezonePicker.js +142 -0
  313. package/dist/connectors/telegram/timezonePicker.js.map +1 -0
  314. package/dist/connectors/telegram/updateDispatcher.d.ts +85 -0
  315. package/dist/connectors/telegram/updateDispatcher.d.ts.map +1 -0
  316. package/dist/connectors/telegram/updateDispatcher.js +159 -0
  317. package/dist/connectors/telegram/updateDispatcher.js.map +1 -0
  318. package/dist/connectors/test/connector.d.ts +52 -0
  319. package/dist/connectors/test/connector.d.ts.map +1 -0
  320. package/dist/connectors/test/connector.js +143 -0
  321. package/dist/connectors/test/connector.js.map +1 -0
  322. package/dist/connectors/test/sessionKeyCodec.d.ts +25 -0
  323. package/dist/connectors/test/sessionKeyCodec.d.ts.map +1 -0
  324. package/dist/connectors/test/sessionKeyCodec.js +50 -0
  325. package/dist/connectors/test/sessionKeyCodec.js.map +1 -0
  326. package/dist/diagLog.d.ts +6 -0
  327. package/dist/diagLog.d.ts.map +1 -0
  328. package/dist/diagLog.js +58 -0
  329. package/dist/diagLog.js.map +1 -0
  330. package/dist/effortLevels.d.ts +68 -0
  331. package/dist/effortLevels.d.ts.map +1 -0
  332. package/dist/effortLevels.js +114 -0
  333. package/dist/effortLevels.js.map +1 -0
  334. package/dist/folderName.d.ts +42 -0
  335. package/dist/folderName.d.ts.map +1 -0
  336. package/dist/folderName.js +51 -0
  337. package/dist/folderName.js.map +1 -0
  338. package/dist/i18n/de.d.ts +2 -0
  339. package/dist/i18n/de.d.ts.map +1 -0
  340. package/dist/i18n/de.js +665 -0
  341. package/dist/i18n/de.js.map +1 -0
  342. package/dist/i18n/en.d.ts +7 -0
  343. package/dist/i18n/en.d.ts.map +1 -0
  344. package/dist/i18n/en.js +694 -0
  345. package/dist/i18n/en.js.map +1 -0
  346. package/dist/i18n/es.d.ts +2 -0
  347. package/dist/i18n/es.d.ts.map +1 -0
  348. package/dist/i18n/es.js +665 -0
  349. package/dist/i18n/es.js.map +1 -0
  350. package/dist/i18n/fr.d.ts +2 -0
  351. package/dist/i18n/fr.d.ts.map +1 -0
  352. package/dist/i18n/fr.js +665 -0
  353. package/dist/i18n/fr.js.map +1 -0
  354. package/dist/i18n/hi.d.ts +2 -0
  355. package/dist/i18n/hi.d.ts.map +1 -0
  356. package/dist/i18n/hi.js +665 -0
  357. package/dist/i18n/hi.js.map +1 -0
  358. package/dist/i18n/ja.d.ts +2 -0
  359. package/dist/i18n/ja.d.ts.map +1 -0
  360. package/dist/i18n/ja.js +665 -0
  361. package/dist/i18n/ja.js.map +1 -0
  362. package/dist/i18n/ka.d.ts +2 -0
  363. package/dist/i18n/ka.d.ts.map +1 -0
  364. package/dist/i18n/ka.js +665 -0
  365. package/dist/i18n/ka.js.map +1 -0
  366. package/dist/i18n/pt.d.ts +2 -0
  367. package/dist/i18n/pt.d.ts.map +1 -0
  368. package/dist/i18n/pt.js +665 -0
  369. package/dist/i18n/pt.js.map +1 -0
  370. package/dist/i18n/ru.d.ts +6 -0
  371. package/dist/i18n/ru.d.ts.map +1 -0
  372. package/dist/i18n/ru.js +668 -0
  373. package/dist/i18n/ru.js.map +1 -0
  374. package/dist/i18n/uk.d.ts +8 -0
  375. package/dist/i18n/uk.d.ts.map +1 -0
  376. package/dist/i18n/uk.js +670 -0
  377. package/dist/i18n/uk.js.map +1 -0
  378. package/dist/i18n/uz.d.ts +2 -0
  379. package/dist/i18n/uz.d.ts.map +1 -0
  380. package/dist/i18n/uz.js +665 -0
  381. package/dist/i18n/uz.js.map +1 -0
  382. package/dist/i18n/zh.d.ts +2 -0
  383. package/dist/i18n/zh.d.ts.map +1 -0
  384. package/dist/i18n/zh.js +665 -0
  385. package/dist/i18n/zh.js.map +1 -0
  386. package/dist/i18n.d.ts +115 -0
  387. package/dist/i18n.d.ts.map +1 -0
  388. package/dist/i18n.js +233 -0
  389. package/dist/i18n.js.map +1 -0
  390. package/dist/index.d.ts +3 -0
  391. package/dist/index.d.ts.map +1 -0
  392. package/dist/index.js +10 -0
  393. package/dist/index.js.map +1 -0
  394. package/dist/installManager.d.ts +99 -0
  395. package/dist/installManager.d.ts.map +1 -0
  396. package/dist/installManager.js +943 -0
  397. package/dist/installManager.js.map +1 -0
  398. package/dist/instanceLock.d.ts +161 -0
  399. package/dist/instanceLock.d.ts.map +1 -0
  400. package/dist/instanceLock.js +388 -0
  401. package/dist/instanceLock.js.map +1 -0
  402. package/dist/mcpConfig.d.ts +76 -0
  403. package/dist/mcpConfig.d.ts.map +1 -0
  404. package/dist/mcpConfig.js +270 -0
  405. package/dist/mcpConfig.js.map +1 -0
  406. package/dist/openCodeOpenQuestion.d.ts +44 -0
  407. package/dist/openCodeOpenQuestion.d.ts.map +1 -0
  408. package/dist/openCodeOpenQuestion.js +64 -0
  409. package/dist/openCodeOpenQuestion.js.map +1 -0
  410. package/dist/openCodeQuestionFlow.d.ts +105 -0
  411. package/dist/openCodeQuestionFlow.d.ts.map +1 -0
  412. package/dist/openCodeQuestionFlow.js +143 -0
  413. package/dist/openCodeQuestionFlow.js.map +1 -0
  414. package/dist/openCodeSessionRouting.d.ts +133 -0
  415. package/dist/openCodeSessionRouting.d.ts.map +1 -0
  416. package/dist/openCodeSessionRouting.js +253 -0
  417. package/dist/openCodeSessionRouting.js.map +1 -0
  418. package/dist/openCodeSessionTitle.d.ts +50 -0
  419. package/dist/openCodeSessionTitle.d.ts.map +1 -0
  420. package/dist/openCodeSessionTitle.js +84 -0
  421. package/dist/openCodeSessionTitle.js.map +1 -0
  422. package/dist/outputTrace.d.ts +108 -0
  423. package/dist/outputTrace.d.ts.map +1 -0
  424. package/dist/outputTrace.js +430 -0
  425. package/dist/outputTrace.js.map +1 -0
  426. package/dist/pendingQuestionRepost.d.ts +47 -0
  427. package/dist/pendingQuestionRepost.d.ts.map +1 -0
  428. package/dist/pendingQuestionRepost.js +29 -0
  429. package/dist/pendingQuestionRepost.js.map +1 -0
  430. package/dist/pinnedStatus.d.ts +52 -0
  431. package/dist/pinnedStatus.d.ts.map +1 -0
  432. package/dist/pinnedStatus.js +36 -0
  433. package/dist/pinnedStatus.js.map +1 -0
  434. package/dist/platform/answerSink.d.ts +93 -0
  435. package/dist/platform/answerSink.d.ts.map +1 -0
  436. package/dist/platform/answerSink.js +31 -0
  437. package/dist/platform/answerSink.js.map +1 -0
  438. package/dist/platform/capabilityFallback.d.ts +39 -0
  439. package/dist/platform/capabilityFallback.d.ts.map +1 -0
  440. package/dist/platform/capabilityFallback.js +55 -0
  441. package/dist/platform/capabilityFallback.js.map +1 -0
  442. package/dist/platform/commandRouter.d.ts +51 -0
  443. package/dist/platform/commandRouter.d.ts.map +1 -0
  444. package/dist/platform/commandRouter.js +53 -0
  445. package/dist/platform/commandRouter.js.map +1 -0
  446. package/dist/platform/connectorSet.d.ts +39 -0
  447. package/dist/platform/connectorSet.d.ts.map +1 -0
  448. package/dist/platform/connectorSet.js +55 -0
  449. package/dist/platform/connectorSet.js.map +1 -0
  450. package/dist/platform/inbound.d.ts +147 -0
  451. package/dist/platform/inbound.d.ts.map +1 -0
  452. package/dist/platform/inbound.js +18 -0
  453. package/dist/platform/inbound.js.map +1 -0
  454. package/dist/platform/outbound.d.ts +225 -0
  455. package/dist/platform/outbound.d.ts.map +1 -0
  456. package/dist/platform/outbound.js +30 -0
  457. package/dist/platform/outbound.js.map +1 -0
  458. package/dist/platform/unservedStateGuard.d.ts +27 -0
  459. package/dist/platform/unservedStateGuard.d.ts.map +1 -0
  460. package/dist/platform/unservedStateGuard.js +42 -0
  461. package/dist/platform/unservedStateGuard.js.map +1 -0
  462. package/dist/postToSession.d.ts +94 -0
  463. package/dist/postToSession.d.ts.map +1 -0
  464. package/dist/postToSession.js +56 -0
  465. package/dist/postToSession.js.map +1 -0
  466. package/dist/progressLine.d.ts +180 -0
  467. package/dist/progressLine.d.ts.map +1 -0
  468. package/dist/progressLine.js +293 -0
  469. package/dist/progressLine.js.map +1 -0
  470. package/dist/rateLimiter.d.ts +246 -0
  471. package/dist/rateLimiter.d.ts.map +1 -0
  472. package/dist/rateLimiter.js +555 -0
  473. package/dist/rateLimiter.js.map +1 -0
  474. package/dist/requests/answerRequest.d.ts +57 -0
  475. package/dist/requests/answerRequest.d.ts.map +1 -0
  476. package/dist/requests/answerRequest.js +96 -0
  477. package/dist/requests/answerRequest.js.map +1 -0
  478. package/dist/requests/answerTail.d.ts +83 -0
  479. package/dist/requests/answerTail.d.ts.map +1 -0
  480. package/dist/requests/answerTail.js +102 -0
  481. package/dist/requests/answerTail.js.map +1 -0
  482. package/dist/requests/limitWaitAnswer.d.ts +87 -0
  483. package/dist/requests/limitWaitAnswer.d.ts.map +1 -0
  484. package/dist/requests/limitWaitAnswer.js +83 -0
  485. package/dist/requests/limitWaitAnswer.js.map +1 -0
  486. package/dist/requests/requestGroup.d.ts +44 -0
  487. package/dist/requests/requestGroup.d.ts.map +1 -0
  488. package/dist/requests/requestGroup.js +63 -0
  489. package/dist/requests/requestGroup.js.map +1 -0
  490. package/dist/requests/requestHeader.d.ts +70 -0
  491. package/dist/requests/requestHeader.d.ts.map +1 -0
  492. package/dist/requests/requestHeader.js +83 -0
  493. package/dist/requests/requestHeader.js.map +1 -0
  494. package/dist/requests/requestLedger.d.ts +217 -0
  495. package/dist/requests/requestLedger.d.ts.map +1 -0
  496. package/dist/requests/requestLedger.js +468 -0
  497. package/dist/requests/requestLedger.js.map +1 -0
  498. package/dist/requests/sessionTurnProbe.d.ts +52 -0
  499. package/dist/requests/sessionTurnProbe.d.ts.map +1 -0
  500. package/dist/requests/sessionTurnProbe.js +29 -0
  501. package/dist/requests/sessionTurnProbe.js.map +1 -0
  502. package/dist/requests/types.d.ts +181 -0
  503. package/dist/requests/types.d.ts.map +1 -0
  504. package/dist/requests/types.js +9 -0
  505. package/dist/requests/types.js.map +1 -0
  506. package/dist/requests/wakeUpEngine.d.ts +160 -0
  507. package/dist/requests/wakeUpEngine.d.ts.map +1 -0
  508. package/dist/requests/wakeUpEngine.js +399 -0
  509. package/dist/requests/wakeUpEngine.js.map +1 -0
  510. package/dist/requests/wakeUpRules.d.ts +151 -0
  511. package/dist/requests/wakeUpRules.d.ts.map +1 -0
  512. package/dist/requests/wakeUpRules.js +167 -0
  513. package/dist/requests/wakeUpRules.js.map +1 -0
  514. package/dist/resumeContext.d.ts +87 -0
  515. package/dist/resumeContext.d.ts.map +1 -0
  516. package/dist/resumeContext.js +114 -0
  517. package/dist/resumeContext.js.map +1 -0
  518. package/dist/scheduler/checkRun.d.ts +95 -0
  519. package/dist/scheduler/checkRun.d.ts.map +1 -0
  520. package/dist/scheduler/checkRun.js +172 -0
  521. package/dist/scheduler/checkRun.js.map +1 -0
  522. package/dist/scheduler/delivery.d.ts +99 -0
  523. package/dist/scheduler/delivery.d.ts.map +1 -0
  524. package/dist/scheduler/delivery.js +212 -0
  525. package/dist/scheduler/delivery.js.map +1 -0
  526. package/dist/scheduler/deliveryKind.d.ts +29 -0
  527. package/dist/scheduler/deliveryKind.d.ts.map +1 -0
  528. package/dist/scheduler/deliveryKind.js +39 -0
  529. package/dist/scheduler/deliveryKind.js.map +1 -0
  530. package/dist/scheduler/directoryThreads.d.ts +19 -0
  531. package/dist/scheduler/directoryThreads.d.ts.map +1 -0
  532. package/dist/scheduler/directoryThreads.js +28 -0
  533. package/dist/scheduler/directoryThreads.js.map +1 -0
  534. package/dist/scheduler/engine.d.ts +77 -0
  535. package/dist/scheduler/engine.d.ts.map +1 -0
  536. package/dist/scheduler/engine.js +337 -0
  537. package/dist/scheduler/engine.js.map +1 -0
  538. package/dist/scheduler/injection.d.ts +102 -0
  539. package/dist/scheduler/injection.d.ts.map +1 -0
  540. package/dist/scheduler/injection.js +122 -0
  541. package/dist/scheduler/injection.js.map +1 -0
  542. package/dist/scheduler/mcpBoot.d.ts +65 -0
  543. package/dist/scheduler/mcpBoot.d.ts.map +1 -0
  544. package/dist/scheduler/mcpBoot.js +60 -0
  545. package/dist/scheduler/mcpBoot.js.map +1 -0
  546. package/dist/scheduler/mcpSurface.d.ts +363 -0
  547. package/dist/scheduler/mcpSurface.d.ts.map +1 -0
  548. package/dist/scheduler/mcpSurface.js +1297 -0
  549. package/dist/scheduler/mcpSurface.js.map +1 -0
  550. package/dist/scheduler/rebindResume.d.ts +27 -0
  551. package/dist/scheduler/rebindResume.d.ts.map +1 -0
  552. package/dist/scheduler/rebindResume.js +17 -0
  553. package/dist/scheduler/rebindResume.js.map +1 -0
  554. package/dist/scheduler/recurrence.d.ts +58 -0
  555. package/dist/scheduler/recurrence.d.ts.map +1 -0
  556. package/dist/scheduler/recurrence.js +210 -0
  557. package/dist/scheduler/recurrence.js.map +1 -0
  558. package/dist/scheduler/runLedger.d.ts +59 -0
  559. package/dist/scheduler/runLedger.d.ts.map +1 -0
  560. package/dist/scheduler/runLedger.js +54 -0
  561. package/dist/scheduler/runLedger.js.map +1 -0
  562. package/dist/scheduler/store.d.ts +97 -0
  563. package/dist/scheduler/store.d.ts.map +1 -0
  564. package/dist/scheduler/store.js +124 -0
  565. package/dist/scheduler/store.js.map +1 -0
  566. package/dist/scheduler/timezoneRecompute.d.ts +61 -0
  567. package/dist/scheduler/timezoneRecompute.d.ts.map +1 -0
  568. package/dist/scheduler/timezoneRecompute.js +46 -0
  569. package/dist/scheduler/timezoneRecompute.js.map +1 -0
  570. package/dist/scheduler/types.d.ts +139 -0
  571. package/dist/scheduler/types.d.ts.map +1 -0
  572. package/dist/scheduler/types.js +8 -0
  573. package/dist/scheduler/types.js.map +1 -0
  574. package/dist/sendErrorClassifier.d.ts +45 -0
  575. package/dist/sendErrorClassifier.d.ts.map +1 -0
  576. package/dist/sendErrorClassifier.js +65 -0
  577. package/dist/sendErrorClassifier.js.map +1 -0
  578. package/dist/sessionKey.d.ts +136 -0
  579. package/dist/sessionKey.d.ts.map +1 -0
  580. package/dist/sessionKey.js +153 -0
  581. package/dist/sessionKey.js.map +1 -0
  582. package/dist/sessionPick.d.ts +42 -0
  583. package/dist/sessionPick.d.ts.map +1 -0
  584. package/dist/sessionPick.js +39 -0
  585. package/dist/sessionPick.js.map +1 -0
  586. package/dist/shutdown.d.ts +126 -0
  587. package/dist/shutdown.d.ts.map +1 -0
  588. package/dist/shutdown.js +164 -0
  589. package/dist/shutdown.js.map +1 -0
  590. package/dist/startupPromptBuffer.d.ts +85 -0
  591. package/dist/startupPromptBuffer.d.ts.map +1 -0
  592. package/dist/startupPromptBuffer.js +123 -0
  593. package/dist/startupPromptBuffer.js.map +1 -0
  594. package/dist/state.d.ts +1416 -0
  595. package/dist/state.d.ts.map +1 -0
  596. package/dist/state.js +2128 -0
  597. package/dist/state.js.map +1 -0
  598. package/dist/threadContextPreamble.d.ts +89 -0
  599. package/dist/threadContextPreamble.d.ts.map +1 -0
  600. package/dist/threadContextPreamble.js +102 -0
  601. package/dist/threadContextPreamble.js.map +1 -0
  602. package/dist/threadRouting.d.ts +164 -0
  603. package/dist/threadRouting.d.ts.map +1 -0
  604. package/dist/threadRouting.js +182 -0
  605. package/dist/threadRouting.js.map +1 -0
  606. package/dist/types.d.ts +1022 -0
  607. package/dist/types.d.ts.map +1 -0
  608. package/dist/types.js +3 -0
  609. package/dist/types.js.map +1 -0
  610. package/dist/utils/abortableFifo.d.ts +10 -0
  611. package/dist/utils/abortableFifo.d.ts.map +1 -0
  612. package/dist/utils/abortableFifo.js +55 -0
  613. package/dist/utils/abortableFifo.js.map +1 -0
  614. package/dist/utils/adoptedToolList.d.ts +27 -0
  615. package/dist/utils/adoptedToolList.d.ts.map +1 -0
  616. package/dist/utils/adoptedToolList.js +22 -0
  617. package/dist/utils/adoptedToolList.js.map +1 -0
  618. package/dist/utils/agentEnvironment.d.ts +42 -0
  619. package/dist/utils/agentEnvironment.d.ts.map +1 -0
  620. package/dist/utils/agentEnvironment.js +122 -0
  621. package/dist/utils/agentEnvironment.js.map +1 -0
  622. package/dist/utils/ansiClean.d.ts +11 -0
  623. package/dist/utils/ansiClean.d.ts.map +1 -0
  624. package/dist/utils/ansiClean.js +139 -0
  625. package/dist/utils/ansiClean.js.map +1 -0
  626. package/dist/utils/autoContinueOnLimit.d.ts +56 -0
  627. package/dist/utils/autoContinueOnLimit.d.ts.map +1 -0
  628. package/dist/utils/autoContinueOnLimit.js +79 -0
  629. package/dist/utils/autoContinueOnLimit.js.map +1 -0
  630. package/dist/utils/canonicalPathContainment.d.ts +7 -0
  631. package/dist/utils/canonicalPathContainment.d.ts.map +1 -0
  632. package/dist/utils/canonicalPathContainment.js +48 -0
  633. package/dist/utils/canonicalPathContainment.js.map +1 -0
  634. package/dist/utils/claudeAccountPickerPlan.d.ts +85 -0
  635. package/dist/utils/claudeAccountPickerPlan.d.ts.map +1 -0
  636. package/dist/utils/claudeAccountPickerPlan.js +123 -0
  637. package/dist/utils/claudeAccountPickerPlan.js.map +1 -0
  638. package/dist/utils/claudeAuthLogin.d.ts +71 -0
  639. package/dist/utils/claudeAuthLogin.d.ts.map +1 -0
  640. package/dist/utils/claudeAuthLogin.js +93 -0
  641. package/dist/utils/claudeAuthLogin.js.map +1 -0
  642. package/dist/utils/claudeChunkClassifier.d.ts +97 -0
  643. package/dist/utils/claudeChunkClassifier.d.ts.map +1 -0
  644. package/dist/utils/claudeChunkClassifier.js +254 -0
  645. package/dist/utils/claudeChunkClassifier.js.map +1 -0
  646. package/dist/utils/claudeCodeVersion.d.ts +31 -0
  647. package/dist/utils/claudeCodeVersion.d.ts.map +1 -0
  648. package/dist/utils/claudeCodeVersion.js +62 -0
  649. package/dist/utils/claudeCodeVersion.js.map +1 -0
  650. package/dist/utils/claudeCompactHook.d.ts +64 -0
  651. package/dist/utils/claudeCompactHook.d.ts.map +1 -0
  652. package/dist/utils/claudeCompactHook.js +98 -0
  653. package/dist/utils/claudeCompactHook.js.map +1 -0
  654. package/dist/utils/claudeLimitSwitch.d.ts +40 -0
  655. package/dist/utils/claudeLimitSwitch.d.ts.map +1 -0
  656. package/dist/utils/claudeLimitSwitch.js +54 -0
  657. package/dist/utils/claudeLimitSwitch.js.map +1 -0
  658. package/dist/utils/claudeLivenessAction.d.ts +208 -0
  659. package/dist/utils/claudeLivenessAction.d.ts.map +1 -0
  660. package/dist/utils/claudeLivenessAction.js +135 -0
  661. package/dist/utils/claudeLivenessAction.js.map +1 -0
  662. package/dist/utils/claudeMcpHeal.d.ts +92 -0
  663. package/dist/utils/claudeMcpHeal.d.ts.map +1 -0
  664. package/dist/utils/claudeMcpHeal.js +91 -0
  665. package/dist/utils/claudeMcpHeal.js.map +1 -0
  666. package/dist/utils/claudeProfileUsageLines.d.ts +15 -0
  667. package/dist/utils/claudeProfileUsageLines.d.ts.map +1 -0
  668. package/dist/utils/claudeProfileUsageLines.js +42 -0
  669. package/dist/utils/claudeProfileUsageLines.js.map +1 -0
  670. package/dist/utils/claudeProfiles.d.ts +117 -0
  671. package/dist/utils/claudeProfiles.d.ts.map +1 -0
  672. package/dist/utils/claudeProfiles.js +285 -0
  673. package/dist/utils/claudeProfiles.js.map +1 -0
  674. package/dist/utils/claudeRelayRouting.d.ts +86 -0
  675. package/dist/utils/claudeRelayRouting.d.ts.map +1 -0
  676. package/dist/utils/claudeRelayRouting.js +159 -0
  677. package/dist/utils/claudeRelayRouting.js.map +1 -0
  678. package/dist/utils/claudeRuntimeInfo.d.ts +26 -0
  679. package/dist/utils/claudeRuntimeInfo.d.ts.map +1 -0
  680. package/dist/utils/claudeRuntimeInfo.js +151 -0
  681. package/dist/utils/claudeRuntimeInfo.js.map +1 -0
  682. package/dist/utils/claudeScrapeShapes.d.ts +256 -0
  683. package/dist/utils/claudeScrapeShapes.d.ts.map +1 -0
  684. package/dist/utils/claudeScrapeShapes.js +290 -0
  685. package/dist/utils/claudeScrapeShapes.js.map +1 -0
  686. package/dist/utils/claudeSessionTitle.d.ts +27 -0
  687. package/dist/utils/claudeSessionTitle.d.ts.map +1 -0
  688. package/dist/utils/claudeSessionTitle.js +90 -0
  689. package/dist/utils/claudeSessionTitle.js.map +1 -0
  690. package/dist/utils/claudeStreamJson.d.ts +214 -0
  691. package/dist/utils/claudeStreamJson.d.ts.map +1 -0
  692. package/dist/utils/claudeStreamJson.js +364 -0
  693. package/dist/utils/claudeStreamJson.js.map +1 -0
  694. package/dist/utils/claudeSubagentTail.d.ts +93 -0
  695. package/dist/utils/claudeSubagentTail.d.ts.map +1 -0
  696. package/dist/utils/claudeSubagentTail.js +136 -0
  697. package/dist/utils/claudeSubagentTail.js.map +1 -0
  698. package/dist/utils/claudeUsage.d.ts +209 -0
  699. package/dist/utils/claudeUsage.d.ts.map +1 -0
  700. package/dist/utils/claudeUsage.js +413 -0
  701. package/dist/utils/claudeUsage.js.map +1 -0
  702. package/dist/utils/claudeUsageRefresher.d.ts +44 -0
  703. package/dist/utils/claudeUsageRefresher.d.ts.map +1 -0
  704. package/dist/utils/claudeUsageRefresher.js +95 -0
  705. package/dist/utils/claudeUsageRefresher.js.map +1 -0
  706. package/dist/utils/clearThreadOutputQueues.d.ts +43 -0
  707. package/dist/utils/clearThreadOutputQueues.d.ts.map +1 -0
  708. package/dist/utils/clearThreadOutputQueues.js +39 -0
  709. package/dist/utils/clearThreadOutputQueues.js.map +1 -0
  710. package/dist/utils/compactCommandRoute.d.ts +45 -0
  711. package/dist/utils/compactCommandRoute.d.ts.map +1 -0
  712. package/dist/utils/compactCommandRoute.js +36 -0
  713. package/dist/utils/compactCommandRoute.js.map +1 -0
  714. package/dist/utils/compactOnIdle.d.ts +329 -0
  715. package/dist/utils/compactOnIdle.d.ts.map +1 -0
  716. package/dist/utils/compactOnIdle.js +379 -0
  717. package/dist/utils/compactOnIdle.js.map +1 -0
  718. package/dist/utils/consoleFileTap.d.ts +51 -0
  719. package/dist/utils/consoleFileTap.d.ts.map +1 -0
  720. package/dist/utils/consoleFileTap.js +86 -0
  721. package/dist/utils/consoleFileTap.js.map +1 -0
  722. package/dist/utils/displayVerbosity.d.ts +44 -0
  723. package/dist/utils/displayVerbosity.d.ts.map +1 -0
  724. package/dist/utils/displayVerbosity.js +75 -0
  725. package/dist/utils/displayVerbosity.js.map +1 -0
  726. package/dist/utils/download.d.ts +72 -0
  727. package/dist/utils/download.d.ts.map +1 -0
  728. package/dist/utils/download.js +216 -0
  729. package/dist/utils/download.js.map +1 -0
  730. package/dist/utils/draftFinalize.d.ts +110 -0
  731. package/dist/utils/draftFinalize.d.ts.map +1 -0
  732. package/dist/utils/draftFinalize.js +100 -0
  733. package/dist/utils/draftFinalize.js.map +1 -0
  734. package/dist/utils/draftId.d.ts +36 -0
  735. package/dist/utils/draftId.d.ts.map +1 -0
  736. package/dist/utils/draftId.js +46 -0
  737. package/dist/utils/draftId.js.map +1 -0
  738. package/dist/utils/draftPacer.d.ts +72 -0
  739. package/dist/utils/draftPacer.d.ts.map +1 -0
  740. package/dist/utils/draftPacer.js +53 -0
  741. package/dist/utils/draftPacer.js.map +1 -0
  742. package/dist/utils/effortStartupKeystroke.d.ts +20 -0
  743. package/dist/utils/effortStartupKeystroke.d.ts.map +1 -0
  744. package/dist/utils/effortStartupKeystroke.js +28 -0
  745. package/dist/utils/effortStartupKeystroke.js.map +1 -0
  746. package/dist/utils/ensureSessionPlan.d.ts +70 -0
  747. package/dist/utils/ensureSessionPlan.d.ts.map +1 -0
  748. package/dist/utils/ensureSessionPlan.js +54 -0
  749. package/dist/utils/ensureSessionPlan.js.map +1 -0
  750. package/dist/utils/fallbackBridge.d.ts +32 -0
  751. package/dist/utils/fallbackBridge.d.ts.map +1 -0
  752. package/dist/utils/fallbackBridge.js +62 -0
  753. package/dist/utils/fallbackBridge.js.map +1 -0
  754. package/dist/utils/fallbackChain.d.ts +299 -0
  755. package/dist/utils/fallbackChain.d.ts.map +1 -0
  756. package/dist/utils/fallbackChain.js +542 -0
  757. package/dist/utils/fallbackChain.js.map +1 -0
  758. package/dist/utils/fileSendPlan.d.ts +217 -0
  759. package/dist/utils/fileSendPlan.d.ts.map +1 -0
  760. package/dist/utils/fileSendPlan.js +291 -0
  761. package/dist/utils/fileSendPlan.js.map +1 -0
  762. package/dist/utils/fileSendService.d.ts +94 -0
  763. package/dist/utils/fileSendService.d.ts.map +1 -0
  764. package/dist/utils/fileSendService.js +387 -0
  765. package/dist/utils/fileSendService.js.map +1 -0
  766. package/dist/utils/groupFinalizePlan.d.ts +38 -0
  767. package/dist/utils/groupFinalizePlan.d.ts.map +1 -0
  768. package/dist/utils/groupFinalizePlan.js +35 -0
  769. package/dist/utils/groupFinalizePlan.js.map +1 -0
  770. package/dist/utils/identicalOutputGuard.d.ts +83 -0
  771. package/dist/utils/identicalOutputGuard.d.ts.map +1 -0
  772. package/dist/utils/identicalOutputGuard.js +99 -0
  773. package/dist/utils/identicalOutputGuard.js.map +1 -0
  774. package/dist/utils/isoTimestamp.d.ts +16 -0
  775. package/dist/utils/isoTimestamp.d.ts.map +1 -0
  776. package/dist/utils/isoTimestamp.js +34 -0
  777. package/dist/utils/isoTimestamp.js.map +1 -0
  778. package/dist/utils/jsonStreamBusyWatchdog.d.ts +130 -0
  779. package/dist/utils/jsonStreamBusyWatchdog.d.ts.map +1 -0
  780. package/dist/utils/jsonStreamBusyWatchdog.js +122 -0
  781. package/dist/utils/jsonStreamBusyWatchdog.js.map +1 -0
  782. package/dist/utils/jsonStreamHost.d.ts +238 -0
  783. package/dist/utils/jsonStreamHost.d.ts.map +1 -0
  784. package/dist/utils/jsonStreamHost.js +438 -0
  785. package/dist/utils/jsonStreamHost.js.map +1 -0
  786. package/dist/utils/keyedTransitionQueue.d.ts +18 -0
  787. package/dist/utils/keyedTransitionQueue.d.ts.map +1 -0
  788. package/dist/utils/keyedTransitionQueue.js +34 -0
  789. package/dist/utils/keyedTransitionQueue.js.map +1 -0
  790. package/dist/utils/limitEpisodeRecovery.d.ts +92 -0
  791. package/dist/utils/limitEpisodeRecovery.d.ts.map +1 -0
  792. package/dist/utils/limitEpisodeRecovery.js +133 -0
  793. package/dist/utils/limitEpisodeRecovery.js.map +1 -0
  794. package/dist/utils/limitHeldPromptQueue.d.ts +48 -0
  795. package/dist/utils/limitHeldPromptQueue.d.ts.map +1 -0
  796. package/dist/utils/limitHeldPromptQueue.js +59 -0
  797. package/dist/utils/limitHeldPromptQueue.js.map +1 -0
  798. package/dist/utils/limitHeldPrompts.d.ts +58 -0
  799. package/dist/utils/limitHeldPrompts.d.ts.map +1 -0
  800. package/dist/utils/limitHeldPrompts.js +65 -0
  801. package/dist/utils/limitHeldPrompts.js.map +1 -0
  802. package/dist/utils/linkPreviewSuppression.d.ts +18 -0
  803. package/dist/utils/linkPreviewSuppression.d.ts.map +1 -0
  804. package/dist/utils/linkPreviewSuppression.js +37 -0
  805. package/dist/utils/linkPreviewSuppression.js.map +1 -0
  806. package/dist/utils/localClock.d.ts +15 -0
  807. package/dist/utils/localClock.d.ts.map +1 -0
  808. package/dist/utils/localClock.js +29 -0
  809. package/dist/utils/localClock.js.map +1 -0
  810. package/dist/utils/markdownTableRender.d.ts +83 -0
  811. package/dist/utils/markdownTableRender.d.ts.map +1 -0
  812. package/dist/utils/markdownTableRender.js +298 -0
  813. package/dist/utils/markdownTableRender.js.map +1 -0
  814. package/dist/utils/mediaGroupCollector.d.ts +51 -0
  815. package/dist/utils/mediaGroupCollector.d.ts.map +1 -0
  816. package/dist/utils/mediaGroupCollector.js +90 -0
  817. package/dist/utils/mediaGroupCollector.js.map +1 -0
  818. package/dist/utils/messageSendService.d.ts +136 -0
  819. package/dist/utils/messageSendService.d.ts.map +1 -0
  820. package/dist/utils/messageSendService.js +165 -0
  821. package/dist/utils/messageSendService.js.map +1 -0
  822. package/dist/utils/minutesOverride.d.ts +7 -0
  823. package/dist/utils/minutesOverride.d.ts.map +1 -0
  824. package/dist/utils/minutesOverride.js +16 -0
  825. package/dist/utils/minutesOverride.js.map +1 -0
  826. package/dist/utils/modelPickerPlan.d.ts +119 -0
  827. package/dist/utils/modelPickerPlan.d.ts.map +1 -0
  828. package/dist/utils/modelPickerPlan.js +171 -0
  829. package/dist/utils/modelPickerPlan.js.map +1 -0
  830. package/dist/utils/modelRecentPlan.d.ts +56 -0
  831. package/dist/utils/modelRecentPlan.d.ts.map +1 -0
  832. package/dist/utils/modelRecentPlan.js +107 -0
  833. package/dist/utils/modelRecentPlan.js.map +1 -0
  834. package/dist/utils/modelSetReplyDecision.d.ts +67 -0
  835. package/dist/utils/modelSetReplyDecision.d.ts.map +1 -0
  836. package/dist/utils/modelSetReplyDecision.js +27 -0
  837. package/dist/utils/modelSetReplyDecision.js.map +1 -0
  838. package/dist/utils/openCodeAuthLogin.d.ts +181 -0
  839. package/dist/utils/openCodeAuthLogin.d.ts.map +1 -0
  840. package/dist/utils/openCodeAuthLogin.js +393 -0
  841. package/dist/utils/openCodeAuthLogin.js.map +1 -0
  842. package/dist/utils/openCodeCompactPlugin.d.ts +81 -0
  843. package/dist/utils/openCodeCompactPlugin.d.ts.map +1 -0
  844. package/dist/utils/openCodeCompactPlugin.js +146 -0
  845. package/dist/utils/openCodeCompactPlugin.js.map +1 -0
  846. package/dist/utils/openCodeTurnActivity.d.ts +67 -0
  847. package/dist/utils/openCodeTurnActivity.d.ts.map +1 -0
  848. package/dist/utils/openCodeTurnActivity.js +27 -0
  849. package/dist/utils/openCodeTurnActivity.js.map +1 -0
  850. package/dist/utils/outputDebounce.d.ts +24 -0
  851. package/dist/utils/outputDebounce.d.ts.map +1 -0
  852. package/dist/utils/outputDebounce.js +30 -0
  853. package/dist/utils/outputDebounce.js.map +1 -0
  854. package/dist/utils/outputFlushTiming.d.ts +54 -0
  855. package/dist/utils/outputFlushTiming.d.ts.map +1 -0
  856. package/dist/utils/outputFlushTiming.js +48 -0
  857. package/dist/utils/outputFlushTiming.js.map +1 -0
  858. package/dist/utils/paginateList.d.ts +25 -0
  859. package/dist/utils/paginateList.d.ts.map +1 -0
  860. package/dist/utils/paginateList.js +32 -0
  861. package/dist/utils/paginateList.js.map +1 -0
  862. package/dist/utils/paneDiff.d.ts +55 -0
  863. package/dist/utils/paneDiff.d.ts.map +1 -0
  864. package/dist/utils/paneDiff.js +88 -0
  865. package/dist/utils/paneDiff.js.map +1 -0
  866. package/dist/utils/paneResizeGuard.d.ts +69 -0
  867. package/dist/utils/paneResizeGuard.d.ts.map +1 -0
  868. package/dist/utils/paneResizeGuard.js +91 -0
  869. package/dist/utils/paneResizeGuard.js.map +1 -0
  870. package/dist/utils/persistAdapterSessionIds.d.ts +39 -0
  871. package/dist/utils/persistAdapterSessionIds.d.ts.map +1 -0
  872. package/dist/utils/persistAdapterSessionIds.js +28 -0
  873. package/dist/utils/persistAdapterSessionIds.js.map +1 -0
  874. package/dist/utils/pinnedBannerSkipDecision.d.ts +44 -0
  875. package/dist/utils/pinnedBannerSkipDecision.d.ts.map +1 -0
  876. package/dist/utils/pinnedBannerSkipDecision.js +20 -0
  877. package/dist/utils/pinnedBannerSkipDecision.js.map +1 -0
  878. package/dist/utils/pollBackoff.d.ts +45 -0
  879. package/dist/utils/pollBackoff.d.ts.map +1 -0
  880. package/dist/utils/pollBackoff.js +44 -0
  881. package/dist/utils/pollBackoff.js.map +1 -0
  882. package/dist/utils/promptDelivery.d.ts +46 -0
  883. package/dist/utils/promptDelivery.d.ts.map +1 -0
  884. package/dist/utils/promptDelivery.js +49 -0
  885. package/dist/utils/promptDelivery.js.map +1 -0
  886. package/dist/utils/providerDisconnectPlan.d.ts +82 -0
  887. package/dist/utils/providerDisconnectPlan.d.ts.map +1 -0
  888. package/dist/utils/providerDisconnectPlan.js +110 -0
  889. package/dist/utils/providerDisconnectPlan.js.map +1 -0
  890. package/dist/utils/rateLimitLog.d.ts +48 -0
  891. package/dist/utils/rateLimitLog.d.ts.map +1 -0
  892. package/dist/utils/rateLimitLog.js +43 -0
  893. package/dist/utils/rateLimitLog.js.map +1 -0
  894. package/dist/utils/recentRelayWindow.d.ts +165 -0
  895. package/dist/utils/recentRelayWindow.d.ts.map +1 -0
  896. package/dist/utils/recentRelayWindow.js +284 -0
  897. package/dist/utils/recentRelayWindow.js.map +1 -0
  898. package/dist/utils/recvPreviewRedaction.d.ts +23 -0
  899. package/dist/utils/recvPreviewRedaction.d.ts.map +1 -0
  900. package/dist/utils/recvPreviewRedaction.js +39 -0
  901. package/dist/utils/recvPreviewRedaction.js.map +1 -0
  902. package/dist/utils/reminderFlow.d.ts +148 -0
  903. package/dist/utils/reminderFlow.d.ts.map +1 -0
  904. package/dist/utils/reminderFlow.js +122 -0
  905. package/dist/utils/reminderFlow.js.map +1 -0
  906. package/dist/utils/reminderScheduleText.d.ts +87 -0
  907. package/dist/utils/reminderScheduleText.d.ts.map +1 -0
  908. package/dist/utils/reminderScheduleText.js +135 -0
  909. package/dist/utils/reminderScheduleText.js.map +1 -0
  910. package/dist/utils/reminderWizard.d.ts +710 -0
  911. package/dist/utils/reminderWizard.d.ts.map +1 -0
  912. package/dist/utils/reminderWizard.js +1164 -0
  913. package/dist/utils/reminderWizard.js.map +1 -0
  914. package/dist/utils/replyQuote.d.ts +111 -0
  915. package/dist/utils/replyQuote.d.ts.map +1 -0
  916. package/dist/utils/replyQuote.js +122 -0
  917. package/dist/utils/replyQuote.js.map +1 -0
  918. package/dist/utils/resolveBinary.d.ts +25 -0
  919. package/dist/utils/resolveBinary.d.ts.map +1 -0
  920. package/dist/utils/resolveBinary.js +99 -0
  921. package/dist/utils/resolveBinary.js.map +1 -0
  922. package/dist/utils/retryAfterHeader.d.ts +7 -0
  923. package/dist/utils/retryAfterHeader.d.ts.map +1 -0
  924. package/dist/utils/retryAfterHeader.js +17 -0
  925. package/dist/utils/retryAfterHeader.js.map +1 -0
  926. package/dist/utils/rotatingJsonlFile.d.ts +40 -0
  927. package/dist/utils/rotatingJsonlFile.d.ts.map +1 -0
  928. package/dist/utils/rotatingJsonlFile.js +106 -0
  929. package/dist/utils/rotatingJsonlFile.js.map +1 -0
  930. package/dist/utils/rotatingLogFile.d.ts +25 -0
  931. package/dist/utils/rotatingLogFile.d.ts.map +1 -0
  932. package/dist/utils/rotatingLogFile.js +74 -0
  933. package/dist/utils/rotatingLogFile.js.map +1 -0
  934. package/dist/utils/sendRateTracker.d.ts +59 -0
  935. package/dist/utils/sendRateTracker.d.ts.map +1 -0
  936. package/dist/utils/sendRateTracker.js +144 -0
  937. package/dist/utils/sendRateTracker.js.map +1 -0
  938. package/dist/utils/serialQueue.d.ts +5 -0
  939. package/dist/utils/serialQueue.d.ts.map +1 -0
  940. package/dist/utils/serialQueue.js +14 -0
  941. package/dist/utils/serialQueue.js.map +1 -0
  942. package/dist/utils/sseStreamLifecycle.d.ts +32 -0
  943. package/dist/utils/sseStreamLifecycle.d.ts.map +1 -0
  944. package/dist/utils/sseStreamLifecycle.js +41 -0
  945. package/dist/utils/sseStreamLifecycle.js.map +1 -0
  946. package/dist/utils/startupReadiness.d.ts +119 -0
  947. package/dist/utils/startupReadiness.d.ts.map +1 -0
  948. package/dist/utils/startupReadiness.js +148 -0
  949. package/dist/utils/startupReadiness.js.map +1 -0
  950. package/dist/utils/statusFlushDecision.d.ts +18 -0
  951. package/dist/utils/statusFlushDecision.d.ts.map +1 -0
  952. package/dist/utils/statusFlushDecision.js +53 -0
  953. package/dist/utils/statusFlushDecision.js.map +1 -0
  954. package/dist/utils/subagentRender.d.ts +52 -0
  955. package/dist/utils/subagentRender.d.ts.map +1 -0
  956. package/dist/utils/subagentRender.js +66 -0
  957. package/dist/utils/subagentRender.js.map +1 -0
  958. package/dist/utils/subagentStatusRender.d.ts +90 -0
  959. package/dist/utils/subagentStatusRender.d.ts.map +1 -0
  960. package/dist/utils/subagentStatusRender.js +124 -0
  961. package/dist/utils/subagentStatusRender.js.map +1 -0
  962. package/dist/utils/telegramError.d.ts +2 -0
  963. package/dist/utils/telegramError.d.ts.map +1 -0
  964. package/dist/utils/telegramError.js +16 -0
  965. package/dist/utils/telegramError.js.map +1 -0
  966. package/dist/utils/terminalEmitPlan.d.ts +74 -0
  967. package/dist/utils/terminalEmitPlan.d.ts.map +1 -0
  968. package/dist/utils/terminalEmitPlan.js +86 -0
  969. package/dist/utils/terminalEmitPlan.js.map +1 -0
  970. package/dist/utils/thinkingRender.d.ts +74 -0
  971. package/dist/utils/thinkingRender.d.ts.map +1 -0
  972. package/dist/utils/thinkingRender.js +85 -0
  973. package/dist/utils/thinkingRender.js.map +1 -0
  974. package/dist/utils/threadStatusReport.d.ts +79 -0
  975. package/dist/utils/threadStatusReport.d.ts.map +1 -0
  976. package/dist/utils/threadStatusReport.js +88 -0
  977. package/dist/utils/threadStatusReport.js.map +1 -0
  978. package/dist/utils/threadToggle.d.ts +29 -0
  979. package/dist/utils/threadToggle.d.ts.map +1 -0
  980. package/dist/utils/threadToggle.js +39 -0
  981. package/dist/utils/threadToggle.js.map +1 -0
  982. package/dist/utils/timezone.d.ts +125 -0
  983. package/dist/utils/timezone.d.ts.map +1 -0
  984. package/dist/utils/timezone.js +278 -0
  985. package/dist/utils/timezone.js.map +1 -0
  986. package/dist/utils/tmuxExec.d.ts +61 -0
  987. package/dist/utils/tmuxExec.d.ts.map +1 -0
  988. package/dist/utils/tmuxExec.js +109 -0
  989. package/dist/utils/tmuxExec.js.map +1 -0
  990. package/dist/utils/tmuxSessionName.d.ts +34 -0
  991. package/dist/utils/tmuxSessionName.d.ts.map +1 -0
  992. package/dist/utils/tmuxSessionName.js +51 -0
  993. package/dist/utils/tmuxSessionName.js.map +1 -0
  994. package/dist/utils/toolResultRender.d.ts +61 -0
  995. package/dist/utils/toolResultRender.d.ts.map +1 -0
  996. package/dist/utils/toolResultRender.js +62 -0
  997. package/dist/utils/toolResultRender.js.map +1 -0
  998. package/dist/utils/topicRequest.d.ts +61 -0
  999. package/dist/utils/topicRequest.d.ts.map +1 -0
  1000. package/dist/utils/topicRequest.js +68 -0
  1001. package/dist/utils/topicRequest.js.map +1 -0
  1002. package/dist/utils/topicView.d.ts +55 -0
  1003. package/dist/utils/topicView.d.ts.map +1 -0
  1004. package/dist/utils/topicView.js +56 -0
  1005. package/dist/utils/topicView.js.map +1 -0
  1006. package/dist/utils/transcribeAudio.d.ts +89 -0
  1007. package/dist/utils/transcribeAudio.d.ts.map +1 -0
  1008. package/dist/utils/transcribeAudio.js +249 -0
  1009. package/dist/utils/transcribeAudio.js.map +1 -0
  1010. package/dist/utils/transientFrames.d.ts +52 -0
  1011. package/dist/utils/transientFrames.d.ts.map +1 -0
  1012. package/dist/utils/transientFrames.js +41 -0
  1013. package/dist/utils/transientFrames.js.map +1 -0
  1014. package/dist/utils/typingActive.d.ts +35 -0
  1015. package/dist/utils/typingActive.d.ts.map +1 -0
  1016. package/dist/utils/typingActive.js +22 -0
  1017. package/dist/utils/typingActive.js.map +1 -0
  1018. package/dist/utils/typingLoopBackstop.d.ts +64 -0
  1019. package/dist/utils/typingLoopBackstop.d.ts.map +1 -0
  1020. package/dist/utils/typingLoopBackstop.js +68 -0
  1021. package/dist/utils/typingLoopBackstop.js.map +1 -0
  1022. package/dist/utils/verbosityRender.d.ts +18 -0
  1023. package/dist/utils/verbosityRender.d.ts.map +1 -0
  1024. package/dist/utils/verbosityRender.js +17 -0
  1025. package/dist/utils/verbosityRender.js.map +1 -0
  1026. package/dist/utils/wedgeRecovery.d.ts +57 -0
  1027. package/dist/utils/wedgeRecovery.d.ts.map +1 -0
  1028. package/dist/utils/wedgeRecovery.js +24 -0
  1029. package/dist/utils/wedgeRecovery.js.map +1 -0
  1030. package/dist/utils.d.ts +30 -0
  1031. package/dist/utils.d.ts.map +1 -0
  1032. package/dist/utils.js +61 -0
  1033. package/dist/utils.js.map +1 -0
  1034. package/dist/validation.d.ts +113 -0
  1035. package/dist/validation.d.ts.map +1 -0
  1036. package/dist/validation.js +226 -0
  1037. package/dist/validation.js.map +1 -0
  1038. package/dist/voiceQueue.d.ts +7 -0
  1039. package/dist/voiceQueue.d.ts.map +1 -0
  1040. package/dist/voiceQueue.js +33 -0
  1041. package/dist/voiceQueue.js.map +1 -0
  1042. package/examples/.env.example +17 -0
  1043. package/examples/docker-compose.yml +36 -0
  1044. package/package.json +83 -4
@@ -0,0 +1,1891 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ClaudeJsonStreamAdapter = exports.claudeJsonStreamUsageLogPrefix = void 0;
37
+ exports.readLatestCompactSummaryFromTranscript = readLatestCompactSummaryFromTranscript;
38
+ const crypto_1 = require("crypto");
39
+ const events_1 = require("events");
40
+ const fs = __importStar(require("fs"));
41
+ const sessionKey_1 = require("../sessionKey");
42
+ const apiErrorRetry_1 = require("../apiErrorRetry");
43
+ const installManager_1 = require("../installManager");
44
+ const mcpConfig_1 = require("../mcpConfig");
45
+ const claudeCompactHook_1 = require("../utils/claudeCompactHook");
46
+ const claudePlatformFlags_1 = require("./claudePlatformFlags");
47
+ const state_1 = require("../state");
48
+ const resolveBinary_1 = require("../utils/resolveBinary");
49
+ const displayVerbosity_1 = require("../utils/displayVerbosity");
50
+ const i18n_1 = require("../i18n");
51
+ const resumeContext_1 = require("../resumeContext");
52
+ const effortLevels_1 = require("../effortLevels");
53
+ const claudeCliAdapter_1 = require("./claudeCliAdapter");
54
+ const claudeStreamJson_1 = require("../utils/claudeStreamJson");
55
+ const claudeMcpHeal_1 = require("../utils/claudeMcpHeal");
56
+ const tmuxExec_1 = require("../utils/tmuxExec");
57
+ const pollBackoff_1 = require("../utils/pollBackoff");
58
+ const claudeRuntimeInfo_1 = require("../utils/claudeRuntimeInfo");
59
+ const jsonStreamBusyWatchdog_1 = require("../utils/jsonStreamBusyWatchdog");
60
+ const jsonStreamHost_1 = require("../utils/jsonStreamHost");
61
+ const adapterNames_1 = require("./adapterNames");
62
+ const claudeCodeVersion_1 = require("../utils/claudeCodeVersion");
63
+ const sessionLaunchDefaults_1 = require("./sessionLaunchDefaults");
64
+ /**
65
+ * In-flight explicit stops, per key — a second stop (or a start's implicit stop)
66
+ * AWAITS the first instead of racing it: the delayed first `tmux kill-session`
67
+ * could otherwise land AFTER a fresh same-name spawn and kill the new session.
68
+ * MODULE-level, shared by the idle and the per-turn adapter instances: both host
69
+ * a conversation under the SAME tmux name and dir, and a `/claude_mode` switch
70
+ * stops the process on one instance while the other spawns the next.
71
+ */
72
+ const stopsInFlightByKey = new Map();
73
+ /**
74
+ * @description Coalesce window for streamed answer/thinking deltas before an
75
+ * `output`/`thinking` emit — the CLI streams per-token, so raw per-delta emits
76
+ * would flood Telegram with edits. Mirrors OpenCode's `sseOutputBatchMs` (500).
77
+ */
78
+ const streamOutputBatchMs = 350;
79
+ /** Prefix of the per-turn token accounting line (L-D11); the process-level e2e
80
+ * and the live cache check read it. */
81
+ exports.claudeJsonStreamUsageLogPrefix = '[ClaudeJson] usage ';
82
+ /** How long to wait for the `initialize` control-response handshake before
83
+ * proceeding without the interactive control channel (questions unavailable). */
84
+ const initializeHandshakeTimeoutMs = 15000;
85
+ /**
86
+ * @description SECOND Claude backend: drives the `claude` CLI over its
87
+ * documented `--input-format stream-json --output-format stream-json` protocol
88
+ * (typed events, no TUI scrape) as an EXTERNAL tmux-hosted process per
89
+ * {@link SessionKey} (plan 2026-07-05-jsonstream-restart-isolation): a `#!/bin/sh`
90
+ * wrapper backgrounds claude with stdin on a FIFO the process itself holds
91
+ * `0<>` and stdout appended to a `stdout.jsonl` the adapter TAILS — so a bot
92
+ * restart (every hot reload) neither EOFs claude's stdin nor loses its output;
93
+ * the restarted bot re-adopts the tmux session and replays the missed tail.
94
+ * Same structured events, on the SAME subscription billing (proven
95
+ * `apiKeySource:"none"` + `seven_day` rate-limit event; the wrapper runs
96
+ * `env -u ANTHROPIC_API_KEY`, never `--bare`).
97
+ *
98
+ * Structural template is {@link import('./openCodeAdapter').OpenCodeAdapter}
99
+ * (event-driven, own process, per-key session map); the Claude on-disk
100
+ * transcript readers are reused for `/sessions` / resume / recap.
101
+ *
102
+ * Interactive questions (`AskUserQuestion`) reach Telegram through the same
103
+ * `question` event + pin flow as OpenCode: the CLI surfaces them as a
104
+ * `control_request` (`subtype:"can_use_tool"`, `tool_name:"AskUserQuestion"`)
105
+ * on stdout, answered with a `control_response` carrying
106
+ * `updatedInput.answers` on stdin — a wire protocol reverse-engineered from a
107
+ * live capture + the open-source `@anthropic-ai/claude-agent-sdk`. Ordinary
108
+ * tool permissions are auto-allowed (operator trusts their own agent — parity
109
+ * with the tmux backend's `bypassPermissions`), so only questions block.
110
+ *
111
+ * A topic flips between it and the tmux-scrape backend via `/claude_mode`
112
+ * (they share the on-disk transcript, so the switch resumes the same
113
+ * conversation). The DEFAULT Claude backend (`getDefaultClaudeBackendName`):
114
+ * `/login` is handled out-of-band by the bot (`claude auth login` in a pty),
115
+ * so it no longer needs a TUI to sign in.
116
+ */
117
+ class ClaudeJsonStreamAdapter extends events_1.EventEmitter {
118
+ name;
119
+ label;
120
+ /**
121
+ * `idle` — the process stays between turns and is stopped at the idle mark (L3);
122
+ * `perTurn` — the process is stopped right after each turn (L5, L-D3), by the
123
+ * bot on the `turnEnded` event. Same host, same session layout: one process per
124
+ * conversation at a time whichever lifecycle runs it.
125
+ */
126
+ lifecycle;
127
+ constructor(options = { lifecycle: 'idle' }) {
128
+ super();
129
+ this.lifecycle = options.lifecycle;
130
+ this.name = options.lifecycle === 'perTurn' ? adapterNames_1.claudePerTurnAdapterName : adapterNames_1.claudeJsonStreamAdapterName;
131
+ this.label = options.lifecycle === 'perTurn' ? 'Claude Code (per-turn)' : 'Claude Code (stream)';
132
+ }
133
+ /** Emits incremental text deltas (like the tmux scrape) → the transports
134
+ * synthesise continuation (`getDmDraftContinuation` / group delta path). */
135
+ outputsDeltas = true;
136
+ /** No TUI banner → keep the bot's `agent.ready` cue + one-shot boot ping (L2). */
137
+ selfGreetsOnStart = false;
138
+ sessions = new Map();
139
+ claudePath = (0, resolveBinary_1.resolveClaudeBinary)();
140
+ displayPrefsReader = null;
141
+ seenWatermarkWriter = null;
142
+ jsonStreamTailWriter = null;
143
+ sessionLaunchDefaultsReader = null;
144
+ claudeConfigDirReader = null;
145
+ /** The stops in flight — the module-level map shared by both lifecycles' instances (see {@link stopsInFlightByKey}). */
146
+ stopsInFlight = stopsInFlightByKey;
147
+ setDisplayPrefsReader(reader) {
148
+ this.displayPrefsReader = reader;
149
+ }
150
+ setSeenWatermarkWriter(writer) {
151
+ this.seenWatermarkWriter = writer;
152
+ }
153
+ setJsonStreamTailWriter(writer) {
154
+ this.jsonStreamTailWriter = writer;
155
+ }
156
+ setSessionLaunchDefaultsReader(reader) {
157
+ this.sessionLaunchDefaultsReader = reader;
158
+ }
159
+ setClaudeConfigDirReader(reader) {
160
+ this.claudeConfigDirReader = reader;
161
+ }
162
+ claudeRateLimitSink = null;
163
+ /** Where a session's `rate_limit_event` frames go (the bot's per-profile usage cache). */
164
+ setClaudeRateLimitSink(sink) {
165
+ this.claudeRateLimitSink = sink;
166
+ }
167
+ /** The config directory the conversation's next process must start with (its account profile). */
168
+ resolveConfigDir(key) {
169
+ return this.claudeConfigDirReader?.(key) ?? null;
170
+ }
171
+ getLaunchOptions(key) {
172
+ return (0, sessionLaunchDefaults_1.getSessionLaunchOptions)({
173
+ savedEffort: this.getEffort(key),
174
+ defaults: this.sessionLaunchDefaultsReader?.(key) ?? null,
175
+ botDefaultEffort: effortLevels_1.defaultEffortLevel,
176
+ });
177
+ }
178
+ getDisplayPrefs(key) {
179
+ return this.displayPrefsReader?.(key) ?? (0, displayVerbosity_1.getDefaultDisplayPrefs)();
180
+ }
181
+ advanceSeenWatermark(key, watermark) {
182
+ this.seenWatermarkWriter?.(key, watermark);
183
+ }
184
+ // ─────────────────────────────────────────────────────────────────────────
185
+ // Lifecycle (S1)
186
+ // ─────────────────────────────────────────────────────────────────────────
187
+ async startSession(key, workDir, _args, sessionId) {
188
+ await this.stopSessionInternal(key);
189
+ const id = sessionId && (0, claudeCliAdapter_1.checkIsValidUuid)(sessionId) ? sessionId : (0, crypto_1.randomUUID)();
190
+ await this.spawnSession(key, workDir, id, { ...this.getLaunchOptions(key), resume: false, configDir: this.resolveConfigDir(key) });
191
+ }
192
+ async resumeSession(key, workDir, sessionId, options) {
193
+ await this.stopSessionInternal(key);
194
+ if (!(0, claudeCliAdapter_1.checkIsValidUuid)(sessionId))
195
+ throw new Error(`Invalid sessionId: ${sessionId}`);
196
+ await this.spawnSession(key, workDir, sessionId, { ...this.getLaunchOptions(key), resume: true, configDir: this.resolveConfigDir(key) });
197
+ // Post the short last-N-turn context block ONLY on the explicit user resume
198
+ // (`/sessions` pick) — a silent re-attach stays quiet (ResumeSessionOptions).
199
+ if (options?.isWithRecentContext) {
200
+ try {
201
+ const turns = await this.getRecentTurns(key, workDir, sessionId, resumeContext_1.resumeContextTurnLimit);
202
+ const rendered = (0, resumeContext_1.formatResumeContext)(turns);
203
+ if (rendered)
204
+ this.emit('output', key, rendered, { isComplete: true });
205
+ }
206
+ catch (e) {
207
+ console.warn(`[ClaudeJson] resume context block failed:`, e instanceof Error ? e.message : e);
208
+ }
209
+ }
210
+ }
211
+ /**
212
+ * @description Spawn (or re-spawn) the CLI process for a thread as an
213
+ * EXTERNAL tmux-hosted process (wrapper + FIFO stdin + stdout file — the
214
+ * probe-proven layout in `utils/jsonStreamHost.ts`), start the stdout tail
215
+ * poller, and complete the `initialize` control handshake (which enables the
216
+ * `AskUserQuestion` control channel). Rejects — with the wrapper's exit code
217
+ * and a stderr excerpt — if the process fails to come up. Reused by start /
218
+ * resume / effort-respawn.
219
+ */
220
+ async spawnSession(key, workDir, sessionId, opts) {
221
+ if (!(0, installManager_1.checkIsInstalled)('claude')) {
222
+ this.emit('output', key, 'Installing Claude Code...');
223
+ await (0, installManager_1.installTool)('claude');
224
+ }
225
+ // Claude writes the transcript only with the first turn, so a session that never took one
226
+ // (e.g. `/model` right after `/new`) has nothing to `--resume` and the CLI exits
227
+ // "No conversation found". Such a session is started again under the same id instead.
228
+ const isResumable = opts.resume && fs.existsSync((0, claudeCliAdapter_1.getClaudeTranscriptPath)(workDir, sessionId));
229
+ const mcpFlags = await (0, mcpConfig_1.prepareMcpFlags)({ key, dataDir: (0, state_1.resolveDataDir)() });
230
+ const args = [
231
+ '-p',
232
+ // Followed by an option on purpose: `--disallowedTools` takes several values.
233
+ ...(0, claudePlatformFlags_1.getClaudePlatformFlags)(key),
234
+ '--input-format', 'stream-json',
235
+ '--output-format', 'stream-json',
236
+ '--include-partial-messages',
237
+ '--verbose',
238
+ '--replay-user-messages',
239
+ // Bypass ALL permission checks (tmux-backend parity) so the operator's own
240
+ // agent never stalls on a permission prompt. `--dangerously-skip-permissions`
241
+ // + `bypassPermissions` means regular tools (Bash/Read/…) never route through
242
+ // the stdio prompt tool at all. `--permission-prompt-tool stdio` STAYS: it is
243
+ // what keeps `AskUserQuestion` in the tool list AND still routes it through the
244
+ // control channel even under bypass (verified live on v2.1.201 — bypass does
245
+ // NOT suppress AskUserQuestion, and `apiKeySource` stays `none`). The residual
246
+ // circuit-breakers claude never bypasses (`rm -rf /`, `rm -rf ~`) still arrive
247
+ // as `can_use_tool` and are answered by the generic auto-allow below.
248
+ '--dangerously-skip-permissions',
249
+ '--permission-mode', 'bypassPermissions',
250
+ '--permission-prompt-tool', 'stdio',
251
+ ];
252
+ if (isResumable)
253
+ args.push('--resume', sessionId);
254
+ else
255
+ args.push('--session-id', sessionId);
256
+ if (opts.model)
257
+ args.push('--model', opts.model);
258
+ if (opts.effort)
259
+ args.push('--effort', opts.effort);
260
+ args.push(...mcpFlags);
261
+ // Overflow-triggered compaction gets the bot's summary guidance (see the module).
262
+ args.push(...(0, claudeCompactHook_1.prepareClaudeCompactHookFlags)((0, state_1.resolveDataDir)()));
263
+ // Subscription billing: the wrapper runs `env -u ANTHROPIC_API_KEY` (a set
264
+ // key would meter the API); a tracker conversation's wrapper starts claude
265
+ // with `env -i` and the agent allowlist instead (R32) — no key either. The CLI
266
+ // reads the OAuth login from ~/.claude — `apiKeySource:"none"` (probe-verified
267
+ // under the wrapper).
268
+ const sessionDir = (0, jsonStreamHost_1.resolveJsonStreamSessionDir)((0, state_1.resolveDataDir)(), key);
269
+ const paths = (0, jsonStreamHost_1.getJsonStreamSessionPaths)(sessionDir);
270
+ const tmuxName = (0, jsonStreamHost_1.buildJsonStreamTmuxSessionName)(key);
271
+ console.log(`[ClaudeJson] spawn ${(0, sessionKey_1.keyToString)(key)} session=${sessionId} resume=${isResumable} effort=${opts.effort} model=${opts.model ?? 'default'} configDir=${opts.configDir ?? 'default'} (tmux ${tmuxName})`);
272
+ let pid;
273
+ let fifoFd;
274
+ try {
275
+ // Fresh host layout — a stale dir/fifo from a crashed run must not be reused.
276
+ fs.rmSync(sessionDir, { recursive: true, force: true });
277
+ fs.mkdirSync(sessionDir, { recursive: true, mode: 0o700 });
278
+ await (0, tmuxExec_1.execFilePromise)('mkfifo', [paths.stdinFifo]);
279
+ fs.writeFileSync(paths.wrapperFile, (0, jsonStreamHost_1.buildWrapperScript)(this.claudePath, args, workDir, paths, (0, claudePlatformFlags_1.getClaudePlatformEnvironment)(key), opts.configDir), { mode: 0o755 });
280
+ // A stale same-name tmux session (crashed bot / pre-adopt build) would make
281
+ // `new-session` fail — and must not keep running unowned next to ours.
282
+ await (0, tmuxExec_1.tmuxAsync)('kill-session', '-t', (0, tmuxExec_1.getTmuxSessionTarget)(tmuxName));
283
+ await (0, tmuxExec_1.tmuxOrThrowAsync)('new-session', '-d', '-s', tmuxName, paths.wrapperFile);
284
+ const pidRead = await (0, jsonStreamHost_1.waitForPidFile)(paths.pidFile);
285
+ if (pidRead === null)
286
+ throw new Error(`claude never wrote its pid file${describeSpawnFailure(paths)}`);
287
+ pid = pidRead;
288
+ const fdRead = await (0, jsonStreamHost_1.openFifoWriterNonBlocking)(paths.stdinFifo);
289
+ if (fdRead === null)
290
+ throw new Error(`claude is not holding its stdin FIFO${describeSpawnFailure(paths)}`);
291
+ fifoFd = fdRead;
292
+ }
293
+ catch (e) {
294
+ (0, mcpConfig_1.cleanupMcpTempFiles)({ key, dataDir: (0, state_1.resolveDataDir)() });
295
+ await (0, tmuxExec_1.tmuxAsync)('kill-session', '-t', (0, tmuxExec_1.getTmuxSessionTarget)(tmuxName));
296
+ try {
297
+ fs.rmSync(sessionDir, { recursive: true, force: true });
298
+ }
299
+ catch { /* best-effort */ }
300
+ throw new Error(`Failed to start Claude stream session: ${e instanceof Error ? e.message : String(e)}`);
301
+ }
302
+ const session = {
303
+ key, workDir, sessionId,
304
+ pid, paths, fifoFd,
305
+ stdinWriteChain: Promise.resolve(),
306
+ tail: (0, jsonStreamHost_1.createStdoutTailState)(0),
307
+ pollTimer: null, pollDelayMs: pollBackoff_1.basePollIntervalMs, unchangedStreak: 0,
308
+ isOversizeWarned: false, lastPersistedTailOffset: 0,
309
+ reader: new claudeStreamJson_1.ClaudeStreamLineReader(),
310
+ isActive: true, isStopping: false, isSuspending: false, isRespawning: false, isBusy: false, unconsumedInputCount: 0,
311
+ lastStdoutActivityAt: Date.now(), outstandingToolUseIds: new Set(),
312
+ model: opts.model, reportedModel: null, effort: opts.effort,
313
+ configDir: opts.configDir, isConfigDirSwitchPending: false,
314
+ currentResponseText: '', emittedLength: 0, outputTimer: null,
315
+ reasoningText: '', reasoningStartedAt: null, reasoningTimer: null, reasoningActive: false,
316
+ toolNamesById: new Map(), questionToolUseIds: new Set(),
317
+ subagentActive: false, childResponseText: '', childEmittedLength: 0, childOutputTimer: null,
318
+ pendingInitResolve: null, initRequestId: null, pendingControlRequests: new Map(),
319
+ compactionInProgress: false, pendingCompaction: null,
320
+ pendingQuestion: null, apiErrorFired: false, swallowNextAbortError: false,
321
+ lastWatermarkOffset: -1,
322
+ backgroundTaskIds: new Set(), claudeCodeVersion: null, applyingChunk: null,
323
+ adoptCatchUpOffset: null, adoptCatchUpResolvers: [],
324
+ };
325
+ this.sessions.set((0, sessionKey_1.keyToString)(key), session);
326
+ // A fresh spawn starts a fresh stdout file — reset the persisted tail offset
327
+ // so a later adopt never resumes from a previous run's position.
328
+ this.jsonStreamTailWriter?.(key, buildTailRecord(session, 0));
329
+ this.schedulePoll(session, pollBackoff_1.basePollIntervalMs);
330
+ // Initialize handshake: declares the interactive control channel (permission
331
+ // prompts + AskUserQuestion route to stdio). Without it AskUserQuestion is not
332
+ // even in the tool list (verified). Best-effort — proceed on timeout so a
333
+ // handshake hiccup never blocks a plain-output session. The response arrives
334
+ // through the tail poller started above.
335
+ await this.performInitialize(session);
336
+ this.emit('started', key);
337
+ }
338
+ // ─────────────────────────────────────────────────────────────────────────
339
+ // External-process transport: stdout tail poll + exit detection
340
+ // ─────────────────────────────────────────────────────────────────────────
341
+ /** Arm the next tail poll (single-flight `setTimeout` chain, mirroring the
342
+ * scrape backend's `schedulePoll` — never overlapping ticks). */
343
+ schedulePoll(session, delayMs) {
344
+ if (!session.isActive)
345
+ return;
346
+ if (session.pollTimer)
347
+ clearTimeout(session.pollTimer);
348
+ session.pollDelayMs = delayMs;
349
+ session.pollTimer = setTimeout(() => {
350
+ session.pollTimer = null;
351
+ this.pollTailTick(session);
352
+ }, delayMs);
353
+ }
354
+ /** Snap the tail cadence back to base — called on every stdin write, when
355
+ * fresh output is expected shortly (mirrors the scrape backend's write snap). */
356
+ snapPollToBase(session) {
357
+ if (!session.isActive)
358
+ return;
359
+ session.unchangedStreak = 0;
360
+ this.schedulePoll(session, pollBackoff_1.basePollIntervalMs);
361
+ }
362
+ pollTailTick(session) {
363
+ if (!session.isActive || this.sessions.get((0, sessionKey_1.keyToString)(session.key)) !== session)
364
+ return;
365
+ let isChanged = false;
366
+ try {
367
+ isChanged = this.drainStdoutTail(session);
368
+ }
369
+ catch (e) {
370
+ console.warn(`[ClaudeJson] stdout tail read failed for ${(0, sessionKey_1.keyToString)(session.key)}:`, e instanceof Error ? e.message : e);
371
+ }
372
+ // Exit detection (locked decision): the wrapper writes `exitcode` when
373
+ // claude exits; pid-alive covers a hard-killed wrapper that never wrote it.
374
+ const exitCode = (0, jsonStreamHost_1.readExitCodeFile)(session.paths.exitCodeFile);
375
+ if (exitCode !== null || !(0, jsonStreamHost_1.checkIsPidAlive)(session.pid)) {
376
+ // Final drain — bytes flushed at process exit may postdate the read above.
377
+ try {
378
+ this.drainStdoutTail(session);
379
+ }
380
+ catch { /* already reported above */ }
381
+ this.finalizeExternalExit(session, exitCode ?? (0, jsonStreamHost_1.readExitCodeFile)(session.paths.exitCodeFile));
382
+ return;
383
+ }
384
+ this.settleAdoptCatchUp(session, false);
385
+ // Backstop: a busy session gone silent with nothing in flight lost its
386
+ // terminal `result` — clear the stuck flag so the typing indicator can't hang.
387
+ this.maybeClearBusyOnIdle(session);
388
+ const next = (0, pollBackoff_1.getNextPollDelay)({ isChanged, currentDelayMs: session.pollDelayMs, unchangedStreak: session.unchangedStreak });
389
+ session.unchangedStreak = next.unchangedStreak;
390
+ this.schedulePoll(session, next.delayMs);
391
+ }
392
+ /**
393
+ * @description Idle watchdog (bounded safety net). `isBusy` is cleared in
394
+ * exactly one place — a processed terminal `result` (`handleTurnEnd`) — so a
395
+ * single missed `result` (an aborted `interrupt`, a process gone quiet after
396
+ * the answer, a future CLI dropping the line) hangs the native typing
397
+ * indicator indefinitely. When the session is busy but stdout has been silent
398
+ * past {@link busyIdleWatchdogMs} and nothing is genuinely in flight, the turn
399
+ * has really ended: clear the flag. The pure decision + its rationale live in
400
+ * `utils/jsonStreamBusyWatchdog` — every in-flight signal (tool / sub-agent /
401
+ * question / batched answer) vetoes the clear, so a legitimately long-running
402
+ * turn is never truncated (a working agent never goes silent with nothing in
403
+ * flight — it streams deltas or waits on a tool/sub-agent/user).
404
+ */
405
+ maybeClearBusyOnIdle(session) {
406
+ const shouldClear = (0, jsonStreamBusyWatchdog_1.checkShouldClearBusyOnIdle)({
407
+ isBusy: session.isBusy,
408
+ msSinceStdoutActivity: Date.now() - session.lastStdoutActivityAt,
409
+ idleTimeoutMs: jsonStreamBusyWatchdog_1.busyIdleWatchdogMs,
410
+ outstandingToolCount: session.outstandingToolUseIds.size,
411
+ subagentActive: session.subagentActive,
412
+ hasPendingQuestion: session.pendingQuestion !== null,
413
+ hasUnflushedAnswer: session.currentResponseText.length !== session.emittedLength,
414
+ });
415
+ if (!shouldClear)
416
+ return;
417
+ console.warn(`[ClaudeJson] busy-idle watchdog: ${(0, sessionKey_1.keyToString)(session.key)} idle ${jsonStreamBusyWatchdog_1.busyIdleWatchdogMs}ms with nothing in flight — clearing stuck busy (missed terminal result?)`);
418
+ session.isBusy = false;
419
+ this.finishReasoning(session);
420
+ // The record must not keep saying "turn in flight": an adopt would restore the cleared flag.
421
+ this.jsonStreamTailWriter?.(session.key, buildTailRecord(session, session.lastPersistedTailOffset));
422
+ }
423
+ /**
424
+ * @description Read whatever `stdout.jsonl` grew since the last poll and feed
425
+ * it through the SAME decode → line-reader → classifier pipeline the stdio
426
+ * pipe used to feed. Returns whether anything new was consumed (drives the
427
+ * adaptive poll backoff). After consuming, persists the line-boundary tail
428
+ * offset so a bot restart resumes exactly where processing stopped.
429
+ */
430
+ drainStdoutTail(session) {
431
+ const size = (0, jsonStreamHost_1.getFileSize)(session.paths.stdoutFile);
432
+ if (size === null)
433
+ return false; // not created yet (claude still booting)
434
+ if (size > jsonStreamHost_1.stdoutOversizeWarnBytes && !session.isOversizeWarned) {
435
+ session.isOversizeWarned = true;
436
+ console.warn(`[ClaudeJson] stdout log for ${(0, sessionKey_1.keyToString)(session.key)} exceeds ${jsonStreamHost_1.stdoutOversizeWarnBytes} bytes (no rotation in v1)`);
437
+ }
438
+ const decision = (0, jsonStreamHost_1.getStdoutTailDecision)(session.tail, size);
439
+ if (decision.kind === 'reseed') {
440
+ // External truncation — the retained partial line died with the old file.
441
+ session.reader = new claudeStreamJson_1.ClaudeStreamLineReader();
442
+ return false;
443
+ }
444
+ if (decision.kind === 'none')
445
+ return false;
446
+ const chunk = (0, jsonStreamHost_1.readFileByteRange)(session.paths.stdoutFile, decision.startOffset, decision.endOffset);
447
+ if (chunk.length === 0)
448
+ return false;
449
+ const text = (0, jsonStreamHost_1.decodeStdoutTailChunk)(session.tail, chunk);
450
+ if (text) {
451
+ // Any new stdout — even a `tool_progress` frame the classifier ignores —
452
+ // means the process is alive and working; feed the idle watchdog's clock.
453
+ session.lastStdoutActivityAt = Date.now();
454
+ this.onStdout(session, text);
455
+ }
456
+ // Persist the consumption boundary ONLY when nothing sits in the answer /
457
+ // child batchers: the offset means "everything before here has LEFT the
458
+ // adapter", so text still waiting in a 350ms batch must hold it back —
459
+ // otherwise a reload in that window skips the batched text on replay
460
+ // (live seam-loss 2026-07-05: lines 216–221 were consumed
461
+ // into the batch, the offset moved past them, and the kill dropped them).
462
+ // A deferred persist happens in `flushAnswer` / the child flush, right
463
+ // after the batched text is emitted.
464
+ if (checkIsEmitCaughtUp(session))
465
+ this.persistTailOffset(session);
466
+ return true;
467
+ }
468
+ /** Persist the tail's line-boundary offset (monotonic; inert until the
469
+ * writer is registered — same idiom as the seen-watermark writer). */
470
+ persistTailOffset(session) {
471
+ if (session.applyingChunk) {
472
+ session.applyingChunk.isPersistDeferred = true;
473
+ return;
474
+ }
475
+ const boundary = (0, jsonStreamHost_1.getStdoutLineBoundaryOffset)(session.tail, session.reader.pending);
476
+ if (boundary <= session.lastPersistedTailOffset)
477
+ return;
478
+ session.lastPersistedTailOffset = boundary;
479
+ this.jsonStreamTailWriter?.(session.key, buildTailRecord(session, boundary));
480
+ }
481
+ /**
482
+ * @description Single teardown convergence point for the external process —
483
+ * both the explicit stop (`isStopping` → `stopped`) and the poll tick's exit
484
+ * detection (→ `closed`, with the wrapper-reported exit code and a stderr
485
+ * excerpt). Kills any tmux leftovers, removes the host dir, and cleans the
486
+ * MCP temp files. A respawn owns its own transition (`isRespawning`).
487
+ */
488
+ finalizeExternalExit(session, exitCode) {
489
+ if (session.isRespawning)
490
+ return; // an effort/model re-spawn owns the transition
491
+ const key = session.key;
492
+ // Only act if this session is still the current one for the key.
493
+ if (this.sessions.get((0, sessionKey_1.keyToString)(key)) !== session)
494
+ return;
495
+ this.clearTimers(session);
496
+ session.isActive = false;
497
+ this.sessions.delete((0, sessionKey_1.keyToString)(key));
498
+ this.settleAdoptCatchUp(session, true);
499
+ this.closeFifo(session);
500
+ const stderrTail = session.isStopping ? '' : (0, jsonStreamHost_1.readStderrTail)(session.paths.stderrFile);
501
+ void (0, tmuxExec_1.tmuxAsync)('kill-session', '-t', (0, tmuxExec_1.getTmuxSessionTarget)((0, jsonStreamHost_1.buildJsonStreamTmuxSessionName)(key)));
502
+ try {
503
+ fs.rmSync(session.paths.dir, { recursive: true, force: true });
504
+ }
505
+ catch { /* best-effort */ }
506
+ (0, mcpConfig_1.cleanupMcpTempFiles)({ key, dataDir: (0, state_1.resolveDataDir)() });
507
+ if (session.isSuspending) {
508
+ // The session id stays persisted: the next trigger resumes the conversation (L3).
509
+ console.log(`[ClaudeJson] session ${(0, sessionKey_1.keyToString)(key)} suspended (code=${exitCode})`);
510
+ this.emit('suspended', key);
511
+ }
512
+ else if (session.isStopping) {
513
+ console.log(`[ClaudeJson] session ${(0, sessionKey_1.keyToString)(key)} stopped (code=${exitCode})`);
514
+ this.emit('stopped', key);
515
+ }
516
+ else {
517
+ console.warn(`[ClaudeJson] session ${(0, sessionKey_1.keyToString)(key)} exited unexpectedly (code=${exitCode})${stderrTail ? ` stderr: ${stderrTail}` : ''}`);
518
+ this.emit('closed', key);
519
+ }
520
+ }
521
+ /** Close the FIFO fd AFTER any queued writes settle, so an in-flight write
522
+ * never hits a closed fd (EBADF noise on every stop). */
523
+ closeFifo(session) {
524
+ const fd = session.fifoFd;
525
+ session.stdinWriteChain = session.stdinWriteChain
526
+ .catch(() => { })
527
+ .then(() => { try {
528
+ fs.closeSync(fd);
529
+ }
530
+ catch { /* already closed */ } });
531
+ }
532
+ // ─────────────────────────────────────────────────────────────────────────
533
+ // Reattach at boot (S3) — adopt the external process, resume the tail
534
+ // ─────────────────────────────────────────────────────────────────────────
535
+ /** Scan tmux for `cjson-…` sessions that outlived the bot (mirror of the
536
+ * scrape backend's scan). The bot decides adopt-vs-orphan per key — this
537
+ * method only lists. */
538
+ async listExistingTmuxSessions() {
539
+ const raw = await (0, tmuxExec_1.tmuxAsync)('list-sessions', '-F', '#{session_name}');
540
+ if (!raw)
541
+ return [];
542
+ const result = [];
543
+ for (const name of raw.split('\n').map((s) => s.trim()).filter(Boolean)) {
544
+ const key = (0, jsonStreamHost_1.parseJsonStreamTmuxSessionName)(name);
545
+ if (key)
546
+ result.push({ key, sessionName: name });
547
+ }
548
+ return result;
549
+ }
550
+ /** Kill an orphan `cjson-…` tmux session AND its host dir (the dir is
551
+ * per-thread, derived from the parsed name; an unparseable name only
552
+ * kills the tmux session). */
553
+ async killOrphanTmuxSession(sessionName) {
554
+ console.log(`[ClaudeJson] kill orphan tmux session: ${sessionName}`);
555
+ await (0, tmuxExec_1.tmuxAsync)('kill-session', '-t', (0, tmuxExec_1.getTmuxSessionTarget)(sessionName));
556
+ const key = (0, jsonStreamHost_1.parseJsonStreamTmuxSessionName)(sessionName);
557
+ if (!key)
558
+ return;
559
+ try {
560
+ fs.rmSync((0, jsonStreamHost_1.resolveJsonStreamSessionDir)((0, state_1.resolveDataDir)(), key), { recursive: true, force: true });
561
+ }
562
+ catch { /* best-effort */ }
563
+ }
564
+ /**
565
+ * @description Adopt an external json-stream process that survived a bot
566
+ * restart: reopen the stdin FIFO writer and resume the stdout tail from the
567
+ * persisted line-boundary offset — everything claude produced during the
568
+ * downtime replays through the normal pipeline, so the in-flight turn is
569
+ * delivered end-to-end (which is why the bot posts NO reattach recap for an
570
+ * adopt). An unknown / foreign-session offset seeds to the CURRENT EOF (no
571
+ * backlog flood — the first-migration case). No initialize handshake — the
572
+ * surviving process completed it at spawn; a pending question is restored
573
+ * from the sidecar so its buttons stay answerable. Returns `false` — after
574
+ * killing the leftovers — when the process is dead (exitcode present / pid
575
+ * gone / FIFO unheld): the caller falls back to the dead-process `--resume`
576
+ * reopen.
577
+ */
578
+ async adoptExistingTmuxSession(key, sessionName, workDir, claudeSessionId, persistedTail) {
579
+ const names = await (0, tmuxExec_1.tmuxAsync)('list-sessions', '-F', '#{session_name}');
580
+ if (!names.split('\n').includes(sessionName)) {
581
+ console.log(`[ClaudeJson] adopt: tmux session ${sessionName} no longer exists`);
582
+ return false;
583
+ }
584
+ const k = (0, sessionKey_1.keyToString)(key);
585
+ if (this.sessions.has(k)) {
586
+ console.log(`[ClaudeJson] adopt: already tracking ${k}, skipping`);
587
+ return true;
588
+ }
589
+ const sessionDir = (0, jsonStreamHost_1.resolveJsonStreamSessionDir)((0, state_1.resolveDataDir)(), key);
590
+ const paths = (0, jsonStreamHost_1.getJsonStreamSessionPaths)(sessionDir);
591
+ const pid = (0, jsonStreamHost_1.readPidFile)(paths.pidFile);
592
+ const exitCode = (0, jsonStreamHost_1.readExitCodeFile)(paths.exitCodeFile);
593
+ if (pid === null || exitCode !== null || !(0, jsonStreamHost_1.checkIsPidAlive)(pid)) {
594
+ console.log(`[ClaudeJson] adopt: ${sessionName} process is dead (pid=${pid} exit=${exitCode}), cleaning up`);
595
+ await this.killOrphanTmuxSession(sessionName);
596
+ return false;
597
+ }
598
+ const fifoFd = await (0, jsonStreamHost_1.openFifoWriterNonBlocking)(paths.stdinFifo);
599
+ if (fifoFd === null) {
600
+ console.log(`[ClaudeJson] adopt: ${sessionName} is not holding its stdin FIFO, cleaning up`);
601
+ await this.killOrphanTmuxSession(sessionName);
602
+ return false;
603
+ }
604
+ const size = (0, jsonStreamHost_1.getFileSize)(paths.stdoutFile) ?? 0;
605
+ const { startOffset, backgroundTaskIds, isTurnInFlight, outstandingToolUseIds, claudeCodeVersion } = (0, jsonStreamHost_1.resolveAdoptedTail)(persistedTail, claudeSessionId, size);
606
+ console.log(`[ClaudeJson] adopt: re-attaching to ${sessionName} in ${workDir} (pid=${pid}, tail=${startOffset}/${size})`);
607
+ const session = {
608
+ key, workDir, sessionId: claudeSessionId,
609
+ pid, paths, fifoFd,
610
+ stdinWriteChain: Promise.resolve(),
611
+ tail: (0, jsonStreamHost_1.createStdoutTailState)(startOffset),
612
+ pollTimer: null, pollDelayMs: pollBackoff_1.basePollIntervalMs, unchangedStreak: 0,
613
+ isOversizeWarned: false, lastPersistedTailOffset: startOffset,
614
+ reader: new claudeStreamJson_1.ClaudeStreamLineReader(),
615
+ // isBusy starts from the PERSISTED turn-in-flight flag: a turn in a long, silent
616
+ // tool call leaves no frame after the tail offset to rebuild it from. The
617
+ // replayed/live events then keep it right (deltas/toolUse set it, `result`
618
+ // clears it) — see `applyAction`.
619
+ isActive: true, isStopping: false, isSuspending: false, isRespawning: false, isBusy: isTurnInFlight, unconsumedInputCount: 0,
620
+ // The outstanding tools come from the record too: they veto the busy-idle watchdog, which would
621
+ // otherwise clear the restored turn after its silence window and let the stale-tool stop kill it.
622
+ lastStdoutActivityAt: Date.now(), outstandingToolUseIds: new Set(outstandingToolUseIds),
623
+ model: null, reportedModel: null, effort: null,
624
+ // The account the surviving process runs on is in its own wrapper; the bot compares it with the topic's pick.
625
+ configDir: (0, jsonStreamHost_1.readWrapperScriptConfigDir)(paths.wrapperFile), isConfigDirSwitchPending: false,
626
+ currentResponseText: '', emittedLength: 0, outputTimer: null,
627
+ reasoningText: '', reasoningStartedAt: null, reasoningTimer: null, reasoningActive: false,
628
+ toolNamesById: new Map(), questionToolUseIds: new Set(),
629
+ subagentActive: false, childResponseText: '', childEmittedLength: 0, childOutputTimer: null,
630
+ pendingInitResolve: null, initRequestId: null, pendingControlRequests: new Map(),
631
+ compactionInProgress: false, pendingCompaction: null,
632
+ pendingQuestion: this.readQuestionSidecar(paths),
633
+ apiErrorFired: false, swallowNextAbortError: false,
634
+ lastWatermarkOffset: -1,
635
+ // The frames that built the list and reported the version lie before the
636
+ // tail offset (not replayed): both come from the persisted record.
637
+ backgroundTaskIds: new Set(backgroundTaskIds), claudeCodeVersion, applyingChunk: null,
638
+ // Nothing to catch up on when the tail already sits at EOF.
639
+ adoptCatchUpOffset: startOffset < size ? size : null, adoptCatchUpResolvers: [],
640
+ };
641
+ if (session.pendingQuestion) {
642
+ // The external process is still blocked on this question — busy, and the
643
+ // question's internal tool_result echo must stay suppressed after answer.
644
+ session.isBusy = true;
645
+ session.questionToolUseIds.add(session.pendingQuestion.toolUseId);
646
+ }
647
+ this.sessions.set(k, session);
648
+ this.schedulePoll(session, pollBackoff_1.basePollIntervalMs);
649
+ this.emit('started', key);
650
+ return true;
651
+ }
652
+ /**
653
+ * @description Resolves once an ADOPTED session's tail has consumed what its
654
+ * stdout held at the adopt — the replayed frames have rebuilt the live state
655
+ * (busy, tasks, input) — or once the session is gone. Immediate for a session
656
+ * that was not adopted or whose tail already sat at EOF. The stale-tool-list
657
+ * stop (L4) looks only after this: a look before it would read a turn in flight
658
+ * as idle.
659
+ */
660
+ whenAdoptReplayed(key) {
661
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
662
+ if (!session || session.adoptCatchUpOffset === null)
663
+ return Promise.resolve();
664
+ return new Promise((resolve) => { session.adoptCatchUpResolvers.push(resolve); });
665
+ }
666
+ /** Settle the adopt catch-up once the tail consumed up to the adopt-time EOF (or the session ended). */
667
+ settleAdoptCatchUp(session, isSessionGone) {
668
+ if (session.adoptCatchUpOffset === null)
669
+ return;
670
+ if (!isSessionGone && session.tail.consumedBytes < session.adoptCatchUpOffset)
671
+ return;
672
+ session.adoptCatchUpOffset = null;
673
+ const resolvers = session.adoptCatchUpResolvers.splice(0);
674
+ for (const resolve of resolvers)
675
+ resolve();
676
+ }
677
+ /** Restore a pending question persisted by a previous bot life (see
678
+ * {@link writeQuestionSidecar}). Parse-boundary narrowing; the questions
679
+ * array re-runs the same validator as a live control_request, so a corrupt
680
+ * sidecar yields `null`, never a malformed pending question. */
681
+ readQuestionSidecar(paths) {
682
+ let parsed;
683
+ try {
684
+ parsed = JSON.parse(fs.readFileSync(paths.questionFile, 'utf8'));
685
+ }
686
+ catch {
687
+ return null; // absent (the common case) or corrupt
688
+ }
689
+ if (!(0, claudeStreamJson_1.checkIsStreamRecord)(parsed))
690
+ return null;
691
+ const { requestId, toolUseId, rawInput, questions } = parsed;
692
+ if (typeof requestId !== 'string' || typeof toolUseId !== 'string')
693
+ return null;
694
+ if (!(0, claudeStreamJson_1.checkIsStreamRecord)(rawInput) || !Array.isArray(questions))
695
+ return null;
696
+ const revalidated = this.parseQuestions({ questions });
697
+ if (revalidated.length === 0)
698
+ return null;
699
+ return { requestId, toolUseId, rawInput, questions: revalidated };
700
+ }
701
+ performInitialize(session) {
702
+ const requestId = 'init_' + (0, crypto_1.randomUUID)();
703
+ session.initRequestId = requestId;
704
+ const request = {
705
+ type: 'control_request',
706
+ request_id: requestId,
707
+ request: { subtype: 'initialize', supportedDialogKinds: ['refusal_fallback_prompt'] },
708
+ };
709
+ return new Promise((resolve) => {
710
+ let settled = false;
711
+ const done = () => { if (!settled) {
712
+ settled = true;
713
+ session.pendingInitResolve = null;
714
+ resolve();
715
+ } };
716
+ session.pendingInitResolve = done;
717
+ this.writeStdin(session, request);
718
+ setTimeout(() => {
719
+ if (!settled)
720
+ console.warn(`[ClaudeJson] initialize handshake timed out for ${(0, sessionKey_1.keyToString)(session.key)} — questions may be unavailable`);
721
+ done();
722
+ }, initializeHandshakeTimeoutMs);
723
+ });
724
+ }
725
+ stopSession(key) {
726
+ void this.stopSessionInternal(key);
727
+ }
728
+ /**
729
+ * @description Stop the process but KEEP the session resumable (lifecycle plan
730
+ * L3): the same teardown as a stop (SIGTERM, tmux kill, host dir removed —
731
+ * L-D13), converging on `suspended` instead of `stopped`, so the bot keeps the
732
+ * persisted id and the retry / compaction state the stop would drop. The caller
733
+ * checks `checkIsWorking` first — a suspend kills a background task like any
734
+ * stop. Joins a stop already in flight.
735
+ */
736
+ async suspendSession(key) {
737
+ await this.stopSessionInternal(key, { isSuspend: true });
738
+ }
739
+ async stopSessionInternal(key, options = { isSuspend: false }) {
740
+ const k = (0, sessionKey_1.keyToString)(key);
741
+ const inFlight = this.stopsInFlight.get(k);
742
+ if (inFlight)
743
+ return inFlight; // join the running stop instead of racing it
744
+ const session = this.sessions.get(k);
745
+ if (!session)
746
+ return;
747
+ const stopPromise = this.performStop(session, options).finally(() => { this.stopsInFlight.delete(k); });
748
+ this.stopsInFlight.set(k, stopPromise);
749
+ return stopPromise;
750
+ }
751
+ /** Explicit stop = hard-kill the EXTERNAL process (released sessions are
752
+ * never adopted — locked decision): SIGTERM the pid, kill the tmux session,
753
+ * then converge through {@link finalizeExternalExit} (dir removal + `stopped`,
754
+ * or `suspended` for an idle stop that keeps the session resumable). */
755
+ async performStop(session, options) {
756
+ // Reject a pending question server-side before teardown so the model's
757
+ // AskUserQuestion turn is unblocked (deny), mirroring OpenCode's reject.
758
+ this.rejectQuestion(session.key);
759
+ session.isStopping = true;
760
+ session.isSuspending = options.isSuspend;
761
+ // Let the reject (and any queued frame) reach the FIFO before the kill.
762
+ await session.stdinWriteChain.catch(() => { });
763
+ try {
764
+ process.kill(session.pid, 'SIGTERM');
765
+ }
766
+ catch { /* already gone */ }
767
+ await (0, tmuxExec_1.tmuxAsync)('kill-session', '-t', (0, tmuxExec_1.getTmuxSessionTarget)((0, jsonStreamHost_1.buildJsonStreamTmuxSessionName)(session.key)));
768
+ this.finalizeExternalExit(session, null);
769
+ }
770
+ checkIsActive(key) {
771
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
772
+ return session?.isActive === true;
773
+ }
774
+ checkIsBusy(key) {
775
+ return this.sessions.get((0, sessionKey_1.keyToString)(key))?.isBusy === true;
776
+ }
777
+ checkHasUnconsumedInput(key) {
778
+ return (this.sessions.get((0, sessionKey_1.keyToString)(key))?.unconsumedInputCount ?? 0) > 0;
779
+ }
780
+ /**
781
+ * @description Whether the process is WORKING and must not be stopped (L-D2):
782
+ * a running turn, a background task the CLI still runs (background Bash /
783
+ * Monitor / sub-agent — a stop kills them, and a finished one starts its own
784
+ * turn), input written but not yet taken in, or a bot-issued compaction in
785
+ * flight. An unknown / inactive session is not working.
786
+ */
787
+ checkIsWorking(key) {
788
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
789
+ if (!session?.isActive)
790
+ return false;
791
+ return session.isBusy || this.checkHasBackgroundWork(key);
792
+ }
793
+ /** Background tasks, input not yet taken in, a compaction in flight — "working" minus the turn (L-D2). */
794
+ checkHasBackgroundWork(key) {
795
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
796
+ if (!session?.isActive)
797
+ return false;
798
+ return session.backgroundTaskIds.size > 0
799
+ || session.unconsumedInputCount > 0
800
+ || session.compactionInProgress;
801
+ }
802
+ /** The CLI version the live process reported on `system/init`, `null` until then (L-D10 gate input). */
803
+ getClaudeCodeVersion(key) {
804
+ return this.sessions.get((0, sessionKey_1.keyToString)(key))?.claudeCodeVersion ?? null;
805
+ }
806
+ /** L-D10: only a CLI that reports the background-task list may be stopped automatically. */
807
+ checkIsAutoStopSupported(key) {
808
+ return (0, claudeCodeVersion_1.checkIsClaudeAutoStopSupported)(this.getClaudeCodeVersion(key));
809
+ }
810
+ async getRuntimeInfo(key) {
811
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
812
+ if (!session?.isActive) {
813
+ return { version: null, model: null, contextWindowTokens: null, contextUsedTokens: null };
814
+ }
815
+ const filePath = (0, claudeCliAdapter_1.getClaudeTranscriptPath)(session.workDir, session.sessionId);
816
+ try {
817
+ return await (0, claudeRuntimeInfo_1.readClaudeRuntimeInfo)(filePath);
818
+ }
819
+ catch {
820
+ return { version: null, model: null, contextWindowTokens: null, contextUsedTokens: null };
821
+ }
822
+ }
823
+ getClaudeSessionId(key) {
824
+ return this.sessions.get((0, sessionKey_1.keyToString)(key))?.sessionId ?? null;
825
+ }
826
+ /**
827
+ * @description Real, CONFIRMED compaction on the json-stream backend (F3):
828
+ * send `/compact` (or `/compact <instruction>` for F2's closing section) as a
829
+ * stream-json user turn — the CLI parses the slash command, compacts, and
830
+ * reports the outcome on a `compact_boundary` (success, with token counts) /
831
+ * a failing `compact_status` frame. The whole turn's own output is suppressed
832
+ * (`compactionInProgress`) so only the bot's confirmation shows. Resolves the
833
+ * {@link CompactionResult} — a success carrying the boundary frame's pre/post
834
+ * token counts (`null` when only `compact_status success` was seen) — awaiting
835
+ * the terminal signal so the caller can post its notice AFTER the context was
836
+ * really compacted.
837
+ */
838
+ async compactContext(key, instruction) {
839
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
840
+ if (!session?.isActive)
841
+ return { ok: false, error: (0, i18n_1.t)('compact.start_agent_first') };
842
+ if (session.pendingCompaction) {
843
+ return { ok: false, error: (0, i18n_1.t)('compact.failed', { reason: 'a compaction is already running' }) };
844
+ }
845
+ if (session.isBusy)
846
+ return { ok: false, error: (0, i18n_1.t)('compact.busy') };
847
+ const trimmed = instruction?.trim();
848
+ const text = trimmed ? `/compact ${trimmed}` : '/compact';
849
+ const startedAt = Date.now();
850
+ const result = await new Promise((resolve) => {
851
+ // Bounded by SILENCE, not by elapsed time. A flat 3-minute cap on total
852
+ // elapsed time is what made idle compaction look mute: a real 3 min 15.6 s
853
+ // compaction (`compact_metadata.duration_ms: 195649`) was declared failed
854
+ // while the CLI was succeeding, so the notice was never posted. Summarising
855
+ // scales with the context being summarised, and compact-on-idle exists FOR
856
+ // big contexts — any fixed cap fails exactly where the feature matters.
857
+ // While it works the CLI heartbeats `system/status status:"compacting"`
858
+ // every few seconds, so real silence is the honest death signal.
859
+ const timer = setInterval(() => {
860
+ const verdict = (0, jsonStreamBusyWatchdog_1.getCompactionWaitVerdict)({
861
+ msSinceStdoutActivity: Date.now() - session.lastStdoutActivityAt,
862
+ msSinceCompactionStarted: Date.now() - startedAt,
863
+ silenceTimeoutMs: jsonStreamBusyWatchdog_1.compactionSilenceTimeoutMs,
864
+ absoluteTimeoutMs: jsonStreamBusyWatchdog_1.compactionAbsoluteTimeoutMs,
865
+ });
866
+ if (verdict === 'keepWaiting')
867
+ return;
868
+ const outcome = (0, jsonStreamBusyWatchdog_1.getCompactionTimeoutOutcome)({
869
+ verdict,
870
+ sawSuccess: session.pendingCompaction?.sawSuccess === true,
871
+ });
872
+ if (outcome.kind === 'succeededWithoutTokenCounts') {
873
+ this.resolveCompaction(session, { ok: true, preTokens: null, postTokens: null });
874
+ return;
875
+ }
876
+ this.resolveCompaction(session, {
877
+ ok: false,
878
+ error: outcome.reason === 'silent'
879
+ ? `the CLI went silent for ${Math.round(jsonStreamBusyWatchdog_1.compactionSilenceTimeoutMs / 1000)}s without confirming the compaction`
880
+ : `the compaction did not finish within ${Math.round(jsonStreamBusyWatchdog_1.compactionAbsoluteTimeoutMs / 60_000)} min`,
881
+ });
882
+ }, jsonStreamBusyWatchdog_1.compactionWaitPollMs);
883
+ timer.unref?.();
884
+ session.pendingCompaction = { resolve, timer, sawSuccess: false };
885
+ session.compactionInProgress = true;
886
+ // Fresh turn: reset the answer cursor + idle-watchdog clock, mark busy.
887
+ session.currentResponseText = '';
888
+ session.emittedLength = 0;
889
+ session.isBusy = true;
890
+ session.lastStdoutActivityAt = Date.now();
891
+ // Not counted as unconsumed input: a bot-issued `/compact` is a control
892
+ // turn whose echo is not guaranteed, and it only runs on an idle session.
893
+ this.writeStdin(session, { type: 'user', message: { role: 'user', content: text } });
894
+ });
895
+ if (result.ok) {
896
+ console.log(`[ClaudeJson] compacted ${(0, sessionKey_1.keyToString)(key)} (pre=${result.preTokens ?? '?'} post=${result.postTokens ?? '?'})`);
897
+ return result;
898
+ }
899
+ console.warn(`[ClaudeJson] compaction failed for ${(0, sessionKey_1.keyToString)(key)}: ${result.error}`);
900
+ // The raw internal reason is wrapped into the user-facing template HERE (not at
901
+ // the resolve sites) so every failure path reads the same way in the topic.
902
+ return { ok: false, error: (0, i18n_1.t)('compact.failed', { reason: result.error }) };
903
+ }
904
+ /**
905
+ * @description Read the newest compaction summary from the on-disk transcript
906
+ * (the `isCompactSummary:true` message) so F2 can lift its appended closing
907
+ * section into the idle-compaction notice. Returns `null` when the session is
908
+ * inactive, the transcript is unreadable, or no summary is present.
909
+ */
910
+ async getLatestCompactionSummary(key) {
911
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
912
+ if (!session?.isActive)
913
+ return null;
914
+ return readLatestCompactSummaryFromTranscript((0, claudeCliAdapter_1.getClaudeTranscriptPath)(session.workDir, session.sessionId));
915
+ }
916
+ // ─────────────────────────────────────────────────────────────────────────
917
+ // Input (S3)
918
+ // ─────────────────────────────────────────────────────────────────────────
919
+ sendInput(key, input) {
920
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
921
+ if (!session?.isActive) {
922
+ console.warn(`[ClaudeJson] sendInput to inactive session ${(0, sessionKey_1.keyToString)(key)} dropped`);
923
+ return;
924
+ }
925
+ // A fresh user turn begins → reset the answer cursor so its first tail is a
926
+ // new message (the bot also flips `needsNewMessage` for delta adapters).
927
+ session.currentResponseText = '';
928
+ session.emittedLength = 0;
929
+ session.apiErrorFired = false;
930
+ session.isBusy = true;
931
+ // A fresh turn resets the idle-watchdog clock: without this a session that
932
+ // sat idle for minutes (busy=false, clock stale) would trip the watchdog on
933
+ // its very next poll — before claude has a chance to emit the first token.
934
+ session.lastStdoutActivityAt = Date.now();
935
+ // The turn in flight is persisted at once (same offset, flipped flag): a restart
936
+ // during a long, silent tool call finds no frame after the offset to rebuild it.
937
+ this.jsonStreamTailWriter?.(key, buildTailRecord(session, session.lastPersistedTailOffset));
938
+ this.writeUserMessage(session, input);
939
+ }
940
+ sendSignal(key, _signal) {
941
+ this.sendInterrupt(key);
942
+ }
943
+ sendEscape(key) {
944
+ this.sendInterrupt(key);
945
+ }
946
+ sendInterrupt(key) {
947
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
948
+ if (!session?.isActive)
949
+ return;
950
+ this.writeStdin(session, {
951
+ type: 'control_request',
952
+ request_id: 'interrupt_' + (0, crypto_1.randomUUID)(),
953
+ request: { subtype: 'interrupt' },
954
+ });
955
+ // An interrupt ABORTS the current turn. The CLI does not reliably emit a
956
+ // terminal `result` for an aborted turn, so clearing `isBusy` here (rather
957
+ // than waiting on the idle watchdog) makes the explicit stop deterministic —
958
+ // the typing indicator drops immediately. If output resumes, a delta re-arms
959
+ // busy; if a `result` does arrive, `handleTurnEnd` is a harmless no-op.
960
+ session.isBusy = false;
961
+ session.outstandingToolUseIds.clear();
962
+ // When the CLI DOES emit a terminal `result{is_error}` for this abort, it
963
+ // carries no text → `claudeStreamJson` labels it the literal `'API error'`.
964
+ // Arm the one-shot so `handleTurnEnd` swallows it instead of relaying a bogus
965
+ // "Claude error: API error" (the reported triple-message on question-cancel,
966
+ // and any bare `/esc` mid-turn). Consumed by the next `handleTurnEnd`.
967
+ session.swallowNextAbortError = true;
968
+ }
969
+ /** Write one user turn, counting it until Claude echoes it back (it has read it). */
970
+ writeUserMessage(session, content) {
971
+ session.unconsumedInputCount += 1;
972
+ this.writeStdin(session, { type: 'user', message: { role: 'user', content } });
973
+ }
974
+ /** Enqueue one stream-json frame onto the stdin FIFO. Fire-and-forget for
975
+ * callers (sync signature preserved); the per-session chain keeps wire
976
+ * order and absorbs transient `EAGAIN` (see `writeFifoText`). */
977
+ writeStdin(session, obj) {
978
+ const line = JSON.stringify(obj) + '\n';
979
+ session.stdinWriteChain = session.stdinWriteChain
980
+ .then(() => (0, jsonStreamHost_1.writeFifoText)(session.fifoFd, line))
981
+ .catch((e) => console.error(`[ClaudeJson] stdin write failed for ${(0, sessionKey_1.keyToString)(session.key)}:`, e instanceof Error ? e.message : e));
982
+ // New input → output expected shortly; snap the tail poll back to base.
983
+ this.snapPollToBase(session);
984
+ }
985
+ // ─────────────────────────────────────────────────────────────────────────
986
+ // Output parsing (S2) + control channel (S4)
987
+ // ─────────────────────────────────────────────────────────────────────────
988
+ onStdout(session, chunk) {
989
+ const applyingChunk = { isPersistDeferred: false };
990
+ session.applyingChunk = applyingChunk;
991
+ try {
992
+ this.applyStdoutLines(session, session.reader.push(chunk));
993
+ }
994
+ finally {
995
+ session.applyingChunk = null;
996
+ }
997
+ // A persist a handler asked for mid-chunk (see `applyingChunk`) runs now,
998
+ // under the same emit-caught-up gate the drain applies.
999
+ if (applyingChunk.isPersistDeferred && checkIsEmitCaughtUp(session))
1000
+ this.persistTailOffset(session);
1001
+ }
1002
+ applyStdoutLines(session, lines) {
1003
+ for (const line of lines) {
1004
+ const msg = (0, claudeStreamJson_1.parseStreamJsonLine)(line);
1005
+ if (!msg)
1006
+ continue;
1007
+ for (const action of (0, claudeStreamJson_1.classifyClaudeStreamMessage)(msg)) {
1008
+ this.applyAction(session, action);
1009
+ }
1010
+ // S7: advance the seen-watermark as each PARENT assistant message settles
1011
+ // (is relayed), not only at turn end. The external process normally
1012
+ // SURVIVES a bot restart now (adopt replays the stdout tail — no recap),
1013
+ // but when the process itself DIES mid-turn the dead-process `--resume`
1014
+ // fallback recaps from this watermark: without the per-message advance
1015
+ // the aborted turn's already-relayed assistant messages would re-count
1016
+ // as a false "missed N" (same shared recap reader as the tmux backend,
1017
+ // the 2026-07-04 bug). A settled `assistant` message is on disk here, so
1018
+ // the transcript EOF includes it. A CHILD (sub-agent) message
1019
+ // (`parent_tool_use_id` set) must never advance the watermark.
1020
+ if (msg.type === 'assistant' && msg.parent_tool_use_id == null) {
1021
+ this.advanceWatermarkFromTranscript(session);
1022
+ }
1023
+ }
1024
+ }
1025
+ /**
1026
+ * @description Settle the CLI's reply to a control_request the BOT wrote,
1027
+ * matched by `request_id`: the spawn-time `initialize` handshake, plus the MCP
1028
+ * heal's `mcp_status` / `mcp_reconnect` round-trips. A response for an id we
1029
+ * are not waiting on belongs to nothing of ours — ignore it rather than guess
1030
+ * which awaiter it might settle.
1031
+ */
1032
+ handleControlResponse(session, action) {
1033
+ if (session.pendingInitResolve && action.requestId === session.initRequestId) {
1034
+ session.pendingInitResolve();
1035
+ return;
1036
+ }
1037
+ const pending = session.pendingControlRequests.get(action.requestId);
1038
+ if (!pending)
1039
+ return;
1040
+ session.pendingControlRequests.delete(action.requestId);
1041
+ clearTimeout(pending.timer);
1042
+ pending.resolve({ isSuccess: action.isSuccess, payload: action.payload });
1043
+ }
1044
+ /**
1045
+ * @description Write ONE bot-issued control_request and resolve with its
1046
+ * `control_response`, or `null` when none arrives within
1047
+ * {@link mcpControlRequestTimeoutMs}. The reply comes back through the normal
1048
+ * stdout-tail → classifier path (the CLI answers on the same stdio control
1049
+ * channel `can_use_tool` uses), so the bounded timer is what keeps a silent
1050
+ * CLI from hanging the caller. Never rejects: an unanswered request is an
1051
+ * unknown, not an error.
1052
+ *
1053
+ * A session that is no longer the live one for its key gets NOTHING written:
1054
+ * its fd is closed (and its number reusable), so a write after teardown could
1055
+ * land in an unrelated file — and no reply could ever settle the awaiter
1056
+ * anyway. Same identity guard as the poll tick and the exit finalizer.
1057
+ */
1058
+ requestControl(session, requestId, frame) {
1059
+ if (!session.isActive || this.sessions.get((0, sessionKey_1.keyToString)(session.key)) !== session)
1060
+ return Promise.resolve(null);
1061
+ return new Promise((resolve) => {
1062
+ const timer = setTimeout(() => {
1063
+ // Only the entry still parked here is ours to time out — a response that
1064
+ // landed first already removed it (and resolved).
1065
+ if (!session.pendingControlRequests.delete(requestId))
1066
+ return;
1067
+ resolve(null);
1068
+ }, claudeMcpHeal_1.mcpControlRequestTimeoutMs);
1069
+ timer.unref?.();
1070
+ session.pendingControlRequests.set(requestId, { resolve, timer });
1071
+ this.writeStdin(session, frame);
1072
+ });
1073
+ }
1074
+ /**
1075
+ * @description Heal the bot's own injected MCP server inside this LIVE session:
1076
+ * ask `mcp_status`, and reconnect the server ONLY when it reports `failed`
1077
+ * (the latched state a bot restart leaves behind — the CLI never retries it,
1078
+ * so the bot's tools stay gone for the rest of the session). `connected` is
1079
+ * left strictly alone, and any other status (`needs-auth`, an unknown future
1080
+ * one) is skipped rather than guessed at — see `decideMcpHeal`.
1081
+ *
1082
+ * Control frames only: nothing written here can be read as a user turn, the
1083
+ * session is never marked busy, and the pending-request map is keyed by
1084
+ * `request_id` so the `can_use_tool` / `interrupt` paths are untouched.
1085
+ *
1086
+ * `healed` is reported off the reconnect's own ack, and that ack is MEASURED to
1087
+ * be both synchronous and honest — so no confirming third round-trip is needed
1088
+ * and adding one would only be ceremony. Against a still-dead endpoint the
1089
+ * reconnect answers `{subtype:'error', error:'ECONNREFUSED…'}` (never a hollow
1090
+ * success), and after a successful one an IMMEDIATELY following `mcp_status`
1091
+ * already reads `connected`. Do not re-litigate this as a missing verification.
1092
+ */
1093
+ async healMcpServer(key, serverName) {
1094
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
1095
+ if (!session?.isActive)
1096
+ return 'unavailable';
1097
+ const statusRequestId = 'mcp_status_' + (0, crypto_1.randomUUID)();
1098
+ const status = await this.requestControl(session, statusRequestId, (0, claudeMcpHeal_1.buildMcpStatusControlRequest)(statusRequestId));
1099
+ // No answer (timeout) or an `error` verdict: nothing is known about the
1100
+ // server, so nothing may be done to it.
1101
+ if (!status?.isSuccess)
1102
+ return 'unavailable';
1103
+ const decision = (0, claudeMcpHeal_1.decideMcpHeal)((0, claudeMcpHeal_1.getMcpServerStatus)(status.payload, serverName));
1104
+ if (decision === 'healthy')
1105
+ return 'healthy';
1106
+ if (decision === 'skip')
1107
+ return 'skipped';
1108
+ const reconnectRequestId = 'mcp_reconnect_' + (0, crypto_1.randomUUID)();
1109
+ const reconnect = await this.requestControl(session, reconnectRequestId, (0, claudeMcpHeal_1.buildMcpReconnectControlRequest)(reconnectRequestId, serverName));
1110
+ // `mcp_reconnect` answers a bare success ack (no inner record); anything
1111
+ // else means the reconnect did not land, so the server is still broken.
1112
+ return reconnect?.isSuccess === true ? 'healed' : 'unavailable';
1113
+ }
1114
+ applyAction(session, action) {
1115
+ // A bot-issued `/compact` turn produces its own noise ("Not enough messages
1116
+ // to compact.", the summarisation itself) — suppress ALL of it so only the
1117
+ // bot's confirmation shows. The compact_* frames + turn end still drive the
1118
+ // awaiter; a stray provider error still surfaces. (A CLI-side AUTO compaction
1119
+ // during a normal turn is NOT gated here — `compactionInProgress` is only set
1120
+ // by our own `compactContext`, and `pendingCompaction` guards the handlers.)
1121
+ if (session.compactionInProgress) {
1122
+ switch (action.kind) {
1123
+ case 'turnEnd':
1124
+ this.handleTurnEnd(session, action);
1125
+ return;
1126
+ case 'compactStatus':
1127
+ this.handleCompactStatus(session, action);
1128
+ return;
1129
+ case 'compactBoundary':
1130
+ this.handleCompactBoundary(session, action);
1131
+ return;
1132
+ case 'init':
1133
+ this.handleInit(session, action);
1134
+ return;
1135
+ case 'backgroundTasks':
1136
+ this.handleBackgroundTasks(session, action);
1137
+ return;
1138
+ case 'apiRetry':
1139
+ this.maybeEmitApiError(session, action.text);
1140
+ return;
1141
+ // A reply to one of OUR control requests is never the compaction turn's
1142
+ // output — its awaiter must settle whatever else is running.
1143
+ case 'controlResponse':
1144
+ this.handleControlResponse(session, action);
1145
+ return;
1146
+ default: return; // swallow text / thinking / tool / toolResult / control / echo
1147
+ }
1148
+ }
1149
+ switch (action.kind) {
1150
+ case 'init':
1151
+ // Per-turn `init` re-emits; the id is fixed by our `--session-id`, so the
1152
+ // id itself is nothing to act on. The MODEL it carries is load-bearing:
1153
+ // it is the only report of what claude actually runs. Without capturing
1154
+ // it `/status` and the pinned banner showed no model at all on a default
1155
+ // start / resume / adopt (nothing ever set the `--model` pick).
1156
+ this.handleInit(session, action);
1157
+ return;
1158
+ case 'backgroundTasks':
1159
+ this.handleBackgroundTasks(session, action);
1160
+ return;
1161
+ case 'textDelta':
1162
+ // Mid-turn activity marks the session busy: `sendInput` normally set it,
1163
+ // but an ADOPTED session (bot restart mid-turn) reconstructs the busy
1164
+ // state purely from the replayed/live events; `turnEnd` clears it.
1165
+ session.isBusy = true;
1166
+ if (action.isSubagent)
1167
+ this.handleSubagentText(session, action.text);
1168
+ else
1169
+ this.appendAnswerDelta(session, action.text);
1170
+ return;
1171
+ case 'thinkingDelta':
1172
+ session.isBusy = true;
1173
+ if (action.isSubagent)
1174
+ return; // child reasoning never rendered (parity)
1175
+ this.appendThinkingDelta(session, action.text);
1176
+ return;
1177
+ case 'toolUse':
1178
+ session.isBusy = true;
1179
+ this.handleToolUse(session, action);
1180
+ return;
1181
+ case 'toolResult':
1182
+ this.handleToolResult(session, action);
1183
+ return;
1184
+ case 'turnEnd':
1185
+ this.handleTurnEnd(session, action);
1186
+ return;
1187
+ case 'controlRequest':
1188
+ this.handleControlRequest(session, action);
1189
+ return;
1190
+ case 'controlResponse':
1191
+ this.handleControlResponse(session, action);
1192
+ return;
1193
+ case 'apiRetry':
1194
+ this.maybeEmitApiError(session, action.text);
1195
+ return;
1196
+ case 'compactStatus':
1197
+ // A CLI-side auto-compaction (no bot-issued `/compact`) — no awaiter to
1198
+ // resolve, so this is a no-op; the guard lives in the handler.
1199
+ this.handleCompactStatus(session, action);
1200
+ return;
1201
+ case 'compactBoundary':
1202
+ this.handleCompactBoundary(session, action);
1203
+ return;
1204
+ case 'rateLimit':
1205
+ // Subscription usage-window signal; not surfaced to the topic (parity) — handed to the bot's usage
1206
+ // cache for the profile this process runs on.
1207
+ this.claudeRateLimitSink?.(session.configDir, {
1208
+ status: action.status, rateLimitType: action.rateLimitType, resetsAtMs: action.resetsAtMs, windows: action.windows,
1209
+ });
1210
+ return;
1211
+ case 'userEcho':
1212
+ // Claude has read one of our user messages. A message written mid-turn
1213
+ // is taken into the RUNNING turn, so the session is busy from here until
1214
+ // the turn's `result`, even if an earlier `result` already cleared it.
1215
+ session.unconsumedInputCount = Math.max(0, session.unconsumedInputCount - 1);
1216
+ session.isBusy = true;
1217
+ return;
1218
+ }
1219
+ }
1220
+ handleInit(session, action) {
1221
+ if (action.model)
1222
+ session.reportedModel = action.model;
1223
+ if (action.claudeCodeVersion)
1224
+ session.claudeCodeVersion = action.claudeCodeVersion;
1225
+ }
1226
+ /** Replace the live background-task list with the frame's (it is re-sent
1227
+ * WHOLE on every change, so no diffing). The tail-offset persist that follows
1228
+ * this frame's drain carries the new list to `state.json`. */
1229
+ handleBackgroundTasks(session, action) {
1230
+ session.backgroundTaskIds = new Set(action.taskIds);
1231
+ }
1232
+ // — compaction (F3) —
1233
+ handleCompactStatus(session, action) {
1234
+ const pending = session.pendingCompaction;
1235
+ if (!pending)
1236
+ return;
1237
+ if (action.result === 'success') {
1238
+ // Wait for the boundary frame (it carries the pre/post token counts).
1239
+ pending.sawSuccess = true;
1240
+ return;
1241
+ }
1242
+ // Any non-success result (e.g. "not enough messages") is a failure.
1243
+ this.resolveCompaction(session, {
1244
+ ok: false,
1245
+ error: action.error ?? action.result ?? 'compaction did not run',
1246
+ });
1247
+ }
1248
+ handleCompactBoundary(session, action) {
1249
+ if (!session.pendingCompaction) {
1250
+ // The CLI's own compaction (a context overflow mid-turn, or one met while replaying the downtime tail):
1251
+ // nobody waits for it, but the conversation's context was replaced all the same.
1252
+ this.emit('contextCompacted', session.key, action.trigger);
1253
+ return;
1254
+ }
1255
+ this.resolveCompaction(session, { ok: true, preTokens: action.preTokens, postTokens: action.postTokens }, action.trigger);
1256
+ }
1257
+ /**
1258
+ * Resolve (and clear) the in-flight compaction awaiter exactly once. Every way a bot-issued compaction can
1259
+ * succeed (its boundary, its turn end, the timeout that saw its success) ends here, so a success is told
1260
+ * once as `contextCompacted`.
1261
+ */
1262
+ resolveCompaction(session, result, trigger = null) {
1263
+ const pending = session.pendingCompaction;
1264
+ if (!pending)
1265
+ return;
1266
+ session.pendingCompaction = null;
1267
+ session.compactionInProgress = false;
1268
+ if (pending.timer)
1269
+ clearInterval(pending.timer);
1270
+ pending.resolve(result);
1271
+ if (result.ok)
1272
+ this.emit('contextCompacted', session.key, trigger);
1273
+ }
1274
+ // — answer text —
1275
+ appendAnswerDelta(session, text) {
1276
+ // Reasoning is over the moment the answer starts (Claude closes the thinking
1277
+ // block before the text block).
1278
+ this.finishReasoning(session);
1279
+ session.currentResponseText += text;
1280
+ if (session.outputTimer)
1281
+ return; // a flush is already scheduled
1282
+ session.outputTimer = setTimeout(() => {
1283
+ session.outputTimer = null;
1284
+ this.flushAnswer(session, false);
1285
+ }, streamOutputBatchMs);
1286
+ }
1287
+ flushAnswer(session, isFinal) {
1288
+ if (session.outputTimer) {
1289
+ clearTimeout(session.outputTimer);
1290
+ session.outputTimer = null;
1291
+ }
1292
+ const tail = session.currentResponseText.slice(session.emittedLength);
1293
+ if (tail) {
1294
+ session.emittedLength = session.currentResponseText.length;
1295
+ const meta = isFinal ? { isFinal: true } : {};
1296
+ // NO isContinuation: `outputsDeltas` adapters let the transports synthesise it.
1297
+ this.emit('output', session.key, tail, meta);
1298
+ }
1299
+ // The answer batcher is drained — the held-back consumption boundary is now
1300
+ // safe to persist (see `drainStdoutTail`).
1301
+ if (checkIsEmitCaughtUp(session))
1302
+ this.persistTailOffset(session);
1303
+ }
1304
+ // — reasoning / thinking —
1305
+ appendThinkingDelta(session, text) {
1306
+ if (!session.reasoningActive) {
1307
+ session.reasoningActive = true;
1308
+ session.reasoningStartedAt = Date.now();
1309
+ session.reasoningText = '';
1310
+ }
1311
+ session.reasoningText += text;
1312
+ if (session.reasoningTimer)
1313
+ return;
1314
+ session.reasoningTimer = setTimeout(() => {
1315
+ session.reasoningTimer = null;
1316
+ this.emit('thinking', session.key, { phase: 'live', text: session.reasoningText });
1317
+ }, streamOutputBatchMs);
1318
+ }
1319
+ finishReasoning(session) {
1320
+ if (!session.reasoningActive)
1321
+ return;
1322
+ if (session.reasoningTimer) {
1323
+ clearTimeout(session.reasoningTimer);
1324
+ session.reasoningTimer = null;
1325
+ }
1326
+ const durationMs = session.reasoningStartedAt ? Date.now() - session.reasoningStartedAt : undefined;
1327
+ this.emit('thinking', session.key, { phase: 'done', text: session.reasoningText, durationMs });
1328
+ session.reasoningActive = false;
1329
+ session.reasoningStartedAt = null;
1330
+ }
1331
+ // — tools —
1332
+ handleToolUse(session, action) {
1333
+ // AskUserQuestion never renders as a tool (it is intercepted on the control
1334
+ // channel); guard defensively.
1335
+ if (action.tool === 'AskUserQuestion')
1336
+ return;
1337
+ if (action.isSubagent) {
1338
+ this.markSubagentActive(session);
1339
+ return;
1340
+ }
1341
+ session.toolNamesById.set(action.toolUseId, action.tool);
1342
+ // Track it as in flight until its tool_result returns — a busy session with
1343
+ // an outstanding tool (e.g. a long silent Bash) must NOT trip the idle
1344
+ // watchdog even though stdout goes quiet while the tool runs.
1345
+ session.outstandingToolUseIds.add(action.toolUseId);
1346
+ // Transient status only; the completed body arrives as a toolResult.
1347
+ this.emit('status', session.key, `🔧 ${action.tool}`);
1348
+ }
1349
+ handleToolResult(session, action) {
1350
+ // The tool returned — no longer in flight (do this before any early return so
1351
+ // the outstanding-tool set can never leak and pin the idle watchdog open).
1352
+ session.outstandingToolUseIds.delete(action.toolUseId);
1353
+ // Skip AskUserQuestion's internal "questions have been answered" tool_result.
1354
+ if (session.questionToolUseIds.has(action.toolUseId))
1355
+ return;
1356
+ const tool = session.toolNamesById.get(action.toolUseId) ?? 'tool';
1357
+ if (!action.output.trim())
1358
+ return;
1359
+ // Mode-agnostic emit — the bot applies the per-thread `/tool_results` pref.
1360
+ this.emit('toolResult', session.key, { tool, output: action.output });
1361
+ }
1362
+ // — sub-agent (v1) —
1363
+ markSubagentActive(session) {
1364
+ session.subagentActive = true;
1365
+ this.emit('subagentStatus', session.key, { active: true, title: null });
1366
+ }
1367
+ handleSubagentText(session, text) {
1368
+ if (this.getDisplayPrefs(session.key).subagent === 'full') {
1369
+ session.childResponseText += text;
1370
+ if (session.childOutputTimer)
1371
+ return;
1372
+ session.childOutputTimer = setTimeout(() => {
1373
+ session.childOutputTimer = null;
1374
+ const tail = session.childResponseText.slice(session.childEmittedLength);
1375
+ if (!tail.trim())
1376
+ return;
1377
+ session.childEmittedLength = session.childResponseText.length;
1378
+ this.emit('output', session.key, tail, { isSubagent: true });
1379
+ // Child batcher drained — release the held-back tail offset (see
1380
+ // `drainStdoutTail`).
1381
+ if (checkIsEmitCaughtUp(session))
1382
+ this.persistTailOffset(session);
1383
+ }, streamOutputBatchMs);
1384
+ }
1385
+ else {
1386
+ this.markSubagentActive(session);
1387
+ }
1388
+ }
1389
+ clearSubagent(session) {
1390
+ if (session.childOutputTimer) {
1391
+ clearTimeout(session.childOutputTimer);
1392
+ session.childOutputTimer = null;
1393
+ }
1394
+ session.childResponseText = '';
1395
+ session.childEmittedLength = 0;
1396
+ if (session.subagentActive) {
1397
+ session.subagentActive = false;
1398
+ this.emit('subagentStatus', session.key, { active: false, title: null });
1399
+ }
1400
+ }
1401
+ // — turn end —
1402
+ /** Every terminal `result` — a normal turn, a compaction turn, an error — ends with the `turnEnded` event. */
1403
+ handleTurnEnd(session, action) {
1404
+ this.applyTurnEnd(session, action);
1405
+ // After the handlers above: the bot's per-turn stop (L5) reads the session's state as settled here.
1406
+ this.emit('turnEnded', session.key);
1407
+ this.applyPendingConfigDirSwitch(session);
1408
+ }
1409
+ applyTurnEnd(session, action) {
1410
+ // L-D11: every turn's accounting, the compaction turn included — the
1411
+ // cross-process prompt-cache check reads these lines, so they must be real
1412
+ // and repeatable, never reconstructed from a transcript afterwards.
1413
+ if (action.usage) {
1414
+ const { inputTokens, cacheReadTokens, cacheWriteTokens, outputTokens } = action.usage;
1415
+ console.log(`${exports.claudeJsonStreamUsageLogPrefix}${(0, sessionKey_1.keyToString)(session.key)}: input=${inputTokens} cacheRead=${cacheReadTokens} cacheWrite=${cacheWriteTokens} output=${outputTokens}`);
1416
+ }
1417
+ session.isBusy = false;
1418
+ // Self-healing accounting: a FAILED turn (usage limit, API error) may never echo the messages that were
1419
+ // queued behind it, and a count left above zero would make the session look "working" forever — a pending
1420
+ // account switch would never fire. A message still genuinely queued is echoed later (the decrement clamps
1421
+ // at zero and the echo marks the session busy again), so zeroing here can only under-count briefly.
1422
+ if (action.isError)
1423
+ session.unconsumedInputCount = 0;
1424
+ session.outstandingToolUseIds.clear();
1425
+ this.finishReasoning(session);
1426
+ this.clearSubagent(session);
1427
+ // A bot-issued `/compact` turn ends here. Emit NOTHING (the summary text /
1428
+ // "not enough" message are suppressed) and settle the awaiter: a still-pending
1429
+ // compaction with no failure signal is a clean success (fallback for a build
1430
+ // that skipped the boundary frame); an errored turn is a failure.
1431
+ if (session.compactionInProgress) {
1432
+ session.swallowNextAbortError = false;
1433
+ if (session.pendingCompaction) {
1434
+ const sawSuccess = session.pendingCompaction.sawSuccess;
1435
+ this.resolveCompaction(session, sawSuccess || !action.isError
1436
+ ? { ok: true, preTokens: null, postTokens: null }
1437
+ : { ok: false, error: action.errorText ?? 'compaction failed' });
1438
+ }
1439
+ else {
1440
+ session.compactionInProgress = false;
1441
+ }
1442
+ return;
1443
+ }
1444
+ // One-shot: consume the interrupt's swallow flag for THIS terminal result
1445
+ // (read-and-clear so it can never leak onto a later, unrelated turn).
1446
+ const swallowAbortError = session.swallowNextAbortError;
1447
+ session.swallowNextAbortError = false;
1448
+ if (action.isError && action.errorText) {
1449
+ // Our own interrupt produced this error result — relay nothing (no bogus
1450
+ // "Claude error", no spurious retry). A REAL provider error arriving
1451
+ // WITHOUT a preceding interrupt still classifies / surfaces normally.
1452
+ if (swallowAbortError) {
1453
+ console.log(`[ClaudeJson] swallowed interrupt-aborted turn error for ${(0, sessionKey_1.keyToString)(session.key)}: ${action.errorText}`);
1454
+ return;
1455
+ }
1456
+ const emitted = this.maybeEmitApiError(session, action.errorText);
1457
+ if (!emitted)
1458
+ this.emit('output', session.key, `Claude error: ${action.errorText}`, { isFinal: true });
1459
+ return;
1460
+ }
1461
+ // Reconciliation backstop: if the delta stream under-delivered vs the final
1462
+ // `result` text, append the gap so the answer is never short.
1463
+ if (action.resultText && action.resultText.length > session.currentResponseText.length
1464
+ && action.resultText.startsWith(session.currentResponseText)) {
1465
+ session.currentResponseText = action.resultText;
1466
+ }
1467
+ this.flushAnswer(session, true);
1468
+ // Advance the seen watermark to the transcript's current byte size so a bot
1469
+ // restart can count assistant messages produced while it was down. Also runs
1470
+ // per settled parent message (see `onStdout`); this turn-end call is the
1471
+ // safety-net catch-up for the final assistant line.
1472
+ this.advanceWatermarkFromTranscript(session);
1473
+ }
1474
+ /**
1475
+ * @description Advance the persisted seen-watermark to the transcript's current
1476
+ * byte size when it grew past the last write (S7). A cheap `fs.statSync().size`
1477
+ * (NOT a whole-file read — this runs per settled parent assistant message, not
1478
+ * only at turn end) plus a monotonic guard, mirroring the tmux backend's
1479
+ * {@link import('./claudeCliAdapter').ClaudeCliAdapter} advance so both Claude
1480
+ * paths track "relayed up to here". Best-effort — a transcript not yet on disk
1481
+ * leaves the watermark where it was; the next relayed message re-tries.
1482
+ */
1483
+ advanceWatermarkFromTranscript(session) {
1484
+ try {
1485
+ const filePath = (0, claudeCliAdapter_1.getClaudeTranscriptPath)(session.workDir, session.sessionId);
1486
+ const eof = fs.statSync(filePath).size;
1487
+ if (eof <= session.lastWatermarkOffset)
1488
+ return; // monotonic: only real growth writes
1489
+ session.lastWatermarkOffset = eof;
1490
+ this.advanceSeenWatermark(session.key, { sessionId: session.sessionId, claudeTranscriptOffset: eof });
1491
+ }
1492
+ catch {
1493
+ // Transcript not yet on disk (UUID just born) / stat failed — retry next relay.
1494
+ }
1495
+ }
1496
+ // — api error —
1497
+ /** Classify + emit an `apiError` once per episode; returns whether it fired. */
1498
+ maybeEmitApiError(session, text) {
1499
+ if (session.apiErrorFired)
1500
+ return false;
1501
+ const apiError = (0, apiErrorRetry_1.classifyAgentApiError)(text, Date.now());
1502
+ if (!apiError)
1503
+ return false;
1504
+ session.apiErrorFired = true;
1505
+ this.emit('apiError', session.key, apiError);
1506
+ return true;
1507
+ }
1508
+ // ─────────────────────────────────────────────────────────────────────────
1509
+ // Questions & permissions — control channel (S4)
1510
+ // ─────────────────────────────────────────────────────────────────────────
1511
+ handleControlRequest(session, action) {
1512
+ if (action.subtype === 'can_use_tool') {
1513
+ if (action.toolName === 'AskUserQuestion' && action.input && action.toolUseId) {
1514
+ session.questionToolUseIds.add(action.toolUseId);
1515
+ this.surfaceQuestion(session, action.requestId, action.toolUseId, action.input);
1516
+ return;
1517
+ }
1518
+ // Any other tool → auto-allow (operator trusts their own agent; parity with
1519
+ // the tmux backend's bypassPermissions). Under bypass this fires only for the
1520
+ // residual circuit-breakers claude never bypasses (`rm -rf /`, `rm -rf ~`).
1521
+ // `buildCanUseToolAllow` guarantees the schema-required `updatedInput`.
1522
+ this.writeControlResponse(session, action.requestId, (0, claudeStreamJson_1.buildCanUseToolAllow)(action.input, action.toolUseId));
1523
+ return;
1524
+ }
1525
+ if (action.subtype === 'request_user_dialog') {
1526
+ // No dialog UI in Telegram → cancel so the CLI falls back gracefully.
1527
+ this.writeControlResponse(session, action.requestId, { behavior: 'cancelled' });
1528
+ return;
1529
+ }
1530
+ // Unknown control request → generic success so the CLI is never left hanging.
1531
+ this.writeControlResponse(session, action.requestId, {});
1532
+ }
1533
+ surfaceQuestion(session, requestId, toolUseId, rawInput) {
1534
+ const questions = this.parseQuestions(rawInput);
1535
+ if (questions.length === 0) {
1536
+ // Nothing to ask — allow with the raw input so the turn continues.
1537
+ this.writeControlResponse(session, requestId, (0, claudeStreamJson_1.buildCanUseToolAllow)(rawInput, toolUseId));
1538
+ return;
1539
+ }
1540
+ session.pendingQuestion = { requestId, toolUseId, rawInput, questions };
1541
+ session.isBusy = true;
1542
+ this.writeQuestionSidecar(session);
1543
+ const payload = { requestId, questions };
1544
+ this.emit('question', session.key, payload);
1545
+ }
1546
+ /**
1547
+ * @description Persist the pending question to the host dir. The external
1548
+ * claude process stays BLOCKED on its `can_use_tool` across a bot restart,
1549
+ * but the control_request line lies BEFORE the persisted tail offset (it was
1550
+ * consumed pre-restart), so tail replay alone would never resurface it — the
1551
+ * sidecar is what lets an adopting bot still answer over the FIFO. Removed
1552
+ * the moment the question resolves (answer / reject); dies with the dir on
1553
+ * stop.
1554
+ */
1555
+ writeQuestionSidecar(session) {
1556
+ if (!session.pendingQuestion)
1557
+ return;
1558
+ try {
1559
+ fs.writeFileSync(session.paths.questionFile, JSON.stringify(session.pendingQuestion));
1560
+ }
1561
+ catch (e) {
1562
+ console.warn(`[ClaudeJson] cannot persist pending question for ${(0, sessionKey_1.keyToString)(session.key)}:`, e instanceof Error ? e.message : e);
1563
+ }
1564
+ }
1565
+ clearQuestionSidecar(session) {
1566
+ try {
1567
+ fs.unlinkSync(session.paths.questionFile);
1568
+ }
1569
+ catch { /* absent */ }
1570
+ }
1571
+ /** Map the AskUserQuestion `input.questions` to the shared question shape
1572
+ * (dropping option `preview`, which breaks in the Telegram relay). */
1573
+ parseQuestions(rawInput) {
1574
+ const rawQuestions = Array.isArray(rawInput.questions) ? rawInput.questions : [];
1575
+ const result = [];
1576
+ for (const raw of rawQuestions) {
1577
+ if (typeof raw !== 'object' || raw === null)
1578
+ continue;
1579
+ const q = raw;
1580
+ if (typeof q.question !== 'string')
1581
+ continue;
1582
+ const rawOptions = Array.isArray(q.options) ? q.options : [];
1583
+ const options = rawOptions
1584
+ .map((o) => {
1585
+ if (typeof o !== 'object' || o === null)
1586
+ return null;
1587
+ const oo = o;
1588
+ if (typeof oo.label !== 'string')
1589
+ return null;
1590
+ return typeof oo.description === 'string' ? { label: oo.label, description: oo.description } : { label: oo.label };
1591
+ })
1592
+ .filter((o) => o !== null);
1593
+ if (options.length === 0)
1594
+ continue;
1595
+ const question = { question: q.question, options };
1596
+ if (typeof q.header === 'string')
1597
+ question.header = q.header;
1598
+ if (q.multiSelect === true)
1599
+ question.multiple = true;
1600
+ result.push(question);
1601
+ }
1602
+ return result;
1603
+ }
1604
+ answerQuestion(key, answers) {
1605
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
1606
+ if (!session?.isActive || !session.pendingQuestion)
1607
+ return;
1608
+ const pending = session.pendingQuestion;
1609
+ session.pendingQuestion = null;
1610
+ this.clearQuestionSidecar(session);
1611
+ // The turn resumes now; reset the idle-watchdog clock so the (possibly long)
1612
+ // wait for the user's answer doesn't instantly trip it before output resumes.
1613
+ session.lastStdoutActivityAt = Date.now();
1614
+ // Build the answers map: question text → selected label(s) (comma-joined for
1615
+ // multi-select), the exact shape AskUserQuestion expects.
1616
+ const answersMap = {};
1617
+ pending.questions.forEach((q, i) => {
1618
+ const selected = answers[i] ?? [];
1619
+ answersMap[q.question] = selected.join(',');
1620
+ });
1621
+ this.writeControlResponse(session, pending.requestId, (0, claudeStreamJson_1.buildCanUseToolAllow)({ ...pending.rawInput, answers: answersMap }, pending.toolUseId));
1622
+ }
1623
+ rejectQuestion(key) {
1624
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
1625
+ if (!session?.pendingQuestion)
1626
+ return;
1627
+ const pending = session.pendingQuestion;
1628
+ session.pendingQuestion = null;
1629
+ this.clearQuestionSidecar(session);
1630
+ this.writeControlResponse(session, pending.requestId, (0, claudeStreamJson_1.buildCanUseToolDeny)('User declined to answer the question.', pending.toolUseId));
1631
+ }
1632
+ writeControlResponse(session, requestId, response) {
1633
+ this.writeStdin(session, { type: 'control_response', response: { subtype: 'success', request_id: requestId, response } });
1634
+ }
1635
+ // ─────────────────────────────────────────────────────────────────────────
1636
+ // Session history / resume (S5) — reuse the shared Claude transcript readers
1637
+ // ─────────────────────────────────────────────────────────────────────────
1638
+ async getSessions(_key, workDir) {
1639
+ return (0, claudeCliAdapter_1.listClaudeSessionsForWorkDir)((0, claudeCliAdapter_1.getClaudeProjectsRoot)(), workDir);
1640
+ }
1641
+ async getRecentTurns(_key, workDir, sessionId, limit) {
1642
+ const filePath = (0, claudeCliAdapter_1.getClaudeTranscriptPath)(workDir, sessionId);
1643
+ return (0, claudeCliAdapter_1.readRecentClaudeTurns)(filePath, limit);
1644
+ }
1645
+ async getReattachRecap(key, workDir, sessionId, watermark) {
1646
+ const filePath = (0, claudeCliAdapter_1.getClaudeTranscriptPath)(workDir, sessionId);
1647
+ const offset = watermark?.claudeTranscriptOffset;
1648
+ const isWatermarkKnown = typeof offset === 'number' && watermark?.sessionId === sessionId;
1649
+ const { missedCount, turns, headOffset } = (0, claudeCliAdapter_1.readClaudeReattachTranscript)(filePath, offset ?? 0, resumeContext_1.resumeContextTurnLimit);
1650
+ const headWatermark = headOffset === undefined ? undefined : { sessionId, claudeTranscriptOffset: headOffset };
1651
+ return { missedCount: isWatermarkKnown ? missedCount : 0, turns, isWatermarkKnown, isActive: this.checkIsBusy(key), headWatermark };
1652
+ }
1653
+ // ─────────────────────────────────────────────────────────────────────────
1654
+ // Model / effort (S6) — spawn flags; a live change re-spawns with --resume
1655
+ // ─────────────────────────────────────────────────────────────────────────
1656
+ async setModel(key, modelId) {
1657
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
1658
+ if (!session?.isActive)
1659
+ return (0, i18n_1.t)('model.start_agent_first');
1660
+ await this.respawnWithChange(session, { model: modelId, effort: session.effort });
1661
+ return null;
1662
+ }
1663
+ /**
1664
+ * @description The model the session is RUNNING. Claude's own `system/init`
1665
+ * report wins over the pinned `--model` pick: it is the resolved id (an alias
1666
+ * like `opus` resolves to its snapshot) and it is the only value present when
1667
+ * no pick was ever made. The pick is the fallback for the window between a
1668
+ * `/model` re-spawn and its first `init`, so the label never blanks out
1669
+ * mid-switch.
1670
+ */
1671
+ getCurrentModel(key) {
1672
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
1673
+ return session?.reportedModel ?? session?.model ?? null;
1674
+ }
1675
+ async getAvailableModels() {
1676
+ // The CLI `--model` accepts these aliases (resolved to the latest snapshot).
1677
+ return ['fable', 'opus', 'sonnet', 'haiku'];
1678
+ }
1679
+ async setEffort(key, level) {
1680
+ if (!(0, effortLevels_1.checkIsClaudeEffortLevel)(level)) {
1681
+ return (0, i18n_1.t)('effort.invalid_level', { level, valid: (0, effortLevels_1.getClaudeAvailableLevels)().join(', ') });
1682
+ }
1683
+ (0, claudeCliAdapter_1.saveEffortPref)(key, level);
1684
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
1685
+ if (!session?.isActive)
1686
+ return (0, i18n_1.t)('effort.start_agent_first');
1687
+ await this.respawnWithChange(session, { model: session.model, effort: level });
1688
+ return null;
1689
+ }
1690
+ getEffort(key) {
1691
+ return (0, claudeCliAdapter_1.loadEffortPrefs)()[(0, sessionKey_1.keyToString)(key)] ?? null;
1692
+ }
1693
+ async getAvailableEffortLevels(_key) {
1694
+ return (0, effortLevels_1.getClaudeAvailableLevels)();
1695
+ }
1696
+ /**
1697
+ * @description Apply a model/effort change by re-spawning the child with
1698
+ * `--resume <sessionId>` (the on-disk session persists, so only an in-flight
1699
+ * streaming reply is lost — same trade-off as OpenCode's server restart). The
1700
+ * intermediate exit is suppressed (`isRespawning`) so the bot sees no
1701
+ * closed/stopped churn.
1702
+ */
1703
+ async respawnWithChange(session, change) {
1704
+ const { key, workDir, sessionId } = session;
1705
+ const configDir = change.configDir === undefined ? session.configDir : change.configDir;
1706
+ session.isRespawning = true;
1707
+ this.rejectQuestion(key);
1708
+ await session.stdinWriteChain.catch(() => { });
1709
+ this.clearTimers(session);
1710
+ session.isActive = false;
1711
+ this.closeFifo(session);
1712
+ try {
1713
+ process.kill(session.pid, 'SIGTERM');
1714
+ }
1715
+ catch { /* gone */ }
1716
+ await (0, tmuxExec_1.tmuxAsync)('kill-session', '-t', (0, tmuxExec_1.getTmuxSessionTarget)((0, jsonStreamHost_1.buildJsonStreamTmuxSessionName)(key)));
1717
+ // spawnSession lays the host dir out fresh and replaces the map entry.
1718
+ await this.spawnSession(key, workDir, sessionId, { effort: change.effort, model: change.model, resume: true, configDir });
1719
+ }
1720
+ // ─────────────────────────────────────────────────────────────────────────
1721
+ // Account profile (`/account`) — the spawn's CLAUDE_CONFIG_DIR; a live change re-spawns
1722
+ // ─────────────────────────────────────────────────────────────────────────
1723
+ /** The `CLAUDE_CONFIG_DIR` the live process runs with (`null` = default profile); `undefined` without a live process. */
1724
+ getSessionClaudeConfigDir(key) {
1725
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
1726
+ return session?.isActive ? session.configDir : undefined;
1727
+ }
1728
+ /**
1729
+ * @description Bring the live process onto the account profile its conversation resolves to NOW: nothing
1730
+ * when it already runs there; a re-spawn with `--resume` (the `/model` path — same conversation, model and
1731
+ * effort kept) when it is idle; deferred to the end of its turn when it works, since a re-spawn kills the turn
1732
+ * and any background task. A sleeping conversation needs nothing: its next resume reads the reader.
1733
+ *
1734
+ * `isAfterLimit`: the switch answers a usage limit (the offer button, auto-switch, a pick during the limit
1735
+ * wait). The turn is dead and the model cannot act on the limited account, so the re-spawn happens NOW even
1736
+ * when the session looks working (busy flag, unconsumed input). Live background tasks (background Bash,
1737
+ * sub-agents) are stopped by it too — a deliberate choice: the user chose to move, and a process on a limited
1738
+ * account cannot make progress; the caller says so when `checkHasBackgroundWork` was true.
1739
+ */
1740
+ async applyClaudeConfigDir(key, options = {}) {
1741
+ const session = this.sessions.get((0, sessionKey_1.keyToString)(key));
1742
+ if (!session?.isActive)
1743
+ return 'inactive';
1744
+ const wanted = this.resolveConfigDir(key);
1745
+ if (wanted === session.configDir) {
1746
+ session.isConfigDirSwitchPending = false;
1747
+ return 'unchanged';
1748
+ }
1749
+ if (!options.isAfterLimit && this.checkIsWorking(key)) {
1750
+ session.isConfigDirSwitchPending = true;
1751
+ return 'deferred';
1752
+ }
1753
+ session.isConfigDirSwitchPending = false;
1754
+ console.log(`[ClaudeJson] ${(0, sessionKey_1.keyToString)(key)}: re-spawning under configDir=${wanted ?? 'default'} (was ${session.configDir ?? 'default'})`);
1755
+ await this.respawnWithChange(session, { model: session.model, effort: session.effort, configDir: wanted });
1756
+ return 'respawned';
1757
+ }
1758
+ /** A deferred profile switch runs once the turn that held it off has ended (and nothing else works). */
1759
+ applyPendingConfigDirSwitch(session) {
1760
+ if (!session.isConfigDirSwitchPending || !session.isActive)
1761
+ return;
1762
+ if (this.checkIsWorking(session.key))
1763
+ return; // a background task still runs: the next turn end looks again
1764
+ // Detached from the tail poll that delivered the `result`: the re-spawn tears this very session down.
1765
+ setTimeout(() => {
1766
+ void this.applyClaudeConfigDir(session.key).catch((e) => console.warn(`[ClaudeJson] ${(0, sessionKey_1.keyToString)(session.key)}: the deferred profile switch failed:`, e instanceof Error ? e.message : e));
1767
+ }, 0).unref?.();
1768
+ }
1769
+ clearTimers(session) {
1770
+ if (session.pollTimer) {
1771
+ clearTimeout(session.pollTimer);
1772
+ session.pollTimer = null;
1773
+ }
1774
+ if (session.outputTimer) {
1775
+ clearTimeout(session.outputTimer);
1776
+ session.outputTimer = null;
1777
+ }
1778
+ if (session.reasoningTimer) {
1779
+ clearTimeout(session.reasoningTimer);
1780
+ session.reasoningTimer = null;
1781
+ }
1782
+ if (session.childOutputTimer) {
1783
+ clearTimeout(session.childOutputTimer);
1784
+ session.childOutputTimer = null;
1785
+ }
1786
+ // An in-flight compaction dies with the session: the process that was going
1787
+ // to confirm it is gone, so settle the caller now instead of leaving it
1788
+ // parked until the silence watchdog notices a session that no longer exists.
1789
+ this.resolveCompaction(session, { ok: false, error: 'the session ended before the compaction confirmed' });
1790
+ // Same reasoning for bot-issued control requests: the process they were
1791
+ // talking to is going away (stop / exit / model-effort respawn), so their
1792
+ // replies can never arrive. Settle each as an unknown (`null`) and drop the
1793
+ // map, rather than leaving a caller parked on the round-trip timeout and a
1794
+ // timer armed against a dead session.
1795
+ const pendingControls = [...session.pendingControlRequests.values()];
1796
+ session.pendingControlRequests.clear();
1797
+ for (const pending of pendingControls) {
1798
+ clearTimeout(pending.timer);
1799
+ pending.resolve(null);
1800
+ }
1801
+ }
1802
+ }
1803
+ exports.ClaudeJsonStreamAdapter = ClaudeJsonStreamAdapter;
1804
+ /** The tail record persisted for a session at `offsetBytes` — the offset and the working
1805
+ * state in force there (task list, turn in flight, outstanding tools) travel together
1806
+ * (see `JsonStreamTailOffset`). */
1807
+ function buildTailRecord(session, offsetBytes) {
1808
+ return {
1809
+ sessionId: session.sessionId,
1810
+ offsetBytes,
1811
+ backgroundTaskIds: [...session.backgroundTaskIds],
1812
+ isTurnInFlight: session.isBusy,
1813
+ outstandingToolUseIds: [...session.outstandingToolUseIds],
1814
+ // Only once known: the record never claims a version the process did not report.
1815
+ ...(session.claudeCodeVersion !== null ? { claudeCodeVersion: session.claudeCodeVersion } : {}),
1816
+ };
1817
+ }
1818
+ /**
1819
+ * @description Whether every consumed event has LEFT the adapter — nothing is
1820
+ * waiting in the answer / sub-agent 350ms batchers. Gates the tail-offset
1821
+ * persist: batched-but-unemitted text must keep the persisted offset BEHIND
1822
+ * it, so a restart replays (never skips) it. Live thinking text is
1823
+ * deliberately ignored — it renders as a transient frame, so a lost batch of
1824
+ * it at a reload seam costs nothing permanent.
1825
+ */
1826
+ function checkIsEmitCaughtUp(session) {
1827
+ return session.currentResponseText.length === session.emittedLength
1828
+ && session.childResponseText.length === session.childEmittedLength;
1829
+ }
1830
+ /**
1831
+ * @description Extract the newest compaction summary from a Claude on-disk
1832
+ * transcript: the last JSONL line with `isCompactSummary === true`, whose
1833
+ * `message.content` (a string, or `{type:'text'}` blocks) holds the summary the
1834
+ * `/compact` turn produced. Returns `null` for an unreadable file or when no
1835
+ * summary line is present. Reads the whole file — cheap enough for the
1836
+ * once-per-idle-compaction call.
1837
+ */
1838
+ function readLatestCompactSummaryFromTranscript(filePath) {
1839
+ let raw;
1840
+ try {
1841
+ raw = fs.readFileSync(filePath, 'utf8');
1842
+ }
1843
+ catch {
1844
+ return null;
1845
+ }
1846
+ let summary = null;
1847
+ for (const line of raw.split('\n')) {
1848
+ const trimmed = line.trim();
1849
+ if (!trimmed)
1850
+ continue;
1851
+ let obj;
1852
+ try {
1853
+ obj = JSON.parse(trimmed);
1854
+ }
1855
+ catch {
1856
+ continue;
1857
+ }
1858
+ if (!(0, claudeStreamJson_1.checkIsStreamRecord)(obj) || obj.isCompactSummary !== true)
1859
+ continue;
1860
+ const message = (0, claudeStreamJson_1.checkIsStreamRecord)(obj.message) ? obj.message : null;
1861
+ const content = message?.content;
1862
+ if (typeof content === 'string' && content.trim()) {
1863
+ summary = content;
1864
+ }
1865
+ else if (Array.isArray(content)) {
1866
+ const chunks = [];
1867
+ for (const block of content) {
1868
+ if ((0, claudeStreamJson_1.checkIsStreamRecord)(block) && block.type === 'text' && typeof block.text === 'string') {
1869
+ chunks.push(block.text);
1870
+ }
1871
+ }
1872
+ if (chunks.join('').trim())
1873
+ summary = chunks.join('');
1874
+ }
1875
+ }
1876
+ return summary;
1877
+ }
1878
+ /** Spawn-fail diagnostics: the wrapper's exit code + a stderr excerpt (the
1879
+ * passive `stderr.log` is read ONLY here and at unexpected exit — locked
1880
+ * decision, no live stderr consumer). */
1881
+ function describeSpawnFailure(paths) {
1882
+ const exitCode = (0, jsonStreamHost_1.readExitCodeFile)(paths.exitCodeFile);
1883
+ const stderrTail = (0, jsonStreamHost_1.readStderrTail)(paths.stderrFile);
1884
+ const parts = [];
1885
+ if (exitCode !== null)
1886
+ parts.push(`exit=${exitCode}`);
1887
+ if (stderrTail)
1888
+ parts.push(`stderr: ${stderrTail}`);
1889
+ return parts.length > 0 ? ` (${parts.join(', ')})` : '';
1890
+ }
1891
+ //# sourceMappingURL=claudeJsonStreamAdapter.js.map