@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,198 @@
1
+ // User-defined OpenCode command handler.
2
+ // Handles slash commands that map to user-configured commands in opencode.json.
3
+
4
+ import type { CommandContext, CommandHandler } from './types.js'
5
+ import {
6
+ ChannelType,
7
+ MessageFlags,
8
+ type TextChannel,
9
+ type ThreadChannel,
10
+ } from 'discord.js'
11
+ import { getOrCreateRuntime } from '../session-handler/thread-session-runtime.js'
12
+ import { SILENT_MESSAGE_FLAGS } from '../discord-utils.js'
13
+ import { createLogger, LogPrefix } from '../logger.js'
14
+ import { getChannelDirectory, getThreadSession } from '../database.js'
15
+ import { store } from '../store.js'
16
+ import fs from 'node:fs'
17
+
18
+ const userCommandLogger = createLogger(LogPrefix.USER_CMD)
19
+ const DISCORD_MESSAGE_LIMIT = 2000
20
+ const DISCORD_THREAD_NAME_LIMIT = 100
21
+
22
+ export const handleUserCommand: CommandHandler = async ({
23
+ command,
24
+ appId,
25
+ }: CommandContext) => {
26
+ const discordCommandName = command.commandName
27
+ // Look up the original OpenCode command name from the mapping populated at registration.
28
+ // The sanitized Discord name is lossy (e.g. foo:bar → foo-bar), so resolving from
29
+ // the exact registered slash command name avoids collisions.
30
+ const registered = store.getState().registeredUserCommands.find(
31
+ (c) => c.discordCommandName === discordCommandName,
32
+ )
33
+ const fallbackBase = discordCommandName.replace(/-(cmd|skill|mcp-prompt)$/, '')
34
+ const commandName = registered?.name || fallbackBase
35
+ const args = command.options.getString('arguments') || ''
36
+ const commandInvocation = args ? `/${commandName} ${args}` : `/${commandName}`
37
+ const threadOpeningMessage =
38
+ commandInvocation.length <= DISCORD_MESSAGE_LIMIT
39
+ ? commandInvocation
40
+ : `${commandInvocation.slice(0, DISCORD_MESSAGE_LIMIT - 14)}... truncated`
41
+
42
+ userCommandLogger.log(
43
+ `Executing /${commandName} (from /${discordCommandName}) argsLength=${args.length}`,
44
+ )
45
+
46
+ const channel = command.channel
47
+
48
+ userCommandLogger.log(
49
+ `Channel info: type=${channel?.type}, id=${channel?.id}, isNull=${channel === null}`,
50
+ )
51
+
52
+ const isThread =
53
+ channel &&
54
+ [
55
+ ChannelType.PublicThread,
56
+ ChannelType.PrivateThread,
57
+ ChannelType.AnnouncementThread,
58
+ ].includes(channel.type)
59
+
60
+ const isTextChannel = channel?.type === ChannelType.GuildText
61
+
62
+ if (!channel || (!isTextChannel && !isThread)) {
63
+ await command.reply({
64
+ content: 'This command can only be used in text channels or threads',
65
+ flags: MessageFlags.Ephemeral,
66
+ })
67
+ return
68
+ }
69
+
70
+ let projectDirectory: string | undefined
71
+ let textChannel: TextChannel | null = null
72
+ let thread: ThreadChannel | null = null
73
+
74
+ if (isThread) {
75
+ // Running in an existing thread - get project directory from parent channel
76
+ thread = channel as ThreadChannel
77
+ textChannel = thread.parent as TextChannel | null
78
+
79
+ // Verify this thread has an existing session
80
+ const sessionId = await getThreadSession(thread.id)
81
+
82
+ if (!sessionId) {
83
+ await command.reply({
84
+ content:
85
+ 'This thread does not have an active session. Use this command in a project channel to create a new thread.',
86
+ flags: MessageFlags.Ephemeral,
87
+ })
88
+ return
89
+ }
90
+
91
+ if (textChannel) {
92
+ const channelConfig = await getChannelDirectory(textChannel.id)
93
+ projectDirectory = channelConfig?.directory
94
+ }
95
+ } else {
96
+ // Running in a text channel - will create a new thread
97
+ textChannel = channel as TextChannel
98
+
99
+ const channelConfig = await getChannelDirectory(textChannel.id)
100
+ projectDirectory = channelConfig?.directory
101
+ }
102
+
103
+ if (!projectDirectory) {
104
+ await command.reply({
105
+ content: 'This channel is not configured with a project directory',
106
+ flags: MessageFlags.Ephemeral,
107
+ })
108
+ return
109
+ }
110
+
111
+ if (!fs.existsSync(projectDirectory)) {
112
+ await command.reply({
113
+ content: `Directory does not exist: ${projectDirectory}`,
114
+ flags: MessageFlags.Ephemeral,
115
+ })
116
+ return
117
+ }
118
+
119
+ await command.deferReply()
120
+
121
+ try {
122
+ // Use the dedicated session.command API instead of formatting as text prompt
123
+ const commandPayload = { name: commandName, arguments: args }
124
+
125
+ if (isThread && thread) {
126
+ // Running in existing thread - just send the command
127
+ await command.editReply(`Running ${commandInvocation}...`)
128
+
129
+ const runtime = getOrCreateRuntime({
130
+ threadId: thread.id,
131
+ thread,
132
+ projectDirectory,
133
+ sdkDirectory: projectDirectory,
134
+ channelId: textChannel?.id,
135
+ appId,
136
+ })
137
+ await runtime.enqueueIncoming({
138
+ prompt: '',
139
+ userId: command.user.id,
140
+ username: command.user.displayName,
141
+ command: commandPayload,
142
+ appId,
143
+ mode: 'local-queue',
144
+ })
145
+ } else if (textChannel) {
146
+ // Running in text channel - create a new thread
147
+ const starterMessage = await textChannel.send({
148
+ content: threadOpeningMessage,
149
+ flags: SILENT_MESSAGE_FLAGS,
150
+ })
151
+
152
+ const newThread = await starterMessage.startThread({
153
+ name: commandInvocation.slice(0, DISCORD_THREAD_NAME_LIMIT),
154
+ autoArchiveDuration: 1440,
155
+ reason: `OpenCode command: ${commandName}`,
156
+ })
157
+
158
+ // Add user to thread so it appears in their sidebar
159
+ await newThread.members.add(command.user.id)
160
+
161
+ await command.editReply(
162
+ `Started /${commandName} in ${newThread.toString()}`,
163
+ )
164
+
165
+ const runtime = getOrCreateRuntime({
166
+ threadId: newThread.id,
167
+ thread: newThread,
168
+ projectDirectory,
169
+ sdkDirectory: projectDirectory,
170
+ channelId: textChannel.id,
171
+ appId,
172
+ })
173
+ await runtime.enqueueIncoming({
174
+ prompt: '',
175
+ userId: command.user.id,
176
+ username: command.user.displayName,
177
+ command: commandPayload,
178
+ appId,
179
+ mode: 'local-queue',
180
+ })
181
+ }
182
+ } catch (error) {
183
+ userCommandLogger.error(`Error executing /${commandName}:`, error)
184
+
185
+ const errorMessage = error instanceof Error ? error.message : String(error)
186
+
187
+ if (command.deferred) {
188
+ await command.editReply({
189
+ content: `Failed to execute /${commandName}: ${errorMessage}`,
190
+ })
191
+ } else {
192
+ await command.reply({
193
+ content: `Failed to execute /${commandName}: ${errorMessage}`,
194
+ flags: MessageFlags.Ephemeral,
195
+ })
196
+ }
197
+ }
198
+ }
@@ -0,0 +1,173 @@
1
+ // /verbosity command.
2
+ // Shows a dropdown to set output verbosity level for sessions in a channel.
3
+ // 'text_and_essential_tools' (default): shows text and essential tools (edits, custom MCP tools)
4
+ // 'tools_and_text': shows all output including tool executions
5
+ // 'text_only': only shows text responses
6
+
7
+ import {
8
+ ChatInputCommandInteraction,
9
+ StringSelectMenuInteraction,
10
+ StringSelectMenuBuilder,
11
+ ActionRowBuilder,
12
+ MessageFlags,
13
+ ChannelType,
14
+ type ThreadChannel,
15
+ } from 'discord.js'
16
+ import {
17
+ getChannelVerbosity,
18
+ setChannelVerbosity,
19
+ type VerbosityLevel,
20
+ } from '../database.js'
21
+ import { getPrisma } from '../db.js'
22
+ import { store } from '../store.js'
23
+ import { createLogger, LogPrefix } from '../logger.js'
24
+
25
+ const verbosityLogger = createLogger(LogPrefix.VERBOSITY)
26
+
27
+ const VERBOSITY_OPTIONS: Array<{
28
+ value: VerbosityLevel
29
+ label: string
30
+ description: string
31
+ }> = [
32
+ {
33
+ value: 'tools_and_text',
34
+ label: 'Tools and text',
35
+ description: 'All output including tool executions and status messages',
36
+ },
37
+ {
38
+ value: 'text_and_essential_tools',
39
+ label: 'Text and essential tools',
40
+ description: 'Text + essential tools (edits, custom MCP). Hides read/search.',
41
+ },
42
+ {
43
+ value: 'text_only',
44
+ label: 'Text only',
45
+ description: 'Only text responses. Hides all tools and status messages.',
46
+ },
47
+ ]
48
+
49
+ function resolveChannelId(channel: ChatInputCommandInteraction['channel']): string | null {
50
+ if (!channel) {
51
+ return null
52
+ }
53
+ if (channel.type === ChannelType.GuildText) {
54
+ return channel.id
55
+ }
56
+ if (
57
+ channel.type === ChannelType.PublicThread ||
58
+ channel.type === ChannelType.PrivateThread ||
59
+ channel.type === ChannelType.AnnouncementThread
60
+ ) {
61
+ return (channel as ThreadChannel).parentId || channel.id
62
+ }
63
+ return channel.id
64
+ }
65
+
66
+ /**
67
+ * Check if there is a per-channel verbosity override in the DB.
68
+ * Returns the override value if it exists, null otherwise.
69
+ */
70
+ async function getChannelVerbosityOverride(
71
+ channelId: string,
72
+ ): Promise<VerbosityLevel | null> {
73
+ const prisma = await getPrisma()
74
+ const row = await prisma.channel_verbosity.findUnique({
75
+ where: { channel_id: channelId },
76
+ })
77
+ if (row?.verbosity) {
78
+ return row.verbosity as VerbosityLevel
79
+ }
80
+ return null
81
+ }
82
+
83
+ /**
84
+ * Handle the /verbosity slash command.
85
+ * Shows a dropdown with the current verbosity level and available options.
86
+ */
87
+ export async function handleVerbosityCommand({
88
+ command,
89
+ }: {
90
+ command: ChatInputCommandInteraction
91
+ appId: string
92
+ }): Promise<void> {
93
+ verbosityLogger.log('[VERBOSITY] Command called')
94
+
95
+ const channelId = resolveChannelId(command.channel)
96
+ if (!channelId) {
97
+ await command.reply({
98
+ content: 'Could not determine channel.',
99
+ flags: MessageFlags.Ephemeral,
100
+ })
101
+ return
102
+ }
103
+
104
+ const override = await getChannelVerbosityOverride(channelId)
105
+ const currentLevel = override || store.getState().defaultVerbosity
106
+ const source = override ? 'channel override' : 'global default'
107
+
108
+ const options = VERBOSITY_OPTIONS.map((opt) => ({
109
+ label: opt.label,
110
+ value: opt.value,
111
+ description: opt.description,
112
+ default: opt.value === currentLevel,
113
+ }))
114
+
115
+ const selectMenu = new StringSelectMenuBuilder()
116
+ .setCustomId(`verbosity_select:${channelId}`)
117
+ .setPlaceholder('Select verbosity level')
118
+ .addOptions(options)
119
+
120
+ const actionRow =
121
+ new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(selectMenu)
122
+
123
+ await command.reply({
124
+ content: `**Verbosity**\nCurrent: \`${currentLevel}\` (${source})`,
125
+ components: [actionRow],
126
+ flags: MessageFlags.Ephemeral,
127
+ })
128
+ }
129
+
130
+ /**
131
+ * Handle the verbosity select menu interaction.
132
+ * Sets the selected verbosity level for the channel.
133
+ */
134
+ export async function handleVerbositySelectMenu(
135
+ interaction: StringSelectMenuInteraction,
136
+ ): Promise<void> {
137
+ const customId = interaction.customId
138
+ if (!customId.startsWith('verbosity_select:')) {
139
+ return
140
+ }
141
+
142
+ await interaction.deferUpdate()
143
+
144
+ const channelId = customId.replace('verbosity_select:', '')
145
+ const level = interaction.values[0] as VerbosityLevel | undefined
146
+
147
+ if (!level) {
148
+ await interaction.editReply({
149
+ content: 'No level selected.',
150
+ components: [],
151
+ })
152
+ return
153
+ }
154
+
155
+ const currentLevel = await getChannelVerbosity(channelId)
156
+ if (currentLevel === level) {
157
+ await interaction.editReply({
158
+ content: `Verbosity is already \`${level}\` for this channel.`,
159
+ components: [],
160
+ })
161
+ return
162
+ }
163
+
164
+ await setChannelVerbosity(channelId, level)
165
+ verbosityLogger.log(`[VERBOSITY] Set channel ${channelId} to ${level}`)
166
+
167
+ const description = VERBOSITY_OPTIONS.find((o) => o.value === level)?.description || ''
168
+
169
+ await interaction.editReply({
170
+ content: `Verbosity set to \`${level}\` for this channel.\n${description}\nApplies immediately, including active sessions.`,
171
+ components: [],
172
+ })
173
+ }
@@ -0,0 +1,70 @@
1
+ // /toggle-worktrees command.
2
+ // Allows per-channel opt-in for automatic worktree creation,
3
+ // as an alternative to the global --use-worktrees CLI flag.
4
+
5
+ import {
6
+ ChatInputCommandInteraction,
7
+ MessageFlags,
8
+ ChannelType,
9
+ type TextChannel,
10
+ } from 'discord.js'
11
+ import {
12
+ getChannelWorktreesEnabled,
13
+ setChannelWorktreesEnabled,
14
+ } from '../database.js'
15
+ import { getKimakiMetadata } from '../discord-utils.js'
16
+ import { createLogger, LogPrefix } from '../logger.js'
17
+
18
+ const worktreeSettingsLogger = createLogger(LogPrefix.WORKTREE)
19
+
20
+ /**
21
+ * Handle the /toggle-worktrees slash command.
22
+ * Toggles automatic worktree creation for new sessions in this channel.
23
+ */
24
+ export async function handleToggleWorktreesCommand({
25
+ command,
26
+ }: {
27
+ command: ChatInputCommandInteraction
28
+ appId: string
29
+ }): Promise<void> {
30
+ worktreeSettingsLogger.log('[TOGGLE_WORKTREES] Command called')
31
+
32
+ const channel = command.channel
33
+
34
+ if (!channel || channel.type !== ChannelType.GuildText) {
35
+ await command.reply({
36
+ content: 'This command can only be used in text channels (not threads).',
37
+ flags: MessageFlags.Ephemeral,
38
+ })
39
+ return
40
+ }
41
+
42
+ const textChannel = channel as TextChannel
43
+ const metadata = await getKimakiMetadata(textChannel)
44
+
45
+ if (!metadata.projectDirectory) {
46
+ await command.reply({
47
+ content:
48
+ 'This channel is not configured with a project directory.\nUse `/add-project` to set up this channel.',
49
+ flags: MessageFlags.Ephemeral,
50
+ })
51
+ return
52
+ }
53
+
54
+ const wasEnabled = await getChannelWorktreesEnabled(textChannel.id)
55
+ const nextEnabled = !wasEnabled
56
+ await setChannelWorktreesEnabled(textChannel.id, nextEnabled)
57
+
58
+ const nextLabel = nextEnabled ? 'enabled' : 'disabled'
59
+
60
+ worktreeSettingsLogger.log(
61
+ `[TOGGLE_WORKTREES] ${nextLabel.toUpperCase()} for channel ${textChannel.id}`,
62
+ )
63
+
64
+ await command.reply({
65
+ content: nextEnabled
66
+ ? `Worktrees **enabled** for this channel.\n\nNew sessions started from messages in **#${textChannel.name}** will now automatically create git worktrees.\n\nNew setting for **#${textChannel.name}**: **enabled**.`
67
+ : `Worktrees **disabled** for this channel.\n\nNew sessions started from messages in **#${textChannel.name}** will use the main project directory.\n\nNew setting for **#${textChannel.name}**: **disabled**.`,
68
+ flags: MessageFlags.Ephemeral,
69
+ })
70
+ }