@otto-assistant/bridge 0.4.92

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 (483) hide show
  1. package/bin.js +2 -0
  2. package/dist/agent-model.e2e.test.js +755 -0
  3. package/dist/ai-tool-to-genai.js +233 -0
  4. package/dist/ai-tool-to-genai.test.js +267 -0
  5. package/dist/ai-tool.js +6 -0
  6. package/dist/anthropic-auth-plugin.js +728 -0
  7. package/dist/anthropic-auth-plugin.test.js +125 -0
  8. package/dist/anthropic-auth-state.js +231 -0
  9. package/dist/bin.js +90 -0
  10. package/dist/channel-management.js +227 -0
  11. package/dist/cli-parsing.test.js +137 -0
  12. package/dist/cli-send-thread.e2e.test.js +356 -0
  13. package/dist/cli.js +3276 -0
  14. package/dist/commands/abort.js +65 -0
  15. package/dist/commands/action-buttons.js +245 -0
  16. package/dist/commands/add-project.js +113 -0
  17. package/dist/commands/agent.js +335 -0
  18. package/dist/commands/ask-question.js +274 -0
  19. package/dist/commands/btw.js +116 -0
  20. package/dist/commands/compact.js +120 -0
  21. package/dist/commands/context-usage.js +140 -0
  22. package/dist/commands/create-new-project.js +130 -0
  23. package/dist/commands/diff.js +63 -0
  24. package/dist/commands/file-upload.js +275 -0
  25. package/dist/commands/fork.js +220 -0
  26. package/dist/commands/gemini-apikey.js +70 -0
  27. package/dist/commands/login.js +885 -0
  28. package/dist/commands/mcp.js +239 -0
  29. package/dist/commands/memory-snapshot.js +24 -0
  30. package/dist/commands/mention-mode.js +44 -0
  31. package/dist/commands/merge-worktree.js +159 -0
  32. package/dist/commands/model-variant.js +364 -0
  33. package/dist/commands/model.js +776 -0
  34. package/dist/commands/new-worktree.js +366 -0
  35. package/dist/commands/paginated-select.js +57 -0
  36. package/dist/commands/permissions.js +274 -0
  37. package/dist/commands/queue.js +206 -0
  38. package/dist/commands/remove-project.js +115 -0
  39. package/dist/commands/restart-opencode-server.js +127 -0
  40. package/dist/commands/resume.js +149 -0
  41. package/dist/commands/run-command.js +79 -0
  42. package/dist/commands/screenshare.js +303 -0
  43. package/dist/commands/screenshare.test.js +20 -0
  44. package/dist/commands/session-id.js +78 -0
  45. package/dist/commands/session.js +176 -0
  46. package/dist/commands/share.js +80 -0
  47. package/dist/commands/tasks.js +205 -0
  48. package/dist/commands/types.js +2 -0
  49. package/dist/commands/undo-redo.js +305 -0
  50. package/dist/commands/unset-model.js +138 -0
  51. package/dist/commands/upgrade.js +42 -0
  52. package/dist/commands/user-command.js +155 -0
  53. package/dist/commands/verbosity.js +125 -0
  54. package/dist/commands/worktree-settings.js +43 -0
  55. package/dist/commands/worktrees.js +410 -0
  56. package/dist/condense-memory.js +33 -0
  57. package/dist/config.js +94 -0
  58. package/dist/context-awareness-plugin.js +363 -0
  59. package/dist/context-awareness-plugin.test.js +124 -0
  60. package/dist/critique-utils.js +95 -0
  61. package/dist/database.js +1310 -0
  62. package/dist/db.js +251 -0
  63. package/dist/db.test.js +138 -0
  64. package/dist/debounce-timeout.js +28 -0
  65. package/dist/debounced-process-flush.js +77 -0
  66. package/dist/discord-bot.js +1008 -0
  67. package/dist/discord-command-registration.js +524 -0
  68. package/dist/discord-urls.js +81 -0
  69. package/dist/discord-utils.js +591 -0
  70. package/dist/discord-utils.test.js +134 -0
  71. package/dist/errors.js +157 -0
  72. package/dist/escape-backticks.test.js +429 -0
  73. package/dist/event-stream-real-capture.e2e.test.js +533 -0
  74. package/dist/eventsource-parser.test.js +327 -0
  75. package/dist/exec-async.js +26 -0
  76. package/dist/external-opencode-sync.js +480 -0
  77. package/dist/format-tables.js +302 -0
  78. package/dist/format-tables.test.js +308 -0
  79. package/dist/forum-sync/config.js +79 -0
  80. package/dist/forum-sync/discord-operations.js +154 -0
  81. package/dist/forum-sync/index.js +5 -0
  82. package/dist/forum-sync/markdown.js +113 -0
  83. package/dist/forum-sync/sync-to-discord.js +417 -0
  84. package/dist/forum-sync/sync-to-files.js +190 -0
  85. package/dist/forum-sync/types.js +53 -0
  86. package/dist/forum-sync/watchers.js +307 -0
  87. package/dist/gateway-proxy-reconnect.e2e.test.js +394 -0
  88. package/dist/gateway-proxy.e2e.test.js +483 -0
  89. package/dist/genai-worker-wrapper.js +111 -0
  90. package/dist/genai-worker.js +311 -0
  91. package/dist/genai.js +232 -0
  92. package/dist/generated/browser.js +17 -0
  93. package/dist/generated/client.js +37 -0
  94. package/dist/generated/commonInputTypes.js +10 -0
  95. package/dist/generated/enums.js +52 -0
  96. package/dist/generated/internal/class.js +49 -0
  97. package/dist/generated/internal/prismaNamespace.js +253 -0
  98. package/dist/generated/internal/prismaNamespaceBrowser.js +223 -0
  99. package/dist/generated/models/bot_api_keys.js +1 -0
  100. package/dist/generated/models/bot_tokens.js +1 -0
  101. package/dist/generated/models/channel_agents.js +1 -0
  102. package/dist/generated/models/channel_directories.js +1 -0
  103. package/dist/generated/models/channel_mention_mode.js +1 -0
  104. package/dist/generated/models/channel_models.js +1 -0
  105. package/dist/generated/models/channel_verbosity.js +1 -0
  106. package/dist/generated/models/channel_worktrees.js +1 -0
  107. package/dist/generated/models/forum_sync_configs.js +1 -0
  108. package/dist/generated/models/global_models.js +1 -0
  109. package/dist/generated/models/ipc_requests.js +1 -0
  110. package/dist/generated/models/part_messages.js +1 -0
  111. package/dist/generated/models/scheduled_tasks.js +1 -0
  112. package/dist/generated/models/session_agents.js +1 -0
  113. package/dist/generated/models/session_events.js +1 -0
  114. package/dist/generated/models/session_models.js +1 -0
  115. package/dist/generated/models/session_start_sources.js +1 -0
  116. package/dist/generated/models/thread_sessions.js +1 -0
  117. package/dist/generated/models/thread_worktrees.js +1 -0
  118. package/dist/generated/models.js +1 -0
  119. package/dist/heap-monitor.js +122 -0
  120. package/dist/hrana-server.js +263 -0
  121. package/dist/hrana-server.test.js +370 -0
  122. package/dist/html-actions.js +123 -0
  123. package/dist/html-actions.test.js +70 -0
  124. package/dist/html-components.js +117 -0
  125. package/dist/html-components.test.js +34 -0
  126. package/dist/image-optimizer-plugin.js +153 -0
  127. package/dist/image-utils.js +112 -0
  128. package/dist/interaction-handler.js +397 -0
  129. package/dist/ipc-polling.js +252 -0
  130. package/dist/ipc-tools-plugin.js +193 -0
  131. package/dist/kimaki-digital-twin.e2e.test.js +161 -0
  132. package/dist/kimaki-opencode-plugin-loading.e2e.test.js +87 -0
  133. package/dist/kimaki-opencode-plugin.js +17 -0
  134. package/dist/kimaki-opencode-plugin.test.js +98 -0
  135. package/dist/limit-heading-depth.js +25 -0
  136. package/dist/limit-heading-depth.test.js +105 -0
  137. package/dist/logger.js +165 -0
  138. package/dist/markdown.js +342 -0
  139. package/dist/markdown.test.js +257 -0
  140. package/dist/message-finish-field.e2e.test.js +165 -0
  141. package/dist/message-formatting.js +413 -0
  142. package/dist/message-formatting.test.js +73 -0
  143. package/dist/message-preprocessing.js +330 -0
  144. package/dist/onboarding-tutorial.js +172 -0
  145. package/dist/onboarding-welcome.js +37 -0
  146. package/dist/openai-realtime.js +224 -0
  147. package/dist/opencode-command-detection.js +65 -0
  148. package/dist/opencode-command-detection.test.js +240 -0
  149. package/dist/opencode-command.js +129 -0
  150. package/dist/opencode-command.test.js +48 -0
  151. package/dist/opencode-interrupt-plugin.js +361 -0
  152. package/dist/opencode-interrupt-plugin.test.js +458 -0
  153. package/dist/opencode.js +861 -0
  154. package/dist/otto/branding.js +22 -0
  155. package/dist/otto/index.js +21 -0
  156. package/dist/parse-permission-rules.test.js +117 -0
  157. package/dist/patch-text-parser.js +97 -0
  158. package/dist/plugin-logger.js +59 -0
  159. package/dist/privacy-sanitizer.js +105 -0
  160. package/dist/queue-advanced-abort.e2e.test.js +293 -0
  161. package/dist/queue-advanced-action-buttons.e2e.test.js +206 -0
  162. package/dist/queue-advanced-e2e-setup.js +786 -0
  163. package/dist/queue-advanced-footer.e2e.test.js +472 -0
  164. package/dist/queue-advanced-model-switch.e2e.test.js +299 -0
  165. package/dist/queue-advanced-permissions-typing.e2e.test.js +180 -0
  166. package/dist/queue-advanced-question.e2e.test.js +261 -0
  167. package/dist/queue-advanced-typing-interrupt.e2e.test.js +114 -0
  168. package/dist/queue-advanced-typing.e2e.test.js +153 -0
  169. package/dist/queue-drain-after-interactive-ui.e2e.test.js +119 -0
  170. package/dist/queue-interrupt-drain.e2e.test.js +135 -0
  171. package/dist/queue-question-select-drain.e2e.test.js +120 -0
  172. package/dist/runtime-idle-sweeper.js +52 -0
  173. package/dist/runtime-lifecycle.e2e.test.js +508 -0
  174. package/dist/sentry.js +23 -0
  175. package/dist/session-handler/agent-utils.js +67 -0
  176. package/dist/session-handler/event-stream-state.js +420 -0
  177. package/dist/session-handler/event-stream-state.test.js +563 -0
  178. package/dist/session-handler/model-utils.js +124 -0
  179. package/dist/session-handler/opencode-session-event-log.js +94 -0
  180. package/dist/session-handler/thread-runtime-state.js +104 -0
  181. package/dist/session-handler/thread-session-runtime.js +3258 -0
  182. package/dist/session-handler.js +9 -0
  183. package/dist/session-search.js +100 -0
  184. package/dist/session-search.test.js +40 -0
  185. package/dist/session-title-rename.test.js +80 -0
  186. package/dist/startup-service.js +153 -0
  187. package/dist/startup-time.e2e.test.js +296 -0
  188. package/dist/store.js +17 -0
  189. package/dist/system-message.js +613 -0
  190. package/dist/system-message.test.js +602 -0
  191. package/dist/task-runner.js +295 -0
  192. package/dist/task-schedule.js +209 -0
  193. package/dist/task-schedule.test.js +71 -0
  194. package/dist/test-utils.js +299 -0
  195. package/dist/thinking-utils.js +35 -0
  196. package/dist/thread-message-queue.e2e.test.js +999 -0
  197. package/dist/tools.js +357 -0
  198. package/dist/undo-redo.e2e.test.js +161 -0
  199. package/dist/unnest-code-blocks.js +146 -0
  200. package/dist/unnest-code-blocks.test.js +673 -0
  201. package/dist/upgrade.js +114 -0
  202. package/dist/utils.js +144 -0
  203. package/dist/voice-attachment.js +34 -0
  204. package/dist/voice-handler.js +646 -0
  205. package/dist/voice-message.e2e.test.js +1021 -0
  206. package/dist/voice.js +447 -0
  207. package/dist/voice.test.js +235 -0
  208. package/dist/wait-session.js +94 -0
  209. package/dist/websockify.js +69 -0
  210. package/dist/worker-types.js +4 -0
  211. package/dist/worktree-lifecycle.e2e.test.js +308 -0
  212. package/dist/worktree-utils.js +3 -0
  213. package/dist/worktrees.js +929 -0
  214. package/dist/worktrees.test.js +189 -0
  215. package/dist/xml.js +92 -0
  216. package/dist/xml.test.js +32 -0
  217. package/package.json +98 -0
  218. package/schema.prisma +295 -0
  219. package/skills/batch/SKILL.md +87 -0
  220. package/skills/critique/SKILL.md +112 -0
  221. package/skills/egaki/SKILL.md +100 -0
  222. package/skills/errore/SKILL.md +647 -0
  223. package/skills/event-sourcing-state/SKILL.md +252 -0
  224. package/skills/gitchamber/SKILL.md +93 -0
  225. package/skills/goke/SKILL.md +644 -0
  226. package/skills/jitter/EDITOR.md +219 -0
  227. package/skills/jitter/EXPORT-INTERNALS.md +309 -0
  228. package/skills/jitter/SKILL.md +158 -0
  229. package/skills/jitter/jitter-clipboard.json +1042 -0
  230. package/skills/jitter/package.json +14 -0
  231. package/skills/jitter/tsconfig.json +15 -0
  232. package/skills/jitter/utils/actions.ts +212 -0
  233. package/skills/jitter/utils/export.ts +114 -0
  234. package/skills/jitter/utils/index.ts +141 -0
  235. package/skills/jitter/utils/snapshot.ts +154 -0
  236. package/skills/jitter/utils/traverse.ts +246 -0
  237. package/skills/jitter/utils/types.ts +279 -0
  238. package/skills/jitter/utils/wait.ts +133 -0
  239. package/skills/lintcn/SKILL.md +873 -0
  240. package/skills/new-skill/SKILL.md +211 -0
  241. package/skills/npm-package/SKILL.md +239 -0
  242. package/skills/playwriter/SKILL.md +35 -0
  243. package/skills/proxyman/SKILL.md +215 -0
  244. package/skills/security-review/SKILL.md +208 -0
  245. package/skills/simplify/SKILL.md +58 -0
  246. package/skills/spiceflow/SKILL.md +14 -0
  247. package/skills/termcast/SKILL.md +945 -0
  248. package/skills/tuistory/SKILL.md +250 -0
  249. package/skills/usecomputer/SKILL.md +264 -0
  250. package/skills/x-articles/SKILL.md +554 -0
  251. package/skills/zele/SKILL.md +112 -0
  252. package/skills/zustand-centralized-state/SKILL.md +1004 -0
  253. package/src/agent-model.e2e.test.ts +976 -0
  254. package/src/ai-tool-to-genai.test.ts +296 -0
  255. package/src/ai-tool-to-genai.ts +283 -0
  256. package/src/ai-tool.ts +39 -0
  257. package/src/anthropic-auth-plugin.test.ts +159 -0
  258. package/src/anthropic-auth-plugin.ts +861 -0
  259. package/src/anthropic-auth-state.ts +282 -0
  260. package/src/bin.ts +111 -0
  261. package/src/channel-management.ts +334 -0
  262. package/src/cli-parsing.test.ts +195 -0
  263. package/src/cli-send-thread.e2e.test.ts +464 -0
  264. package/src/cli.ts +4581 -0
  265. package/src/commands/abort.ts +89 -0
  266. package/src/commands/action-buttons.ts +364 -0
  267. package/src/commands/add-project.ts +149 -0
  268. package/src/commands/agent.ts +473 -0
  269. package/src/commands/ask-question.ts +390 -0
  270. package/src/commands/btw.ts +164 -0
  271. package/src/commands/compact.ts +157 -0
  272. package/src/commands/context-usage.ts +199 -0
  273. package/src/commands/create-new-project.ts +190 -0
  274. package/src/commands/diff.ts +91 -0
  275. package/src/commands/file-upload.ts +389 -0
  276. package/src/commands/fork.ts +321 -0
  277. package/src/commands/gemini-apikey.ts +104 -0
  278. package/src/commands/login.ts +1173 -0
  279. package/src/commands/mcp.ts +307 -0
  280. package/src/commands/memory-snapshot.ts +30 -0
  281. package/src/commands/mention-mode.ts +68 -0
  282. package/src/commands/merge-worktree.ts +223 -0
  283. package/src/commands/model-variant.ts +483 -0
  284. package/src/commands/model.ts +1053 -0
  285. package/src/commands/new-worktree.ts +510 -0
  286. package/src/commands/paginated-select.ts +81 -0
  287. package/src/commands/permissions.ts +397 -0
  288. package/src/commands/queue.ts +271 -0
  289. package/src/commands/remove-project.ts +155 -0
  290. package/src/commands/restart-opencode-server.ts +162 -0
  291. package/src/commands/resume.ts +230 -0
  292. package/src/commands/run-command.ts +123 -0
  293. package/src/commands/screenshare.test.ts +30 -0
  294. package/src/commands/screenshare.ts +366 -0
  295. package/src/commands/session-id.ts +109 -0
  296. package/src/commands/session.ts +227 -0
  297. package/src/commands/share.ts +106 -0
  298. package/src/commands/tasks.ts +293 -0
  299. package/src/commands/types.ts +25 -0
  300. package/src/commands/undo-redo.ts +386 -0
  301. package/src/commands/unset-model.ts +173 -0
  302. package/src/commands/upgrade.ts +52 -0
  303. package/src/commands/user-command.ts +198 -0
  304. package/src/commands/verbosity.ts +173 -0
  305. package/src/commands/worktree-settings.ts +70 -0
  306. package/src/commands/worktrees.ts +552 -0
  307. package/src/condense-memory.ts +36 -0
  308. package/src/config.ts +111 -0
  309. package/src/context-awareness-plugin.test.ts +142 -0
  310. package/src/context-awareness-plugin.ts +510 -0
  311. package/src/critique-utils.ts +139 -0
  312. package/src/database.ts +1876 -0
  313. package/src/db.test.ts +162 -0
  314. package/src/db.ts +286 -0
  315. package/src/debounce-timeout.ts +43 -0
  316. package/src/debounced-process-flush.ts +104 -0
  317. package/src/discord-bot.ts +1330 -0
  318. package/src/discord-command-registration.ts +693 -0
  319. package/src/discord-urls.ts +88 -0
  320. package/src/discord-utils.test.ts +153 -0
  321. package/src/discord-utils.ts +800 -0
  322. package/src/errors.ts +201 -0
  323. package/src/escape-backticks.test.ts +469 -0
  324. package/src/event-stream-real-capture.e2e.test.ts +692 -0
  325. package/src/eventsource-parser.test.ts +351 -0
  326. package/src/exec-async.ts +35 -0
  327. package/src/external-opencode-sync.ts +685 -0
  328. package/src/format-tables.test.ts +335 -0
  329. package/src/format-tables.ts +445 -0
  330. package/src/forum-sync/config.ts +92 -0
  331. package/src/forum-sync/discord-operations.ts +241 -0
  332. package/src/forum-sync/index.ts +9 -0
  333. package/src/forum-sync/markdown.ts +172 -0
  334. package/src/forum-sync/sync-to-discord.ts +595 -0
  335. package/src/forum-sync/sync-to-files.ts +294 -0
  336. package/src/forum-sync/types.ts +175 -0
  337. package/src/forum-sync/watchers.ts +454 -0
  338. package/src/gateway-proxy-reconnect.e2e.test.ts +523 -0
  339. package/src/gateway-proxy.e2e.test.ts +640 -0
  340. package/src/genai-worker-wrapper.ts +164 -0
  341. package/src/genai-worker.ts +386 -0
  342. package/src/genai.ts +321 -0
  343. package/src/generated/browser.ts +114 -0
  344. package/src/generated/client.ts +138 -0
  345. package/src/generated/commonInputTypes.ts +736 -0
  346. package/src/generated/enums.ts +88 -0
  347. package/src/generated/internal/class.ts +384 -0
  348. package/src/generated/internal/prismaNamespace.ts +2386 -0
  349. package/src/generated/internal/prismaNamespaceBrowser.ts +326 -0
  350. package/src/generated/models/bot_api_keys.ts +1288 -0
  351. package/src/generated/models/bot_tokens.ts +1656 -0
  352. package/src/generated/models/channel_agents.ts +1256 -0
  353. package/src/generated/models/channel_directories.ts +1859 -0
  354. package/src/generated/models/channel_mention_mode.ts +1300 -0
  355. package/src/generated/models/channel_models.ts +1288 -0
  356. package/src/generated/models/channel_verbosity.ts +1228 -0
  357. package/src/generated/models/channel_worktrees.ts +1300 -0
  358. package/src/generated/models/forum_sync_configs.ts +1452 -0
  359. package/src/generated/models/global_models.ts +1288 -0
  360. package/src/generated/models/ipc_requests.ts +1485 -0
  361. package/src/generated/models/part_messages.ts +1302 -0
  362. package/src/generated/models/scheduled_tasks.ts +2320 -0
  363. package/src/generated/models/session_agents.ts +1086 -0
  364. package/src/generated/models/session_events.ts +1439 -0
  365. package/src/generated/models/session_models.ts +1114 -0
  366. package/src/generated/models/session_start_sources.ts +1408 -0
  367. package/src/generated/models/thread_sessions.ts +1781 -0
  368. package/src/generated/models/thread_worktrees.ts +1356 -0
  369. package/src/generated/models.ts +30 -0
  370. package/src/heap-monitor.ts +152 -0
  371. package/src/hrana-server.test.ts +434 -0
  372. package/src/hrana-server.ts +314 -0
  373. package/src/html-actions.test.ts +87 -0
  374. package/src/html-actions.ts +174 -0
  375. package/src/html-components.test.ts +38 -0
  376. package/src/html-components.ts +181 -0
  377. package/src/image-optimizer-plugin.ts +194 -0
  378. package/src/image-utils.ts +149 -0
  379. package/src/interaction-handler.ts +576 -0
  380. package/src/ipc-polling.ts +326 -0
  381. package/src/ipc-tools-plugin.ts +236 -0
  382. package/src/kimaki-digital-twin.e2e.test.ts +199 -0
  383. package/src/kimaki-opencode-plugin-loading.e2e.test.ts +109 -0
  384. package/src/kimaki-opencode-plugin.test.ts +108 -0
  385. package/src/kimaki-opencode-plugin.ts +18 -0
  386. package/src/limit-heading-depth.test.ts +116 -0
  387. package/src/limit-heading-depth.ts +26 -0
  388. package/src/logger.ts +208 -0
  389. package/src/markdown.test.ts +308 -0
  390. package/src/markdown.ts +410 -0
  391. package/src/message-finish-field.e2e.test.ts +192 -0
  392. package/src/message-formatting.test.ts +81 -0
  393. package/src/message-formatting.ts +533 -0
  394. package/src/message-preprocessing.ts +455 -0
  395. package/src/onboarding-tutorial.ts +176 -0
  396. package/src/onboarding-welcome.ts +49 -0
  397. package/src/openai-realtime.ts +358 -0
  398. package/src/opencode-command-detection.test.ts +307 -0
  399. package/src/opencode-command-detection.ts +76 -0
  400. package/src/opencode-command.test.ts +70 -0
  401. package/src/opencode-command.ts +188 -0
  402. package/src/opencode-interrupt-plugin.test.ts +677 -0
  403. package/src/opencode-interrupt-plugin.ts +477 -0
  404. package/src/opencode.ts +1110 -0
  405. package/src/otto/branding.ts +23 -0
  406. package/src/otto/index.ts +22 -0
  407. package/src/parse-permission-rules.test.ts +127 -0
  408. package/src/patch-text-parser.ts +107 -0
  409. package/src/plugin-logger.ts +68 -0
  410. package/src/privacy-sanitizer.ts +142 -0
  411. package/src/queue-advanced-abort.e2e.test.ts +382 -0
  412. package/src/queue-advanced-action-buttons.e2e.test.ts +268 -0
  413. package/src/queue-advanced-e2e-setup.ts +873 -0
  414. package/src/queue-advanced-footer.e2e.test.ts +576 -0
  415. package/src/queue-advanced-model-switch.e2e.test.ts +383 -0
  416. package/src/queue-advanced-permissions-typing.e2e.test.ts +245 -0
  417. package/src/queue-advanced-question.e2e.test.ts +316 -0
  418. package/src/queue-advanced-typing-interrupt.e2e.test.ts +146 -0
  419. package/src/queue-advanced-typing.e2e.test.ts +199 -0
  420. package/src/queue-drain-after-interactive-ui.e2e.test.ts +151 -0
  421. package/src/queue-interrupt-drain.e2e.test.ts +166 -0
  422. package/src/queue-question-select-drain.e2e.test.ts +152 -0
  423. package/src/runtime-idle-sweeper.ts +76 -0
  424. package/src/runtime-lifecycle.e2e.test.ts +641 -0
  425. package/src/schema.sql +173 -0
  426. package/src/sentry.ts +26 -0
  427. package/src/session-handler/agent-utils.ts +97 -0
  428. package/src/session-handler/event-stream-fixtures/real-session-action-buttons.jsonl +45 -0
  429. package/src/session-handler/event-stream-fixtures/real-session-footer-suppressed-on-pre-idle-interrupt.jsonl +40 -0
  430. package/src/session-handler/event-stream-fixtures/real-session-permission-external-file.jsonl +23 -0
  431. package/src/session-handler/event-stream-fixtures/real-session-task-normal.jsonl +22 -0
  432. package/src/session-handler/event-stream-fixtures/real-session-task-three-parallel-sleeps.jsonl +277 -0
  433. package/src/session-handler/event-stream-fixtures/real-session-task-user-interruption.jsonl +46 -0
  434. package/src/session-handler/event-stream-fixtures/session-abort-after-idle-race.jsonl +21 -0
  435. package/src/session-handler/event-stream-fixtures/session-concurrent-messages-serialized.jsonl +56 -0
  436. package/src/session-handler/event-stream-fixtures/session-explicit-abort.jsonl +44 -0
  437. package/src/session-handler/event-stream-fixtures/session-normal-completion.jsonl +29 -0
  438. package/src/session-handler/event-stream-fixtures/session-tool-call-noisy-stream.jsonl +29 -0
  439. package/src/session-handler/event-stream-fixtures/session-two-completions-same-session.jsonl +50 -0
  440. package/src/session-handler/event-stream-fixtures/session-user-interruption.jsonl +59 -0
  441. package/src/session-handler/event-stream-fixtures/session-voice-queued-followup.jsonl +52 -0
  442. package/src/session-handler/event-stream-state.test.ts +645 -0
  443. package/src/session-handler/event-stream-state.ts +608 -0
  444. package/src/session-handler/model-utils.ts +183 -0
  445. package/src/session-handler/opencode-session-event-log.ts +130 -0
  446. package/src/session-handler/thread-runtime-state.ts +212 -0
  447. package/src/session-handler/thread-session-runtime.ts +4281 -0
  448. package/src/session-handler.ts +15 -0
  449. package/src/session-search.test.ts +50 -0
  450. package/src/session-search.ts +148 -0
  451. package/src/session-title-rename.test.ts +112 -0
  452. package/src/startup-service.ts +200 -0
  453. package/src/startup-time.e2e.test.ts +373 -0
  454. package/src/store.ts +122 -0
  455. package/src/system-message.test.ts +612 -0
  456. package/src/system-message.ts +723 -0
  457. package/src/task-runner.ts +421 -0
  458. package/src/task-schedule.test.ts +84 -0
  459. package/src/task-schedule.ts +311 -0
  460. package/src/test-utils.ts +435 -0
  461. package/src/thinking-utils.ts +61 -0
  462. package/src/thread-message-queue.e2e.test.ts +1219 -0
  463. package/src/tools.ts +430 -0
  464. package/src/undici.d.ts +12 -0
  465. package/src/undo-redo.e2e.test.ts +209 -0
  466. package/src/unnest-code-blocks.test.ts +713 -0
  467. package/src/unnest-code-blocks.ts +185 -0
  468. package/src/upgrade.ts +127 -0
  469. package/src/utils.ts +212 -0
  470. package/src/voice-attachment.ts +51 -0
  471. package/src/voice-handler.ts +908 -0
  472. package/src/voice-message.e2e.test.ts +1255 -0
  473. package/src/voice.test.ts +281 -0
  474. package/src/voice.ts +627 -0
  475. package/src/wait-session.ts +147 -0
  476. package/src/websockify.ts +101 -0
  477. package/src/worker-types.ts +64 -0
  478. package/src/worktree-lifecycle.e2e.test.ts +391 -0
  479. package/src/worktree-utils.ts +4 -0
  480. package/src/worktrees.test.ts +223 -0
  481. package/src/worktrees.ts +1294 -0
  482. package/src/xml.test.ts +38 -0
  483. package/src/xml.ts +121 -0
@@ -0,0 +1,135 @@
1
+ // E2e test for queue + interrupt interaction.
2
+ // Validates that a user can queue a command via /queue while a slow session
3
+ // is in progress, then send a normal (non-queued) message to interrupt.
4
+ //
5
+ // Expected behavior:
6
+ // 1. Slow session is running
7
+ // 2. User queues a message via /queue (enters kimaki local queue)
8
+ // 3. User sends a normal message (interrupt)
9
+ // 4. Session aborts the slow task, processes the interrupt message immediately
10
+ // 5. Interrupt response appears in Discord with a ⬥ ok reply
11
+ // 6. When interrupt response completes, the queued message drains and runs
12
+ //
13
+ // Uses opencode-deterministic-provider (no real LLM calls).
14
+ // Poll timeouts: 4s max, 100ms interval. Slow matcher uses 100s delay.
15
+ import { describe, test, expect } from 'vitest';
16
+ import { setupQueueAdvancedSuite, TEST_USER_ID, } from './queue-advanced-e2e-setup.js';
17
+ import { waitForFooterMessage, waitForBotMessageContaining, waitForMessageById, } from './test-utils.js';
18
+ const TEXT_CHANNEL_ID = '200000000000001099';
19
+ const e2eTest = describe;
20
+ e2eTest('queue + interrupt drain ordering', () => {
21
+ const ctx = setupQueueAdvancedSuite({
22
+ channelId: TEXT_CHANNEL_ID,
23
+ channelName: 'qa-interrupt-drain-e2e',
24
+ dirName: 'qa-interrupt-drain-e2e',
25
+ username: 'interrupt-tester',
26
+ });
27
+ test('queued message via /queue + normal interrupt: interrupt reply should appear, then queue drains', async () => {
28
+ // 1. Establish session with a quick first message
29
+ await ctx.discord.channel(TEXT_CHANNEL_ID).user(TEST_USER_ID).sendMessage({
30
+ content: 'Reply with exactly: setup-interrupt-drain',
31
+ });
32
+ const thread = await ctx.discord.channel(TEXT_CHANNEL_ID).waitForThread({
33
+ timeout: 4_000,
34
+ predicate: (t) => {
35
+ return t.name === 'Reply with exactly: setup-interrupt-drain';
36
+ },
37
+ });
38
+ const th = ctx.discord.thread(thread.id);
39
+ await th.waitForBotReply({ timeout: 4_000 });
40
+ // Wait for first run to fully complete (footer) so state is clean
41
+ await waitForFooterMessage({
42
+ discord: ctx.discord,
43
+ threadId: thread.id,
44
+ timeout: 4_000,
45
+ });
46
+ // 2. Start a slow session — PLUGIN_TIMEOUT_SLEEP_MARKER has a 100s delay
47
+ // before the finish event, guaranteeing the session stays busy.
48
+ await th.user(TEST_USER_ID).sendMessage({
49
+ content: 'PLUGIN_TIMEOUT_SLEEP_MARKER',
50
+ });
51
+ // Wait for the slow matcher to start streaming (text appears before delay)
52
+ await waitForBotMessageContaining({
53
+ discord: ctx.discord,
54
+ threadId: thread.id,
55
+ userId: TEST_USER_ID,
56
+ text: 'starting sleep',
57
+ afterUserMessageIncludes: 'PLUGIN_TIMEOUT_SLEEP_MARKER',
58
+ timeout: 4_000,
59
+ });
60
+ // 3. Queue a message via /queue while the slow session is running
61
+ const { id: queueInteractionId } = await th.user(TEST_USER_ID)
62
+ .runSlashCommand({
63
+ name: 'queue',
64
+ options: [{ name: 'message', type: 3, value: 'Reply with exactly: queued-behind-slow' }],
65
+ });
66
+ const queueAck = await th.waitForInteractionAck({
67
+ interactionId: queueInteractionId,
68
+ timeout: 4_000,
69
+ });
70
+ if (!queueAck.messageId) {
71
+ throw new Error('Expected /queue response message id');
72
+ }
73
+ const queueStatusMessage = await waitForMessageById({
74
+ discord: ctx.discord,
75
+ threadId: thread.id,
76
+ messageId: queueAck.messageId,
77
+ timeout: 4_000,
78
+ });
79
+ // The /queue message should be queued (session is busy with the 100s task)
80
+ expect(queueStatusMessage.content).toContain('Queued message');
81
+ // 4. Send a normal (non-queued) message — this should interrupt the slow
82
+ // session and be processed immediately
83
+ await th.user(TEST_USER_ID).sendMessage({
84
+ content: 'Reply with exactly: interrupt-now',
85
+ });
86
+ // 5. Wait for the final state: the interrupt message should get its own
87
+ // ⬥ ok reply, then the queued message should drain and get processed.
88
+ // We wait for the queued message's footer as the final signal.
89
+ await waitForFooterMessage({
90
+ discord: ctx.discord,
91
+ threadId: thread.id,
92
+ timeout: 12_000,
93
+ afterMessageIncludes: 'queued-behind-slow',
94
+ afterAuthorId: ctx.discord.botUserId,
95
+ });
96
+ // 6. Capture the full interaction in an inline snapshot.
97
+ expect(await th.text()).toMatchInlineSnapshot(`
98
+ "--- from: user (interrupt-tester)
99
+ Reply with exactly: setup-interrupt-drain
100
+ --- from: assistant (TestBot)
101
+ ⬥ ok
102
+ *project ⋅ main ⋅ Ns ⋅ N% ⋅ deterministic-v2*
103
+ --- from: user (interrupt-tester)
104
+ PLUGIN_TIMEOUT_SLEEP_MARKER
105
+ --- from: assistant (TestBot)
106
+ ⬥ starting sleep 100
107
+ Queued message (position 1)
108
+ --- from: user (interrupt-tester)
109
+ Reply with exactly: interrupt-now
110
+ --- from: assistant (TestBot)
111
+ ⬥ ok
112
+ *project ⋅ main ⋅ Ns ⋅ N% ⋅ deterministic-v2*
113
+ » **interrupt-tester:** Reply with exactly: queued-behind-slow
114
+ ⬥ ok
115
+ *project ⋅ main ⋅ Ns ⋅ N% ⋅ deterministic-v2*"
116
+ `);
117
+ // 7. Assert the interrupt message got its own ⬥ ok reply between the
118
+ // user's interrupt message and the queue dispatch indicator.
119
+ const text = await th.text();
120
+ const lines = text.split('\n');
121
+ const interruptUserLine = lines.findIndex((line) => {
122
+ return line.includes('Reply with exactly: interrupt-now');
123
+ });
124
+ expect(interruptUserLine).toBeGreaterThan(-1);
125
+ const queueDispatchLine = lines.findIndex((line) => {
126
+ return line.includes('» **interrupt-tester:** Reply with exactly: queued-behind-slow');
127
+ });
128
+ expect(queueDispatchLine).toBeGreaterThan(-1);
129
+ const linesBetween = lines.slice(interruptUserLine + 1, queueDispatchLine);
130
+ const hasInterruptReply = linesBetween.some((line) => {
131
+ return line.includes('⬥ ok');
132
+ });
133
+ expect(hasInterruptReply).toBe(true);
134
+ }, 20_000);
135
+ });
@@ -0,0 +1,120 @@
1
+ // E2e test: queued message must drain after the user answers a pending question
2
+ // via the Discord dropdown select menu. Reproduces a bug where answering via
3
+ // select (not text) leaves queued messages stuck because the session continues
4
+ // processing after the answer and may enter another blocking state.
5
+ import { describe, test, expect } from 'vitest';
6
+ import { setupQueueAdvancedSuite, TEST_USER_ID, } from './queue-advanced-e2e-setup.js';
7
+ import { waitForBotMessageContaining, waitForFooterMessage, } from './test-utils.js';
8
+ import { pendingQuestionContexts } from './commands/ask-question.js';
9
+ const TEXT_CHANNEL_ID = '200000000000001030';
10
+ async function waitForPendingQuestion({ threadId, timeoutMs, }) {
11
+ const start = Date.now();
12
+ while (Date.now() - start < timeoutMs) {
13
+ const entry = [...pendingQuestionContexts.entries()].find(([, context]) => {
14
+ return context.thread.id === threadId;
15
+ });
16
+ if (entry) {
17
+ return { contextHash: entry[0] };
18
+ }
19
+ await new Promise((resolve) => {
20
+ setTimeout(resolve, 100);
21
+ });
22
+ }
23
+ throw new Error('Timed out waiting for pending question context');
24
+ }
25
+ describe('queue drain after question select answer', () => {
26
+ const ctx = setupQueueAdvancedSuite({
27
+ channelId: TEXT_CHANNEL_ID,
28
+ channelName: 'qa-question-select-drain',
29
+ dirName: 'qa-question-select-drain',
30
+ username: 'question-select-tester',
31
+ });
32
+ test('queued message drains after answering question via dropdown select', async () => {
33
+ // 1. Send a message that triggers the question tool
34
+ await ctx.discord.channel(TEXT_CHANNEL_ID).user(TEST_USER_ID).sendMessage({
35
+ content: 'QUESTION_SELECT_QUEUE_MARKER',
36
+ });
37
+ const thread = await ctx.discord.channel(TEXT_CHANNEL_ID).waitForThread({
38
+ timeout: 8_000,
39
+ predicate: (t) => {
40
+ return t.name === 'QUESTION_SELECT_QUEUE_MARKER';
41
+ },
42
+ });
43
+ const th = ctx.discord.thread(thread.id);
44
+ // 2. Wait for the question dropdown message to appear in Discord.
45
+ // Uses visible message wait instead of internal Map polling which
46
+ // is too timing-sensitive on CI.
47
+ const questionMessages = await waitForBotMessageContaining({
48
+ discord: ctx.discord,
49
+ threadId: thread.id,
50
+ text: 'How to proceed?',
51
+ timeout: 12_000,
52
+ });
53
+ // Get the pending question context hash from the internal map.
54
+ // By this point the question message is visible so the context must exist.
55
+ const pending = (() => {
56
+ const entry = [...pendingQuestionContexts.entries()].find(([, context]) => {
57
+ return context.thread.id === thread.id;
58
+ });
59
+ return entry ? { contextHash: entry[0] } : null;
60
+ })();
61
+ expect(pending).toBeTruthy();
62
+ if (!pending) {
63
+ throw new Error('Expected pending question context');
64
+ }
65
+ const questionMsg = questionMessages.find((m) => {
66
+ return m.content.includes('How to proceed?');
67
+ });
68
+ expect(questionMsg).toBeTruthy();
69
+ // 3. Queue a message while question is pending
70
+ const { id: queueInteractionId } = await th.user(TEST_USER_ID)
71
+ .runSlashCommand({
72
+ name: 'queue',
73
+ options: [{ name: 'message', type: 3, value: 'Reply with exactly: post-question-drain' }],
74
+ });
75
+ const queueAck = await th.waitForInteractionAck({
76
+ interactionId: queueInteractionId,
77
+ timeout: 8_000,
78
+ });
79
+ if (!queueAck.messageId) {
80
+ throw new Error('Expected /queue response message id');
81
+ }
82
+ // 4. Answer the question via dropdown select (pick first option "Alpha")
83
+ const interaction = await th.user(TEST_USER_ID).selectMenu({
84
+ messageId: questionMsg.id,
85
+ customId: `ask_question:${pending.contextHash}:0`,
86
+ values: ['0'],
87
+ });
88
+ await th.waitForInteractionAck({
89
+ interactionId: interaction.id,
90
+ timeout: 8_000,
91
+ });
92
+ // 5. Queued message should be handed off to OpenCode's own prompt queue
93
+ // after the question reply, so the dispatch indicator appears without
94
+ // waiting for a later natural idle.
95
+ await waitForBotMessageContaining({
96
+ discord: ctx.discord,
97
+ threadId: thread.id,
98
+ text: '» **question-select-tester:** Reply with exactly: post-question-drain',
99
+ timeout: 8_000,
100
+ });
101
+ // 6. Wait for footer from the drained queued message
102
+ await waitForFooterMessage({
103
+ discord: ctx.discord,
104
+ threadId: thread.id,
105
+ timeout: 8_000,
106
+ afterMessageIncludes: '» **question-select-tester:**',
107
+ afterAuthorId: ctx.discord.botUserId,
108
+ });
109
+ // Assert key invariants instead of exact snapshot — on CI the deterministic
110
+ // matcher can fire a second time after the drained message (rawPromptIncludes
111
+ // scans full history), adding an extra question to the timeline.
112
+ const timeline = await th.text({ showInteractions: true });
113
+ expect(timeline).toContain('QUESTION_SELECT_QUEUE_MARKER');
114
+ expect(timeline).toContain('How to proceed?');
115
+ expect(timeline).toContain('[user selects dropdown: 0]');
116
+ expect(timeline).toContain('» **question-select-tester:** Reply with exactly: post-question-drain');
117
+ expect(timeline).toContain('⬥ ok');
118
+ expect(timeline).toContain('*project ⋅ main ⋅');
119
+ }, 20_000);
120
+ });
@@ -0,0 +1,52 @@
1
+ // Runtime inactivity sweeper.
2
+ // Periodically disposes thread runtimes that stayed idle past a timeout.
3
+ import { createLogger, LogPrefix } from './logger.js';
4
+ import { disposeInactiveRuntimes, } from './session-handler/thread-session-runtime.js';
5
+ const logger = createLogger(LogPrefix.SESSION);
6
+ // 24 hours — users often return the next day to click buttons/selects,
7
+ // so runtimes (and their in-memory context maps) must stay alive that long.
8
+ export const DEFAULT_RUNTIME_IDLE_MS = 24 * 60 * 60 * 1000;
9
+ export const DEFAULT_SWEEP_INTERVAL_MS = 60 * 1000;
10
+ export function startRuntimeIdleSweeper({ runtimeIdleMs = DEFAULT_RUNTIME_IDLE_MS, sweepIntervalMs = DEFAULT_SWEEP_INTERVAL_MS, } = {}) {
11
+ let stopped = false;
12
+ let sweeping = false;
13
+ let sweepPromise = null;
14
+ const sweep = async () => {
15
+ if (stopped || sweeping) {
16
+ return;
17
+ }
18
+ sweeping = true;
19
+ const currentSweepPromise = (async () => {
20
+ const nowMs = Date.now();
21
+ const disposeResult = disposeInactiveRuntimes({
22
+ idleMs: runtimeIdleMs,
23
+ nowMs,
24
+ });
25
+ if (disposeResult.disposedThreadIds.length > 0) {
26
+ logger.log(`[IDLE SWEEP] Disposed ${disposeResult.disposedThreadIds.length} inactive runtime(s) after ${runtimeIdleMs}ms`);
27
+ }
28
+ })();
29
+ sweepPromise = currentSweepPromise;
30
+ await currentSweepPromise.finally(() => {
31
+ sweeping = false;
32
+ sweepPromise = null;
33
+ });
34
+ };
35
+ const interval = setInterval(() => {
36
+ void sweep();
37
+ }, sweepIntervalMs);
38
+ void sweep();
39
+ logger.log(`[IDLE SWEEP] Started (runtimeIdleMs=${runtimeIdleMs}, intervalMs=${sweepIntervalMs})`);
40
+ return async () => {
41
+ if (stopped) {
42
+ return;
43
+ }
44
+ stopped = true;
45
+ clearInterval(interval);
46
+ if (sweepPromise) {
47
+ await sweepPromise;
48
+ sweepPromise = null;
49
+ }
50
+ logger.log('[IDLE SWEEP] Stopped');
51
+ };
52
+ }