@iaforged/context-code 1.0.63 → 1.0.65

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 (2000) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +633 -9
  3. package/context-bootstrap.js +28 -28
  4. package/package.json +169 -170
  5. package/dist/src/QueryEngine.js +0 -928
  6. package/dist/src/Task.js +0 -49
  7. package/dist/src/Tool.js +0 -56
  8. package/dist/src/assistant/AssistantSessionChooser.js +0 -16
  9. package/dist/src/assistant/index.js +0 -16
  10. package/dist/src/assistant/sessionDiscovery.js +0 -16
  11. package/dist/src/assistant/sessionHistory.js +0 -47
  12. package/dist/src/bootstrap/state.js +0 -1165
  13. package/dist/src/bridge/bridgeApi.js +0 -304
  14. package/dist/src/bridge/bridgeConfig.js +0 -39
  15. package/dist/src/bridge/bridgeDebug.js +0 -73
  16. package/dist/src/bridge/bridgeEnabled.js +0 -187
  17. package/dist/src/bridge/bridgeMain.js +0 -2289
  18. package/dist/src/bridge/bridgeMessaging.js +0 -353
  19. package/dist/src/bridge/bridgePermissionCallbacks.js +0 -10
  20. package/dist/src/bridge/bridgePointer.js +0 -175
  21. package/dist/src/bridge/bridgeStatusUtil.js +0 -105
  22. package/dist/src/bridge/bridgeUI.js +0 -412
  23. package/dist/src/bridge/capacityWake.js +0 -35
  24. package/dist/src/bridge/codeSessionApi.js +0 -111
  25. package/dist/src/bridge/createSession.js +0 -273
  26. package/dist/src/bridge/debugUtils.js +0 -115
  27. package/dist/src/bridge/envLessBridgeConfig.js +0 -121
  28. package/dist/src/bridge/flushGate.js +0 -65
  29. package/dist/src/bridge/inboundAttachments.js +0 -152
  30. package/dist/src/bridge/inboundMessages.js +0 -63
  31. package/dist/src/bridge/initReplBridge.js +0 -428
  32. package/dist/src/bridge/jwtUtils.js +0 -185
  33. package/dist/src/bridge/pollConfig.js +0 -85
  34. package/dist/src/bridge/pollConfigDefaults.js +0 -62
  35. package/dist/src/bridge/remoteBridgeCore.js +0 -712
  36. package/dist/src/bridge/replBridge.js +0 -1720
  37. package/dist/src/bridge/replBridgeHandle.js +0 -30
  38. package/dist/src/bridge/replBridgeTransport.js +0 -236
  39. package/dist/src/bridge/sessionIdCompat.js +0 -56
  40. package/dist/src/bridge/sessionRunner.js +0 -421
  41. package/dist/src/bridge/trustedDevice.js +0 -172
  42. package/dist/src/bridge/types.js +0 -9
  43. package/dist/src/bridge/workSecret.js +0 -99
  44. package/dist/src/buddy/CompanionSprite.js +0 -349
  45. package/dist/src/buddy/companion.js +0 -107
  46. package/dist/src/buddy/prompt.js +0 -33
  47. package/dist/src/buddy/sprites.js +0 -488
  48. package/dist/src/buddy/types.js +0 -90
  49. package/dist/src/buddy/useBuddyNotification.js +0 -90
  50. package/dist/src/cli/bg.js +0 -16
  51. package/dist/src/cli/exit.js +0 -30
  52. package/dist/src/cli/handlers/agents.js +0 -55
  53. package/dist/src/cli/handlers/ant.js +0 -16
  54. package/dist/src/cli/handlers/auth.js +0 -312
  55. package/dist/src/cli/handlers/autoMode.js +0 -128
  56. package/dist/src/cli/handlers/mcp.js +0 -334
  57. package/dist/src/cli/handlers/plugins.js +0 -634
  58. package/dist/src/cli/handlers/projects_bridge.js +0 -40
  59. package/dist/src/cli/handlers/templateJobs.js +0 -16
  60. package/dist/src/cli/handlers/util.js +0 -76
  61. package/dist/src/cli/ndjsonSafeStringify.js +0 -27
  62. package/dist/src/cli/print.js +0 -4225
  63. package/dist/src/cli/remoteIO.js +0 -208
  64. package/dist/src/cli/rollback.js +0 -16
  65. package/dist/src/cli/structuredIO.js +0 -644
  66. package/dist/src/cli/transports/HybridTransport.js +0 -233
  67. package/dist/src/cli/transports/SSETransport.js +0 -538
  68. package/dist/src/cli/transports/SerialBatchEventUploader.js +0 -224
  69. package/dist/src/cli/transports/Transport.js +0 -1
  70. package/dist/src/cli/transports/WebSocketTransport.js +0 -613
  71. package/dist/src/cli/transports/WorkerStateUploader.js +0 -88
  72. package/dist/src/cli/transports/ccrClient.js +0 -711
  73. package/dist/src/cli/transports/transportUtils.js +0 -39
  74. package/dist/src/cli/up.js +0 -16
  75. package/dist/src/cli/update.js +0 -315
  76. package/dist/src/commands/add-dir/add-dir.js +0 -121
  77. package/dist/src/commands/add-dir/index.js +0 -8
  78. package/dist/src/commands/add-dir/validation.js +0 -76
  79. package/dist/src/commands/advisor.js +0 -88
  80. package/dist/src/commands/agents/agents.js +0 -9
  81. package/dist/src/commands/agents/index.js +0 -7
  82. package/dist/src/commands/ant-trace/index.js +0 -1
  83. package/dist/src/commands/assistant/assistant.js +0 -16
  84. package/dist/src/commands/autofix-pr/index.js +0 -1
  85. package/dist/src/commands/backfill-sessions/index.js +0 -1
  86. package/dist/src/commands/branch/branch.js +0 -205
  87. package/dist/src/commands/branch/index.js +0 -11
  88. package/dist/src/commands/break-cache/index.js +0 -1
  89. package/dist/src/commands/bridge/bridge.js +0 -512
  90. package/dist/src/commands/bridge/index.js +0 -22
  91. package/dist/src/commands/bridge-kick.js +0 -179
  92. package/dist/src/commands/brief.js +0 -94
  93. package/dist/src/commands/btw/btw.js +0 -234
  94. package/dist/src/commands/btw/index.js +0 -9
  95. package/dist/src/commands/bughunter/index.js +0 -1
  96. package/dist/src/commands/chrome/chrome.js +0 -291
  97. package/dist/src/commands/chrome/index.js +0 -10
  98. package/dist/src/commands/clear/caches.js +0 -116
  99. package/dist/src/commands/clear/clear.js +0 -5
  100. package/dist/src/commands/clear/conversation.js +0 -191
  101. package/dist/src/commands/clear/index.js +0 -9
  102. package/dist/src/commands/color/color.js +0 -58
  103. package/dist/src/commands/color/index.js +0 -9
  104. package/dist/src/commands/commit-push-pr.js +0 -137
  105. package/dist/src/commands/commit.js +0 -80
  106. package/dist/src/commands/compact/compact.js +0 -196
  107. package/dist/src/commands/compact/index.js +0 -11
  108. package/dist/src/commands/config/config.js +0 -5
  109. package/dist/src/commands/config/index.js +0 -8
  110. package/dist/src/commands/context/context-noninteractive.js +0 -221
  111. package/dist/src/commands/context/context.js +0 -46
  112. package/dist/src/commands/context/index.js +0 -21
  113. package/dist/src/commands/copy/copy.js +0 -366
  114. package/dist/src/commands/copy/index.js +0 -7
  115. package/dist/src/commands/cost/cost.js +0 -21
  116. package/dist/src/commands/cost/index.js +0 -16
  117. package/dist/src/commands/createMovedToPluginCommand.js +0 -33
  118. package/dist/src/commands/ctx_viz/index.js +0 -1
  119. package/dist/src/commands/debug-tool-call/index.js +0 -1
  120. package/dist/src/commands/desktop/desktop.js +0 -5
  121. package/dist/src/commands/desktop/index.js +0 -22
  122. package/dist/src/commands/diff/diff.js +0 -5
  123. package/dist/src/commands/diff/index.js +0 -6
  124. package/dist/src/commands/doctor/doctor.js +0 -5
  125. package/dist/src/commands/doctor/index.js +0 -9
  126. package/dist/src/commands/effort/effort.js +0 -166
  127. package/dist/src/commands/effort/index.js +0 -11
  128. package/dist/src/commands/env/index.js +0 -1
  129. package/dist/src/commands/exit/exit.js +0 -31
  130. package/dist/src/commands/exit/index.js +0 -9
  131. package/dist/src/commands/export/export.js +0 -86
  132. package/dist/src/commands/export/index.js +0 -8
  133. package/dist/src/commands/extra-usage/extra-usage-core.js +0 -99
  134. package/dist/src/commands/extra-usage/extra-usage-noninteractive.js +0 -13
  135. package/dist/src/commands/extra-usage/extra-usage.js +0 -14
  136. package/dist/src/commands/extra-usage/index.js +0 -27
  137. package/dist/src/commands/fast/fast.js +0 -275
  138. package/dist/src/commands/fast/index.js +0 -20
  139. package/dist/src/commands/feedback/feedback.js +0 -10
  140. package/dist/src/commands/feedback/index.js +0 -20
  141. package/dist/src/commands/files/files.js +0 -11
  142. package/dist/src/commands/files/index.js +0 -9
  143. package/dist/src/commands/good-claude/index.js +0 -1
  144. package/dist/src/commands/heapdump/heapdump.js +0 -14
  145. package/dist/src/commands/heapdump/index.js +0 -9
  146. package/dist/src/commands/help/help.js +0 -5
  147. package/dist/src/commands/help/index.js +0 -7
  148. package/dist/src/commands/hooks/hooks.js +0 -11
  149. package/dist/src/commands/hooks/index.js +0 -8
  150. package/dist/src/commands/ide/ide.js +0 -615
  151. package/dist/src/commands/ide/index.js +0 -8
  152. package/dist/src/commands/init-verifiers.js +0 -258
  153. package/dist/src/commands/init.js +0 -249
  154. package/dist/src/commands/insights.js +0 -2555
  155. package/dist/src/commands/install-github-app/ApiKeyStep.js +0 -230
  156. package/dist/src/commands/install-github-app/CheckExistingSecretStep.js +0 -194
  157. package/dist/src/commands/install-github-app/CheckGitHubStep.js +0 -15
  158. package/dist/src/commands/install-github-app/ChooseRepoStep.js +0 -211
  159. package/dist/src/commands/install-github-app/CreatingStep.js +0 -52
  160. package/dist/src/commands/install-github-app/ErrorStep.js +0 -83
  161. package/dist/src/commands/install-github-app/ExistingWorkflowStep.js +0 -104
  162. package/dist/src/commands/install-github-app/InstallAppStep.js +0 -96
  163. package/dist/src/commands/install-github-app/OAuthFlowStep.js +0 -190
  164. package/dist/src/commands/install-github-app/SuccessStep.js +0 -93
  165. package/dist/src/commands/install-github-app/WarningsStep.js +0 -70
  166. package/dist/src/commands/install-github-app/index.js +0 -10
  167. package/dist/src/commands/install-github-app/install-github-app.js +0 -593
  168. package/dist/src/commands/install-github-app/setupGitHubActions.js +0 -227
  169. package/dist/src/commands/install-slack-app/index.js +0 -9
  170. package/dist/src/commands/install-slack-app/install-slack-app.js +0 -25
  171. package/dist/src/commands/install.js +0 -118
  172. package/dist/src/commands/issue/index.js +0 -1
  173. package/dist/src/commands/keybindings/index.js +0 -10
  174. package/dist/src/commands/keybindings/keybindings.js +0 -47
  175. package/dist/src/commands/login/index.js +0 -11
  176. package/dist/src/commands/login/login.js +0 -99
  177. package/dist/src/commands/login-openai/index.js +0 -7
  178. package/dist/src/commands/login-openai/login-openai.js +0 -54
  179. package/dist/src/commands/logout/index.js +0 -8
  180. package/dist/src/commands/logout/logout.js +0 -72
  181. package/dist/src/commands/mcp/addCommand.js +0 -183
  182. package/dist/src/commands/mcp/index.js +0 -9
  183. package/dist/src/commands/mcp/mcp.js +0 -78
  184. package/dist/src/commands/mcp/xaaIdpCommand.js +0 -193
  185. package/dist/src/commands/memory/index.js +0 -7
  186. package/dist/src/commands/memory/memory.js +0 -71
  187. package/dist/src/commands/mobile/index.js +0 -8
  188. package/dist/src/commands/mobile/mobile.js +0 -278
  189. package/dist/src/commands/mock-limits/index.js +0 -1
  190. package/dist/src/commands/model/index.js +0 -14
  191. package/dist/src/commands/model/model.js +0 -297
  192. package/dist/src/commands/oauth-refresh/index.js +0 -1
  193. package/dist/src/commands/onboarding/index.js +0 -1
  194. package/dist/src/commands/output-style/index.js +0 -8
  195. package/dist/src/commands/output-style/output-style.js +0 -6
  196. package/dist/src/commands/passes/index.js +0 -17
  197. package/dist/src/commands/passes/passes.js +0 -22
  198. package/dist/src/commands/perf-issue/index.js +0 -1
  199. package/dist/src/commands/permissions/index.js +0 -8
  200. package/dist/src/commands/permissions/permissions.js +0 -8
  201. package/dist/src/commands/plan/index.js +0 -8
  202. package/dist/src/commands/plan/plan.js +0 -115
  203. package/dist/src/commands/plugin/AddMarketplace.js +0 -95
  204. package/dist/src/commands/plugin/BrowseMarketplace.js +0 -576
  205. package/dist/src/commands/plugin/DiscoverPlugins.js +0 -613
  206. package/dist/src/commands/plugin/ManageMarketplaces.js +0 -582
  207. package/dist/src/commands/plugin/ManagePlugins.js +0 -1783
  208. package/dist/src/commands/plugin/PluginErrors.js +0 -124
  209. package/dist/src/commands/plugin/PluginOptionsDialog.js +0 -367
  210. package/dist/src/commands/plugin/PluginOptionsFlow.js +0 -97
  211. package/dist/src/commands/plugin/PluginSettings.js +0 -1042
  212. package/dist/src/commands/plugin/PluginTrustWarning.js +0 -34
  213. package/dist/src/commands/plugin/UnifiedInstalledCell.js +0 -615
  214. package/dist/src/commands/plugin/ValidatePlugin.js +0 -95
  215. package/dist/src/commands/plugin/index.js +0 -10
  216. package/dist/src/commands/plugin/parseArgs.js +0 -71
  217. package/dist/src/commands/plugin/plugin.js +0 -5
  218. package/dist/src/commands/plugin/pluginDetailsHelpers.js +0 -89
  219. package/dist/src/commands/plugin/usePagination.js +0 -89
  220. package/dist/src/commands/pr_comments/index.js +0 -49
  221. package/dist/src/commands/privacy-settings/index.js +0 -11
  222. package/dist/src/commands/privacy-settings/privacy-settings.js +0 -54
  223. package/dist/src/commands/profile/index.js +0 -9
  224. package/dist/src/commands/profile/profile.js +0 -426
  225. package/dist/src/commands/provider/index.js +0 -8
  226. package/dist/src/commands/provider/provider.js +0 -349
  227. package/dist/src/commands/rate-limit-options/index.js +0 -15
  228. package/dist/src/commands/rate-limit-options/rate-limit-options.js +0 -213
  229. package/dist/src/commands/release-notes/index.js +0 -8
  230. package/dist/src/commands/release-notes/release-notes.js +0 -38
  231. package/dist/src/commands/reload-plugins/index.js +0 -11
  232. package/dist/src/commands/reload-plugins/reload-plugins.js +0 -52
  233. package/dist/src/commands/remote-env/index.js +0 -12
  234. package/dist/src/commands/remote-env/remote-env.js +0 -5
  235. package/dist/src/commands/remote-setup/api.js +0 -155
  236. package/dist/src/commands/remote-setup/index.js +0 -15
  237. package/dist/src/commands/remote-setup/remote-setup.js +0 -149
  238. package/dist/src/commands/rename/generateSessionName.js +0 -58
  239. package/dist/src/commands/rename/index.js +0 -9
  240. package/dist/src/commands/rename/rename.js +0 -52
  241. package/dist/src/commands/reset-limits/index.js +0 -4
  242. package/dist/src/commands/resume/index.js +0 -9
  243. package/dist/src/commands/resume/resume.js +0 -239
  244. package/dist/src/commands/review/UltrareviewOverageDialog.js +0 -97
  245. package/dist/src/commands/review/reviewRemote.js +0 -259
  246. package/dist/src/commands/review/ultrareviewCommand.js +0 -57
  247. package/dist/src/commands/review/ultrareviewEnabled.js +0 -10
  248. package/dist/src/commands/review.js +0 -50
  249. package/dist/src/commands/rewind/index.js +0 -10
  250. package/dist/src/commands/rewind/rewind.js +0 -7
  251. package/dist/src/commands/sandbox-toggle/index.js +0 -41
  252. package/dist/src/commands/sandbox-toggle/sandbox-toggle.js +0 -72
  253. package/dist/src/commands/security-review.js +0 -231
  254. package/dist/src/commands/session/index.js +0 -13
  255. package/dist/src/commands/session/session.js +0 -142
  256. package/dist/src/commands/share/index.js +0 -1
  257. package/dist/src/commands/skills/index.js +0 -7
  258. package/dist/src/commands/skills/skills.js +0 -5
  259. package/dist/src/commands/stats/index.js +0 -7
  260. package/dist/src/commands/stats/stats.js +0 -5
  261. package/dist/src/commands/status/index.js +0 -8
  262. package/dist/src/commands/status/status.js +0 -5
  263. package/dist/src/commands/statusline.js +0 -22
  264. package/dist/src/commands/stickers/index.js +0 -8
  265. package/dist/src/commands/stickers/stickers.js +0 -14
  266. package/dist/src/commands/summary/index.js +0 -1
  267. package/dist/src/commands/tag/index.js +0 -9
  268. package/dist/src/commands/tag/tag.js +0 -215
  269. package/dist/src/commands/tasks/index.js +0 -8
  270. package/dist/src/commands/tasks/tasks.js +0 -5
  271. package/dist/src/commands/telegram/index.js +0 -9
  272. package/dist/src/commands/telegram/telegram.js +0 -118
  273. package/dist/src/commands/teleport/index.js +0 -1
  274. package/dist/src/commands/terminalSetup/index.js +0 -18
  275. package/dist/src/commands/terminalSetup/terminalSetup.js +0 -491
  276. package/dist/src/commands/theme/index.js +0 -7
  277. package/dist/src/commands/theme/theme.js +0 -50
  278. package/dist/src/commands/thinkback/index.js +0 -9
  279. package/dist/src/commands/thinkback/thinkback.js +0 -527
  280. package/dist/src/commands/thinkback-play/index.js +0 -13
  281. package/dist/src/commands/thinkback-play/thinkback-play.js +0 -34
  282. package/dist/src/commands/ultraplan.js +0 -418
  283. package/dist/src/commands/upgrade/index.js +0 -12
  284. package/dist/src/commands/upgrade/upgrade.js +0 -37
  285. package/dist/src/commands/usage/index.js +0 -7
  286. package/dist/src/commands/usage/usage.js +0 -5
  287. package/dist/src/commands/version.js +0 -18
  288. package/dist/src/commands/vim/index.js +0 -8
  289. package/dist/src/commands/vim/vim.js +0 -25
  290. package/dist/src/commands/voice/index.js +0 -14
  291. package/dist/src/commands/voice/voice.js +0 -130
  292. package/dist/src/commands/whatsapp/index.js +0 -9
  293. package/dist/src/commands/whatsapp/whatsapp.js +0 -326
  294. package/dist/src/commands.js +0 -646
  295. package/dist/src/components/AgentProgressLine.js +0 -111
  296. package/dist/src/components/App.js +0 -45
  297. package/dist/src/components/ApproveApiKey.js +0 -124
  298. package/dist/src/components/AutoModeOptInDialog.js +0 -140
  299. package/dist/src/components/AutoUpdater.js +0 -157
  300. package/dist/src/components/AutoUpdaterWrapper.js +0 -78
  301. package/dist/src/components/AwsAuthStatusBox.js +0 -88
  302. package/dist/src/components/BaseTextInput.js +0 -105
  303. package/dist/src/components/BashModeProgress.js +0 -48
  304. package/dist/src/components/BridgeDialog.js +0 -414
  305. package/dist/src/components/BypassPermissionsModeDialog.js +0 -87
  306. package/dist/src/components/ChannelDowngradeDialog.js +0 -100
  307. package/dist/src/components/ClaudeCodeHint/PluginHintMenu.js +0 -37
  308. package/dist/src/components/ClaudeInChromeOnboarding.js +0 -126
  309. package/dist/src/components/ClaudeMdExternalIncludesDialog.js +0 -137
  310. package/dist/src/components/ClickableImageRef.js +0 -64
  311. package/dist/src/components/CompactSummary.js +0 -119
  312. package/dist/src/components/ConfigurableShortcutHint.js +0 -34
  313. package/dist/src/components/ConsoleOAuthFlow.js +0 -756
  314. package/dist/src/components/ContextSuggestions.js +0 -43
  315. package/dist/src/components/ContextVisualization.js +0 -483
  316. package/dist/src/components/CoordinatorAgentStatus.js +0 -261
  317. package/dist/src/components/CostThresholdDialog.js +0 -48
  318. package/dist/src/components/CtrlOToExpand.js +0 -50
  319. package/dist/src/components/CustomSelect/SelectMulti.js +0 -149
  320. package/dist/src/components/CustomSelect/index.js +0 -2
  321. package/dist/src/components/CustomSelect/option-map.js +0 -32
  322. package/dist/src/components/CustomSelect/select-input-option.js +0 -426
  323. package/dist/src/components/CustomSelect/select-option.js +0 -23
  324. package/dist/src/components/CustomSelect/select.js +0 -518
  325. package/dist/src/components/CustomSelect/use-multi-select-state.js +0 -214
  326. package/dist/src/components/CustomSelect/use-select-input.js +0 -170
  327. package/dist/src/components/CustomSelect/use-select-navigation.js +0 -366
  328. package/dist/src/components/CustomSelect/use-select-state.js +0 -22
  329. package/dist/src/components/DesktopHandoff.js +0 -195
  330. package/dist/src/components/DesktopUpsell/DesktopUpsellStartup.js +0 -173
  331. package/dist/src/components/DevBar.js +0 -50
  332. package/dist/src/components/DevChannelsDialog.js +0 -103
  333. package/dist/src/components/DiagnosticsDisplay.js +0 -91
  334. package/dist/src/components/EffortCallout.js +0 -264
  335. package/dist/src/components/EffortIndicator.js +0 -29
  336. package/dist/src/components/ExitFlow.js +0 -40
  337. package/dist/src/components/ExportDialog.js +0 -101
  338. package/dist/src/components/FallbackToolUseErrorMessage.js +0 -115
  339. package/dist/src/components/FallbackToolUseRejectedMessage.js +0 -16
  340. package/dist/src/components/FastIcon.js +0 -42
  341. package/dist/src/components/Feedback.js +0 -439
  342. package/dist/src/components/FeedbackSurvey/FeedbackSurvey.js +0 -150
  343. package/dist/src/components/FeedbackSurvey/FeedbackSurveyView.js +0 -103
  344. package/dist/src/components/FeedbackSurvey/TranscriptSharePrompt.js +0 -83
  345. package/dist/src/components/FeedbackSurvey/submitTranscriptShare.js +0 -75
  346. package/dist/src/components/FeedbackSurvey/useDebouncedDigitInput.js +0 -51
  347. package/dist/src/components/FeedbackSurvey/useFeedbackSurvey.js +0 -258
  348. package/dist/src/components/FeedbackSurvey/useMemorySurvey.js +0 -191
  349. package/dist/src/components/FeedbackSurvey/usePostCompactSurvey.js +0 -202
  350. package/dist/src/components/FeedbackSurvey/useSurveyState.js +0 -80
  351. package/dist/src/components/FileEditToolDiff.js +0 -166
  352. package/dist/src/components/FileEditToolUpdatedMessage.js +0 -111
  353. package/dist/src/components/FileEditToolUseRejectedMessage.js +0 -157
  354. package/dist/src/components/FilePathLink.js +0 -34
  355. package/dist/src/components/FullscreenLayout.js +0 -578
  356. package/dist/src/components/GlobalSearchDialog.js +0 -339
  357. package/dist/src/components/HelpV2/Commands.js +0 -65
  358. package/dist/src/components/HelpV2/General.js +0 -24
  359. package/dist/src/components/HelpV2/HelpV2.js +0 -186
  360. package/dist/src/components/HighlightedCode/Fallback.js +0 -193
  361. package/dist/src/components/HighlightedCode.js +0 -184
  362. package/dist/src/components/HistorySearchDialog.js +0 -92
  363. package/dist/src/components/IdeAutoConnectDialog.js +0 -153
  364. package/dist/src/components/IdeOnboardingDialog.js +0 -174
  365. package/dist/src/components/IdeStatusIndicator.js +0 -49
  366. package/dist/src/components/IdleReturnDialog.js +0 -116
  367. package/dist/src/components/InterruptedByUser.js +0 -15
  368. package/dist/src/components/InvalidConfigDialog.js +0 -134
  369. package/dist/src/components/InvalidSettingsDialog.js +0 -84
  370. package/dist/src/components/KeybindingWarnings.js +0 -54
  371. package/dist/src/components/LanguagePicker.js +0 -84
  372. package/dist/src/components/LogSelector.js +0 -1579
  373. package/dist/src/components/LogoV2/AnimatedAsterisk.js +0 -42
  374. package/dist/src/components/LogoV2/AnimatedClawd.js +0 -111
  375. package/dist/src/components/LogoV2/ChannelsNotice.js +0 -258
  376. package/dist/src/components/LogoV2/Clawd.js +0 -5
  377. package/dist/src/components/LogoV2/CondensedLogo.js +0 -159
  378. package/dist/src/components/LogoV2/EmergencyTip.js +0 -47
  379. package/dist/src/components/LogoV2/Feed.js +0 -84
  380. package/dist/src/components/LogoV2/FeedColumn.js +0 -55
  381. package/dist/src/components/LogoV2/GuestPassesUpsell.js +0 -71
  382. package/dist/src/components/LogoV2/LogoV2.js +0 -565
  383. package/dist/src/components/LogoV2/Opus1mMergeNotice.js +0 -56
  384. package/dist/src/components/LogoV2/OverageCreditUpsell.js +0 -160
  385. package/dist/src/components/LogoV2/VoiceModeNotice.js +0 -70
  386. package/dist/src/components/LogoV2/WelcomeV2.js +0 -461
  387. package/dist/src/components/LogoV2/feedConfigs.js +0 -78
  388. package/dist/src/components/LspRecommendation/LspRecommendationMenu.js +0 -46
  389. package/dist/src/components/MCPServerApprovalDialog.js +0 -113
  390. package/dist/src/components/MCPServerDesktopImportDialog.js +0 -206
  391. package/dist/src/components/MCPServerDialogCopy.js +0 -15
  392. package/dist/src/components/MCPServerMultiselectDialog.js +0 -133
  393. package/dist/src/components/ManagedSettingsSecurityDialog/ManagedSettingsSecurityDialog.js +0 -149
  394. package/dist/src/components/ManagedSettingsSecurityDialog/utils.js +0 -105
  395. package/dist/src/components/Markdown.js +0 -217
  396. package/dist/src/components/MarkdownTable.js +0 -279
  397. package/dist/src/components/MemoryUsageIndicator.js +0 -27
  398. package/dist/src/components/Message.js +0 -566
  399. package/dist/src/components/MessageModel.js +0 -36
  400. package/dist/src/components/MessageResponse.js +0 -73
  401. package/dist/src/components/MessageRow.js +0 -346
  402. package/dist/src/components/MessageSelector.js +0 -743
  403. package/dist/src/components/MessageTimestamp.js +0 -57
  404. package/dist/src/components/Messages.js +0 -637
  405. package/dist/src/components/ModelPicker.js +0 -484
  406. package/dist/src/components/NativeAutoUpdater.js +0 -153
  407. package/dist/src/components/NotebookEditToolUseRejectedMessage.js +0 -83
  408. package/dist/src/components/OffscreenFreeze.js +0 -35
  409. package/dist/src/components/Onboarding.js +0 -174
  410. package/dist/src/components/OutputStylePicker.js +0 -102
  411. package/dist/src/components/PackageManagerAutoUpdater.js +0 -100
  412. package/dist/src/components/Passes/Passes.js +0 -113
  413. package/dist/src/components/PrBadge.js +0 -90
  414. package/dist/src/components/PressEnterToContinue.js +0 -15
  415. package/dist/src/components/PromptInput/HistorySearchInput.js +0 -44
  416. package/dist/src/components/PromptInput/IssueFlagBanner.js +0 -8
  417. package/dist/src/components/PromptInput/Notifications.js +0 -221
  418. package/dist/src/components/PromptInput/PromptInput.js +0 -1998
  419. package/dist/src/components/PromptInput/PromptInputFooter.js +0 -84
  420. package/dist/src/components/PromptInput/PromptInputFooterLeftSide.js +0 -409
  421. package/dist/src/components/PromptInput/PromptInputFooterSuggestions.js +0 -280
  422. package/dist/src/components/PromptInput/PromptInputHelpMenu.js +0 -379
  423. package/dist/src/components/PromptInput/PromptInputModeIndicator.js +0 -72
  424. package/dist/src/components/PromptInput/PromptInputQueuedCommands.js +0 -105
  425. package/dist/src/components/PromptInput/PromptInputStashNotice.js +0 -20
  426. package/dist/src/components/PromptInput/SandboxPromptFooterHint.js +0 -65
  427. package/dist/src/components/PromptInput/ShimmeredInput.js +0 -132
  428. package/dist/src/components/PromptInput/VoiceIndicator.js +0 -136
  429. package/dist/src/components/PromptInput/inputModes.js +0 -24
  430. package/dist/src/components/PromptInput/inputPaste.js +0 -62
  431. package/dist/src/components/PromptInput/useMaybeTruncateInput.js +0 -33
  432. package/dist/src/components/PromptInput/usePromptInputPlaceholder.js +0 -55
  433. package/dist/src/components/PromptInput/useShowFastIconHint.js +0 -23
  434. package/dist/src/components/PromptInput/useSwarmBanner.js +0 -112
  435. package/dist/src/components/PromptInput/utils.js +0 -50
  436. package/dist/src/components/QuickOpenDialog.js +0 -243
  437. package/dist/src/components/RemoteCallout.js +0 -53
  438. package/dist/src/components/RemoteEnvironmentDialog.js +0 -345
  439. package/dist/src/components/ResumeTask.js +0 -173
  440. package/dist/src/components/SandboxViolationExpandedView.js +0 -102
  441. package/dist/src/components/ScrollKeybindingHandler.js +0 -982
  442. package/dist/src/components/SearchBox.js +0 -55
  443. package/dist/src/components/SentryErrorBoundary.js +0 -16
  444. package/dist/src/components/SessionBackgroundHint.js +0 -104
  445. package/dist/src/components/SessionPreview.js +0 -200
  446. package/dist/src/components/Settings/Config.js +0 -1628
  447. package/dist/src/components/Settings/Settings.js +0 -129
  448. package/dist/src/components/Settings/Status.js +0 -230
  449. package/dist/src/components/Settings/Usage.js +0 -341
  450. package/dist/src/components/ShowInIDEPrompt.js +0 -151
  451. package/dist/src/components/SkillImprovementSurvey.js +0 -130
  452. package/dist/src/components/Spinner/FlashingChar.js +0 -51
  453. package/dist/src/components/Spinner/GlimmerMessage.js +0 -328
  454. package/dist/src/components/Spinner/ShimmerChar.js +0 -22
  455. package/dist/src/components/Spinner/SpinnerAnimationRow.js +0 -169
  456. package/dist/src/components/Spinner/SpinnerGlyph.js +0 -69
  457. package/dist/src/components/Spinner/TeammateSpinnerLine.js +0 -170
  458. package/dist/src/components/Spinner/TeammateSpinnerTree.js +0 -268
  459. package/dist/src/components/Spinner/index.js +0 -11
  460. package/dist/src/components/Spinner/teammateSelectHint.js +0 -1
  461. package/dist/src/components/Spinner/useShimmerAnimation.js +0 -22
  462. package/dist/src/components/Spinner/useStalledAnimation.js +0 -63
  463. package/dist/src/components/Spinner/utils.js +0 -77
  464. package/dist/src/components/Spinner.js +0 -470
  465. package/dist/src/components/Stats.js +0 -1000
  466. package/dist/src/components/StatusLine.js +0 -285
  467. package/dist/src/components/StatusNotices.js +0 -50
  468. package/dist/src/components/StructuredDiff/Fallback.js +0 -335
  469. package/dist/src/components/StructuredDiff/colorDiff.js +0 -26
  470. package/dist/src/components/StructuredDiff.js +0 -152
  471. package/dist/src/components/StructuredDiffList.js +0 -8
  472. package/dist/src/components/TagTabs.js +0 -100
  473. package/dist/src/components/TaskListV2.js +0 -333
  474. package/dist/src/components/TeammateViewHeader.js +0 -87
  475. package/dist/src/components/TeleportError.js +0 -191
  476. package/dist/src/components/TeleportProgress.js +0 -130
  477. package/dist/src/components/TeleportRepoMismatchDialog.js +0 -98
  478. package/dist/src/components/TeleportResumeWrapper.js +0 -158
  479. package/dist/src/components/TeleportStash.js +0 -82
  480. package/dist/src/components/TextInput.js +0 -108
  481. package/dist/src/components/ThemePicker.js +0 -330
  482. package/dist/src/components/ThinkingToggle.js +0 -153
  483. package/dist/src/components/TokenWarning.js +0 -172
  484. package/dist/src/components/ToolUseLoader.js +0 -34
  485. package/dist/src/components/TrustDialog/TrustDialog.js +0 -301
  486. package/dist/src/components/TrustDialog/utils.js +0 -199
  487. package/dist/src/components/ValidationErrorsList.js +0 -146
  488. package/dist/src/components/VimTextInput.js +0 -136
  489. package/dist/src/components/VirtualMessageList.js +0 -892
  490. package/dist/src/components/WorkflowMultiselectDialog.js +0 -118
  491. package/dist/src/components/WorktreeExitDialog.js +0 -222
  492. package/dist/src/components/agents/AgentDetail.js +0 -226
  493. package/dist/src/components/agents/AgentEditor.js +0 -146
  494. package/dist/src/components/agents/AgentNavigationFooter.js +0 -21
  495. package/dist/src/components/agents/AgentsList.js +0 -436
  496. package/dist/src/components/agents/AgentsMenu.js +0 -848
  497. package/dist/src/components/agents/ColorPicker.js +0 -110
  498. package/dist/src/components/agents/ModelSelector.js +0 -62
  499. package/dist/src/components/agents/SnapshotUpdateDialog.js +0 -16
  500. package/dist/src/components/agents/ToolSelector.js +0 -557
  501. package/dist/src/components/agents/agentFileUtils.js +0 -179
  502. package/dist/src/components/agents/generateAgent.js +0 -161
  503. package/dist/src/components/agents/new-agent-creation/CreateAgentWizard.js +0 -88
  504. package/dist/src/components/agents/new-agent-creation/wizard-steps/ColorStep.js +0 -80
  505. package/dist/src/components/agents/new-agent-creation/wizard-steps/ConfirmStep.js +0 -386
  506. package/dist/src/components/agents/new-agent-creation/wizard-steps/ConfirmStepWrapper.js +0 -63
  507. package/dist/src/components/agents/new-agent-creation/wizard-steps/DescriptionStep.js +0 -126
  508. package/dist/src/components/agents/new-agent-creation/wizard-steps/GenerateStep.js +0 -118
  509. package/dist/src/components/agents/new-agent-creation/wizard-steps/LocationStep.js +0 -79
  510. package/dist/src/components/agents/new-agent-creation/wizard-steps/MemoryStep.js +0 -107
  511. package/dist/src/components/agents/new-agent-creation/wizard-steps/MethodStep.js +0 -79
  512. package/dist/src/components/agents/new-agent-creation/wizard-steps/ModelStep.js +0 -48
  513. package/dist/src/components/agents/new-agent-creation/wizard-steps/PromptStep.js +0 -131
  514. package/dist/src/components/agents/new-agent-creation/wizard-steps/ToolsStep.js +0 -51
  515. package/dist/src/components/agents/new-agent-creation/wizard-steps/TypeStep.js +0 -100
  516. package/dist/src/components/agents/types.js +0 -4
  517. package/dist/src/components/agents/utils.js +0 -14
  518. package/dist/src/components/agents/validateAgent.js +0 -79
  519. package/dist/src/components/design-system/Byline.js +0 -72
  520. package/dist/src/components/design-system/Dialog.js +0 -116
  521. package/dist/src/components/design-system/Divider.js +0 -109
  522. package/dist/src/components/design-system/FuzzyPicker.js +0 -187
  523. package/dist/src/components/design-system/KeyboardShortcutHint.js +0 -67
  524. package/dist/src/components/design-system/ListItem.js +0 -183
  525. package/dist/src/components/design-system/LoadingState.js +0 -68
  526. package/dist/src/components/design-system/Pane.js +0 -68
  527. package/dist/src/components/design-system/ProgressBar.js +0 -62
  528. package/dist/src/components/design-system/Ratchet.js +0 -71
  529. package/dist/src/components/design-system/StatusIcon.js +0 -69
  530. package/dist/src/components/design-system/Tabs.js +0 -269
  531. package/dist/src/components/design-system/ThemeProvider.js +0 -137
  532. package/dist/src/components/design-system/ThemedBox.js +0 -125
  533. package/dist/src/components/design-system/ThemedText.js +0 -60
  534. package/dist/src/components/design-system/color.js +0 -22
  535. package/dist/src/components/diff/DiffDetailView.js +0 -284
  536. package/dist/src/components/diff/DiffDialog.js +0 -387
  537. package/dist/src/components/diff/DiffFileList.js +0 -291
  538. package/dist/src/components/grove/Grove.js +0 -483
  539. package/dist/src/components/hooks/HooksConfigMenu.js +0 -570
  540. package/dist/src/components/hooks/PromptDialog.js +0 -81
  541. package/dist/src/components/hooks/SelectEventMode.js +0 -117
  542. package/dist/src/components/hooks/SelectHookMode.js +0 -93
  543. package/dist/src/components/hooks/SelectMatcherMode.js +0 -124
  544. package/dist/src/components/hooks/ViewHookMode.js +0 -197
  545. package/dist/src/components/mcp/CapabilitiesSection.js +0 -55
  546. package/dist/src/components/mcp/ElicitationDialog.js +0 -945
  547. package/dist/src/components/mcp/MCPAgentServerMenu.js +0 -95
  548. package/dist/src/components/mcp/MCPListPanel.js +0 -504
  549. package/dist/src/components/mcp/MCPReconnect.js +0 -168
  550. package/dist/src/components/mcp/MCPRemoteServerMenu.js +0 -460
  551. package/dist/src/components/mcp/MCPSettings.js +0 -414
  552. package/dist/src/components/mcp/MCPStdioServerMenu.js +0 -95
  553. package/dist/src/components/mcp/MCPToolDetailView.js +0 -219
  554. package/dist/src/components/mcp/MCPToolListView.js +0 -136
  555. package/dist/src/components/mcp/McpParsingWarnings.js +0 -211
  556. package/dist/src/components/mcp/index.js +0 -8
  557. package/dist/src/components/mcp/types.js +0 -3
  558. package/dist/src/components/mcp/utils/reconnectHelpers.js +0 -35
  559. package/dist/src/components/memory/MemoryFileSelector.js +0 -455
  560. package/dist/src/components/memory/MemoryUpdateNotification.js +0 -42
  561. package/dist/src/components/messageActions.js +0 -418
  562. package/dist/src/components/messages/AdvisorMessage.js +0 -151
  563. package/dist/src/components/messages/AssistantRedactedThinkingMessage.js +0 -27
  564. package/dist/src/components/messages/AssistantTextMessage.js +0 -274
  565. package/dist/src/components/messages/AssistantThinkingMessage.js +0 -69
  566. package/dist/src/components/messages/AssistantToolUseMessage.js +0 -323
  567. package/dist/src/components/messages/AttachmentMessage.js +0 -418
  568. package/dist/src/components/messages/CollapsedReadSearchContent.js +0 -362
  569. package/dist/src/components/messages/CompactBoundaryMessage.js +0 -18
  570. package/dist/src/components/messages/GroupedToolUseContent.js +0 -37
  571. package/dist/src/components/messages/HighlightedThinkingText.js +0 -164
  572. package/dist/src/components/messages/HookProgressMessage.js +0 -110
  573. package/dist/src/components/messages/PlanApprovalMessage.js +0 -212
  574. package/dist/src/components/messages/RateLimitMessage.js +0 -149
  575. package/dist/src/components/messages/ShutdownMessage.js +0 -123
  576. package/dist/src/components/messages/SystemAPIErrorMessage.js +0 -135
  577. package/dist/src/components/messages/SystemTextMessage.js +0 -843
  578. package/dist/src/components/messages/TaskAssignmentMessage.js +0 -71
  579. package/dist/src/components/messages/UserAgentNotificationMessage.js +0 -77
  580. package/dist/src/components/messages/UserBashInputMessage.js +0 -51
  581. package/dist/src/components/messages/UserBashOutputMessage.js +0 -54
  582. package/dist/src/components/messages/UserChannelMessage.js +0 -129
  583. package/dist/src/components/messages/UserCommandMessage.js +0 -106
  584. package/dist/src/components/messages/UserImageMessage.js +0 -53
  585. package/dist/src/components/messages/UserLocalCommandOutputMessage.js +0 -169
  586. package/dist/src/components/messages/UserMemoryInputMessage.js +0 -72
  587. package/dist/src/components/messages/UserPlanMessage.js +0 -37
  588. package/dist/src/components/messages/UserPromptMessage.js +0 -63
  589. package/dist/src/components/messages/UserResourceUpdateMessage.js +0 -101
  590. package/dist/src/components/messages/UserTeammateMessage.js +0 -156
  591. package/dist/src/components/messages/UserTextMessage.js +0 -271
  592. package/dist/src/components/messages/UserToolResultMessage/RejectedPlanMessage.js +0 -27
  593. package/dist/src/components/messages/UserToolResultMessage/RejectedToolUseMessage.js +0 -16
  594. package/dist/src/components/messages/UserToolResultMessage/UserToolCanceledMessage.js +0 -16
  595. package/dist/src/components/messages/UserToolResultMessage/UserToolErrorMessage.js +0 -91
  596. package/dist/src/components/messages/UserToolResultMessage/UserToolRejectMessage.js +0 -73
  597. package/dist/src/components/messages/UserToolResultMessage/UserToolResultMessage.js +0 -83
  598. package/dist/src/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +0 -58
  599. package/dist/src/components/messages/UserToolResultMessage/utils.js +0 -43
  600. package/dist/src/components/messages/nullRenderingAttachments.js +0 -58
  601. package/dist/src/components/messages/teamMemCollapsed.js +0 -142
  602. package/dist/src/components/messages/teamMemSaved.js +0 -17
  603. package/dist/src/components/permissions/AskUserQuestionPermissionRequest/AskUserQuestionPermissionRequest.js +0 -654
  604. package/dist/src/components/permissions/AskUserQuestionPermissionRequest/PreviewBox.js +0 -219
  605. package/dist/src/components/permissions/AskUserQuestionPermissionRequest/PreviewQuestionView.js +0 -227
  606. package/dist/src/components/permissions/AskUserQuestionPermissionRequest/QuestionNavigationBar.js +0 -174
  607. package/dist/src/components/permissions/AskUserQuestionPermissionRequest/QuestionView.js +0 -444
  608. package/dist/src/components/permissions/AskUserQuestionPermissionRequest/SubmitQuestionsView.js +0 -136
  609. package/dist/src/components/permissions/AskUserQuestionPermissionRequest/use-multiple-choice-state.js +0 -100
  610. package/dist/src/components/permissions/BashPermissionRequest/BashPermissionRequest.js +0 -404
  611. package/dist/src/components/permissions/BashPermissionRequest/bashToolUseOptions.js +0 -110
  612. package/dist/src/components/permissions/ComputerUseApproval/ComputerUseApproval.js +0 -448
  613. package/dist/src/components/permissions/EnterPlanModePermissionRequest/EnterPlanModePermissionRequest.js +0 -125
  614. package/dist/src/components/permissions/ExitPlanModePermissionRequest/ExitPlanModePermissionRequest.js +0 -650
  615. package/dist/src/components/permissions/FallbackPermissionRequest.js +0 -348
  616. package/dist/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.js +0 -184
  617. package/dist/src/components/permissions/FilePermissionDialog/FilePermissionDialog.js +0 -108
  618. package/dist/src/components/permissions/FilePermissionDialog/ideDiffConfig.js +0 -13
  619. package/dist/src/components/permissions/FilePermissionDialog/permissionOptions.js +0 -136
  620. package/dist/src/components/permissions/FilePermissionDialog/useFilePermissionDialog.js +0 -131
  621. package/dist/src/components/permissions/FilePermissionDialog/usePermissionHandler.js +0 -86
  622. package/dist/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.js +0 -163
  623. package/dist/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.js +0 -78
  624. package/dist/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js +0 -112
  625. package/dist/src/components/permissions/NotebookEditPermissionRequest/NotebookEditPermissionRequest.js +0 -163
  626. package/dist/src/components/permissions/NotebookEditPermissionRequest/NotebookEditToolDiff.js +0 -217
  627. package/dist/src/components/permissions/PermissionDecisionDebugInfo.js +0 -466
  628. package/dist/src/components/permissions/PermissionDialog.js +0 -54
  629. package/dist/src/components/permissions/PermissionExplanation.js +0 -269
  630. package/dist/src/components/permissions/PermissionPrompt.js +0 -316
  631. package/dist/src/components/permissions/PermissionRequest.js +0 -160
  632. package/dist/src/components/permissions/PermissionRequestTitle.js +0 -57
  633. package/dist/src/components/permissions/PermissionRuleExplanation.js +0 -109
  634. package/dist/src/components/permissions/PowerShellPermissionRequest/PowerShellPermissionRequest.js +0 -178
  635. package/dist/src/components/permissions/PowerShellPermissionRequest/powershellToolUseOptions.js +0 -73
  636. package/dist/src/components/permissions/SandboxPermissionRequest.js +0 -161
  637. package/dist/src/components/permissions/SedEditPermissionRequest/SedEditPermissionRequest.js +0 -228
  638. package/dist/src/components/permissions/SkillPermissionRequest/SkillPermissionRequest.js +0 -384
  639. package/dist/src/components/permissions/WebFetchPermissionRequest/WebFetchPermissionRequest.js +0 -258
  640. package/dist/src/components/permissions/WorkerBadge.js +0 -43
  641. package/dist/src/components/permissions/WorkerPendingPermission.js +0 -106
  642. package/dist/src/components/permissions/hooks.js +0 -163
  643. package/dist/src/components/permissions/rules/AddPermissionRules.js +0 -170
  644. package/dist/src/components/permissions/rules/AddWorkspaceDirectory.js +0 -334
  645. package/dist/src/components/permissions/rules/PermissionRuleDescription.js +0 -77
  646. package/dist/src/components/permissions/rules/PermissionRuleInput.js +0 -135
  647. package/dist/src/components/permissions/rules/PermissionRuleList.js +0 -1189
  648. package/dist/src/components/permissions/rules/RecentDenialsTab.js +0 -204
  649. package/dist/src/components/permissions/rules/RemoveWorkspaceDirectory.js +0 -102
  650. package/dist/src/components/permissions/rules/WorkspaceTab.js +0 -132
  651. package/dist/src/components/permissions/shellPermissionHelpers.js +0 -111
  652. package/dist/src/components/permissions/useShellPermissionFeedback.js +0 -108
  653. package/dist/src/components/permissions/utils.js +0 -14
  654. package/dist/src/components/sandbox/SandboxConfigTab.js +0 -47
  655. package/dist/src/components/sandbox/SandboxDependenciesTab.js +0 -122
  656. package/dist/src/components/sandbox/SandboxDoctorSection.js +0 -46
  657. package/dist/src/components/sandbox/SandboxOverridesTab.js +0 -192
  658. package/dist/src/components/sandbox/SandboxSettings.js +0 -296
  659. package/dist/src/components/shell/ExpandShellOutputContext.js +0 -33
  660. package/dist/src/components/shell/OutputLine.js +0 -110
  661. package/dist/src/components/shell/ShellProgressMessage.js +0 -143
  662. package/dist/src/components/shell/ShellTimeDisplay.js +0 -71
  663. package/dist/src/components/skills/SkillsMenu.js +0 -238
  664. package/dist/src/components/tasks/AsyncAgentDetailDialog.js +0 -234
  665. package/dist/src/components/tasks/BackgroundTask.js +0 -363
  666. package/dist/src/components/tasks/BackgroundTaskStatus.js +0 -419
  667. package/dist/src/components/tasks/BackgroundTasksDialog.js +0 -496
  668. package/dist/src/components/tasks/DreamDetailDialog.js +0 -250
  669. package/dist/src/components/tasks/InProcessTeammateDetailDialog.js +0 -274
  670. package/dist/src/components/tasks/RemoteSessionDetailDialog.js +0 -868
  671. package/dist/src/components/tasks/RemoteSessionProgress.js +0 -249
  672. package/dist/src/components/tasks/ShellDetailDialog.js +0 -403
  673. package/dist/src/components/tasks/ShellProgress.js +0 -76
  674. package/dist/src/components/tasks/renderToolActivity.js +0 -28
  675. package/dist/src/components/tasks/taskStatusUtils.js +0 -94
  676. package/dist/src/components/teams/TeamStatus.js +0 -76
  677. package/dist/src/components/teams/TeamsDialog.js +0 -672
  678. package/dist/src/components/ui/OrderedList.js +0 -66
  679. package/dist/src/components/ui/OrderedListItem.js +0 -41
  680. package/dist/src/components/ui/TreeSelect.js +0 -300
  681. package/dist/src/components/wizard/WizardDialogLayout.js +0 -47
  682. package/dist/src/components/wizard/WizardNavigationFooter.js +0 -10
  683. package/dist/src/components/wizard/WizardProvider.js +0 -217
  684. package/dist/src/components/wizard/index.js +0 -4
  685. package/dist/src/components/wizard/useWizard.js +0 -9
  686. package/dist/src/constants/apiLimits.js +0 -81
  687. package/dist/src/constants/betas.js +0 -45
  688. package/dist/src/constants/common.js +0 -29
  689. package/dist/src/constants/cyberRiskInstruction.js +0 -24
  690. package/dist/src/constants/errorIds.js +0 -14
  691. package/dist/src/constants/figures.js +0 -38
  692. package/dist/src/constants/files.js +0 -150
  693. package/dist/src/constants/github-app.js +0 -139
  694. package/dist/src/constants/keys.js +0 -10
  695. package/dist/src/constants/messages.js +0 -1
  696. package/dist/src/constants/oauth.js +0 -221
  697. package/dist/src/constants/outputStyles.js +0 -162
  698. package/dist/src/constants/product.js +0 -56
  699. package/dist/src/constants/prompts.js +0 -752
  700. package/dist/src/constants/spinnerVerbs.js +0 -202
  701. package/dist/src/constants/system.js +0 -77
  702. package/dist/src/constants/systemPromptSections.js +0 -39
  703. package/dist/src/constants/toolLimits.js +0 -50
  704. package/dist/src/constants/tools.js +0 -103
  705. package/dist/src/constants/turnCompletionVerbs.js +0 -12
  706. package/dist/src/constants/xml.js +0 -73
  707. package/dist/src/context/QueuedMessageContext.js +0 -51
  708. package/dist/src/context/fpsMetrics.js +0 -22
  709. package/dist/src/context/mailbox.js +0 -35
  710. package/dist/src/context/modalContext.js +0 -34
  711. package/dist/src/context/notifications.js +0 -199
  712. package/dist/src/context/overlayContext.js +0 -149
  713. package/dist/src/context/promptOverlayContext.js +0 -118
  714. package/dist/src/context/stats.js +0 -207
  715. package/dist/src/context/voice.js +0 -74
  716. package/dist/src/context.js +0 -146
  717. package/dist/src/coordinator/coordinatorMode.js +0 -345
  718. package/dist/src/cost-tracker.js +0 -208
  719. package/dist/src/costHook.js +0 -17
  720. package/dist/src/daemon/main.js +0 -16
  721. package/dist/src/daemon/workerRegistry.js +0 -16
  722. package/dist/src/dialogLaunchers.js +0 -68
  723. package/dist/src/entrypoints/agentSdkTypes.js +0 -202
  724. package/dist/src/entrypoints/cli.js +0 -237
  725. package/dist/src/entrypoints/init.js +0 -265
  726. package/dist/src/entrypoints/mcp.js +0 -142
  727. package/dist/src/entrypoints/sandboxTypes.js +0 -112
  728. package/dist/src/entrypoints/sdk/controlSchemas.js +0 -452
  729. package/dist/src/entrypoints/sdk/controlTypes.js +0 -1
  730. package/dist/src/entrypoints/sdk/coreSchemas.js +0 -1331
  731. package/dist/src/entrypoints/sdk/coreTypes.generated.js +0 -1
  732. package/dist/src/entrypoints/sdk/coreTypes.js +0 -49
  733. package/dist/src/entrypoints/sdk/runtimeTypes.js +0 -1
  734. package/dist/src/entrypoints/sdk/toolTypes.js +0 -1
  735. package/dist/src/environment-runner/main.js +0 -16
  736. package/dist/src/history.js +0 -386
  737. package/dist/src/hooks/fileSuggestions.js +0 -635
  738. package/dist/src/hooks/notifs/useAutoModeUnavailableNotification.js +0 -47
  739. package/dist/src/hooks/notifs/useCanSwitchToExistingSubscription.js +0 -57
  740. package/dist/src/hooks/notifs/useDeprecationWarningNotification.js +0 -43
  741. package/dist/src/hooks/notifs/useFastModeNotification.js +0 -164
  742. package/dist/src/hooks/notifs/useIDEStatusIndicator.js +0 -174
  743. package/dist/src/hooks/notifs/useInstallMessages.js +0 -27
  744. package/dist/src/hooks/notifs/useLspInitializationNotification.js +0 -144
  745. package/dist/src/hooks/notifs/useMcpConnectivityStatus.js +0 -80
  746. package/dist/src/hooks/notifs/useModelMigrationNotifications.js +0 -53
  747. package/dist/src/hooks/notifs/useNpmDeprecationNotification.js +0 -24
  748. package/dist/src/hooks/notifs/usePluginAutoupdateNotification.js +0 -82
  749. package/dist/src/hooks/notifs/usePluginInstallationStatus.js +0 -127
  750. package/dist/src/hooks/notifs/useRateLimitWarningNotification.js +0 -118
  751. package/dist/src/hooks/notifs/useSettingsErrors.js +0 -64
  752. package/dist/src/hooks/notifs/useStartupNotification.js +0 -33
  753. package/dist/src/hooks/notifs/useTeammateShutdownNotification.js +0 -64
  754. package/dist/src/hooks/renderPlaceholder.js +0 -26
  755. package/dist/src/hooks/toolPermission/PermissionContext.js +0 -211
  756. package/dist/src/hooks/toolPermission/handlers/coordinatorHandler.js +0 -44
  757. package/dist/src/hooks/toolPermission/handlers/interactiveHandler.js +0 -397
  758. package/dist/src/hooks/toolPermission/handlers/swarmWorkerHandler.js +0 -108
  759. package/dist/src/hooks/toolPermission/permissionLogging.js +0 -145
  760. package/dist/src/hooks/unifiedSuggestions.js +0 -130
  761. package/dist/src/hooks/useAfterFirstRender.js +0 -12
  762. package/dist/src/hooks/useApiKeyVerification.js +0 -63
  763. package/dist/src/hooks/useArrowKeyHistory.js +0 -203
  764. package/dist/src/hooks/useAssistantHistory.js +0 -194
  765. package/dist/src/hooks/useAwaySummary.js +0 -105
  766. package/dist/src/hooks/useBackgroundTaskNavigation.js +0 -204
  767. package/dist/src/hooks/useBlink.js +0 -28
  768. package/dist/src/hooks/useCanUseTool.js +0 -192
  769. package/dist/src/hooks/useCancelRequest.js +0 -195
  770. package/dist/src/hooks/useChromeExtensionNotification.js +0 -49
  771. package/dist/src/hooks/useClaudeCodeHintRecommendation.js +0 -117
  772. package/dist/src/hooks/useClipboardImageHint.js +0 -59
  773. package/dist/src/hooks/useCommandKeybindings.js +0 -87
  774. package/dist/src/hooks/useCommandQueue.js +0 -10
  775. package/dist/src/hooks/useCopyOnSelect.js +0 -88
  776. package/dist/src/hooks/useDeferredHookMessages.js +0 -43
  777. package/dist/src/hooks/useDiffData.js +0 -69
  778. package/dist/src/hooks/useDiffInIDE.js +0 -252
  779. package/dist/src/hooks/useDirectConnect.js +0 -150
  780. package/dist/src/hooks/useDoublePress.js +0 -44
  781. package/dist/src/hooks/useDynamicConfig.js +0 -17
  782. package/dist/src/hooks/useElapsedTime.js +0 -25
  783. package/dist/src/hooks/useExitOnCtrlCD.js +0 -57
  784. package/dist/src/hooks/useExitOnCtrlCDWithKeybindings.js +0 -17
  785. package/dist/src/hooks/useFileHistorySnapshotInit.js +0 -14
  786. package/dist/src/hooks/useGlobalKeybindings.js +0 -215
  787. package/dist/src/hooks/useHistorySearch.js +0 -241
  788. package/dist/src/hooks/useIDEIntegration.js +0 -56
  789. package/dist/src/hooks/useIdeAtMentioned.js +0 -51
  790. package/dist/src/hooks/useIdeConnectionStatus.js +0 -21
  791. package/dist/src/hooks/useIdeLogging.js +0 -29
  792. package/dist/src/hooks/useIdeSelection.js +0 -106
  793. package/dist/src/hooks/useInboxPoller.js +0 -709
  794. package/dist/src/hooks/useInputBuffer.js +0 -73
  795. package/dist/src/hooks/useIssueFlagBanner.js +0 -115
  796. package/dist/src/hooks/useLogMessages.js +0 -98
  797. package/dist/src/hooks/useLspPluginRecommendation.js +0 -176
  798. package/dist/src/hooks/useMailboxBridge.js +0 -15
  799. package/dist/src/hooks/useMainLoopModel.js +0 -25
  800. package/dist/src/hooks/useManagePlugins.js +0 -261
  801. package/dist/src/hooks/useMemoryUsage.js +0 -28
  802. package/dist/src/hooks/useMergedClients.js +0 -11
  803. package/dist/src/hooks/useMergedCommands.js +0 -10
  804. package/dist/src/hooks/useMergedTools.js +0 -32
  805. package/dist/src/hooks/useMinDisplayTime.js +0 -26
  806. package/dist/src/hooks/useNotifyAfterTimeout.js +0 -51
  807. package/dist/src/hooks/useOfficialMarketplaceNotification.js +0 -46
  808. package/dist/src/hooks/usePasteHandler.js +0 -188
  809. package/dist/src/hooks/usePluginRecommendationBase.js +0 -101
  810. package/dist/src/hooks/usePrStatus.js +0 -91
  811. package/dist/src/hooks/usePromptSuggestion.js +0 -128
  812. package/dist/src/hooks/usePromptsFromClaudeInChrome.js +0 -66
  813. package/dist/src/hooks/useQueueProcessor.js +0 -46
  814. package/dist/src/hooks/useRemoteSession.js +0 -431
  815. package/dist/src/hooks/useReplBridge.js +0 -717
  816. package/dist/src/hooks/useSSHSession.js +0 -167
  817. package/dist/src/hooks/useScheduledTasks.js +0 -104
  818. package/dist/src/hooks/useSearchInput.js +0 -302
  819. package/dist/src/hooks/useSessionBackgrounding.js +0 -132
  820. package/dist/src/hooks/useSettings.js +0 -10
  821. package/dist/src/hooks/useSettingsChange.js +0 -13
  822. package/dist/src/hooks/useSkillImprovementSurvey.js +0 -69
  823. package/dist/src/hooks/useSkillsChange.js +0 -51
  824. package/dist/src/hooks/useSwarmInitialization.js +0 -67
  825. package/dist/src/hooks/useSwarmPermissionPoller.js +0 -215
  826. package/dist/src/hooks/useTaskListWatcher.js +0 -157
  827. package/dist/src/hooks/useTasksV2.js +0 -220
  828. package/dist/src/hooks/useTeammateViewAutoExit.js +0 -55
  829. package/dist/src/hooks/useTelegramMirror.js +0 -47
  830. package/dist/src/hooks/useTeleportResume.js +0 -81
  831. package/dist/src/hooks/useTerminalSize.js +0 -9
  832. package/dist/src/hooks/useTextInput.js +0 -397
  833. package/dist/src/hooks/useTimeout.js +0 -10
  834. package/dist/src/hooks/useTurnDiffs.js +0 -160
  835. package/dist/src/hooks/useTypeahead.js +0 -1392
  836. package/dist/src/hooks/useUpdateNotification.js +0 -22
  837. package/dist/src/hooks/useVimInput.js +0 -232
  838. package/dist/src/hooks/useVirtualScroll.js +0 -627
  839. package/dist/src/hooks/useVoice.js +0 -954
  840. package/dist/src/hooks/useVoiceEnabled.js +0 -21
  841. package/dist/src/hooks/useVoiceIntegration.js +0 -631
  842. package/dist/src/hooks/useWhatsAppMirror.js +0 -46
  843. package/dist/src/index.js +0 -18
  844. package/dist/src/ink/Ansi.js +0 -269
  845. package/dist/src/ink/bidi.js +0 -117
  846. package/dist/src/ink/clearTerminal.js +0 -58
  847. package/dist/src/ink/colorize.js +0 -198
  848. package/dist/src/ink/components/AlternateScreen.js +0 -74
  849. package/dist/src/ink/components/App.js +0 -558
  850. package/dist/src/ink/components/AppContext.js +0 -11
  851. package/dist/src/ink/components/Box.js +0 -153
  852. package/dist/src/ink/components/Button.js +0 -166
  853. package/dist/src/ink/components/ClockContext.js +0 -108
  854. package/dist/src/ink/components/CursorDeclarationContext.js +0 -3
  855. package/dist/src/ink/components/ErrorOverview.js +0 -49
  856. package/dist/src/ink/components/Link.js +0 -33
  857. package/dist/src/ink/components/Newline.js +0 -29
  858. package/dist/src/ink/components/NoSelect.js +0 -56
  859. package/dist/src/ink/components/RawAnsi.js +0 -45
  860. package/dist/src/ink/components/ScrollBox.js +0 -170
  861. package/dist/src/ink/components/Spacer.js +0 -19
  862. package/dist/src/ink/components/StdinContext.js +0 -16
  863. package/dist/src/ink/components/TerminalFocusContext.js +0 -45
  864. package/dist/src/ink/components/TerminalSizeContext.js +0 -3
  865. package/dist/src/ink/components/Text.js +0 -194
  866. package/dist/src/ink/constants.js +0 -2
  867. package/dist/src/ink/devtools.js +0 -16
  868. package/dist/src/ink/dom.js +0 -298
  869. package/dist/src/ink/events/click-event.js +0 -36
  870. package/dist/src/ink/events/dispatcher.js +0 -172
  871. package/dist/src/ink/events/emitter.js +0 -31
  872. package/dist/src/ink/events/event-handlers.js +0 -30
  873. package/dist/src/ink/events/event.js +0 -9
  874. package/dist/src/ink/events/focus-event.js +0 -16
  875. package/dist/src/ink/events/input-event.js +0 -161
  876. package/dist/src/ink/events/keyboard-event.js +0 -45
  877. package/dist/src/ink/events/terminal-event.js +0 -78
  878. package/dist/src/ink/events/terminal-focus-event.js +0 -15
  879. package/dist/src/ink/focus.js +0 -158
  880. package/dist/src/ink/frame.js +0 -30
  881. package/dist/src/ink/get-max-width.js +0 -23
  882. package/dist/src/ink/hit-test.js +0 -113
  883. package/dist/src/ink/hooks/use-animation-frame.js +0 -48
  884. package/dist/src/ink/hooks/use-app.js +0 -7
  885. package/dist/src/ink/hooks/use-declared-cursor.js +0 -60
  886. package/dist/src/ink/hooks/use-input.js +0 -70
  887. package/dist/src/ink/hooks/use-interval.js +0 -54
  888. package/dist/src/ink/hooks/use-search-highlight.js +0 -32
  889. package/dist/src/ink/hooks/use-selection.js +0 -60
  890. package/dist/src/ink/hooks/use-stdin.js +0 -7
  891. package/dist/src/ink/hooks/use-tab-status.js +0 -57
  892. package/dist/src/ink/hooks/use-terminal-focus.js +0 -15
  893. package/dist/src/ink/hooks/use-terminal-title.js +0 -29
  894. package/dist/src/ink/hooks/use-terminal-viewport.js +0 -77
  895. package/dist/src/ink/ink.js +0 -1644
  896. package/dist/src/ink/instances.js +0 -7
  897. package/dist/src/ink/layout/engine.js +0 -4
  898. package/dist/src/ink/layout/geometry.js +0 -61
  899. package/dist/src/ink/layout/node.js +0 -62
  900. package/dist/src/ink/layout/yoga.js +0 -237
  901. package/dist/src/ink/line-width-cache.js +0 -19
  902. package/dist/src/ink/log-update.js +0 -583
  903. package/dist/src/ink/measure-element.js +0 -8
  904. package/dist/src/ink/measure-text.js +0 -35
  905. package/dist/src/ink/node-cache.js +0 -30
  906. package/dist/src/ink/optimizer.js +0 -81
  907. package/dist/src/ink/output.js +0 -556
  908. package/dist/src/ink/parse-keypress.js +0 -695
  909. package/dist/src/ink/reconciler.js +0 -384
  910. package/dist/src/ink/render-border.js +0 -134
  911. package/dist/src/ink/render-node-to-output.js +0 -1216
  912. package/dist/src/ink/render-to-screen.js +0 -171
  913. package/dist/src/ink/renderer.js +0 -129
  914. package/dist/src/ink/root.js +0 -80
  915. package/dist/src/ink/screen.js +0 -1132
  916. package/dist/src/ink/searchHighlight.js +0 -78
  917. package/dist/src/ink/selection.js +0 -792
  918. package/dist/src/ink/squash-text-nodes.js +0 -56
  919. package/dist/src/ink/stringWidth.js +0 -200
  920. package/dist/src/ink/styles.js +0 -299
  921. package/dist/src/ink/supports-hyperlinks.js +0 -40
  922. package/dist/src/ink/tabstops.js +0 -39
  923. package/dist/src/ink/terminal-focus-state.js +0 -35
  924. package/dist/src/ink/terminal-querier.js +0 -173
  925. package/dist/src/ink/terminal.js +0 -208
  926. package/dist/src/ink/termio/ansi.js +0 -70
  927. package/dist/src/ink/termio/csi.js +0 -260
  928. package/dist/src/ink/termio/dec.js +0 -53
  929. package/dist/src/ink/termio/esc.js +0 -55
  930. package/dist/src/ink/termio/osc.js +0 -432
  931. package/dist/src/ink/termio/parser.js +0 -356
  932. package/dist/src/ink/termio/sgr.js +0 -292
  933. package/dist/src/ink/termio/tokenize.js +0 -264
  934. package/dist/src/ink/termio/types.js +0 -55
  935. package/dist/src/ink/termio.js +0 -24
  936. package/dist/src/ink/useTerminalNotification.js +0 -57
  937. package/dist/src/ink/warn.js +0 -10
  938. package/dist/src/ink/widest-line.js +0 -14
  939. package/dist/src/ink/wrap-text.js +0 -54
  940. package/dist/src/ink/wrapAnsi.js +0 -6
  941. package/dist/src/ink.js +0 -50
  942. package/dist/src/interactiveHelpers.js +0 -317
  943. package/dist/src/keybindings/KeybindingContext.js +0 -184
  944. package/dist/src/keybindings/KeybindingProviderSetup.js +0 -259
  945. package/dist/src/keybindings/defaultBindings.js +0 -333
  946. package/dist/src/keybindings/loadUserBindings.js +0 -393
  947. package/dist/src/keybindings/match.js +0 -111
  948. package/dist/src/keybindings/parser.js +0 -184
  949. package/dist/src/keybindings/reservedShortcuts.js +0 -109
  950. package/dist/src/keybindings/resolver.js +0 -182
  951. package/dist/src/keybindings/schema.js +0 -205
  952. package/dist/src/keybindings/shortcutFormat.js +0 -48
  953. package/dist/src/keybindings/template.js +0 -40
  954. package/dist/src/keybindings/useKeybinding.js +0 -161
  955. package/dist/src/keybindings/useShortcutDisplay.js +0 -43
  956. package/dist/src/keybindings/validate.js +0 -395
  957. package/dist/src/main.js +0 -4073
  958. package/dist/src/memdir/findRelevantMemories.js +0 -101
  959. package/dist/src/memdir/memdir.js +0 -408
  960. package/dist/src/memdir/memoryAge.js +0 -52
  961. package/dist/src/memdir/memoryScan.js +0 -65
  962. package/dist/src/memdir/memoryTypes.js +0 -260
  963. package/dist/src/memdir/paths.js +0 -236
  964. package/dist/src/memdir/teamMemPaths.js +0 -261
  965. package/dist/src/memdir/teamMemPrompts.js +0 -82
  966. package/dist/src/migrations/migrateAutoUpdatesToSettings.js +0 -47
  967. package/dist/src/migrations/migrateBypassPermissionsAcceptedToSettings.js +0 -32
  968. package/dist/src/migrations/migrateEnableAllProjectMcpServersToSettings.js +0 -83
  969. package/dist/src/migrations/migrateFennecToOpus.js +0 -39
  970. package/dist/src/migrations/migrateLegacyOpusToCurrent.js +0 -44
  971. package/dist/src/migrations/migrateOpusToOpus1m.js +0 -31
  972. package/dist/src/migrations/migrateReplBridgeEnabledToRemoteControlAtStartup.js +0 -23
  973. package/dist/src/migrations/migrateSonnet1mToSonnet45.js +0 -38
  974. package/dist/src/migrations/migrateSonnet45ToSonnet46.js +0 -48
  975. package/dist/src/migrations/resetAutoModeOptInForDefaultOffer.js +0 -47
  976. package/dist/src/migrations/resetProToOpusDefault.js +0 -46
  977. package/dist/src/mirrors/shared.js +0 -186
  978. package/dist/src/moreright/useMoreRight.js +0 -13
  979. package/dist/src/native-ts/color-diff/index.js +0 -821
  980. package/dist/src/native-ts/file-index/index.js +0 -328
  981. package/dist/src/native-ts/yoga-layout/enums.js +0 -101
  982. package/dist/src/native-ts/yoga-layout/index.js +0 -2113
  983. package/dist/src/outputStyles/loadOutputStylesDir.js +0 -71
  984. package/dist/src/plugins/builtinPlugins.js +0 -132
  985. package/dist/src/plugins/bundled/index.js +0 -22
  986. package/dist/src/projectOnboardingState.js +0 -61
  987. package/dist/src/query/config.js +0 -17
  988. package/dist/src/query/deps.js +0 -12
  989. package/dist/src/query/stopHooks.js +0 -334
  990. package/dist/src/query/tokenBudget.js +0 -49
  991. package/dist/src/query.js +0 -1330
  992. package/dist/src/recovery/bunBundleShim.js +0 -11
  993. package/dist/src/remote/RemoteSessionManager.js +0 -195
  994. package/dist/src/remote/SessionsWebSocket.js +0 -305
  995. package/dist/src/remote/remotePermissionBridge.js +0 -70
  996. package/dist/src/remote/sdkMessageAdapter.js +0 -227
  997. package/dist/src/replLauncher.js +0 -6
  998. package/dist/src/schemas/hooks.js +0 -174
  999. package/dist/src/screens/Doctor.js +0 -580
  1000. package/dist/src/screens/REPL.js +0 -4434
  1001. package/dist/src/screens/ResumeConversation.js +0 -341
  1002. package/dist/src/self-hosted-runner/main.js +0 -16
  1003. package/dist/src/server/backends/dangerousBackend.js +0 -16
  1004. package/dist/src/server/connectHeadless.js +0 -16
  1005. package/dist/src/server/createDirectConnectSession.js +0 -62
  1006. package/dist/src/server/directConnectManager.js +0 -153
  1007. package/dist/src/server/lockfile.js +0 -16
  1008. package/dist/src/server/parseConnectUrl.js +0 -16
  1009. package/dist/src/server/server.js +0 -16
  1010. package/dist/src/server/serverBanner.js +0 -16
  1011. package/dist/src/server/serverLog.js +0 -16
  1012. package/dist/src/server/sessionManager.js +0 -16
  1013. package/dist/src/server/types.js +0 -7
  1014. package/dist/src/services/AgentSummary/agentSummary.js +0 -147
  1015. package/dist/src/services/MagicDocs/magicDocs.js +0 -193
  1016. package/dist/src/services/MagicDocs/prompts.js +0 -110
  1017. package/dist/src/services/PromptSuggestion/promptSuggestion.js +0 -402
  1018. package/dist/src/services/PromptSuggestion/speculation.js +0 -643
  1019. package/dist/src/services/SessionMemory/prompts.js +0 -254
  1020. package/dist/src/services/SessionMemory/sessionMemory.js +0 -358
  1021. package/dist/src/services/SessionMemory/sessionMemoryUtils.js +0 -157
  1022. package/dist/src/services/analytics/config.js +0 -33
  1023. package/dist/src/services/analytics/datadog.js +0 -259
  1024. package/dist/src/services/analytics/firstPartyEventLogger.js +0 -342
  1025. package/dist/src/services/analytics/firstPartyEventLoggingExporter.js +0 -594
  1026. package/dist/src/services/analytics/growthbook.js +0 -952
  1027. package/dist/src/services/analytics/index.js +0 -114
  1028. package/dist/src/services/analytics/metadata.js +0 -698
  1029. package/dist/src/services/analytics/sink.js +0 -95
  1030. package/dist/src/services/analytics/sinkKillswitch.js +0 -19
  1031. package/dist/src/services/api/adminRequests.js +0 -57
  1032. package/dist/src/services/api/bootstrap.js +0 -149
  1033. package/dist/src/services/api/claude.js +0 -2461
  1034. package/dist/src/services/api/client.js +0 -325
  1035. package/dist/src/services/api/dumpPrompts.js +0 -174
  1036. package/dist/src/services/api/emptyUsage.js +0 -20
  1037. package/dist/src/services/api/errorUtils.js +0 -203
  1038. package/dist/src/services/api/errors.js +0 -934
  1039. package/dist/src/services/api/filesApi.js +0 -523
  1040. package/dist/src/services/api/firstTokenDate.js +0 -49
  1041. package/dist/src/services/api/grove.js +0 -272
  1042. package/dist/src/services/api/index.js +0 -23
  1043. package/dist/src/services/api/logging.js +0 -484
  1044. package/dist/src/services/api/metricsOptOut.js +0 -127
  1045. package/dist/src/services/api/openai.js +0 -1187
  1046. package/dist/src/services/api/openrouter.js +0 -30
  1047. package/dist/src/services/api/overageCreditGrant.js +0 -123
  1048. package/dist/src/services/api/promptCacheBreakDetection.js +0 -510
  1049. package/dist/src/services/api/referral.js +0 -219
  1050. package/dist/src/services/api/sessionIngress.js +0 -358
  1051. package/dist/src/services/api/ultrareviewQuota.js +0 -29
  1052. package/dist/src/services/api/usage.js +0 -31
  1053. package/dist/src/services/api/withRetry.js +0 -599
  1054. package/dist/src/services/autoDream/autoDream.js +0 -244
  1055. package/dist/src/services/autoDream/config.js +0 -17
  1056. package/dist/src/services/autoDream/consolidationLock.js +0 -122
  1057. package/dist/src/services/autoDream/consolidationPrompt.js +0 -56
  1058. package/dist/src/services/awaySummary.js +0 -61
  1059. package/dist/src/services/claudeAiLimits.js +0 -331
  1060. package/dist/src/services/claudeAiLimitsHook.js +0 -15
  1061. package/dist/src/services/compact/apiMicrocompact.js +0 -97
  1062. package/dist/src/services/compact/autoCompact.js +0 -236
  1063. package/dist/src/services/compact/cachedMicrocompact.js +0 -16
  1064. package/dist/src/services/compact/compact.js +0 -1258
  1065. package/dist/src/services/compact/compactWarningHook.js +0 -12
  1066. package/dist/src/services/compact/compactWarningState.js +0 -15
  1067. package/dist/src/services/compact/grouping.js +0 -58
  1068. package/dist/src/services/compact/microCompact.js +0 -414
  1069. package/dist/src/services/compact/postCompactCleanup.js +0 -72
  1070. package/dist/src/services/compact/prompt.js +0 -327
  1071. package/dist/src/services/compact/sessionMemoryCompact.js +0 -467
  1072. package/dist/src/services/compact/timeBasedMCConfig.js +0 -11
  1073. package/dist/src/services/diagnosticTracking.js +0 -282
  1074. package/dist/src/services/extractMemories/extractMemories.js +0 -444
  1075. package/dist/src/services/extractMemories/prompts.js +0 -129
  1076. package/dist/src/services/internalLogging.js +0 -68
  1077. package/dist/src/services/lsp/LSPClient.js +0 -306
  1078. package/dist/src/services/lsp/LSPDiagnosticRegistry.js +0 -277
  1079. package/dist/src/services/lsp/LSPServerInstance.js +0 -390
  1080. package/dist/src/services/lsp/LSPServerManager.js +0 -305
  1081. package/dist/src/services/lsp/config.js +0 -57
  1082. package/dist/src/services/lsp/manager.js +0 -246
  1083. package/dist/src/services/lsp/passiveFeedback.js +0 -226
  1084. package/dist/src/services/mcp/InProcessTransport.js +0 -54
  1085. package/dist/src/services/mcp/MCPConnectionManager.js +0 -50
  1086. package/dist/src/services/mcp/SdkControlTransport.js +0 -115
  1087. package/dist/src/services/mcp/auth.js +0 -1882
  1088. package/dist/src/services/mcp/channelAllowlist.js +0 -57
  1089. package/dist/src/services/mcp/channelNotification.js +0 -236
  1090. package/dist/src/services/mcp/channelPermissions.js +0 -192
  1091. package/dist/src/services/mcp/claudeai.js +0 -123
  1092. package/dist/src/services/mcp/client.js +0 -2480
  1093. package/dist/src/services/mcp/config.js +0 -1277
  1094. package/dist/src/services/mcp/elicitationHandler.js +0 -192
  1095. package/dist/src/services/mcp/envExpansion.js +0 -30
  1096. package/dist/src/services/mcp/headersHelper.js +0 -94
  1097. package/dist/src/services/mcp/mcpStringUtils.js +0 -85
  1098. package/dist/src/services/mcp/normalization.js +0 -21
  1099. package/dist/src/services/mcp/oauthPort.js +0 -69
  1100. package/dist/src/services/mcp/officialRegistry.js +0 -54
  1101. package/dist/src/services/mcp/types.js +0 -94
  1102. package/dist/src/services/mcp/useManageMCPConnections.js +0 -820
  1103. package/dist/src/services/mcp/utils.js +0 -433
  1104. package/dist/src/services/mcp/vscodeSdkMcp.js +0 -69
  1105. package/dist/src/services/mcp/xaa.js +0 -342
  1106. package/dist/src/services/mcp/xaaIdpLogin.js +0 -377
  1107. package/dist/src/services/mcpServerApproval.js +0 -29
  1108. package/dist/src/services/mockRateLimits.js +0 -666
  1109. package/dist/src/services/notifier.js +0 -114
  1110. package/dist/src/services/oauth/auth-code-listener.js +0 -236
  1111. package/dist/src/services/oauth/client.js +0 -545
  1112. package/dist/src/services/oauth/crypto.js +0 -19
  1113. package/dist/src/services/oauth/getOauthProfile.js +0 -48
  1114. package/dist/src/services/oauth/index.js +0 -152
  1115. package/dist/src/services/oauth/types.js +0 -1
  1116. package/dist/src/services/plugins/PluginInstallationManager.js +0 -139
  1117. package/dist/src/services/plugins/pluginCliCommands.js +0 -230
  1118. package/dist/src/services/plugins/pluginOperations.js +0 -826
  1119. package/dist/src/services/policyLimits/index.js +0 -547
  1120. package/dist/src/services/policyLimits/types.js +0 -9
  1121. package/dist/src/services/preventSleep.js +0 -143
  1122. package/dist/src/services/rateLimitMessages.js +0 -271
  1123. package/dist/src/services/rateLimitMocking.js +0 -91
  1124. package/dist/src/services/remoteManagedSettings/index.js +0 -534
  1125. package/dist/src/services/remoteManagedSettings/securityCheck.js +0 -59
  1126. package/dist/src/services/remoteManagedSettings/syncCache.js +0 -90
  1127. package/dist/src/services/remoteManagedSettings/syncCacheState.js +0 -89
  1128. package/dist/src/services/remoteManagedSettings/types.js +0 -12
  1129. package/dist/src/services/settingsSync/index.js +0 -478
  1130. package/dist/src/services/settingsSync/types.js +0 -35
  1131. package/dist/src/services/teamMemorySync/index.js +0 -976
  1132. package/dist/src/services/teamMemorySync/secretScanner.js +0 -275
  1133. package/dist/src/services/teamMemorySync/teamMemSecretGuard.js +0 -35
  1134. package/dist/src/services/teamMemorySync/types.js +0 -47
  1135. package/dist/src/services/teamMemorySync/watcher.js +0 -326
  1136. package/dist/src/services/tips/tipHistory.js +0 -17
  1137. package/dist/src/services/tips/tipRegistry.js +0 -589
  1138. package/dist/src/services/tips/tipScheduler.js +0 -40
  1139. package/dist/src/services/tokenEstimation.js +0 -365
  1140. package/dist/src/services/toolUseSummary/toolUseSummaryGenerator.js +0 -87
  1141. package/dist/src/services/tools/StreamingToolExecutor.js +0 -413
  1142. package/dist/src/services/tools/toolExecution.js +0 -1218
  1143. package/dist/src/services/tools/toolHooks.js +0 -454
  1144. package/dist/src/services/tools/toolOrchestration.js +0 -110
  1145. package/dist/src/services/vcr.js +0 -291
  1146. package/dist/src/services/voice.js +0 -394
  1147. package/dist/src/services/voiceKeyterms.js +0 -94
  1148. package/dist/src/services/voiceStreamSTT.js +0 -406
  1149. package/dist/src/setup.js +0 -349
  1150. package/dist/src/skills/bundled/batch.js +0 -114
  1151. package/dist/src/skills/bundled/claudeApi.js +0 -145
  1152. package/dist/src/skills/bundled/claudeApiContent.js +0 -14
  1153. package/dist/src/skills/bundled/claudeInChrome.js +0 -27
  1154. package/dist/src/skills/bundled/debug.js +0 -99
  1155. package/dist/src/skills/bundled/index.js +0 -5
  1156. package/dist/src/skills/bundled/keybindings.js +0 -292
  1157. package/dist/src/skills/bundled/loop.js +0 -81
  1158. package/dist/src/skills/bundled/loremIpsum.js +0 -266
  1159. package/dist/src/skills/bundled/remember.js +0 -75
  1160. package/dist/src/skills/bundled/scheduleRemoteAgents.js +0 -373
  1161. package/dist/src/skills/bundled/simplify.js +0 -66
  1162. package/dist/src/skills/bundled/skillify.js +0 -184
  1163. package/dist/src/skills/bundled/stuck.js +0 -75
  1164. package/dist/src/skills/bundled/updateConfig.js +0 -463
  1165. package/dist/src/skills/bundled/verify.js +0 -25
  1166. package/dist/src/skills/bundled/verifyContent.js +0 -7
  1167. package/dist/src/skills/bundledSkills.js +0 -159
  1168. package/dist/src/skills/loadSkillsDir.js +0 -736
  1169. package/dist/src/skills/mcpSkillBuilders.js +0 -10
  1170. package/dist/src/ssh/createSSHSession.js +0 -16
  1171. package/dist/src/state/AppState.js +0 -184
  1172. package/dist/src/state/AppStateStore.js +0 -119
  1173. package/dist/src/state/onChangeAppState.js +0 -132
  1174. package/dist/src/state/selectors.js +0 -51
  1175. package/dist/src/state/store.js +0 -21
  1176. package/dist/src/state/teammateViewHelpers.js +0 -124
  1177. package/dist/src/tasks/DreamTask/DreamTask.js +0 -99
  1178. package/dist/src/tasks/InProcessTeammateTask/InProcessTeammateTask.js +0 -116
  1179. package/dist/src/tasks/InProcessTeammateTask/types.js +0 -35
  1180. package/dist/src/tasks/LocalAgentTask/LocalAgentTask.js +0 -507
  1181. package/dist/src/tasks/LocalMainSessionTask.js +0 -338
  1182. package/dist/src/tasks/LocalShellTask/LocalShellTask.js +0 -475
  1183. package/dist/src/tasks/LocalShellTask/guards.js +0 -9
  1184. package/dist/src/tasks/LocalShellTask/killShellTasks.js +0 -59
  1185. package/dist/src/tasks/RemoteAgentTask/RemoteAgentTask.js +0 -742
  1186. package/dist/src/tasks/pillLabel.js +0 -69
  1187. package/dist/src/tasks/stopTask.js +0 -67
  1188. package/dist/src/tasks/types.js +0 -18
  1189. package/dist/src/tasks.js +0 -39
  1190. package/dist/src/telegram/bridge.js +0 -334
  1191. package/dist/src/telegram/config.js +0 -57
  1192. package/dist/src/telegram/mirror.js +0 -91
  1193. package/dist/src/tools/AgentTool/AgentTool.js +0 -1222
  1194. package/dist/src/tools/AgentTool/UI.js +0 -592
  1195. package/dist/src/tools/AgentTool/agentColorManager.js +0 -43
  1196. package/dist/src/tools/AgentTool/agentDisplay.js +0 -72
  1197. package/dist/src/tools/AgentTool/agentMemory.js +0 -125
  1198. package/dist/src/tools/AgentTool/agentMemorySnapshot.js +0 -136
  1199. package/dist/src/tools/AgentTool/agentToolUtils.js +0 -456
  1200. package/dist/src/tools/AgentTool/built-in/claudeCodeGuideAgent.js +0 -175
  1201. package/dist/src/tools/AgentTool/built-in/exploreAgent.js +0 -76
  1202. package/dist/src/tools/AgentTool/built-in/generalPurposeAgent.js +0 -28
  1203. package/dist/src/tools/AgentTool/built-in/planAgent.js +0 -87
  1204. package/dist/src/tools/AgentTool/built-in/statuslineSetup.js +0 -140
  1205. package/dist/src/tools/AgentTool/built-in/verificationAgent.js +0 -146
  1206. package/dist/src/tools/AgentTool/builtInAgents.js +0 -58
  1207. package/dist/src/tools/AgentTool/constants.js +0 -11
  1208. package/dist/src/tools/AgentTool/forkSubagent.js +0 -177
  1209. package/dist/src/tools/AgentTool/loadAgentsDir.js +0 -497
  1210. package/dist/src/tools/AgentTool/prompt.js +0 -260
  1211. package/dist/src/tools/AgentTool/resumeAgent.js +0 -182
  1212. package/dist/src/tools/AgentTool/runAgent.js +0 -629
  1213. package/dist/src/tools/AskUserQuestionTool/AskUserQuestionTool.js +0 -237
  1214. package/dist/src/tools/AskUserQuestionTool/prompt.js +0 -38
  1215. package/dist/src/tools/BashTool/BashTool.js +0 -1008
  1216. package/dist/src/tools/BashTool/BashToolResultMessage.js +0 -168
  1217. package/dist/src/tools/BashTool/UI.js +0 -133
  1218. package/dist/src/tools/BashTool/bashCommandHelpers.js +0 -184
  1219. package/dist/src/tools/BashTool/bashPermissions.js +0 -2023
  1220. package/dist/src/tools/BashTool/bashSecurity.js +0 -2267
  1221. package/dist/src/tools/BashTool/commandSemantics.js +0 -105
  1222. package/dist/src/tools/BashTool/commentLabel.js +0 -14
  1223. package/dist/src/tools/BashTool/destructiveCommandWarning.js +0 -88
  1224. package/dist/src/tools/BashTool/modeValidation.js +0 -86
  1225. package/dist/src/tools/BashTool/pathValidation.js +0 -1080
  1226. package/dist/src/tools/BashTool/prompt.js +0 -333
  1227. package/dist/src/tools/BashTool/readOnlyValidation.js +0 -1794
  1228. package/dist/src/tools/BashTool/sedEditParser.js +0 -282
  1229. package/dist/src/tools/BashTool/sedValidation.js +0 -580
  1230. package/dist/src/tools/BashTool/shouldUseSandbox.js +0 -125
  1231. package/dist/src/tools/BashTool/toolName.js +0 -2
  1232. package/dist/src/tools/BashTool/utils.js +0 -180
  1233. package/dist/src/tools/BriefTool/BriefTool.js +0 -172
  1234. package/dist/src/tools/BriefTool/UI.js +0 -66
  1235. package/dist/src/tools/BriefTool/attachments.js +0 -86
  1236. package/dist/src/tools/BriefTool/prompt.js +0 -19
  1237. package/dist/src/tools/BriefTool/upload.js +0 -136
  1238. package/dist/src/tools/ConfigTool/ConfigTool.js +0 -398
  1239. package/dist/src/tools/ConfigTool/UI.js +0 -24
  1240. package/dist/src/tools/ConfigTool/constants.js +0 -1
  1241. package/dist/src/tools/ConfigTool/prompt.js +0 -82
  1242. package/dist/src/tools/ConfigTool/supportedSettings.js +0 -180
  1243. package/dist/src/tools/EnterPlanModeTool/EnterPlanModeTool.js +0 -98
  1244. package/dist/src/tools/EnterPlanModeTool/UI.js +0 -13
  1245. package/dist/src/tools/EnterPlanModeTool/constants.js +0 -1
  1246. package/dist/src/tools/EnterPlanModeTool/prompt.js +0 -164
  1247. package/dist/src/tools/EnterWorktreeTool/EnterWorktreeTool.js +0 -104
  1248. package/dist/src/tools/EnterWorktreeTool/UI.js +0 -8
  1249. package/dist/src/tools/EnterWorktreeTool/constants.js +0 -1
  1250. package/dist/src/tools/EnterWorktreeTool/prompt.js +0 -30
  1251. package/dist/src/tools/ExitPlanModeTool/ExitPlanModeV2Tool.js +0 -385
  1252. package/dist/src/tools/ExitPlanModeTool/UI.js +0 -31
  1253. package/dist/src/tools/ExitPlanModeTool/constants.js +0 -2
  1254. package/dist/src/tools/ExitPlanModeTool/prompt.js +0 -27
  1255. package/dist/src/tools/ExitWorktreeTool/ExitWorktreeTool.js +0 -257
  1256. package/dist/src/tools/ExitWorktreeTool/UI.js +0 -9
  1257. package/dist/src/tools/ExitWorktreeTool/constants.js +0 -1
  1258. package/dist/src/tools/ExitWorktreeTool/prompt.js +0 -32
  1259. package/dist/src/tools/FileEditTool/FileEditTool.js +0 -480
  1260. package/dist/src/tools/FileEditTool/UI.js +0 -201
  1261. package/dist/src/tools/FileEditTool/constants.js +0 -7
  1262. package/dist/src/tools/FileEditTool/prompt.js +0 -24
  1263. package/dist/src/tools/FileEditTool/types.js +0 -50
  1264. package/dist/src/tools/FileEditTool/utils.js +0 -579
  1265. package/dist/src/tools/FileReadTool/FileReadTool.js +0 -889
  1266. package/dist/src/tools/FileReadTool/UI.js +0 -125
  1267. package/dist/src/tools/FileReadTool/imageProcessor.js +0 -46
  1268. package/dist/src/tools/FileReadTool/limits.js +0 -70
  1269. package/dist/src/tools/FileReadTool/prompt.js +0 -31
  1270. package/dist/src/tools/FileWriteTool/FileWriteTool.js +0 -341
  1271. package/dist/src/tools/FileWriteTool/UI.js +0 -338
  1272. package/dist/src/tools/FileWriteTool/prompt.js +0 -15
  1273. package/dist/src/tools/GlobTool/GlobTool.js +0 -161
  1274. package/dist/src/tools/GlobTool/UI.js +0 -39
  1275. package/dist/src/tools/GlobTool/prompt.js +0 -6
  1276. package/dist/src/tools/GrepTool/GrepTool.js +0 -439
  1277. package/dist/src/tools/GrepTool/UI.js +0 -154
  1278. package/dist/src/tools/GrepTool/prompt.js +0 -16
  1279. package/dist/src/tools/LSPTool/LSPTool.js +0 -660
  1280. package/dist/src/tools/LSPTool/UI.js +0 -204
  1281. package/dist/src/tools/LSPTool/formatters.js +0 -445
  1282. package/dist/src/tools/LSPTool/prompt.js +0 -20
  1283. package/dist/src/tools/LSPTool/schemas.js +0 -197
  1284. package/dist/src/tools/LSPTool/symbolContext.js +0 -75
  1285. package/dist/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.js +0 -100
  1286. package/dist/src/tools/ListMcpResourcesTool/UI.js +0 -16
  1287. package/dist/src/tools/ListMcpResourcesTool/prompt.js +0 -18
  1288. package/dist/src/tools/MCPTool/MCPTool.js +0 -60
  1289. package/dist/src/tools/MCPTool/UI.js +0 -342
  1290. package/dist/src/tools/MCPTool/classifyForCollapse.js +0 -597
  1291. package/dist/src/tools/MCPTool/prompt.js +0 -3
  1292. package/dist/src/tools/McpAuthTool/McpAuthTool.js +0 -162
  1293. package/dist/src/tools/NotebookEditTool/NotebookEditTool.js +0 -421
  1294. package/dist/src/tools/NotebookEditTool/UI.js +0 -40
  1295. package/dist/src/tools/NotebookEditTool/constants.js +0 -2
  1296. package/dist/src/tools/NotebookEditTool/prompt.js +0 -2
  1297. package/dist/src/tools/PowerShellTool/PowerShellTool.js +0 -899
  1298. package/dist/src/tools/PowerShellTool/UI.js +0 -57
  1299. package/dist/src/tools/PowerShellTool/clmTypes.js +0 -207
  1300. package/dist/src/tools/PowerShellTool/commandSemantics.js +0 -115
  1301. package/dist/src/tools/PowerShellTool/commonParameters.js +0 -27
  1302. package/dist/src/tools/PowerShellTool/destructiveCommandWarning.js +0 -92
  1303. package/dist/src/tools/PowerShellTool/gitSafety.js +0 -185
  1304. package/dist/src/tools/PowerShellTool/modeValidation.js +0 -357
  1305. package/dist/src/tools/PowerShellTool/pathValidation.js +0 -1712
  1306. package/dist/src/tools/PowerShellTool/powershellPermissions.js +0 -1351
  1307. package/dist/src/tools/PowerShellTool/powershellSecurity.js +0 -942
  1308. package/dist/src/tools/PowerShellTool/prompt.js +0 -132
  1309. package/dist/src/tools/PowerShellTool/readOnlyValidation.js +0 -1633
  1310. package/dist/src/tools/PowerShellTool/toolName.js +0 -2
  1311. package/dist/src/tools/REPLTool/constants.js +0 -43
  1312. package/dist/src/tools/REPLTool/primitiveTools.js +0 -36
  1313. package/dist/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.js +0 -112
  1314. package/dist/src/tools/ReadMcpResourceTool/UI.js +0 -23
  1315. package/dist/src/tools/ReadMcpResourceTool/prompt.js +0 -15
  1316. package/dist/src/tools/RemoteTriggerTool/RemoteTriggerTool.js +0 -142
  1317. package/dist/src/tools/RemoteTriggerTool/UI.js +0 -11
  1318. package/dist/src/tools/RemoteTriggerTool/prompt.js +0 -12
  1319. package/dist/src/tools/ScheduleCronTool/CronCreateTool.js +0 -120
  1320. package/dist/src/tools/ScheduleCronTool/CronDeleteTool.js +0 -74
  1321. package/dist/src/tools/ScheduleCronTool/CronListTool.js +0 -77
  1322. package/dist/src/tools/ScheduleCronTool/UI.js +0 -28
  1323. package/dist/src/tools/ScheduleCronTool/prompt.js +0 -115
  1324. package/dist/src/tools/SendMessageTool/SendMessageTool.js +0 -675
  1325. package/dist/src/tools/SendMessageTool/UI.js +0 -23
  1326. package/dist/src/tools/SendMessageTool/constants.js +0 -1
  1327. package/dist/src/tools/SendMessageTool/prompt.js +0 -47
  1328. package/dist/src/tools/SkillTool/SkillTool.js +0 -827
  1329. package/dist/src/tools/SkillTool/UI.js +0 -60
  1330. package/dist/src/tools/SkillTool/constants.js +0 -1
  1331. package/dist/src/tools/SkillTool/prompt.js +0 -184
  1332. package/dist/src/tools/SleepTool/prompt.js +0 -14
  1333. package/dist/src/tools/SyntheticOutputTool/SyntheticOutputTool.js +0 -138
  1334. package/dist/src/tools/TaskCreateTool/TaskCreateTool.js +0 -104
  1335. package/dist/src/tools/TaskCreateTool/constants.js +0 -1
  1336. package/dist/src/tools/TaskCreateTool/prompt.js +0 -52
  1337. package/dist/src/tools/TaskGetTool/TaskGetTool.js +0 -106
  1338. package/dist/src/tools/TaskGetTool/constants.js +0 -1
  1339. package/dist/src/tools/TaskGetTool/prompt.js +0 -23
  1340. package/dist/src/tools/TaskListTool/TaskListTool.js +0 -89
  1341. package/dist/src/tools/TaskListTool/constants.js +0 -1
  1342. package/dist/src/tools/TaskListTool/prompt.js +0 -44
  1343. package/dist/src/tools/TaskOutputTool/TaskOutputTool.js +0 -535
  1344. package/dist/src/tools/TaskOutputTool/constants.js +0 -1
  1345. package/dist/src/tools/TaskStopTool/TaskStopTool.js +0 -110
  1346. package/dist/src/tools/TaskStopTool/UI.js +0 -30
  1347. package/dist/src/tools/TaskStopTool/prompt.js +0 -7
  1348. package/dist/src/tools/TaskUpdateTool/TaskUpdateTool.js +0 -301
  1349. package/dist/src/tools/TaskUpdateTool/constants.js +0 -1
  1350. package/dist/src/tools/TaskUpdateTool/prompt.js +0 -76
  1351. package/dist/src/tools/TeamCreateTool/TeamCreateTool.js +0 -177
  1352. package/dist/src/tools/TeamCreateTool/UI.js +0 -4
  1353. package/dist/src/tools/TeamCreateTool/constants.js +0 -1
  1354. package/dist/src/tools/TeamCreateTool/prompt.js +0 -113
  1355. package/dist/src/tools/TeamDeleteTool/TeamDeleteTool.js +0 -102
  1356. package/dist/src/tools/TeamDeleteTool/UI.js +0 -13
  1357. package/dist/src/tools/TeamDeleteTool/constants.js +0 -1
  1358. package/dist/src/tools/TeamDeleteTool/prompt.js +0 -16
  1359. package/dist/src/tools/TodoWriteTool/TodoWriteTool.js +0 -99
  1360. package/dist/src/tools/TodoWriteTool/constants.js +0 -1
  1361. package/dist/src/tools/TodoWriteTool/prompt.js +0 -181
  1362. package/dist/src/tools/ToolSearchTool/ToolSearchTool.js +0 -357
  1363. package/dist/src/tools/ToolSearchTool/constants.js +0 -1
  1364. package/dist/src/tools/ToolSearchTool/prompt.js +0 -99
  1365. package/dist/src/tools/TungstenTool/TungstenLiveMonitor.js +0 -7
  1366. package/dist/src/tools/TungstenTool/TungstenTool.js +0 -3
  1367. package/dist/src/tools/WebFetchTool/UI.js +0 -30
  1368. package/dist/src/tools/WebFetchTool/WebFetchTool.js +0 -246
  1369. package/dist/src/tools/WebFetchTool/preapproved.js +0 -155
  1370. package/dist/src/tools/WebFetchTool/prompt.js +0 -39
  1371. package/dist/src/tools/WebFetchTool/utils.js +0 -381
  1372. package/dist/src/tools/WebSearchTool/UI.js +0 -66
  1373. package/dist/src/tools/WebSearchTool/WebSearchTool.js +0 -352
  1374. package/dist/src/tools/WebSearchTool/prompt.js +0 -32
  1375. package/dist/src/tools/WorkflowTool/constants.js +0 -2
  1376. package/dist/src/tools/shared/gitOperationTracking.js +0 -220
  1377. package/dist/src/tools/shared/spawnMultiAgent.js +0 -805
  1378. package/dist/src/tools/testing/TestingPermissionTool.js +0 -72
  1379. package/dist/src/tools/utils.js +0 -24
  1380. package/dist/src/tools.js +0 -332
  1381. package/dist/src/types/command.js +0 -10
  1382. package/dist/src/types/connectorText.js +0 -2
  1383. package/dist/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.js +0 -673
  1384. package/dist/src/types/generated/events_mono/common/v1/auth.js +0 -49
  1385. package/dist/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.js +0 -147
  1386. package/dist/src/types/generated/google/protobuf/timestamp.js +0 -38
  1387. package/dist/src/types/hooks.js +0 -153
  1388. package/dist/src/types/ids.js +0 -27
  1389. package/dist/src/types/logs.js +0 -11
  1390. package/dist/src/types/message.js +0 -1
  1391. package/dist/src/types/permissions.js +0 -25
  1392. package/dist/src/types/plugin.js +0 -72
  1393. package/dist/src/types/textInputTypes.js +0 -20
  1394. package/dist/src/types/utils.js +0 -5
  1395. package/dist/src/upstreamproxy/relay.js +0 -346
  1396. package/dist/src/upstreamproxy/upstreamproxy.js +0 -236
  1397. package/dist/src/utils/CircularBuffer.js +0 -75
  1398. package/dist/src/utils/Cursor.js +0 -1229
  1399. package/dist/src/utils/QueryGuard.js +0 -115
  1400. package/dist/src/utils/Shell.js +0 -374
  1401. package/dist/src/utils/ShellCommand.js +0 -338
  1402. package/dist/src/utils/abortController.js +0 -74
  1403. package/dist/src/utils/activityManager.js +0 -127
  1404. package/dist/src/utils/advisor.js +0 -77
  1405. package/dist/src/utils/agentContext.js +0 -91
  1406. package/dist/src/utils/agentId.js +0 -83
  1407. package/dist/src/utils/agentSwarmsEnabled.js +0 -37
  1408. package/dist/src/utils/agenticSessionSearch.js +0 -255
  1409. package/dist/src/utils/analyzeContext.js +0 -848
  1410. package/dist/src/utils/ansiToPng.js +0 -259
  1411. package/dist/src/utils/ansiToSvg.js +0 -207
  1412. package/dist/src/utils/api.js +0 -555
  1413. package/dist/src/utils/apiPreconnect.js +0 -62
  1414. package/dist/src/utils/appleTerminalBackup.js +0 -95
  1415. package/dist/src/utils/argumentSubstitution.js +0 -114
  1416. package/dist/src/utils/array.js +0 -12
  1417. package/dist/src/utils/asciicast.js +0 -200
  1418. package/dist/src/utils/attachments.js +0 -2514
  1419. package/dist/src/utils/attribution.js +0 -308
  1420. package/dist/src/utils/attributionHooks.js +0 -16
  1421. package/dist/src/utils/attributionTrailer.js +0 -16
  1422. package/dist/src/utils/auth.js +0 -2020
  1423. package/dist/src/utils/authFileDescriptor.js +0 -152
  1424. package/dist/src/utils/authPortable.js +0 -14
  1425. package/dist/src/utils/autoModeDenials.js +0 -15
  1426. package/dist/src/utils/autoRunIssue.js +0 -112
  1427. package/dist/src/utils/autoUpdater.js +0 -461
  1428. package/dist/src/utils/aws.js +0 -44
  1429. package/dist/src/utils/awsAuthStatusManager.js +0 -66
  1430. package/dist/src/utils/background/remote/preconditions.js +0 -175
  1431. package/dist/src/utils/background/remote/remoteSession.js +0 -53
  1432. package/dist/src/utils/backgroundHousekeeping.js +0 -66
  1433. package/dist/src/utils/bash/ParsedCommand.js +0 -241
  1434. package/dist/src/utils/bash/ShellSnapshot.js +0 -489
  1435. package/dist/src/utils/bash/ast.js +0 -2590
  1436. package/dist/src/utils/bash/bashParser.js +0 -4355
  1437. package/dist/src/utils/bash/bashPipeCommand.js +0 -249
  1438. package/dist/src/utils/bash/commands.js +0 -1131
  1439. package/dist/src/utils/bash/heredoc.js +0 -647
  1440. package/dist/src/utils/bash/parser.js +0 -195
  1441. package/dist/src/utils/bash/prefix.js +0 -154
  1442. package/dist/src/utils/bash/registry.js +0 -23
  1443. package/dist/src/utils/bash/shellCompletion.js +0 -196
  1444. package/dist/src/utils/bash/shellPrefix.js +0 -25
  1445. package/dist/src/utils/bash/shellQuote.js +0 -253
  1446. package/dist/src/utils/bash/shellQuoting.js +0 -106
  1447. package/dist/src/utils/bash/specs/alias.js +0 -11
  1448. package/dist/src/utils/bash/specs/index.js +0 -16
  1449. package/dist/src/utils/bash/specs/nohup.js +0 -10
  1450. package/dist/src/utils/bash/specs/pyright.js +0 -88
  1451. package/dist/src/utils/bash/specs/sleep.js +0 -10
  1452. package/dist/src/utils/bash/specs/srun.js +0 -28
  1453. package/dist/src/utils/bash/specs/time.js +0 -10
  1454. package/dist/src/utils/bash/specs/timeout.js +0 -17
  1455. package/dist/src/utils/bash/treeSitterAnalysis.js +0 -407
  1456. package/dist/src/utils/betas.js +0 -332
  1457. package/dist/src/utils/billing.js +0 -54
  1458. package/dist/src/utils/binaryCheck.js +0 -40
  1459. package/dist/src/utils/browser.js +0 -58
  1460. package/dist/src/utils/bufferedWriter.js +0 -77
  1461. package/dist/src/utils/bundledMode.js +0 -19
  1462. package/dist/src/utils/caCerts.js +0 -93
  1463. package/dist/src/utils/caCertsConfig.js +0 -77
  1464. package/dist/src/utils/cachePaths.js +0 -28
  1465. package/dist/src/utils/ccshareResume.js +0 -16
  1466. package/dist/src/utils/classifierApprovals.js +0 -66
  1467. package/dist/src/utils/classifierApprovalsHook.js +0 -10
  1468. package/dist/src/utils/claudeCodeHints.js +0 -142
  1469. package/dist/src/utils/claudeDesktop.js +0 -108
  1470. package/dist/src/utils/claudeInChrome/chromeNativeHost.js +0 -416
  1471. package/dist/src/utils/claudeInChrome/common.js +0 -466
  1472. package/dist/src/utils/claudeInChrome/mcpServer.js +0 -237
  1473. package/dist/src/utils/claudeInChrome/prompt.js +0 -79
  1474. package/dist/src/utils/claudeInChrome/setup.js +0 -320
  1475. package/dist/src/utils/claudeInChrome/setupPortable.js +0 -172
  1476. package/dist/src/utils/claudeInChrome/toolRendering.js +0 -234
  1477. package/dist/src/utils/claudemd.js +0 -1054
  1478. package/dist/src/utils/cleanup.js +0 -514
  1479. package/dist/src/utils/cleanupRegistry.js +0 -22
  1480. package/dist/src/utils/cliArgs.js +0 -53
  1481. package/dist/src/utils/cliHighlight.js +0 -45
  1482. package/dist/src/utils/codeIndexing.js +0 -149
  1483. package/dist/src/utils/collapseBackgroundBashNotifications.js +0 -70
  1484. package/dist/src/utils/collapseHookSummaries.js +0 -48
  1485. package/dist/src/utils/collapseReadSearch.js +0 -871
  1486. package/dist/src/utils/collapseTeammateShutdowns.js +0 -44
  1487. package/dist/src/utils/combinedAbortSignal.js +0 -40
  1488. package/dist/src/utils/commandLifecycle.js +0 -7
  1489. package/dist/src/utils/commitAttribution.js +0 -720
  1490. package/dist/src/utils/completionCache.js +0 -138
  1491. package/dist/src/utils/computerUse/appNames.js +0 -170
  1492. package/dist/src/utils/computerUse/cleanup.js +0 -66
  1493. package/dist/src/utils/computerUse/common.js +0 -56
  1494. package/dist/src/utils/computerUse/computerUseLock.js +0 -183
  1495. package/dist/src/utils/computerUse/drainRunLoop.js +0 -71
  1496. package/dist/src/utils/computerUse/escHotkey.js +0 -53
  1497. package/dist/src/utils/computerUse/executor.js +0 -480
  1498. package/dist/src/utils/computerUse/gates.js +0 -55
  1499. package/dist/src/utils/computerUse/hostAdapter.js +0 -62
  1500. package/dist/src/utils/computerUse/inputLoader.js +0 -27
  1501. package/dist/src/utils/computerUse/mcpServer.js +0 -84
  1502. package/dist/src/utils/computerUse/setup.js +0 -42
  1503. package/dist/src/utils/computerUse/swiftLoader.js +0 -20
  1504. package/dist/src/utils/computerUse/toolRendering.js +0 -100
  1505. package/dist/src/utils/computerUse/wrapper.js +0 -318
  1506. package/dist/src/utils/concurrentSessions.js +0 -179
  1507. package/dist/src/utils/config.js +0 -1084
  1508. package/dist/src/utils/configConstants.js +0 -18
  1509. package/dist/src/utils/contentArray.js +0 -45
  1510. package/dist/src/utils/context.js +0 -185
  1511. package/dist/src/utils/contextAnalysis.js +0 -171
  1512. package/dist/src/utils/contextSuggestions.js +0 -158
  1513. package/dist/src/utils/controlMessageCompat.js +0 -31
  1514. package/dist/src/utils/conversationRecovery.js +0 -436
  1515. package/dist/src/utils/cron.js +0 -260
  1516. package/dist/src/utils/cronJitterConfig.js +0 -62
  1517. package/dist/src/utils/cronScheduler.js +0 -388
  1518. package/dist/src/utils/cronTasks.js +0 -328
  1519. package/dist/src/utils/cronTasksLock.js +0 -159
  1520. package/dist/src/utils/crossProjectResume.js +0 -46
  1521. package/dist/src/utils/crypto.js +0 -13
  1522. package/dist/src/utils/cwd.js +0 -29
  1523. package/dist/src/utils/databaseMcp/common.js +0 -48
  1524. package/dist/src/utils/databaseMcp/mcpServer.js +0 -2
  1525. package/dist/src/utils/databaseMcp/server/connection.js +0 -243
  1526. package/dist/src/utils/databaseMcp/server/index.js +0 -1442
  1527. package/dist/src/utils/databaseMcp/server/queries.js +0 -683
  1528. package/dist/src/utils/databaseMcp/server/types.js +0 -7
  1529. package/dist/src/utils/databaseMcp/setup.js +0 -28
  1530. package/dist/src/utils/debug.js +0 -220
  1531. package/dist/src/utils/debugFilter.js +0 -125
  1532. package/dist/src/utils/deepLink/banner.js +0 -103
  1533. package/dist/src/utils/deepLink/parseDeepLink.js +0 -138
  1534. package/dist/src/utils/deepLink/protocolHandler.js +0 -119
  1535. package/dist/src/utils/deepLink/registerProtocol.js +0 -291
  1536. package/dist/src/utils/deepLink/terminalLauncher.js +0 -455
  1537. package/dist/src/utils/deepLink/terminalPreference.js +0 -51
  1538. package/dist/src/utils/desktopDeepLink.js +0 -208
  1539. package/dist/src/utils/detectRepository.js +0 -157
  1540. package/dist/src/utils/diagLogs.js +0 -74
  1541. package/dist/src/utils/diff.js +0 -108
  1542. package/dist/src/utils/directMemberMessage.js +0 -34
  1543. package/dist/src/utils/displayTags.js +0 -46
  1544. package/dist/src/utils/doctorContextWarnings.js +0 -179
  1545. package/dist/src/utils/doctorDiagnostic.js +0 -495
  1546. package/dist/src/utils/dxt/helpers.js +0 -64
  1547. package/dist/src/utils/dxt/zip.js +0 -167
  1548. package/dist/src/utils/earlyInput.js +0 -166
  1549. package/dist/src/utils/editor.js +0 -163
  1550. package/dist/src/utils/effort.js +0 -278
  1551. package/dist/src/utils/embeddedTools.js +0 -26
  1552. package/dist/src/utils/env.js +0 -358
  1553. package/dist/src/utils/envDynamic.js +0 -130
  1554. package/dist/src/utils/envUtils.js +0 -154
  1555. package/dist/src/utils/envValidation.js +0 -26
  1556. package/dist/src/utils/errorLogSink.js +0 -197
  1557. package/dist/src/utils/errors.js +0 -207
  1558. package/dist/src/utils/eventLoopStallDetector.js +0 -16
  1559. package/dist/src/utils/exampleCommands.js +0 -165
  1560. package/dist/src/utils/execFileNoThrow.js +0 -93
  1561. package/dist/src/utils/execFileNoThrowPortable.js +0 -111
  1562. package/dist/src/utils/execSyncWrapper.js +0 -68
  1563. package/dist/src/utils/exportRenderer.js +0 -71
  1564. package/dist/src/utils/extraUsage.js +0 -19
  1565. package/dist/src/utils/fastMode.js +0 -393
  1566. package/dist/src/utils/file.js +0 -467
  1567. package/dist/src/utils/fileHistory.js +0 -851
  1568. package/dist/src/utils/fileOperationAnalytics.js +0 -45
  1569. package/dist/src/utils/filePersistence/filePersistence.js +0 -212
  1570. package/dist/src/utils/filePersistence/outputsScanner.js +0 -104
  1571. package/dist/src/utils/filePersistence/types.js +0 -5
  1572. package/dist/src/utils/fileRead.js +0 -81
  1573. package/dist/src/utils/fileReadCache.js +0 -78
  1574. package/dist/src/utils/fileStateCache.js +0 -99
  1575. package/dist/src/utils/findExecutable.js +0 -13
  1576. package/dist/src/utils/fingerprint.js +0 -59
  1577. package/dist/src/utils/forkedAgent.js +0 -410
  1578. package/dist/src/utils/format.js +0 -238
  1579. package/dist/src/utils/formatBriefTimestamp.js +0 -72
  1580. package/dist/src/utils/fpsTracker.js +0 -34
  1581. package/dist/src/utils/frontmatterParser.js +0 -260
  1582. package/dist/src/utils/fsOperations.js +0 -834
  1583. package/dist/src/utils/fullscreen.js +0 -194
  1584. package/dist/src/utils/generatedFiles.js +0 -122
  1585. package/dist/src/utils/generators.js +0 -67
  1586. package/dist/src/utils/genericProcessUtils.js +0 -155
  1587. package/dist/src/utils/getWorktreePaths.js +0 -56
  1588. package/dist/src/utils/getWorktreePathsPortable.js +0 -23
  1589. package/dist/src/utils/ghPrStatus.js +0 -71
  1590. package/dist/src/utils/git/gitConfigParser.js +0 -226
  1591. package/dist/src/utils/git/gitFilesystem.js +0 -606
  1592. package/dist/src/utils/git/gitignore.js +0 -84
  1593. package/dist/src/utils/git.js +0 -725
  1594. package/dist/src/utils/gitDiff.js +0 -395
  1595. package/dist/src/utils/gitSettings.js +0 -18
  1596. package/dist/src/utils/github/ghAuthStatus.js +0 -23
  1597. package/dist/src/utils/githubRepoPathMapping.js +0 -135
  1598. package/dist/src/utils/glob.js +0 -90
  1599. package/dist/src/utils/gracefulShutdown.js +0 -447
  1600. package/dist/src/utils/groupToolUses.js +0 -126
  1601. package/dist/src/utils/handlePromptSubmit.js +0 -398
  1602. package/dist/src/utils/hash.js +0 -46
  1603. package/dist/src/utils/headlessProfiler.js +0 -147
  1604. package/dist/src/utils/heapDumpService.js +0 -202
  1605. package/dist/src/utils/heatmap.js +0 -151
  1606. package/dist/src/utils/highlightMatch.js +0 -28
  1607. package/dist/src/utils/hooks/AsyncHookRegistry.js +0 -187
  1608. package/dist/src/utils/hooks/apiQueryHookHelper.js +0 -77
  1609. package/dist/src/utils/hooks/execAgentHook.js +0 -257
  1610. package/dist/src/utils/hooks/execHttpHook.js +0 -184
  1611. package/dist/src/utils/hooks/execPromptHook.js +0 -171
  1612. package/dist/src/utils/hooks/fileChangedWatcher.js +0 -161
  1613. package/dist/src/utils/hooks/hookEvents.js +0 -111
  1614. package/dist/src/utils/hooks/hookHelpers.js +0 -60
  1615. package/dist/src/utils/hooks/hooksConfigManager.js +0 -323
  1616. package/dist/src/utils/hooks/hooksConfigSnapshot.js +0 -114
  1617. package/dist/src/utils/hooks/hooksSettings.js +0 -204
  1618. package/dist/src/utils/hooks/postSamplingHooks.js +0 -39
  1619. package/dist/src/utils/hooks/registerFrontmatterHooks.js +0 -47
  1620. package/dist/src/utils/hooks/registerSkillHooks.js +0 -40
  1621. package/dist/src/utils/hooks/sessionHooks.js +0 -252
  1622. package/dist/src/utils/hooks/skillImprovement.js +0 -211
  1623. package/dist/src/utils/hooks/ssrfGuard.js +0 -258
  1624. package/dist/src/utils/hooks.js +0 -3668
  1625. package/dist/src/utils/horizontalScroll.js +0 -108
  1626. package/dist/src/utils/http.js +0 -121
  1627. package/dist/src/utils/hyperlink.js +0 -28
  1628. package/dist/src/utils/iTermBackup.js +0 -48
  1629. package/dist/src/utils/ide.js +0 -1198
  1630. package/dist/src/utils/idePathConversion.js +0 -66
  1631. package/dist/src/utils/idleTimeout.js +0 -44
  1632. package/dist/src/utils/imagePaste.js +0 -329
  1633. package/dist/src/utils/imageResizer.js +0 -664
  1634. package/dist/src/utils/imageStore.js +0 -150
  1635. package/dist/src/utils/imageValidation.js +0 -92
  1636. package/dist/src/utils/immediateCommand.js +0 -12
  1637. package/dist/src/utils/inProcessTeammateHelpers.js +0 -71
  1638. package/dist/src/utils/ink.js +0 -20
  1639. package/dist/src/utils/intl.js +0 -83
  1640. package/dist/src/utils/jetbrains.js +0 -152
  1641. package/dist/src/utils/json.js +0 -295
  1642. package/dist/src/utils/jsonRead.js +0 -14
  1643. package/dist/src/utils/keyboardShortcuts.js +0 -11
  1644. package/dist/src/utils/lazySchema.js +0 -8
  1645. package/dist/src/utils/listSessionsImpl.js +0 -332
  1646. package/dist/src/utils/localInstaller.js +0 -131
  1647. package/dist/src/utils/lockfile.js +0 -22
  1648. package/dist/src/utils/log.js +0 -280
  1649. package/dist/src/utils/logoV2Utils.js +0 -288
  1650. package/dist/src/utils/mailbox.js +0 -50
  1651. package/dist/src/utils/managedEnv.js +0 -160
  1652. package/dist/src/utils/managedEnvConstants.js +0 -187
  1653. package/dist/src/utils/markdown.js +0 -300
  1654. package/dist/src/utils/markdownConfigLoader.js +0 -480
  1655. package/dist/src/utils/mcp/dateTimeParser.js +0 -102
  1656. package/dist/src/utils/mcp/elicitationValidation.js +0 -259
  1657. package/dist/src/utils/mcpInstructionsDelta.js +0 -97
  1658. package/dist/src/utils/mcpOutputStorage.js +0 -159
  1659. package/dist/src/utils/mcpValidation.js +0 -165
  1660. package/dist/src/utils/mcpWebSocketTransport.js +0 -180
  1661. package/dist/src/utils/memoize.js +0 -205
  1662. package/dist/src/utils/memory/types.js +0 -9
  1663. package/dist/src/utils/memory/versions.js +0 -7
  1664. package/dist/src/utils/memoryFileDetection.js +0 -247
  1665. package/dist/src/utils/messagePredicates.js +0 -6
  1666. package/dist/src/utils/messageQueueManager.js +0 -430
  1667. package/dist/src/utils/messages/mappers.js +0 -240
  1668. package/dist/src/utils/messages/systemInit.js +0 -74
  1669. package/dist/src/utils/messages.js +0 -4273
  1670. package/dist/src/utils/model/agent.js +0 -128
  1671. package/dist/src/utils/model/aliases.js +0 -21
  1672. package/dist/src/utils/model/antModels.js +0 -25
  1673. package/dist/src/utils/model/bedrock.js +0 -220
  1674. package/dist/src/utils/model/check1mAccess.js +0 -64
  1675. package/dist/src/utils/model/configs.js +0 -93
  1676. package/dist/src/utils/model/contextWindowUpgradeCheck.js +0 -41
  1677. package/dist/src/utils/model/deprecation.js +0 -72
  1678. package/dist/src/utils/model/model.js +0 -635
  1679. package/dist/src/utils/model/modelAllowlist.js +0 -148
  1680. package/dist/src/utils/model/modelCapabilities.js +0 -107
  1681. package/dist/src/utils/model/modelOptions.js +0 -627
  1682. package/dist/src/utils/model/modelStrings.js +0 -144
  1683. package/dist/src/utils/model/modelSupportOverrides.js +0 -40
  1684. package/dist/src/utils/model/openrouter.js +0 -51
  1685. package/dist/src/utils/model/providerBaseUrls.js +0 -77
  1686. package/dist/src/utils/model/providerCatalog.js +0 -81
  1687. package/dist/src/utils/model/providerModels.js +0 -334
  1688. package/dist/src/utils/model/providerProfiles.js +0 -392
  1689. package/dist/src/utils/model/providerProfilesDb.js +0 -556
  1690. package/dist/src/utils/model/providerSwitch.js +0 -68
  1691. package/dist/src/utils/model/providers.js +0 -199
  1692. package/dist/src/utils/model/validateModel.js +0 -257
  1693. package/dist/src/utils/modelCost.js +0 -160
  1694. package/dist/src/utils/modifiers.js +0 -35
  1695. package/dist/src/utils/mtls.js +0 -134
  1696. package/dist/src/utils/nativeInstaller/download.js +0 -370
  1697. package/dist/src/utils/nativeInstaller/index.js +0 -8
  1698. package/dist/src/utils/nativeInstaller/installer.js +0 -1396
  1699. package/dist/src/utils/nativeInstaller/packageManagers.js +0 -258
  1700. package/dist/src/utils/nativeInstaller/pidLock.js +0 -347
  1701. package/dist/src/utils/notebook.js +0 -176
  1702. package/dist/src/utils/objectGroupBy.js +0 -15
  1703. package/dist/src/utils/pasteStore.js +0 -93
  1704. package/dist/src/utils/path.js +0 -140
  1705. package/dist/src/utils/pdf.js +0 -236
  1706. package/dist/src/utils/pdfUtils.js +0 -61
  1707. package/dist/src/utils/peerAddress.js +0 -20
  1708. package/dist/src/utils/permissions/PermissionMode.js +0 -95
  1709. package/dist/src/utils/permissions/PermissionPromptToolResultSchema.js +0 -85
  1710. package/dist/src/utils/permissions/PermissionResult.js +0 -11
  1711. package/dist/src/utils/permissions/PermissionRule.js +0 -19
  1712. package/dist/src/utils/permissions/PermissionUpdate.js +0 -268
  1713. package/dist/src/utils/permissions/PermissionUpdateSchema.js +0 -61
  1714. package/dist/src/utils/permissions/autoModeState.js +0 -34
  1715. package/dist/src/utils/permissions/bashClassifier.js +0 -30
  1716. package/dist/src/utils/permissions/bypassPermissionsKillswitch.js +0 -115
  1717. package/dist/src/utils/permissions/classifierDecision.js +0 -88
  1718. package/dist/src/utils/permissions/classifierShared.js +0 -28
  1719. package/dist/src/utils/permissions/dangerousPatterns.js +0 -78
  1720. package/dist/src/utils/permissions/denialTracking.js +0 -34
  1721. package/dist/src/utils/permissions/filesystem.js +0 -1411
  1722. package/dist/src/utils/permissions/getNextPermissionMode.js +0 -74
  1723. package/dist/src/utils/permissions/pathValidation.js +0 -351
  1724. package/dist/src/utils/permissions/permissionExplainer.js +0 -188
  1725. package/dist/src/utils/permissions/permissionRuleParser.js +0 -177
  1726. package/dist/src/utils/permissions/permissionSetup.js +0 -1164
  1727. package/dist/src/utils/permissions/permissions.js +0 -1065
  1728. package/dist/src/utils/permissions/permissionsLoader.js +0 -217
  1729. package/dist/src/utils/permissions/shadowedRuleDetection.js +0 -149
  1730. package/dist/src/utils/permissions/shellRuleMatching.js +0 -174
  1731. package/dist/src/utils/permissions/yoloClassifier.js +0 -1195
  1732. package/dist/src/utils/planModeV2.js +0 -75
  1733. package/dist/src/utils/plans.js +0 -334
  1734. package/dist/src/utils/platform.js +0 -122
  1735. package/dist/src/utils/plugins/addDirPluginSettings.js +0 -53
  1736. package/dist/src/utils/plugins/cacheUtils.js +0 -174
  1737. package/dist/src/utils/plugins/dependencyResolver.js +0 -244
  1738. package/dist/src/utils/plugins/fetchTelemetry.js +0 -108
  1739. package/dist/src/utils/plugins/gitAvailability.js +0 -65
  1740. package/dist/src/utils/plugins/headlessPluginInstall.js +0 -136
  1741. package/dist/src/utils/plugins/hintRecommendation.js +0 -136
  1742. package/dist/src/utils/plugins/installCounts.js +0 -218
  1743. package/dist/src/utils/plugins/installedPluginsManager.js +0 -1003
  1744. package/dist/src/utils/plugins/loadPluginAgents.js +0 -219
  1745. package/dist/src/utils/plugins/loadPluginCommands.js +0 -595
  1746. package/dist/src/utils/plugins/loadPluginHooks.js +0 -239
  1747. package/dist/src/utils/plugins/loadPluginOutputStyles.js +0 -112
  1748. package/dist/src/utils/plugins/lspPluginIntegration.js +0 -293
  1749. package/dist/src/utils/plugins/lspRecommendation.js +0 -278
  1750. package/dist/src/utils/plugins/managedPlugins.js +0 -26
  1751. package/dist/src/utils/plugins/marketplaceHelpers.js +0 -470
  1752. package/dist/src/utils/plugins/marketplaceManager.js +0 -1939
  1753. package/dist/src/utils/plugins/mcpPluginIntegration.js +0 -465
  1754. package/dist/src/utils/plugins/mcpbHandler.js +0 -708
  1755. package/dist/src/utils/plugins/officialMarketplace.js +0 -21
  1756. package/dist/src/utils/plugins/officialMarketplaceGcs.js +0 -195
  1757. package/dist/src/utils/plugins/officialMarketplaceStartupCheck.js +0 -338
  1758. package/dist/src/utils/plugins/orphanedPluginFilter.js +0 -96
  1759. package/dist/src/utils/plugins/parseMarketplaceInput.js +0 -143
  1760. package/dist/src/utils/plugins/performStartupChecks.js +0 -66
  1761. package/dist/src/utils/plugins/pluginAutoupdate.js +0 -210
  1762. package/dist/src/utils/plugins/pluginBlocklist.js +0 -93
  1763. package/dist/src/utils/plugins/pluginDirectories.js +0 -170
  1764. package/dist/src/utils/plugins/pluginFlagging.js +0 -173
  1765. package/dist/src/utils/plugins/pluginIdentifier.js +0 -78
  1766. package/dist/src/utils/plugins/pluginInstallationHelpers.js +0 -400
  1767. package/dist/src/utils/plugins/pluginLoader.js +0 -2426
  1768. package/dist/src/utils/plugins/pluginOptionsStorage.js +0 -311
  1769. package/dist/src/utils/plugins/pluginPolicy.js +0 -18
  1770. package/dist/src/utils/plugins/pluginStartupCheck.js +0 -261
  1771. package/dist/src/utils/plugins/pluginVersioning.js +0 -128
  1772. package/dist/src/utils/plugins/reconciler.js +0 -181
  1773. package/dist/src/utils/plugins/refresh.js +0 -162
  1774. package/dist/src/utils/plugins/schemas.js +0 -1283
  1775. package/dist/src/utils/plugins/validatePlugin.js +0 -765
  1776. package/dist/src/utils/plugins/walkPluginMarkdown.js +0 -49
  1777. package/dist/src/utils/plugins/zipCache.js +0 -346
  1778. package/dist/src/utils/plugins/zipCacheAdapters.js +0 -133
  1779. package/dist/src/utils/postCommitAttribution.js +0 -16
  1780. package/dist/src/utils/powershell/dangerousCmdlets.js +0 -174
  1781. package/dist/src/utils/powershell/parser.js +0 -1357
  1782. package/dist/src/utils/powershell/staticPrefix.js +0 -277
  1783. package/dist/src/utils/preflightChecks.js +0 -147
  1784. package/dist/src/utils/privacyLevel.js +0 -49
  1785. package/dist/src/utils/process.js +0 -56
  1786. package/dist/src/utils/processUserInput/processBashCommand.js +0 -119
  1787. package/dist/src/utils/processUserInput/processSlashCommand.js +0 -845
  1788. package/dist/src/utils/processUserInput/processTextPrompt.js +0 -68
  1789. package/dist/src/utils/processUserInput/processUserInput.js +0 -326
  1790. package/dist/src/utils/profilerBase.js +0 -29
  1791. package/dist/src/utils/promptCategory.js +0 -39
  1792. package/dist/src/utils/promptEditor.js +0 -151
  1793. package/dist/src/utils/promptShellExecution.js +0 -119
  1794. package/dist/src/utils/proxy.js +0 -347
  1795. package/dist/src/utils/queryContext.js +0 -110
  1796. package/dist/src/utils/queryHelpers.js +0 -436
  1797. package/dist/src/utils/queryProfiler.js +0 -242
  1798. package/dist/src/utils/queueProcessor.js +0 -70
  1799. package/dist/src/utils/readEditContext.js +0 -176
  1800. package/dist/src/utils/readFileInRange.js +0 -278
  1801. package/dist/src/utils/releaseNotes.js +0 -304
  1802. package/dist/src/utils/renderOptions.js +0 -67
  1803. package/dist/src/utils/ripgrep.js +0 -540
  1804. package/dist/src/utils/sandbox/sandbox-adapter.js +0 -749
  1805. package/dist/src/utils/sandbox/sandbox-ui-utils.js +0 -11
  1806. package/dist/src/utils/sanitization.js +0 -72
  1807. package/dist/src/utils/screenshotClipboard.js +0 -89
  1808. package/dist/src/utils/sdkEventQueue.js +0 -49
  1809. package/dist/src/utils/sdkHeapDumpMonitor.js +0 -16
  1810. package/dist/src/utils/secureStorage/fallbackStorage.js +0 -59
  1811. package/dist/src/utils/secureStorage/index.js +0 -14
  1812. package/dist/src/utils/secureStorage/keychainPrefetch.js +0 -91
  1813. package/dist/src/utils/secureStorage/macOsKeychainHelpers.js +0 -91
  1814. package/dist/src/utils/secureStorage/macOsKeychainStorage.js +0 -192
  1815. package/dist/src/utils/secureStorage/plainTextStorage.js +0 -81
  1816. package/dist/src/utils/secureStorage/secureStoreDefs.js +0 -1
  1817. package/dist/src/utils/secureStorage/sqliteStorage.js +0 -217
  1818. package/dist/src/utils/secureStorage/types.js +0 -1
  1819. package/dist/src/utils/semanticBoolean.js +0 -23
  1820. package/dist/src/utils/semanticNumber.js +0 -34
  1821. package/dist/src/utils/semver.js +0 -53
  1822. package/dist/src/utils/sequential.js +0 -43
  1823. package/dist/src/utils/sessionActivity.js +0 -120
  1824. package/dist/src/utils/sessionDataUploader.js +0 -16
  1825. package/dist/src/utils/sessionEnvVars.js +0 -18
  1826. package/dist/src/utils/sessionEnvironment.js +0 -131
  1827. package/dist/src/utils/sessionFileAccessHooks.js +0 -207
  1828. package/dist/src/utils/sessionIngressAuth.js +0 -113
  1829. package/dist/src/utils/sessionRestore.js +0 -359
  1830. package/dist/src/utils/sessionStart.js +0 -165
  1831. package/dist/src/utils/sessionState.js +0 -76
  1832. package/dist/src/utils/sessionStorage.js +0 -4162
  1833. package/dist/src/utils/sessionStoragePortable.js +0 -665
  1834. package/dist/src/utils/sessionTitle.js +0 -120
  1835. package/dist/src/utils/sessionUrl.js +0 -50
  1836. package/dist/src/utils/set.js +0 -50
  1837. package/dist/src/utils/settings/allErrors.js +0 -29
  1838. package/dist/src/utils/settings/applySettingsChange.js +0 -65
  1839. package/dist/src/utils/settings/changeDetector.js +0 -409
  1840. package/dist/src/utils/settings/constants.js +0 -166
  1841. package/dist/src/utils/settings/internalWrites.js +0 -33
  1842. package/dist/src/utils/settings/managedPath.js +0 -29
  1843. package/dist/src/utils/settings/mdm/constants.js +0 -62
  1844. package/dist/src/utils/settings/mdm/rawRead.js +0 -97
  1845. package/dist/src/utils/settings/mdm/settings.js +0 -254
  1846. package/dist/src/utils/settings/permissionValidation.js +0 -224
  1847. package/dist/src/utils/settings/pluginOnlyPolicy.js +0 -53
  1848. package/dist/src/utils/settings/schemaOutput.js +0 -7
  1849. package/dist/src/utils/settings/settings.js +0 -791
  1850. package/dist/src/utils/settings/settingsCache.js +0 -47
  1851. package/dist/src/utils/settings/toolValidationConfig.js +0 -76
  1852. package/dist/src/utils/settings/types.js +0 -846
  1853. package/dist/src/utils/settings/validateEditTool.js +0 -34
  1854. package/dist/src/utils/settings/validation.js +0 -192
  1855. package/dist/src/utils/settings/validationTips.js +0 -111
  1856. package/dist/src/utils/shell/bashProvider.js +0 -202
  1857. package/dist/src/utils/shell/outputLimits.js +0 -7
  1858. package/dist/src/utils/shell/powershellDetection.js +0 -96
  1859. package/dist/src/utils/shell/powershellProvider.js +0 -104
  1860. package/dist/src/utils/shell/prefix.js +0 -246
  1861. package/dist/src/utils/shell/readOnlyCommandValidation.js +0 -1776
  1862. package/dist/src/utils/shell/resolveDefaultShell.js +0 -13
  1863. package/dist/src/utils/shell/shellProvider.js +0 -2
  1864. package/dist/src/utils/shell/shellToolUtils.js +0 -21
  1865. package/dist/src/utils/shell/specPrefix.js +0 -198
  1866. package/dist/src/utils/shellConfig.js +0 -136
  1867. package/dist/src/utils/sideQuery.js +0 -195
  1868. package/dist/src/utils/sideQuestion.js +0 -121
  1869. package/dist/src/utils/signal.js +0 -34
  1870. package/dist/src/utils/sinks.js +0 -15
  1871. package/dist/src/utils/skills/skillChangeDetector.js +0 -264
  1872. package/dist/src/utils/slashCommandParsing.js +0 -46
  1873. package/dist/src/utils/sleep.js +0 -72
  1874. package/dist/src/utils/sliceAnsi.js +0 -74
  1875. package/dist/src/utils/slowOperations.js +0 -323
  1876. package/dist/src/utils/standaloneAgent.js +0 -20
  1877. package/dist/src/utils/startupProfiler.js +0 -158
  1878. package/dist/src/utils/staticRender.js +0 -103
  1879. package/dist/src/utils/stats.js +0 -802
  1880. package/dist/src/utils/statsCache.js +0 -330
  1881. package/dist/src/utils/status.js +0 -544
  1882. package/dist/src/utils/statusNoticeDefinitions.js +0 -112
  1883. package/dist/src/utils/statusNoticeHelpers.js +0 -15
  1884. package/dist/src/utils/stream.js +0 -73
  1885. package/dist/src/utils/streamJsonStdoutGuard.js +0 -107
  1886. package/dist/src/utils/streamlinedTransform.js +0 -162
  1887. package/dist/src/utils/stringUtils.js +0 -202
  1888. package/dist/src/utils/subprocessEnv.js +0 -87
  1889. package/dist/src/utils/suggestions/commandSuggestions.js +0 -458
  1890. package/dist/src/utils/suggestions/directoryCompletion.js +0 -191
  1891. package/dist/src/utils/suggestions/shellHistoryCompletion.js +0 -95
  1892. package/dist/src/utils/suggestions/skillUsageTracking.js +0 -50
  1893. package/dist/src/utils/suggestions/slackChannelSuggestions.js +0 -169
  1894. package/dist/src/utils/swarm/It2SetupPrompt.js +0 -386
  1895. package/dist/src/utils/swarm/backends/ITermBackend.js +0 -276
  1896. package/dist/src/utils/swarm/backends/InProcessBackend.js +0 -237
  1897. package/dist/src/utils/swarm/backends/PaneBackendExecutor.js +0 -250
  1898. package/dist/src/utils/swarm/backends/TmuxBackend.js +0 -574
  1899. package/dist/src/utils/swarm/backends/detection.js +0 -112
  1900. package/dist/src/utils/swarm/backends/it2Setup.js +0 -185
  1901. package/dist/src/utils/swarm/backends/registry.js +0 -369
  1902. package/dist/src/utils/swarm/backends/teammateModeSnapshot.js +0 -68
  1903. package/dist/src/utils/swarm/backends/types.js +0 -9
  1904. package/dist/src/utils/swarm/constants.js +0 -29
  1905. package/dist/src/utils/swarm/inProcessRunner.js +0 -1021
  1906. package/dist/src/utils/swarm/leaderPermissionBridge.js +0 -31
  1907. package/dist/src/utils/swarm/permissionSync.js +0 -667
  1908. package/dist/src/utils/swarm/reconnection.js +0 -82
  1909. package/dist/src/utils/swarm/spawnInProcess.js +0 -218
  1910. package/dist/src/utils/swarm/spawnUtils.js +0 -123
  1911. package/dist/src/utils/swarm/teamHelpers.js +0 -484
  1912. package/dist/src/utils/swarm/teammateInit.js +0 -87
  1913. package/dist/src/utils/swarm/teammateLayoutManager.js +0 -82
  1914. package/dist/src/utils/swarm/teammateModel.js +0 -9
  1915. package/dist/src/utils/swarm/teammatePromptAddendum.js +0 -17
  1916. package/dist/src/utils/systemDirectories.js +0 -51
  1917. package/dist/src/utils/systemPrompt.js +0 -90
  1918. package/dist/src/utils/systemPromptType.js +0 -9
  1919. package/dist/src/utils/systemTheme.js +0 -108
  1920. package/dist/src/utils/systemThemeWatcher.js +0 -16
  1921. package/dist/src/utils/taggedId.js +0 -49
  1922. package/dist/src/utils/task/TaskOutput.js +0 -320
  1923. package/dist/src/utils/task/diskOutput.js +0 -387
  1924. package/dist/src/utils/task/framework.js +0 -236
  1925. package/dist/src/utils/task/outputFormatting.js +0 -24
  1926. package/dist/src/utils/task/sdkProgress.js +0 -24
  1927. package/dist/src/utils/tasks.js +0 -672
  1928. package/dist/src/utils/teamDiscovery.js +0 -48
  1929. package/dist/src/utils/teamMemoryOps.js +0 -67
  1930. package/dist/src/utils/teammate.js +0 -237
  1931. package/dist/src/utils/teammateContext.js +0 -56
  1932. package/dist/src/utils/teammateMailbox.js +0 -793
  1933. package/dist/src/utils/telemetry/betaSessionTracing.js +0 -371
  1934. package/dist/src/utils/telemetry/bigqueryExporter.js +0 -178
  1935. package/dist/src/utils/telemetry/events.js +0 -57
  1936. package/dist/src/utils/telemetry/instrumentation.js +0 -617
  1937. package/dist/src/utils/telemetry/logger.js +0 -25
  1938. package/dist/src/utils/telemetry/perfettoTracing.js +0 -882
  1939. package/dist/src/utils/telemetry/pluginTelemetry.js +0 -157
  1940. package/dist/src/utils/telemetry/sessionTracing.js +0 -693
  1941. package/dist/src/utils/telemetry/skillLoadedEvent.js +0 -26
  1942. package/dist/src/utils/telemetryAttributes.js +0 -57
  1943. package/dist/src/utils/teleport/api.js +0 -299
  1944. package/dist/src/utils/teleport/environmentSelection.js +0 -55
  1945. package/dist/src/utils/teleport/environments.js +0 -84
  1946. package/dist/src/utils/teleport/gitBundle.js +0 -192
  1947. package/dist/src/utils/teleport.js +0 -1041
  1948. package/dist/src/utils/tempfile.js +0 -26
  1949. package/dist/src/utils/terminal.js +0 -105
  1950. package/dist/src/utils/terminalPanel.js +0 -155
  1951. package/dist/src/utils/textHighlighting.js +0 -113
  1952. package/dist/src/utils/theme.js +0 -525
  1953. package/dist/src/utils/thinking.js +0 -130
  1954. package/dist/src/utils/timeouts.js +0 -35
  1955. package/dist/src/utils/tmuxSocket.js +0 -373
  1956. package/dist/src/utils/todo/types.js +0 -9
  1957. package/dist/src/utils/tokenBudget.js +0 -62
  1958. package/dist/src/utils/tokens.js +0 -223
  1959. package/dist/src/utils/toolErrors.js +0 -101
  1960. package/dist/src/utils/toolPool.js +0 -63
  1961. package/dist/src/utils/toolResultStorage.js +0 -769
  1962. package/dist/src/utils/toolSchemaCache.js +0 -7
  1963. package/dist/src/utils/toolSearch.js +0 -551
  1964. package/dist/src/utils/transcriptSearch.js +0 -200
  1965. package/dist/src/utils/treeify.js +0 -111
  1966. package/dist/src/utils/truncate.js +0 -164
  1967. package/dist/src/utils/udsClient.js +0 -16
  1968. package/dist/src/utils/udsMessaging.js +0 -16
  1969. package/dist/src/utils/ultraplan/ccrSession.js +0 -264
  1970. package/dist/src/utils/ultraplan/keyword.js +0 -122
  1971. package/dist/src/utils/ultraplan/prompt.txt +0 -1
  1972. package/dist/src/utils/unaryLogging.js +0 -16
  1973. package/dist/src/utils/undercover.js +0 -89
  1974. package/dist/src/utils/user.js +0 -138
  1975. package/dist/src/utils/userAgent.js +0 -13
  1976. package/dist/src/utils/userPromptKeywords.js +0 -21
  1977. package/dist/src/utils/uuid.js +0 -22
  1978. package/dist/src/utils/warningHandler.js +0 -97
  1979. package/dist/src/utils/which.js +0 -75
  1980. package/dist/src/utils/windowsPaths.js +0 -146
  1981. package/dist/src/utils/withResolvers.js +0 -13
  1982. package/dist/src/utils/words.js +0 -793
  1983. package/dist/src/utils/workloadContext.js +0 -42
  1984. package/dist/src/utils/worktree.js +0 -1142
  1985. package/dist/src/utils/worktreeModeEnabled.js +0 -11
  1986. package/dist/src/utils/xdg.js +0 -52
  1987. package/dist/src/utils/xml.js +0 -15
  1988. package/dist/src/utils/yaml.js +0 -16
  1989. package/dist/src/utils/zodToJsonSchema.js +0 -19
  1990. package/dist/src/vim/motions.js +0 -73
  1991. package/dist/src/vim/operators.js +0 -401
  1992. package/dist/src/vim/textObjects.js +0 -153
  1993. package/dist/src/vim/transitions.js +0 -340
  1994. package/dist/src/vim/types.js +0 -93
  1995. package/dist/src/voice/voiceModeEnabled.js +0 -48
  1996. package/dist/src/whatsapp/bridge.js +0 -267
  1997. package/dist/src/whatsapp/config.js +0 -128
  1998. package/dist/src/whatsapp/markdown.js +0 -37
  1999. package/dist/src/whatsapp/mirror.js +0 -74
  2000. package/dist/src/whatsapp/session.js +0 -142
@@ -1,4434 +0,0 @@
1
- import { feature } from '../recovery/bunBundleShim.js';
2
- import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { createRequire } from 'module';
4
- const require = createRequire(import.meta.url);
5
- import { c as _c } from "react/compiler-runtime";
6
- // biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
7
- import { spawnSync } from 'child_process';
8
- import { snapshotOutputTokensForTurn, getCurrentTurnTokenBudget, getTurnOutputTokens, getBudgetContinuationCount, getTotalInputTokens } from '../bootstrap/state.js';
9
- import { parseTokenBudget } from '../utils/tokenBudget.js';
10
- import { count } from '../utils/array.js';
11
- import { dirname, join } from 'path';
12
- import { tmpdir } from 'os';
13
- import figures from 'figures';
14
- // eslint-disable-next-line custom-rules/prefer-use-keybindings -- / n N Esc [ v are bare letters in transcript modal context, same class as g/G/j/k in ScrollKeybindingHandler
15
- import { useInput } from '../ink.js';
16
- import { useSearchInput } from '../hooks/useSearchInput.js';
17
- import { useTerminalSize } from '../hooks/useTerminalSize.js';
18
- import { useSearchHighlight } from '../ink/hooks/use-search-highlight.js';
19
- import { renderMessagesToPlainText } from '../utils/exportRenderer.js';
20
- import { openFileInExternalEditor } from '../utils/editor.js';
21
- import { writeFile } from 'fs/promises';
22
- import { Box, Text, useStdin, useTheme, useTerminalFocus, useTerminalTitle, useTabStatus } from '../ink.js';
23
- import { CostThresholdDialog } from '../components/CostThresholdDialog.js';
24
- import { IdleReturnDialog } from '../components/IdleReturnDialog.js';
25
- import * as React from 'react';
26
- import { useEffect, useMemo, useRef, useState, useCallback, useDeferredValue, useLayoutEffect } from 'react';
27
- import { useNotifications } from '../context/notifications.js';
28
- import { sendNotification } from '../services/notifier.js';
29
- import { startPreventSleep, stopPreventSleep } from '../services/preventSleep.js';
30
- import { useTerminalNotification } from '../ink/useTerminalNotification.js';
31
- import { hasCursorUpViewportYankBug } from '../ink/terminal.js';
32
- import { createFileStateCacheWithSizeLimit, mergeFileStateCaches, READ_FILE_STATE_CACHE_SIZE } from '../utils/fileStateCache.js';
33
- import { updateLastInteractionTime, getLastInteractionTime, getOriginalCwd, getProjectRoot, getSessionId, switchSession, setCostStateForRestore, getTurnHookDurationMs, getTurnHookCount, resetTurnHookDuration, getTurnToolDurationMs, getTurnToolCount, resetTurnToolDuration, getTurnClassifierDurationMs, getTurnClassifierCount, resetTurnClassifierDuration } from '../bootstrap/state.js';
34
- import { asSessionId, asAgentId } from '../types/ids.js';
35
- import { logForDebugging } from '../utils/debug.js';
36
- import { QueryGuard } from '../utils/QueryGuard.js';
37
- import { isEnvTruthy } from '../utils/envUtils.js';
38
- import { formatTokens, truncateToWidth } from '../utils/format.js';
39
- import { consumeEarlyInput } from '../utils/earlyInput.js';
40
- import { setMemberActive } from '../utils/swarm/teamHelpers.js';
41
- import { isSwarmWorker, generateSandboxRequestId, sendSandboxPermissionRequestViaMailbox, sendSandboxPermissionResponseViaMailbox } from '../utils/swarm/permissionSync.js';
42
- import { registerSandboxPermissionCallback } from '../hooks/useSwarmPermissionPoller.js';
43
- import { getTeamName, getAgentName } from '../utils/teammate.js';
44
- import { WorkerPendingPermission } from '../components/permissions/WorkerPendingPermission.js';
45
- import { injectUserMessageToTeammate, getAllInProcessTeammateTasks } from '../tasks/InProcessTeammateTask/InProcessTeammateTask.js';
46
- import { isLocalAgentTask, queuePendingMessage, appendMessageToLocalAgent } from '../tasks/LocalAgentTask/LocalAgentTask.js';
47
- import { registerLeaderToolUseConfirmQueue, unregisterLeaderToolUseConfirmQueue, registerLeaderSetToolPermissionContext, unregisterLeaderSetToolPermissionContext } from '../utils/swarm/leaderPermissionBridge.js';
48
- import { endInteractionSpan } from '../utils/telemetry/sessionTracing.js';
49
- import { useLogMessages } from '../hooks/useLogMessages.js';
50
- import { useReplBridge } from '../hooks/useReplBridge.js';
51
- import { useTelegramMirror } from '../hooks/useTelegramMirror.js';
52
- import { useWhatsAppMirror } from '../hooks/useWhatsAppMirror.js';
53
- import { getCommandName, isCommandEnabled } from '../commands.js';
54
- import { MessageSelector, selectableUserMessagesFilter, messagesAfterAreOnlySynthetic } from '../components/MessageSelector.js';
55
- import { useIdeLogging } from '../hooks/useIdeLogging.js';
56
- import { PermissionRequest } from '../components/permissions/PermissionRequest.js';
57
- import { ElicitationDialog } from '../components/mcp/ElicitationDialog.js';
58
- import { PromptDialog } from '../components/hooks/PromptDialog.js';
59
- import PromptInput from '../components/PromptInput/PromptInput.js';
60
- import { PromptInputQueuedCommands } from '../components/PromptInput/PromptInputQueuedCommands.js';
61
- import { useRemoteSession } from '../hooks/useRemoteSession.js';
62
- import { useDirectConnect } from '../hooks/useDirectConnect.js';
63
- import { useSSHSession } from '../hooks/useSSHSession.js';
64
- import { useAssistantHistory } from '../hooks/useAssistantHistory.js';
65
- import { SkillImprovementSurvey } from '../components/SkillImprovementSurvey.js';
66
- import { useSkillImprovementSurvey } from '../hooks/useSkillImprovementSurvey.js';
67
- import { useMoreRight } from '../moreright/useMoreRight.js';
68
- import { SpinnerWithVerb, BriefIdleStatus } from '../components/Spinner.js';
69
- import { getSystemPrompt } from '../constants/prompts.js';
70
- import { buildEffectiveSystemPrompt } from '../utils/systemPrompt.js';
71
- import { getSystemContext, getUserContext } from '../context.js';
72
- import { getMemoryFiles } from '../utils/claudemd.js';
73
- import { startBackgroundHousekeeping } from '../utils/backgroundHousekeeping.js';
74
- import { getTotalCost, saveCurrentSessionCosts, resetCostState, getStoredSessionCosts } from '../cost-tracker.js';
75
- import { useCostSummary } from '../costHook.js';
76
- import { useFpsMetrics } from '../context/fpsMetrics.js';
77
- import { useAfterFirstRender } from '../hooks/useAfterFirstRender.js';
78
- import { useDeferredHookMessages } from '../hooks/useDeferredHookMessages.js';
79
- import { addToHistory, removeLastFromHistory, expandPastedTextRefs, parseReferences } from '../history.js';
80
- import { prependModeCharacterToInput } from '../components/PromptInput/inputModes.js';
81
- import { prependToShellHistoryCache } from '../utils/suggestions/shellHistoryCompletion.js';
82
- import { useApiKeyVerification } from '../hooks/useApiKeyVerification.js';
83
- import { GlobalKeybindingHandlers } from '../hooks/useGlobalKeybindings.js';
84
- import { CommandKeybindingHandlers } from '../hooks/useCommandKeybindings.js';
85
- import { KeybindingSetup } from '../keybindings/KeybindingProviderSetup.js';
86
- import { useShortcutDisplay } from '../keybindings/useShortcutDisplay.js';
87
- import { getShortcutDisplay } from '../keybindings/shortcutFormat.js';
88
- import { CancelRequestHandler } from '../hooks/useCancelRequest.js';
89
- import { useBackgroundTaskNavigation } from '../hooks/useBackgroundTaskNavigation.js';
90
- import { useSwarmInitialization } from '../hooks/useSwarmInitialization.js';
91
- import { useTeammateViewAutoExit } from '../hooks/useTeammateViewAutoExit.js';
92
- import { errorMessage } from '../utils/errors.js';
93
- import { isHumanTurn } from '../utils/messagePredicates.js';
94
- import { logError } from '../utils/log.js';
95
- // Dead code elimination: conditional imports
96
- /* eslint-disable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */
97
- const useVoiceIntegration = feature('VOICE_MODE') ? require('../hooks/useVoiceIntegration.js').useVoiceIntegration : () => ({
98
- stripTrailing: () => 0,
99
- handleKeyEvent: () => { },
100
- resetAnchor: () => { }
101
- });
102
- const VoiceKeybindingHandler = feature('VOICE_MODE') ? require('../hooks/useVoiceIntegration.js').VoiceKeybindingHandler : () => null;
103
- // Frustration detection is ant-only (dogfooding). Conditional require so external
104
- // builds eliminate the module entirely (including its two O(n) useMemos that run
105
- // on every messages change, plus the GrowthBook fetch).
106
- const useFrustrationDetection = "external" === 'ant' ? require('../components/FeedbackSurvey/useFrustrationDetection.js').useFrustrationDetection : () => ({
107
- state: 'closed',
108
- handleTranscriptSelect: () => { }
109
- });
110
- // Ant-only org warning. Conditional require so the org UUID list is
111
- // eliminated from external builds (one UUID is on excluded-strings).
112
- const useAntOrgWarningNotification = "external" === 'ant' ? require('../hooks/notifs/useAntOrgWarningNotification.js').useAntOrgWarningNotification : () => { };
113
- // Dead code elimination: conditional import for coordinator mode
114
- const getCoordinatorUserContext = feature('COORDINATOR_MODE') ? require('../coordinator/coordinatorMode.js').getCoordinatorUserContext : () => ({});
115
- /* eslint-enable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */
116
- import useCanUseTool from '../hooks/useCanUseTool.js';
117
- import { applyPermissionUpdate, applyPermissionUpdates, persistPermissionUpdate } from '../utils/permissions/PermissionUpdate.js';
118
- import { buildPermissionUpdates } from '../components/permissions/ExitPlanModePermissionRequest/ExitPlanModePermissionRequest.js';
119
- import { stripDangerousPermissionsForAutoMode } from '../utils/permissions/permissionSetup.js';
120
- import { getScratchpadDir, isScratchpadEnabled } from '../utils/permissions/filesystem.js';
121
- import { WEB_FETCH_TOOL_NAME } from '../tools/WebFetchTool/prompt.js';
122
- import { SLEEP_TOOL_NAME } from '../tools/SleepTool/prompt.js';
123
- import { clearSpeculativeChecks } from '../tools/BashTool/bashPermissions.js';
124
- import { getGlobalConfig, saveGlobalConfig, getGlobalConfigWriteCount } from '../utils/config.js';
125
- import { hasConsoleBillingAccess } from '../utils/billing.js';
126
- import { logEvent } from '../services/analytics/index.js';
127
- import { getFeatureValue_CACHED_MAY_BE_STALE } from '../services/analytics/growthbook.js';
128
- import { textForResubmit, handleMessageFromStream, isCompactBoundaryMessage, getMessagesAfterCompactBoundary, getContentText, createUserMessage, createAssistantMessage, createTurnDurationMessage, createAgentsKilledMessage, createApiMetricsMessage, createSystemMessage, createCommandInputMessage, formatCommandInputTags } from '../utils/messages.js';
129
- import { generateSessionTitle } from '../utils/sessionTitle.js';
130
- import { BASH_INPUT_TAG, COMMAND_MESSAGE_TAG, COMMAND_NAME_TAG, LOCAL_COMMAND_STDOUT_TAG } from '../constants/xml.js';
131
- import { escapeXml } from '../utils/xml.js';
132
- import { gracefulShutdownSync } from '../utils/gracefulShutdown.js';
133
- import { handlePromptSubmit } from '../utils/handlePromptSubmit.js';
134
- import { useQueueProcessor } from '../hooks/useQueueProcessor.js';
135
- import { useMailboxBridge } from '../hooks/useMailboxBridge.js';
136
- import { queryCheckpoint, logQueryProfileReport } from '../utils/queryProfiler.js';
137
- import { query } from '../query.js';
138
- import { mergeClients, useMergedClients } from '../hooks/useMergedClients.js';
139
- import { getQuerySourceForREPL } from '../utils/promptCategory.js';
140
- import { useMergedTools } from '../hooks/useMergedTools.js';
141
- import { mergeAndFilterTools } from '../utils/toolPool.js';
142
- import { useMergedCommands } from '../hooks/useMergedCommands.js';
143
- import { useSkillsChange } from '../hooks/useSkillsChange.js';
144
- import { useManagePlugins } from '../hooks/useManagePlugins.js';
145
- import { Messages } from '../components/Messages.js';
146
- import { TaskListV2 } from '../components/TaskListV2.js';
147
- import { TeammateViewHeader } from '../components/TeammateViewHeader.js';
148
- import { useTasksV2WithCollapseEffect } from '../hooks/useTasksV2.js';
149
- import { maybeMarkProjectOnboardingComplete } from '../projectOnboardingState.js';
150
- import { randomUUID } from 'crypto';
151
- import { processSessionStartHooks } from '../utils/sessionStart.js';
152
- import { executeSessionEndHooks, getSessionEndHookTimeoutMs } from '../utils/hooks.js';
153
- import { useIdeSelection } from '../hooks/useIdeSelection.js';
154
- import { getTools, assembleToolPool } from '../tools.js';
155
- import { resolveAgentTools } from '../tools/AgentTool/agentToolUtils.js';
156
- import { resumeAgentBackground } from '../tools/AgentTool/resumeAgent.js';
157
- import { useMainLoopModel } from '../hooks/useMainLoopModel.js';
158
- import { useAppState, useSetAppState, useAppStateStore } from '../state/AppState.js';
159
- import { copyPlanForFork, copyPlanForResume, getPlanSlug, setPlanSlug } from '../utils/plans.js';
160
- import { clearSessionMetadata, resetSessionFilePointer, adoptResumedSessionFile, removeTranscriptMessage, restoreSessionMetadata, getCurrentSessionTitle, isEphemeralToolProgress, isLoggableMessage, saveWorktreeState, getAgentTranscript } from '../utils/sessionStorage.js';
161
- import { deserializeMessages } from '../utils/conversationRecovery.js';
162
- import { extractReadFilesFromMessages, extractBashToolsFromMessages } from '../utils/queryHelpers.js';
163
- import { resetMicrocompactState } from '../services/compact/microCompact.js';
164
- import { runPostCompactCleanup } from '../services/compact/postCompactCleanup.js';
165
- import { provisionContentReplacementState, reconstructContentReplacementState } from '../utils/toolResultStorage.js';
166
- import { partialCompactConversation } from '../services/compact/compact.js';
167
- import { fileHistoryMakeSnapshot, fileHistoryRewind, copyFileHistoryForResume, fileHistoryEnabled, fileHistoryHasAnyChanges } from '../utils/fileHistory.js';
168
- import { incrementPromptCount } from '../utils/commitAttribution.js';
169
- import { recordAttributionSnapshot } from '../utils/sessionStorage.js';
170
- import { computeStandaloneAgentContext, restoreAgentFromSession, restoreSessionStateFromLog, restoreWorktreeForResume, exitRestoredWorktree } from '../utils/sessionRestore.js';
171
- import { isBgSession, updateSessionName, updateSessionActivity } from '../utils/concurrentSessions.js';
172
- import { isInProcessTeammateTask } from '../tasks/InProcessTeammateTask/types.js';
173
- import { restoreRemoteAgentTasks } from '../tasks/RemoteAgentTask/RemoteAgentTask.js';
174
- import { useInboxPoller } from '../hooks/useInboxPoller.js';
175
- // Dead code elimination: conditional import for loop mode
176
- /* eslint-disable @typescript-eslint/no-require-imports */
177
- const proactiveModule = feature('PROACTIVE') || feature('KAIROS') ? require('../proactive/index.js') : null;
178
- const PROACTIVE_NO_OP_SUBSCRIBE = (_cb) => () => { };
179
- const PROACTIVE_FALSE = () => false;
180
- const SUGGEST_BG_PR_NOOP = (_p, _n) => false;
181
- const useProactive = feature('PROACTIVE') || feature('KAIROS') ? require('../proactive/useProactive.js').useProactive : null;
182
- const useScheduledTasks = feature('AGENT_TRIGGERS') ? require('../hooks/useScheduledTasks.js').useScheduledTasks : null;
183
- /* eslint-enable @typescript-eslint/no-require-imports */
184
- import { isAgentSwarmsEnabled } from '../utils/agentSwarmsEnabled.js';
185
- import { useTaskListWatcher } from '../hooks/useTaskListWatcher.js';
186
- import { closeOpenDiffs, getConnectedIdeClient } from '../utils/ide.js';
187
- import { useIDEIntegration } from '../hooks/useIDEIntegration.js';
188
- import exit from '../commands/exit/index.js';
189
- import { ExitFlow } from '../components/ExitFlow.js';
190
- import { getCurrentWorktreeSession } from '../utils/worktree.js';
191
- import { popAllEditable, enqueue, getCommandQueue, getCommandQueueLength, removeByFilter } from '../utils/messageQueueManager.js';
192
- import { useCommandQueue } from '../hooks/useCommandQueue.js';
193
- import { SessionBackgroundHint } from '../components/SessionBackgroundHint.js';
194
- import { startBackgroundSession } from '../tasks/LocalMainSessionTask.js';
195
- import { useSessionBackgrounding } from '../hooks/useSessionBackgrounding.js';
196
- import { diagnosticTracker } from '../services/diagnosticTracking.js';
197
- import { handleSpeculationAccept } from '../services/PromptSuggestion/speculation.js';
198
- import { IdeOnboardingDialog } from '../components/IdeOnboardingDialog.js';
199
- import { EffortCallout, shouldShowEffortCallout } from '../components/EffortCallout.js';
200
- import { RemoteCallout } from '../components/RemoteCallout.js';
201
- /* eslint-disable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */
202
- const AntModelSwitchCallout = "external" === 'ant' ? require('../components/AntModelSwitchCallout.js').AntModelSwitchCallout : null;
203
- const shouldShowAntModelSwitch = "external" === 'ant' ? require('../components/AntModelSwitchCallout.js').shouldShowModelSwitchCallout : () => false;
204
- const UndercoverAutoCallout = "external" === 'ant' ? require('../components/UndercoverAutoCallout.js').UndercoverAutoCallout : null;
205
- /* eslint-enable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */
206
- import { activityManager } from '../utils/activityManager.js';
207
- import { createAbortController } from '../utils/abortController.js';
208
- import { MCPConnectionManager } from '../services/mcp/MCPConnectionManager.js';
209
- import { useFeedbackSurvey } from '../components/FeedbackSurvey/useFeedbackSurvey.js';
210
- import { useMemorySurvey } from '../components/FeedbackSurvey/useMemorySurvey.js';
211
- import { usePostCompactSurvey } from '../components/FeedbackSurvey/usePostCompactSurvey.js';
212
- import { FeedbackSurvey } from '../components/FeedbackSurvey/FeedbackSurvey.js';
213
- import { useInstallMessages } from '../hooks/notifs/useInstallMessages.js';
214
- import { useAwaySummary } from '../hooks/useAwaySummary.js';
215
- import { useChromeExtensionNotification } from '../hooks/useChromeExtensionNotification.js';
216
- import { useOfficialMarketplaceNotification } from '../hooks/useOfficialMarketplaceNotification.js';
217
- import { usePromptsFromClaudeInChrome } from '../hooks/usePromptsFromClaudeInChrome.js';
218
- import { getTipToShowOnSpinner, recordShownTip } from '../services/tips/tipScheduler.js';
219
- import { checkAndDisableBypassPermissionsIfNeeded, checkAndDisableAutoModeIfNeeded, useKickOffCheckAndDisableBypassPermissionsIfNeeded, useKickOffCheckAndDisableAutoModeIfNeeded } from '../utils/permissions/bypassPermissionsKillswitch.js';
220
- import { SandboxManager } from '../utils/sandbox/sandbox-adapter.js';
221
- import { SANDBOX_NETWORK_ACCESS_TOOL_NAME } from '../cli/structuredIO.js';
222
- import { useFileHistorySnapshotInit } from '../hooks/useFileHistorySnapshotInit.js';
223
- import { SandboxPermissionRequest } from '../components/permissions/SandboxPermissionRequest.js';
224
- import { SandboxViolationExpandedView } from '../components/SandboxViolationExpandedView.js';
225
- import { useSettingsErrors } from '../hooks/notifs/useSettingsErrors.js';
226
- import { useMcpConnectivityStatus } from '../hooks/notifs/useMcpConnectivityStatus.js';
227
- import { useAutoModeUnavailableNotification } from '../hooks/notifs/useAutoModeUnavailableNotification.js';
228
- import { AUTO_MODE_DESCRIPTION } from '../components/AutoModeOptInDialog.js';
229
- import { useLspInitializationNotification } from '../hooks/notifs/useLspInitializationNotification.js';
230
- import { useLspPluginRecommendation } from '../hooks/useLspPluginRecommendation.js';
231
- import { LspRecommendationMenu } from '../components/LspRecommendation/LspRecommendationMenu.js';
232
- import { useClaudeCodeHintRecommendation } from '../hooks/useClaudeCodeHintRecommendation.js';
233
- import { PluginHintMenu } from '../components/ClaudeCodeHint/PluginHintMenu.js';
234
- import { DesktopUpsellStartup, shouldShowDesktopUpsellStartup } from '../components/DesktopUpsell/DesktopUpsellStartup.js';
235
- import { usePluginInstallationStatus } from '../hooks/notifs/usePluginInstallationStatus.js';
236
- import { usePluginAutoupdateNotification } from '../hooks/notifs/usePluginAutoupdateNotification.js';
237
- import { performStartupChecks } from '../utils/plugins/performStartupChecks.js';
238
- import { UserTextMessage } from '../components/messages/UserTextMessage.js';
239
- import { AwsAuthStatusBox } from '../components/AwsAuthStatusBox.js';
240
- import { useRateLimitWarningNotification } from '../hooks/notifs/useRateLimitWarningNotification.js';
241
- import { useDeprecationWarningNotification } from '../hooks/notifs/useDeprecationWarningNotification.js';
242
- import { useNpmDeprecationNotification } from '../hooks/notifs/useNpmDeprecationNotification.js';
243
- import { useIDEStatusIndicator } from '../hooks/notifs/useIDEStatusIndicator.js';
244
- import { useModelMigrationNotifications } from '../hooks/notifs/useModelMigrationNotifications.js';
245
- import { useCanSwitchToExistingSubscription } from '../hooks/notifs/useCanSwitchToExistingSubscription.js';
246
- import { useTeammateLifecycleNotification } from '../hooks/notifs/useTeammateShutdownNotification.js';
247
- import { useFastModeNotification } from '../hooks/notifs/useFastModeNotification.js';
248
- import { AutoRunIssueNotification, shouldAutoRunIssue, getAutoRunIssueReasonText, getAutoRunCommand } from '../utils/autoRunIssue.js';
249
- import { TungstenLiveMonitor } from '../tools/TungstenTool/TungstenLiveMonitor.js';
250
- /* eslint-disable @typescript-eslint/no-require-imports */
251
- const WebBrowserPanelModule = feature('WEB_BROWSER_TOOL') ? require('../tools/WebBrowserTool/WebBrowserPanel.js') : null;
252
- /* eslint-enable @typescript-eslint/no-require-imports */
253
- import { IssueFlagBanner } from '../components/PromptInput/IssueFlagBanner.js';
254
- import { useIssueFlagBanner } from '../hooks/useIssueFlagBanner.js';
255
- import { CompanionSprite, CompanionFloatingBubble, MIN_COLS_FOR_FULL_SPRITE } from '../buddy/CompanionSprite.js';
256
- import { DevBar } from '../components/DevBar.js';
257
- import { REMOTE_SAFE_COMMANDS } from '../commands.js';
258
- import { FullscreenLayout, useUnseenDivider, computeUnseenDivider } from '../components/FullscreenLayout.js';
259
- import { isFullscreenEnvEnabled, maybeGetTmuxMouseHint, isMouseTrackingEnabled } from '../utils/fullscreen.js';
260
- import { AlternateScreen } from '../ink/components/AlternateScreen.js';
261
- import { ScrollKeybindingHandler } from '../components/ScrollKeybindingHandler.js';
262
- import { useMessageActions, MessageActionsKeybindings, MessageActionsBar } from '../components/messageActions.js';
263
- import { setClipboard } from '../ink/termio/osc.js';
264
- import { createAttachmentMessage, getQueuedCommandAttachments } from '../utils/attachments.js';
265
- // Stable empty array for hooks that accept MCPServerConnection[] — avoids
266
- // creating a new [] literal on every render in remote mode, which would
267
- // cause useEffect dependency changes and infinite re-render loops.
268
- const EMPTY_MCP_CLIENTS = [];
269
- // Stable stub for useAssistantHistory's non-KAIROS branch — avoids a new
270
- // function identity each render, which would break composedOnScroll's memo.
271
- const HISTORY_STUB = {
272
- maybeLoadOlder: (_) => { }
273
- };
274
- // Window after a user-initiated scroll during which type-into-empty does NOT
275
- // repin to bottom. Josh Rosen's workflow: Claude emits long output → scroll
276
- // up to read the start → start typing → before this fix, snapped to bottom.
277
- // https://anthropic.slack.com/archives/C07VBSHV7EV/p1773545449871739
278
- const RECENT_SCROLL_REPIN_WINDOW_MS = 3000;
279
- // Use LRU cache to prevent unbounded memory growth
280
- // 100 files should be sufficient for most coding sessions while preventing
281
- // memory issues when working across many files in large projects
282
- function median(values) {
283
- const sorted = [...values].sort((a, b) => a - b);
284
- const mid = Math.floor(sorted.length / 2);
285
- return sorted.length % 2 === 0 ? Math.round((sorted[mid - 1] + sorted[mid]) / 2) : sorted[mid];
286
- }
287
- /**
288
- * Small component to display transcript mode footer with dynamic keybinding.
289
- * Must be rendered inside KeybindingSetup to access keybinding context.
290
- */
291
- function TranscriptModeFooter(t0) {
292
- const $ = _c(9);
293
- const { showAllInTranscript, virtualScroll, searchBadge, suppressShowAll: t1, status } = t0;
294
- const suppressShowAll = t1 === undefined ? false : t1;
295
- const toggleShortcut = useShortcutDisplay("app:toggleTranscript", "Global", "ctrl+o");
296
- const showAllShortcut = useShortcutDisplay("transcript:toggleShowAll", "Transcript", "ctrl+e");
297
- const t2 = searchBadge ? " \xB7 n/N para navegar" : virtualScroll ? ` · ${figures.arrowUp}${figures.arrowDown} desplazar · inicio/fin extremo` : suppressShowAll ? "" : ` · ${showAllShortcut} para ${showAllInTranscript ? "contraer" : "mostrar todo"}`;
298
- let t3;
299
- if ($[0] !== t2 || $[1] !== toggleShortcut) {
300
- t3 = _jsxs(Text, { dimColor: true, children: ["Mostrando transcripci\u00F3n detallada \u00B7 ", toggleShortcut, " para alternar", t2] });
301
- $[0] = t2;
302
- $[1] = toggleShortcut;
303
- $[2] = t3;
304
- }
305
- else {
306
- t3 = $[2];
307
- }
308
- let t4;
309
- if ($[3] !== searchBadge || $[4] !== status) {
310
- t4 = status ? _jsxs(_Fragment, { children: [_jsx(Box, { flexGrow: 1 }), _jsxs(Text, { children: [status, " "] })] }) : searchBadge ? _jsxs(_Fragment, { children: [_jsx(Box, { flexGrow: 1 }), _jsxs(Text, { dimColor: true, children: [searchBadge.current, "/", searchBadge.count, " "] })] }) : null;
311
- $[3] = searchBadge;
312
- $[4] = status;
313
- $[5] = t4;
314
- }
315
- else {
316
- t4 = $[5];
317
- }
318
- let t5;
319
- if ($[6] !== t3 || $[7] !== t4) {
320
- t5 = _jsxs(Box, { noSelect: true, alignItems: "center", alignSelf: "center", borderTopDimColor: true, borderBottom: false, borderLeft: false, borderRight: false, borderStyle: "single", marginTop: 1, paddingLeft: 2, width: "100%", children: [t3, t4] });
321
- $[6] = t3;
322
- $[7] = t4;
323
- $[8] = t5;
324
- }
325
- else {
326
- t5 = $[8];
327
- }
328
- return t5;
329
- }
330
- /** less-style / bar. 1-row, same border-top styling as TranscriptModeFooter
331
- * so swapping them in the bottom slot doesn't shift ScrollBox height.
332
- * useSearchInput handles readline editing; we report query changes and
333
- * render the counter. Incremental — re-search + highlight per keystroke. */
334
- function TranscriptSearchBar({ jumpRef, count, current, onClose, onCancel, setHighlight, initialQuery }) {
335
- const { query, cursorOffset } = useSearchInput({
336
- isActive: true,
337
- initialQuery,
338
- onExit: () => onClose(query),
339
- onCancel
340
- });
341
- // Index warm-up runs before the query effect so it measures the real
342
- // cost — otherwise setSearchQuery fills the cache first and warm
343
- // reports ~0ms while the user felt the actual lag.
344
- // First / in a transcript session pays the extractSearchText cost.
345
- // Subsequent / return 0 immediately (indexWarmed ref in VML).
346
- // Transcript is frozen at ctrl+o so the cache stays valid.
347
- // Initial 'building' so warmDone is false on mount — the [query] effect
348
- // waits for the warm effect's first resolve instead of racing it. With
349
- // null initial, warmDone would be true on mount → [query] fires →
350
- // setSearchQuery fills cache → warm reports ~0ms while the user felt
351
- // the real lag.
352
- const [indexStatus, setIndexStatus] = React.useState('building');
353
- React.useEffect(() => {
354
- let alive = true;
355
- const warm = jumpRef.current?.warmSearchIndex;
356
- if (!warm) {
357
- setIndexStatus(null); // VML not mounted yet — rare, skip indicator
358
- return;
359
- }
360
- setIndexStatus('building');
361
- warm().then(ms => {
362
- if (!alive)
363
- return;
364
- // <20ms = imperceptible. No point showing "indexed in 3ms".
365
- if (ms < 20) {
366
- setIndexStatus(null);
367
- }
368
- else {
369
- setIndexStatus({
370
- ms
371
- });
372
- setTimeout(() => alive && setIndexStatus(null), 2000);
373
- }
374
- });
375
- return () => {
376
- alive = false;
377
- };
378
- // eslint-disable-next-line react-hooks/exhaustive-deps
379
- }, []); // mount-only: bar opens once per /
380
- // Gate the query effect on warm completion. setHighlight stays instant
381
- // (screen-space overlay, no indexing). setSearchQuery (the scan) waits.
382
- const warmDone = indexStatus !== 'building';
383
- useEffect(() => {
384
- if (!warmDone)
385
- return;
386
- jumpRef.current?.setSearchQuery(query);
387
- setHighlight(query);
388
- // eslint-disable-next-line react-hooks/exhaustive-deps
389
- }, [query, warmDone]);
390
- const off = cursorOffset;
391
- const cursorChar = off < query.length ? query[off] : ' ';
392
- return _jsxs(Box, { borderTopDimColor: true, borderBottom: false, borderLeft: false, borderRight: false, borderStyle: "single", marginTop: 1, paddingLeft: 2, width: "100%",
393
- // applySearchHighlight scans the whole screen buffer. The query
394
- // text rendered here IS on screen — /foo matches its own 'foo' in
395
- // the bar. With no content matches that's the ONLY visible match →
396
- // gets CURRENT → underlined. noSelect makes searchHighlight.ts:76
397
- // skip these cells (same exclusion as gutters). You can't text-
398
- // select the bar either; it's transient chrome, fine.
399
- noSelect: true, children: [_jsx(Text, { children: "/" }), _jsx(Text, { children: query.slice(0, off) }), _jsx(Text, { inverse: true, children: cursorChar }), off < query.length && _jsx(Text, { children: query.slice(off + 1) }), _jsx(Box, { flexGrow: 1 }), indexStatus === 'building' ? _jsx(Text, { dimColor: true, children: "indexando\u2026 " }) : indexStatus ? _jsxs(Text, { dimColor: true, children: ["indexado en ", indexStatus.ms, "ms "] }) : count === 0 && query ? _jsx(Text, { color: "error", children: "sin coincidencias " }) : count > 0 ?
400
- _jsxs(Text, { dimColor: true, children: [current, "/", count, ' '] }) : null] });
401
- }
402
- const TITLE_ANIMATION_FRAMES = ['⠂', '⠐'];
403
- const TITLE_STATIC_PREFIX = '✳';
404
- const TITLE_ANIMATION_INTERVAL_MS = 960;
405
- /**
406
- * Sets the terminal tab title, with an animated prefix glyph while a query
407
- * is running. Isolated from REPL so the 960ms animation tick re-renders only
408
- * this leaf component (which returns null — pure side-effect) instead of the
409
- * entire REPL tree. Before extraction, the tick was ~1 REPL render/sec for
410
- * the duration of every turn, dragging PromptInput and friends along.
411
- */
412
- function AnimatedTerminalTitle(t0) {
413
- const $ = _c(6);
414
- const { isAnimating, title, disabled, noPrefix } = t0;
415
- const terminalFocused = useTerminalFocus();
416
- const [frame, setFrame] = useState(0);
417
- let t1;
418
- let t2;
419
- if ($[0] !== disabled || $[1] !== isAnimating || $[2] !== noPrefix || $[3] !== terminalFocused) {
420
- t1 = () => {
421
- if (disabled || noPrefix || !isAnimating || !terminalFocused) {
422
- return;
423
- }
424
- const interval = setInterval(_temp2, TITLE_ANIMATION_INTERVAL_MS, setFrame);
425
- return () => clearInterval(interval);
426
- };
427
- t2 = [disabled, noPrefix, isAnimating, terminalFocused];
428
- $[0] = disabled;
429
- $[1] = isAnimating;
430
- $[2] = noPrefix;
431
- $[3] = terminalFocused;
432
- $[4] = t1;
433
- $[5] = t2;
434
- }
435
- else {
436
- t1 = $[4];
437
- t2 = $[5];
438
- }
439
- useEffect(t1, t2);
440
- const prefix = isAnimating ? TITLE_ANIMATION_FRAMES[frame] ?? TITLE_STATIC_PREFIX : TITLE_STATIC_PREFIX;
441
- useTerminalTitle(disabled ? null : noPrefix ? title : `${prefix} ${title}`);
442
- return null;
443
- }
444
- function _temp2(setFrame_0) {
445
- return setFrame_0(_temp);
446
- }
447
- function _temp(f) {
448
- return (f + 1) % TITLE_ANIMATION_FRAMES.length;
449
- }
450
- export function REPL({ commands: initialCommands, debug, initialTools, initialMessages, pendingHookMessages, initialFileHistorySnapshots, initialContentReplacements, initialAgentName, initialAgentColor, mcpClients: initialMcpClients, dynamicMcpConfig: initialDynamicMcpConfig, autoConnectIdeFlag, strictMcpConfig = false, systemPrompt: customSystemPrompt, appendSystemPrompt, onBeforeQuery, onTurnComplete, disabled = false, mainThreadAgentDefinition: initialMainThreadAgentDefinition, disableSlashCommands = false, taskListId, remoteSessionConfig, directConnectConfig, sshSession, thinkingConfig }) {
451
- const isRemoteSession = !!remoteSessionConfig;
452
- // Env-var gates hoisted to mount-time — isEnvTruthy does toLowerCase+trim+
453
- // includes, and these were on the render path (hot during PageUp spam).
454
- const titleDisabled = useMemo(() => isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_TERMINAL_TITLE), []);
455
- const moreRightEnabled = useMemo(() => "external" === 'ant' && isEnvTruthy(process.env.CLAUDE_MORERIGHT), []);
456
- const disableVirtualScroll = useMemo(() => isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_VIRTUAL_SCROLL), []);
457
- const disableMessageActions = feature('MESSAGE_ACTIONS') ?
458
- // biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
459
- useMemo(() => isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_MESSAGE_ACTIONS), []) : false;
460
- // Log REPL mount/unmount lifecycle
461
- useEffect(() => {
462
- logForDebugging(`[REPL:mount] REPL mounted, disabled=${disabled}`);
463
- return () => logForDebugging(`[REPL:unmount] REPL unmounting`);
464
- }, [disabled]);
465
- // Agent definition is state so /resume can update it mid-session
466
- const [mainThreadAgentDefinition, setMainThreadAgentDefinition] = useState(initialMainThreadAgentDefinition);
467
- const toolPermissionContext = useAppState(s => s.toolPermissionContext);
468
- const verbose = useAppState(s => s.verbose);
469
- const mcp = useAppState(s => s.mcp);
470
- const plugins = useAppState(s => s.plugins);
471
- const agentDefinitions = useAppState(s => s.agentDefinitions);
472
- const fileHistory = useAppState(s => s.fileHistory);
473
- const initialMessage = useAppState(s => s.initialMessage);
474
- const queuedCommands = useCommandQueue();
475
- // feature() is a build-time constant — dead code elimination removes the hook
476
- // call entirely in external builds, so this is safe despite looking conditional.
477
- // These fields contain excluded strings that must not appear in external builds.
478
- const spinnerTip = useAppState(s => s.spinnerTip);
479
- const showExpandedTodos = useAppState(s => s.expandedView) === 'tasks';
480
- const pendingWorkerRequest = useAppState(s => s.pendingWorkerRequest);
481
- const pendingSandboxRequest = useAppState(s => s.pendingSandboxRequest);
482
- const teamContext = useAppState(s => s.teamContext);
483
- const tasks = useAppState(s => s.tasks);
484
- const workerSandboxPermissions = useAppState(s => s.workerSandboxPermissions);
485
- const elicitation = useAppState(s => s.elicitation);
486
- const ultraplanPendingChoice = useAppState(s => s.ultraplanPendingChoice);
487
- const ultraplanLaunchPending = useAppState(s => s.ultraplanLaunchPending);
488
- const viewingAgentTaskId = useAppState(s => s.viewingAgentTaskId);
489
- const setAppState = useSetAppState();
490
- // Bootstrap: retained local_agent that hasn't loaded disk yet → read
491
- // sidechain JSONL and UUID-merge with whatever stream has appended so far.
492
- // Stream appends immediately on retain (no defer); bootstrap fills the
493
- // prefix. Disk-write-before-yield means live is always a suffix of disk.
494
- const viewedLocalAgent = viewingAgentTaskId ? tasks[viewingAgentTaskId] : undefined;
495
- const needsBootstrap = isLocalAgentTask(viewedLocalAgent) && viewedLocalAgent.retain && !viewedLocalAgent.diskLoaded;
496
- useEffect(() => {
497
- if (!viewingAgentTaskId || !needsBootstrap)
498
- return;
499
- const taskId = viewingAgentTaskId;
500
- void getAgentTranscript(asAgentId(taskId)).then(result => {
501
- setAppState(prev => {
502
- const t = prev.tasks[taskId];
503
- if (!isLocalAgentTask(t) || t.diskLoaded || !t.retain)
504
- return prev;
505
- const live = t.messages ?? [];
506
- const liveUuids = new Set(live.map(m => m.uuid));
507
- const diskOnly = result ? result.messages.filter(m => !liveUuids.has(m.uuid)) : [];
508
- return {
509
- ...prev,
510
- tasks: {
511
- ...prev.tasks,
512
- [taskId]: {
513
- ...t,
514
- messages: [...diskOnly, ...live],
515
- diskLoaded: true
516
- }
517
- }
518
- };
519
- });
520
- });
521
- }, [viewingAgentTaskId, needsBootstrap, setAppState]);
522
- const store = useAppStateStore();
523
- const terminal = useTerminalNotification();
524
- const mainLoopModel = useMainLoopModel();
525
- // Note: standaloneAgentContext is initialized in main.tsx (via initialState) or
526
- // ResumeConversation.tsx (via setAppState before rendering REPL) to avoid
527
- // useEffect-based state initialization on mount (per CLAUDE.md guidelines)
528
- // Local state for commands (hot-reloadable when skill files change)
529
- const [localCommands, setLocalCommands] = useState(initialCommands);
530
- // Watch for skill file changes and reload all commands
531
- useSkillsChange(isRemoteSession ? undefined : getProjectRoot(), setLocalCommands);
532
- // Track proactive mode for tools dependency - SleepTool filters by proactive state
533
- const proactiveActive = React.useSyncExternalStore(proactiveModule?.subscribeToProactiveChanges ?? PROACTIVE_NO_OP_SUBSCRIBE, proactiveModule?.isProactiveActive ?? PROACTIVE_FALSE);
534
- // BriefTool.isEnabled() reads getUserMsgOptIn() from bootstrap state, which
535
- // /brief flips mid-session alongside isBriefOnly. The memo below needs a
536
- // React-visible dep to re-run getTools() when that happens; isBriefOnly is
537
- // the AppState mirror that triggers the re-render. Without this, toggling
538
- // /brief mid-session leaves the stale tool list (no SendUserMessage) and
539
- // the model emits plain text the brief filter hides.
540
- const isBriefOnly = useAppState(s => s.isBriefOnly);
541
- const localTools = useMemo(() => getTools(toolPermissionContext), [toolPermissionContext, proactiveActive, isBriefOnly]);
542
- useKickOffCheckAndDisableBypassPermissionsIfNeeded();
543
- useKickOffCheckAndDisableAutoModeIfNeeded();
544
- const [dynamicMcpConfig, setDynamicMcpConfig] = useState(initialDynamicMcpConfig);
545
- const onChangeDynamicMcpConfig = useCallback((config) => {
546
- setDynamicMcpConfig(config);
547
- }, [setDynamicMcpConfig]);
548
- const [screen, setScreen] = useState('prompt');
549
- const [showAllInTranscript, setShowAllInTranscript] = useState(false);
550
- // [ forces the dump-to-scrollback path inside transcript mode. Separate
551
- // from CLAUDE_CODE_NO_FLICKER=0 (which is process-lifetime) — this is
552
- // ephemeral, reset on transcript exit. Diagnostic escape hatch so
553
- // terminal/tmux native cmd-F can search the full flat render.
554
- const [dumpMode, setDumpMode] = useState(false);
555
- // v-for-editor render progress. Inline in the footer — notifications
556
- // render inside PromptInput which isn't mounted in transcript.
557
- const [editorStatus, setEditorStatus] = useState('');
558
- // Incremented on transcript exit. Async v-render captures this at start;
559
- // each status write no-ops if stale (user left transcript mid-render —
560
- // the stable setState would otherwise stamp a ghost toast into the next
561
- // session). Also clears any pending 4s auto-clear.
562
- const editorGenRef = useRef(0);
563
- const editorTimerRef = useRef(undefined);
564
- const editorRenderingRef = useRef(false);
565
- const { addNotification, removeNotification } = useNotifications();
566
- // eslint-disable-next-line prefer-const
567
- let trySuggestBgPRIntercept = SUGGEST_BG_PR_NOOP;
568
- const mcpClients = useMergedClients(initialMcpClients, mcp.clients);
569
- // IDE integration
570
- const [ideSelection, setIDESelection] = useState(undefined);
571
- const [ideToInstallExtension, setIDEToInstallExtension] = useState(null);
572
- const [ideInstallationStatus, setIDEInstallationStatus] = useState(null);
573
- const [showIdeOnboarding, setShowIdeOnboarding] = useState(false);
574
- // Dead code elimination: model switch callout state (ant-only)
575
- const [showModelSwitchCallout, setShowModelSwitchCallout] = useState(() => {
576
- if ("external" === 'ant') {
577
- return shouldShowAntModelSwitch();
578
- }
579
- return false;
580
- });
581
- const [showEffortCallout, setShowEffortCallout] = useState(() => shouldShowEffortCallout(mainLoopModel));
582
- const showRemoteCallout = useAppState(s => s.showRemoteCallout);
583
- const [showDesktopUpsellStartup, setShowDesktopUpsellStartup] = useState(() => shouldShowDesktopUpsellStartup());
584
- // notifications
585
- useModelMigrationNotifications();
586
- useCanSwitchToExistingSubscription();
587
- useIDEStatusIndicator({
588
- ideSelection,
589
- mcpClients,
590
- ideInstallationStatus
591
- });
592
- useMcpConnectivityStatus({
593
- mcpClients
594
- });
595
- useAutoModeUnavailableNotification();
596
- usePluginInstallationStatus();
597
- usePluginAutoupdateNotification();
598
- useSettingsErrors();
599
- useRateLimitWarningNotification(mainLoopModel);
600
- useFastModeNotification();
601
- useDeprecationWarningNotification(mainLoopModel);
602
- useNpmDeprecationNotification();
603
- useAntOrgWarningNotification();
604
- useInstallMessages();
605
- useChromeExtensionNotification();
606
- useOfficialMarketplaceNotification();
607
- useLspInitializationNotification();
608
- useTeammateLifecycleNotification();
609
- const { recommendation: lspRecommendation, handleResponse: handleLspResponse } = useLspPluginRecommendation();
610
- const { recommendation: hintRecommendation, handleResponse: handleHintResponse } = useClaudeCodeHintRecommendation();
611
- // Memoize the combined initial tools array to prevent reference changes
612
- const combinedInitialTools = useMemo(() => {
613
- return [...localTools, ...initialTools];
614
- }, [localTools, initialTools]);
615
- // Initialize plugin management
616
- useManagePlugins({
617
- enabled: !isRemoteSession
618
- });
619
- const tasksV2 = useTasksV2WithCollapseEffect();
620
- // Start background plugin installations
621
- // SECURITY: This code is guaranteed to run ONLY after the "trust this folder" dialog
622
- // has been confirmed by the user. The trust dialog is shown in cli.tsx (line ~387)
623
- // before the REPL component is rendered. The dialog blocks execution until the user
624
- // accepts, and only then is the REPL component mounted and this effect runs.
625
- // This ensures that plugin installations from repository and user settings only
626
- // happen after explicit user consent to trust the current working directory.
627
- useEffect(() => {
628
- if (isRemoteSession)
629
- return;
630
- void performStartupChecks(setAppState);
631
- }, [setAppState, isRemoteSession]);
632
- // Allow Claude in Chrome MCP to send prompts through MCP notifications
633
- // and sync permission mode changes to the Chrome extension
634
- usePromptsFromClaudeInChrome(isRemoteSession ? EMPTY_MCP_CLIENTS : mcpClients, toolPermissionContext.mode);
635
- // Initialize swarm features: teammate hooks and context
636
- // Handles both fresh spawns and resumed teammate sessions
637
- useSwarmInitialization(setAppState, initialMessages, {
638
- enabled: !isRemoteSession
639
- });
640
- const mergedTools = useMergedTools(combinedInitialTools, mcp.tools, toolPermissionContext);
641
- // Apply agent tool restrictions if mainThreadAgentDefinition is set
642
- const { tools, allowedAgentTypes } = useMemo(() => {
643
- if (!mainThreadAgentDefinition) {
644
- return {
645
- tools: mergedTools,
646
- allowedAgentTypes: undefined
647
- };
648
- }
649
- const resolved = resolveAgentTools(mainThreadAgentDefinition, mergedTools, false, true);
650
- return {
651
- tools: resolved.resolvedTools,
652
- allowedAgentTypes: resolved.allowedAgentTypes
653
- };
654
- }, [mainThreadAgentDefinition, mergedTools]);
655
- // Merge commands from local state, plugins, and MCP
656
- const commandsWithPlugins = useMergedCommands(localCommands, plugins.commands);
657
- const mergedCommands = useMergedCommands(commandsWithPlugins, mcp.commands);
658
- // Filter out all commands if disableSlashCommands is true
659
- const commands = useMemo(() => disableSlashCommands ? [] : mergedCommands, [disableSlashCommands, mergedCommands]);
660
- useIdeLogging(isRemoteSession ? EMPTY_MCP_CLIENTS : mcp.clients);
661
- useIdeSelection(isRemoteSession ? EMPTY_MCP_CLIENTS : mcp.clients, setIDESelection);
662
- const [streamMode, setStreamMode] = useState('responding');
663
- // Ref mirror so onSubmit can read the latest value without adding
664
- // streamMode to its deps. streamMode flips between
665
- // requesting/responding/tool-use ~10x per turn during streaming; having it
666
- // in onSubmit's deps was recreating onSubmit on every flip, which
667
- // cascaded into PromptInput prop churn and downstream useCallback/useMemo
668
- // invalidation. The only consumers inside callbacks are debug logging and
669
- // telemetry (handlePromptSubmit.ts), so a stale-by-one-render value is
670
- // harmless — but ref mirrors sync on every render anyway so it's fresh.
671
- const streamModeRef = useRef(streamMode);
672
- streamModeRef.current = streamMode;
673
- const [streamingToolUses, setStreamingToolUses] = useState([]);
674
- const [streamingThinking, setStreamingThinking] = useState(null);
675
- // Auto-hide streaming thinking after 30 seconds of being completed
676
- useEffect(() => {
677
- if (streamingThinking && !streamingThinking.isStreaming && streamingThinking.streamingEndedAt) {
678
- const elapsed = Date.now() - streamingThinking.streamingEndedAt;
679
- const remaining = 30000 - elapsed;
680
- if (remaining > 0) {
681
- const timer = setTimeout(setStreamingThinking, remaining, null);
682
- return () => clearTimeout(timer);
683
- }
684
- else {
685
- setStreamingThinking(null);
686
- }
687
- }
688
- }, [streamingThinking]);
689
- const [abortController, setAbortController] = useState(null);
690
- // Ref that always points to the current abort controller, used by the
691
- // REPL bridge to abort the active query when a remote interrupt arrives.
692
- const abortControllerRef = useRef(null);
693
- abortControllerRef.current = abortController;
694
- // Ref for the bridge result callback — set after useReplBridge initializes,
695
- // read in the onQuery finally block to notify mobile clients that a turn ended.
696
- const sendBridgeResultRef = useRef(() => { });
697
- // Ref for the synchronous restore callback — set after restoreMessageSync is
698
- // defined, read in the onQuery finally block for auto-restore on interrupt.
699
- const restoreMessageSyncRef = useRef(() => { });
700
- // Ref to the fullscreen layout's scroll box for keyboard scrolling.
701
- // Null when fullscreen mode is disabled (ref never attached).
702
- const scrollRef = useRef(null);
703
- // Separate ref for the modal slot's inner ScrollBox — passed through
704
- // FullscreenLayout → ModalContext so Tabs can attach it to its own
705
- // ScrollBox for tall content (e.g. /status's MCP-server list). NOT
706
- // keyboard-driven — ScrollKeybindingHandler stays on the outer ref so
707
- // PgUp/PgDn/wheel always scroll the transcript behind the modal.
708
- // Plumbing kept for future modal-scroll wiring.
709
- const modalScrollRef = useRef(null);
710
- // Timestamp of the last user-initiated scroll (wheel, PgUp/PgDn, ctrl+u,
711
- // End/Home, G, drag-to-scroll). Stamped in composedOnScroll — the single
712
- // chokepoint ScrollKeybindingHandler calls for every user scroll action.
713
- // Programmatic scrolls (repinScroll's scrollToBottom, sticky auto-follow)
714
- // do NOT go through composedOnScroll, so they don't stamp this. Ref not
715
- // state: no re-render on every wheel tick.
716
- const lastUserScrollTsRef = useRef(0);
717
- // Synchronous state machine for the query lifecycle. Replaces the
718
- // error-prone dual-state pattern where isLoading (React state, async
719
- // batched) and isQueryRunning (ref, sync) could desync. See QueryGuard.ts.
720
- const queryGuard = React.useRef(new QueryGuard()).current;
721
- // Subscribe to the guard — true during dispatching or running.
722
- // This is the single source of truth for "is a local query in flight".
723
- const isQueryActive = React.useSyncExternalStore(queryGuard.subscribe, queryGuard.getSnapshot);
724
- // Separate loading flag for operations outside the local query guard:
725
- // remote sessions (useRemoteSession / useDirectConnect) and foregrounded
726
- // background tasks (useSessionBackgrounding). These don't route through
727
- // onQuery / queryGuard, so they need their own spinner-visibility state.
728
- // Initialize true if remote mode with initial prompt (CCR processing it).
729
- const [isExternalLoading, setIsExternalLoadingRaw] = React.useState(remoteSessionConfig?.hasInitialPrompt ?? false);
730
- // Derived: any loading source active. Read-only — no setter. Local query
731
- // loading is driven by queryGuard (reserve/tryStart/end/cancelReservation),
732
- // external loading by setIsExternalLoading.
733
- const isLoading = isQueryActive || isExternalLoading;
734
- // Elapsed time is computed by SpinnerWithVerb from these refs on each
735
- // animation frame, avoiding a useInterval that re-renders the entire REPL.
736
- const [userInputOnProcessing, setUserInputOnProcessingRaw] = React.useState(undefined);
737
- // messagesRef.current.length at the moment userInputOnProcessing was set.
738
- // The placeholder hides once displayedMessages grows past this — i.e. the
739
- // real user message has landed in the visible transcript.
740
- const userInputBaselineRef = React.useRef(0);
741
- // True while the submitted prompt is being processed but its user message
742
- // hasn't reached setMessages yet. setMessages uses this to keep the
743
- // baseline in sync when unrelated async messages (bridge status, hook
744
- // results, scheduled tasks) land during that window.
745
- const userMessagePendingRef = React.useRef(false);
746
- // Wall-clock time tracking refs for accurate elapsed time calculation
747
- const loadingStartTimeRef = React.useRef(0);
748
- const totalPausedMsRef = React.useRef(0);
749
- const pauseStartTimeRef = React.useRef(null);
750
- const resetTimingRefs = React.useCallback(() => {
751
- loadingStartTimeRef.current = Date.now();
752
- totalPausedMsRef.current = 0;
753
- pauseStartTimeRef.current = null;
754
- }, []);
755
- // Reset timing refs inline when isQueryActive transitions false→true.
756
- // queryGuard.reserve() (in executeUserInput) fires BEFORE processUserInput's
757
- // first await, but the ref reset in onQuery's try block runs AFTER. During
758
- // that gap, React renders the spinner with loadingStartTimeRef=0, computing
759
- // elapsedTimeMs = Date.now() - 0 ≈ 56 years. This inline reset runs on the
760
- // first render where isQueryActive is observed true — the same render that
761
- // first shows the spinner — so the ref is correct by the time the spinner
762
- // reads it. See INC-4549.
763
- const wasQueryActiveRef = React.useRef(false);
764
- if (isQueryActive && !wasQueryActiveRef.current) {
765
- resetTimingRefs();
766
- }
767
- wasQueryActiveRef.current = isQueryActive;
768
- // Wrapper for setIsExternalLoading that resets timing refs on transition
769
- // to true — SpinnerWithVerb reads these for elapsed time, so they must be
770
- // reset for remote sessions / foregrounded tasks too (not just local
771
- // queries, which reset them in onQuery). Without this, a remote-only
772
- // session would show ~56 years elapsed (Date.now() - 0).
773
- const setIsExternalLoading = React.useCallback((value) => {
774
- setIsExternalLoadingRaw(value);
775
- if (value)
776
- resetTimingRefs();
777
- }, [resetTimingRefs]);
778
- // Start time of the first turn that had swarm teammates running
779
- // Used to compute total elapsed time (including teammate execution) for the deferred message
780
- const swarmStartTimeRef = React.useRef(null);
781
- const swarmBudgetInfoRef = React.useRef(undefined);
782
- // Ref to track current focusedInputDialog for use in callbacks
783
- // This avoids stale closures when checking dialog state in timer callbacks
784
- const focusedInputDialogRef = React.useRef(undefined);
785
- // How long after the last keystroke before deferred dialogs are shown
786
- const PROMPT_SUPPRESSION_MS = 1500;
787
- // True when user is actively typing — defers interrupt dialogs so keystrokes
788
- // don't accidentally dismiss or answer a permission prompt the user hasn't read yet.
789
- const [isPromptInputActive, setIsPromptInputActive] = React.useState(false);
790
- const [autoUpdaterResult, setAutoUpdaterResult] = useState(null);
791
- useEffect(() => {
792
- if (autoUpdaterResult?.notifications) {
793
- autoUpdaterResult.notifications.forEach(notification => {
794
- addNotification({
795
- key: 'auto-updater-notification',
796
- text: notification,
797
- priority: 'low'
798
- });
799
- });
800
- }
801
- }, [autoUpdaterResult, addNotification]);
802
- // tmux + fullscreen + `mouse off`: one-time hint that wheel won't scroll.
803
- // We no longer mutate tmux's session-scoped mouse option (it poisoned
804
- // sibling panes); tmux users already know this tradeoff from vim/less.
805
- useEffect(() => {
806
- if (isFullscreenEnvEnabled()) {
807
- void maybeGetTmuxMouseHint().then(hint => {
808
- if (hint) {
809
- addNotification({
810
- key: 'tmux-mouse-hint',
811
- text: hint,
812
- priority: 'low'
813
- });
814
- }
815
- });
816
- }
817
- // eslint-disable-next-line react-hooks/exhaustive-deps
818
- }, []);
819
- const [showUndercoverCallout, setShowUndercoverCallout] = useState(false);
820
- useEffect(() => {
821
- if ("external" === 'ant') {
822
- void (async () => {
823
- // Wait for repo classification to settle (memoized, no-op if primed).
824
- const { isInternalModelRepo } = await import('../utils/commitAttribution.js');
825
- await isInternalModelRepo();
826
- const { shouldShowUndercoverAutoNotice } = await import('../utils/undercover.js');
827
- if (shouldShowUndercoverAutoNotice()) {
828
- setShowUndercoverCallout(true);
829
- }
830
- })();
831
- }
832
- // eslint-disable-next-line react-hooks/exhaustive-deps
833
- }, []);
834
- const [toolJSX, setToolJSXInternal] = useState(null);
835
- // Track local JSX commands separately so tools can't overwrite them.
836
- // This enables "immediate" commands (like /btw) to persist while Claude is processing.
837
- const localJSXCommandRef = useRef(null);
838
- // Wrapper for setToolJSX that preserves local JSX commands (like /btw).
839
- // When a local JSX command is active, we ignore updates from tools
840
- // unless they explicitly set clearLocalJSX: true (from onDone callbacks).
841
- //
842
- // TO ADD A NEW IMMEDIATE COMMAND:
843
- // 1. Set `immediate: true` in the command definition
844
- // 2. Set `isLocalJSXCommand: true` when calling setToolJSX in the command's JSX
845
- // 3. In the onDone callback, use `setToolJSX({ jsx: null, shouldHidePromptInput: false, clearLocalJSX: true })`
846
- // to explicitly clear the overlay when the user dismisses it
847
- const setToolJSX = useCallback((args) => {
848
- // If setting a local JSX command, store it in the ref
849
- if (args?.isLocalJSXCommand) {
850
- const { clearLocalJSX: _, ...rest } = args;
851
- localJSXCommandRef.current = {
852
- ...rest,
853
- isLocalJSXCommand: true
854
- };
855
- setToolJSXInternal(rest);
856
- return;
857
- }
858
- // If there's an active local JSX command in the ref
859
- if (localJSXCommandRef.current) {
860
- // Allow clearing only if explicitly requested (from onDone callbacks)
861
- if (args?.clearLocalJSX) {
862
- localJSXCommandRef.current = null;
863
- setToolJSXInternal(null);
864
- return;
865
- }
866
- // Otherwise, keep the local JSX command visible - ignore tool updates
867
- return;
868
- }
869
- // No active local JSX command, allow any update
870
- if (args?.clearLocalJSX) {
871
- setToolJSXInternal(null);
872
- return;
873
- }
874
- setToolJSXInternal(args);
875
- }, []);
876
- const [toolUseConfirmQueue, setToolUseConfirmQueue] = useState([]);
877
- // Sticky footer JSX registered by permission request components (currently
878
- // only ExitPlanModePermissionRequest). Renders in FullscreenLayout's `bottom`
879
- // slot so response options stay visible while the user scrolls a long plan.
880
- const [permissionStickyFooter, setPermissionStickyFooter] = useState(null);
881
- const [sandboxPermissionRequestQueue, setSandboxPermissionRequestQueue] = useState([]);
882
- const [promptQueue, setPromptQueue] = useState([]);
883
- // Track bridge cleanup functions for sandbox permission requests so the
884
- // local dialog handler can cancel the remote prompt when the local user
885
- // responds first. Keyed by host to support concurrent same-host requests.
886
- const sandboxBridgeCleanupRef = useRef(new Map());
887
- // -- Terminal title management
888
- // Session title (set via /rename or restored on resume) wins over
889
- // the agent name, which wins over the Haiku-extracted topic;
890
- // all fall back to the product name.
891
- const terminalTitleFromRename = useAppState(s => s.settings.terminalTitleFromRename) !== false;
892
- const sessionTitle = terminalTitleFromRename ? getCurrentSessionTitle(getSessionId()) : undefined;
893
- const [haikuTitle, setHaikuTitle] = useState();
894
- // Gates the one-shot Haiku call that generates the tab title. Seeded true
895
- // on resume (initialMessages present) so we don't re-title a resumed
896
- // session from mid-conversation context.
897
- const haikuTitleAttemptedRef = useRef((initialMessages?.length ?? 0) > 0);
898
- const agentTitle = mainThreadAgentDefinition?.agentType;
899
- const terminalTitle = sessionTitle ?? agentTitle ?? haikuTitle ?? 'Context Code';
900
- const isWaitingForApproval = toolUseConfirmQueue.length > 0 || promptQueue.length > 0 || pendingWorkerRequest || pendingSandboxRequest;
901
- // Local-jsx commands (like /plugin, /config) show user-facing dialogs that
902
- // wait for input. Require jsx != null — if the flag is stuck true but jsx
903
- // is null, treat as not-showing so TextInput focus and queue processor
904
- // aren't deadlocked by a phantom overlay.
905
- const isShowingLocalJSXCommand = toolJSX?.isLocalJSXCommand === true && toolJSX?.jsx != null;
906
- const titleIsAnimating = isLoading && !isWaitingForApproval && !isShowingLocalJSXCommand;
907
- // Title animation state lives in <AnimatedTerminalTitle> so the 960ms tick
908
- // doesn't re-render REPL. titleDisabled/terminalTitle are still computed
909
- // here because onQueryImpl reads them (background session description,
910
- // haiku title extraction gate).
911
- // Prevent macOS from sleeping while Claude is working
912
- useEffect(() => {
913
- if (isLoading && !isWaitingForApproval && !isShowingLocalJSXCommand) {
914
- startPreventSleep();
915
- return () => stopPreventSleep();
916
- }
917
- }, [isLoading, isWaitingForApproval, isShowingLocalJSXCommand]);
918
- const sessionStatus = isWaitingForApproval || isShowingLocalJSXCommand ? 'waiting' : isLoading ? 'busy' : 'idle';
919
- const waitingFor = sessionStatus !== 'waiting' ? undefined : toolUseConfirmQueue.length > 0 ? `approve ${toolUseConfirmQueue[0].tool.name}` : pendingWorkerRequest ? 'worker request' : pendingSandboxRequest ? 'sandbox request' : isShowingLocalJSXCommand ? 'dialog open' : 'input needed';
920
- // Push status to the PID file for `claude ps`. Fire-and-forget; ps falls
921
- // back to transcript-tail derivation when this is missing/stale.
922
- useEffect(() => {
923
- if (feature('BG_SESSIONS')) {
924
- void updateSessionActivity({
925
- status: sessionStatus,
926
- waitingFor
927
- });
928
- }
929
- }, [sessionStatus, waitingFor]);
930
- // 3P default: off — OSC 21337 is ant-only while the spec stabilizes.
931
- // Gated so we can roll back if the sidebar indicator conflicts with
932
- // the title spinner in terminals that render both. When the flag is
933
- // on, the user-facing config setting controls whether it's active.
934
- const tabStatusGateEnabled = getFeatureValue_CACHED_MAY_BE_STALE('tengu_terminal_sidebar', false);
935
- const showStatusInTerminalTab = tabStatusGateEnabled && (getGlobalConfig().showStatusInTerminalTab ?? false);
936
- useTabStatus(titleDisabled || !showStatusInTerminalTab ? null : sessionStatus);
937
- // Register the leader's setToolUseConfirmQueue for in-process teammates
938
- useEffect(() => {
939
- registerLeaderToolUseConfirmQueue(setToolUseConfirmQueue);
940
- return () => unregisterLeaderToolUseConfirmQueue();
941
- }, [setToolUseConfirmQueue]);
942
- const [messages, rawSetMessages] = useState(initialMessages ?? []);
943
- const messagesRef = useRef(messages);
944
- // Stores the willowMode variant that was shown (or false if no hint shown).
945
- // Captured at hint_shown time so hint_converted telemetry reports the same
946
- // variant — the GrowthBook value shouldn't change mid-session, but reading
947
- // it once guarantees consistency between the paired events.
948
- const idleHintShownRef = useRef(false);
949
- // Wrap setMessages so messagesRef is always current the instant the
950
- // call returns — not when React later processes the batch. Apply the
951
- // updater eagerly against the ref, then hand React the computed value
952
- // (not the function). rawSetMessages batching becomes last-write-wins,
953
- // and the last write is correct because each call composes against the
954
- // already-updated ref. This is the Zustand pattern: ref is source of
955
- // truth, React state is the render projection. Without this, paths
956
- // that queue functional updaters then synchronously read the ref
957
- // (e.g. handleSpeculationAccept → onQuery) see stale data.
958
- const setMessages = useCallback((action) => {
959
- const prev = messagesRef.current;
960
- const next = typeof action === 'function' ? action(messagesRef.current) : action;
961
- messagesRef.current = next;
962
- if (next.length < userInputBaselineRef.current) {
963
- // Shrank (compact/rewind/clear) — clamp so placeholderText's length
964
- // check can't go stale.
965
- userInputBaselineRef.current = 0;
966
- }
967
- else if (next.length > prev.length && userMessagePendingRef.current) {
968
- // Grew while the submitted user message hasn't landed yet. If the
969
- // added messages don't include it (bridge status, hook results,
970
- // scheduled tasks landing async during processUserInputBase), bump
971
- // baseline so the placeholder stays visible. Once the user message
972
- // lands, stop tracking — later additions (assistant stream) should
973
- // not re-show the placeholder.
974
- const delta = next.length - prev.length;
975
- const added = prev.length === 0 || next[0] === prev[0] ? next.slice(-delta) : next.slice(0, delta);
976
- if (added.some(isHumanTurn)) {
977
- userMessagePendingRef.current = false;
978
- }
979
- else {
980
- userInputBaselineRef.current = next.length;
981
- }
982
- }
983
- rawSetMessages(next);
984
- }, []);
985
- // Capture the baseline message count alongside the placeholder text so
986
- // the render can hide it once displayedMessages grows past the baseline.
987
- const setUserInputOnProcessing = useCallback((input) => {
988
- if (input !== undefined) {
989
- userInputBaselineRef.current = messagesRef.current.length;
990
- userMessagePendingRef.current = true;
991
- }
992
- else {
993
- userMessagePendingRef.current = false;
994
- }
995
- setUserInputOnProcessingRaw(input);
996
- }, []);
997
- // Fullscreen: track the unseen-divider position. dividerIndex changes
998
- // only ~twice/scroll-session (first scroll-away + repin). pillVisible
999
- // and stickyPrompt now live in FullscreenLayout — they subscribe to
1000
- // ScrollBox directly so per-frame scroll never re-renders REPL.
1001
- const { dividerIndex, dividerYRef, onScrollAway, onRepin, jumpToNew, shiftDivider } = useUnseenDivider(messages.length);
1002
- if (feature('AWAY_SUMMARY')) {
1003
- // biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
1004
- useAwaySummary(messages, setMessages, isLoading);
1005
- }
1006
- const [cursor, setCursor] = useState(null);
1007
- const cursorNavRef = useRef(null);
1008
- // Memoized so Messages' React.memo holds.
1009
- const unseenDivider = useMemo(() => computeUnseenDivider(messages, dividerIndex),
1010
- // eslint-disable-next-line react-hooks/exhaustive-deps -- length change covers appends; useUnseenDivider's count-drop guard clears dividerIndex on replace/rewind
1011
- [dividerIndex, messages.length]);
1012
- // Re-pin scroll to bottom and clear the unseen-messages baseline. Called
1013
- // on any user-driven return-to-live action (submit, type-into-empty,
1014
- // overlay appear/dismiss).
1015
- const repinScroll = useCallback(() => {
1016
- scrollRef.current?.scrollToBottom();
1017
- onRepin();
1018
- setCursor(null);
1019
- }, [onRepin, setCursor]);
1020
- // Backstop for the submit-handler repin at onSubmit. If a buffered stdin
1021
- // event (wheel/drag) races between handler-fire and state-commit, the
1022
- // handler's scrollToBottom can be undone. This effect fires on the render
1023
- // where the user's message actually lands — tied to React's commit cycle,
1024
- // so it can't race with stdin. Keyed on lastMsg identity (not messages.length)
1025
- // so useAssistantHistory's prepends don't spuriously repin.
1026
- const lastMsg = messages.at(-1);
1027
- const lastMsgIsHuman = lastMsg != null && isHumanTurn(lastMsg);
1028
- useEffect(() => {
1029
- if (lastMsgIsHuman) {
1030
- repinScroll();
1031
- }
1032
- }, [lastMsgIsHuman, lastMsg, repinScroll]);
1033
- // Assistant-chat: lazy-load remote history on scroll-up. No-op unless
1034
- // KAIROS build + config.viewerOnly. feature() is build-time constant so
1035
- // the branch is dead-code-eliminated in non-KAIROS builds (same pattern
1036
- // as useUnseenDivider above).
1037
- const { maybeLoadOlder } = feature('KAIROS') ?
1038
- // biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
1039
- useAssistantHistory({
1040
- config: remoteSessionConfig,
1041
- setMessages,
1042
- scrollRef,
1043
- onPrepend: shiftDivider
1044
- }) : HISTORY_STUB;
1045
- // Compose useUnseenDivider's callbacks with the lazy-load trigger.
1046
- const composedOnScroll = useCallback((sticky, handle) => {
1047
- lastUserScrollTsRef.current = Date.now();
1048
- if (sticky) {
1049
- onRepin();
1050
- }
1051
- else {
1052
- onScrollAway(handle);
1053
- if (feature('KAIROS'))
1054
- maybeLoadOlder(handle);
1055
- // Dismiss the companion bubble on scroll — it's absolute-positioned
1056
- // at bottom-right and covers transcript content. Scrolling = user is
1057
- // trying to read something under it.
1058
- if (feature('BUDDY')) {
1059
- setAppState(prev => prev.companionReaction === undefined ? prev : {
1060
- ...prev,
1061
- companionReaction: undefined
1062
- });
1063
- }
1064
- }
1065
- }, [onRepin, onScrollAway, maybeLoadOlder, setAppState]);
1066
- // Deferred SessionStart hook messages — REPL renders immediately and
1067
- // hook messages are injected when they resolve. awaitPendingHooks()
1068
- // must be called before the first API call so the model sees hook context.
1069
- const awaitPendingHooks = useDeferredHookMessages(pendingHookMessages, setMessages);
1070
- // Deferred messages for the Messages component — renders at transition
1071
- // priority so the reconciler yields every 5ms, keeping input responsive
1072
- // while the expensive message processing pipeline runs.
1073
- const deferredMessages = useDeferredValue(messages);
1074
- const deferredBehind = messages.length - deferredMessages.length;
1075
- if (deferredBehind > 0) {
1076
- logForDebugging(`[useDeferredValue] Messages deferred by ${deferredBehind} (${deferredMessages.length}→${messages.length})`);
1077
- }
1078
- // Frozen state for transcript mode - stores lengths instead of cloning arrays for memory efficiency
1079
- const [frozenTranscriptState, setFrozenTranscriptState] = useState(null);
1080
- // Initialize input with any early input that was captured before REPL was ready.
1081
- // Using lazy initialization ensures cursor offset is set correctly in PromptInput.
1082
- const [inputValue, setInputValueRaw] = useState(() => consumeEarlyInput());
1083
- const inputValueRef = useRef(inputValue);
1084
- inputValueRef.current = inputValue;
1085
- const insertTextRef = useRef(null);
1086
- // Wrap setInputValue to co-locate suppression state updates.
1087
- // Both setState calls happen in the same synchronous context so React
1088
- // batches them into a single render, eliminating the extra render that
1089
- // the previous useEffect → setState pattern caused.
1090
- const setInputValue = useCallback((value) => {
1091
- if (trySuggestBgPRIntercept(inputValueRef.current, value))
1092
- return;
1093
- // In fullscreen mode, typing into an empty prompt re-pins scroll to
1094
- // bottom. Only fires on empty→non-empty so scrolling up to reference
1095
- // something while composing a message doesn't yank the view back on
1096
- // every keystroke. Restores the pre-fullscreen muscle memory of
1097
- // typing to snap back to the end of the conversation.
1098
- // Skipped if the user scrolled within the last 3s — they're actively
1099
- // reading, not lost. lastUserScrollTsRef starts at 0 so the first-
1100
- // ever keypress (no scroll yet) always repins.
1101
- if (inputValueRef.current === '' && value !== '' && Date.now() - lastUserScrollTsRef.current >= RECENT_SCROLL_REPIN_WINDOW_MS) {
1102
- repinScroll();
1103
- }
1104
- // Sync ref immediately (like setMessages) so callers that read
1105
- // inputValueRef before React commits — e.g. the auto-restore finally
1106
- // block's `=== ''` guard — see the fresh value, not the stale render.
1107
- inputValueRef.current = value;
1108
- setInputValueRaw(value);
1109
- setIsPromptInputActive(value.trim().length > 0);
1110
- }, [setIsPromptInputActive, repinScroll, trySuggestBgPRIntercept]);
1111
- // Schedule a timeout to stop suppressing dialogs after the user stops typing.
1112
- // Only manages the timeout — the immediate activation is handled by setInputValue above.
1113
- useEffect(() => {
1114
- if (inputValue.trim().length === 0)
1115
- return;
1116
- const timer = setTimeout(setIsPromptInputActive, PROMPT_SUPPRESSION_MS, false);
1117
- return () => clearTimeout(timer);
1118
- }, [inputValue]);
1119
- const [inputMode, setInputMode] = useState('prompt');
1120
- const [stashedPrompt, setStashedPrompt] = useState();
1121
- // Callback to filter commands based on CCR's available slash commands
1122
- const handleRemoteInit = useCallback((remoteSlashCommands) => {
1123
- const remoteCommandSet = new Set(remoteSlashCommands);
1124
- // Keep commands that CCR lists OR that are in the local-safe set
1125
- setLocalCommands(prev => prev.filter(cmd => remoteCommandSet.has(cmd.name) || REMOTE_SAFE_COMMANDS.has(cmd)));
1126
- }, [setLocalCommands]);
1127
- const [inProgressToolUseIDs, setInProgressToolUseIDs] = useState(new Set());
1128
- const hasInterruptibleToolInProgressRef = useRef(false);
1129
- // Remote session hook - manages WebSocket connection and message handling for --remote mode
1130
- const remoteSession = useRemoteSession({
1131
- config: remoteSessionConfig,
1132
- setMessages,
1133
- setIsLoading: setIsExternalLoading,
1134
- onInit: handleRemoteInit,
1135
- setToolUseConfirmQueue,
1136
- tools: combinedInitialTools,
1137
- setStreamingToolUses,
1138
- setStreamMode,
1139
- setInProgressToolUseIDs
1140
- });
1141
- // Direct connect hook - manages WebSocket to a claude server for `claude connect` mode
1142
- const directConnect = useDirectConnect({
1143
- config: directConnectConfig,
1144
- setMessages,
1145
- setIsLoading: setIsExternalLoading,
1146
- setToolUseConfirmQueue,
1147
- tools: combinedInitialTools
1148
- });
1149
- // SSH session hook - manages ssh child process for `claude ssh` mode.
1150
- // Same callback shape as useDirectConnect; only the transport under the
1151
- // hood differs (ChildProcess stdin/stdout vs WebSocket).
1152
- const sshRemote = useSSHSession({
1153
- session: sshSession,
1154
- setMessages,
1155
- setIsLoading: setIsExternalLoading,
1156
- setToolUseConfirmQueue,
1157
- tools: combinedInitialTools
1158
- });
1159
- // Use whichever remote mode is active
1160
- const activeRemote = sshRemote.isRemoteMode ? sshRemote : directConnect.isRemoteMode ? directConnect : remoteSession;
1161
- const [pastedContents, setPastedContents] = useState({});
1162
- const [submitCount, setSubmitCount] = useState(0);
1163
- // Ref instead of state to avoid triggering React re-renders on every
1164
- // streaming text_delta. The spinner reads this via its animation timer.
1165
- const responseLengthRef = useRef(0);
1166
- // API performance metrics ref for ant-only spinner display (TTFT/OTPS).
1167
- // Accumulates metrics from all API requests in a turn for P50 aggregation.
1168
- const apiMetricsRef = useRef([]);
1169
- const setResponseLength = useCallback((f) => {
1170
- const prev = responseLengthRef.current;
1171
- responseLengthRef.current = f(prev);
1172
- // When content is added (not a compaction reset), update the latest
1173
- // metrics entry so OTPS reflects all content generation activity.
1174
- // Updating lastTokenTime here ensures the denominator includes both
1175
- // streaming time AND subagent execution time, preventing inflation.
1176
- if (responseLengthRef.current > prev) {
1177
- const entries = apiMetricsRef.current;
1178
- if (entries.length > 0) {
1179
- const lastEntry = entries.at(-1);
1180
- lastEntry.lastTokenTime = Date.now();
1181
- lastEntry.endResponseLength = responseLengthRef.current;
1182
- }
1183
- }
1184
- }, []);
1185
- // Streaming text display: set state directly per delta (Ink's 16ms render
1186
- // throttle batches rapid updates). Cleared on message arrival (messages.ts)
1187
- // so displayedMessages switches from deferredMessages to messages atomically.
1188
- const [streamingText, setStreamingText] = useState(null);
1189
- const reducedMotion = useAppState(s => s.settings.prefersReducedMotion) ?? false;
1190
- const showStreamingText = !reducedMotion && !hasCursorUpViewportYankBug();
1191
- const onStreamingText = useCallback((f) => {
1192
- if (!showStreamingText)
1193
- return;
1194
- setStreamingText(f);
1195
- }, [showStreamingText]);
1196
- // Hide the in-progress source line so text streams line-by-line, not
1197
- // char-by-char. lastIndexOf returns -1 when no newline, giving '' → null.
1198
- // Guard on showStreamingText so toggling reducedMotion mid-stream
1199
- // immediately hides the streaming preview.
1200
- const visibleStreamingText = streamingText && showStreamingText ? streamingText.substring(0, streamingText.lastIndexOf('\n') + 1) || null : null;
1201
- const [lastQueryCompletionTime, setLastQueryCompletionTime] = useState(0);
1202
- const [spinnerMessage, setSpinnerMessage] = useState(null);
1203
- const [spinnerColor, setSpinnerColor] = useState(null);
1204
- const [spinnerShimmerColor, setSpinnerShimmerColor] = useState(null);
1205
- const [isMessageSelectorVisible, setIsMessageSelectorVisible] = useState(false);
1206
- const [messageSelectorPreselect, setMessageSelectorPreselect] = useState(undefined);
1207
- const [showCostDialog, setShowCostDialog] = useState(false);
1208
- const [conversationId, setConversationId] = useState(randomUUID());
1209
- // Idle-return dialog: shown when user submits after a long idle gap
1210
- const [idleReturnPending, setIdleReturnPending] = useState(null);
1211
- const skipIdleCheckRef = useRef(false);
1212
- const lastQueryCompletionTimeRef = useRef(lastQueryCompletionTime);
1213
- lastQueryCompletionTimeRef.current = lastQueryCompletionTime;
1214
- // Aggregate tool result budget: per-conversation decision tracking.
1215
- // When the GrowthBook flag is on, query.ts enforces the budget; when
1216
- // off (undefined), enforcement is skipped entirely. Stale entries after
1217
- // /clear, rewind, or compact are harmless (tool_use_ids are UUIDs, stale
1218
- // keys are never looked up). Memory is bounded by total replacement count
1219
- // × ~2KB preview over the REPL lifetime — negligible.
1220
- //
1221
- // Lazy init via useState initializer — useRef(expr) evaluates expr on every
1222
- // render (React ignores it after first, but the computation still runs).
1223
- // For large resumed sessions, reconstruction does O(messages × blocks)
1224
- // work; we only want that once.
1225
- const [contentReplacementStateRef] = useState(() => ({
1226
- current: provisionContentReplacementState(initialMessages, initialContentReplacements)
1227
- }));
1228
- const [haveShownCostDialog, setHaveShownCostDialog] = useState(getGlobalConfig().hasAcknowledgedCostThreshold);
1229
- const [vimMode, setVimMode] = useState('INSERT');
1230
- const [showBashesDialog, setShowBashesDialog] = useState(false);
1231
- const [isSearchingHistory, setIsSearchingHistory] = useState(false);
1232
- const [isHelpOpen, setIsHelpOpen] = useState(false);
1233
- // showBashesDialog is REPL-level so it survives PromptInput unmounting.
1234
- // When ultraplan approval fires while the pill dialog is open, PromptInput
1235
- // unmounts (focusedInputDialog → 'ultraplan-choice') but this stays true;
1236
- // after accepting, PromptInput remounts into an empty "No tasks" dialog
1237
- // (the completed ultraplan task has been filtered out). Close it here.
1238
- useEffect(() => {
1239
- if (ultraplanPendingChoice && showBashesDialog) {
1240
- setShowBashesDialog(false);
1241
- }
1242
- }, [ultraplanPendingChoice, showBashesDialog]);
1243
- const isTerminalFocused = useTerminalFocus();
1244
- const terminalFocusRef = useRef(isTerminalFocused);
1245
- terminalFocusRef.current = isTerminalFocused;
1246
- const [theme] = useTheme();
1247
- // resetLoadingState runs twice per turn (onQueryImpl tail + onQuery finally).
1248
- // Without this guard, both calls pick a tip → two recordShownTip → two
1249
- // saveGlobalConfig writes back-to-back. Reset at submit in onSubmit.
1250
- const tipPickedThisTurnRef = React.useRef(false);
1251
- const pickNewSpinnerTip = useCallback(() => {
1252
- if (tipPickedThisTurnRef.current)
1253
- return;
1254
- tipPickedThisTurnRef.current = true;
1255
- const newMessages = messagesRef.current.slice(bashToolsProcessedIdx.current);
1256
- for (const tool of extractBashToolsFromMessages(newMessages)) {
1257
- bashTools.current.add(tool);
1258
- }
1259
- bashToolsProcessedIdx.current = messagesRef.current.length;
1260
- void getTipToShowOnSpinner({
1261
- theme,
1262
- readFileState: readFileState.current,
1263
- bashTools: bashTools.current
1264
- }).then(async (tip) => {
1265
- if (tip) {
1266
- const content = await tip.content({
1267
- theme
1268
- });
1269
- setAppState(prev => ({
1270
- ...prev,
1271
- spinnerTip: content
1272
- }));
1273
- recordShownTip(tip);
1274
- }
1275
- else {
1276
- setAppState(prev => {
1277
- if (prev.spinnerTip === undefined)
1278
- return prev;
1279
- return {
1280
- ...prev,
1281
- spinnerTip: undefined
1282
- };
1283
- });
1284
- }
1285
- });
1286
- }, [setAppState, theme]);
1287
- // Resets UI loading state. Does NOT call onTurnComplete - that should be
1288
- // called explicitly only when a query turn actually completes.
1289
- const resetLoadingState = useCallback(() => {
1290
- // isLoading is now derived from queryGuard — no setter call needed.
1291
- // queryGuard.end() (onQuery finally) or cancelReservation() (executeUserInput
1292
- // finally) have already transitioned the guard to idle by the time this runs.
1293
- // External loading (remote/backgrounding) is reset separately by those hooks.
1294
- setIsExternalLoading(false);
1295
- setUserInputOnProcessing(undefined);
1296
- responseLengthRef.current = 0;
1297
- apiMetricsRef.current = [];
1298
- setStreamingText(null);
1299
- setStreamingToolUses([]);
1300
- setSpinnerMessage(null);
1301
- setSpinnerColor(null);
1302
- setSpinnerShimmerColor(null);
1303
- pickNewSpinnerTip();
1304
- endInteractionSpan();
1305
- // Speculative bash classifier checks are only valid for the current
1306
- // turn's commands — clear after each turn to avoid accumulating
1307
- // Promise chains for unconsumed checks (denied/aborted paths).
1308
- clearSpeculativeChecks();
1309
- }, [pickNewSpinnerTip]);
1310
- // Session backgrounding — hook is below, after getToolUseContext
1311
- const hasRunningTeammates = useMemo(() => getAllInProcessTeammateTasks(tasks).some(t => t.status === 'running'), [tasks]);
1312
- // Show deferred turn duration message once all swarm teammates finish
1313
- useEffect(() => {
1314
- if (!hasRunningTeammates && swarmStartTimeRef.current !== null) {
1315
- const totalMs = Date.now() - swarmStartTimeRef.current;
1316
- const deferredBudget = swarmBudgetInfoRef.current;
1317
- swarmStartTimeRef.current = null;
1318
- swarmBudgetInfoRef.current = undefined;
1319
- setMessages(prev => [...prev, createTurnDurationMessage(totalMs, deferredBudget,
1320
- // Count only what recordTranscript will persist — ephemeral
1321
- // progress ticks and non-ant attachments are filtered by
1322
- // isLoggableMessage and never reach disk. Using raw prev.length
1323
- // would make checkResumeConsistency report false delta<0 for
1324
- // every turn that ran a progress-emitting tool.
1325
- count(prev, isLoggableMessage))]);
1326
- }
1327
- }, [hasRunningTeammates, setMessages]);
1328
- // Show auto permissions warning when entering auto mode
1329
- // (either via Shift+Tab toggle or on startup). Debounced to avoid
1330
- // flashing when the user is cycling through modes quickly.
1331
- // Only shown 3 times total across sessions.
1332
- const safeYoloMessageShownRef = useRef(false);
1333
- useEffect(() => {
1334
- if (feature('TRANSCRIPT_CLASSIFIER')) {
1335
- if (toolPermissionContext.mode !== 'auto') {
1336
- safeYoloMessageShownRef.current = false;
1337
- return;
1338
- }
1339
- if (safeYoloMessageShownRef.current)
1340
- return;
1341
- const config = getGlobalConfig();
1342
- const count = config.autoPermissionsNotificationCount ?? 0;
1343
- if (count >= 3)
1344
- return;
1345
- const timer = setTimeout((ref, setMessages) => {
1346
- ref.current = true;
1347
- saveGlobalConfig(prev => {
1348
- const prevCount = prev.autoPermissionsNotificationCount ?? 0;
1349
- if (prevCount >= 3)
1350
- return prev;
1351
- return {
1352
- ...prev,
1353
- autoPermissionsNotificationCount: prevCount + 1
1354
- };
1355
- });
1356
- setMessages(prev => [...prev, createSystemMessage(AUTO_MODE_DESCRIPTION, 'warning')]);
1357
- }, 800, safeYoloMessageShownRef, setMessages);
1358
- return () => clearTimeout(timer);
1359
- }
1360
- }, [toolPermissionContext.mode, setMessages]);
1361
- // If worktree creation was slow and sparse-checkout isn't configured,
1362
- // nudge the user toward settings.worktree.sparsePaths.
1363
- const worktreeTipShownRef = useRef(false);
1364
- useEffect(() => {
1365
- if (worktreeTipShownRef.current)
1366
- return;
1367
- const wt = getCurrentWorktreeSession();
1368
- if (!wt?.creationDurationMs || wt.usedSparsePaths)
1369
- return;
1370
- if (wt.creationDurationMs < 15_000)
1371
- return;
1372
- worktreeTipShownRef.current = true;
1373
- const secs = Math.round(wt.creationDurationMs / 1000);
1374
- setMessages(prev => [...prev, createSystemMessage(`Worktree creation took ${secs}s. For large repos, set \`worktree.sparsePaths\` in .claude/settings.json to check out only the directories you need — e.g. \`{"worktree": {"sparsePaths": ["src", "packages/foo"]}}\`.`, 'info')]);
1375
- }, [setMessages]);
1376
- // Hide spinner when the only in-progress tool is Sleep
1377
- const onlySleepToolActive = useMemo(() => {
1378
- const lastAssistant = messages.findLast(m => m.type === 'assistant');
1379
- if (lastAssistant?.type !== 'assistant')
1380
- return false;
1381
- const inProgressToolUses = lastAssistant.message.content.filter(b => b.type === 'tool_use' && inProgressToolUseIDs.has(b.id));
1382
- return inProgressToolUses.length > 0 && inProgressToolUses.every(b => b.type === 'tool_use' && b.name === SLEEP_TOOL_NAME);
1383
- }, [messages, inProgressToolUseIDs]);
1384
- const { onBeforeQuery: mrOnBeforeQuery, onTurnComplete: mrOnTurnComplete, render: mrRender } = useMoreRight({
1385
- enabled: moreRightEnabled,
1386
- setMessages,
1387
- inputValue,
1388
- setInputValue,
1389
- setToolJSX
1390
- });
1391
- const showSpinner = (!toolJSX || toolJSX.showSpinner === true) && toolUseConfirmQueue.length === 0 && promptQueue.length === 0 && (
1392
- // Show spinner during input processing, API call, while teammates are running,
1393
- // or while pending task notifications are queued (prevents spinner bounce between consecutive notifications)
1394
- isLoading || userInputOnProcessing || hasRunningTeammates ||
1395
- // Keep spinner visible while task notifications are queued for processing.
1396
- // Without this, the spinner briefly disappears between consecutive notifications
1397
- // (e.g., multiple background agents completing in rapid succession) because
1398
- // isLoading goes false momentarily between processing each one.
1399
- getCommandQueueLength() > 0) &&
1400
- // Hide spinner when waiting for leader to approve permission request
1401
- !pendingWorkerRequest && !onlySleepToolActive && (
1402
- // Hide spinner when streaming text is visible (the text IS the feedback),
1403
- // but keep it when isBriefOnly suppresses the streaming text display
1404
- !visibleStreamingText || isBriefOnly);
1405
- // Check if any permission or ask question prompt is currently visible
1406
- // This is used to prevent the survey from opening while prompts are active
1407
- const hasActivePrompt = toolUseConfirmQueue.length > 0 || promptQueue.length > 0 || sandboxPermissionRequestQueue.length > 0 || elicitation.queue.length > 0 || workerSandboxPermissions.queue.length > 0;
1408
- const feedbackSurveyOriginal = useFeedbackSurvey(messages, isLoading, submitCount, 'session', hasActivePrompt);
1409
- const skillImprovementSurvey = useSkillImprovementSurvey(setMessages);
1410
- const showIssueFlagBanner = useIssueFlagBanner(messages, submitCount);
1411
- // Wrap feedback survey handler to trigger auto-run /issue
1412
- const feedbackSurvey = useMemo(() => ({
1413
- ...feedbackSurveyOriginal,
1414
- handleSelect: (selected) => {
1415
- // Reset the ref when a new survey response comes in
1416
- didAutoRunIssueRef.current = false;
1417
- const showedTranscriptPrompt = feedbackSurveyOriginal.handleSelect(selected);
1418
- // Auto-run /issue for "bad" if transcript prompt wasn't shown
1419
- if (selected === 'bad' && !showedTranscriptPrompt && shouldAutoRunIssue('feedback_survey_bad')) {
1420
- setAutoRunIssueReason('feedback_survey_bad');
1421
- didAutoRunIssueRef.current = true;
1422
- }
1423
- }
1424
- }), [feedbackSurveyOriginal]);
1425
- // Post-compact survey: shown after compaction if feature gate is enabled
1426
- const postCompactSurvey = usePostCompactSurvey(messages, isLoading, hasActivePrompt, {
1427
- enabled: !isRemoteSession
1428
- });
1429
- // Memory survey: shown when the assistant mentions memory and a memory file
1430
- // was read this conversation
1431
- const memorySurvey = useMemorySurvey(messages, isLoading, hasActivePrompt, {
1432
- enabled: !isRemoteSession
1433
- });
1434
- // Frustration detection: show transcript sharing prompt after detecting frustrated messages
1435
- const frustrationDetection = useFrustrationDetection(messages, isLoading, hasActivePrompt, feedbackSurvey.state !== 'closed' || postCompactSurvey.state !== 'closed' || memorySurvey.state !== 'closed');
1436
- // Initialize IDE integration
1437
- useIDEIntegration({
1438
- autoConnectIdeFlag,
1439
- ideToInstallExtension,
1440
- setDynamicMcpConfig,
1441
- setShowIdeOnboarding,
1442
- setIDEInstallationState: setIDEInstallationStatus
1443
- });
1444
- useFileHistorySnapshotInit(initialFileHistorySnapshots, fileHistory, fileHistoryState => setAppState(prev => ({
1445
- ...prev,
1446
- fileHistory: fileHistoryState
1447
- })));
1448
- const resume = useCallback(async (sessionId, log, entrypoint) => {
1449
- const resumeStart = performance.now();
1450
- try {
1451
- // Deserialize messages to properly clean up the conversation
1452
- // This filters unresolved tool uses and adds a synthetic assistant message if needed
1453
- const messages = deserializeMessages(log.messages);
1454
- // Match coordinator/normal mode to the resumed session
1455
- if (feature('COORDINATOR_MODE')) {
1456
- /* eslint-disable @typescript-eslint/no-require-imports */
1457
- const coordinatorModule = require('../coordinator/coordinatorMode.js');
1458
- /* eslint-enable @typescript-eslint/no-require-imports */
1459
- const warning = coordinatorModule.matchSessionMode(log.mode);
1460
- if (warning) {
1461
- // Re-derive agent definitions after mode switch so built-in agents
1462
- // reflect the new coordinator/normal mode
1463
- /* eslint-disable @typescript-eslint/no-require-imports */
1464
- const { getAgentDefinitionsWithOverrides, getActiveAgentsFromList } = require('../tools/AgentTool/loadAgentsDir.js');
1465
- /* eslint-enable @typescript-eslint/no-require-imports */
1466
- getAgentDefinitionsWithOverrides.cache.clear?.();
1467
- const freshAgentDefs = await getAgentDefinitionsWithOverrides(getOriginalCwd());
1468
- setAppState(prev => ({
1469
- ...prev,
1470
- agentDefinitions: {
1471
- ...freshAgentDefs,
1472
- allAgents: freshAgentDefs.allAgents,
1473
- activeAgents: getActiveAgentsFromList(freshAgentDefs.allAgents)
1474
- }
1475
- }));
1476
- messages.push(createSystemMessage(warning, 'warning'));
1477
- }
1478
- }
1479
- // Fire SessionEnd hooks for the current session before starting the
1480
- // resumed one, mirroring the /clear flow in conversation.ts.
1481
- const sessionEndTimeoutMs = getSessionEndHookTimeoutMs();
1482
- await executeSessionEndHooks('resume', {
1483
- getAppState: () => store.getState(),
1484
- setAppState,
1485
- signal: AbortSignal.timeout(sessionEndTimeoutMs),
1486
- timeoutMs: sessionEndTimeoutMs
1487
- });
1488
- // Process session start hooks for resume
1489
- const hookMessages = await processSessionStartHooks('resume', {
1490
- sessionId,
1491
- agentType: mainThreadAgentDefinition?.agentType,
1492
- model: mainLoopModel
1493
- });
1494
- // Append hook messages to the conversation
1495
- messages.push(...hookMessages);
1496
- // For forks, generate a new plan slug and copy the plan content so the
1497
- // original and forked sessions don't clobber each other's plan files.
1498
- // For regular resumes, reuse the original session's plan slug.
1499
- if (entrypoint === 'fork') {
1500
- void copyPlanForFork(log, asSessionId(sessionId));
1501
- }
1502
- else {
1503
- void copyPlanForResume(log, asSessionId(sessionId));
1504
- }
1505
- // Restore file history and attribution state from the resumed conversation
1506
- restoreSessionStateFromLog(log, setAppState);
1507
- if (log.fileHistorySnapshots) {
1508
- void copyFileHistoryForResume(log);
1509
- }
1510
- // Restore agent setting from the resumed conversation
1511
- // Always reset to the new session's values (or clear if none),
1512
- // matching the standaloneAgentContext pattern below
1513
- const { agentDefinition: restoredAgent } = restoreAgentFromSession(log.agentSetting, initialMainThreadAgentDefinition, agentDefinitions);
1514
- setMainThreadAgentDefinition(restoredAgent);
1515
- setAppState(prev => ({
1516
- ...prev,
1517
- agent: restoredAgent?.agentType
1518
- }));
1519
- // Restore standalone agent context from the resumed conversation
1520
- // Always reset to the new session's values (or clear if none)
1521
- setAppState(prev => ({
1522
- ...prev,
1523
- standaloneAgentContext: computeStandaloneAgentContext(log.agentName, log.agentColor)
1524
- }));
1525
- void updateSessionName(log.agentName);
1526
- // Restore read file state from the message history
1527
- restoreReadFileState(messages, log.projectPath ?? getOriginalCwd());
1528
- // Clear any active loading state (no queryId since we're not in a query)
1529
- resetLoadingState();
1530
- setAbortController(null);
1531
- setConversationId(sessionId);
1532
- // Get target session's costs BEFORE saving current session
1533
- // (saveCurrentSessionCosts overwrites the config, so we need to read first)
1534
- const targetSessionCosts = getStoredSessionCosts(sessionId);
1535
- // Save current session's costs before switching to avoid losing accumulated costs
1536
- saveCurrentSessionCosts();
1537
- // Reset cost state for clean slate before restoring target session
1538
- resetCostState();
1539
- // Switch session (id + project dir atomically). fullPath may point to
1540
- // a different project (cross-worktree, /branch); null derives from
1541
- // current originalCwd.
1542
- switchSession(asSessionId(sessionId), log.fullPath ? dirname(log.fullPath) : null);
1543
- // Rename asciicast recording to match the resumed session ID
1544
- const { renameRecordingForSession } = await import('../utils/asciicast.js');
1545
- await renameRecordingForSession();
1546
- await resetSessionFilePointer();
1547
- // Clear then restore session metadata so it's re-appended on exit via
1548
- // reAppendSessionMetadata. clearSessionMetadata must be called first:
1549
- // restoreSessionMetadata only sets-if-truthy, so without the clear,
1550
- // a session without an agent name would inherit the previous session's
1551
- // cached name and write it to the wrong transcript on first message.
1552
- clearSessionMetadata();
1553
- restoreSessionMetadata(log);
1554
- // Resumed sessions shouldn't re-title from mid-conversation context
1555
- // (same reasoning as the useRef seed), and the previous session's
1556
- // Haiku title shouldn't carry over.
1557
- haikuTitleAttemptedRef.current = true;
1558
- setHaikuTitle(undefined);
1559
- // Exit any worktree a prior /resume entered, then cd into the one
1560
- // this session was in. Without the exit, resuming from worktree B
1561
- // to non-worktree C leaves cwd/currentWorktreeSession stale;
1562
- // resuming B→C where C is also a worktree fails entirely
1563
- // (getCurrentWorktreeSession guard blocks the switch).
1564
- //
1565
- // Skipped for /branch: forkLog doesn't carry worktreeSession, so
1566
- // this would kick the user out of a worktree they're still working
1567
- // in. Same fork skip as processResumedConversation for the adopt —
1568
- // fork materializes its own file via recordTranscript on REPL mount.
1569
- if (entrypoint !== 'fork') {
1570
- exitRestoredWorktree();
1571
- restoreWorktreeForResume(log.worktreeSession);
1572
- adoptResumedSessionFile();
1573
- void restoreRemoteAgentTasks({
1574
- abortController: new AbortController(),
1575
- getAppState: () => store.getState(),
1576
- setAppState
1577
- });
1578
- }
1579
- else {
1580
- // Fork: same re-persist as /clear (conversation.ts). The clear
1581
- // above wiped currentSessionWorktree, forkLog doesn't carry it,
1582
- // and the process is still in the same worktree.
1583
- const ws = getCurrentWorktreeSession();
1584
- if (ws)
1585
- saveWorktreeState(ws);
1586
- }
1587
- // Persist the current mode so future resumes know what mode this session was in
1588
- if (feature('COORDINATOR_MODE')) {
1589
- /* eslint-disable @typescript-eslint/no-require-imports */
1590
- const { saveMode } = require('../utils/sessionStorage.js');
1591
- const { isCoordinatorMode } = require('../coordinator/coordinatorMode.js');
1592
- /* eslint-enable @typescript-eslint/no-require-imports */
1593
- saveMode(isCoordinatorMode() ? 'coordinator' : 'normal');
1594
- }
1595
- // Restore target session's costs from the data we read earlier
1596
- if (targetSessionCosts) {
1597
- setCostStateForRestore(targetSessionCosts);
1598
- }
1599
- // Reconstruct replacement state for the resumed session. Runs after
1600
- // setSessionId so any NEW replacements post-resume write to the
1601
- // resumed session's tool-results dir. Gated on ref.current: the
1602
- // initial mount already read the feature flag, so we don't re-read
1603
- // it here (mid-session flag flips stay unobservable in both
1604
- // directions).
1605
- //
1606
- // Skipped for in-session /branch: the existing ref is already correct
1607
- // (branch preserves tool_use_ids), so there's no need to reconstruct.
1608
- // createFork() does write content-replacement entries to the forked
1609
- // JSONL with the fork's sessionId, so `claude -r {forkId}` also works.
1610
- if (contentReplacementStateRef.current && entrypoint !== 'fork') {
1611
- contentReplacementStateRef.current = reconstructContentReplacementState(messages, log.contentReplacements ?? []);
1612
- }
1613
- // Reset messages to the provided initial messages
1614
- // Use a callback to ensure we're not dependent on stale state
1615
- setMessages(() => messages);
1616
- // Clear any active tool JSX
1617
- setToolJSX(null);
1618
- // Clear input to ensure no residual state
1619
- setInputValue('');
1620
- logEvent('tengu_session_resumed', {
1621
- entrypoint: entrypoint,
1622
- success: true,
1623
- resume_duration_ms: Math.round(performance.now() - resumeStart)
1624
- });
1625
- }
1626
- catch (error) {
1627
- logEvent('tengu_session_resumed', {
1628
- entrypoint: entrypoint,
1629
- success: false
1630
- });
1631
- throw error;
1632
- }
1633
- }, [resetLoadingState, setAppState]);
1634
- // Lazy init: useRef(createX()) would call createX on every render and
1635
- // discard the result. LRUCache construction inside FileStateCache is
1636
- // expensive (~170ms), so we use useState's lazy initializer to create
1637
- // it exactly once, then feed that stable reference into useRef.
1638
- const [initialReadFileState] = useState(() => createFileStateCacheWithSizeLimit(READ_FILE_STATE_CACHE_SIZE));
1639
- const readFileState = useRef(initialReadFileState);
1640
- const bashTools = useRef(new Set());
1641
- const bashToolsProcessedIdx = useRef(0);
1642
- // Session-scoped skill discovery tracking (feeds was_discovered on
1643
- // tengu_skill_tool_invocation). Must persist across getToolUseContext
1644
- // rebuilds within a session: turn-0 discovery writes via processUserInput
1645
- // before onQuery builds its own context, and discovery on turn N must
1646
- // still attribute a SkillTool call on turn N+k. Cleared in clearConversation.
1647
- const discoveredSkillNamesRef = useRef(new Set());
1648
- // Session-level dedup for nested_memory CLAUDE.md attachments.
1649
- // readFileState is a 100-entry LRU; once it evicts a CLAUDE.md path,
1650
- // the next discovery cycle re-injects it. Cleared in clearConversation.
1651
- const loadedNestedMemoryPathsRef = useRef(new Set());
1652
- // Helper to restore read file state from messages (used for resume flows)
1653
- // This allows Claude to edit files that were read in previous sessions
1654
- const restoreReadFileState = useCallback((messages, cwd) => {
1655
- const extracted = extractReadFilesFromMessages(messages, cwd, READ_FILE_STATE_CACHE_SIZE);
1656
- readFileState.current = mergeFileStateCaches(readFileState.current, extracted);
1657
- for (const tool of extractBashToolsFromMessages(messages)) {
1658
- bashTools.current.add(tool);
1659
- }
1660
- }, []);
1661
- // Extract read file state from initialMessages on mount
1662
- // This handles CLI flag resume (--resume-session) and ResumeConversation screen
1663
- // where messages are passed as props rather than through the resume callback
1664
- useEffect(() => {
1665
- if (initialMessages && initialMessages.length > 0) {
1666
- restoreReadFileState(initialMessages, getOriginalCwd());
1667
- void restoreRemoteAgentTasks({
1668
- abortController: new AbortController(),
1669
- getAppState: () => store.getState(),
1670
- setAppState
1671
- });
1672
- }
1673
- // Only run on mount - initialMessages shouldn't change during component lifetime
1674
- // eslint-disable-next-line react-hooks/exhaustive-deps
1675
- }, []);
1676
- const { status: apiKeyStatus, reverify } = useApiKeyVerification();
1677
- // Auto-run /issue state
1678
- const [autoRunIssueReason, setAutoRunIssueReason] = useState(null);
1679
- // Ref to track if autoRunIssue was triggered this survey cycle,
1680
- // so we can suppress the [1] follow-up prompt even after
1681
- // autoRunIssueReason is cleared.
1682
- const didAutoRunIssueRef = useRef(false);
1683
- // State for exit feedback flow
1684
- const [exitFlow, setExitFlow] = useState(null);
1685
- const [isExiting, setIsExiting] = useState(false);
1686
- // Calculate if cost dialog should be shown
1687
- const showingCostDialog = !isLoading && showCostDialog;
1688
- // Determine which dialog should have focus (if any)
1689
- // Permission and interactive dialogs can show even when toolJSX is set,
1690
- // as long as shouldContinueAnimation is true. This prevents deadlocks when
1691
- // agents set background hints while waiting for user interaction.
1692
- function getFocusedInputDialog() {
1693
- // Exit states always take precedence
1694
- if (isExiting || exitFlow)
1695
- return undefined;
1696
- // High priority dialogs (always show regardless of typing)
1697
- if (isMessageSelectorVisible)
1698
- return 'message-selector';
1699
- // Suppress interrupt dialogs while user is actively typing
1700
- if (isPromptInputActive)
1701
- return undefined;
1702
- if (sandboxPermissionRequestQueue[0])
1703
- return 'sandbox-permission';
1704
- // Permission/interactive dialogs (show unless blocked by toolJSX)
1705
- const allowDialogsWithAnimation = !toolJSX || toolJSX.shouldContinueAnimation;
1706
- if (allowDialogsWithAnimation && toolUseConfirmQueue[0])
1707
- return 'tool-permission';
1708
- if (allowDialogsWithAnimation && promptQueue[0])
1709
- return 'prompt';
1710
- // Worker sandbox permission prompts (network access) from swarm workers
1711
- if (allowDialogsWithAnimation && workerSandboxPermissions.queue[0])
1712
- return 'worker-sandbox-permission';
1713
- if (allowDialogsWithAnimation && elicitation.queue[0])
1714
- return 'elicitation';
1715
- if (allowDialogsWithAnimation && showingCostDialog)
1716
- return 'cost';
1717
- if (allowDialogsWithAnimation && idleReturnPending)
1718
- return 'idle-return';
1719
- if (feature('ULTRAPLAN') && allowDialogsWithAnimation && !isLoading && ultraplanPendingChoice)
1720
- return 'ultraplan-choice';
1721
- if (feature('ULTRAPLAN') && allowDialogsWithAnimation && !isLoading && ultraplanLaunchPending)
1722
- return 'ultraplan-launch';
1723
- // Onboarding dialogs (special conditions)
1724
- if (allowDialogsWithAnimation && showIdeOnboarding)
1725
- return 'ide-onboarding';
1726
- // Model switch callout (ant-only, eliminated from external builds)
1727
- if ("external" === 'ant' && allowDialogsWithAnimation && showModelSwitchCallout)
1728
- return 'model-switch';
1729
- // Undercover auto-enable explainer (ant-only, eliminated from external builds)
1730
- if ("external" === 'ant' && allowDialogsWithAnimation && showUndercoverCallout)
1731
- return 'undercover-callout';
1732
- // Effort callout (shown once for Opus 4.6 users when effort is enabled)
1733
- if (allowDialogsWithAnimation && showEffortCallout)
1734
- return 'effort-callout';
1735
- // Remote callout (shown once before first bridge enable)
1736
- if (allowDialogsWithAnimation && showRemoteCallout)
1737
- return 'remote-callout';
1738
- // LSP plugin recommendation (lowest priority - non-blocking suggestion)
1739
- if (allowDialogsWithAnimation && lspRecommendation)
1740
- return 'lsp-recommendation';
1741
- // Plugin hint from CLI/SDK stderr (same priority band as LSP rec)
1742
- if (allowDialogsWithAnimation && hintRecommendation)
1743
- return 'plugin-hint';
1744
- // Desktop app upsell (max 3 launches, lowest priority)
1745
- if (allowDialogsWithAnimation && showDesktopUpsellStartup)
1746
- return 'desktop-upsell';
1747
- return undefined;
1748
- }
1749
- const focusedInputDialog = getFocusedInputDialog();
1750
- // True when permission prompts exist but are hidden because the user is typing
1751
- const hasSuppressedDialogs = isPromptInputActive && (sandboxPermissionRequestQueue[0] || toolUseConfirmQueue[0] || promptQueue[0] || workerSandboxPermissions.queue[0] || elicitation.queue[0] || showingCostDialog);
1752
- // Keep ref in sync so timer callbacks can read the current value
1753
- focusedInputDialogRef.current = focusedInputDialog;
1754
- // Immediately capture pause/resume when focusedInputDialog changes
1755
- // This ensures accurate timing even under high system load, rather than
1756
- // relying on the 100ms polling interval to detect state changes
1757
- useEffect(() => {
1758
- if (!isLoading)
1759
- return;
1760
- const isPaused = focusedInputDialog === 'tool-permission';
1761
- const now = Date.now();
1762
- if (isPaused && pauseStartTimeRef.current === null) {
1763
- // Just entered pause state - record the exact moment
1764
- pauseStartTimeRef.current = now;
1765
- }
1766
- else if (!isPaused && pauseStartTimeRef.current !== null) {
1767
- // Just exited pause state - accumulate paused time immediately
1768
- totalPausedMsRef.current += now - pauseStartTimeRef.current;
1769
- pauseStartTimeRef.current = null;
1770
- }
1771
- }, [focusedInputDialog, isLoading]);
1772
- // Re-pin scroll to bottom whenever the permission overlay appears or
1773
- // dismisses. Overlay now renders below messages inside the same
1774
- // ScrollBox (no remount), so we need an explicit scrollToBottom for:
1775
- // - appear: user may have been scrolled up (sticky broken) — the
1776
- // dialog is blocking and must be visible
1777
- // - dismiss: user may have scrolled up to read context during the
1778
- // overlay, and onScroll was suppressed so the pill state is stale
1779
- // useLayoutEffect so the re-pin commits before the Ink frame renders —
1780
- // no 1-frame flash of the wrong scroll position.
1781
- const prevDialogRef = useRef(focusedInputDialog);
1782
- useLayoutEffect(() => {
1783
- const was = prevDialogRef.current === 'tool-permission';
1784
- const now = focusedInputDialog === 'tool-permission';
1785
- if (was !== now)
1786
- repinScroll();
1787
- prevDialogRef.current = focusedInputDialog;
1788
- }, [focusedInputDialog, repinScroll]);
1789
- function onCancel() {
1790
- if (focusedInputDialog === 'elicitation') {
1791
- // Elicitation dialog handles its own Escape, and closing it shouldn't affect any loading state.
1792
- return;
1793
- }
1794
- logForDebugging(`[onCancel] focusedInputDialog=${focusedInputDialog} streamMode=${streamMode}`);
1795
- // Pause proactive mode so the user gets control back.
1796
- // It will resume when they submit their next input (see onSubmit).
1797
- if (feature('PROACTIVE') || feature('KAIROS')) {
1798
- proactiveModule?.pauseProactive();
1799
- }
1800
- queryGuard.forceEnd();
1801
- skipIdleCheckRef.current = false;
1802
- // Preserve partially-streamed text so the user can read what was
1803
- // generated before pressing Esc. Pushed before resetLoadingState clears
1804
- // streamingText, and before query.ts yields the async interrupt marker,
1805
- // giving final order [user, partial-assistant, [Request interrupted by user]].
1806
- if (streamingText?.trim()) {
1807
- setMessages(prev => [...prev, createAssistantMessage({
1808
- content: streamingText
1809
- })]);
1810
- }
1811
- resetLoadingState();
1812
- // Clear any active token budget so the backstop doesn't fire on
1813
- // a stale budget if the query generator hasn't exited yet.
1814
- if (feature('TOKEN_BUDGET')) {
1815
- snapshotOutputTokensForTurn(null);
1816
- }
1817
- if (focusedInputDialog === 'tool-permission') {
1818
- // Tool use confirm handles the abort signal itself
1819
- toolUseConfirmQueue[0]?.onAbort();
1820
- setToolUseConfirmQueue([]);
1821
- }
1822
- else if (focusedInputDialog === 'prompt') {
1823
- // Reject all pending prompts and clear the queue
1824
- for (const item of promptQueue) {
1825
- item.reject(new Error('Prompt cancelled by user'));
1826
- }
1827
- setPromptQueue([]);
1828
- abortController?.abort('user-cancel');
1829
- }
1830
- else if (activeRemote.isRemoteMode) {
1831
- // Remote mode: send interrupt signal to CCR
1832
- activeRemote.cancelRequest();
1833
- }
1834
- else {
1835
- abortController?.abort('user-cancel');
1836
- }
1837
- // Clear the controller so subsequent Escape presses don't see a stale
1838
- // aborted signal. Without this, canCancelRunningTask is false (signal
1839
- // defined but .aborted === true), so isActive becomes false if no other
1840
- // activating conditions hold — leaving the Escape keybinding inactive.
1841
- setAbortController(null);
1842
- // forceEnd() skips the finally path — fire directly (aborted=true).
1843
- void mrOnTurnComplete(messagesRef.current, true);
1844
- }
1845
- // Function to handle queued command when canceling a permission request
1846
- const handleQueuedCommandOnCancel = useCallback(() => {
1847
- const result = popAllEditable(inputValue, 0);
1848
- if (!result)
1849
- return;
1850
- setInputValue(result.text);
1851
- setInputMode('prompt');
1852
- // Restore images from queued commands to pastedContents
1853
- if (result.images.length > 0) {
1854
- setPastedContents(prev => {
1855
- const newContents = {
1856
- ...prev
1857
- };
1858
- for (const image of result.images) {
1859
- newContents[image.id] = image;
1860
- }
1861
- return newContents;
1862
- });
1863
- }
1864
- }, [setInputValue, setInputMode, inputValue, setPastedContents]);
1865
- // CancelRequestHandler props - rendered inside KeybindingSetup
1866
- const cancelRequestProps = {
1867
- setToolUseConfirmQueue,
1868
- onCancel,
1869
- onAgentsKilled: () => setMessages(prev => [...prev, createAgentsKilledMessage()]),
1870
- isMessageSelectorVisible: isMessageSelectorVisible || !!showBashesDialog,
1871
- screen,
1872
- abortSignal: abortController?.signal,
1873
- popCommandFromQueue: handleQueuedCommandOnCancel,
1874
- vimMode,
1875
- isLocalJSXCommand: toolJSX?.isLocalJSXCommand,
1876
- isSearchingHistory,
1877
- isHelpOpen,
1878
- inputMode,
1879
- inputValue,
1880
- streamMode
1881
- };
1882
- useEffect(() => {
1883
- const totalCost = getTotalCost();
1884
- if (totalCost >= 5 /* $5 */ && !showCostDialog && !haveShownCostDialog) {
1885
- logEvent('tengu_cost_threshold_reached', {});
1886
- // Mark as shown even if the dialog won't render (no console billing
1887
- // access). Otherwise this effect re-fires on every message change for
1888
- // the rest of the session — 200k+ spurious events observed.
1889
- setHaveShownCostDialog(true);
1890
- if (hasConsoleBillingAccess()) {
1891
- setShowCostDialog(true);
1892
- }
1893
- }
1894
- }, [messages, showCostDialog, haveShownCostDialog]);
1895
- const sandboxAskCallback = useCallback(async (hostPattern) => {
1896
- // If running as a swarm worker, forward the request to the leader via mailbox
1897
- if (isAgentSwarmsEnabled() && isSwarmWorker()) {
1898
- const requestId = generateSandboxRequestId();
1899
- // Send the request to the leader via mailbox
1900
- const sent = await sendSandboxPermissionRequestViaMailbox(hostPattern.host, requestId);
1901
- return new Promise(resolveShouldAllowHost => {
1902
- if (!sent) {
1903
- // If we couldn't send via mailbox, fall back to local handling
1904
- setSandboxPermissionRequestQueue(prev => [...prev, {
1905
- hostPattern,
1906
- resolvePromise: resolveShouldAllowHost
1907
- }]);
1908
- return;
1909
- }
1910
- // Register the callback for when the leader responds
1911
- registerSandboxPermissionCallback({
1912
- requestId,
1913
- host: hostPattern.host,
1914
- resolve: resolveShouldAllowHost
1915
- });
1916
- // Update AppState to show pending indicator
1917
- setAppState(prev => ({
1918
- ...prev,
1919
- pendingSandboxRequest: {
1920
- requestId,
1921
- host: hostPattern.host
1922
- }
1923
- }));
1924
- });
1925
- }
1926
- // Normal flow for non-workers: show local UI and optionally race
1927
- // against the REPL bridge (Remote Control) if connected.
1928
- return new Promise(resolveShouldAllowHost => {
1929
- let resolved = false;
1930
- function resolveOnce(allow) {
1931
- if (resolved)
1932
- return;
1933
- resolved = true;
1934
- resolveShouldAllowHost(allow);
1935
- }
1936
- // Queue the local sandbox permission dialog
1937
- setSandboxPermissionRequestQueue(prev => [...prev, {
1938
- hostPattern,
1939
- resolvePromise: resolveOnce
1940
- }]);
1941
- // When the REPL bridge is connected, also forward the sandbox
1942
- // permission request as a can_use_tool control_request so the
1943
- // remote user (e.g. on claude.ai) can approve it too.
1944
- if (feature('BRIDGE_MODE')) {
1945
- const bridgeCallbacks = store.getState().replBridgePermissionCallbacks;
1946
- if (bridgeCallbacks) {
1947
- const bridgeRequestId = randomUUID();
1948
- bridgeCallbacks.sendRequest(bridgeRequestId, SANDBOX_NETWORK_ACCESS_TOOL_NAME, {
1949
- host: hostPattern.host
1950
- }, randomUUID(), `Allow network connection to ${hostPattern.host}?`);
1951
- const unsubscribe = bridgeCallbacks.onResponse(bridgeRequestId, response => {
1952
- unsubscribe();
1953
- const allow = response.behavior === 'allow';
1954
- // Resolve ALL pending requests for the same host, not just
1955
- // this one — mirrors the local dialog handler pattern.
1956
- setSandboxPermissionRequestQueue(queue => {
1957
- queue.filter(item => item.hostPattern.host === hostPattern.host).forEach(item => item.resolvePromise(allow));
1958
- return queue.filter(item => item.hostPattern.host !== hostPattern.host);
1959
- });
1960
- // Clean up all sibling bridge subscriptions for this host
1961
- // (other concurrent same-host requests) before deleting.
1962
- const siblingCleanups = sandboxBridgeCleanupRef.current.get(hostPattern.host);
1963
- if (siblingCleanups) {
1964
- for (const fn of siblingCleanups) {
1965
- fn();
1966
- }
1967
- sandboxBridgeCleanupRef.current.delete(hostPattern.host);
1968
- }
1969
- });
1970
- // Register cleanup so the local dialog handler can cancel
1971
- // the remote prompt and unsubscribe when the local user
1972
- // responds first.
1973
- const cleanup = () => {
1974
- unsubscribe();
1975
- bridgeCallbacks.cancelRequest(bridgeRequestId);
1976
- };
1977
- const existing = sandboxBridgeCleanupRef.current.get(hostPattern.host) ?? [];
1978
- existing.push(cleanup);
1979
- sandboxBridgeCleanupRef.current.set(hostPattern.host, existing);
1980
- }
1981
- }
1982
- });
1983
- }, [setAppState, store]);
1984
- // #34044: if user explicitly set sandbox.enabled=true but deps are missing,
1985
- // isSandboxingEnabled() returns false silently. Surface the reason once at
1986
- // mount so users know their security config isn't being enforced. Full
1987
- // reason goes to debug log; notification points to /sandbox for details.
1988
- // addNotification is stable (useCallback) so the effect fires once.
1989
- useEffect(() => {
1990
- const reason = SandboxManager.getSandboxUnavailableReason();
1991
- if (!reason)
1992
- return;
1993
- if (SandboxManager.isSandboxRequired()) {
1994
- process.stderr.write(`\nError: sandbox required but unavailable: ${reason}\n` + ` sandbox.failIfUnavailable is set — refusing to start without a working sandbox.\n\n`);
1995
- gracefulShutdownSync(1, 'other');
1996
- return;
1997
- }
1998
- logForDebugging(`sandbox disabled: ${reason}`, {
1999
- level: 'warn'
2000
- });
2001
- addNotification({
2002
- key: 'sandbox-unavailable',
2003
- jsx: _jsxs(_Fragment, { children: [_jsx(Text, { color: "warning", children: "sandbox disabled" }), _jsx(Text, { dimColor: true, children: " \u00B7 /sandbox" })] }),
2004
- priority: 'medium'
2005
- });
2006
- }, [addNotification]);
2007
- if (SandboxManager.isSandboxingEnabled()) {
2008
- // If sandboxing is enabled (setting.sandbox is defined, initialise the manager)
2009
- SandboxManager.initialize(sandboxAskCallback).catch(err => {
2010
- // Initialization/validation failed - display error and exit
2011
- process.stderr.write(`\n❌ Sandbox Error: ${errorMessage(err)}\n`);
2012
- gracefulShutdownSync(1, 'other');
2013
- });
2014
- }
2015
- const setToolPermissionContext = useCallback((context, options) => {
2016
- setAppState(prev => ({
2017
- ...prev,
2018
- toolPermissionContext: {
2019
- ...context,
2020
- // Preserve the coordinator's mode only when explicitly requested.
2021
- // Workers' getAppState() returns a transformed context with mode
2022
- // 'acceptEdits' that must not leak into the coordinator's actual
2023
- // state via permission-rule updates — those call sites pass
2024
- // { preserveMode: true }. User-initiated mode changes (e.g.,
2025
- // selecting "allow all edits") must NOT be overridden.
2026
- mode: options?.preserveMode ? prev.toolPermissionContext.mode : context.mode
2027
- }
2028
- }));
2029
- // When permission context changes, recheck all queued items
2030
- // This handles the case where approving item1 with "don't ask again"
2031
- // should auto-approve other queued items that now match the updated rules
2032
- setImmediate(setToolUseConfirmQueue => {
2033
- // Use setToolUseConfirmQueue callback to get current queue state
2034
- // instead of capturing it in the closure, to avoid stale closure issues
2035
- setToolUseConfirmQueue(currentQueue => {
2036
- currentQueue.forEach(item => {
2037
- void item.recheckPermission();
2038
- });
2039
- return currentQueue;
2040
- });
2041
- }, setToolUseConfirmQueue);
2042
- }, [setAppState, setToolUseConfirmQueue]);
2043
- // Register the leader's setToolPermissionContext for in-process teammates
2044
- useEffect(() => {
2045
- registerLeaderSetToolPermissionContext(setToolPermissionContext);
2046
- return () => unregisterLeaderSetToolPermissionContext();
2047
- }, [setToolPermissionContext]);
2048
- const canUseTool = useCanUseTool(setToolUseConfirmQueue, setToolPermissionContext);
2049
- const requestPrompt = useCallback((title, toolInputSummary) => (request) => new Promise((resolve, reject) => {
2050
- setPromptQueue(prev => [...prev, {
2051
- request,
2052
- title,
2053
- toolInputSummary,
2054
- resolve,
2055
- reject
2056
- }]);
2057
- }), []);
2058
- const getToolUseContext = useCallback((messages, newMessages, abortController, mainLoopModel) => {
2059
- // Read mutable values fresh from the store rather than closure-capturing
2060
- // useAppState() snapshots. Same values today (closure is refreshed by the
2061
- // render between turns); decouples freshness from React's render cycle for
2062
- // a future headless conversation loop. Same pattern refreshTools() uses.
2063
- const s = store.getState();
2064
- // Compute tools fresh from store.getState() rather than the closure-
2065
- // captured `tools`. useManageMCPConnections populates appState.mcp
2066
- // async as servers connect — the store may have newer MCP state than
2067
- // the closure captured at render time. Also doubles as refreshTools()
2068
- // for mid-query tool list updates.
2069
- const computeTools = () => {
2070
- const state = store.getState();
2071
- const assembled = assembleToolPool(state.toolPermissionContext, state.mcp.tools);
2072
- const merged = mergeAndFilterTools(combinedInitialTools, assembled, state.toolPermissionContext.mode);
2073
- if (!mainThreadAgentDefinition)
2074
- return merged;
2075
- return resolveAgentTools(mainThreadAgentDefinition, merged, false, true).resolvedTools;
2076
- };
2077
- return {
2078
- abortController,
2079
- options: {
2080
- commands,
2081
- tools: computeTools(),
2082
- debug,
2083
- verbose: s.verbose,
2084
- mainLoopModel,
2085
- thinkingConfig: s.thinkingEnabled !== false ? thinkingConfig : {
2086
- type: 'disabled'
2087
- },
2088
- // Merge fresh from store rather than closing over useMergedClients'
2089
- // memoized output. initialMcpClients is a prop (session-constant).
2090
- mcpClients: mergeClients(initialMcpClients, s.mcp.clients),
2091
- mcpResources: s.mcp.resources,
2092
- ideInstallationStatus: ideInstallationStatus,
2093
- isNonInteractiveSession: false,
2094
- dynamicMcpConfig,
2095
- theme,
2096
- agentDefinitions: allowedAgentTypes ? {
2097
- ...s.agentDefinitions,
2098
- allowedAgentTypes
2099
- } : s.agentDefinitions,
2100
- customSystemPrompt,
2101
- appendSystemPrompt,
2102
- refreshTools: computeTools
2103
- },
2104
- getAppState: () => store.getState(),
2105
- setAppState,
2106
- messages,
2107
- setMessages,
2108
- updateFileHistoryState(updater) {
2109
- // Perf: skip the setState when the updater returns the same reference
2110
- // (e.g. fileHistoryTrackEdit returns `state` when the file is already
2111
- // tracked). Otherwise every no-op call would notify all store listeners.
2112
- setAppState(prev => {
2113
- const updated = updater(prev.fileHistory);
2114
- if (updated === prev.fileHistory)
2115
- return prev;
2116
- return {
2117
- ...prev,
2118
- fileHistory: updated
2119
- };
2120
- });
2121
- },
2122
- updateAttributionState(updater) {
2123
- setAppState(prev => {
2124
- const updated = updater(prev.attribution);
2125
- if (updated === prev.attribution)
2126
- return prev;
2127
- return {
2128
- ...prev,
2129
- attribution: updated
2130
- };
2131
- });
2132
- },
2133
- openMessageSelector: () => {
2134
- if (!disabled) {
2135
- setIsMessageSelectorVisible(true);
2136
- }
2137
- },
2138
- onChangeAPIKey: reverify,
2139
- readFileState: readFileState.current,
2140
- setToolJSX,
2141
- addNotification,
2142
- appendSystemMessage: msg => setMessages(prev => [...prev, msg]),
2143
- sendOSNotification: opts => {
2144
- void sendNotification(opts, terminal);
2145
- },
2146
- onChangeDynamicMcpConfig,
2147
- onInstallIDEExtension: setIDEToInstallExtension,
2148
- nestedMemoryAttachmentTriggers: new Set(),
2149
- loadedNestedMemoryPaths: loadedNestedMemoryPathsRef.current,
2150
- dynamicSkillDirTriggers: new Set(),
2151
- discoveredSkillNames: discoveredSkillNamesRef.current,
2152
- setResponseLength,
2153
- pushApiMetricsEntry: "external" === 'ant' ? (ttftMs) => {
2154
- const now = Date.now();
2155
- const baseline = responseLengthRef.current;
2156
- apiMetricsRef.current.push({
2157
- ttftMs,
2158
- firstTokenTime: now,
2159
- lastTokenTime: now,
2160
- responseLengthBaseline: baseline,
2161
- endResponseLength: baseline
2162
- });
2163
- } : undefined,
2164
- setStreamMode,
2165
- onCompactProgress: event => {
2166
- switch (event.type) {
2167
- case 'hooks_start':
2168
- setSpinnerColor('claudeBlue_FOR_SYSTEM_SPINNER');
2169
- setSpinnerShimmerColor('claudeBlueShimmer_FOR_SYSTEM_SPINNER');
2170
- setSpinnerMessage(event.hookType === 'pre_compact' ? 'Running PreCompact hooks\u2026' : event.hookType === 'post_compact' ? 'Running PostCompact hooks\u2026' : 'Running SessionStart hooks\u2026');
2171
- break;
2172
- case 'compact_start':
2173
- setSpinnerMessage('Compacting conversation');
2174
- break;
2175
- case 'compact_end':
2176
- setSpinnerMessage(null);
2177
- setSpinnerColor(null);
2178
- setSpinnerShimmerColor(null);
2179
- break;
2180
- }
2181
- },
2182
- setInProgressToolUseIDs,
2183
- setHasInterruptibleToolInProgress: (v) => {
2184
- hasInterruptibleToolInProgressRef.current = v;
2185
- },
2186
- resume,
2187
- setConversationId,
2188
- requestPrompt: feature('HOOK_PROMPTS') ? requestPrompt : undefined,
2189
- contentReplacementState: contentReplacementStateRef.current
2190
- };
2191
- }, [commands, combinedInitialTools, mainThreadAgentDefinition, debug, initialMcpClients, ideInstallationStatus, dynamicMcpConfig, theme, allowedAgentTypes, store, setAppState, reverify, addNotification, setMessages, onChangeDynamicMcpConfig, resume, requestPrompt, disabled, customSystemPrompt, appendSystemPrompt, setConversationId]);
2192
- // Session backgrounding (Ctrl+B to background/foreground)
2193
- const handleBackgroundQuery = useCallback(() => {
2194
- // Stop the foreground query so the background one takes over
2195
- abortController?.abort('background');
2196
- // Aborting subagents may produce task-completed notifications.
2197
- // Clear task notifications so the queue processor doesn't immediately
2198
- // start a new foreground query; forward them to the background session.
2199
- const removedNotifications = removeByFilter(cmd => cmd.mode === 'task-notification');
2200
- void (async () => {
2201
- const toolUseContext = getToolUseContext(messagesRef.current, [], new AbortController(), mainLoopModel);
2202
- const [defaultSystemPrompt, userContext, systemContext] = await Promise.all([getSystemPrompt(toolUseContext.options.tools, mainLoopModel, Array.from(toolPermissionContext.additionalWorkingDirectories.keys()), toolUseContext.options.mcpClients), getUserContext(), getSystemContext()]);
2203
- const systemPrompt = buildEffectiveSystemPrompt({
2204
- mainThreadAgentDefinition,
2205
- toolUseContext,
2206
- customSystemPrompt,
2207
- defaultSystemPrompt,
2208
- appendSystemPrompt
2209
- });
2210
- toolUseContext.renderedSystemPrompt = systemPrompt;
2211
- const notificationAttachments = await getQueuedCommandAttachments(removedNotifications).catch(() => []);
2212
- const notificationMessages = notificationAttachments.map(createAttachmentMessage);
2213
- // Deduplicate: if the query loop already yielded a notification into
2214
- // messagesRef before we removed it from the queue, skip duplicates.
2215
- // We use prompt text for dedup because source_uuid is not set on
2216
- // task-notification QueuedCommands (enqueuePendingNotification callers
2217
- // don't pass uuid), so it would always be undefined.
2218
- const existingPrompts = new Set();
2219
- for (const m of messagesRef.current) {
2220
- if (m.type === 'attachment' && m.attachment.type === 'queued_command' && m.attachment.commandMode === 'task-notification' && typeof m.attachment.prompt === 'string') {
2221
- existingPrompts.add(m.attachment.prompt);
2222
- }
2223
- }
2224
- const uniqueNotifications = notificationMessages.filter(m => m.attachment.type === 'queued_command' && (typeof m.attachment.prompt !== 'string' || !existingPrompts.has(m.attachment.prompt)));
2225
- startBackgroundSession({
2226
- messages: [...messagesRef.current, ...uniqueNotifications],
2227
- queryParams: {
2228
- systemPrompt,
2229
- userContext,
2230
- systemContext,
2231
- canUseTool,
2232
- toolUseContext,
2233
- querySource: getQuerySourceForREPL()
2234
- },
2235
- description: terminalTitle,
2236
- setAppState,
2237
- agentDefinition: mainThreadAgentDefinition
2238
- });
2239
- })();
2240
- }, [abortController, mainLoopModel, toolPermissionContext, mainThreadAgentDefinition, getToolUseContext, customSystemPrompt, appendSystemPrompt, canUseTool, setAppState]);
2241
- const { handleBackgroundSession } = useSessionBackgrounding({
2242
- setMessages,
2243
- setIsLoading: setIsExternalLoading,
2244
- resetLoadingState,
2245
- setAbortController,
2246
- onBackgroundQuery: handleBackgroundQuery
2247
- });
2248
- const onQueryEvent = useCallback((event) => {
2249
- handleMessageFromStream(event, newMessage => {
2250
- if (isCompactBoundaryMessage(newMessage)) {
2251
- // Fullscreen: keep pre-compact messages for scrollback. query.ts
2252
- // slices at the boundary for API calls, Messages.tsx skips the
2253
- // boundary filter in fullscreen, and useLogMessages treats this
2254
- // as an incremental append (first uuid unchanged). Cap at one
2255
- // compact-interval of scrollback — normalizeMessages/applyGrouping
2256
- // are O(n) per render, so drop everything before the previous
2257
- // boundary to keep n bounded across multi-day sessions.
2258
- if (isFullscreenEnvEnabled()) {
2259
- setMessages(old => [...getMessagesAfterCompactBoundary(old, {
2260
- includeSnipped: true
2261
- }), newMessage]);
2262
- }
2263
- else {
2264
- setMessages(() => [newMessage]);
2265
- }
2266
- // Bump conversationId so Messages.tsx row keys change and
2267
- // stale memoized rows remount with post-compact content.
2268
- setConversationId(randomUUID());
2269
- // Compaction succeeded — clear the context-blocked flag so ticks resume
2270
- if (feature('PROACTIVE') || feature('KAIROS')) {
2271
- proactiveModule?.setContextBlocked(false);
2272
- }
2273
- }
2274
- else if (newMessage.type === 'progress' && isEphemeralToolProgress(newMessage.data.type)) {
2275
- // Replace the previous ephemeral progress tick for the same tool
2276
- // call instead of appending. Sleep/Bash emit a tick per second and
2277
- // only the last one is rendered; appending blows up the messages
2278
- // array (13k+ observed) and the transcript (120MB of sleep_progress
2279
- // lines). useLogMessages tracks length, so same-length replacement
2280
- // also skips the transcript write.
2281
- // agent_progress / hook_progress / skill_progress are NOT ephemeral
2282
- // — each carries distinct state the UI needs (e.g. subagent tool
2283
- // history). Replacing those leaves the AgentTool UI stuck at
2284
- // "Initializing…" because it renders the full progress trail.
2285
- setMessages(oldMessages => {
2286
- const last = oldMessages.at(-1);
2287
- if (last?.type === 'progress' && last.parentToolUseID === newMessage.parentToolUseID && last.data.type === newMessage.data.type) {
2288
- const copy = oldMessages.slice();
2289
- copy[copy.length - 1] = newMessage;
2290
- return copy;
2291
- }
2292
- return [...oldMessages, newMessage];
2293
- });
2294
- }
2295
- else {
2296
- setMessages(oldMessages => [...oldMessages, newMessage]);
2297
- }
2298
- // Block ticks on API errors to prevent tick → error → tick
2299
- // runaway loops (e.g., auth failure, rate limit, blocking limit).
2300
- // Cleared on compact boundary (above) or successful response (below).
2301
- if (feature('PROACTIVE') || feature('KAIROS')) {
2302
- if (newMessage.type === 'assistant' && 'isApiErrorMessage' in newMessage && newMessage.isApiErrorMessage) {
2303
- proactiveModule?.setContextBlocked(true);
2304
- }
2305
- else if (newMessage.type === 'assistant') {
2306
- proactiveModule?.setContextBlocked(false);
2307
- }
2308
- }
2309
- }, newContent => {
2310
- // setResponseLength handles updating both responseLengthRef (for
2311
- // spinner animation) and apiMetricsRef (endResponseLength/lastTokenTime
2312
- // for OTPS). No separate metrics update needed here.
2313
- setResponseLength(length => length + newContent.length);
2314
- }, setStreamMode, setStreamingToolUses, tombstonedMessage => {
2315
- setMessages(oldMessages => oldMessages.filter(m => m !== tombstonedMessage));
2316
- void removeTranscriptMessage(tombstonedMessage.uuid);
2317
- }, setStreamingThinking, metrics => {
2318
- const now = Date.now();
2319
- const baseline = responseLengthRef.current;
2320
- apiMetricsRef.current.push({
2321
- ...metrics,
2322
- firstTokenTime: now,
2323
- lastTokenTime: now,
2324
- responseLengthBaseline: baseline,
2325
- endResponseLength: baseline
2326
- });
2327
- }, onStreamingText);
2328
- }, [setMessages, setResponseLength, setStreamMode, setStreamingToolUses, setStreamingThinking, onStreamingText]);
2329
- const onQueryImpl = useCallback(async (messagesIncludingNewMessages, newMessages, abortController, shouldQuery, additionalAllowedTools, mainLoopModelParam, effort) => {
2330
- // Prepare IDE integration for new prompt. Read mcpClients fresh from
2331
- // store — useManageMCPConnections may have populated it since the
2332
- // render that captured this closure (same pattern as computeTools).
2333
- if (shouldQuery) {
2334
- const freshClients = mergeClients(initialMcpClients, store.getState().mcp.clients);
2335
- void diagnosticTracker.handleQueryStart(freshClients);
2336
- const ideClient = getConnectedIdeClient(freshClients);
2337
- if (ideClient) {
2338
- void closeOpenDiffs(ideClient);
2339
- }
2340
- }
2341
- // Mark onboarding as complete when any user message is sent to Claude
2342
- void maybeMarkProjectOnboardingComplete();
2343
- // Extract a session title from the first real user message. One-shot
2344
- // via ref (was tengu_birch_mist experiment: first-message-only to save
2345
- // Haiku calls). The ref replaces the old `messages.length <= 1` check,
2346
- // which was broken by SessionStart hook messages (prepended via
2347
- // useDeferredHookMessages) and attachment messages (appended by
2348
- // processTextPrompt) — both pushed length past 1 on turn one, so the
2349
- // title silently fell through to the "Context Code" default.
2350
- if (!titleDisabled && !sessionTitle && !agentTitle && !haikuTitleAttemptedRef.current) {
2351
- const firstUserMessage = newMessages.find(m => m.type === 'user' && !m.isMeta);
2352
- const text = firstUserMessage?.type === 'user' ? getContentText(firstUserMessage.message.content) : null;
2353
- // Skip synthetic breadcrumbs — slash-command output, prompt-skill
2354
- // expansions (/commit → <command-message>), local-command headers
2355
- // (/help → <command-name>), and bash-mode (!cmd → <bash-input>).
2356
- // None of these are the user's topic; wait for real prose.
2357
- if (text && !text.startsWith(`<${LOCAL_COMMAND_STDOUT_TAG}>`) && !text.startsWith(`<${COMMAND_MESSAGE_TAG}>`) && !text.startsWith(`<${COMMAND_NAME_TAG}>`) && !text.startsWith(`<${BASH_INPUT_TAG}>`)) {
2358
- haikuTitleAttemptedRef.current = true;
2359
- void generateSessionTitle(text, new AbortController().signal).then(title => {
2360
- if (title)
2361
- setHaikuTitle(title);
2362
- else
2363
- haikuTitleAttemptedRef.current = false;
2364
- }, () => {
2365
- haikuTitleAttemptedRef.current = false;
2366
- });
2367
- }
2368
- }
2369
- // Apply slash-command-scoped allowedTools (from skill frontmatter) to the
2370
- // store once per turn. This also covers the reset: the next non-skill turn
2371
- // passes [] and clears it. Must run before the !shouldQuery gate: forked
2372
- // commands (executeForkedSlashCommand) return shouldQuery=false, and
2373
- // createGetAppStateWithAllowedTools in forkedAgent.ts reads this field, so
2374
- // stale skill tools would otherwise leak into forked agent permissions.
2375
- // Previously this write was hidden inside getToolUseContext's getAppState
2376
- // (~85 calls/turn); hoisting it here makes getAppState a pure read and stops
2377
- // ephemeral contexts (permission dialog, BackgroundTasksDialog) from
2378
- // accidentally clearing it mid-turn.
2379
- store.setState(prev => {
2380
- const cur = prev.toolPermissionContext.alwaysAllowRules.command;
2381
- if (cur === additionalAllowedTools || cur?.length === additionalAllowedTools.length && cur.every((v, i) => v === additionalAllowedTools[i])) {
2382
- return prev;
2383
- }
2384
- return {
2385
- ...prev,
2386
- toolPermissionContext: {
2387
- ...prev.toolPermissionContext,
2388
- alwaysAllowRules: {
2389
- ...prev.toolPermissionContext.alwaysAllowRules,
2390
- command: additionalAllowedTools
2391
- }
2392
- }
2393
- };
2394
- });
2395
- // The last message is an assistant message if the user input was a bash command,
2396
- // or if the user input was an invalid slash command.
2397
- if (!shouldQuery) {
2398
- // Manual /compact sets messages directly (shouldQuery=false) bypassing
2399
- // handleMessageFromStream. Clear context-blocked if a compact boundary
2400
- // is present so proactive ticks resume after compaction.
2401
- if (newMessages.some(isCompactBoundaryMessage)) {
2402
- // Bump conversationId so Messages.tsx row keys change and
2403
- // stale memoized rows remount with post-compact content.
2404
- setConversationId(randomUUID());
2405
- if (feature('PROACTIVE') || feature('KAIROS')) {
2406
- proactiveModule?.setContextBlocked(false);
2407
- }
2408
- }
2409
- resetLoadingState();
2410
- setAbortController(null);
2411
- return;
2412
- }
2413
- const toolUseContext = getToolUseContext(messagesIncludingNewMessages, newMessages, abortController, mainLoopModelParam);
2414
- // getToolUseContext reads tools/mcpClients fresh from store.getState()
2415
- // (via computeTools/mergeClients). Use those rather than the closure-
2416
- // captured `tools`/`mcpClients` — useManageMCPConnections may have
2417
- // flushed new MCP state between the render that captured this closure
2418
- // and now. Turn 1 via processInitialMessage is the main beneficiary.
2419
- const { tools: freshTools, mcpClients: freshMcpClients } = toolUseContext.options;
2420
- // Scope the skill's effort override to this turn's context only —
2421
- // wrapping getAppState keeps the override out of the global store so
2422
- // background agents and UI subscribers (Spinner, LogoV2) never see it.
2423
- if (effort !== undefined) {
2424
- const previousGetAppState = toolUseContext.getAppState;
2425
- toolUseContext.getAppState = () => ({
2426
- ...previousGetAppState(),
2427
- effortValue: effort
2428
- });
2429
- }
2430
- queryCheckpoint('query_context_loading_start');
2431
- const [, , defaultSystemPrompt, baseUserContext, systemContext] = await Promise.all([
2432
- // IMPORTANT: do this after setMessages() above, to avoid UI jank
2433
- checkAndDisableBypassPermissionsIfNeeded(toolPermissionContext, setAppState),
2434
- // Gated on TRANSCRIPT_CLASSIFIER so GrowthBook kill switch runs wherever auto mode is built in
2435
- feature('TRANSCRIPT_CLASSIFIER') ? checkAndDisableAutoModeIfNeeded(toolPermissionContext, setAppState, store.getState().fastMode) : undefined, getSystemPrompt(freshTools, mainLoopModelParam, Array.from(toolPermissionContext.additionalWorkingDirectories.keys()), freshMcpClients), getUserContext(), getSystemContext()
2436
- ]);
2437
- const userContext = {
2438
- ...baseUserContext,
2439
- ...getCoordinatorUserContext(freshMcpClients, isScratchpadEnabled() ? getScratchpadDir() : undefined),
2440
- ...((feature('PROACTIVE') || feature('KAIROS')) && proactiveModule?.isProactiveActive() && !terminalFocusRef.current ? {
2441
- terminalFocus: 'The terminal is unfocused \u2014 the user is not actively watching.'
2442
- } : {})
2443
- };
2444
- queryCheckpoint('query_context_loading_end');
2445
- const systemPrompt = buildEffectiveSystemPrompt({
2446
- mainThreadAgentDefinition,
2447
- toolUseContext,
2448
- customSystemPrompt,
2449
- defaultSystemPrompt,
2450
- appendSystemPrompt
2451
- });
2452
- toolUseContext.renderedSystemPrompt = systemPrompt;
2453
- queryCheckpoint('query_query_start');
2454
- resetTurnHookDuration();
2455
- resetTurnToolDuration();
2456
- resetTurnClassifierDuration();
2457
- for await (const event of query({
2458
- messages: messagesIncludingNewMessages,
2459
- systemPrompt,
2460
- userContext,
2461
- systemContext,
2462
- canUseTool,
2463
- toolUseContext,
2464
- querySource: getQuerySourceForREPL()
2465
- })) {
2466
- onQueryEvent(event);
2467
- }
2468
- if (feature('BUDDY')) {
2469
- void fireCompanionObserver(messagesRef.current, reaction => setAppState(prev => prev.companionReaction === reaction ? prev : {
2470
- ...prev,
2471
- companionReaction: reaction
2472
- }));
2473
- }
2474
- queryCheckpoint('query_end');
2475
- // Capture ant-only API metrics before resetLoadingState clears the ref.
2476
- // For multi-request turns (tool use loops), compute P50 across all requests.
2477
- if ("external" === 'ant' && apiMetricsRef.current.length > 0) {
2478
- const entries = apiMetricsRef.current;
2479
- const ttfts = entries.map(e => e.ttftMs);
2480
- // Compute per-request OTPS using only active streaming time and
2481
- // streaming-only content. endResponseLength tracks content added by
2482
- // streaming deltas only, excluding subagent/compaction inflation.
2483
- const otpsValues = entries.map(e => {
2484
- const delta = Math.round((e.endResponseLength - e.responseLengthBaseline) / 4);
2485
- const samplingMs = e.lastTokenTime - e.firstTokenTime;
2486
- return samplingMs > 0 ? Math.round(delta / (samplingMs / 1000)) : 0;
2487
- });
2488
- const isMultiRequest = entries.length > 1;
2489
- const hookMs = getTurnHookDurationMs();
2490
- const hookCount = getTurnHookCount();
2491
- const toolMs = getTurnToolDurationMs();
2492
- const toolCount = getTurnToolCount();
2493
- const classifierMs = getTurnClassifierDurationMs();
2494
- const classifierCount = getTurnClassifierCount();
2495
- const turnMs = Date.now() - loadingStartTimeRef.current;
2496
- setMessages(prev => [...prev, createApiMetricsMessage({
2497
- ttftMs: isMultiRequest ? median(ttfts) : ttfts[0],
2498
- otps: isMultiRequest ? median(otpsValues) : otpsValues[0],
2499
- isP50: isMultiRequest,
2500
- hookDurationMs: hookMs > 0 ? hookMs : undefined,
2501
- hookCount: hookCount > 0 ? hookCount : undefined,
2502
- turnDurationMs: turnMs > 0 ? turnMs : undefined,
2503
- toolDurationMs: toolMs > 0 ? toolMs : undefined,
2504
- toolCount: toolCount > 0 ? toolCount : undefined,
2505
- classifierDurationMs: classifierMs > 0 ? classifierMs : undefined,
2506
- classifierCount: classifierCount > 0 ? classifierCount : undefined,
2507
- configWriteCount: getGlobalConfigWriteCount()
2508
- })]);
2509
- }
2510
- resetLoadingState();
2511
- // Log query profiling report if enabled
2512
- logQueryProfileReport();
2513
- // Signal that a query turn has completed successfully
2514
- await onTurnComplete?.(messagesRef.current);
2515
- }, [initialMcpClients, resetLoadingState, getToolUseContext, toolPermissionContext, setAppState, customSystemPrompt, onTurnComplete, appendSystemPrompt, canUseTool, mainThreadAgentDefinition, onQueryEvent, sessionTitle, titleDisabled]);
2516
- const onQuery = useCallback(async (newMessages, abortController, shouldQuery, additionalAllowedTools, mainLoopModelParam, onBeforeQueryCallback, input, effort) => {
2517
- // If this is a teammate, mark them as active when starting a turn
2518
- if (isAgentSwarmsEnabled()) {
2519
- const teamName = getTeamName();
2520
- const agentName = getAgentName();
2521
- if (teamName && agentName) {
2522
- // Fire and forget - turn starts immediately, write happens in background
2523
- void setMemberActive(teamName, agentName, true);
2524
- }
2525
- }
2526
- // Concurrent guard via state machine. tryStart() atomically checks
2527
- // and transitions idle→running, returning the generation number.
2528
- // Returns null if already running — no separate check-then-set.
2529
- const thisGeneration = queryGuard.tryStart();
2530
- if (thisGeneration === null) {
2531
- logEvent('tengu_concurrent_onquery_detected', {});
2532
- // Extract and enqueue user message text, skipping meta messages
2533
- // (e.g. expanded skill content, tick prompts) that should not be
2534
- // replayed as user-visible text.
2535
- newMessages.filter((m) => m.type === 'user' && !m.isMeta).map(_ => getContentText(_.message.content)).filter(_ => _ !== null).forEach((msg, i) => {
2536
- enqueue({
2537
- value: msg,
2538
- mode: 'prompt'
2539
- });
2540
- if (i === 0) {
2541
- logEvent('tengu_concurrent_onquery_enqueued', {});
2542
- }
2543
- });
2544
- return;
2545
- }
2546
- try {
2547
- // isLoading is derived from queryGuard — tryStart() above already
2548
- // transitioned dispatching→running, so no setter call needed here.
2549
- resetTimingRefs();
2550
- setMessages(oldMessages => [...oldMessages, ...newMessages]);
2551
- responseLengthRef.current = 0;
2552
- if (feature('TOKEN_BUDGET')) {
2553
- const parsedBudget = input ? parseTokenBudget(input) : null;
2554
- snapshotOutputTokensForTurn(parsedBudget ?? getCurrentTurnTokenBudget());
2555
- }
2556
- apiMetricsRef.current = [];
2557
- setStreamingToolUses([]);
2558
- setStreamingText(null);
2559
- // messagesRef is updated synchronously by the setMessages wrapper
2560
- // above, so it already includes newMessages from the append at the
2561
- // top of this try block. No reconstruction needed, no waiting for
2562
- // React's scheduler (previously cost 20-56ms per prompt; the 56ms
2563
- // case was a GC pause caught during the await).
2564
- const latestMessages = messagesRef.current;
2565
- if (input) {
2566
- await mrOnBeforeQuery(input, latestMessages, newMessages.length);
2567
- }
2568
- // Pass full conversation history to callback
2569
- if (onBeforeQueryCallback && input) {
2570
- const shouldProceed = await onBeforeQueryCallback(input, latestMessages);
2571
- if (!shouldProceed) {
2572
- return;
2573
- }
2574
- }
2575
- await onQueryImpl(latestMessages, newMessages, abortController, shouldQuery, additionalAllowedTools, mainLoopModelParam, effort);
2576
- }
2577
- finally {
2578
- // queryGuard.end() atomically checks generation and transitions
2579
- // running→idle. Returns false if a newer query owns the guard
2580
- // (cancel+resubmit race where the stale finally fires as a microtask).
2581
- if (queryGuard.end(thisGeneration)) {
2582
- setLastQueryCompletionTime(Date.now());
2583
- skipIdleCheckRef.current = false;
2584
- // Always reset loading state in finally - this ensures cleanup even
2585
- // if onQueryImpl throws. onTurnComplete is called separately in
2586
- // onQueryImpl only on successful completion.
2587
- resetLoadingState();
2588
- await mrOnTurnComplete(messagesRef.current, abortController.signal.aborted);
2589
- // Notify bridge clients that the turn is complete so mobile apps
2590
- // can stop the spark animation and show post-turn UI.
2591
- sendBridgeResultRef.current();
2592
- // Auto-hide tungsten panel content at turn end (ant-only), but keep
2593
- // tungstenActiveSession set so the pill stays in the footer and the user
2594
- // can reopen the panel. Background tmux tasks (e.g. /hunter) run for
2595
- // minutes — wiping the session made the pill disappear entirely, forcing
2596
- // the user to re-invoke Tmux just to peek. Skip on abort so the panel
2597
- // stays open for inspection (matches the turn-duration guard below).
2598
- if ("external" === 'ant' && !abortController.signal.aborted) {
2599
- setAppState(prev => {
2600
- if (prev.tungstenActiveSession === undefined)
2601
- return prev;
2602
- if (prev.tungstenPanelAutoHidden === true)
2603
- return prev;
2604
- return {
2605
- ...prev,
2606
- tungstenPanelAutoHidden: true
2607
- };
2608
- });
2609
- }
2610
- // Capture budget info before clearing (ant-only)
2611
- let budgetInfo;
2612
- if (feature('TOKEN_BUDGET')) {
2613
- if (getCurrentTurnTokenBudget() !== null && getCurrentTurnTokenBudget() > 0 && !abortController.signal.aborted) {
2614
- budgetInfo = {
2615
- tokens: getTurnOutputTokens(),
2616
- limit: getCurrentTurnTokenBudget(),
2617
- nudges: getBudgetContinuationCount()
2618
- };
2619
- }
2620
- snapshotOutputTokensForTurn(null);
2621
- }
2622
- // Add turn duration message for turns longer than 30s or with a budget
2623
- // Skip if user aborted or if in loop mode (too noisy between ticks)
2624
- // Defer if swarm teammates are still running (show when they finish)
2625
- const turnDurationMs = Date.now() - loadingStartTimeRef.current - totalPausedMsRef.current;
2626
- if ((turnDurationMs > 30000 || budgetInfo !== undefined) && !abortController.signal.aborted && !proactiveActive) {
2627
- const hasRunningSwarmAgents = getAllInProcessTeammateTasks(store.getState().tasks).some(t => t.status === 'running');
2628
- if (hasRunningSwarmAgents) {
2629
- // Only record start time on the first deferred turn
2630
- if (swarmStartTimeRef.current === null) {
2631
- swarmStartTimeRef.current = loadingStartTimeRef.current;
2632
- }
2633
- // Always update budget — later turns may carry the actual budget
2634
- if (budgetInfo) {
2635
- swarmBudgetInfoRef.current = budgetInfo;
2636
- }
2637
- }
2638
- else {
2639
- setMessages(prev => [...prev, createTurnDurationMessage(turnDurationMs, budgetInfo, count(prev, isLoggableMessage))]);
2640
- }
2641
- }
2642
- // Clear the controller so CancelRequestHandler's canCancelRunningTask
2643
- // reads false at the idle prompt. Without this, the stale non-aborted
2644
- // controller makes ctrl+c fire onCancel() (aborting nothing) instead of
2645
- // propagating to the double-press exit flow.
2646
- setAbortController(null);
2647
- }
2648
- // Auto-restore: if the user interrupted before any meaningful response
2649
- // arrived, rewind the conversation and restore their prompt — same as
2650
- // opening the message selector and picking the last message.
2651
- // This runs OUTSIDE the queryGuard.end() check because onCancel calls
2652
- // forceEnd(), which bumps the generation so end() returns false above.
2653
- // Guards: reason === 'user-cancel' (onCancel/Esc; programmatic aborts
2654
- // use 'background'/'interrupt' and must not rewind — note abort() with
2655
- // no args sets reason to a DOMException, not undefined), !isActive (no
2656
- // newer query started — cancel+resubmit race), empty input (don't
2657
- // clobber text typed during loading), no queued commands (user queued
2658
- // B while A was loading → they've moved on, don't restore A; also
2659
- // avoids removeLastFromHistory removing B's entry instead of A's),
2660
- // not viewing a teammate (messagesRef is the main conversation — the
2661
- // old Up-arrow quick-restore had this guard, preserve it).
2662
- if (abortController.signal.reason === 'user-cancel' && !queryGuard.isActive && inputValueRef.current === '' && getCommandQueueLength() === 0 && !store.getState().viewingAgentTaskId) {
2663
- const msgs = messagesRef.current;
2664
- const lastUserMsg = msgs.findLast(selectableUserMessagesFilter);
2665
- if (lastUserMsg) {
2666
- const idx = msgs.lastIndexOf(lastUserMsg);
2667
- if (messagesAfterAreOnlySynthetic(msgs, idx)) {
2668
- // The submit is being undone — undo its history entry too,
2669
- // otherwise Up-arrow shows the restored text twice.
2670
- removeLastFromHistory();
2671
- restoreMessageSyncRef.current(lastUserMsg);
2672
- }
2673
- }
2674
- }
2675
- }
2676
- }, [onQueryImpl, setAppState, resetLoadingState, queryGuard, mrOnBeforeQuery, mrOnTurnComplete]);
2677
- // Handle initial message (from CLI args or plan mode exit with context clear)
2678
- // This effect runs when isLoading becomes false and there's a pending message
2679
- const initialMessageRef = useRef(false);
2680
- useEffect(() => {
2681
- const pending = initialMessage;
2682
- if (!pending || isLoading || initialMessageRef.current)
2683
- return;
2684
- // Mark as processing to prevent re-entry
2685
- initialMessageRef.current = true;
2686
- async function processInitialMessage(initialMsg) {
2687
- // Clear context if requested (plan mode exit)
2688
- if (initialMsg.clearContext) {
2689
- // Preserve the plan slug before clearing context, so the new session
2690
- // can access the same plan file after regenerateSessionId()
2691
- const oldPlanSlug = initialMsg.message.planContent ? getPlanSlug() : undefined;
2692
- const { clearConversation } = await import('../commands/clear/conversation.js');
2693
- await clearConversation({
2694
- setMessages,
2695
- readFileState: readFileState.current,
2696
- discoveredSkillNames: discoveredSkillNamesRef.current,
2697
- loadedNestedMemoryPaths: loadedNestedMemoryPathsRef.current,
2698
- getAppState: () => store.getState(),
2699
- setAppState,
2700
- setConversationId
2701
- });
2702
- haikuTitleAttemptedRef.current = false;
2703
- setHaikuTitle(undefined);
2704
- bashTools.current.clear();
2705
- bashToolsProcessedIdx.current = 0;
2706
- // Restore the plan slug for the new session so getPlan() finds the file
2707
- if (oldPlanSlug) {
2708
- setPlanSlug(getSessionId(), oldPlanSlug);
2709
- }
2710
- }
2711
- // Atomically: clear initial message, set permission mode and rules, and store plan for verification
2712
- const shouldStorePlanForVerification = initialMsg.message.planContent && "external" === 'ant' && isEnvTruthy(undefined);
2713
- setAppState(prev => {
2714
- // Build and apply permission updates (mode + allowedPrompts rules)
2715
- let updatedToolPermissionContext = initialMsg.mode ? applyPermissionUpdates(prev.toolPermissionContext, buildPermissionUpdates(initialMsg.mode, initialMsg.allowedPrompts)) : prev.toolPermissionContext;
2716
- // For auto, override the mode (buildPermissionUpdates maps
2717
- // it to 'default' via toExternalPermissionMode) and strip dangerous rules
2718
- if (feature('TRANSCRIPT_CLASSIFIER') && initialMsg.mode === 'auto') {
2719
- updatedToolPermissionContext = stripDangerousPermissionsForAutoMode({
2720
- ...updatedToolPermissionContext,
2721
- mode: 'auto',
2722
- prePlanMode: undefined
2723
- });
2724
- }
2725
- return {
2726
- ...prev,
2727
- initialMessage: null,
2728
- toolPermissionContext: updatedToolPermissionContext,
2729
- ...(shouldStorePlanForVerification && {
2730
- pendingPlanVerification: {
2731
- plan: initialMsg.message.planContent,
2732
- verificationStarted: false,
2733
- verificationCompleted: false
2734
- }
2735
- })
2736
- };
2737
- });
2738
- // Create file history snapshot for code rewind
2739
- if (fileHistoryEnabled()) {
2740
- void fileHistoryMakeSnapshot((updater) => {
2741
- setAppState(prev => ({
2742
- ...prev,
2743
- fileHistory: updater(prev.fileHistory)
2744
- }));
2745
- }, initialMsg.message.uuid);
2746
- }
2747
- // Ensure SessionStart hook context is available before the first API
2748
- // call. onSubmit calls this internally but the onQuery path below
2749
- // bypasses onSubmit — hoist here so both paths see hook messages.
2750
- await awaitPendingHooks();
2751
- // Route all initial prompts through onSubmit to ensure UserPromptSubmit hooks fire
2752
- // TODO: Simplify by always routing through onSubmit once it supports
2753
- // ContentBlockParam arrays (images) as input
2754
- const content = initialMsg.message.message.content;
2755
- // Route all string content through onSubmit to ensure hooks fire
2756
- // For complex content (images, etc.), fall back to direct onQuery
2757
- // Plan messages bypass onSubmit to preserve planContent metadata for rendering
2758
- if (typeof content === 'string' && !initialMsg.message.planContent) {
2759
- // Route through onSubmit for proper processing including UserPromptSubmit hooks
2760
- void onSubmit(content, {
2761
- setCursorOffset: () => { },
2762
- clearBuffer: () => { },
2763
- resetHistory: () => { }
2764
- });
2765
- }
2766
- else {
2767
- // Plan messages or complex content (images, etc.) - send directly to model
2768
- // Plan messages use onQuery to preserve planContent metadata for rendering
2769
- // TODO: Once onSubmit supports ContentBlockParam arrays, remove this branch
2770
- const newAbortController = createAbortController();
2771
- setAbortController(newAbortController);
2772
- void onQuery([initialMsg.message], newAbortController, true,
2773
- // shouldQuery
2774
- [],
2775
- // additionalAllowedTools
2776
- mainLoopModel);
2777
- }
2778
- // Reset ref after a delay to allow new initial messages
2779
- setTimeout(ref => {
2780
- ref.current = false;
2781
- }, 100, initialMessageRef);
2782
- }
2783
- void processInitialMessage(pending);
2784
- }, [initialMessage, isLoading, setMessages, setAppState, onQuery, mainLoopModel, tools]);
2785
- const onSubmit = useCallback(async (input, helpers, speculationAccept, options) => {
2786
- // Re-pin scroll to bottom on submit so the user always sees the new
2787
- // exchange (matches OpenCode's auto-scroll behavior).
2788
- repinScroll();
2789
- // Resume loop mode if paused
2790
- if (feature('PROACTIVE') || feature('KAIROS')) {
2791
- proactiveModule?.resumeProactive();
2792
- }
2793
- // Handle immediate commands - these bypass the queue and execute right away
2794
- // even while Claude is processing. Commands opt-in via `immediate: true`.
2795
- // Commands triggered via keybindings are always treated as immediate.
2796
- if (!speculationAccept && input.trim().startsWith('/')) {
2797
- // Expand [Pasted text #N] refs so immediate commands (e.g. /btw) receive
2798
- // the pasted content, not the placeholder. The non-immediate path gets
2799
- // this expansion later in handlePromptSubmit.
2800
- const trimmedInput = expandPastedTextRefs(input, pastedContents).trim();
2801
- const spaceIndex = trimmedInput.indexOf(' ');
2802
- const commandName = spaceIndex === -1 ? trimmedInput.slice(1) : trimmedInput.slice(1, spaceIndex);
2803
- const commandArgs = spaceIndex === -1 ? '' : trimmedInput.slice(spaceIndex + 1).trim();
2804
- // Find matching command - treat as immediate if:
2805
- // 1. Command has `immediate: true`, OR
2806
- // 2. Command was triggered via keybinding (fromKeybinding option)
2807
- const matchingCommand = commands.find(cmd => isCommandEnabled(cmd) && (cmd.name === commandName || cmd.aliases?.includes(commandName) || getCommandName(cmd) === commandName));
2808
- if (matchingCommand?.name === 'clear' && idleHintShownRef.current) {
2809
- logEvent('tengu_idle_return_action', {
2810
- action: 'hint_converted',
2811
- variant: idleHintShownRef.current,
2812
- idleMinutes: Math.round((Date.now() - lastQueryCompletionTimeRef.current) / 60_000),
2813
- messageCount: messagesRef.current.length,
2814
- totalInputTokens: getTotalInputTokens()
2815
- });
2816
- idleHintShownRef.current = false;
2817
- }
2818
- const shouldTreatAsImmediate = queryGuard.isActive && (matchingCommand?.immediate || options?.fromKeybinding);
2819
- if (matchingCommand && shouldTreatAsImmediate && matchingCommand.type === 'local-jsx') {
2820
- // Only clear input if the submitted text matches what's in the prompt.
2821
- // When a command keybinding fires, input is "/<command>" but the actual
2822
- // input value is the user's existing text - don't clear it in that case.
2823
- if (input.trim() === inputValueRef.current.trim()) {
2824
- setInputValue('');
2825
- helpers.setCursorOffset(0);
2826
- helpers.clearBuffer();
2827
- setPastedContents({});
2828
- }
2829
- const pastedTextRefs = parseReferences(input).filter(r => pastedContents[r.id]?.type === 'text');
2830
- const pastedTextCount = pastedTextRefs.length;
2831
- const pastedTextBytes = pastedTextRefs.reduce((sum, r) => sum + (pastedContents[r.id]?.content.length ?? 0), 0);
2832
- logEvent('tengu_paste_text', {
2833
- pastedTextCount,
2834
- pastedTextBytes
2835
- });
2836
- logEvent('tengu_immediate_command_executed', {
2837
- commandName: matchingCommand.name,
2838
- fromKeybinding: options?.fromKeybinding ?? false
2839
- });
2840
- // Execute the command directly
2841
- const executeImmediateCommand = async () => {
2842
- let doneWasCalled = false;
2843
- const onDone = (result, doneOptions) => {
2844
- doneWasCalled = true;
2845
- setToolJSX({
2846
- jsx: null,
2847
- shouldHidePromptInput: false,
2848
- clearLocalJSX: true
2849
- });
2850
- const newMessages = [];
2851
- if (result && doneOptions?.display !== 'skip') {
2852
- addNotification({
2853
- key: `immediate-${matchingCommand.name}`,
2854
- text: result,
2855
- priority: 'immediate'
2856
- });
2857
- // In fullscreen the command just showed as a centered modal
2858
- // pane — the notification above is enough feedback. Adding
2859
- // "❯ /config" + "⎿ dismissed" to the transcript is clutter
2860
- // (those messages are type:system subtype:local_command —
2861
- // user-visible but NOT sent to the model, so skipping them
2862
- // doesn't change model context). Outside fullscreen the
2863
- // transcript entry stays so scrollback shows what ran.
2864
- if (!isFullscreenEnvEnabled()) {
2865
- newMessages.push(createCommandInputMessage(formatCommandInputTags(getCommandName(matchingCommand), commandArgs)), createCommandInputMessage(`<${LOCAL_COMMAND_STDOUT_TAG}>${escapeXml(result)}</${LOCAL_COMMAND_STDOUT_TAG}>`));
2866
- }
2867
- }
2868
- // Inject meta messages (model-visible, user-hidden) into the transcript
2869
- if (doneOptions?.metaMessages?.length) {
2870
- newMessages.push(...doneOptions.metaMessages.map(content => createUserMessage({
2871
- content,
2872
- isMeta: true
2873
- })));
2874
- }
2875
- if (newMessages.length) {
2876
- setMessages(prev => [...prev, ...newMessages]);
2877
- }
2878
- // Restore stashed prompt after local-jsx command completes.
2879
- // The normal stash restoration path (below) is skipped because
2880
- // local-jsx commands return early from onSubmit.
2881
- if (stashedPrompt !== undefined) {
2882
- setInputValue(stashedPrompt.text);
2883
- helpers.setCursorOffset(stashedPrompt.cursorOffset);
2884
- setPastedContents(stashedPrompt.pastedContents);
2885
- setStashedPrompt(undefined);
2886
- }
2887
- };
2888
- // Build context for the command (reuses existing getToolUseContext).
2889
- // Read messages via ref to keep onSubmit stable across message
2890
- // updates — matches the pattern at L2384/L2400/L2662 and avoids
2891
- // pinning stale REPL render scopes in downstream closures.
2892
- const context = getToolUseContext(messagesRef.current, [], createAbortController(), mainLoopModel);
2893
- const mod = await matchingCommand.load();
2894
- const jsx = await mod.call(onDone, context, commandArgs);
2895
- // Skip if onDone already fired — prevents stuck isLocalJSXCommand
2896
- // (see processSlashCommand.tsx local-jsx case for full mechanism).
2897
- if (jsx && !doneWasCalled) {
2898
- // shouldHidePromptInput: false keeps Notifications mounted
2899
- // so the onDone result isn't lost
2900
- setToolJSX({
2901
- jsx,
2902
- shouldHidePromptInput: false,
2903
- isLocalJSXCommand: true
2904
- });
2905
- }
2906
- };
2907
- void executeImmediateCommand();
2908
- return; // Always return early - don't add to history or queue
2909
- }
2910
- }
2911
- // Remote mode: skip empty input early before any state mutations
2912
- if (activeRemote.isRemoteMode && !input.trim()) {
2913
- return;
2914
- }
2915
- // Idle-return: prompt returning users to start fresh when the
2916
- // conversation is large and the cache is cold. tengu_willow_mode
2917
- // controls treatment: "dialog" (blocking), "hint" (notification), "off".
2918
- {
2919
- const willowMode = getFeatureValue_CACHED_MAY_BE_STALE('tengu_willow_mode', 'off');
2920
- const idleThresholdMin = Number(process.env.CLAUDE_CODE_IDLE_THRESHOLD_MINUTES ?? 75);
2921
- const tokenThreshold = Number(process.env.CLAUDE_CODE_IDLE_TOKEN_THRESHOLD ?? 100_000);
2922
- if (willowMode !== 'off' && !getGlobalConfig().idleReturnDismissed && !skipIdleCheckRef.current && !speculationAccept && !input.trim().startsWith('/') && lastQueryCompletionTimeRef.current > 0 && getTotalInputTokens() >= tokenThreshold) {
2923
- const idleMs = Date.now() - lastQueryCompletionTimeRef.current;
2924
- const idleMinutes = idleMs / 60_000;
2925
- if (idleMinutes >= idleThresholdMin && willowMode === 'dialog') {
2926
- setIdleReturnPending({
2927
- input,
2928
- idleMinutes
2929
- });
2930
- setInputValue('');
2931
- helpers.setCursorOffset(0);
2932
- helpers.clearBuffer();
2933
- return;
2934
- }
2935
- }
2936
- }
2937
- // Add to history for direct user submissions.
2938
- // Queued command processing (executeQueuedInput) doesn't call onSubmit,
2939
- // so notifications and already-queued user input won't be added to history here.
2940
- // Skip history for keybinding-triggered commands (user didn't type the command).
2941
- if (!options?.fromKeybinding) {
2942
- addToHistory({
2943
- display: speculationAccept ? input : prependModeCharacterToInput(input, inputMode),
2944
- pastedContents: speculationAccept ? {} : pastedContents
2945
- });
2946
- // Add the just-submitted command to the front of the ghost-text
2947
- // cache so it's suggested immediately (not after the 60s TTL).
2948
- if (inputMode === 'bash') {
2949
- prependToShellHistoryCache(input.trim());
2950
- }
2951
- }
2952
- // Restore stash if present, but NOT for slash commands or when loading.
2953
- // - Slash commands (especially interactive ones like /model, /context) hide
2954
- // the prompt and show a picker UI. Restoring the stash during a command would
2955
- // place the text in a hidden input, and the user would lose it by typing the
2956
- // next command. Instead, preserve the stash so it survives across command runs.
2957
- // - When loading, the submitted input will be queued and handlePromptSubmit
2958
- // will clear the input field (onInputChange('')), which would clobber the
2959
- // restored stash. Defer restoration to after handlePromptSubmit (below).
2960
- // Remote mode is exempt: it sends via WebSocket and returns early without
2961
- // calling handlePromptSubmit, so there's no clobbering risk — restore eagerly.
2962
- // In both deferred cases, the stash is restored after await handlePromptSubmit.
2963
- const isSlashCommand = !speculationAccept && input.trim().startsWith('/');
2964
- // Submit runs "now" (not queued) when not already loading, or when
2965
- // accepting speculation, or in remote mode (which sends via WS and
2966
- // returns early without calling handlePromptSubmit).
2967
- const submitsNow = !isLoading || speculationAccept || activeRemote.isRemoteMode;
2968
- if (stashedPrompt !== undefined && !isSlashCommand && submitsNow) {
2969
- setInputValue(stashedPrompt.text);
2970
- helpers.setCursorOffset(stashedPrompt.cursorOffset);
2971
- setPastedContents(stashedPrompt.pastedContents);
2972
- setStashedPrompt(undefined);
2973
- }
2974
- else if (submitsNow) {
2975
- if (!options?.fromKeybinding) {
2976
- // Clear input when not loading or accepting speculation.
2977
- // Preserve input for keybinding-triggered commands.
2978
- setInputValue('');
2979
- helpers.setCursorOffset(0);
2980
- }
2981
- setPastedContents({});
2982
- }
2983
- if (submitsNow) {
2984
- setInputMode('prompt');
2985
- setIDESelection(undefined);
2986
- setSubmitCount(_ => _ + 1);
2987
- helpers.clearBuffer();
2988
- tipPickedThisTurnRef.current = false;
2989
- // Show the placeholder in the same React batch as setInputValue('').
2990
- // Skip for slash/bash (they have their own echo), speculation and remote
2991
- // mode (both setMessages directly with no gap to bridge).
2992
- if (!isSlashCommand && inputMode === 'prompt' && !speculationAccept && !activeRemote.isRemoteMode) {
2993
- setUserInputOnProcessing(input);
2994
- // showSpinner includes userInputOnProcessing, so the spinner appears
2995
- // on this render. Reset timing refs now (before queryGuard.reserve()
2996
- // would) so elapsed time doesn't read as Date.now() - 0. The
2997
- // isQueryActive transition above does the same reset — idempotent.
2998
- resetTimingRefs();
2999
- }
3000
- // Increment prompt count for attribution tracking and save snapshot
3001
- // The snapshot persists promptCount so it survives compaction
3002
- if (feature('COMMIT_ATTRIBUTION')) {
3003
- setAppState(prev => ({
3004
- ...prev,
3005
- attribution: incrementPromptCount(prev.attribution, snapshot => {
3006
- void recordAttributionSnapshot(snapshot).catch(error => {
3007
- logForDebugging(`Attribution: Failed to save snapshot: ${error}`);
3008
- });
3009
- })
3010
- }));
3011
- }
3012
- }
3013
- // Handle speculation acceptance
3014
- if (speculationAccept) {
3015
- const { queryRequired } = await handleSpeculationAccept(speculationAccept.state, speculationAccept.speculationSessionTimeSavedMs, speculationAccept.setAppState, input, {
3016
- setMessages,
3017
- readFileState,
3018
- cwd: getOriginalCwd()
3019
- });
3020
- if (queryRequired) {
3021
- const newAbortController = createAbortController();
3022
- setAbortController(newAbortController);
3023
- void onQuery([], newAbortController, true, [], mainLoopModel);
3024
- }
3025
- return;
3026
- }
3027
- // Remote mode: send input via stream-json instead of local query.
3028
- // Permission requests from the remote are bridged into toolUseConfirmQueue
3029
- // and rendered using the standard PermissionRequest component.
3030
- //
3031
- // local-jsx slash commands (e.g. /agents, /config) render UI in THIS
3032
- // process — they have no remote equivalent. Let those fall through to
3033
- // handlePromptSubmit so they execute locally. Prompt commands and
3034
- // plain text go to the remote.
3035
- if (activeRemote.isRemoteMode && !(isSlashCommand && commands.find(c => {
3036
- const name = input.trim().slice(1).split(/\s/)[0];
3037
- return isCommandEnabled(c) && (c.name === name || c.aliases?.includes(name) || getCommandName(c) === name);
3038
- })?.type === 'local-jsx')) {
3039
- // Build content blocks when there are pasted attachments (images)
3040
- const pastedValues = Object.values(pastedContents);
3041
- const imageContents = pastedValues.filter(c => c.type === 'image');
3042
- const imagePasteIds = imageContents.length > 0 ? imageContents.map(c => c.id) : undefined;
3043
- let messageContent = input.trim();
3044
- let remoteContent = input.trim();
3045
- if (pastedValues.length > 0) {
3046
- const contentBlocks = [];
3047
- const remoteBlocks = [];
3048
- const trimmedInput = input.trim();
3049
- if (trimmedInput) {
3050
- contentBlocks.push({
3051
- type: 'text',
3052
- text: trimmedInput
3053
- });
3054
- remoteBlocks.push({
3055
- type: 'text',
3056
- text: trimmedInput
3057
- });
3058
- }
3059
- for (const pasted of pastedValues) {
3060
- if (pasted.type === 'image') {
3061
- const source = {
3062
- type: 'base64',
3063
- media_type: (pasted.mediaType ?? 'image/png'),
3064
- data: pasted.content
3065
- };
3066
- contentBlocks.push({
3067
- type: 'image',
3068
- source
3069
- });
3070
- remoteBlocks.push({
3071
- type: 'image',
3072
- source
3073
- });
3074
- }
3075
- else {
3076
- contentBlocks.push({
3077
- type: 'text',
3078
- text: pasted.content
3079
- });
3080
- remoteBlocks.push({
3081
- type: 'text',
3082
- text: pasted.content
3083
- });
3084
- }
3085
- }
3086
- messageContent = contentBlocks;
3087
- remoteContent = remoteBlocks;
3088
- }
3089
- // Create and add user message to UI
3090
- // Note: empty input already handled by early return above
3091
- const userMessage = createUserMessage({
3092
- content: messageContent,
3093
- imagePasteIds
3094
- });
3095
- setMessages(prev => [...prev, userMessage]);
3096
- // Send to remote session
3097
- await activeRemote.sendMessage(remoteContent, {
3098
- uuid: userMessage.uuid
3099
- });
3100
- return;
3101
- }
3102
- // Ensure SessionStart hook context is available before the first API call.
3103
- await awaitPendingHooks();
3104
- await handlePromptSubmit({
3105
- input,
3106
- helpers,
3107
- queryGuard,
3108
- isExternalLoading,
3109
- mode: inputMode,
3110
- commands,
3111
- onInputChange: setInputValue,
3112
- setPastedContents,
3113
- setToolJSX,
3114
- getToolUseContext,
3115
- messages: messagesRef.current,
3116
- mainLoopModel,
3117
- pastedContents,
3118
- ideSelection,
3119
- setUserInputOnProcessing,
3120
- setAbortController,
3121
- abortController,
3122
- onQuery,
3123
- setAppState,
3124
- querySource: getQuerySourceForREPL(),
3125
- onBeforeQuery,
3126
- canUseTool,
3127
- addNotification,
3128
- setMessages,
3129
- // Read via ref so streamMode can be dropped from onSubmit deps —
3130
- // handlePromptSubmit only uses it for debug log + telemetry event.
3131
- streamMode: streamModeRef.current,
3132
- hasInterruptibleToolInProgress: hasInterruptibleToolInProgressRef.current
3133
- });
3134
- // Restore stash that was deferred above. Two cases:
3135
- // - Slash command: handlePromptSubmit awaited the full command execution
3136
- // (including interactive pickers). Restoring now places the stash back in
3137
- // the visible input.
3138
- // - Loading (queued): handlePromptSubmit enqueued + cleared input, then
3139
- // returned quickly. Restoring now places the stash back after the clear.
3140
- if ((isSlashCommand || isLoading) && stashedPrompt !== undefined) {
3141
- setInputValue(stashedPrompt.text);
3142
- helpers.setCursorOffset(stashedPrompt.cursorOffset);
3143
- setPastedContents(stashedPrompt.pastedContents);
3144
- setStashedPrompt(undefined);
3145
- }
3146
- }, [queryGuard,
3147
- // isLoading is read at the !isLoading checks above for input-clearing
3148
- // and submitCount gating. It's derived from isQueryActive || isExternalLoading,
3149
- // so including it here ensures the closure captures the fresh value.
3150
- isLoading, isExternalLoading, inputMode, commands, setInputValue, setInputMode, setPastedContents, setSubmitCount, setIDESelection, setToolJSX, getToolUseContext,
3151
- // messages is read via messagesRef.current inside the callback to
3152
- // keep onSubmit stable across message updates (see L2384/L2400/L2662).
3153
- // Without this, each setMessages call (~30× per turn) recreates
3154
- // onSubmit, pinning the REPL render scope (1776B) + that render's
3155
- // messages array in downstream closures (PromptInput, handleAutoRunIssue).
3156
- // Heap analysis showed ~9 REPL scopes and ~15 messages array versions
3157
- // accumulating after #20174/#20175, all traced to this dep.
3158
- mainLoopModel, pastedContents, ideSelection, setUserInputOnProcessing, setAbortController, addNotification, onQuery, stashedPrompt, setStashedPrompt, setAppState, onBeforeQuery, canUseTool, remoteSession, setMessages, awaitPendingHooks, repinScroll]);
3159
- // Callback for when user submits input while viewing a teammate's transcript
3160
- const onAgentSubmit = useCallback(async (input, task, helpers) => {
3161
- if (isLocalAgentTask(task)) {
3162
- appendMessageToLocalAgent(task.id, createUserMessage({
3163
- content: input
3164
- }), setAppState);
3165
- if (task.status === 'running') {
3166
- queuePendingMessage(task.id, input, setAppState);
3167
- }
3168
- else {
3169
- void resumeAgentBackground({
3170
- agentId: task.id,
3171
- prompt: input,
3172
- toolUseContext: getToolUseContext(messagesRef.current, [], new AbortController(), mainLoopModel),
3173
- canUseTool
3174
- }).catch(err => {
3175
- logForDebugging(`resumeAgentBackground failed: ${errorMessage(err)}`);
3176
- addNotification({
3177
- key: `resume-agent-failed-${task.id}`,
3178
- jsx: _jsxs(Text, { color: "error", children: ["Failed to resume agent: ", errorMessage(err)] }),
3179
- priority: 'low'
3180
- });
3181
- });
3182
- }
3183
- }
3184
- else {
3185
- injectUserMessageToTeammate(task.id, input, setAppState);
3186
- }
3187
- setInputValue('');
3188
- helpers.setCursorOffset(0);
3189
- helpers.clearBuffer();
3190
- }, [setAppState, setInputValue, getToolUseContext, canUseTool, mainLoopModel, addNotification]);
3191
- // Handlers for auto-run /issue or /good-claude (defined after onSubmit)
3192
- const handleAutoRunIssue = useCallback(() => {
3193
- const command = autoRunIssueReason ? getAutoRunCommand(autoRunIssueReason) : '/issue';
3194
- setAutoRunIssueReason(null); // Clear the state
3195
- onSubmit(command, {
3196
- setCursorOffset: () => { },
3197
- clearBuffer: () => { },
3198
- resetHistory: () => { }
3199
- }).catch(err => {
3200
- logForDebugging(`Auto-run ${command} failed: ${errorMessage(err)}`);
3201
- });
3202
- }, [onSubmit, autoRunIssueReason]);
3203
- const handleCancelAutoRunIssue = useCallback(() => {
3204
- setAutoRunIssueReason(null);
3205
- }, []);
3206
- // Handler for when user presses 1 on survey thanks screen to share details
3207
- const handleSurveyRequestFeedback = useCallback(() => {
3208
- const command = "external" === 'ant' ? '/issue' : '/feedback';
3209
- onSubmit(command, {
3210
- setCursorOffset: () => { },
3211
- clearBuffer: () => { },
3212
- resetHistory: () => { }
3213
- }).catch(err => {
3214
- logForDebugging(`Survey feedback request failed: ${err instanceof Error ? err.message : String(err)}`);
3215
- });
3216
- }, [onSubmit]);
3217
- // onSubmit is unstable (deps include `messages` which changes every turn).
3218
- // `handleOpenRateLimitOptions` is prop-drilled to every MessageRow, and each
3219
- // MessageRow fiber pins the closure (and transitively the entire REPL render
3220
- // scope, ~1.8KB) at mount time. Using a ref keeps this callback stable so
3221
- // old REPL scopes can be GC'd — saves ~35MB over a 1000-turn session.
3222
- const onSubmitRef = useRef(onSubmit);
3223
- onSubmitRef.current = onSubmit;
3224
- const handleOpenRateLimitOptions = useCallback(() => {
3225
- void onSubmitRef.current('/rate-limit-options', {
3226
- setCursorOffset: () => { },
3227
- clearBuffer: () => { },
3228
- resetHistory: () => { }
3229
- });
3230
- }, []);
3231
- const handleExit = useCallback(async () => {
3232
- setIsExiting(true);
3233
- // In bg sessions, always detach instead of kill — even when a worktree is
3234
- // active. Without this guard, the worktree branch below short-circuits into
3235
- // ExitFlow (which calls gracefulShutdown) before exit.tsx is ever loaded.
3236
- if (feature('BG_SESSIONS') && isBgSession()) {
3237
- spawnSync('tmux', ['detach-client'], {
3238
- stdio: 'ignore'
3239
- });
3240
- setIsExiting(false);
3241
- return;
3242
- }
3243
- const showWorktree = getCurrentWorktreeSession() !== null;
3244
- if (showWorktree) {
3245
- setExitFlow(_jsx(ExitFlow, { showWorktree: true, onDone: () => { }, onCancel: () => {
3246
- setExitFlow(null);
3247
- setIsExiting(false);
3248
- } }));
3249
- return;
3250
- }
3251
- const exitMod = await exit.load();
3252
- const exitFlowResult = await exitMod.call(() => { });
3253
- setExitFlow(exitFlowResult);
3254
- // If call() returned without killing the process (bg session detach),
3255
- // clear isExiting so the UI is usable on reattach. No-op on the normal
3256
- // path — gracefulShutdown's process.exit() means we never get here.
3257
- if (exitFlowResult === null) {
3258
- setIsExiting(false);
3259
- }
3260
- }, []);
3261
- const handleShowMessageSelector = useCallback(() => {
3262
- setIsMessageSelectorVisible(prev => !prev);
3263
- }, []);
3264
- // Rewind conversation state to just before `message`: slice messages,
3265
- // reset conversation ID, microcompact state, permission mode, prompt suggestion.
3266
- // Does NOT touch the prompt input. Index is computed from messagesRef (always
3267
- // fresh via the setMessages wrapper) so callers don't need to worry about
3268
- // stale closures.
3269
- const rewindConversationTo = useCallback((message) => {
3270
- const prev = messagesRef.current;
3271
- const messageIndex = prev.lastIndexOf(message);
3272
- if (messageIndex === -1)
3273
- return;
3274
- logEvent('tengu_conversation_rewind', {
3275
- preRewindMessageCount: prev.length,
3276
- postRewindMessageCount: messageIndex,
3277
- messagesRemoved: prev.length - messageIndex,
3278
- rewindToMessageIndex: messageIndex
3279
- });
3280
- setMessages(prev.slice(0, messageIndex));
3281
- // Careful, this has to happen after setMessages
3282
- setConversationId(randomUUID());
3283
- // Reset cached microcompact state so stale pinned cache edits
3284
- // don't reference tool_use_ids from truncated messages
3285
- resetMicrocompactState();
3286
- if (feature('CONTEXT_COLLAPSE')) {
3287
- // Rewind truncates the REPL array. Commits whose archived span
3288
- // was past the rewind point can't be projected anymore
3289
- // (projectView silently skips them) but the staged queue and ID
3290
- // maps reference stale uuids. Simplest safe reset: drop
3291
- // everything. The ctx-agent will re-stage on the next
3292
- // threshold crossing.
3293
- /* eslint-disable @typescript-eslint/no-require-imports */
3294
- ;
3295
- require('../services/contextCollapse/index.js').resetContextCollapse();
3296
- /* eslint-enable @typescript-eslint/no-require-imports */
3297
- }
3298
- // Restore state from the message we're rewinding to
3299
- setAppState(prev => ({
3300
- ...prev,
3301
- // Restore permission mode from the message
3302
- toolPermissionContext: message.permissionMode && prev.toolPermissionContext.mode !== message.permissionMode ? {
3303
- ...prev.toolPermissionContext,
3304
- mode: message.permissionMode
3305
- } : prev.toolPermissionContext,
3306
- // Clear stale prompt suggestion from previous conversation state
3307
- promptSuggestion: {
3308
- text: null,
3309
- promptId: null,
3310
- shownAt: 0,
3311
- acceptedAt: 0,
3312
- generationRequestId: null
3313
- }
3314
- }));
3315
- }, [setMessages, setAppState]);
3316
- // Synchronous rewind + input population. Used directly by auto-restore on
3317
- // interrupt (so React batches with the abort's setMessages → single render,
3318
- // no flicker). MessageSelector wraps this in setImmediate via handleRestoreMessage.
3319
- const restoreMessageSync = useCallback((message) => {
3320
- rewindConversationTo(message);
3321
- const r = textForResubmit(message);
3322
- if (r) {
3323
- setInputValue(r.text);
3324
- setInputMode(r.mode);
3325
- }
3326
- // Restore pasted images
3327
- if (Array.isArray(message.message.content) && message.message.content.some(block => block.type === 'image')) {
3328
- const imageBlocks = message.message.content.filter(block => block.type === 'image');
3329
- if (imageBlocks.length > 0) {
3330
- const newPastedContents = {};
3331
- imageBlocks.forEach((block, index) => {
3332
- if (block.source.type === 'base64') {
3333
- const id = message.imagePasteIds?.[index] ?? index + 1;
3334
- newPastedContents[id] = {
3335
- id,
3336
- type: 'image',
3337
- content: block.source.data,
3338
- mediaType: block.source.media_type
3339
- };
3340
- }
3341
- });
3342
- setPastedContents(newPastedContents);
3343
- }
3344
- }
3345
- }, [rewindConversationTo, setInputValue]);
3346
- restoreMessageSyncRef.current = restoreMessageSync;
3347
- // MessageSelector path: defer via setImmediate so the "Interrupted" message
3348
- // renders to static output before rewind — otherwise it remains vestigial
3349
- // at the top of the screen.
3350
- const handleRestoreMessage = useCallback(async (message) => {
3351
- setImmediate((restore, message) => restore(message), restoreMessageSync, message);
3352
- }, [restoreMessageSync]);
3353
- // Not memoized — hook stores caps via ref, reads latest closure at dispatch.
3354
- // 24-char prefix: deriveUUID preserves first 24, renderable uuid prefix-matches raw source.
3355
- const findRawIndex = (uuid) => {
3356
- const prefix = uuid.slice(0, 24);
3357
- return messages.findIndex(m => m.uuid.slice(0, 24) === prefix);
3358
- };
3359
- const messageActionCaps = {
3360
- copy: text =>
3361
- // setClipboard RETURNS OSC 52 — caller must stdout.write (tmux side-effects load-buffer, but that's tmux-only).
3362
- void setClipboard(text).then(raw => {
3363
- if (raw)
3364
- process.stdout.write(raw);
3365
- addNotification({
3366
- // Same key as text-selection copy — repeated copies replace toast, don't queue.
3367
- key: 'selection-copied',
3368
- text: 'copied',
3369
- color: 'success',
3370
- priority: 'immediate',
3371
- timeoutMs: 2000
3372
- });
3373
- }),
3374
- edit: async (msg) => {
3375
- // Same skip-confirm check as /rewind: lossless → direct, else confirm dialog.
3376
- const rawIdx = findRawIndex(msg.uuid);
3377
- const raw = rawIdx >= 0 ? messages[rawIdx] : undefined;
3378
- if (!raw || !selectableUserMessagesFilter(raw))
3379
- return;
3380
- const noFileChanges = !(await fileHistoryHasAnyChanges(fileHistory, raw.uuid));
3381
- const onlySynthetic = messagesAfterAreOnlySynthetic(messages, rawIdx);
3382
- if (noFileChanges && onlySynthetic) {
3383
- // rewindConversationTo's setMessages races stream appends — cancel first (idempotent).
3384
- onCancel();
3385
- // handleRestoreMessage also restores pasted images.
3386
- void handleRestoreMessage(raw);
3387
- }
3388
- else {
3389
- // Dialog path: onPreRestore (= onCancel) fires when user CONFIRMS, not on nevermind.
3390
- setMessageSelectorPreselect(raw);
3391
- setIsMessageSelectorVisible(true);
3392
- }
3393
- }
3394
- };
3395
- const { enter: enterMessageActions, handlers: messageActionHandlers } = useMessageActions(cursor, setCursor, cursorNavRef, messageActionCaps);
3396
- async function onInit() {
3397
- // Always verify API key on startup, so we can show the user an error in the
3398
- // bottom right corner of the screen if the API key is invalid.
3399
- void reverify();
3400
- // Populate readFileState with CLAUDE.md files at startup
3401
- const memoryFiles = await getMemoryFiles();
3402
- if (memoryFiles.length > 0) {
3403
- const fileList = memoryFiles.map(f => ` [${f.type}] ${f.path} (${f.content.length} chars)${f.parent ? ` (included by ${f.parent})` : ''}`).join('\n');
3404
- logForDebugging(`Loaded ${memoryFiles.length} CLAUDE.md/rules files:\n${fileList}`);
3405
- }
3406
- else {
3407
- logForDebugging('No CLAUDE.md/rules files found');
3408
- }
3409
- for (const file of memoryFiles) {
3410
- // When the injected content doesn't match disk (stripped HTML comments,
3411
- // stripped frontmatter, MEMORY.md truncation), cache the RAW disk bytes
3412
- // with isPartialView so Edit/Write require a real Read first while
3413
- // getChangedFiles + nested_memory dedup still work.
3414
- readFileState.current.set(file.path, {
3415
- content: file.contentDiffersFromDisk ? file.rawContent ?? file.content : file.content,
3416
- timestamp: Date.now(),
3417
- offset: undefined,
3418
- limit: undefined,
3419
- isPartialView: file.contentDiffersFromDisk
3420
- });
3421
- }
3422
- // Initial message handling is done via the initialMessage effect
3423
- }
3424
- // Register cost summary tracker
3425
- useCostSummary(useFpsMetrics());
3426
- // Record transcripts locally, for debugging and conversation recovery
3427
- // Don't record conversation if we only have initial messages; optimizes
3428
- // the case where user resumes a conversation then quites before doing
3429
- // anything else
3430
- useLogMessages(messages, messages.length === initialMessages?.length);
3431
- // REPL Bridge: replicate user/assistant messages to the bridge session
3432
- // for remote access via claude.ai. No-op in external builds or when not enabled.
3433
- const { sendBridgeResult } = useReplBridge(messages, setMessages, abortControllerRef, commands, mainLoopModel);
3434
- sendBridgeResultRef.current = sendBridgeResult;
3435
- // Telegram mirror: espeja prompts + respuestas + resúmenes de tool_use al
3436
- // chat primario cuando el bridge está activo, e inyecta mensajes entrantes
3437
- // desde Telegram al REPL como si fueran prompts del usuario.
3438
- useTelegramMirror(messages);
3439
- // WhatsApp mirror: mismo patrón que Telegram, al número primario configurado.
3440
- useWhatsAppMirror(messages);
3441
- useAfterFirstRender();
3442
- // Track prompt queue usage for analytics. Fire once per transition from
3443
- // empty to non-empty, not on every length change -- otherwise a render loop
3444
- // (concurrent onQuery thrashing, etc.) spams saveGlobalConfig, which hits
3445
- // ELOCKED under concurrent sessions and falls back to unlocked writes.
3446
- // That write storm is the primary trigger for ~/.claude.json corruption
3447
- // (GH #3117).
3448
- const hasCountedQueueUseRef = useRef(false);
3449
- useEffect(() => {
3450
- if (queuedCommands.length < 1) {
3451
- hasCountedQueueUseRef.current = false;
3452
- return;
3453
- }
3454
- if (hasCountedQueueUseRef.current)
3455
- return;
3456
- hasCountedQueueUseRef.current = true;
3457
- saveGlobalConfig(current => ({
3458
- ...current,
3459
- promptQueueUseCount: (current.promptQueueUseCount ?? 0) + 1
3460
- }));
3461
- }, [queuedCommands.length]);
3462
- // Process queued commands when query completes and queue has items
3463
- const executeQueuedInput = useCallback(async (queuedCommands) => {
3464
- await handlePromptSubmit({
3465
- helpers: {
3466
- setCursorOffset: () => { },
3467
- clearBuffer: () => { },
3468
- resetHistory: () => { }
3469
- },
3470
- queryGuard,
3471
- commands,
3472
- onInputChange: () => { },
3473
- setPastedContents: () => { },
3474
- setToolJSX,
3475
- getToolUseContext,
3476
- messages,
3477
- mainLoopModel,
3478
- ideSelection,
3479
- setUserInputOnProcessing,
3480
- setAbortController,
3481
- onQuery,
3482
- setAppState,
3483
- querySource: getQuerySourceForREPL(),
3484
- onBeforeQuery,
3485
- canUseTool,
3486
- addNotification,
3487
- setMessages,
3488
- queuedCommands
3489
- });
3490
- }, [queryGuard, commands, setToolJSX, getToolUseContext, messages, mainLoopModel, ideSelection, setUserInputOnProcessing, canUseTool, setAbortController, onQuery, addNotification, setAppState, onBeforeQuery]);
3491
- useQueueProcessor({
3492
- executeQueuedInput,
3493
- hasActiveLocalJsxUI: isShowingLocalJSXCommand,
3494
- queryGuard
3495
- });
3496
- // We'll use the global lastInteractionTime from state.ts
3497
- // Update last interaction time when input changes.
3498
- // Must be immediate because useEffect runs after the Ink render cycle flush.
3499
- useEffect(() => {
3500
- activityManager.recordUserActivity();
3501
- updateLastInteractionTime(true);
3502
- }, [inputValue, submitCount]);
3503
- useEffect(() => {
3504
- if (submitCount === 1) {
3505
- startBackgroundHousekeeping();
3506
- }
3507
- }, [submitCount]);
3508
- // Show notification when Claude is done responding and user is idle
3509
- useEffect(() => {
3510
- // Don't set up notification if Claude is busy
3511
- if (isLoading)
3512
- return;
3513
- // Only enable notifications after the first new interaction in this session
3514
- if (submitCount === 0)
3515
- return;
3516
- // No query has completed yet
3517
- if (lastQueryCompletionTime === 0)
3518
- return;
3519
- // Set timeout to check idle state
3520
- const timer = setTimeout((lastQueryCompletionTime, isLoading, toolJSX, focusedInputDialogRef, terminal) => {
3521
- // Check if user has interacted since the response ended
3522
- const lastUserInteraction = getLastInteractionTime();
3523
- if (lastUserInteraction > lastQueryCompletionTime) {
3524
- // User has interacted since Claude finished - they're not idle, don't notify
3525
- return;
3526
- }
3527
- // User hasn't interacted since response ended, check other conditions
3528
- const idleTimeSinceResponse = Date.now() - lastQueryCompletionTime;
3529
- if (!isLoading && !toolJSX &&
3530
- // Use ref to get current dialog state, avoiding stale closure
3531
- focusedInputDialogRef.current === undefined && idleTimeSinceResponse >= getGlobalConfig().messageIdleNotifThresholdMs) {
3532
- void sendNotification({
3533
- message: 'Claude is waiting for your input',
3534
- notificationType: 'idle_prompt'
3535
- }, terminal);
3536
- }
3537
- }, getGlobalConfig().messageIdleNotifThresholdMs, lastQueryCompletionTime, isLoading, toolJSX, focusedInputDialogRef, terminal);
3538
- return () => clearTimeout(timer);
3539
- }, [isLoading, toolJSX, submitCount, lastQueryCompletionTime, terminal]);
3540
- // Idle-return hint: show notification when idle threshold is exceeded.
3541
- // Timer fires after the configured idle period; notification persists until
3542
- // dismissed or the user submits.
3543
- useEffect(() => {
3544
- if (lastQueryCompletionTime === 0)
3545
- return;
3546
- if (isLoading)
3547
- return;
3548
- const willowMode = getFeatureValue_CACHED_MAY_BE_STALE('tengu_willow_mode', 'off');
3549
- if (willowMode !== 'hint' && willowMode !== 'hint_v2')
3550
- return;
3551
- if (getGlobalConfig().idleReturnDismissed)
3552
- return;
3553
- const tokenThreshold = Number(process.env.CLAUDE_CODE_IDLE_TOKEN_THRESHOLD ?? 100_000);
3554
- if (getTotalInputTokens() < tokenThreshold)
3555
- return;
3556
- const idleThresholdMs = Number(process.env.CLAUDE_CODE_IDLE_THRESHOLD_MINUTES ?? 75) * 60_000;
3557
- const elapsed = Date.now() - lastQueryCompletionTime;
3558
- const remaining = idleThresholdMs - elapsed;
3559
- const timer = setTimeout((lqct, addNotif, msgsRef, mode, hintRef) => {
3560
- if (msgsRef.current.length === 0)
3561
- return;
3562
- const totalTokens = getTotalInputTokens();
3563
- const formattedTokens = formatTokens(totalTokens);
3564
- const idleMinutes = (Date.now() - lqct) / 60_000;
3565
- addNotif({
3566
- key: 'idle-return-hint',
3567
- jsx: mode === 'hint_v2' ? _jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "new task? " }), _jsx(Text, { color: "suggestion", children: "/clear" }), _jsx(Text, { dimColor: true, children: " to save " }), _jsxs(Text, { color: "suggestion", children: [formattedTokens, " tokens"] })] }) : _jsxs(Text, { color: "warning", children: ["new task? /clear to save ", formattedTokens, " tokens"] }),
3568
- priority: 'medium',
3569
- // Persist until submit — the hint fires at T+75min idle, user may
3570
- // not return for hours. removeNotification in useEffect cleanup
3571
- // handles dismissal. 0x7FFFFFFF = setTimeout max (~24.8 days).
3572
- timeoutMs: 0x7fffffff
3573
- });
3574
- hintRef.current = mode;
3575
- logEvent('tengu_idle_return_action', {
3576
- action: 'hint_shown',
3577
- variant: mode,
3578
- idleMinutes: Math.round(idleMinutes),
3579
- messageCount: msgsRef.current.length,
3580
- totalInputTokens: totalTokens
3581
- });
3582
- }, Math.max(0, remaining), lastQueryCompletionTime, addNotification, messagesRef, willowMode, idleHintShownRef);
3583
- return () => {
3584
- clearTimeout(timer);
3585
- removeNotification('idle-return-hint');
3586
- idleHintShownRef.current = false;
3587
- };
3588
- }, [lastQueryCompletionTime, isLoading, addNotification, removeNotification]);
3589
- // Submits incoming prompts from teammate messages or tasks mode as new turns
3590
- // Returns true if submission succeeded, false if a query is already running
3591
- const handleIncomingPrompt = useCallback((content, options) => {
3592
- if (queryGuard.isActive)
3593
- return false;
3594
- // Defer to user-queued commands — user input always takes priority
3595
- // over system messages (teammate messages, task list items, etc.)
3596
- // Read from the module-level store at call time (not the render-time
3597
- // snapshot) to avoid a stale closure — this callback's deps don't
3598
- // include the queue.
3599
- if (getCommandQueue().some(cmd => cmd.mode === 'prompt' || cmd.mode === 'bash')) {
3600
- return false;
3601
- }
3602
- const newAbortController = createAbortController();
3603
- setAbortController(newAbortController);
3604
- // Create a user message with the formatted content (includes XML wrapper)
3605
- const userMessage = createUserMessage({
3606
- content,
3607
- isMeta: options?.isMeta ? true : undefined
3608
- });
3609
- void onQuery([userMessage], newAbortController, true, [], mainLoopModel);
3610
- return true;
3611
- }, [onQuery, mainLoopModel, store]);
3612
- // Voice input integration (VOICE_MODE builds only)
3613
- const voice = feature('VOICE_MODE') ?
3614
- // biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
3615
- useVoiceIntegration({
3616
- setInputValueRaw,
3617
- inputValueRef,
3618
- insertTextRef
3619
- }) : {
3620
- stripTrailing: () => 0,
3621
- handleKeyEvent: () => { },
3622
- resetAnchor: () => { },
3623
- interimRange: null
3624
- };
3625
- useInboxPoller({
3626
- enabled: isAgentSwarmsEnabled(),
3627
- isLoading,
3628
- focusedInputDialog,
3629
- onSubmitMessage: handleIncomingPrompt
3630
- });
3631
- useMailboxBridge({
3632
- isLoading,
3633
- onSubmitMessage: handleIncomingPrompt
3634
- });
3635
- // Scheduled tasks from .claude/scheduled_tasks.json (CronCreate/Delete/List)
3636
- if (feature('AGENT_TRIGGERS')) {
3637
- // Assistant mode bypasses the isLoading gate (the proactive tick →
3638
- // Sleep → tick loop would otherwise starve the scheduler).
3639
- // kairosEnabled is set once in initialState (main.tsx) and never mutated — no
3640
- // subscription needed. The tengu_kairos_cron runtime gate is checked inside
3641
- // useScheduledTasks's effect (not here) since wrapping a hook call in a dynamic
3642
- // condition would break rules-of-hooks.
3643
- const assistantMode = store.getState().kairosEnabled;
3644
- // biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
3645
- useScheduledTasks({
3646
- isLoading,
3647
- assistantMode,
3648
- setMessages
3649
- });
3650
- }
3651
- // Note: Permission polling is now handled by useInboxPoller
3652
- // - Workers receive permission responses via mailbox messages
3653
- // - Leaders receive permission requests via mailbox messages
3654
- if ("external" === 'ant') {
3655
- // Tasks mode: watch for tasks and auto-process them
3656
- // eslint-disable-next-line react-hooks/rules-of-hooks
3657
- // biome-ignore lint/correctness/useHookAtTopLevel: conditional for dead code elimination in external builds
3658
- useTaskListWatcher({
3659
- taskListId,
3660
- isLoading,
3661
- onSubmitTask: handleIncomingPrompt
3662
- });
3663
- // Loop mode: auto-tick when enabled (via /job command)
3664
- // eslint-disable-next-line react-hooks/rules-of-hooks
3665
- // biome-ignore lint/correctness/useHookAtTopLevel: conditional for dead code elimination in external builds
3666
- useProactive?.({
3667
- // Suppress ticks while an initial message is pending — the initial
3668
- // message will be processed asynchronously and a premature tick would
3669
- // race with it, causing concurrent-query enqueue of expanded skill text.
3670
- isLoading: isLoading || initialMessage !== null,
3671
- queuedCommandsLength: queuedCommands.length,
3672
- hasActiveLocalJsxUI: isShowingLocalJSXCommand,
3673
- isInPlanMode: toolPermissionContext.mode === 'plan',
3674
- onSubmitTick: (prompt) => handleIncomingPrompt(prompt, {
3675
- isMeta: true
3676
- }),
3677
- onQueueTick: (prompt) => enqueue({
3678
- mode: 'prompt',
3679
- value: prompt,
3680
- isMeta: true
3681
- })
3682
- });
3683
- }
3684
- // Abort the current operation when a 'now' priority message arrives
3685
- // (e.g. from a chat UI client via UDS).
3686
- useEffect(() => {
3687
- if (queuedCommands.some(cmd => cmd.priority === 'now')) {
3688
- abortControllerRef.current?.abort('interrupt');
3689
- }
3690
- }, [queuedCommands]);
3691
- // Initial load
3692
- useEffect(() => {
3693
- void onInit();
3694
- // Cleanup on unmount
3695
- return () => {
3696
- void diagnosticTracker.shutdown();
3697
- };
3698
- // TODO: fix this
3699
- // eslint-disable-next-line react-hooks/exhaustive-deps
3700
- }, []);
3701
- // Listen for suspend/resume events
3702
- const { internal_eventEmitter } = useStdin();
3703
- const [remountKey, setRemountKey] = useState(0);
3704
- useEffect(() => {
3705
- const handleSuspend = () => {
3706
- // Print suspension instructions
3707
- process.stdout.write(`\nContext Code has been suspended. Run \`fg\` to bring Context Code back.\nNote: ctrl + z now suspends Context Code, ctrl + _ undoes input.\n`);
3708
- };
3709
- const handleResume = () => {
3710
- // Force complete component tree replacement instead of terminal clear
3711
- // Ink now handles line count reset internally on SIGCONT
3712
- setRemountKey(prev => prev + 1);
3713
- };
3714
- internal_eventEmitter?.on('suspend', handleSuspend);
3715
- internal_eventEmitter?.on('resume', handleResume);
3716
- return () => {
3717
- internal_eventEmitter?.off('suspend', handleSuspend);
3718
- internal_eventEmitter?.off('resume', handleResume);
3719
- };
3720
- }, [internal_eventEmitter]);
3721
- // Derive stop hook spinner suffix from messages state
3722
- const stopHookSpinnerSuffix = useMemo(() => {
3723
- if (!isLoading)
3724
- return null;
3725
- // Find stop hook progress messages
3726
- const progressMsgs = messages.filter((m) => m.type === 'progress' && m.data.type === 'hook_progress' && (m.data.hookEvent === 'Stop' || m.data.hookEvent === 'SubagentStop'));
3727
- if (progressMsgs.length === 0)
3728
- return null;
3729
- // Get the most recent stop hook execution
3730
- const currentToolUseID = progressMsgs.at(-1)?.toolUseID;
3731
- if (!currentToolUseID)
3732
- return null;
3733
- // Check if there's already a summary message for this execution (hooks completed)
3734
- const hasSummaryForCurrentExecution = messages.some(m => m.type === 'system' && m.subtype === 'stop_hook_summary' && m.toolUseID === currentToolUseID);
3735
- if (hasSummaryForCurrentExecution)
3736
- return null;
3737
- const currentHooks = progressMsgs.filter(p => p.toolUseID === currentToolUseID);
3738
- const total = currentHooks.length;
3739
- // Count completed hooks
3740
- const completedCount = count(messages, m => {
3741
- if (m.type !== 'attachment')
3742
- return false;
3743
- const attachment = m.attachment;
3744
- return 'hookEvent' in attachment && (attachment.hookEvent === 'Stop' || attachment.hookEvent === 'SubagentStop') && 'toolUseID' in attachment && attachment.toolUseID === currentToolUseID;
3745
- });
3746
- // Check if any hook has a custom status message
3747
- const customMessage = currentHooks.find(p => p.data.statusMessage)?.data.statusMessage;
3748
- if (customMessage) {
3749
- // Use custom message with progress counter if multiple hooks
3750
- return total === 1 ? `${customMessage}…` : `${customMessage}… ${completedCount}/${total}`;
3751
- }
3752
- // Fall back to default behavior
3753
- const hookType = currentHooks[0]?.data.hookEvent === 'SubagentStop' ? 'subagent stop' : 'stop';
3754
- if ("external" === 'ant') {
3755
- const cmd = currentHooks[completedCount]?.data.command;
3756
- const label = cmd ? ` '${truncateToWidth(cmd, 40)}'` : '';
3757
- return total === 1 ? `running ${hookType} hook${label}` : `running ${hookType} hook${label}\u2026 ${completedCount}/${total}`;
3758
- }
3759
- return total === 1 ? `running ${hookType} hook` : `running stop hooks… ${completedCount}/${total}`;
3760
- }, [messages, isLoading]);
3761
- // Callback to capture frozen state when entering transcript mode
3762
- const handleEnterTranscript = useCallback(() => {
3763
- setFrozenTranscriptState({
3764
- messagesLength: messages.length,
3765
- streamingToolUsesLength: streamingToolUses.length
3766
- });
3767
- }, [messages.length, streamingToolUses.length]);
3768
- // Callback to clear frozen state when exiting transcript mode
3769
- const handleExitTranscript = useCallback(() => {
3770
- setFrozenTranscriptState(null);
3771
- }, []);
3772
- // Props for GlobalKeybindingHandlers component (rendered inside KeybindingSetup)
3773
- const virtualScrollActive = isFullscreenEnvEnabled() && !disableVirtualScroll;
3774
- // Transcript search state. Hooks must be unconditional so they live here
3775
- // (not inside the `if (screen === 'transcript')` branch below); isActive
3776
- // gates the useInput. Query persists across bar open/close so n/N keep
3777
- // working after Enter dismisses the bar (less semantics).
3778
- const jumpRef = useRef(null);
3779
- const [searchOpen, setSearchOpen] = useState(false);
3780
- const [searchQuery, setSearchQuery] = useState('');
3781
- const [searchCount, setSearchCount] = useState(0);
3782
- const [searchCurrent, setSearchCurrent] = useState(0);
3783
- const onSearchMatchesChange = useCallback((count, current) => {
3784
- setSearchCount(count);
3785
- setSearchCurrent(current);
3786
- }, []);
3787
- useInput((input, key, event) => {
3788
- if (key.ctrl || key.meta)
3789
- return;
3790
- // No Esc handling here — less has no navigating mode. Search state
3791
- // (highlights, n/N) is just state. Esc/q/ctrl+c → transcript:exit
3792
- // (ungated). Highlights clear on exit via the screen-change effect.
3793
- if (input === '/') {
3794
- // Capture scrollTop NOW — typing is a preview, 0-matches snaps
3795
- // back here. Synchronous ref write, fires before the bar's
3796
- // mount-effect calls setSearchQuery.
3797
- jumpRef.current?.setAnchor();
3798
- setSearchOpen(true);
3799
- event.stopImmediatePropagation();
3800
- return;
3801
- }
3802
- // Held-key batching: tokenizer coalesces to 'nnn'. Same uniform-batch
3803
- // pattern as modalPagerAction in ScrollKeybindingHandler.tsx. Each
3804
- // repeat is a step (n isn't idempotent like g).
3805
- const c = input[0];
3806
- if ((c === 'n' || c === 'N') && input === c.repeat(input.length) && searchCount > 0) {
3807
- const fn = c === 'n' ? jumpRef.current?.nextMatch : jumpRef.current?.prevMatch;
3808
- if (fn)
3809
- for (let i = 0; i < input.length; i++)
3810
- fn();
3811
- event.stopImmediatePropagation();
3812
- }
3813
- },
3814
- // Search needs virtual scroll (jumpRef drives VirtualMessageList). [
3815
- // kills it, so !dumpMode — after [ there's nothing to jump in.
3816
- {
3817
- isActive: screen === 'transcript' && virtualScrollActive && !searchOpen && !dumpMode
3818
- });
3819
- const { setQuery: setHighlight, scanElement, setPositions } = useSearchHighlight();
3820
- // Resize → abort search. Positions are (msg, query, WIDTH)-keyed —
3821
- // cached positions are stale after a width change (new layout, new
3822
- // wrapping). Clearing searchQuery triggers VML's setSearchQuery('')
3823
- // which clears positionsCache + setPositions(null). Bar closes.
3824
- // User hits / again → fresh everything.
3825
- const transcriptCols = useTerminalSize().columns;
3826
- const prevColsRef = React.useRef(transcriptCols);
3827
- React.useEffect(() => {
3828
- if (prevColsRef.current !== transcriptCols) {
3829
- prevColsRef.current = transcriptCols;
3830
- if (searchQuery || searchOpen) {
3831
- setSearchOpen(false);
3832
- setSearchQuery('');
3833
- setSearchCount(0);
3834
- setSearchCurrent(0);
3835
- jumpRef.current?.disarmSearch();
3836
- setHighlight('');
3837
- }
3838
- }
3839
- }, [transcriptCols, searchQuery, searchOpen, setHighlight]);
3840
- // Transcript escape hatches. Bare letters in modal context (no prompt
3841
- // competing for input) — same class as g/G/j/k in ScrollKeybindingHandler.
3842
- useInput((input, key, event) => {
3843
- if (key.ctrl || key.meta)
3844
- return;
3845
- if (input === 'q') {
3846
- // less: q quits the pager. ctrl+o toggles; q is the lineage exit.
3847
- handleExitTranscript();
3848
- event.stopImmediatePropagation();
3849
- return;
3850
- }
3851
- if (input === '[' && !dumpMode) {
3852
- // Force dump-to-scrollback. Also expand + uncap — no point dumping
3853
- // a subset. Terminal/tmux cmd-F can now find anything. Guard here
3854
- // (not in isActive) so v still works post-[ — dump-mode footer at
3855
- // ~4898 wires editorStatus, confirming v is meant to stay live.
3856
- setDumpMode(true);
3857
- setShowAllInTranscript(true);
3858
- event.stopImmediatePropagation();
3859
- }
3860
- else if (input === 'v') {
3861
- // less-style: v opens the file in $VISUAL/$EDITOR. Render the full
3862
- // transcript (same path /export uses), write to tmp, hand off.
3863
- // openFileInExternalEditor handles alt-screen suspend/resume for
3864
- // terminal editors; GUI editors spawn detached.
3865
- event.stopImmediatePropagation();
3866
- // Drop double-taps: the render is async and a second press before it
3867
- // completes would run a second parallel render (double memory, two
3868
- // tempfiles, two editor spawns). editorGenRef only guards
3869
- // transcript-exit staleness, not same-session concurrency.
3870
- if (editorRenderingRef.current)
3871
- return;
3872
- editorRenderingRef.current = true;
3873
- // Capture generation + make a staleness-aware setter. Each write
3874
- // checks gen (transcript exit bumps it → late writes from the
3875
- // async render go silent).
3876
- const gen = editorGenRef.current;
3877
- const setStatus = (s) => {
3878
- if (gen !== editorGenRef.current)
3879
- return;
3880
- clearTimeout(editorTimerRef.current);
3881
- setEditorStatus(s);
3882
- };
3883
- setStatus(`rendering ${deferredMessages.length} messages…`);
3884
- void (async () => {
3885
- try {
3886
- // Width = terminal minus vim's line-number gutter (4 digits +
3887
- // space + slack). Floor at 80. PassThrough has no .columns so
3888
- // without this Ink defaults to 80. Trailing-space strip: right-
3889
- // aligned timestamps still leave a flexbox spacer run at EOL.
3890
- // eslint-disable-next-line custom-rules/prefer-use-terminal-size -- one-shot at keypress time, not a reactive render dep
3891
- const w = Math.max(80, (process.stdout.columns ?? 80) - 6);
3892
- const raw = await renderMessagesToPlainText(deferredMessages, tools, w);
3893
- const text = raw.replace(/[ \t]+$/gm, '');
3894
- const path = join(tmpdir(), `cc-transcript-${Date.now()}.txt`);
3895
- await writeFile(path, text);
3896
- const opened = openFileInExternalEditor(path);
3897
- setStatus(opened ? `opening ${path}` : `wrote ${path} · no $VISUAL/$EDITOR set`);
3898
- }
3899
- catch (e) {
3900
- setStatus(`render failed: ${e instanceof Error ? e.message : String(e)}`);
3901
- }
3902
- editorRenderingRef.current = false;
3903
- if (gen !== editorGenRef.current)
3904
- return;
3905
- editorTimerRef.current = setTimeout(s => s(''), 4000, setEditorStatus);
3906
- })();
3907
- }
3908
- },
3909
- // !searchOpen: typing 'v' or '[' in the search bar is search input, not
3910
- // a command. No !dumpMode here — v should work after [ (the [ handler
3911
- // guards itself inline).
3912
- {
3913
- isActive: screen === 'transcript' && virtualScrollActive && !searchOpen
3914
- });
3915
- // Fresh `less` per transcript entry. Prevents stale highlights matching
3916
- // unrelated normal-mode text (overlay is alt-screen-global) and avoids
3917
- // surprise n/N on re-entry. Same exit resets [ dump mode — each ctrl+o
3918
- // entry is a fresh instance.
3919
- const inTranscript = screen === 'transcript' && virtualScrollActive;
3920
- useEffect(() => {
3921
- if (!inTranscript) {
3922
- setSearchQuery('');
3923
- setSearchCount(0);
3924
- setSearchCurrent(0);
3925
- setSearchOpen(false);
3926
- editorGenRef.current++;
3927
- clearTimeout(editorTimerRef.current);
3928
- setDumpMode(false);
3929
- setEditorStatus('');
3930
- }
3931
- }, [inTranscript]);
3932
- useEffect(() => {
3933
- setHighlight(inTranscript ? searchQuery : '');
3934
- // Clear the position-based CURRENT (yellow) overlay too. setHighlight
3935
- // only clears the scan-based inverse. Without this, the yellow box
3936
- // persists at its last screen coords after ctrl-c exits transcript.
3937
- if (!inTranscript)
3938
- setPositions(null);
3939
- }, [inTranscript, searchQuery, setHighlight, setPositions]);
3940
- const globalKeybindingProps = {
3941
- screen,
3942
- setScreen,
3943
- showAllInTranscript,
3944
- setShowAllInTranscript,
3945
- messageCount: messages.length,
3946
- onEnterTranscript: handleEnterTranscript,
3947
- onExitTranscript: handleExitTranscript,
3948
- virtualScrollActive,
3949
- // Bar-open is a mode (owns keystrokes — j/k type, Esc cancels).
3950
- // Navigating (query set, bar closed) is NOT — Esc exits transcript,
3951
- // same as less q with highlights still visible. useSearchInput
3952
- // doesn't stopPropagation, so without this gate transcript:exit
3953
- // would fire on the same Esc that cancels the bar (child registers
3954
- // first, fires first, bubbles).
3955
- searchBarOpen: searchOpen
3956
- };
3957
- // Use frozen lengths to slice arrays, avoiding memory overhead of cloning
3958
- const transcriptMessages = frozenTranscriptState ? deferredMessages.slice(0, frozenTranscriptState.messagesLength) : deferredMessages;
3959
- const transcriptStreamingToolUses = frozenTranscriptState ? streamingToolUses.slice(0, frozenTranscriptState.streamingToolUsesLength) : streamingToolUses;
3960
- // Handle shift+down for teammate navigation and background task management.
3961
- // Guard onOpenBackgroundTasks when a local-jsx dialog (e.g. /mcp) is open —
3962
- // otherwise Shift+Down stacks BackgroundTasksDialog on top and deadlocks input.
3963
- useBackgroundTaskNavigation({
3964
- onOpenBackgroundTasks: isShowingLocalJSXCommand ? undefined : () => setShowBashesDialog(true)
3965
- });
3966
- // Auto-exit viewing mode when teammate completes or errors
3967
- useTeammateViewAutoExit();
3968
- if (screen === 'transcript') {
3969
- // Virtual scroll replaces the 30-message cap: everything is scrollable
3970
- // and memory is bounded by the viewport. Without it, wrapping transcript
3971
- // in a ScrollBox would mount all messages (~250 MB on long sessions —
3972
- // the exact problem), so the kill switch and non-fullscreen paths must
3973
- // fall through to the legacy render: no alt screen, dump to terminal
3974
- // scrollback, 30-cap + Ctrl+E. Reusing scrollRef is safe — normal-mode
3975
- // and transcript-mode are mutually exclusive (this early return), so
3976
- // only one ScrollBox is ever mounted at a time.
3977
- const transcriptScrollRef = isFullscreenEnvEnabled() && !disableVirtualScroll && !dumpMode ? scrollRef : undefined;
3978
- const transcriptMessagesElement = _jsx(Messages, { messages: transcriptMessages, tools: tools, commands: commands, verbose: true, toolJSX: null, toolUseConfirmQueue: [], inProgressToolUseIDs: inProgressToolUseIDs, isMessageSelectorVisible: false, conversationId: conversationId, screen: screen, agentDefinitions: agentDefinitions, streamingToolUses: transcriptStreamingToolUses, showAllInTranscript: showAllInTranscript, onOpenRateLimitOptions: handleOpenRateLimitOptions, isLoading: isLoading, hidePastThinking: true, streamingThinking: streamingThinking, scrollRef: transcriptScrollRef, jumpRef: jumpRef, onSearchMatchesChange: onSearchMatchesChange, scanElement: scanElement, setPositions: setPositions, disableRenderCap: dumpMode });
3979
- const transcriptToolJSX = toolJSX && _jsx(Box, { flexDirection: "column", width: "100%", children: toolJSX.jsx });
3980
- const transcriptReturn = _jsxs(KeybindingSetup, { children: [_jsx(AnimatedTerminalTitle, { isAnimating: titleIsAnimating, title: terminalTitle, disabled: titleDisabled, noPrefix: showStatusInTerminalTab }), _jsx(GlobalKeybindingHandlers, { ...globalKeybindingProps }), feature('VOICE_MODE') ? _jsx(VoiceKeybindingHandler, { voiceHandleKeyEvent: voice.handleKeyEvent, stripTrailing: voice.stripTrailing, resetAnchor: voice.resetAnchor, isActive: !toolJSX?.isLocalJSXCommand }) : null, _jsx(CommandKeybindingHandlers, { onSubmit: onSubmit, isActive: !toolJSX?.isLocalJSXCommand }), transcriptScrollRef ?
3981
- _jsx(ScrollKeybindingHandler, { scrollRef: scrollRef,
3982
- // Yield wheel/ctrl+u/d to UltraplanChoiceDialog's own scroll
3983
- // handler while the modal is showing.
3984
- isActive: focusedInputDialog !== 'ultraplan-choice',
3985
- // g/G/j/k/ctrl+u/ctrl+d would eat keystrokes the search bar
3986
- // wants. Off while searching.
3987
- isModal: !searchOpen,
3988
- // Manual scroll exits the search context — clear the yellow
3989
- // current-match marker. Positions are (msg, rowOffset)-keyed;
3990
- // j/k changes scrollTop so rowOffset is stale → wrong row
3991
- // gets yellow. Next n/N re-establishes via step()→jump().
3992
- onScroll: () => jumpRef.current?.disarmSearch() }) : null, _jsx(CancelRequestHandler, { ...cancelRequestProps }), transcriptScrollRef ? _jsx(FullscreenLayout, { scrollRef: scrollRef, scrollable: _jsxs(_Fragment, { children: [transcriptMessagesElement, transcriptToolJSX, _jsx(SandboxViolationExpandedView, {})] }), bottom: searchOpen ? _jsx(TranscriptSearchBar, { jumpRef: jumpRef,
3993
- // Seed was tried (c01578c8) — broke /hello muscle
3994
- // memory (cursor lands after 'foo', /hello → foohello).
3995
- // Cancel-restore handles the 'don't lose prior search'
3996
- // concern differently (onCancel re-applies searchQuery).
3997
- initialQuery: "", count: searchCount, current: searchCurrent, onClose: q => {
3998
- // Enter — commit. 0-match guard: junk query shouldn't
3999
- // persist (badge hidden, n/N dead anyway).
4000
- setSearchQuery(searchCount > 0 ? q : '');
4001
- setSearchOpen(false);
4002
- // onCancel path: bar unmounts before its useEffect([query])
4003
- // can fire with ''. Without this, searchCount stays stale
4004
- // (n guard at :4956 passes) and VML's matches[] too
4005
- // (nextMatch walks the old array). Phantom nav, no
4006
- // highlight. onExit (Enter, q non-empty) still commits.
4007
- if (!q) {
4008
- setSearchCount(0);
4009
- setSearchCurrent(0);
4010
- jumpRef.current?.setSearchQuery('');
4011
- }
4012
- }, onCancel: () => {
4013
- // Esc/ctrl+c/ctrl+g — undo. Bar's effect last fired
4014
- // with whatever was typed. searchQuery (REPL state)
4015
- // is unchanged since / (onClose = commit, didn't run).
4016
- // Two VML calls: '' restores anchor (0-match else-
4017
- // branch), then searchQuery re-scans from anchor's
4018
- // nearest. Both synchronous — one React batch.
4019
- // setHighlight explicit: REPL's sync-effect dep is
4020
- // searchQuery (unchanged), wouldn't re-fire.
4021
- setSearchOpen(false);
4022
- jumpRef.current?.setSearchQuery('');
4023
- jumpRef.current?.setSearchQuery(searchQuery);
4024
- setHighlight(searchQuery);
4025
- }, setHighlight: setHighlight }) : _jsx(TranscriptModeFooter, { showAllInTranscript: showAllInTranscript, virtualScroll: true, status: editorStatus || undefined, searchBadge: searchQuery && searchCount > 0 ? {
4026
- current: searchCurrent,
4027
- count: searchCount
4028
- } : undefined }) }) : _jsxs(_Fragment, { children: [transcriptMessagesElement, transcriptToolJSX, _jsx(SandboxViolationExpandedView, {}), _jsx(TranscriptModeFooter, { showAllInTranscript: showAllInTranscript, virtualScroll: false, suppressShowAll: dumpMode, status: editorStatus || undefined })] })] });
4029
- // The virtual-scroll branch (FullscreenLayout above) needs
4030
- // <AlternateScreen>'s <Box height={rows}> constraint — without it,
4031
- // ScrollBox's flexGrow has no ceiling, viewport = content height,
4032
- // scrollTop pins at 0, and Ink's screen buffer sizes to the full
4033
- // spacer (200×5k+ rows on long sessions). Same root type + props as
4034
- // normal mode's wrap below so React reconciles and the alt buffer
4035
- // stays entered across toggle. The 30-cap dump branch stays
4036
- // unwrapped — it wants native terminal scrollback.
4037
- if (transcriptScrollRef) {
4038
- return _jsx(AlternateScreen, { mouseTracking: isMouseTrackingEnabled(), children: transcriptReturn });
4039
- }
4040
- return transcriptReturn;
4041
- }
4042
- // Get viewed agent task (inlined from selectors for explicit data flow).
4043
- // viewedAgentTask: teammate OR local_agent — drives the boolean checks
4044
- // below. viewedTeammateTask: teammate-only narrowed, for teammate-specific
4045
- // field access (inProgressToolUseIDs).
4046
- const viewedTask = viewingAgentTaskId ? tasks[viewingAgentTaskId] : undefined;
4047
- const viewedTeammateTask = viewedTask && isInProcessTeammateTask(viewedTask) ? viewedTask : undefined;
4048
- const viewedAgentTask = viewedTeammateTask ?? (viewedTask && isLocalAgentTask(viewedTask) ? viewedTask : undefined);
4049
- // Bypass useDeferredValue when streaming text is showing so Messages renders
4050
- // the final message in the same frame streaming text clears. Also bypass when
4051
- // not loading — deferredMessages only matters during streaming (keeps input
4052
- // responsive); after the turn ends, showing messages immediately prevents a
4053
- // jitter gap where the spinner is gone but the answer hasn't appeared yet.
4054
- // Only reducedMotion users keep the deferred path during loading.
4055
- const usesSyncMessages = showStreamingText || !isLoading;
4056
- // When viewing an agent, never fall through to leader — empty until
4057
- // bootstrap/stream fills. Closes the see-leader-type-agent footgun.
4058
- const displayedMessages = viewedAgentTask ? viewedAgentTask.messages ?? [] : usesSyncMessages ? messages : deferredMessages;
4059
- // Show the placeholder until the real user message appears in
4060
- // displayedMessages. userInputOnProcessing stays set for the whole turn
4061
- // (cleared in resetLoadingState); this length check hides it once
4062
- // displayedMessages grows past the baseline captured at submit time.
4063
- // Covers both gaps: before setMessages is called (processUserInput), and
4064
- // while deferredMessages lags behind messages. Suppressed when viewing an
4065
- // agent — displayedMessages is a different array there, and onAgentSubmit
4066
- // doesn't use the placeholder anyway.
4067
- const placeholderText = userInputOnProcessing && !viewedAgentTask && displayedMessages.length <= userInputBaselineRef.current ? userInputOnProcessing : undefined;
4068
- const toolPermissionOverlay = focusedInputDialog === 'tool-permission' ? _jsx(PermissionRequest, { onDone: () => setToolUseConfirmQueue(([_, ...tail]) => tail), onReject: handleQueuedCommandOnCancel, toolUseConfirm: toolUseConfirmQueue[0], toolUseContext: getToolUseContext(messages, messages, abortController ?? createAbortController(), mainLoopModel), verbose: verbose, workerBadge: toolUseConfirmQueue[0]?.workerBadge, setStickyFooter: isFullscreenEnvEnabled() ? setPermissionStickyFooter : undefined }, toolUseConfirmQueue[0]?.toolUseID) : null;
4069
- // Narrow terminals: companion collapses to a one-liner that REPL stacks
4070
- // on its own row (above input in fullscreen, below in scrollback) instead
4071
- // of row-beside. Wide terminals keep the row layout with sprite on the right.
4072
- const companionNarrow = transcriptCols < MIN_COLS_FOR_FULL_SPRITE;
4073
- // Hide the sprite when PromptInput early-returns BackgroundTasksDialog.
4074
- // The sprite sits as a row sibling of PromptInput, so the dialog's Pane
4075
- // divider draws at useTerminalSize() width but only gets terminalWidth -
4076
- // spriteWidth — divider stops short and dialog text wraps early. Don't
4077
- // check footerSelection: pill FOCUS (arrow-down to tasks pill) must keep
4078
- // the sprite visible so arrow-right can navigate to it.
4079
- const companionVisible = !toolJSX?.shouldHidePromptInput && !focusedInputDialog && !showBashesDialog;
4080
- // In fullscreen, ALL local-jsx slash commands float in the modal slot —
4081
- // FullscreenLayout wraps them in an absolute-positioned bottom-anchored
4082
- // pane (▔ divider, ModalContext). Pane/Dialog inside detect the context
4083
- // and skip their own top-level frame. Non-fullscreen keeps the inline
4084
- // render paths below. Commands that used to route through bottom
4085
- // (immediate: /model, /mcp, /btw, ...) and scrollable (non-immediate:
4086
- // /config, /theme, /diff, ...) both go here now.
4087
- const toolJsxCentered = isFullscreenEnvEnabled() && toolJSX?.isLocalJSXCommand === true;
4088
- const centeredModal = toolJsxCentered ? toolJSX.jsx : null;
4089
- // <AlternateScreen> at the root: everything below is inside its
4090
- // <Box height={rows}>. Handlers/contexts are zero-height so ScrollBox's
4091
- // flexGrow in FullscreenLayout resolves against this Box. The transcript
4092
- // early return above wraps its virtual-scroll branch the same way; only
4093
- // the 30-cap dump branch stays unwrapped for native terminal scrollback.
4094
- const mainReturn = _jsxs(KeybindingSetup, { children: [_jsx(AnimatedTerminalTitle, { isAnimating: titleIsAnimating, title: terminalTitle, disabled: titleDisabled, noPrefix: showStatusInTerminalTab }), _jsx(GlobalKeybindingHandlers, { ...globalKeybindingProps }), feature('VOICE_MODE') ? _jsx(VoiceKeybindingHandler, { voiceHandleKeyEvent: voice.handleKeyEvent, stripTrailing: voice.stripTrailing, resetAnchor: voice.resetAnchor, isActive: !toolJSX?.isLocalJSXCommand }) : null, _jsx(CommandKeybindingHandlers, { onSubmit: onSubmit, isActive: !toolJSX?.isLocalJSXCommand }), _jsx(ScrollKeybindingHandler, { scrollRef: scrollRef, isActive: isFullscreenEnvEnabled() && (centeredModal != null || !focusedInputDialog || focusedInputDialog === 'tool-permission'), onScroll: centeredModal || toolPermissionOverlay || viewedAgentTask ? undefined : composedOnScroll }), feature('MESSAGE_ACTIONS') && isFullscreenEnvEnabled() && !disableMessageActions ? _jsx(MessageActionsKeybindings, { handlers: messageActionHandlers, isActive: cursor !== null }) : null, _jsx(CancelRequestHandler, { ...cancelRequestProps }), _jsx(MCPConnectionManager, { dynamicMcpConfig: dynamicMcpConfig, isStrictMcpConfig: strictMcpConfig, children: _jsx(FullscreenLayout, { scrollRef: scrollRef, overlay: toolPermissionOverlay, bottomFloat: feature('BUDDY') && companionVisible && !companionNarrow ? _jsx(CompanionFloatingBubble, {}) : undefined, modal: centeredModal, modalScrollRef: modalScrollRef, dividerYRef: dividerYRef, hidePill: !!viewedAgentTask, hideSticky: !!viewedTeammateTask, newMessageCount: unseenDivider?.count ?? 0, onPillClick: () => {
4095
- setCursor(null);
4096
- jumpToNew(scrollRef.current);
4097
- }, scrollable: _jsxs(_Fragment, { children: [_jsx(TeammateViewHeader, {}), _jsx(Messages, { messages: displayedMessages, tools: tools, commands: commands, verbose: verbose, toolJSX: toolJSX, toolUseConfirmQueue: toolUseConfirmQueue, inProgressToolUseIDs: viewedTeammateTask ? viewedTeammateTask.inProgressToolUseIDs ?? new Set() : inProgressToolUseIDs, isMessageSelectorVisible: isMessageSelectorVisible, conversationId: conversationId, screen: screen, streamingToolUses: streamingToolUses, showAllInTranscript: showAllInTranscript, agentDefinitions: agentDefinitions, onOpenRateLimitOptions: handleOpenRateLimitOptions, isLoading: isLoading, streamingText: isLoading && !viewedAgentTask ? visibleStreamingText : null, isBriefOnly: viewedAgentTask ? false : isBriefOnly, unseenDivider: viewedAgentTask ? undefined : unseenDivider, scrollRef: isFullscreenEnvEnabled() ? scrollRef : undefined, trackStickyPrompt: isFullscreenEnvEnabled() ? true : undefined, cursor: cursor, setCursor: setCursor, cursorNavRef: cursorNavRef }), _jsx(AwsAuthStatusBox, {}), !disabled && placeholderText && !centeredModal && _jsx(UserTextMessage, { param: {
4098
- text: placeholderText,
4099
- type: 'text'
4100
- }, addMargin: true, verbose: verbose }), toolJSX && !(toolJSX.isLocalJSXCommand && toolJSX.isImmediate) && !toolJsxCentered && _jsx(Box, { flexDirection: "column", width: "100%", children: toolJSX.jsx }), "external" === 'ant' && _jsx(TungstenLiveMonitor, {}), feature('WEB_BROWSER_TOOL') ? WebBrowserPanelModule && _jsx(WebBrowserPanelModule.WebBrowserPanel, {}) : null, _jsx(Box, { flexGrow: 1 }), showSpinner && _jsx(SpinnerWithVerb, { mode: streamMode, spinnerTip: spinnerTip, responseLengthRef: responseLengthRef, apiMetricsRef: apiMetricsRef, overrideMessage: spinnerMessage, spinnerSuffix: stopHookSpinnerSuffix, verbose: verbose, loadingStartTimeRef: loadingStartTimeRef, totalPausedMsRef: totalPausedMsRef, pauseStartTimeRef: pauseStartTimeRef, overrideColor: spinnerColor, overrideShimmerColor: spinnerShimmerColor, hasActiveTools: inProgressToolUseIDs.size > 0, leaderIsIdle: !isLoading }), !showSpinner && !isLoading && !userInputOnProcessing && !hasRunningTeammates && isBriefOnly && !viewedAgentTask && _jsx(BriefIdleStatus, {}), isFullscreenEnvEnabled() && _jsx(PromptInputQueuedCommands, {})] }), bottom: _jsxs(Box, { flexDirection: feature('BUDDY') && companionNarrow ? 'column' : 'row', width: "100%", alignItems: feature('BUDDY') && companionNarrow ? undefined : 'flex-end', children: [feature('BUDDY') && companionNarrow && isFullscreenEnvEnabled() && companionVisible ? _jsx(CompanionSprite, {}) : null, _jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [permissionStickyFooter, toolJSX?.isLocalJSXCommand && toolJSX.isImmediate && !toolJsxCentered && _jsx(Box, { flexDirection: "column", width: "100%", children: toolJSX.jsx }), !showSpinner && !toolJSX?.isLocalJSXCommand && showExpandedTodos && tasksV2 && tasksV2.length > 0 && _jsx(Box, { width: "100%", flexDirection: "column", children: _jsx(TaskListV2, { tasks: tasksV2, isStandalone: true }) }), focusedInputDialog === 'sandbox-permission' && _jsx(SandboxPermissionRequest, { hostPattern: sandboxPermissionRequestQueue[0].hostPattern, onUserResponse: (response) => {
4101
- const { allow, persistToSettings } = response;
4102
- const currentRequest = sandboxPermissionRequestQueue[0];
4103
- if (!currentRequest)
4104
- return;
4105
- const approvedHost = currentRequest.hostPattern.host;
4106
- if (persistToSettings) {
4107
- const update = {
4108
- type: 'addRules',
4109
- rules: [{
4110
- toolName: WEB_FETCH_TOOL_NAME,
4111
- ruleContent: `domain:${approvedHost}`
4112
- }],
4113
- behavior: (allow ? 'allow' : 'deny'),
4114
- destination: 'localSettings'
4115
- };
4116
- setAppState(prev => ({
4117
- ...prev,
4118
- toolPermissionContext: applyPermissionUpdate(prev.toolPermissionContext, update)
4119
- }));
4120
- persistPermissionUpdate(update);
4121
- // Immediately update sandbox in-memory config to prevent race conditions
4122
- // where pending requests slip through before settings change is detected
4123
- SandboxManager.refreshConfig();
4124
- }
4125
- // Resolve ALL pending requests for the same host (not just the first one)
4126
- // This handles the case where multiple parallel requests came in for the same domain
4127
- setSandboxPermissionRequestQueue(queue => {
4128
- queue.filter(item => item.hostPattern.host === approvedHost).forEach(item => item.resolvePromise(allow));
4129
- return queue.filter(item => item.hostPattern.host !== approvedHost);
4130
- });
4131
- // Clean up bridge subscriptions and cancel remote prompts
4132
- // for this host since the local user already responded.
4133
- const cleanups = sandboxBridgeCleanupRef.current.get(approvedHost);
4134
- if (cleanups) {
4135
- for (const fn of cleanups) {
4136
- fn();
4137
- }
4138
- sandboxBridgeCleanupRef.current.delete(approvedHost);
4139
- }
4140
- } }, sandboxPermissionRequestQueue[0].hostPattern.host), focusedInputDialog === 'prompt' && _jsx(PromptDialog, { title: promptQueue[0].title, toolInputSummary: promptQueue[0].toolInputSummary, request: promptQueue[0].request, onRespond: selectedKey => {
4141
- const item = promptQueue[0];
4142
- if (!item)
4143
- return;
4144
- item.resolve({
4145
- prompt_response: item.request.prompt,
4146
- selected: selectedKey
4147
- });
4148
- setPromptQueue(([, ...tail]) => tail);
4149
- }, onAbort: () => {
4150
- const item = promptQueue[0];
4151
- if (!item)
4152
- return;
4153
- item.reject(new Error('Prompt cancelled by user'));
4154
- setPromptQueue(([, ...tail]) => tail);
4155
- } }, promptQueue[0].request.prompt), pendingWorkerRequest && _jsx(WorkerPendingPermission, { toolName: pendingWorkerRequest.toolName, description: pendingWorkerRequest.description }), pendingSandboxRequest && _jsx(WorkerPendingPermission, { toolName: "Network Access", description: `Waiting for leader to approve network access to ${pendingSandboxRequest.host}` }), focusedInputDialog === 'worker-sandbox-permission' && _jsx(SandboxPermissionRequest, { hostPattern: {
4156
- host: workerSandboxPermissions.queue[0].host,
4157
- port: undefined
4158
- }, onUserResponse: (response) => {
4159
- const { allow, persistToSettings } = response;
4160
- const currentRequest = workerSandboxPermissions.queue[0];
4161
- if (!currentRequest)
4162
- return;
4163
- const approvedHost = currentRequest.host;
4164
- // Send response via mailbox to the worker
4165
- void sendSandboxPermissionResponseViaMailbox(currentRequest.workerName, currentRequest.requestId, approvedHost, allow, teamContext?.teamName);
4166
- if (persistToSettings && allow) {
4167
- const update = {
4168
- type: 'addRules',
4169
- rules: [{
4170
- toolName: WEB_FETCH_TOOL_NAME,
4171
- ruleContent: `domain:${approvedHost}`
4172
- }],
4173
- behavior: 'allow',
4174
- destination: 'localSettings'
4175
- };
4176
- setAppState(prev => ({
4177
- ...prev,
4178
- toolPermissionContext: applyPermissionUpdate(prev.toolPermissionContext, update)
4179
- }));
4180
- persistPermissionUpdate(update);
4181
- SandboxManager.refreshConfig();
4182
- }
4183
- // Remove from queue
4184
- setAppState(prev => ({
4185
- ...prev,
4186
- workerSandboxPermissions: {
4187
- ...prev.workerSandboxPermissions,
4188
- queue: prev.workerSandboxPermissions.queue.slice(1)
4189
- }
4190
- }));
4191
- } }, workerSandboxPermissions.queue[0].requestId), focusedInputDialog === 'elicitation' && _jsx(ElicitationDialog, { event: elicitation.queue[0], onResponse: (action, content) => {
4192
- const currentRequest = elicitation.queue[0];
4193
- if (!currentRequest)
4194
- return;
4195
- // Call respond callback to resolve Promise
4196
- currentRequest.respond({
4197
- action,
4198
- content
4199
- });
4200
- // For URL accept, keep in queue for phase 2
4201
- const isUrlAccept = currentRequest.params.mode === 'url' && action === 'accept';
4202
- if (!isUrlAccept) {
4203
- setAppState(prev => ({
4204
- ...prev,
4205
- elicitation: {
4206
- queue: prev.elicitation.queue.slice(1)
4207
- }
4208
- }));
4209
- }
4210
- }, onWaitingDismiss: action => {
4211
- const currentRequest = elicitation.queue[0];
4212
- // Remove from queue
4213
- setAppState(prev => ({
4214
- ...prev,
4215
- elicitation: {
4216
- queue: prev.elicitation.queue.slice(1)
4217
- }
4218
- }));
4219
- currentRequest?.onWaitingDismiss?.(action);
4220
- } }, elicitation.queue[0].serverName + ':' + String(elicitation.queue[0].requestId)), focusedInputDialog === 'cost' && _jsx(CostThresholdDialog, { onDone: () => {
4221
- setShowCostDialog(false);
4222
- setHaveShownCostDialog(true);
4223
- saveGlobalConfig(current => ({
4224
- ...current,
4225
- hasAcknowledgedCostThreshold: true
4226
- }));
4227
- logEvent('tengu_cost_threshold_acknowledged', {});
4228
- } }), focusedInputDialog === 'idle-return' && idleReturnPending && _jsx(IdleReturnDialog, { idleMinutes: idleReturnPending.idleMinutes, totalInputTokens: getTotalInputTokens(), onDone: async (action) => {
4229
- const pending = idleReturnPending;
4230
- setIdleReturnPending(null);
4231
- logEvent('tengu_idle_return_action', {
4232
- action: action,
4233
- idleMinutes: Math.round(pending.idleMinutes),
4234
- messageCount: messagesRef.current.length,
4235
- totalInputTokens: getTotalInputTokens()
4236
- });
4237
- if (action === 'dismiss') {
4238
- setInputValue(pending.input);
4239
- return;
4240
- }
4241
- if (action === 'never') {
4242
- saveGlobalConfig(current => {
4243
- if (current.idleReturnDismissed)
4244
- return current;
4245
- return {
4246
- ...current,
4247
- idleReturnDismissed: true
4248
- };
4249
- });
4250
- }
4251
- if (action === 'clear') {
4252
- const { clearConversation } = await import('../commands/clear/conversation.js');
4253
- await clearConversation({
4254
- setMessages,
4255
- readFileState: readFileState.current,
4256
- discoveredSkillNames: discoveredSkillNamesRef.current,
4257
- loadedNestedMemoryPaths: loadedNestedMemoryPathsRef.current,
4258
- getAppState: () => store.getState(),
4259
- setAppState,
4260
- setConversationId
4261
- });
4262
- haikuTitleAttemptedRef.current = false;
4263
- setHaikuTitle(undefined);
4264
- bashTools.current.clear();
4265
- bashToolsProcessedIdx.current = 0;
4266
- }
4267
- skipIdleCheckRef.current = true;
4268
- void onSubmitRef.current(pending.input, {
4269
- setCursorOffset: () => { },
4270
- clearBuffer: () => { },
4271
- resetHistory: () => { }
4272
- });
4273
- } }), focusedInputDialog === 'ide-onboarding' && _jsx(IdeOnboardingDialog, { onDone: () => setShowIdeOnboarding(false), installationStatus: ideInstallationStatus }), "external" === 'ant' && focusedInputDialog === 'model-switch' && AntModelSwitchCallout && _jsx(AntModelSwitchCallout, { onDone: (selection, modelAlias) => {
4274
- setShowModelSwitchCallout(false);
4275
- if (selection === 'switch' && modelAlias) {
4276
- setAppState(prev => ({
4277
- ...prev,
4278
- mainLoopModel: modelAlias,
4279
- mainLoopModelForSession: null
4280
- }));
4281
- }
4282
- } }), "external" === 'ant' && focusedInputDialog === 'undercover-callout' && UndercoverAutoCallout && _jsx(UndercoverAutoCallout, { onDone: () => setShowUndercoverCallout(false) }), focusedInputDialog === 'effort-callout' && _jsx(EffortCallout, { model: mainLoopModel, onDone: selection => {
4283
- setShowEffortCallout(false);
4284
- if (selection !== 'dismiss') {
4285
- setAppState(prev => ({
4286
- ...prev,
4287
- effortValue: selection
4288
- }));
4289
- }
4290
- } }), focusedInputDialog === 'remote-callout' && _jsx(RemoteCallout, { onDone: selection => {
4291
- setAppState(prev => {
4292
- if (!prev.showRemoteCallout)
4293
- return prev;
4294
- return {
4295
- ...prev,
4296
- showRemoteCallout: false,
4297
- ...(selection === 'enable' && {
4298
- replBridgeEnabled: true,
4299
- replBridgeExplicit: true,
4300
- replBridgeOutboundOnly: false
4301
- })
4302
- };
4303
- });
4304
- } }), exitFlow, focusedInputDialog === 'plugin-hint' && hintRecommendation && _jsx(PluginHintMenu, { pluginName: hintRecommendation.pluginName, pluginDescription: hintRecommendation.pluginDescription, marketplaceName: hintRecommendation.marketplaceName, sourceCommand: hintRecommendation.sourceCommand, onResponse: handleHintResponse }), focusedInputDialog === 'lsp-recommendation' && lspRecommendation && _jsx(LspRecommendationMenu, { pluginName: lspRecommendation.pluginName, pluginDescription: lspRecommendation.pluginDescription, fileExtension: lspRecommendation.fileExtension, onResponse: handleLspResponse }), focusedInputDialog === 'desktop-upsell' && _jsx(DesktopUpsellStartup, { onDone: () => setShowDesktopUpsellStartup(false) }), feature('ULTRAPLAN') ? focusedInputDialog === 'ultraplan-choice' && ultraplanPendingChoice && _jsx(UltraplanChoiceDialog, { plan: ultraplanPendingChoice.plan, sessionId: ultraplanPendingChoice.sessionId, taskId: ultraplanPendingChoice.taskId, setMessages: setMessages, readFileState: readFileState.current, getAppState: () => store.getState(), setConversationId: setConversationId }) : null, feature('ULTRAPLAN') ? focusedInputDialog === 'ultraplan-launch' && ultraplanLaunchPending && _jsx(UltraplanLaunchDialog, { onChoice: (choice, opts) => {
4305
- const blurb = ultraplanLaunchPending.blurb;
4306
- setAppState(prev => prev.ultraplanLaunchPending ? {
4307
- ...prev,
4308
- ultraplanLaunchPending: undefined
4309
- } : prev);
4310
- if (choice === 'cancel')
4311
- return;
4312
- // Command's onDone used display:'skip', so add the
4313
- // echo here — gives immediate feedback before the
4314
- // ~5s teleportToRemote resolves.
4315
- setMessages(prev => [...prev, createCommandInputMessage(formatCommandInputTags('ultraplan', blurb))]);
4316
- const appendStdout = (msg) => setMessages(prev => [...prev, createCommandInputMessage(`<${LOCAL_COMMAND_STDOUT_TAG}>${escapeXml(msg)}</${LOCAL_COMMAND_STDOUT_TAG}>`)]);
4317
- // Defer the second message if a query is mid-turn
4318
- // so it lands after the assistant reply, not
4319
- // between the user's prompt and the reply.
4320
- const appendWhenIdle = (msg) => {
4321
- if (!queryGuard.isActive) {
4322
- appendStdout(msg);
4323
- return;
4324
- }
4325
- const unsub = queryGuard.subscribe(() => {
4326
- if (queryGuard.isActive)
4327
- return;
4328
- unsub();
4329
- // Skip if the user stopped ultraplan while we
4330
- // were waiting — avoids a stale "Monitoring
4331
- // <url>" message for a session that's gone.
4332
- if (!store.getState().ultraplanSessionUrl)
4333
- return;
4334
- appendStdout(msg);
4335
- });
4336
- };
4337
- void launchUltraplan({
4338
- blurb,
4339
- getAppState: () => store.getState(),
4340
- setAppState,
4341
- signal: createAbortController().signal,
4342
- disconnectedBridge: opts?.disconnectedBridge,
4343
- onSessionReady: appendWhenIdle
4344
- }).then(appendStdout).catch(logError);
4345
- } }) : null, mrRender(), !toolJSX?.shouldHidePromptInput && !focusedInputDialog && !isExiting && !disabled && !cursor && _jsxs(_Fragment, { children: [autoRunIssueReason && _jsx(AutoRunIssueNotification, { onRun: handleAutoRunIssue, onCancel: handleCancelAutoRunIssue, reason: getAutoRunIssueReasonText(autoRunIssueReason) }), postCompactSurvey.state !== 'closed' ? _jsx(FeedbackSurvey, { state: postCompactSurvey.state, lastResponse: postCompactSurvey.lastResponse, handleSelect: postCompactSurvey.handleSelect, inputValue: inputValue, setInputValue: setInputValue, onRequestFeedback: handleSurveyRequestFeedback }) : memorySurvey.state !== 'closed' ? _jsx(FeedbackSurvey, { state: memorySurvey.state, lastResponse: memorySurvey.lastResponse, handleSelect: memorySurvey.handleSelect, handleTranscriptSelect: memorySurvey.handleTranscriptSelect, inputValue: inputValue, setInputValue: setInputValue, onRequestFeedback: handleSurveyRequestFeedback, message: "How well did Claude use its memory? (optional)" }) : _jsx(FeedbackSurvey, { state: feedbackSurvey.state, lastResponse: feedbackSurvey.lastResponse, handleSelect: feedbackSurvey.handleSelect, handleTranscriptSelect: feedbackSurvey.handleTranscriptSelect, inputValue: inputValue, setInputValue: setInputValue, onRequestFeedback: didAutoRunIssueRef.current ? undefined : handleSurveyRequestFeedback }), frustrationDetection.state !== 'closed' && _jsx(FeedbackSurvey, { state: frustrationDetection.state, lastResponse: null, handleSelect: () => { }, handleTranscriptSelect: frustrationDetection.handleTranscriptSelect, inputValue: inputValue, setInputValue: setInputValue }), "external" === 'ant' && skillImprovementSurvey.suggestion && _jsx(SkillImprovementSurvey, { isOpen: skillImprovementSurvey.isOpen, skillName: skillImprovementSurvey.suggestion.skillName, updates: skillImprovementSurvey.suggestion.updates, handleSelect: skillImprovementSurvey.handleSelect, inputValue: inputValue, setInputValue: setInputValue }), showIssueFlagBanner && _jsx(IssueFlagBanner, {}), _jsx(PromptInput, { debug: debug, ideSelection: ideSelection, hasSuppressedDialogs: !!hasSuppressedDialogs, isLocalJSXCommandActive: isShowingLocalJSXCommand, getToolUseContext: getToolUseContext, toolPermissionContext: toolPermissionContext, setToolPermissionContext: setToolPermissionContext, apiKeyStatus: apiKeyStatus, commands: commands, agents: agentDefinitions.activeAgents, isLoading: isLoading, onExit: handleExit, verbose: verbose, messages: messages, onAutoUpdaterResult: setAutoUpdaterResult, autoUpdaterResult: autoUpdaterResult, input: inputValue, onInputChange: setInputValue, mode: inputMode, onModeChange: setInputMode, stashedPrompt: stashedPrompt, setStashedPrompt: setStashedPrompt, submitCount: submitCount, onShowMessageSelector: handleShowMessageSelector, onMessageActionsEnter:
4346
- // Works during isLoading — edit cancels first; uuid selection survives appends.
4347
- feature('MESSAGE_ACTIONS') && isFullscreenEnvEnabled() && !disableMessageActions ? enterMessageActions : undefined, mcpClients: mcpClients, pastedContents: pastedContents, setPastedContents: setPastedContents, vimMode: vimMode, setVimMode: setVimMode, showBashesDialog: showBashesDialog, setShowBashesDialog: setShowBashesDialog, onSubmit: onSubmit, onAgentSubmit: onAgentSubmit, isSearchingHistory: isSearchingHistory, setIsSearchingHistory: setIsSearchingHistory, helpOpen: isHelpOpen, setHelpOpen: setIsHelpOpen, insertTextRef: feature('VOICE_MODE') ? insertTextRef : undefined, voiceInterimRange: voice.interimRange }), _jsx(SessionBackgroundHint, { onBackgroundSession: handleBackgroundSession, isLoading: isLoading })] }), cursor &&
4348
- _jsx(MessageActionsBar, { cursor: cursor }), focusedInputDialog === 'message-selector' && _jsx(MessageSelector, { messages: messages, preselectedMessage: messageSelectorPreselect, onPreRestore: onCancel, onRestoreCode: async (message) => {
4349
- await fileHistoryRewind((updater) => {
4350
- setAppState(prev => ({
4351
- ...prev,
4352
- fileHistory: updater(prev.fileHistory)
4353
- }));
4354
- }, message.uuid);
4355
- }, onSummarize: async (message, feedback, direction = 'from') => {
4356
- // Project snipped messages so the compact model
4357
- // doesn't summarize content that was intentionally removed.
4358
- const compactMessages = getMessagesAfterCompactBoundary(messages);
4359
- const messageIndex = compactMessages.indexOf(message);
4360
- if (messageIndex === -1) {
4361
- // Selected a snipped or pre-compact message that the
4362
- // selector still shows (REPL keeps full history for
4363
- // scrollback). Surface why nothing happened instead
4364
- // of silently no-oping.
4365
- setMessages(prev => [...prev, createSystemMessage('That message is no longer in the active context (snipped or pre-compact). Choose a more recent message.', 'warning')]);
4366
- return;
4367
- }
4368
- const newAbortController = createAbortController();
4369
- const context = getToolUseContext(compactMessages, [], newAbortController, mainLoopModel);
4370
- const appState = context.getAppState();
4371
- const defaultSysPrompt = await getSystemPrompt(context.options.tools, context.options.mainLoopModel, Array.from(appState.toolPermissionContext.additionalWorkingDirectories.keys()), context.options.mcpClients);
4372
- const systemPrompt = buildEffectiveSystemPrompt({
4373
- mainThreadAgentDefinition: undefined,
4374
- toolUseContext: context,
4375
- customSystemPrompt: context.options.customSystemPrompt,
4376
- defaultSystemPrompt: defaultSysPrompt,
4377
- appendSystemPrompt: context.options.appendSystemPrompt
4378
- });
4379
- const [userContext, systemContext] = await Promise.all([getUserContext(), getSystemContext()]);
4380
- const result = await partialCompactConversation(compactMessages, messageIndex, context, {
4381
- systemPrompt,
4382
- userContext,
4383
- systemContext,
4384
- toolUseContext: context,
4385
- forkContextMessages: compactMessages
4386
- }, feedback, direction);
4387
- const kept = result.messagesToKeep ?? [];
4388
- const ordered = direction === 'up_to' ? [...result.summaryMessages, ...kept] : [...kept, ...result.summaryMessages];
4389
- const postCompact = [result.boundaryMarker, ...ordered, ...result.attachments, ...result.hookResults];
4390
- // Fullscreen 'from' keeps scrollback; 'up_to' must not
4391
- // (old[0] unchanged + grown array means incremental
4392
- // useLogMessages path, so boundary never persisted).
4393
- // Find by uuid since old is raw REPL history and snipped
4394
- // entries can shift the projected messageIndex.
4395
- if (isFullscreenEnvEnabled() && direction === 'from') {
4396
- setMessages(old => {
4397
- const rawIdx = old.findIndex(m => m.uuid === message.uuid);
4398
- return [...old.slice(0, rawIdx === -1 ? 0 : rawIdx), ...postCompact];
4399
- });
4400
- }
4401
- else {
4402
- setMessages(postCompact);
4403
- }
4404
- // Partial compact bypasses handleMessageFromStream — clear
4405
- // the context-blocked flag so proactive ticks resume.
4406
- if (feature('PROACTIVE') || feature('KAIROS')) {
4407
- proactiveModule?.setContextBlocked(false);
4408
- }
4409
- setConversationId(randomUUID());
4410
- runPostCompactCleanup(context.options.querySource);
4411
- if (direction === 'from') {
4412
- const r = textForResubmit(message);
4413
- if (r) {
4414
- setInputValue(r.text);
4415
- setInputMode(r.mode);
4416
- }
4417
- }
4418
- // Show notification with ctrl+o hint
4419
- const historyShortcut = getShortcutDisplay('app:toggleTranscript', 'Global', 'ctrl+o');
4420
- addNotification({
4421
- key: 'summarize-ctrl-o-hint',
4422
- text: `Conversation summarized (${historyShortcut} for history)`,
4423
- priority: 'medium',
4424
- timeoutMs: 8000
4425
- });
4426
- }, onRestoreMessage: handleRestoreMessage, onClose: () => {
4427
- setIsMessageSelectorVisible(false);
4428
- setMessageSelectorPreselect(undefined);
4429
- } }), "external" === 'ant' && _jsx(DevBar, {})] }), feature('BUDDY') && !(companionNarrow && isFullscreenEnvEnabled()) && companionVisible ? _jsx(CompanionSprite, {}) : null] }) }) }, remountKey)] });
4430
- if (isFullscreenEnvEnabled()) {
4431
- return _jsx(AlternateScreen, { mouseTracking: isMouseTrackingEnabled(), children: mainReturn });
4432
- }
4433
- return mainReturn;
4434
- }