@bubblebrain-ai/bubble 0.0.63 → 0.0.64

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 (912) hide show
  1. package/README.md +437 -11
  2. package/dist/agent/abort-errors.d.ts +18 -0
  3. package/dist/agent/abort-errors.js +51 -0
  4. package/dist/agent/budget-ledger.d.ts +20 -0
  5. package/dist/agent/budget-ledger.js +45 -0
  6. package/dist/agent/categories.d.ts +100 -0
  7. package/dist/agent/categories.js +203 -0
  8. package/dist/agent/change-tracker.d.ts +40 -0
  9. package/dist/agent/change-tracker.js +89 -0
  10. package/dist/agent/child-runner.d.ts +64 -0
  11. package/dist/agent/child-runner.js +405 -0
  12. package/dist/agent/input-controller.d.ts +14 -0
  13. package/dist/agent/input-controller.js +43 -0
  14. package/dist/agent/internal-reminder-sanitizer.d.ts +25 -0
  15. package/dist/agent/internal-reminder-sanitizer.js +297 -0
  16. package/dist/agent/profiles.d.ts +76 -0
  17. package/dist/agent/profiles.js +526 -0
  18. package/dist/agent/provider-fingerprint.d.ts +6 -0
  19. package/dist/agent/provider-fingerprint.js +89 -0
  20. package/dist/agent/resident-history.d.ts +7 -0
  21. package/dist/agent/resident-history.js +61 -0
  22. package/dist/agent/result-integrator.d.ts +22 -0
  23. package/dist/agent/result-integrator.js +50 -0
  24. package/dist/agent/routing-catalog.d.ts +131 -0
  25. package/dist/agent/routing-catalog.js +260 -0
  26. package/dist/agent/structured-output.d.ts +37 -0
  27. package/dist/agent/structured-output.js +193 -0
  28. package/dist/agent/subagent/router.d.ts +65 -0
  29. package/dist/agent/subagent/router.js +203 -0
  30. package/dist/agent/subagent/runtime.d.ts +235 -0
  31. package/dist/agent/subagent/runtime.js +835 -0
  32. package/dist/agent/subagent-control.d.ts +100 -0
  33. package/dist/agent/subagent-control.js +70 -0
  34. package/dist/agent/subagent-lifecycle-reminder.d.ts +3 -0
  35. package/dist/agent/subagent-lifecycle-reminder.js +112 -0
  36. package/dist/agent/subagent-route-format.d.ts +8 -0
  37. package/dist/agent/subagent-route-format.js +18 -0
  38. package/dist/agent/subagent-scheduler.d.ts +105 -0
  39. package/dist/agent/subagent-scheduler.js +287 -0
  40. package/dist/agent/subagent-store.d.ts +57 -0
  41. package/dist/agent/subagent-store.js +180 -0
  42. package/dist/agent/subagent-summary.d.ts +30 -0
  43. package/dist/agent/subagent-summary.js +74 -0
  44. package/dist/agent/subagent-wait-guidance.d.ts +2 -0
  45. package/dist/agent/subagent-wait-guidance.js +8 -0
  46. package/dist/agent/subtask-policy.d.ts +13 -0
  47. package/dist/agent/subtask-policy.js +56 -0
  48. package/dist/agent/task-lifecycle-reminder.d.ts +26 -0
  49. package/dist/agent/task-lifecycle-reminder.js +59 -0
  50. package/dist/agent/tool-intent.d.ts +45 -0
  51. package/dist/agent/tool-intent.js +318 -0
  52. package/dist/agent/tool-visibility.d.ts +10 -0
  53. package/dist/agent/tool-visibility.js +6 -0
  54. package/dist/agent/transcript-helpers.d.ts +20 -0
  55. package/dist/agent/transcript-helpers.js +63 -0
  56. package/dist/agent/update-queue.d.ts +13 -0
  57. package/dist/agent/update-queue.js +69 -0
  58. package/dist/agent/workflow/control.d.ts +60 -0
  59. package/dist/agent/workflow/control.js +62 -0
  60. package/dist/agent/workflow/errors.d.ts +16 -0
  61. package/dist/agent/workflow/errors.js +24 -0
  62. package/dist/agent/workflow/runs.d.ts +73 -0
  63. package/dist/agent/workflow/runs.js +160 -0
  64. package/dist/agent/workflow/runtime.d.ts +88 -0
  65. package/dist/agent/workflow/runtime.js +319 -0
  66. package/dist/agent/worktree.d.ts +29 -0
  67. package/dist/agent/worktree.js +73 -0
  68. package/dist/agent.d.ts +460 -0
  69. package/dist/agent.js +2210 -0
  70. package/dist/anthropic-thinking.d.ts +4 -0
  71. package/dist/anthropic-thinking.js +11 -0
  72. package/dist/approval/controller.d.ts +71 -0
  73. package/dist/approval/controller.js +286 -0
  74. package/dist/approval/danger.d.ts +13 -0
  75. package/dist/approval/danger.js +55 -0
  76. package/dist/approval/diff-hunks.d.ts +12 -0
  77. package/dist/approval/diff-hunks.js +32 -0
  78. package/dist/approval/protected-paths.d.ts +1 -0
  79. package/dist/approval/protected-paths.js +35 -0
  80. package/dist/approval/session-cache.d.ts +21 -0
  81. package/dist/approval/session-cache.js +38 -0
  82. package/dist/approval/tool-helper.d.ts +14 -0
  83. package/dist/approval/tool-helper.js +47 -0
  84. package/dist/approval/types.d.ts +146 -0
  85. package/dist/approval/types.js +8 -0
  86. package/dist/bin.d.ts +2 -0
  87. package/dist/bin.js +3 -0
  88. package/dist/bubble-home.d.ts +8 -0
  89. package/dist/bubble-home.js +19 -0
  90. package/dist/checkpoints.d.ts +57 -0
  91. package/dist/checkpoints.js +0 -0
  92. package/dist/cli.d.ts +37 -0
  93. package/dist/cli.js +175 -0
  94. package/dist/clipboard.d.ts +14 -0
  95. package/dist/clipboard.js +132 -0
  96. package/dist/config.d.ts +96 -0
  97. package/dist/config.js +287 -0
  98. package/dist/context/budget.d.ts +28 -0
  99. package/dist/context/budget.js +130 -0
  100. package/dist/context/checkpoint.d.ts +18 -0
  101. package/dist/context/checkpoint.js +117 -0
  102. package/dist/context/compact-llm.d.ts +25 -0
  103. package/dist/context/compact-llm.js +175 -0
  104. package/dist/context/compact.d.ts +124 -0
  105. package/dist/context/compact.js +635 -0
  106. package/dist/context/compaction-files.d.ts +44 -0
  107. package/dist/context/compaction-files.js +148 -0
  108. package/dist/context/llm-compactor.d.ts +53 -0
  109. package/dist/context/llm-compactor.js +424 -0
  110. package/dist/context/overflow.d.ts +9 -0
  111. package/dist/context/overflow.js +50 -0
  112. package/dist/context/projector.d.ts +34 -0
  113. package/dist/context/projector.js +251 -0
  114. package/dist/context/prune.d.ts +26 -0
  115. package/dist/context/prune.js +171 -0
  116. package/dist/context/session-write-lock.d.ts +20 -0
  117. package/dist/context/session-write-lock.js +162 -0
  118. package/dist/context/token-estimator.d.ts +14 -0
  119. package/dist/context/token-estimator.js +106 -0
  120. package/dist/context/tool-images.d.ts +3 -0
  121. package/dist/context/tool-images.js +35 -0
  122. package/dist/context/tool-output-truncate.d.ts +24 -0
  123. package/dist/context/tool-output-truncate.js +181 -0
  124. package/dist/context/usage.d.ts +34 -0
  125. package/dist/context/usage.js +230 -0
  126. package/dist/debug-trace.d.ts +27 -0
  127. package/dist/debug-trace.js +401 -0
  128. package/dist/diff-stats.d.ts +5 -0
  129. package/dist/diff-stats.js +21 -0
  130. package/dist/external-runtime/grok-acp.d.ts +56 -0
  131. package/dist/external-runtime/grok-acp.js +386 -0
  132. package/dist/external-runtime/grok-binary.d.ts +25 -0
  133. package/dist/external-runtime/grok-binary.js +108 -0
  134. package/dist/external-runtime/grok-errors.d.ts +7 -0
  135. package/dist/external-runtime/grok-errors.js +15 -0
  136. package/dist/external-runtime/grok-input-policy.d.ts +58 -0
  137. package/dist/external-runtime/grok-input-policy.js +52 -0
  138. package/dist/external-runtime/grok-ndjson.d.ts +14 -0
  139. package/dist/external-runtime/grok-ndjson.js +193 -0
  140. package/dist/external-runtime/grok-network.d.ts +15 -0
  141. package/dist/external-runtime/grok-network.js +81 -0
  142. package/dist/external-runtime/grok-preflight.d.ts +28 -0
  143. package/dist/external-runtime/grok-preflight.js +194 -0
  144. package/dist/external-runtime/grok-process.d.ts +26 -0
  145. package/dist/external-runtime/grok-process.js +184 -0
  146. package/dist/external-runtime/grok-profile.d.ts +32 -0
  147. package/dist/external-runtime/grok-profile.js +419 -0
  148. package/dist/external-runtime/grok-provider.d.ts +31 -0
  149. package/dist/external-runtime/grok-provider.js +41 -0
  150. package/dist/external-runtime/grok-runtime.d.ts +91 -0
  151. package/dist/external-runtime/grok-runtime.js +882 -0
  152. package/dist/external-runtime/index.d.ts +13 -0
  153. package/dist/external-runtime/index.js +13 -0
  154. package/dist/external-runtime/session-policy.d.ts +11 -0
  155. package/dist/external-runtime/session-policy.js +30 -0
  156. package/dist/external-runtime/types.d.ts +65 -0
  157. package/dist/external-runtime/types.js +1 -0
  158. package/dist/feedback/collect.d.ts +7 -0
  159. package/dist/feedback/collect.js +119 -0
  160. package/dist/feedback/config.d.ts +14 -0
  161. package/dist/feedback/config.js +16 -0
  162. package/dist/feedback/redact.d.ts +1 -0
  163. package/dist/feedback/redact.js +25 -0
  164. package/dist/feedback/submit.d.ts +6 -0
  165. package/dist/feedback/submit.js +43 -0
  166. package/dist/feedback/types.d.ts +22 -0
  167. package/dist/feedback/types.js +1 -0
  168. package/dist/feishu/agent-host/approval-card.d.ts +11 -0
  169. package/dist/feishu/agent-host/approval-card.js +85 -0
  170. package/dist/feishu/agent-host/approval-ui.d.ts +59 -0
  171. package/dist/feishu/agent-host/approval-ui.js +214 -0
  172. package/dist/feishu/agent-host/run-driver.d.ts +51 -0
  173. package/dist/feishu/agent-host/run-driver.js +397 -0
  174. package/dist/feishu/agent-host/runtime-deps.d.ts +33 -0
  175. package/dist/feishu/agent-host/runtime-deps.js +8 -0
  176. package/dist/feishu/card/budget.d.ts +40 -0
  177. package/dist/feishu/card/budget.js +134 -0
  178. package/dist/feishu/card/renderer.d.ts +29 -0
  179. package/dist/feishu/card/renderer.js +245 -0
  180. package/dist/feishu/card/run-state-types.d.ts +49 -0
  181. package/dist/feishu/card/run-state-types.js +15 -0
  182. package/dist/feishu/card/run-state.d.ts +21 -0
  183. package/dist/feishu/card/run-state.js +223 -0
  184. package/dist/feishu/channel/channel.d.ts +52 -0
  185. package/dist/feishu/channel/channel.js +74 -0
  186. package/dist/feishu/config.d.ts +24 -0
  187. package/dist/feishu/config.js +97 -0
  188. package/dist/feishu/format.d.ts +6 -0
  189. package/dist/feishu/format.js +14 -0
  190. package/dist/feishu/index.d.ts +4 -0
  191. package/dist/feishu/index.js +4 -0
  192. package/dist/feishu/logger.d.ts +31 -0
  193. package/dist/feishu/logger.js +62 -0
  194. package/dist/feishu/paths.d.ts +12 -0
  195. package/dist/feishu/paths.js +38 -0
  196. package/dist/feishu/process-registry.d.ts +29 -0
  197. package/dist/feishu/process-registry.js +90 -0
  198. package/dist/feishu/router/commands.d.ts +38 -0
  199. package/dist/feishu/router/commands.js +286 -0
  200. package/dist/feishu/router/event-router.d.ts +40 -0
  201. package/dist/feishu/router/event-router.js +208 -0
  202. package/dist/feishu/router/whitelist.d.ts +23 -0
  203. package/dist/feishu/router/whitelist.js +20 -0
  204. package/dist/feishu/runtime/active-runs.d.ts +32 -0
  205. package/dist/feishu/runtime/active-runs.js +84 -0
  206. package/dist/feishu/runtime/pending-queue.d.ts +36 -0
  207. package/dist/feishu/runtime/pending-queue.js +98 -0
  208. package/dist/feishu/runtime/process-pool.d.ts +29 -0
  209. package/dist/feishu/runtime/process-pool.js +49 -0
  210. package/dist/feishu/schema.d.ts +17 -0
  211. package/dist/feishu/schema.js +252 -0
  212. package/dist/feishu/scope/scope-registry.d.ts +39 -0
  213. package/dist/feishu/scope/scope-registry.js +148 -0
  214. package/dist/feishu/scope/session-binder.d.ts +44 -0
  215. package/dist/feishu/scope/session-binder.js +100 -0
  216. package/dist/feishu/scope/session-store.d.ts +24 -0
  217. package/dist/feishu/scope/session-store.js +73 -0
  218. package/dist/feishu/secrets.d.ts +37 -0
  219. package/dist/feishu/secrets.js +129 -0
  220. package/dist/feishu/serve.d.ts +12 -0
  221. package/dist/feishu/serve.js +302 -0
  222. package/dist/feishu/types.d.ts +75 -0
  223. package/dist/feishu/types.js +23 -0
  224. package/dist/feishu/wizard.d.ts +24 -0
  225. package/dist/feishu/wizard.js +121 -0
  226. package/dist/goal/command.d.ts +20 -0
  227. package/dist/goal/command.js +76 -0
  228. package/dist/goal/engine.d.ts +33 -0
  229. package/dist/goal/engine.js +65 -0
  230. package/dist/goal/format.d.ts +18 -0
  231. package/dist/goal/format.js +112 -0
  232. package/dist/goal/prompts.d.ts +13 -0
  233. package/dist/goal/prompts.js +84 -0
  234. package/dist/goal/store.d.ts +64 -0
  235. package/dist/goal/store.js +174 -0
  236. package/dist/goal/tools.d.ts +13 -0
  237. package/dist/goal/tools.js +67 -0
  238. package/dist/goal/usage.d.ts +2 -0
  239. package/dist/goal/usage.js +3 -0
  240. package/dist/hooks/config.d.ts +9 -0
  241. package/dist/hooks/config.js +278 -0
  242. package/dist/hooks/controller.d.ts +24 -0
  243. package/dist/hooks/controller.js +254 -0
  244. package/dist/hooks/index.d.ts +6 -0
  245. package/dist/hooks/index.js +4 -0
  246. package/dist/hooks/log.d.ts +14 -0
  247. package/dist/hooks/log.js +54 -0
  248. package/dist/hooks/runner.d.ts +5 -0
  249. package/dist/hooks/runner.js +225 -0
  250. package/dist/hooks/trust.d.ts +37 -0
  251. package/dist/hooks/trust.js +143 -0
  252. package/dist/hooks/types.d.ts +173 -0
  253. package/dist/hooks/types.js +46 -0
  254. package/dist/loop/engine.d.ts +29 -0
  255. package/dist/loop/engine.js +63 -0
  256. package/dist/lsp/config.d.ts +18 -0
  257. package/dist/lsp/config.js +58 -0
  258. package/dist/lsp/diagnostics.d.ts +24 -0
  259. package/dist/lsp/diagnostics.js +103 -0
  260. package/dist/lsp/index.d.ts +3 -0
  261. package/dist/lsp/index.js +3 -0
  262. package/dist/lsp/service.d.ts +97 -0
  263. package/dist/lsp/service.js +815 -0
  264. package/dist/main.d.ts +5 -0
  265. package/dist/main.js +984 -0
  266. package/dist/mcp/client.d.ts +68 -0
  267. package/dist/mcp/client.js +177 -0
  268. package/dist/mcp/config.d.ts +30 -0
  269. package/dist/mcp/config.js +144 -0
  270. package/dist/mcp/manager.d.ts +67 -0
  271. package/dist/mcp/manager.js +328 -0
  272. package/dist/mcp/name.d.ts +26 -0
  273. package/dist/mcp/name.js +40 -0
  274. package/dist/mcp/transports.d.ts +54 -0
  275. package/dist/mcp/transports.js +267 -0
  276. package/dist/mcp/types.d.ts +111 -0
  277. package/dist/mcp/types.js +14 -0
  278. package/dist/memory/db.d.ts +65 -0
  279. package/dist/memory/db.js +332 -0
  280. package/dist/memory/index.d.ts +10 -0
  281. package/dist/memory/index.js +10 -0
  282. package/dist/memory/paths.d.ts +18 -0
  283. package/dist/memory/paths.js +38 -0
  284. package/dist/memory/phase1.d.ts +23 -0
  285. package/dist/memory/phase1.js +292 -0
  286. package/dist/memory/phase2.d.ts +19 -0
  287. package/dist/memory/phase2.js +119 -0
  288. package/dist/memory/prompts.d.ts +19 -0
  289. package/dist/memory/prompts.js +104 -0
  290. package/dist/memory/reset.d.ts +1 -0
  291. package/dist/memory/reset.js +13 -0
  292. package/dist/memory/session-policy.d.ts +25 -0
  293. package/dist/memory/session-policy.js +55 -0
  294. package/dist/memory/start.d.ts +24 -0
  295. package/dist/memory/start.js +50 -0
  296. package/dist/memory/storage.d.ts +11 -0
  297. package/dist/memory/storage.js +95 -0
  298. package/dist/memory/store.d.ts +43 -0
  299. package/dist/memory/store.js +193 -0
  300. package/dist/memory/usage.d.ts +1 -0
  301. package/dist/memory/usage.js +38 -0
  302. package/dist/model-catalog.d.ts +65 -0
  303. package/dist/model-catalog.js +387 -0
  304. package/dist/model-config.d.ts +40 -0
  305. package/dist/model-config.js +74 -0
  306. package/dist/model-data.generated.d.ts +16 -0
  307. package/dist/model-data.generated.js +275 -0
  308. package/dist/model-pricing.d.ts +54 -0
  309. package/dist/model-pricing.js +244 -0
  310. package/dist/model-selection.d.ts +7 -0
  311. package/dist/model-selection.js +18 -0
  312. package/dist/network/chatgpt-transport.d.ts +16 -0
  313. package/dist/network/chatgpt-transport.js +232 -0
  314. package/dist/network/errors.d.ts +47 -0
  315. package/dist/network/errors.js +48 -0
  316. package/dist/network/provider-transport-log.d.ts +12 -0
  317. package/dist/network/provider-transport-log.js +32 -0
  318. package/dist/network/provider-transport.d.ts +37 -0
  319. package/dist/network/provider-transport.js +256 -0
  320. package/dist/network/retry.d.ts +34 -0
  321. package/dist/network/retry.js +97 -0
  322. package/dist/network/system-proxy.d.ts +18 -0
  323. package/dist/network/system-proxy.js +175 -0
  324. package/dist/oauth/grok.d.ts +26 -0
  325. package/dist/oauth/grok.js +251 -0
  326. package/dist/oauth/index.d.ts +4 -0
  327. package/dist/oauth/index.js +3 -0
  328. package/dist/oauth/openai-codex.d.ts +15 -0
  329. package/dist/oauth/openai-codex.js +193 -0
  330. package/dist/oauth/refresh-control.d.ts +12 -0
  331. package/dist/oauth/refresh-control.js +42 -0
  332. package/dist/oauth/storage.d.ts +88 -0
  333. package/dist/oauth/storage.js +357 -0
  334. package/dist/oauth/types.d.ts +15 -0
  335. package/dist/oauth/types.js +1 -0
  336. package/dist/orchestrator/default-hooks.d.ts +22 -0
  337. package/dist/orchestrator/default-hooks.js +127 -0
  338. package/dist/orchestrator/hooks.d.ts +69 -0
  339. package/dist/orchestrator/hooks.js +52 -0
  340. package/dist/permission/mode.d.ts +19 -0
  341. package/dist/permission/mode.js +16 -0
  342. package/dist/permissions/rule.d.ts +42 -0
  343. package/dist/permissions/rule.js +293 -0
  344. package/dist/permissions/settings.d.ts +97 -0
  345. package/dist/permissions/settings.js +289 -0
  346. package/dist/permissions/shell-command.d.ts +36 -0
  347. package/dist/permissions/shell-command.js +226 -0
  348. package/dist/permissions/trust-prompt.d.ts +10 -0
  349. package/dist/permissions/trust-prompt.js +34 -0
  350. package/dist/permissions/trust.d.ts +26 -0
  351. package/dist/permissions/trust.js +113 -0
  352. package/dist/permissions/types.d.ts +61 -0
  353. package/dist/permissions/types.js +14 -0
  354. package/dist/print-output.d.ts +98 -0
  355. package/dist/print-output.js +117 -0
  356. package/dist/prompt/compose.d.ts +19 -0
  357. package/dist/prompt/compose.js +110 -0
  358. package/dist/prompt/delegation.d.ts +14 -0
  359. package/dist/prompt/delegation.js +100 -0
  360. package/dist/prompt/environment.d.ts +12 -0
  361. package/dist/prompt/environment.js +55 -0
  362. package/dist/prompt/provider-prompts/anthropic.d.ts +1 -0
  363. package/dist/prompt/provider-prompts/anthropic.js +5 -0
  364. package/dist/prompt/provider-prompts/codex.d.ts +1 -0
  365. package/dist/prompt/provider-prompts/codex.js +5 -0
  366. package/dist/prompt/provider-prompts/deepseek.d.ts +1 -0
  367. package/dist/prompt/provider-prompts/deepseek.js +7 -0
  368. package/dist/prompt/provider-prompts/default.d.ts +1 -0
  369. package/dist/prompt/provider-prompts/default.js +6 -0
  370. package/dist/prompt/provider-prompts/gemini.d.ts +1 -0
  371. package/dist/prompt/provider-prompts/gemini.js +5 -0
  372. package/dist/prompt/provider-prompts/glm.d.ts +1 -0
  373. package/dist/prompt/provider-prompts/glm.js +7 -0
  374. package/dist/prompt/provider-prompts/gpt.d.ts +1 -0
  375. package/dist/prompt/provider-prompts/gpt.js +5 -0
  376. package/dist/prompt/provider-prompts/kimi.d.ts +1 -0
  377. package/dist/prompt/provider-prompts/kimi.js +8 -0
  378. package/dist/prompt/reminders.d.ts +33 -0
  379. package/dist/prompt/reminders.js +135 -0
  380. package/dist/prompt/routing.d.ts +14 -0
  381. package/dist/prompt/routing.js +71 -0
  382. package/dist/prompt/runtime.d.ts +12 -0
  383. package/dist/prompt/runtime.js +40 -0
  384. package/dist/prompt/task-reminders.d.ts +12 -0
  385. package/dist/prompt/task-reminders.js +64 -0
  386. package/dist/provider-ai-sdk.d.ts +59 -0
  387. package/dist/provider-ai-sdk.js +541 -0
  388. package/dist/provider-anthropic.d.ts +126 -0
  389. package/dist/provider-anthropic.js +940 -0
  390. package/dist/provider-ark-responses.d.ts +29 -0
  391. package/dist/provider-ark-responses.js +518 -0
  392. package/dist/provider-artifacts.d.ts +7 -0
  393. package/dist/provider-artifacts.js +60 -0
  394. package/dist/provider-error-record.d.ts +43 -0
  395. package/dist/provider-error-record.js +213 -0
  396. package/dist/provider-grok.d.ts +50 -0
  397. package/dist/provider-grok.js +110 -0
  398. package/dist/provider-model-policy.d.ts +16 -0
  399. package/dist/provider-model-policy.js +33 -0
  400. package/dist/provider-openai-codex.d.ts +66 -0
  401. package/dist/provider-openai-codex.js +781 -0
  402. package/dist/provider-registry.d.ts +197 -0
  403. package/dist/provider-registry.js +1194 -0
  404. package/dist/provider-transform.d.ts +12 -0
  405. package/dist/provider-transform.js +293 -0
  406. package/dist/provider-zen-errors.d.ts +9 -0
  407. package/dist/provider-zen-errors.js +36 -0
  408. package/dist/provider.d.ts +85 -0
  409. package/dist/provider.js +925 -0
  410. package/dist/question/controller.d.ts +22 -0
  411. package/dist/question/controller.js +98 -0
  412. package/dist/question/index.d.ts +2 -0
  413. package/dist/question/index.js +2 -0
  414. package/dist/question/normalize.d.ts +6 -0
  415. package/dist/question/normalize.js +11 -0
  416. package/dist/question/types.d.ts +42 -0
  417. package/dist/question/types.js +6 -0
  418. package/dist/reasoning-debug.d.ts +7 -0
  419. package/dist/reasoning-debug.js +33 -0
  420. package/dist/rewind.d.ts +20 -0
  421. package/dist/rewind.js +29 -0
  422. package/dist/sdk/index.d.ts +319 -0
  423. package/dist/sdk/index.js +1068 -0
  424. package/dist/sdk/replay-event-log.d.ts +26 -0
  425. package/dist/sdk/replay-event-log.js +122 -0
  426. package/dist/sdk/session-turn-coordinator.d.ts +45 -0
  427. package/dist/sdk/session-turn-coordinator.js +227 -0
  428. package/dist/session-context-fence.d.ts +16 -0
  429. package/dist/session-context-fence.js +26 -0
  430. package/dist/session-log.d.ts +25 -0
  431. package/dist/session-log.js +444 -0
  432. package/dist/session-title.d.ts +16 -0
  433. package/dist/session-title.js +131 -0
  434. package/dist/session-types.d.ts +86 -0
  435. package/dist/session-types.js +1 -0
  436. package/dist/session.d.ts +135 -0
  437. package/dist/session.js +664 -0
  438. package/dist/skills/discovery.d.ts +12 -0
  439. package/dist/skills/discovery.js +166 -0
  440. package/dist/skills/format.d.ts +32 -0
  441. package/dist/skills/format.js +68 -0
  442. package/dist/skills/frontmatter.d.ts +5 -0
  443. package/dist/skills/frontmatter.js +60 -0
  444. package/dist/skills/invocation.d.ts +8 -0
  445. package/dist/skills/invocation.js +33 -0
  446. package/dist/skills/registry.d.ts +28 -0
  447. package/dist/skills/registry.js +79 -0
  448. package/dist/skills/types.d.ts +34 -0
  449. package/dist/skills/types.js +1 -0
  450. package/dist/slash-commands/commands.d.ts +10 -0
  451. package/dist/slash-commands/commands.js +1251 -0
  452. package/dist/slash-commands/feishu.d.ts +17 -0
  453. package/dist/slash-commands/feishu.js +400 -0
  454. package/dist/slash-commands/index.d.ts +4 -0
  455. package/dist/slash-commands/index.js +8 -0
  456. package/dist/slash-commands/registry.d.ts +32 -0
  457. package/dist/slash-commands/registry.js +73 -0
  458. package/dist/slash-commands/types.d.ts +109 -0
  459. package/dist/slash-commands/types.js +1 -0
  460. package/dist/slash-commands/unified.d.ts +38 -0
  461. package/dist/slash-commands/unified.js +38 -0
  462. package/dist/stats/usage.d.ts +59 -0
  463. package/dist/stats/usage.js +485 -0
  464. package/dist/stream-json.d.ts +13 -0
  465. package/dist/stream-json.js +74 -0
  466. package/dist/system-prompt.d.ts +40 -0
  467. package/dist/system-prompt.js +7 -0
  468. package/dist/tasks/manager.d.ts +145 -0
  469. package/dist/tasks/manager.js +634 -0
  470. package/dist/tasks/process-utils.d.ts +10 -0
  471. package/dist/tasks/process-utils.js +49 -0
  472. package/dist/tasks/promotion.d.ts +17 -0
  473. package/dist/tasks/promotion.js +30 -0
  474. package/dist/tasks/wake.d.ts +53 -0
  475. package/dist/tasks/wake.js +125 -0
  476. package/dist/text-display.d.ts +3 -0
  477. package/dist/text-display.js +25 -0
  478. package/dist/tools/agent-lifecycle.d.ts +30 -0
  479. package/dist/tools/agent-lifecycle.js +790 -0
  480. package/dist/tools/bash.d.ts +23 -0
  481. package/dist/tools/bash.js +443 -0
  482. package/dist/tools/child-tools.d.ts +41 -0
  483. package/dist/tools/child-tools.js +122 -0
  484. package/dist/tools/edit-apply.d.ts +25 -0
  485. package/dist/tools/edit-apply.js +274 -0
  486. package/dist/tools/edit.d.ts +18 -0
  487. package/dist/tools/edit.js +200 -0
  488. package/dist/tools/exa-mcp.d.ts +3 -0
  489. package/dist/tools/exa-mcp.js +74 -0
  490. package/dist/tools/exit-plan-mode.d.ts +22 -0
  491. package/dist/tools/exit-plan-mode.js +79 -0
  492. package/dist/tools/file-mutation-queue.d.ts +2 -0
  493. package/dist/tools/file-mutation-queue.js +43 -0
  494. package/dist/tools/file-state.d.ts +48 -0
  495. package/dist/tools/file-state.js +76 -0
  496. package/dist/tools/grep.d.ts +9 -0
  497. package/dist/tools/grep.js +387 -0
  498. package/dist/tools/index.d.ts +63 -0
  499. package/dist/tools/index.js +76 -0
  500. package/dist/tools/ls.d.ts +3 -0
  501. package/dist/tools/ls.js +85 -0
  502. package/dist/tools/lsp.d.ts +4 -0
  503. package/dist/tools/lsp.js +95 -0
  504. package/dist/tools/memory.d.ts +8 -0
  505. package/dist/tools/memory.js +77 -0
  506. package/dist/tools/path-utils.d.ts +8 -0
  507. package/dist/tools/path-utils.js +53 -0
  508. package/dist/tools/prompt-metadata.d.ts +3 -0
  509. package/dist/tools/prompt-metadata.js +17 -0
  510. package/dist/tools/question.d.ts +3 -0
  511. package/dist/tools/question.js +177 -0
  512. package/dist/tools/read.d.ts +8 -0
  513. package/dist/tools/read.js +309 -0
  514. package/dist/tools/sensitive-paths.d.ts +11 -0
  515. package/dist/tools/sensitive-paths.js +106 -0
  516. package/dist/tools/server-manager.d.ts +6 -0
  517. package/dist/tools/server-manager.js +6 -0
  518. package/dist/tools/server.d.ts +6 -0
  519. package/dist/tools/server.js +249 -0
  520. package/dist/tools/skill-search.d.ts +10 -0
  521. package/dist/tools/skill-search.js +134 -0
  522. package/dist/tools/skill.d.ts +7 -0
  523. package/dist/tools/skill.js +81 -0
  524. package/dist/tools/task-tools.d.ts +10 -0
  525. package/dist/tools/task-tools.js +133 -0
  526. package/dist/tools/tool-search.d.ts +23 -0
  527. package/dist/tools/tool-search.js +145 -0
  528. package/dist/tools/web-fetch.d.ts +6 -0
  529. package/dist/tools/web-fetch.js +76 -0
  530. package/dist/tools/web-search.d.ts +5 -0
  531. package/dist/tools/web-search.js +50 -0
  532. package/dist/tools/write.d.ts +10 -0
  533. package/dist/tools/write.js +155 -0
  534. package/dist/tui/animation-clock.d.ts +14 -0
  535. package/dist/tui/animation-clock.js +34 -0
  536. package/dist/tui/app.d.ts +176 -0
  537. package/dist/tui/app.js +1659 -0
  538. package/dist/tui/components/approval-dialog.d.ts +43 -0
  539. package/dist/tui/components/approval-dialog.js +212 -0
  540. package/dist/tui/components/bottom-sheet.d.ts +9 -0
  541. package/dist/tui/components/bottom-sheet.js +32 -0
  542. package/dist/tui/components/context-info.d.ts +54 -0
  543. package/dist/tui/components/context-info.js +388 -0
  544. package/dist/tui/components/feedback-dialog.d.ts +56 -0
  545. package/dist/tui/components/feedback-dialog.js +262 -0
  546. package/dist/tui/components/feishu-setup-dialog.d.ts +65 -0
  547. package/dist/tui/components/feishu-setup-dialog.js +332 -0
  548. package/dist/tui/components/image-preview.d.ts +32 -0
  549. package/dist/tui/components/image-preview.js +130 -0
  550. package/dist/tui/components/plan-dialog.d.ts +34 -0
  551. package/dist/tui/components/plan-dialog.js +196 -0
  552. package/dist/tui/components/provider-key-input.d.ts +18 -0
  553. package/dist/tui/components/provider-key-input.js +49 -0
  554. package/dist/tui/components/question-dialog.d.ts +25 -0
  555. package/dist/tui/components/question-dialog.js +263 -0
  556. package/dist/tui/components/responsive-transcript.d.ts +31 -0
  557. package/dist/tui/components/responsive-transcript.js +77 -0
  558. package/dist/tui/components/rewind-picker.d.ts +62 -0
  559. package/dist/tui/components/rewind-picker.js +317 -0
  560. package/dist/tui/components/session-picker.d.ts +49 -0
  561. package/dist/tui/components/session-picker.js +303 -0
  562. package/dist/tui/components/skills-panel.d.ts +63 -0
  563. package/dist/tui/components/skills-panel.js +582 -0
  564. package/dist/tui/components/stats-panel.d.ts +40 -0
  565. package/dist/tui/components/stats-panel.js +301 -0
  566. package/dist/tui/components/streaming-message.d.ts +69 -0
  567. package/dist/tui/components/streaming-message.js +398 -0
  568. package/dist/tui/components/subagent-inspector.d.ts +28 -0
  569. package/dist/tui/components/subagent-inspector.js +127 -0
  570. package/dist/tui/components/task-inspector.d.ts +26 -0
  571. package/dist/tui/components/task-inspector.js +70 -0
  572. package/dist/tui/components/tasks-pane.d.ts +126 -0
  573. package/dist/tui/components/tasks-pane.js +566 -0
  574. package/dist/tui/components/transcript.d.ts +103 -0
  575. package/dist/tui/components/transcript.js +858 -0
  576. package/dist/tui/components/welcome.d.ts +20 -0
  577. package/dist/tui/components/welcome.js +133 -0
  578. package/dist/tui/components/workflow-inspector.d.ts +30 -0
  579. package/dist/tui/components/workflow-inspector.js +136 -0
  580. package/dist/tui/composer-autocomplete.d.ts +76 -0
  581. package/dist/tui/composer-autocomplete.js +465 -0
  582. package/dist/tui/composer-style.d.ts +7 -0
  583. package/dist/tui/composer-style.js +29 -0
  584. package/dist/tui/controller/agent-event-reducer.d.ts +75 -0
  585. package/dist/tui/controller/agent-event-reducer.js +239 -0
  586. package/dist/tui/controller/composer-controller.d.ts +95 -0
  587. package/dist/tui/controller/composer-controller.js +502 -0
  588. package/dist/tui/controller/controller.d.ts +199 -0
  589. package/dist/tui/controller/controller.js +1034 -0
  590. package/dist/tui/controller/effects.d.ts +71 -0
  591. package/dist/tui/controller/effects.js +1 -0
  592. package/dist/tui/controller/goal-runtime-controller.d.ts +47 -0
  593. package/dist/tui/controller/goal-runtime-controller.js +202 -0
  594. package/dist/tui/controller/input-queue-machine.d.ts +71 -0
  595. package/dist/tui/controller/input-queue-machine.js +121 -0
  596. package/dist/tui/controller/intents.d.ts +56 -0
  597. package/dist/tui/controller/intents.js +6 -0
  598. package/dist/tui/controller/overlay-controller.d.ts +64 -0
  599. package/dist/tui/controller/overlay-controller.js +129 -0
  600. package/dist/tui/controller/ports.d.ts +57 -0
  601. package/dist/tui/controller/ports.js +9 -0
  602. package/dist/tui/controller/session-transition.d.ts +54 -0
  603. package/dist/tui/controller/session-transition.js +68 -0
  604. package/dist/tui/controller/state.d.ts +14 -0
  605. package/dist/tui/controller/state.js +36 -0
  606. package/dist/tui/controller/task-runtime-controller.d.ts +66 -0
  607. package/dist/tui/controller/task-runtime-controller.js +158 -0
  608. package/dist/tui/detect-theme.d.ts +4 -0
  609. package/dist/tui/detect-theme.js +116 -0
  610. package/dist/tui/display-history.d.ts +64 -0
  611. package/dist/tui/display-history.js +283 -0
  612. package/dist/tui/display-sanitizer.d.ts +3 -0
  613. package/dist/tui/display-sanitizer.js +38 -0
  614. package/dist/tui/edit-diff.d.ts +11 -0
  615. package/dist/tui/edit-diff.js +57 -0
  616. package/dist/tui/file-mentions.d.ts +29 -0
  617. package/dist/tui/file-mentions.js +174 -0
  618. package/dist/tui/footer.d.ts +37 -0
  619. package/dist/tui/footer.js +80 -0
  620. package/dist/tui/formatting/edit-diff.d.ts +11 -0
  621. package/dist/tui/formatting/edit-diff.js +52 -0
  622. package/dist/tui/formatting/summary.d.ts +43 -0
  623. package/dist/tui/formatting/summary.js +150 -0
  624. package/dist/tui/fullscreen.d.ts +48 -0
  625. package/dist/tui/fullscreen.js +256 -0
  626. package/dist/tui/image-display.d.ts +23 -0
  627. package/dist/tui/image-display.js +92 -0
  628. package/dist/tui/image-paste.d.ts +113 -0
  629. package/dist/tui/image-paste.js +565 -0
  630. package/dist/tui/input-history.d.ts +47 -0
  631. package/dist/tui/input-history.js +250 -0
  632. package/dist/tui/markdown-style.d.ts +5 -0
  633. package/dist/tui/markdown-style.js +23 -0
  634. package/dist/tui/model/composer-buffer.d.ts +55 -0
  635. package/dist/tui/model/composer-buffer.js +317 -0
  636. package/dist/tui/model/composer-types.d.ts +17 -0
  637. package/dist/tui/model/composer-types.js +1 -0
  638. package/dist/tui/model/display-history.d.ts +78 -0
  639. package/dist/tui/model/display-history.js +124 -0
  640. package/dist/tui/model/display-reconstruct.d.ts +3 -0
  641. package/dist/tui/model/display-reconstruct.js +130 -0
  642. package/dist/tui/model/file-mentions.d.ts +31 -0
  643. package/dist/tui/model/file-mentions.js +178 -0
  644. package/dist/tui/model/image-attachment.d.ts +15 -0
  645. package/dist/tui/model/image-attachment.js +1 -0
  646. package/dist/tui/model/image-paste.d.ts +119 -0
  647. package/dist/tui/model/image-paste.js +610 -0
  648. package/dist/tui/model/input-history.d.ts +1 -0
  649. package/dist/tui/model/input-history.js +1 -0
  650. package/dist/tui/model/input-queue.d.ts +12 -0
  651. package/dist/tui/model/input-queue.js +17 -0
  652. package/dist/tui/model/key-events.d.ts +9 -0
  653. package/dist/tui/model/key-events.js +8 -0
  654. package/dist/tui/model/paste-operation-tracker.d.ts +13 -0
  655. package/dist/tui/model/paste-operation-tracker.js +25 -0
  656. package/dist/tui/model/recent-activity.d.ts +8 -0
  657. package/dist/tui/model/recent-activity.js +71 -0
  658. package/dist/tui/model/subagent-view.d.ts +87 -0
  659. package/dist/tui/model/subagent-view.js +336 -0
  660. package/dist/tui/model/submit-dedupe.d.ts +5 -0
  661. package/dist/tui/model/submit-dedupe.js +25 -0
  662. package/dist/tui/model/sync-output.d.ts +17 -0
  663. package/dist/tui/model/sync-output.js +35 -0
  664. package/dist/tui/model/task-lifecycle.d.ts +57 -0
  665. package/dist/tui/model/task-lifecycle.js +124 -0
  666. package/dist/tui/model/terminal-env.d.ts +15 -0
  667. package/dist/tui/model/terminal-env.js +22 -0
  668. package/dist/tui/model/terminal-mouse.d.ts +28 -0
  669. package/dist/tui/model/terminal-mouse.js +82 -0
  670. package/dist/tui/model/theme-style.d.ts +10 -0
  671. package/dist/tui/model/theme-style.js +79 -0
  672. package/dist/tui/model/theme.d.ts +72 -0
  673. package/dist/tui/model/theme.js +121 -0
  674. package/dist/tui/model/trace-groups.d.ts +45 -0
  675. package/dist/tui/model/trace-groups.js +558 -0
  676. package/dist/tui/model/trace-interaction.d.ts +63 -0
  677. package/dist/tui/model/trace-interaction.js +87 -0
  678. package/dist/tui/model/width.d.ts +18 -0
  679. package/dist/tui/model/width.js +130 -0
  680. package/dist/tui/model-picker-data.d.ts +9 -0
  681. package/dist/tui/model-picker-data.js +39 -0
  682. package/dist/tui/model-switch.d.ts +49 -0
  683. package/dist/tui/model-switch.js +67 -0
  684. package/dist/tui/paste-placeholder.d.ts +11 -0
  685. package/dist/tui/paste-placeholder.js +52 -0
  686. package/dist/tui/recent-activity.d.ts +8 -0
  687. package/dist/tui/recent-activity.js +71 -0
  688. package/dist/tui/run-session-picker.d.ts +9 -0
  689. package/dist/tui/run-session-picker.js +64 -0
  690. package/dist/tui/run.d.ts +72 -0
  691. package/dist/tui/run.js +139 -0
  692. package/dist/tui/session-display.d.ts +6 -0
  693. package/dist/tui/session-display.js +12 -0
  694. package/dist/tui/session-picker-data.d.ts +18 -0
  695. package/dist/tui/session-picker-data.js +21 -0
  696. package/dist/tui/terminal/multiplexer.d.ts +5 -0
  697. package/dist/tui/terminal/multiplexer.js +14 -0
  698. package/dist/tui/testing/fake-agent.d.ts +24 -0
  699. package/dist/tui/testing/fake-agent.js +22 -0
  700. package/dist/tui/testing/spy-host.d.ts +21 -0
  701. package/dist/tui/testing/spy-host.js +55 -0
  702. package/dist/tui/trace-groups.d.ts +43 -0
  703. package/dist/tui/trace-groups.js +554 -0
  704. package/dist/tui/wordmark.d.ts +18 -0
  705. package/dist/tui/wordmark.js +208 -0
  706. package/dist/types.d.ts +503 -0
  707. package/dist/types.js +4 -0
  708. package/dist/update/index.d.ts +61 -0
  709. package/dist/update/index.js +267 -0
  710. package/dist/variant/thinking-level.d.ts +5 -0
  711. package/dist/variant/thinking-level.js +26 -0
  712. package/dist/variant/variant-resolver.d.ts +28 -0
  713. package/dist/variant/variant-resolver.js +62 -0
  714. package/node_modules/@bubblebrain-ai/pi-tui/LICENSE +21 -0
  715. package/node_modules/@bubblebrain-ai/pi-tui/README.md +854 -0
  716. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.d.ts +26 -0
  717. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.d.ts.map +1 -0
  718. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.js +121 -0
  719. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/alt-screen-search.js.map +1 -0
  720. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.d.ts +86 -0
  721. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.d.ts.map +1 -0
  722. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.js +649 -0
  723. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/autocomplete.js.map +1 -0
  724. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.d.ts +13 -0
  725. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.d.ts.map +1 -0
  726. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.js +36 -0
  727. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/alt-screen-flash.js.map +1 -0
  728. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.d.ts +22 -0
  729. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.d.ts.map +1 -0
  730. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.js +99 -0
  731. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/box.js.map +1 -0
  732. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.d.ts +22 -0
  733. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.d.ts.map +1 -0
  734. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.js +36 -0
  735. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/cancellable-loader.js.map +1 -0
  736. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.d.ts +330 -0
  737. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.d.ts.map +1 -0
  738. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.js +2344 -0
  739. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/editor.js.map +1 -0
  740. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.d.ts +7 -0
  741. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.d.ts.map +1 -0
  742. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.js +43 -0
  743. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/h-stack.js.map +1 -0
  744. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.d.ts +28 -0
  745. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.d.ts.map +1 -0
  746. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.js +82 -0
  747. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/image.js.map +1 -0
  748. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.d.ts +48 -0
  749. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.d.ts.map +1 -0
  750. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.js +390 -0
  751. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/input.js.map +1 -0
  752. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.d.ts +31 -0
  753. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.d.ts.map +1 -0
  754. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.js +67 -0
  755. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/loader.js.map +1 -0
  756. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.d.ts +103 -0
  757. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.d.ts.map +1 -0
  758. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.js +797 -0
  759. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/markdown.js.map +1 -0
  760. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.d.ts +56 -0
  761. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.d.ts.map +1 -0
  762. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.js +179 -0
  763. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/scroll-view.js.map +1 -0
  764. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.d.ts +53 -0
  765. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.d.ts.map +1 -0
  766. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.js +175 -0
  767. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/select-list.js.map +1 -0
  768. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.d.ts +50 -0
  769. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.d.ts.map +1 -0
  770. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.js +174 -0
  771. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/settings-list.js.map +1 -0
  772. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.d.ts +12 -0
  773. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.d.ts.map +1 -0
  774. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.js +22 -0
  775. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/spacer.js.map +1 -0
  776. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.d.ts +32 -0
  777. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.d.ts.map +1 -0
  778. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.js +109 -0
  779. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/stack.js.map +1 -0
  780. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.d.ts +19 -0
  781. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.d.ts.map +1 -0
  782. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.js +81 -0
  783. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/text.js.map +1 -0
  784. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.d.ts +13 -0
  785. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.d.ts.map +1 -0
  786. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.js +48 -0
  787. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/truncated-text.js.map +1 -0
  788. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.d.ts +8 -0
  789. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.d.ts.map +1 -0
  790. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.js +26 -0
  791. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/components/v-stack.js.map +1 -0
  792. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.d.ts +39 -0
  793. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.d.ts.map +1 -0
  794. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.js +2 -0
  795. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/editor-component.js.map +1 -0
  796. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.d.ts +16 -0
  797. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.d.ts.map +1 -0
  798. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.js +110 -0
  799. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/fuzzy.js.map +1 -0
  800. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.d.ts +31 -0
  801. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.d.ts.map +1 -0
  802. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.js +42 -0
  803. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/index.js.map +1 -0
  804. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.d.ts +273 -0
  805. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.d.ts.map +1 -0
  806. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.js +231 -0
  807. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keybindings.js.map +1 -0
  808. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.d.ts +184 -0
  809. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.d.ts.map +1 -0
  810. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.js +1174 -0
  811. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/keys.js.map +1 -0
  812. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.d.ts +28 -0
  813. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.d.ts.map +1 -0
  814. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.js +46 -0
  815. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/kill-ring.js.map +1 -0
  816. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.d.ts +10 -0
  817. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.d.ts.map +1 -0
  818. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.js +1268 -0
  819. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/latex.js.map +1 -0
  820. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.d.ts +40 -0
  821. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.d.ts.map +1 -0
  822. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.js +6 -0
  823. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout-node.js.map +1 -0
  824. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.d.ts +42 -0
  825. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.d.ts.map +1 -0
  826. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.js +335 -0
  827. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/layout.js.map +1 -0
  828. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.d.ts +3 -0
  829. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.d.ts.map +1 -0
  830. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.js +60 -0
  831. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/native-modifiers.js.map +1 -0
  832. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.d.ts +56 -0
  833. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.d.ts.map +1 -0
  834. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.js +363 -0
  835. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/stdin-buffer.js.map +1 -0
  836. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.d.ts +10 -0
  837. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.d.ts.map +1 -0
  838. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.js +59 -0
  839. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-colors.js.map +1 -0
  840. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.d.ts +116 -0
  841. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.d.ts.map +1 -0
  842. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.js +518 -0
  843. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal-image.js.map +1 -0
  844. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.d.ts +142 -0
  845. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.d.ts.map +1 -0
  846. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.js +544 -0
  847. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/terminal.js.map +1 -0
  848. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.d.ts +11 -0
  849. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.d.ts.map +1 -0
  850. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.js +11 -0
  851. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/testing.js.map +1 -0
  852. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.d.ts +141 -0
  853. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.d.ts.map +1 -0
  854. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.js +1340 -0
  855. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-alt-screen.js.map +1 -0
  856. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.d.ts +39 -0
  857. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.d.ts.map +1 -0
  858. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.js +536 -0
  859. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui-main-screen.js.map +1 -0
  860. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.d.ts +340 -0
  861. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.d.ts.map +1 -0
  862. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.js +1020 -0
  863. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/tui.js.map +1 -0
  864. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.d.ts +17 -0
  865. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.d.ts.map +1 -0
  866. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.js +27 -0
  867. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/undo-stack.js.map +1 -0
  868. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.d.ts +96 -0
  869. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.d.ts.map +1 -0
  870. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.js +1193 -0
  871. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/utils.js.map +1 -0
  872. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.d.ts +25 -0
  873. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.d.ts.map +1 -0
  874. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.js +96 -0
  875. package/node_modules/@bubblebrain-ai/pi-tui/dist/src/word-navigation.js.map +1 -0
  876. package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.d.ts +73 -0
  877. package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.d.ts.map +1 -0
  878. package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.js +188 -0
  879. package/node_modules/@bubblebrain-ai/pi-tui/dist/test/virtual-terminal.js.map +1 -0
  880. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/README.md +20 -0
  881. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/build.sh +62 -0
  882. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
  883. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
  884. package/node_modules/@bubblebrain-ai/pi-tui/native/darwin/src/darwin-modifiers.c +70 -0
  885. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/README.md +22 -0
  886. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/build.mjs +229 -0
  887. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  888. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  889. package/node_modules/@bubblebrain-ai/pi-tui/native/win32/src/win32-console-mode.c +119 -0
  890. package/node_modules/@bubblebrain-ai/pi-tui/package.json +66 -0
  891. package/node_modules/get-east-asian-width/index.d.ts +60 -0
  892. package/node_modules/get-east-asian-width/index.js +30 -0
  893. package/node_modules/get-east-asian-width/license +9 -0
  894. package/node_modules/get-east-asian-width/lookup-data.js +21 -0
  895. package/node_modules/get-east-asian-width/lookup.js +138 -0
  896. package/node_modules/get-east-asian-width/package.json +71 -0
  897. package/node_modules/get-east-asian-width/readme.md +65 -0
  898. package/node_modules/get-east-asian-width/utilities.js +24 -0
  899. package/node_modules/marked/LICENSE +44 -0
  900. package/node_modules/marked/README.md +115 -0
  901. package/node_modules/marked/bin/main.js +284 -0
  902. package/node_modules/marked/bin/marked.js +16 -0
  903. package/node_modules/marked/lib/marked.d.ts +760 -0
  904. package/node_modules/marked/lib/marked.esm.js +77 -0
  905. package/node_modules/marked/lib/marked.esm.js.map +7 -0
  906. package/node_modules/marked/lib/marked.umd.js +79 -0
  907. package/node_modules/marked/lib/marked.umd.js.map +7 -0
  908. package/node_modules/marked/man/marked.1 +113 -0
  909. package/node_modules/marked/man/marked.1.md +93 -0
  910. package/node_modules/marked/package.json +103 -0
  911. package/package.json +96 -17
  912. package/bin/bubble.js +0 -39
@@ -0,0 +1,1251 @@
1
+ import { UserConfig } from "../config.js";
2
+ import { formatContextUsage } from "../context/usage.js";
3
+ import { formatDiagnostics } from "../lsp/index.js";
4
+ import { normalizeNameForMCP } from "../mcp/name.js";
5
+ import { parseRule } from "../permissions/rule.js";
6
+ import { describeRepoCapabilities } from "../permissions/trust.js";
7
+ import { encodeModel, decodeModel, displayModel, BUILTIN_PROVIDERS, isUserVisibleProvider } from "../provider-registry.js";
8
+ import { getAvailableThinkingLevels, getDefaultThinkingLevel, normalizeThinkingLevel } from "../provider-transform.js";
9
+ import { SessionManager } from "../session.js";
10
+ import { buildSystemPrompt } from "../system-prompt.js";
11
+ import { normalizeSingleLine } from "../text-display.js";
12
+ import { formatRelativeTime } from "../tui/recent-activity.js";
13
+ import { HOOK_EVENT_NAMES, isHookEventName } from "../hooks/index.js";
14
+ import { isThinkingLevel } from "../variant/thinking-level.js";
15
+ import { normalizeInheritedThinkingLevel } from "../variant/variant-resolver.js";
16
+ import { collectUsageStatsBundle, formatStatsText } from "../stats/usage.js";
17
+ import { buildMemoryPrompt, getMemoryStatus, isMemoryDisabled, resetMemory, searchMemory, } from "../memory/index.js";
18
+ import { feishuCommand } from "./feishu.js";
19
+ import { GROK_LOCAL_COMMAND_HELP } from "../external-runtime/grok-input-policy.js";
20
+ import { isGrokSubscriptionProviderId } from "../external-runtime/grok-provider.js";
21
+ import { classifyExternalRuntimeBinding } from "../external-runtime/session-policy.js";
22
+ import { providerModelPolicyError } from "../provider-model-policy.js";
23
+ import { executeRewind } from "../rewind.js";
24
+ const VALID_SCOPES = ["user", "project", "local"];
25
+ const VALID_LISTS = ["allow", "deny"];
26
+ function isAbortLike(error) {
27
+ return error instanceof Error && (error.name === "AbortError" || error.name === "AgentAbortError");
28
+ }
29
+ function formatCompactDuration(elapsedMs) {
30
+ if (elapsedMs < 1_000)
31
+ return `${Math.max(0, Math.round(elapsedMs))}ms`;
32
+ return `${(elapsedMs / 1_000).toFixed(1)}s`;
33
+ }
34
+ function isScope(value) {
35
+ return VALID_SCOPES.includes(value);
36
+ }
37
+ function isList(value) {
38
+ return VALID_LISTS.includes(value);
39
+ }
40
+ async function handleRewindCommand(args, ctx) {
41
+ const session = ctx.sessionManager;
42
+ if (!session)
43
+ return "Rewind requires an active session.";
44
+ const turns = session.listUserTurns();
45
+ if (turns.length === 0)
46
+ return "Nothing to rewind: no user messages in this session.";
47
+ const tokens = args.trim().split(/\s+/).filter(Boolean);
48
+ const flags = tokens.filter((token) => token.startsWith("--"));
49
+ const positional = tokens.filter((token) => !token.startsWith("--"));
50
+ const checkpoints = session.getCheckpoints();
51
+ if (positional.length === 0) {
52
+ if (ctx.openRewindPicker) {
53
+ ctx.openRewindPicker();
54
+ return;
55
+ }
56
+ const lines = ["Rewind points (oldest first):", ""];
57
+ turns.forEach((turn, index) => {
58
+ const time = new Date(turn.timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
59
+ const files = checkpoints.filesTouchedAt(turn.id).length;
60
+ const fileNote = files > 0 ? ` [${files} file${files === 1 ? "" : "s"} changed]` : "";
61
+ lines.push(` ${index + 1}. ${time} ${turn.preview}${fileNote}`);
62
+ });
63
+ lines.push("", "Usage:", " /rewind <n> restore conversation AND files to just before message n", " /rewind <n> --chat conversation only", " /rewind <n> --code files only", "", "Note: only edits made by the edit/write tools are tracked; changes from", "bash commands are not. Checkpoints complement git, they don't replace it.");
64
+ return lines.join("\n");
65
+ }
66
+ const n = Number(positional[0]);
67
+ if (!Number.isInteger(n) || n < 1 || n > turns.length) {
68
+ return `Invalid rewind point "${positional[0]}". Run /rewind to list points (1-${turns.length}).`;
69
+ }
70
+ const target = turns[n - 1];
71
+ const codeOnly = flags.includes("--code");
72
+ const chatOnly = flags.includes("--chat") || flags.includes("--conversation");
73
+ if (codeOnly && chatOnly)
74
+ return "Pick at most one of --code / --chat.";
75
+ const scope = codeOnly ? "code" : chatOnly ? "chat" : "all";
76
+ const result = await executeRewind(session, ctx.agent, target.id, scope);
77
+ const lines = [
78
+ codeOnly
79
+ ? `Files restored to just before: ${target.preview}`
80
+ : `⏪ Rewound to before: ${target.preview}`,
81
+ ];
82
+ if (scope !== "chat") {
83
+ const touched = result.files.restored.length + result.files.deleted.length;
84
+ if (touched === 0 && result.files.failed.length === 0) {
85
+ lines.push("Files: no tracked edits to undo.");
86
+ }
87
+ else {
88
+ for (const file of result.files.restored)
89
+ lines.push(`Restored ${file}`);
90
+ for (const file of result.files.deleted)
91
+ lines.push(`Deleted ${file} (created after this point)`);
92
+ for (const file of result.files.failed)
93
+ lines.push(`FAILED to restore ${file}`);
94
+ }
95
+ }
96
+ if (scope !== "code") {
97
+ ctx.rebuildTranscript?.();
98
+ if (ctx.fillComposer)
99
+ ctx.fillComposer(target.text);
100
+ else
101
+ lines.push("", "Rewound message (copy to re-edit):", target.text);
102
+ }
103
+ return lines.join("\n");
104
+ }
105
+ function handlePermissionsMutation(sub, tokens, ctx) {
106
+ if (!ctx.settingsManager) {
107
+ return "No settings manager is attached to this session.";
108
+ }
109
+ const [scope, list, ...ruleParts] = tokens;
110
+ if (!scope || !list || ruleParts.length === 0) {
111
+ return `Usage: /permissions ${sub} <user|project|local> <allow|deny> <rule>\n`
112
+ + `Example: /permissions ${sub} local allow Bash(git status)`;
113
+ }
114
+ if (!isScope(scope)) {
115
+ return `Unknown scope "${scope}". Use one of: ${VALID_SCOPES.join(", ")}.`;
116
+ }
117
+ if (!isList(list)) {
118
+ return `Unknown list "${list}". Use allow or deny.`;
119
+ }
120
+ const rule = ruleParts.join(" ");
121
+ const parsed = parseRule(rule);
122
+ if (!parsed.ok) {
123
+ return `Invalid rule: ${parsed.error.message}`;
124
+ }
125
+ if (sub === "add") {
126
+ const added = ctx.settingsManager.addRule(scope, list, rule);
127
+ if (!added)
128
+ return `Rule already present in ${scope} ${list}: ${rule}`;
129
+ return `Added to ${scope} ${list}: ${rule}\n → ${ctx.settingsManager.getPath(scope)}`;
130
+ }
131
+ const removed = ctx.settingsManager.removeRule(scope, list, rule);
132
+ if (!removed)
133
+ return `Rule not found in ${scope} ${list}: ${rule}`;
134
+ return `Removed from ${scope} ${list}: ${rule}`;
135
+ }
136
+ async function handleHooksCommand(args, ctx) {
137
+ const hooks = ctx.hookController;
138
+ if (!hooks)
139
+ return "Hooks controller is not attached to this session.";
140
+ const tokens = args.trim().split(/\s+/).filter(Boolean);
141
+ const sub = tokens[0] ?? "status";
142
+ if (sub === "status" || sub === "list" || sub === "") {
143
+ return hooks.status();
144
+ }
145
+ if (sub === "reload") {
146
+ hooks.reload();
147
+ return `Reloaded hooks.\n\n${hooks.status()}`;
148
+ }
149
+ if (sub === "trust" && tokens[1] === "project") {
150
+ return hooks.trustProject();
151
+ }
152
+ if (sub === "untrust" && tokens[1] === "project") {
153
+ return hooks.untrustProject();
154
+ }
155
+ if (sub === "test") {
156
+ const event = tokens[1];
157
+ if (!isHookEventName(event)) {
158
+ return `Usage: /hooks test <event> [target]\nEvents: ${HOOK_EVENT_NAMES.join(", ")}`;
159
+ }
160
+ return hooks.test(event, tokens.slice(2).join(" ") || undefined);
161
+ }
162
+ if (sub === "explain") {
163
+ const event = tokens[1];
164
+ if (!isHookEventName(event)) {
165
+ return `Usage: /hooks explain <event>\nEvents: ${HOOK_EVENT_NAMES.join(", ")}`;
166
+ }
167
+ return hooks.explain(event);
168
+ }
169
+ if (sub === "logs") {
170
+ const limit = Number(tokens[1] ?? 20);
171
+ return hooks.logs(Number.isFinite(limit) ? limit : 20);
172
+ }
173
+ return "Usage: /hooks [status|reload|trust project|untrust project|test <event> [target]|explain <event>|logs [limit]]";
174
+ }
175
+ function persistSelectedModel(model, ctx) {
176
+ const userConfig = new UserConfig();
177
+ userConfig.setDefaultModel(model);
178
+ userConfig.setDefaultThinkingLevel(ctx.agent.thinking);
179
+ userConfig.pushRecentModel(model);
180
+ if (ctx.sessionManager) {
181
+ ctx.sessionManager.updateMetadata({ model, thinkingLevel: ctx.agent.thinking, reasoningEffort: ctx.agent.thinking });
182
+ ctx.sessionManager.appendMarker("model_switch", model);
183
+ }
184
+ }
185
+ /** Rebuild the system prompt from the agent's live options (model, tools, memory, Skills catalog). */
186
+ export function syncSystemPrompt(ctx, model) {
187
+ const { providerId } = decodeModel(model);
188
+ const toolPromptOptions = typeof ctx.agent.getSystemPromptToolOptions === "function"
189
+ ? ctx.agent.getSystemPromptToolOptions()
190
+ : {};
191
+ ctx.agent.setSystemPrompt(buildSystemPrompt({
192
+ agentName: "Bubble",
193
+ // Same placeholders as startup when no model is configured yet.
194
+ configuredProvider: providerId || "none",
195
+ configuredModel: model ? displayModel(model) : "none",
196
+ configuredModelId: model || "none",
197
+ thinkingLevel: ctx.agent.thinking,
198
+ workingDir: ctx.cwd,
199
+ ...toolPromptOptions,
200
+ memoryPrompt: buildMemoryPrompt(ctx.cwd),
201
+ }));
202
+ }
203
+ function formatMcpContextStatus(ctx) {
204
+ const states = ctx.mcpManager?.getStates() ?? [];
205
+ const lines = ["MCP"];
206
+ if (!ctx.mcpManager || states.length === 0) {
207
+ lines.push("- No MCP servers configured for this session.");
208
+ lines.push("- Context impact: none.");
209
+ return lines.join("\n");
210
+ }
211
+ for (const state of states) {
212
+ if (state.status.kind === "connected") {
213
+ lines.push(`- ${state.name} (${state.scope}): connected · ${state.status.tools.length} deferred tool${state.status.tools.length === 1 ? "" : "s"} · ${state.status.prompts.length} prompt${state.status.prompts.length === 1 ? "" : "s"}`);
214
+ continue;
215
+ }
216
+ if (state.status.kind === "failed") {
217
+ lines.push(`- ${state.name} (${state.scope}): failed · ${state.status.error}`);
218
+ continue;
219
+ }
220
+ lines.push(`- ${state.name} (${state.scope}): ${state.status.kind}`);
221
+ }
222
+ lines.push("- Context impact: MCP tool schemas are deferred. The prompt pays only a small deferred-tool reminder until tool_search unlocks a tool; unlocked MCP schemas then count under Tools.");
223
+ lines.push("- MCP prompts are slash commands; they do not enter context until invoked.");
224
+ return lines.join("\n");
225
+ }
226
+ function switchToProviderModel(providerId, modelId, ctx, thinkingLevel, preparedProvider) {
227
+ const provider = ctx.registry.getConfigured().find((item) => item.id === providerId);
228
+ if (!provider?.apiKey) {
229
+ return false;
230
+ }
231
+ ctx.agent.thinking = thinkingLevel !== undefined
232
+ ? normalizeThinkingLevel(thinkingLevel, getAvailableThinkingLevels(providerId, modelId))
233
+ : normalizeInheritedThinkingLevel(providerId, modelId, ctx.agent.thinking);
234
+ ctx.agent.setProvider(preparedProvider ?? ctx.createProvider(providerId, provider.apiKey, provider.baseURL));
235
+ ctx.agent.providerId = providerId;
236
+ ctx.agent.model = encodeModel(providerId, modelId);
237
+ syncSystemPrompt(ctx, ctx.agent.model);
238
+ persistSelectedModel(ctx.agent.model, ctx);
239
+ return true;
240
+ }
241
+ function parseModelArgs(args) {
242
+ const tokens = args.trim().split(/\s+/).filter(Boolean);
243
+ let model;
244
+ let thinkingLevel;
245
+ for (let index = 0; index < tokens.length; index++) {
246
+ const token = tokens[index];
247
+ if (token === "--reasoning-effort" || token === "--thinking") {
248
+ const value = tokens[++index];
249
+ if (!isThinkingLevel(value)) {
250
+ return { error: `Invalid reasoning effort "${value ?? ""}".` };
251
+ }
252
+ thinkingLevel = value;
253
+ continue;
254
+ }
255
+ if (!model) {
256
+ model = token;
257
+ continue;
258
+ }
259
+ return { error: `Unexpected model argument "${token}".` };
260
+ }
261
+ return { model, thinkingLevel };
262
+ }
263
+ function displaySelectedModel(model, thinkingLevel) {
264
+ const label = displayModel(model);
265
+ const { providerId, modelId } = decodeModel(model);
266
+ const defaultLevel = providerId ? getDefaultThinkingLevel(providerId, modelId) : "off";
267
+ return thinkingLevel === "off" || thinkingLevel === defaultLevel ? label : `${label} (${thinkingLevel})`;
268
+ }
269
+ function getGrokSessionId(ctx) {
270
+ const binding = ctx.sessionManager?.getMetadata().externalRuntime;
271
+ return binding && isGrokSubscriptionProviderId(binding.id) ? binding.sessionId : undefined;
272
+ }
273
+ function isGrokSessionActive(ctx) {
274
+ return classifyExternalRuntimeBinding(ctx.sessionManager?.getMetadata().externalRuntime) === "grok";
275
+ }
276
+ function hasExternalRuntimeSession(ctx) {
277
+ return classifyExternalRuntimeBinding(ctx.sessionManager?.getMetadata().externalRuntime) !== "none";
278
+ }
279
+ async function transitionGrokSessionToNative(ctx) {
280
+ if (!hasExternalRuntimeSession(ctx))
281
+ return;
282
+ if (!ctx.transitionToNative) {
283
+ throw new Error("Switching from Grok subscription to a native Bubble session is unavailable in this mode.");
284
+ }
285
+ const next = await ctx.transitionToNative();
286
+ if (!next) {
287
+ throw new Error("Bubble could not start a fresh native session.");
288
+ }
289
+ // Handlers below may persist provider/model metadata after the transition.
290
+ // Keep those writes on the new native session rather than the old Grok log.
291
+ ctx.sessionManager = next;
292
+ }
293
+ /**
294
+ * Sign in to the Grok subscription as a native model provider (like ChatGPT
295
+ * OAuth): browser PKCE against auth.x.ai, tokens in ~/.bubble/auth.json, and
296
+ * grok models served through Bubble's own agent loop. An existing Grok CLI
297
+ * login is imported so users who already ran `grok login` skip the browser.
298
+ */
299
+ async function loginGrokSubscription(ctx) {
300
+ const providerId = "grok";
301
+ const { loginGrok, importGrokCliCredentials } = await import("../oauth/grok.js");
302
+ const storage = ctx.registry.getAuthStorage();
303
+ const runBrowserLogin = async () => {
304
+ const tokens = await loginGrok({
305
+ onStatus: (msg) => ctx.addMessage("assistant", msg),
306
+ });
307
+ storage.set(providerId, {
308
+ type: "oauth",
309
+ accessToken: tokens.accessToken,
310
+ refreshToken: tokens.refreshToken,
311
+ expiresAt: tokens.expiresAt,
312
+ });
313
+ };
314
+ let importedExisting = false;
315
+ if (!storage.has(providerId)) {
316
+ const imported = importGrokCliCredentials();
317
+ if (imported) {
318
+ storage.set(providerId, {
319
+ type: "oauth",
320
+ accessToken: imported.accessToken,
321
+ refreshToken: imported.refreshToken,
322
+ expiresAt: imported.expiresAt,
323
+ });
324
+ importedExisting = true;
325
+ ctx.addMessage("assistant", "Imported the existing Grok CLI sign-in.");
326
+ }
327
+ }
328
+ const hadStoredLogin = storage.has(providerId);
329
+ if (!hadStoredLogin) {
330
+ await runBrowserLogin();
331
+ }
332
+ try {
333
+ await ctx.registry.prepareProvider(providerId);
334
+ }
335
+ catch (error) {
336
+ // Stored/imported credentials whose refresh token was revoked get exactly
337
+ // one browser repair attempt; a failure right after browser login is real.
338
+ if (!hadStoredLogin)
339
+ throw error;
340
+ ctx.addMessage("assistant", `Stored Grok credentials could not be refreshed (${error instanceof Error ? error.message : String(error)}). Signing in again…`);
341
+ storage.remove(providerId);
342
+ await runBrowserLogin();
343
+ await ctx.registry.prepareProvider(providerId);
344
+ }
345
+ const provider = ctx.registry.getConfigured().find((item) => item.id === providerId);
346
+ const defaultModel = ctx.registry.getDefaultModel(providerId, "oauth");
347
+ if (!provider?.apiKey || !defaultModel) {
348
+ return `Grok subscription login succeeded, but the provider could not be activated. Tokens saved to ${storage.getPath()}`;
349
+ }
350
+ // Complete every fallible preparation step before leaving a legacy
351
+ // Grok-runtime session; commit only after the native switch succeeds.
352
+ const preparedProvider = ctx.createProvider(providerId, provider.apiKey, provider.baseURL);
353
+ await transitionGrokSessionToNative(ctx);
354
+ const switched = switchToProviderModel(providerId, defaultModel, ctx, undefined, preparedProvider);
355
+ if (!switched) {
356
+ return `Grok subscription login succeeded, but the provider could not be activated. Tokens saved to ${storage.getPath()}`;
357
+ }
358
+ ctx.registry.setDefault(providerId);
359
+ const via = importedExisting ? " (reused your Grok CLI sign-in)" : "";
360
+ return `Grok subscription login successful${via}. Switched to ${displayModel(ctx.agent.model)}. Tokens saved to ${storage.getPath()}`;
361
+ }
362
+ async function logoutGrokSubscription(ctx) {
363
+ const storage = ctx.registry.getAuthStorage();
364
+ const hadNativeLogin = storage.has("grok");
365
+ storage.remove("grok");
366
+ // Legacy cleanup: sessions bound to the old Grok ACP runtime, and the
367
+ // isolated CLI profile's credentials.
368
+ if (isGrokSessionActive(ctx) && ctx.externalRuntime && ctx.startFreshSession) {
369
+ await ctx.externalRuntime.cancel(getGrokSessionId(ctx)).catch(() => undefined);
370
+ await ctx.externalRuntime.dispose().catch(() => undefined);
371
+ await ctx.externalRuntime.logout().catch(() => undefined);
372
+ const freshSession = await ctx.startFreshSession();
373
+ freshSession.clearExternalRuntimeMetadata();
374
+ freshSession.appendMarker("runtime_switch", "native");
375
+ ctx.sessionManager = freshSession;
376
+ ctx.onExternalRuntimeChange?.(freshSession);
377
+ return "Grok subscription logged out. Started a fresh native Bubble session.";
378
+ }
379
+ await ctx.externalRuntime?.logout().catch(() => undefined);
380
+ if (!hadNativeLogin) {
381
+ return "No Grok subscription login was stored on this device.";
382
+ }
383
+ return "Grok subscription logged out. Only this device's local login was removed.";
384
+ }
385
+ function parseMemoryScopeArgs(args) {
386
+ const tokens = args.trim().split(/\s+/).filter(Boolean);
387
+ let scope = "project";
388
+ const rest = [];
389
+ for (const token of tokens) {
390
+ if (token === "--global") {
391
+ scope = "global";
392
+ continue;
393
+ }
394
+ if (token === "--project") {
395
+ scope = "project";
396
+ continue;
397
+ }
398
+ rest.push(token);
399
+ }
400
+ return { scope, rest: rest.join(" ") };
401
+ }
402
+ async function handleMemoryCommand(args, ctx) {
403
+ const trimmed = args.trim();
404
+ const [sub = "status", ...rest] = trimmed.split(/\s+/);
405
+ if (!trimmed || sub === "status") {
406
+ const status = getMemoryStatus(ctx.cwd);
407
+ const lines = [
408
+ "Memory status:",
409
+ ` environment: ${status.environment}`,
410
+ ` bubble home: ${status.bubbleHome}`,
411
+ ` project root: ${status.paths.projectRoot}`,
412
+ ` global root: ${status.paths.globalRoot}`,
413
+ ` startup pipeline: ${isMemoryDisabled() ? "disabled" : "enabled"}`,
414
+ "",
415
+ "Files:",
416
+ ];
417
+ for (const file of status.files) {
418
+ lines.push(` ${file.exists ? "present" : "missing"} ${file.label} (${file.bytes} bytes)`);
419
+ lines.push(` ${file.path}`);
420
+ }
421
+ lines.push("", "SQLite state:");
422
+ lines.push(` path: ${status.database.path}`);
423
+ lines.push(` stage1Outputs: ${status.database.stage1Outputs}`);
424
+ lines.push(` disabledThreads: ${status.database.disabledThreads}`);
425
+ for (const job of status.database.jobs) {
426
+ lines.push(` job ${job.kind}/${job.jobKey}: ${job.status}`);
427
+ if (job.lastError)
428
+ lines.push(` lastError: ${job.lastError}`);
429
+ }
430
+ return lines.join("\n");
431
+ }
432
+ if (sub === "add") {
433
+ return "Manual memory writes are disabled. Bubble now follows the automatic startup memory pipeline.";
434
+ }
435
+ if (sub === "search") {
436
+ const query = rest.join(" ").trim();
437
+ if (!query) {
438
+ return "Usage: /memory search <query>";
439
+ }
440
+ const results = searchMemory(ctx.cwd, query);
441
+ if (results.length === 0) {
442
+ return `No memory matches for "${query}".`;
443
+ }
444
+ const lines = [`Memory search results for "${query}":`];
445
+ for (const result of results) {
446
+ lines.push(` ${result.scope} ${result.path}:${result.line}`);
447
+ lines.push(` ${result.text}`);
448
+ }
449
+ return lines.join("\n");
450
+ }
451
+ if (sub === "compact") {
452
+ if (!ctx.runMemoryCompaction) {
453
+ return "Memory compaction is not attached to this session.";
454
+ }
455
+ return await ctx.runMemoryCompaction();
456
+ }
457
+ if (sub === "summarize") {
458
+ if (!ctx.runMemorySummary) {
459
+ return "Memory summary is not attached to this session.";
460
+ }
461
+ const parsed = parseMemoryScopeArgs(rest.join(" "));
462
+ if (parsed.rest)
463
+ return "Usage: /memory summarize [--project|--global]";
464
+ const result = await ctx.runMemorySummary(parsed.scope);
465
+ if (ctx.agent.model)
466
+ syncSystemPrompt(ctx, ctx.agent.model);
467
+ return result;
468
+ }
469
+ if (sub === "refresh") {
470
+ if (!ctx.runMemoryRefresh) {
471
+ return "Memory refresh is not attached to this session.";
472
+ }
473
+ const parsed = parseMemoryScopeArgs(rest.join(" "));
474
+ if (parsed.rest)
475
+ return "Usage: /memory refresh [--project|--global]";
476
+ const result = await ctx.runMemoryRefresh(parsed.scope);
477
+ if (ctx.agent.model)
478
+ syncSystemPrompt(ctx, ctx.agent.model);
479
+ return result;
480
+ }
481
+ if (sub === "reset") {
482
+ const result = resetMemory(ctx.cwd);
483
+ if (ctx.agent.model)
484
+ syncSystemPrompt(ctx, ctx.agent.model);
485
+ return result;
486
+ }
487
+ return "Usage: /memory [status|search|compact|summarize|refresh|reset]";
488
+ }
489
+ const builtinSlashCommandEntries = [
490
+ {
491
+ name: "skills",
492
+ description: "Open the searchable skills picker",
493
+ async handler(_args, ctx) {
494
+ ctx.openPicker("skill");
495
+ },
496
+ },
497
+ {
498
+ name: "help",
499
+ description: "Show available slash commands",
500
+ async handler(_args, ctx) {
501
+ if (hasExternalRuntimeSession(ctx)) {
502
+ const grok = isGrokSessionActive(ctx);
503
+ return [
504
+ grok
505
+ ? "Grok Subscription · workspace tools · Bubble approvals"
506
+ : "Unsupported external runtime session · recovery-only mode",
507
+ "Available commands:",
508
+ ...GROK_LOCAL_COMMAND_HELP.map((command) => (` ${command.usage} - ${command.description}`)),
509
+ ].join("\n");
510
+ }
511
+ const { registry } = await import("./index.js");
512
+ const lines = ["Available commands:"];
513
+ for (const cmd of registry.list()) {
514
+ lines.push(` /${cmd.name} - ${cmd.description}`);
515
+ }
516
+ return lines.join("\n");
517
+ },
518
+ },
519
+ {
520
+ name: "memory",
521
+ description: "Inspect and maintain Bubble's automatic persistent memory. Usage: /memory [status|search|compact|summarize|refresh|reset]",
522
+ async handler(args, ctx) {
523
+ return handleMemoryCommand(args, ctx);
524
+ },
525
+ },
526
+ {
527
+ name: "context",
528
+ description: "Show current context window usage and breakdown",
529
+ async handler(_args, ctx) {
530
+ const snapshot = ctx.agent.getContextUsageSnapshot();
531
+ if (ctx.openContextInfo) {
532
+ ctx.openContextInfo(snapshot);
533
+ return;
534
+ }
535
+ return `${formatContextUsage(snapshot)}\n\n${formatMcpContextStatus(ctx)}`;
536
+ },
537
+ },
538
+ {
539
+ name: "quit",
540
+ description: "Exit the application",
541
+ async handler(_args, ctx) {
542
+ ctx.exit();
543
+ },
544
+ },
545
+ {
546
+ name: "theme",
547
+ description: "Pick the color theme. Usage: /theme [auto|light|dark]",
548
+ async handler(args, ctx) {
549
+ if (!ctx.setThemeMode || !ctx.getThemeMode || !ctx.getResolvedTheme) {
550
+ return "Theme switching is only available inside the TUI.";
551
+ }
552
+ const arg = args.trim().toLowerCase();
553
+ if (!arg) {
554
+ ctx.openPicker("theme");
555
+ return;
556
+ }
557
+ if (arg !== "auto" && arg !== "light" && arg !== "dark") {
558
+ return "Usage: /theme [auto|light|dark]";
559
+ }
560
+ ctx.setThemeMode(arg);
561
+ const resolved = arg === "auto" ? ctx.getResolvedTheme() : arg;
562
+ return `Theme set to ${arg}${arg === "auto" ? ` (resolved to ${resolved})` : ""}.`;
563
+ },
564
+ },
565
+ {
566
+ name: "clear",
567
+ description: "Clear the current conversation history",
568
+ async handler(_args, ctx) {
569
+ ctx.agent.messages = ctx.agent.messages.filter((m) => m.role === "system" || m.role === "meta");
570
+ // The resident history just shrank: drop the incremental usage anchor
571
+ // too (same as /compact and /rewind), or budget accounting keeps
572
+ // measuring against the pre-clear message count.
573
+ ctx.agent.resetContextUsageAnchor();
574
+ ctx.sessionManager?.appendMarker("conversation_clear", "");
575
+ ctx.sessionManager?.clearTitleMetadata?.();
576
+ ctx.clearMessages();
577
+ },
578
+ },
579
+ {
580
+ name: "rewind",
581
+ description: "Rewind conversation and/or file edits to before an earlier message. Usage: /rewind [n] [--code|--chat]",
582
+ handler: handleRewindCommand,
583
+ },
584
+ {
585
+ name: "undo",
586
+ description: "Alias for /rewind",
587
+ handler: handleRewindCommand,
588
+ },
589
+ {
590
+ name: "session",
591
+ description: "Browse recent sessions and resume one. /session to pick, /session --list to print",
592
+ async handler(args, ctx) {
593
+ const flag = args.trim();
594
+ if (flag && flag !== "--list") {
595
+ return "Usage: /session (open the session picker) or /session --list";
596
+ }
597
+ if (!flag && ctx.openSessionPicker) {
598
+ ctx.openSessionPicker();
599
+ return;
600
+ }
601
+ const summaries = SessionManager.summarizeSessionsForCwd(ctx.cwd);
602
+ if (summaries.length === 0) {
603
+ return "No sessions recorded for this project yet.";
604
+ }
605
+ const activeFile = ctx.sessionManager?.getSessionFile();
606
+ const lines = ["Recent sessions:"];
607
+ for (const summary of summaries.slice(0, 15)) {
608
+ const current = summary.file === activeFile ? " (current)" : "";
609
+ const title = normalizeSingleLine(summary.title || summary.preview || summary.name);
610
+ const count = `${summary.messageCount} message${summary.messageCount === 1 ? "" : "s"}`;
611
+ lines.push(`- ${title} — ${count}, ${formatRelativeTime(summary.mtime)} (${summary.name})${current}`);
612
+ }
613
+ if (summaries.length > 15) {
614
+ lines.push(`- … and ${summaries.length - 15} more`);
615
+ }
616
+ lines.push("", "Resume one with: bubble --resume --session <name>");
617
+ return lines.join("\n");
618
+ },
619
+ },
620
+ {
621
+ name: "provider",
622
+ description: "Manage providers. /provider to switch, /provider --add [id] to add, /provider --remove <id>, /provider --set <id>",
623
+ async handler(args, ctx) {
624
+ const trimmed = args.trim();
625
+ if (!trimmed) {
626
+ ctx.openPicker("provider");
627
+ return;
628
+ }
629
+ const parts = trimmed.split(/\s+/);
630
+ const flag = parts[0];
631
+ const value = parts[1];
632
+ if (flag === "--add") {
633
+ if (!value) {
634
+ ctx.openPicker("provider-add");
635
+ return;
636
+ }
637
+ if (isGrokSubscriptionProviderId(value)) {
638
+ return "Grok Subscription is built in. Use /provider --set grok or /login grok to activate it.";
639
+ }
640
+ const builtin = BUILTIN_PROVIDERS.find((p) => p.id === value && isUserVisibleProvider(p.id));
641
+ if (!builtin) {
642
+ const ids = BUILTIN_PROVIDERS.filter((p) => isUserVisibleProvider(p.id)).map((p) => p.id).join(", ");
643
+ return `Unknown provider "${value}". Supported: ${ids}`;
644
+ }
645
+ ctx.registry.addProvider(value, "");
646
+ ctx.registry.setDefault(value);
647
+ ctx.openPicker("key", value);
648
+ return;
649
+ }
650
+ if (flag === "--remove" && value) {
651
+ if (isGrokSubscriptionProviderId(value)) {
652
+ return "Grok Subscription is built in and cannot be removed. Use /logout grok to remove its local login.";
653
+ }
654
+ if (ctx.registry.getModelConfig().hasProvider(value)) {
655
+ return `Provider ${value} is defined in ~/.bubble/models.json. Please edit that file directly.`;
656
+ }
657
+ ctx.registry.removeProvider(value);
658
+ // Registry mutation without a model switch still changes the routing
659
+ // world (design §1.6): refresh the routing menu in the system prompt.
660
+ syncSystemPrompt(ctx, ctx.agent.model);
661
+ return `Provider ${value} removed.`;
662
+ }
663
+ if (flag === "--set" && value) {
664
+ if (isGrokSubscriptionProviderId(value)) {
665
+ return loginGrokSubscription(ctx);
666
+ }
667
+ const providers = ctx.registry.getConfigured();
668
+ const p = providers.find((x) => x.id === value);
669
+ if (!p)
670
+ return `Provider ${value} is not configured.`;
671
+ await transitionGrokSessionToNative(ctx);
672
+ ctx.registry.setDefault(value);
673
+ if (ctx.registry.getModelConfig().hasProvider(value)) {
674
+ return `Default provider set to ${p.name}. Note: config is managed via ~/.bubble/models.json.`;
675
+ }
676
+ return `Default provider set to ${p.name}.`;
677
+ }
678
+ if (flag === "--list") {
679
+ const providers = ctx.registry.getConfigured();
680
+ const grokActive = isGrokSessionActive(ctx);
681
+ const lines = ["Available providers:"];
682
+ for (const p of providers) {
683
+ const marker = !grokActive && p.id === ctx.registry.getDefault()?.id ? "* " : " ";
684
+ const source = ctx.registry.getModelConfig().hasProvider(p.id) ? " [models.json]" : "";
685
+ const oauth = ctx.registry.getAuthStorage().has(p.id) ? " [oauth]" : "";
686
+ lines.push(`${marker}${p.name} (${p.id}) ${p.enabled ? "" : "[disabled]"}${oauth}${source}`);
687
+ }
688
+ if (!providers.some((provider) => provider.id === "grok")) {
689
+ lines.push(`${grokActive ? "* " : " "}Grok Subscription (grok) [not signed in — /login grok]`);
690
+ }
691
+ if (ctx.registry.getModelConfig().getLoadError()) {
692
+ lines.push(`Warning: failed to load models.json: ${ctx.registry.getModelConfig().getLoadError()}`);
693
+ }
694
+ return lines.join("\n");
695
+ }
696
+ return `Usage: /provider [--add|--remove|--set|--list] <id>`;
697
+ },
698
+ },
699
+ {
700
+ name: "login",
701
+ description: "Login to OpenAI OAuth or Grok Subscription. Usage: /login [openai|grok]",
702
+ async handler(args, ctx) {
703
+ // No default provider: a bare command must ask which account, never
704
+ // silently act on OpenAI now that more than one OAuth provider exists.
705
+ const providerId = args?.trim();
706
+ if (!providerId) {
707
+ ctx.openPicker("login");
708
+ return;
709
+ }
710
+ if (isGrokSubscriptionProviderId(providerId)) {
711
+ return loginGrokSubscription(ctx);
712
+ }
713
+ if (!ctx.registry.supportsOAuth(providerId)) {
714
+ return `Unsupported login provider: ${providerId}. Supported providers: 'openai' and 'grok'.`;
715
+ }
716
+ const { loginOpenAICodex } = await import("../oauth/openai-codex.js");
717
+ const tokens = await loginOpenAICodex({
718
+ onStatus: (msg) => ctx.addMessage("assistant", msg),
719
+ });
720
+ ctx.registry.getAuthStorage().set(providerId, {
721
+ type: "oauth",
722
+ accessToken: tokens.accessToken,
723
+ refreshToken: tokens.refreshToken,
724
+ expiresAt: tokens.expiresAt,
725
+ idToken: tokens.idToken,
726
+ accountId: tokens.accountId,
727
+ });
728
+ await ctx.registry.prepareProvider(providerId);
729
+ const provider = ctx.registry.getConfigured().find((item) => item.id === providerId);
730
+ const discoveredModels = provider ? await ctx.registry.listModels(provider) : [];
731
+ const defaultModel = discoveredModels[0]?.id || ctx.registry.getDefaultModel(providerId, "oauth");
732
+ if (!defaultModel) {
733
+ return `OpenAI Codex OAuth login succeeded, but no default model is configured for ${providerId}.`;
734
+ }
735
+ if (!provider?.apiKey) {
736
+ return `OpenAI Codex OAuth login succeeded, but the provider could not be activated. Tokens saved to ${ctx.registry.getAuthStorage().getPath()}`;
737
+ }
738
+ // Complete every fallible OAuth/provider/model preparation step before
739
+ // leaving a Grok-bound session. The provider object is created once and
740
+ // committed only after the fresh native session switch succeeds.
741
+ const preparedProvider = ctx.createProvider(providerId, provider.apiKey, provider.baseURL);
742
+ await transitionGrokSessionToNative(ctx);
743
+ const switched = switchToProviderModel(providerId, defaultModel, ctx, undefined, preparedProvider);
744
+ if (!switched) {
745
+ return `OpenAI Codex OAuth login succeeded, but the provider could not be activated. Tokens saved to ${ctx.registry.getAuthStorage().getPath()}`;
746
+ }
747
+ ctx.registry.setDefault(providerId);
748
+ return `OpenAI Codex OAuth login successful. Switched to ${displayModel(ctx.agent.model)}. Account: ${tokens.accountId || "unknown"}. Tokens saved to ${ctx.registry.getAuthStorage().getPath()}`;
749
+ },
750
+ },
751
+ {
752
+ name: "model",
753
+ description: "Switch model. Use /model <id> [--reasoning-effort <level>] or just /model to open picker.",
754
+ async handler(args, ctx) {
755
+ if (!args) {
756
+ if (hasExternalRuntimeSession(ctx)) {
757
+ if (isGrokSessionActive(ctx)) {
758
+ ctx.openPicker("model");
759
+ return;
760
+ }
761
+ return "This external runtime manages its model and reasoning settings. Bubble's model picker is unavailable until you switch to a native session.";
762
+ }
763
+ if (ctx.registry.getEnabled().length === 0) {
764
+ ctx.openPicker("model");
765
+ return;
766
+ }
767
+ ctx.openPicker("model");
768
+ return;
769
+ }
770
+ const parsed = parseModelArgs(args);
771
+ if (parsed.error) {
772
+ return parsed.error;
773
+ }
774
+ if (!parsed.model) {
775
+ if (hasExternalRuntimeSession(ctx)) {
776
+ if (isGrokSessionActive(ctx)) {
777
+ ctx.openPicker("model");
778
+ return;
779
+ }
780
+ return "This external runtime manages its model and reasoning settings. Bubble's model picker is unavailable until you switch to a native session.";
781
+ }
782
+ ctx.openPicker("model");
783
+ return;
784
+ }
785
+ const explicitModelProvider = parsed.model.includes(":") ? parsed.model.split(":", 1)[0] : undefined;
786
+ if (isGrokSessionActive(ctx) && (!explicitModelProvider || isGrokSubscriptionProviderId(explicitModelProvider))) {
787
+ if (!ctx.externalRuntime)
788
+ return "Grok Subscription runtime is unavailable.";
789
+ const boundSessionId = getGrokSessionId(ctx);
790
+ if (boundSessionId)
791
+ await ctx.externalRuntime.hydrateSession(boundSessionId);
792
+ const requestedModel = parsed.model.includes(":")
793
+ ? parsed.model.split(":").slice(1).join(":")
794
+ : parsed.model;
795
+ const selection = await ctx.externalRuntime.setModel(requestedModel, parsed.thinkingLevel);
796
+ const metadata = ctx.sessionManager?.getMetadata().externalRuntime;
797
+ if (metadata && isGrokSubscriptionProviderId(metadata.id)) {
798
+ ctx.sessionManager?.updateMetadata({
799
+ externalRuntime: {
800
+ ...metadata,
801
+ modelId: selection.modelId,
802
+ reasoningEffort: selection.reasoningEffort,
803
+ },
804
+ });
805
+ }
806
+ ctx.sessionManager?.appendMarker("model_switch", selection.modelId ?? requestedModel);
807
+ ctx.sessionManager?.appendMarker("thinking_level_switch", selection.reasoningEffort);
808
+ ctx.onExternalRuntimeChange?.(ctx.sessionManager);
809
+ return `Grok model switched to ${selection.modelId ?? requestedModel}${selection.reasoningEffort !== "off" ? ` (${selection.reasoningEffort})` : ""}.`;
810
+ }
811
+ const defaultProvider = ctx.registry.getDefault()?.id || "openai";
812
+ const next = parsed.model.includes(":") ? parsed.model : encodeModel(defaultProvider, parsed.model);
813
+ const { providerId, modelId } = decodeModel(next);
814
+ const targetProviderId = providerId || defaultProvider;
815
+ const modelPolicyError = providerModelPolicyError(targetProviderId, modelId);
816
+ if (modelPolicyError)
817
+ return modelPolicyError;
818
+ await ctx.registry.prepareProvider(targetProviderId);
819
+ const targetProvider = ctx.registry.getConfigured().find((item) => item.id === targetProviderId);
820
+ if (!targetProvider?.apiKey) {
821
+ return `Provider ${targetProviderId} is not configured or has no active credentials.`;
822
+ }
823
+ const preparedProvider = ctx.createProvider(targetProviderId, targetProvider.apiKey, targetProvider.baseURL);
824
+ await transitionGrokSessionToNative(ctx);
825
+ switchToProviderModel(targetProviderId, modelId, ctx, parsed.thinkingLevel, preparedProvider);
826
+ return `Model switched to ${displaySelectedModel(next, ctx.agent.thinking)}.`;
827
+ },
828
+ },
829
+ {
830
+ name: "logout",
831
+ description: "Remove local login credentials. Usage: /logout [openai|grok]",
832
+ async handler(args, ctx) {
833
+ // No default provider: a bare command must ask which account, never
834
+ // silently act on OpenAI now that more than one OAuth provider exists.
835
+ const providerId = args?.trim();
836
+ if (!providerId) {
837
+ ctx.openPicker("logout");
838
+ return;
839
+ }
840
+ if (isGrokSubscriptionProviderId(providerId)) {
841
+ return logoutGrokSubscription(ctx);
842
+ }
843
+ // Alias-aware: `openai` may be backed by the legacy `openai-codex` key.
844
+ const loginKeys = ctx.registry.getOAuthLoginKeys(providerId);
845
+ if (loginKeys.length === 0) {
846
+ return `No OAuth credentials found for ${providerId}.`;
847
+ }
848
+ for (const key of loginKeys)
849
+ ctx.registry.getAuthStorage().remove(key);
850
+ const fallback = ctx.registry.getDefault();
851
+ if (fallback?.apiKey) {
852
+ const fallbackModel = ctx.registry.getDefaultModel(fallback.id);
853
+ if (fallbackModel) {
854
+ switchToProviderModel(fallback.id, fallbackModel, ctx);
855
+ return `OAuth credentials for ${providerId} removed. Switched to ${fallback.name}.`;
856
+ }
857
+ ctx.agent.setProvider(ctx.createProvider(fallback.id, fallback.apiKey, fallback.baseURL));
858
+ ctx.agent.providerId = fallback.id;
859
+ }
860
+ else if (ctx.agent.providerId === providerId) {
861
+ ctx.agent.providerId = "";
862
+ }
863
+ // No-fallback logout mutates the routing world without a model switch
864
+ // (design §1.6): refresh the menu so it stops advertising the provider.
865
+ syncSystemPrompt(ctx, ctx.agent.model);
866
+ return `OAuth credentials for ${providerId} removed.`;
867
+ },
868
+ },
869
+ {
870
+ name: "goal",
871
+ description: "Set, manage, or inspect an autonomous goal. Usage: /goal <objective> [--budget N] | status | pause | resume | edit | clear",
872
+ async handler(args, ctx) {
873
+ if (!ctx.handleGoalCommand)
874
+ return "Goals are not available in this host.";
875
+ await ctx.handleGoalCommand(`/goal${args.trim() ? ` ${args.trim()}` : ""}`);
876
+ },
877
+ },
878
+ {
879
+ name: "plan",
880
+ description: "Toggle plan mode on/off (Tab switches Build/Plan)",
881
+ async handler(_args, ctx) {
882
+ const next = ctx.agent.mode === "plan" ? "default" : "plan";
883
+ ctx.agent.setMode(next);
884
+ return next === "plan"
885
+ ? "Entered plan mode. The assistant will investigate and propose a plan before making changes."
886
+ : "Exited plan mode.";
887
+ },
888
+ },
889
+ {
890
+ name: "permissions",
891
+ description: "Inspect or edit allow/deny rules. Subcommands: add <scope> <list> <rule>, remove <scope> <list> <rule>, clear (session approvals), reload.",
892
+ async handler(args, ctx) {
893
+ const tokens = args.trim().split(/\s+/).filter(Boolean);
894
+ const sub = tokens[0] ?? "";
895
+ if (sub === "add" || sub === "remove") {
896
+ return handlePermissionsMutation(sub, tokens.slice(1), ctx);
897
+ }
898
+ if (sub === "clear") {
899
+ if (!ctx.bashAllowlist)
900
+ return "No approval controller is attached to this session.";
901
+ const size = ctx.bashAllowlist.size();
902
+ if (size === 0)
903
+ return "Bash allowlist is already empty.";
904
+ ctx.bashAllowlist.clear();
905
+ return `Cleared ${size} session-approved bash command${size === 1 ? "" : "s"}.`;
906
+ }
907
+ if (sub === "reload") {
908
+ if (!ctx.settingsManager)
909
+ return "No settings manager is attached to this session.";
910
+ ctx.settingsManager.reload();
911
+ ctx.lspService?.updateConfig(ctx.settingsManager.getMerged().lsp);
912
+ ctx.lspService?.restart();
913
+ return "Reloaded settings from disk.";
914
+ }
915
+ const lines = [];
916
+ if (ctx.settingsManager) {
917
+ const merged = ctx.settingsManager.getMerged();
918
+ lines.push("Settings files:");
919
+ lines.push(` user: ${ctx.settingsManager.getPath("user")}`);
920
+ lines.push(` project: ${ctx.settingsManager.getPath("project")}`);
921
+ lines.push(` local: ${ctx.settingsManager.getPath("local")}`);
922
+ if (merged.defaultMode) {
923
+ lines.push("", `defaultMode: ${merged.defaultMode}`);
924
+ }
925
+ lines.push("", `Allow rules (${merged.ruleSet.allow.length}):`);
926
+ if (merged.ruleSet.allow.length === 0) {
927
+ lines.push(" (none)");
928
+ }
929
+ else {
930
+ for (const r of merged.ruleSet.allow)
931
+ lines.push(` ${r.source}`);
932
+ }
933
+ const untrusted = merged.untrusted;
934
+ if (untrusted.allow.length + untrusted.mcpServers.length + untrusted.lspServers.length > 0) {
935
+ lines.push("", "This folder is not trusted, so these stay off (Bubble asks at startup):");
936
+ lines.push(...describeRepoCapabilities(untrusted).map((line) => ` ${line}`));
937
+ }
938
+ lines.push("", `Deny rules (${merged.ruleSet.deny.length}):`);
939
+ if (merged.ruleSet.deny.length === 0) {
940
+ lines.push(" (none)");
941
+ }
942
+ else {
943
+ for (const r of merged.ruleSet.deny)
944
+ lines.push(` ${r.source}`);
945
+ }
946
+ if (merged.diagnostics.length > 0) {
947
+ lines.push("", "Diagnostics:");
948
+ for (const d of merged.diagnostics) {
949
+ lines.push(` [${d.scope}] ${d.message}`);
950
+ }
951
+ }
952
+ }
953
+ if (ctx.bashAllowlist) {
954
+ const entries = ctx.bashAllowlist.list();
955
+ if (lines.length > 0)
956
+ lines.push("");
957
+ lines.push(`Session-approved bash commands (${entries.length}):`);
958
+ if (entries.length === 0) {
959
+ lines.push(' (none) — "don\'t ask again for this exact command this session" adds entries here');
960
+ }
961
+ else {
962
+ for (const command of entries)
963
+ lines.push(` ${command}`);
964
+ }
965
+ }
966
+ if (lines.length === 0) {
967
+ return "Permissions system not attached to this session.";
968
+ }
969
+ return lines.join("\n");
970
+ },
971
+ },
972
+ {
973
+ name: "hooks",
974
+ description: "Inspect and manage lifecycle hooks. Usage: /hooks [status|trust project|test <event>]",
975
+ async handler(args, ctx) {
976
+ return handleHooksCommand(args, ctx);
977
+ },
978
+ },
979
+ {
980
+ name: "lsp",
981
+ description: "Inspect or restart language servers. Usage: /lsp [status|diagnostics|restart]",
982
+ async handler(args, ctx) {
983
+ const tokens = args.trim().split(/\s+/).filter(Boolean);
984
+ const sub = tokens[0] ?? "status";
985
+ const lsp = ctx.lspService;
986
+ if (!lsp)
987
+ return "LSP is not initialized for this session.";
988
+ if (sub === "restart") {
989
+ ctx.settingsManager?.reload();
990
+ ctx.lspService?.updateConfig(ctx.settingsManager?.getMerged().lsp);
991
+ await lsp.restart();
992
+ return "Restarted LSP servers.";
993
+ }
994
+ if (sub === "diagnostics") {
995
+ const diagnostics = lsp.diagnostics();
996
+ const entries = Object.entries(diagnostics).filter(([, issues]) => issues.length > 0);
997
+ if (entries.length === 0)
998
+ return "No LSP diagnostics.";
999
+ const lines = ["LSP diagnostics:"];
1000
+ for (const [file, issues] of entries.slice(0, 10)) {
1001
+ lines.push(formatDiagnostics(file, issues, ctx.cwd));
1002
+ }
1003
+ if (entries.length > 10)
1004
+ lines.push(`... ${entries.length - 10} more file(s) with diagnostics`);
1005
+ return lines.join("\n");
1006
+ }
1007
+ if (sub !== "status" && sub !== "list" && sub !== "") {
1008
+ return `Unknown /lsp subcommand "${sub}". Use /lsp status, /lsp diagnostics, or /lsp restart.`;
1009
+ }
1010
+ if (lsp.isDisabled()) {
1011
+ return "LSPs have been disabled in settings.";
1012
+ }
1013
+ const statuses = lsp.status();
1014
+ if (statuses.length === 0) {
1015
+ return "LSPs will activate as files are read.";
1016
+ }
1017
+ const lines = ["LSP servers:"];
1018
+ for (const status of statuses) {
1019
+ const marker = status.status === "connected" ? "*" : status.status === "starting" ? "~" : "!";
1020
+ const suffix = status.message ? ` — ${status.message}` : "";
1021
+ lines.push(` ${marker} ${status.id} ${status.root}${suffix}`);
1022
+ }
1023
+ return lines.join("\n");
1024
+ },
1025
+ },
1026
+ {
1027
+ name: "mcp",
1028
+ description: "Manage MCP servers. Usage: /mcp [list|tools <name>|reconnect <name>]",
1029
+ async handler(args, ctx) {
1030
+ const tokens = args.trim().split(/\s+/).filter(Boolean);
1031
+ const sub = tokens[0] ?? "list";
1032
+ if (!ctx.mcpManager) {
1033
+ return "MCP is not initialized for this session.";
1034
+ }
1035
+ if (sub === "reconnect") {
1036
+ const name = tokens[1];
1037
+ if (!name)
1038
+ return "Usage: /mcp reconnect <server-name>";
1039
+ const state = await ctx.mcpManager.reconnect(name);
1040
+ if (!state)
1041
+ return `Unknown MCP server: ${name}`;
1042
+ if (state.status.kind === "connected") {
1043
+ return `Reconnected ${name}. ${state.status.tools.length} tool${state.status.tools.length === 1 ? "" : "s"} available.`;
1044
+ }
1045
+ if (state.status.kind === "failed") {
1046
+ return `Failed to connect ${name}: ${state.status.error}`;
1047
+ }
1048
+ return `${name}: ${state.status.kind}`;
1049
+ }
1050
+ if (sub === "tools") {
1051
+ const name = tokens[1];
1052
+ if (!name)
1053
+ return "Usage: /mcp tools <server-name>";
1054
+ const state = ctx.mcpManager.getStates().find((s) => s.name === name);
1055
+ if (!state)
1056
+ return `Unknown MCP server: ${name}`;
1057
+ if (state.status.kind !== "connected") {
1058
+ return `${name} is not connected — no tools to list. Try /mcp reconnect ${name}.`;
1059
+ }
1060
+ const lines = [`Tools from ${name} (${state.status.tools.length}):`, ""];
1061
+ for (const tool of state.status.tools) {
1062
+ lines.push(`- \`${tool.name}\`${tool.description ? ` — ${tool.description.replace(/\s+/g, " ").slice(0, 100)}` : ""}`);
1063
+ }
1064
+ return lines.join("\n");
1065
+ }
1066
+ if (sub !== "list" && sub !== "") {
1067
+ return `Unknown /mcp subcommand "${sub}". Use /mcp list, /mcp tools <name>, or /mcp reconnect <name>.`;
1068
+ }
1069
+ const states = ctx.mcpManager.getStates();
1070
+ if (states.length === 0) {
1071
+ return "No MCP servers configured. Add entries under `mcpServers` in ~/.bubble/settings.json or <cwd>/.bubble/settings.json.";
1072
+ }
1073
+ // Rendered as markdown in the TUI: each server is its own paragraph,
1074
+ // failures are bold + uppercase so they stand apart from healthy rows,
1075
+ // and tool lists stay collapsed behind /mcp tools <name>.
1076
+ const lines = ["MCP servers:"];
1077
+ for (const state of states) {
1078
+ const meta = `${state.scope}/${state.config.type}`;
1079
+ lines.push("");
1080
+ if (state.status.kind === "connected") {
1081
+ const info = state.status.serverInfo ? ` · ${state.status.serverInfo.name}@${state.status.serverInfo.version}` : "";
1082
+ const tn = state.status.tools.length;
1083
+ const pn = state.status.prompts.length;
1084
+ const counts = [`${tn} tool${tn === 1 ? "" : "s"}`];
1085
+ if (pn > 0)
1086
+ counts.push(`${pn} prompt${pn === 1 ? "" : "s"}`);
1087
+ lines.push(`✔ ${state.name} — connected · ${counts.join(" · ")} (${meta}${info})`);
1088
+ if (pn > 0) {
1089
+ const prompts = state.status.prompts.map((p) => `/${normalizeNameForMCP(p.name)}`);
1090
+ lines.push(` prompts: ${prompts.join(", ")}`);
1091
+ }
1092
+ }
1093
+ else if (state.status.kind === "failed") {
1094
+ lines.push(`**✘ ${state.name} — UNABLE TO CONNECT** (${meta})`);
1095
+ lines.push(` ${state.status.error.replace(/\s+/g, " ").slice(0, 200)}`);
1096
+ lines.push(` retry: /mcp reconnect ${state.name}`);
1097
+ }
1098
+ else {
1099
+ lines.push(`○ ${state.name} — disabled (${meta})`);
1100
+ }
1101
+ }
1102
+ lines.push("");
1103
+ lines.push("Details: /mcp tools <name> · /mcp reconnect <name>");
1104
+ return lines.join("\n");
1105
+ },
1106
+ },
1107
+ {
1108
+ name: "compact",
1109
+ description: "Compact session context; optional text says what to preserve",
1110
+ async handler(args, ctx) {
1111
+ if (!ctx.sessionManager) {
1112
+ return "Compaction requires session persistence. Start an interactive session first.";
1113
+ }
1114
+ const preHook = await ctx.hookController?.runEvent({
1115
+ eventName: "PreCompact",
1116
+ cwd: ctx.cwd,
1117
+ sessionId: ctx.sessionManager.getSessionFile(),
1118
+ agentRole: "driver",
1119
+ target: "manual",
1120
+ payload: {
1121
+ kind: "manual",
1122
+ messageCount: ctx.agent.messages.length,
1123
+ },
1124
+ });
1125
+ if (preHook?.decision === "deny") {
1126
+ return preHook.reason ?? `Compaction blocked by hook ${preHook.sourceHookId ?? "<unknown>"}.`;
1127
+ }
1128
+ if (ctx.compactionAbortSignal?.aborted)
1129
+ return "Compaction cancelled.";
1130
+ // Plan first so we can report "already compact" without spending a model
1131
+ // call, and so the LLM summarizer gets the exact set of evicted messages.
1132
+ const plan = ctx.sessionManager.getCompactionPlan();
1133
+ if (!plan) {
1134
+ await ctx.hookController?.runEvent({
1135
+ eventName: "PostCompact",
1136
+ cwd: ctx.cwd,
1137
+ sessionId: ctx.sessionManager.getSessionFile(),
1138
+ agentRole: "driver",
1139
+ target: "manual",
1140
+ payload: { kind: "manual", compacted: false },
1141
+ });
1142
+ return "Session is already compact enough.";
1143
+ }
1144
+ // Stream an LLM summary for high fidelity, reporting progress to the TUI.
1145
+ // On any failure (or empty output) fall back to the instant heuristic
1146
+ // compaction so /compact always makes progress.
1147
+ let result;
1148
+ const startedAt = Date.now();
1149
+ try {
1150
+ ctx.compactionProgress?.({ phase: "collecting", streamedChars: 0 });
1151
+ let summary = "";
1152
+ try {
1153
+ summary = await ctx.agent.summarizeForCompaction(plan.oldMessages, (full) => {
1154
+ ctx.compactionProgress?.({ phase: "summarizing", streamedChars: full.length });
1155
+ }, ctx.compactionAbortSignal, args);
1156
+ // The signal is authoritative even if a provider finishes normally
1157
+ // after ignoring or racing its abort notification.
1158
+ if (ctx.compactionAbortSignal?.aborted)
1159
+ return "Compaction cancelled.";
1160
+ }
1161
+ catch (error) {
1162
+ if (ctx.compactionAbortSignal?.aborted || isAbortLike(error)) {
1163
+ return "Compaction cancelled.";
1164
+ }
1165
+ summary = "";
1166
+ }
1167
+ if (summary) {
1168
+ ctx.compactionProgress?.({ phase: "applying", streamedChars: summary.length });
1169
+ result = ctx.sessionManager.applyLLMCompaction(summary);
1170
+ }
1171
+ else {
1172
+ result = ctx.sessionManager.compact();
1173
+ }
1174
+ }
1175
+ finally {
1176
+ ctx.compactionProgress?.(null);
1177
+ }
1178
+ if (!result.compacted) {
1179
+ await ctx.hookController?.runEvent({
1180
+ eventName: "PostCompact",
1181
+ cwd: ctx.cwd,
1182
+ sessionId: ctx.sessionManager.getSessionFile(),
1183
+ agentRole: "driver",
1184
+ target: "manual",
1185
+ payload: {
1186
+ kind: "manual",
1187
+ compacted: false,
1188
+ },
1189
+ });
1190
+ return "Session is already compact enough.";
1191
+ }
1192
+ const systemMessage = ctx.agent.messages.find((message) => message.role === "system");
1193
+ ctx.agent.messages = [
1194
+ ...(systemMessage ? [systemMessage] : []),
1195
+ ...ctx.sessionManager.getMessages(),
1196
+ ];
1197
+ ctx.agent.resetContextUsageAnchor();
1198
+ const dropped = result.droppedEntries ?? 0;
1199
+ await ctx.hookController?.runEvent({
1200
+ eventName: "PostCompact",
1201
+ cwd: ctx.cwd,
1202
+ sessionId: ctx.sessionManager.getSessionFile(),
1203
+ agentRole: "driver",
1204
+ target: "manual",
1205
+ payload: {
1206
+ kind: "manual",
1207
+ compacted: true,
1208
+ droppedEntries: dropped,
1209
+ },
1210
+ });
1211
+ return {
1212
+ result: `Compaction completed in ${formatCompactDuration(Date.now() - startedAt)}.`,
1213
+ detail: {
1214
+ kind: "compaction-summary",
1215
+ content: result.summary ?? "",
1216
+ },
1217
+ };
1218
+ },
1219
+ },
1220
+ {
1221
+ name: "stats",
1222
+ description: "Show recent model usage statistics",
1223
+ async handler(_args, ctx) {
1224
+ if (ctx.openStats) {
1225
+ ctx.openStats();
1226
+ return;
1227
+ }
1228
+ return formatStatsText(collectUsageStatsBundle());
1229
+ },
1230
+ },
1231
+ {
1232
+ name: "feedback",
1233
+ description: "Send feedback or report a bug to Bubble developers",
1234
+ async handler(args, ctx) {
1235
+ if (!ctx.openFeedback) {
1236
+ return "Feedback is only available in interactive TUI mode.";
1237
+ }
1238
+ ctx.openFeedback(args ?? "");
1239
+ },
1240
+ },
1241
+ feishuCommand,
1242
+ ];
1243
+ /**
1244
+ * Public export — built-in commands tagged with `source: "builtin"` so the
1245
+ * registry and TUI can group them uniformly alongside MCP-derived commands.
1246
+ * Kept as a mapped projection to avoid adding the field to every object literal.
1247
+ */
1248
+ export const builtinSlashCommands = builtinSlashCommandEntries.map((cmd) => ({
1249
+ ...cmd,
1250
+ source: "builtin",
1251
+ }));