@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,421 @@
1
+ // Scheduled task runner for executing due `send --send-at` jobs in the bot process.
2
+
3
+ import { type REST, Routes } from 'discord.js'
4
+ import { createDiscordRest } from './discord-urls.js'
5
+ import YAML from 'yaml'
6
+ import {
7
+ claimScheduledTaskRunning,
8
+ getDuePlannedScheduledTasks,
9
+ markScheduledTaskCronRescheduled,
10
+ markScheduledTaskCronRetry,
11
+ markScheduledTaskFailed,
12
+ markScheduledTaskOneShotCompleted,
13
+ recoverStaleRunningScheduledTasks,
14
+ type ScheduledTask,
15
+ } from './database.js'
16
+ import { createLogger, formatErrorWithStack, LogPrefix } from './logger.js'
17
+ import { notifyError } from './sentry.js'
18
+ import type { ThreadStartMarker } from './system-message.js'
19
+ import {
20
+ type ScheduledTaskPayload,
21
+ getNextCronRun,
22
+ getPromptPreview,
23
+ parseScheduledTaskPayload,
24
+ } from './task-schedule.js'
25
+
26
+ const taskLogger = createLogger(LogPrefix.TASK)
27
+
28
+ type StartTaskRunnerOptions = {
29
+ token: string
30
+ pollIntervalMs?: number
31
+ staleRunningMs?: number
32
+ dueBatchSize?: number
33
+ }
34
+
35
+ function isRecord(value: unknown): value is Record<string, unknown> {
36
+ return typeof value === 'object' && value !== null
37
+ }
38
+
39
+ function parseMessageId(value: unknown): string | Error {
40
+ if (!isRecord(value)) {
41
+ return new Error('Discord response is not an object')
42
+ }
43
+ if (typeof value.id !== 'string') {
44
+ return new Error('Discord response is missing message ID')
45
+ }
46
+ return value.id
47
+ }
48
+
49
+ async function executeThreadScheduledTask({
50
+ rest,
51
+ task,
52
+ payload,
53
+ }: {
54
+ rest: REST
55
+ task: ScheduledTask
56
+ payload: Extract<ScheduledTaskPayload, { kind: 'thread' }>
57
+ }): Promise<void | Error> {
58
+ const marker: ThreadStartMarker = {
59
+ start: true,
60
+ scheduledKind: task.schedule_kind,
61
+ scheduledTaskId: task.id,
62
+ ...(payload.agent ? { agent: payload.agent } : {}),
63
+ ...(payload.model ? { model: payload.model } : {}),
64
+ ...(payload.username ? { username: payload.username } : {}),
65
+ ...(payload.userId ? { userId: payload.userId } : {}),
66
+ ...(payload.permissions?.length ? { permissions: payload.permissions } : {}),
67
+ ...(payload.injectionGuardPatterns?.length
68
+ ? { injectionGuardPatterns: payload.injectionGuardPatterns }
69
+ : {}),
70
+ }
71
+ const embed = [{ color: 0x2b2d31, footer: { text: YAML.stringify(marker) } }]
72
+ // Newline between prefix and prompt so leading /command detection can
73
+ // find the command on its own line.
74
+ const prefixedPrompt = `» **kimaki-cli:**\n${payload.prompt}`
75
+
76
+ const postResult = await rest
77
+ .post(Routes.channelMessages(payload.threadId), {
78
+ body: {
79
+ content: prefixedPrompt,
80
+ embeds: embed,
81
+ },
82
+ })
83
+ .catch((error) => {
84
+ return new Error(`Failed to post scheduled thread task ${task.id}`, {
85
+ cause: error,
86
+ })
87
+ })
88
+
89
+ if (postResult instanceof Error) {
90
+ return postResult
91
+ }
92
+ }
93
+
94
+ async function executeChannelScheduledTask({
95
+ rest,
96
+ task,
97
+ payload,
98
+ }: {
99
+ rest: REST
100
+ task: ScheduledTask
101
+ payload: Extract<ScheduledTaskPayload, { kind: 'channel' }>
102
+ }): Promise<void | Error> {
103
+ const marker: ThreadStartMarker | undefined = payload.notifyOnly
104
+ ? undefined
105
+ : {
106
+ start: true,
107
+ scheduledKind: task.schedule_kind,
108
+ scheduledTaskId: task.id,
109
+ ...(payload.worktreeName ? { worktree: payload.worktreeName } : {}),
110
+ ...(payload.cwd ? { cwd: payload.cwd } : {}),
111
+ ...(payload.agent ? { agent: payload.agent } : {}),
112
+ ...(payload.model ? { model: payload.model } : {}),
113
+ ...(payload.username ? { username: payload.username } : {}),
114
+ ...(payload.userId ? { userId: payload.userId } : {}),
115
+ ...(payload.permissions?.length ? { permissions: payload.permissions } : {}),
116
+ ...(payload.injectionGuardPatterns?.length
117
+ ? { injectionGuardPatterns: payload.injectionGuardPatterns }
118
+ : {}),
119
+ }
120
+ const embeds = marker
121
+ ? [{ color: 0x2b2d31, footer: { text: YAML.stringify(marker) } }]
122
+ : undefined
123
+
124
+ const starterResult = await rest
125
+ .post(Routes.channelMessages(payload.channelId), {
126
+ body: {
127
+ content: payload.prompt,
128
+ embeds,
129
+ },
130
+ })
131
+ .catch((error) => {
132
+ return new Error(`Failed to create starter message for task ${task.id}`, {
133
+ cause: error,
134
+ })
135
+ })
136
+
137
+ if (starterResult instanceof Error) {
138
+ return starterResult
139
+ }
140
+
141
+ const starterMessageId = parseMessageId(starterResult)
142
+ if (starterMessageId instanceof Error) {
143
+ return new Error(`Invalid starter message response for task ${task.id}`, {
144
+ cause: starterMessageId,
145
+ })
146
+ }
147
+
148
+ const threadName = (payload.name || getPromptPreview(payload.prompt)).slice(
149
+ 0,
150
+ 100,
151
+ )
152
+ const threadResult = await rest
153
+ .post(Routes.threads(payload.channelId, starterMessageId), {
154
+ body: {
155
+ name: threadName,
156
+ auto_archive_duration: 1440,
157
+ },
158
+ })
159
+ .catch((error) => {
160
+ return new Error(`Failed to create thread for task ${task.id}`, {
161
+ cause: error,
162
+ })
163
+ })
164
+
165
+ if (threadResult instanceof Error) {
166
+ return threadResult
167
+ }
168
+
169
+ if (!payload.userId) {
170
+ return
171
+ }
172
+
173
+ const threadIdResult = parseMessageId(threadResult)
174
+ if (threadIdResult instanceof Error) {
175
+ return new Error(`Invalid thread response for task ${task.id}`, {
176
+ cause: threadIdResult,
177
+ })
178
+ }
179
+
180
+ const addMemberResult = await rest
181
+ .put(Routes.threadMembers(threadIdResult, payload.userId))
182
+ .catch((error) => {
183
+ return new Error(
184
+ `Failed to add user to scheduled thread for task ${task.id}`,
185
+ { cause: error },
186
+ )
187
+ })
188
+ if (addMemberResult instanceof Error) {
189
+ return addMemberResult
190
+ }
191
+ }
192
+
193
+ async function executeScheduledTask({
194
+ rest,
195
+ task,
196
+ }: {
197
+ rest: REST
198
+ task: ScheduledTask
199
+ }): Promise<void | Error> {
200
+ const payloadResult = parseScheduledTaskPayload(task.payload_json)
201
+ if (payloadResult instanceof Error) {
202
+ return new Error(`Task ${task.id} has invalid payload`, {
203
+ cause: payloadResult,
204
+ })
205
+ }
206
+
207
+ if (payloadResult.kind === 'thread') {
208
+ return executeThreadScheduledTask({
209
+ rest,
210
+ task,
211
+ payload: payloadResult,
212
+ })
213
+ }
214
+
215
+ return executeChannelScheduledTask({
216
+ rest,
217
+ task,
218
+ payload: payloadResult,
219
+ })
220
+ }
221
+
222
+ async function finalizeSuccessfulTask({
223
+ task,
224
+ completedAt,
225
+ }: {
226
+ task: ScheduledTask
227
+ completedAt: Date
228
+ }): Promise<void> {
229
+ if (task.schedule_kind === 'at') {
230
+ await markScheduledTaskOneShotCompleted({ taskId: task.id, completedAt })
231
+ return
232
+ }
233
+
234
+ if (!task.cron_expr) {
235
+ await markScheduledTaskFailed({
236
+ taskId: task.id,
237
+ failedAt: completedAt,
238
+ errorMessage: 'Missing cron expression on cron task',
239
+ })
240
+ return
241
+ }
242
+
243
+ // Use stored timezone, falling back to UTC (not machine local) for consistency
244
+ const timezone = task.timezone || 'UTC'
245
+ const nextRunResult = getNextCronRun({
246
+ cronExpr: task.cron_expr,
247
+ timezone,
248
+ from: completedAt,
249
+ })
250
+ if (nextRunResult instanceof Error) {
251
+ await markScheduledTaskFailed({
252
+ taskId: task.id,
253
+ failedAt: completedAt,
254
+ errorMessage: nextRunResult.message,
255
+ })
256
+ return
257
+ }
258
+
259
+ await markScheduledTaskCronRescheduled({
260
+ taskId: task.id,
261
+ completedAt,
262
+ nextRunAt: nextRunResult,
263
+ })
264
+ }
265
+
266
+ async function finalizeFailedTask({
267
+ task,
268
+ failedAt,
269
+ error,
270
+ }: {
271
+ task: ScheduledTask
272
+ failedAt: Date
273
+ error: Error
274
+ }): Promise<void> {
275
+ if (task.schedule_kind === 'cron' && task.cron_expr) {
276
+ // Use stored timezone, falling back to UTC (not machine local) for consistency
277
+ const timezone = task.timezone || 'UTC'
278
+ const nextRunResult = getNextCronRun({
279
+ cronExpr: task.cron_expr,
280
+ timezone,
281
+ from: failedAt,
282
+ })
283
+ if (!(nextRunResult instanceof Error)) {
284
+ await markScheduledTaskCronRetry({
285
+ taskId: task.id,
286
+ failedAt,
287
+ errorMessage: error.message,
288
+ nextRunAt: nextRunResult,
289
+ })
290
+ return
291
+ }
292
+ }
293
+
294
+ await markScheduledTaskFailed({
295
+ taskId: task.id,
296
+ failedAt,
297
+ errorMessage: error.message,
298
+ })
299
+ }
300
+
301
+ async function processDueTask({
302
+ rest,
303
+ task,
304
+ }: {
305
+ rest: REST
306
+ task: ScheduledTask
307
+ }): Promise<void> {
308
+ const startedAt = new Date()
309
+ const claimed = await claimScheduledTaskRunning({
310
+ taskId: task.id,
311
+ startedAt,
312
+ })
313
+ if (!claimed) {
314
+ return
315
+ }
316
+
317
+ const executeResult = await executeScheduledTask({ rest, task })
318
+ const finishedAt = new Date()
319
+
320
+ if (executeResult instanceof Error) {
321
+ taskLogger.warn(
322
+ `[task-runner] task ${task.id} failed: ${formatErrorWithStack(executeResult)}`,
323
+ )
324
+ await finalizeFailedTask({
325
+ task,
326
+ failedAt: finishedAt,
327
+ error: executeResult,
328
+ })
329
+ return
330
+ }
331
+
332
+ await finalizeSuccessfulTask({ task, completedAt: finishedAt })
333
+ }
334
+
335
+ async function runTaskRunnerTick({
336
+ rest,
337
+ staleRunningMs,
338
+ dueBatchSize,
339
+ }: {
340
+ rest: REST
341
+ staleRunningMs: number
342
+ dueBatchSize: number
343
+ }): Promise<void> {
344
+ const staleBefore = new Date(Date.now() - staleRunningMs)
345
+ const recoveredCount = await recoverStaleRunningScheduledTasks({
346
+ staleBefore,
347
+ })
348
+ if (recoveredCount > 0) {
349
+ taskLogger.warn(
350
+ `[task-runner] Recovered ${recoveredCount} stale running task(s)`,
351
+ )
352
+ }
353
+
354
+ const dueTasks = await getDuePlannedScheduledTasks({
355
+ now: new Date(),
356
+ limit: dueBatchSize,
357
+ })
358
+
359
+ await dueTasks.reduce<Promise<void>>(async (previous, task) => {
360
+ await previous
361
+ await processDueTask({ rest, task })
362
+ }, Promise.resolve())
363
+ }
364
+
365
+ export function startTaskRunner({
366
+ token,
367
+ pollIntervalMs = 5_000,
368
+ staleRunningMs = 120_000,
369
+ dueBatchSize = 20,
370
+ }: StartTaskRunnerOptions): () => Promise<void> {
371
+ const rest = createDiscordRest(token)
372
+ let stopped = false
373
+ let ticking = false
374
+ let tickPromise: Promise<void> | null = null
375
+
376
+ const tick = async () => {
377
+ if (stopped || ticking) {
378
+ return
379
+ }
380
+
381
+ ticking = true
382
+ const currentTickPromise = runTaskRunnerTick({
383
+ rest,
384
+ staleRunningMs,
385
+ dueBatchSize,
386
+ }).catch((error) => {
387
+ return new Error('Task runner tick failed', { cause: error })
388
+ })
389
+ tickPromise = currentTickPromise.then(() => {
390
+ return
391
+ })
392
+ const runResult = await currentTickPromise
393
+ if (runResult instanceof Error) {
394
+ taskLogger.error(`[task-runner] ${formatErrorWithStack(runResult)}`)
395
+ void notifyError(runResult, 'Task runner tick failed')
396
+ }
397
+ ticking = false
398
+ tickPromise = null
399
+ }
400
+
401
+ const timer = setInterval(() => {
402
+ void tick()
403
+ }, pollIntervalMs)
404
+
405
+ void tick()
406
+
407
+ taskLogger.log(`[task-runner] started (interval=${pollIntervalMs}ms)`)
408
+
409
+ return async () => {
410
+ if (stopped) {
411
+ return
412
+ }
413
+ stopped = true
414
+ clearInterval(timer)
415
+ if (tickPromise) {
416
+ await tickPromise
417
+ tickPromise = null
418
+ }
419
+ taskLogger.log('[task-runner] stopped')
420
+ }
421
+ }
@@ -0,0 +1,84 @@
1
+ // Tests for scheduled task date/cron parsing and UTC validation rules.
2
+
3
+ import { describe, expect, test } from 'vitest'
4
+ import { parseSendAtValue } from './task-schedule.js'
5
+
6
+ describe('parseSendAtValue', () => {
7
+ test('accepts UTC ISO date ending with Z', () => {
8
+ const now = new Date('2026-02-22T13:00:00Z')
9
+ const result = parseSendAtValue({
10
+ value: '2026-03-01T09:00:00Z',
11
+ now,
12
+ timezone: 'UTC',
13
+ })
14
+
15
+ expect(result).not.toBeInstanceOf(Error)
16
+ if (result instanceof Error) {
17
+ throw result
18
+ }
19
+
20
+ expect(result.scheduleKind).toBe('at')
21
+ expect(result.runAt?.toISOString()).toBe('2026-03-01T09:00:00.000Z')
22
+ expect(result.nextRunAt.toISOString()).toBe('2026-03-01T09:00:00.000Z')
23
+ })
24
+
25
+ test('rejects ISO date with non-UTC offset', () => {
26
+ const now = new Date('2026-02-22T13:00:00Z')
27
+ const result = parseSendAtValue({
28
+ value: '2026-03-01T09:00:00+01:00',
29
+ now,
30
+ timezone: 'UTC',
31
+ })
32
+
33
+ expect(result).toBeInstanceOf(Error)
34
+ if (result instanceof Error) {
35
+ expect(result.message).toContain('must be UTC ISO format ending with Z')
36
+ }
37
+ })
38
+
39
+ test('rejects local ISO date without timezone suffix', () => {
40
+ const now = new Date('2026-02-22T13:00:00Z')
41
+ const result = parseSendAtValue({
42
+ value: '2026-03-01T09:00:00',
43
+ now,
44
+ timezone: 'UTC',
45
+ })
46
+
47
+ expect(result).toBeInstanceOf(Error)
48
+ if (result instanceof Error) {
49
+ expect(result.message).toContain('must be UTC ISO format ending with Z')
50
+ }
51
+ })
52
+
53
+ test('rejects UTC dates in the past', () => {
54
+ const now = new Date('2026-02-22T13:00:00Z')
55
+ const result = parseSendAtValue({
56
+ value: '2026-02-22T12:59:59Z',
57
+ now,
58
+ timezone: 'UTC',
59
+ })
60
+
61
+ expect(result).toBeInstanceOf(Error)
62
+ if (result instanceof Error) {
63
+ expect(result.message).toContain('must be in the future (UTC)')
64
+ }
65
+ })
66
+
67
+ test('accepts cron expressions', () => {
68
+ const now = new Date('2026-02-22T13:00:00Z')
69
+ const result = parseSendAtValue({
70
+ value: '0 9 * * 1',
71
+ now,
72
+ timezone: 'UTC',
73
+ })
74
+
75
+ expect(result).not.toBeInstanceOf(Error)
76
+ if (result instanceof Error) {
77
+ throw result
78
+ }
79
+
80
+ expect(result.scheduleKind).toBe('cron')
81
+ expect(result.cronExpr).toBe('0 9 * * 1')
82
+ expect(result.nextRunAt.toISOString()).toBe('2026-02-23T09:00:00.000Z')
83
+ })
84
+ })