@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,445 @@
1
+ // Markdown table formatter for Discord.
2
+ // Converts GFM tables to Discord Components V2 (ContainerBuilder with TextDisplay
3
+ // key-value pairs and Separators between row groups). Large tables are split
4
+ // across multiple Container components to stay within the 40-component limit.
5
+
6
+ import { Lexer, type Token, type Tokens } from 'marked'
7
+ import {
8
+ ButtonStyle,
9
+ ComponentType,
10
+ SeparatorSpacingSize,
11
+ type APIActionRowComponent,
12
+ type APIButtonComponent,
13
+ type APIContainerComponent,
14
+ type APITextDisplayComponent,
15
+ type APISeparatorComponent,
16
+ type APIMessageTopLevelComponent,
17
+ } from 'discord.js'
18
+ import {
19
+ parseInlineHtmlRenderables,
20
+ type HtmlButtonRenderable,
21
+ type HtmlRenderable,
22
+ } from './html-components.js'
23
+
24
+ export type ContentSegment =
25
+ | { type: 'text'; text: string }
26
+ | { type: 'components'; components: APIMessageTopLevelComponent[] }
27
+
28
+ type TableRenderOptions = {
29
+ resolveButtonCustomId?: ({
30
+ button,
31
+ }: {
32
+ button: HtmlButtonRenderable
33
+ }) => string | Error
34
+ }
35
+
36
+ type RenderedTableCell =
37
+ | { type: 'text'; text: string }
38
+ | {
39
+ type: 'button'
40
+ label: string
41
+ customId: string
42
+ variant: HtmlButtonRenderable['variant']
43
+ disabled: boolean
44
+ }
45
+
46
+ type RenderedTableRow = {
47
+ components: Array<
48
+ APITextDisplayComponent | APIActionRowComponent<APIButtonComponent>
49
+ >
50
+ componentCost: number
51
+ }
52
+
53
+ // Max 40 components per message (nested components count toward the limit).
54
+ // Row cost is dynamic now because a table row can render as a plain TextDisplay
55
+ // or as a TextDisplay plus an Action Row holding one or more buttons.
56
+ const MAX_COMPONENTS = 40
57
+
58
+ /**
59
+ * Split markdown into text and table component segments.
60
+ * Tables are rendered as CV2 Container components with bold key-value TextDisplay
61
+ * pairs. Large tables are split across multiple component segments.
62
+ */
63
+ export function splitTablesFromMarkdown(
64
+ markdown: string,
65
+ options: TableRenderOptions = {},
66
+ ): ContentSegment[] {
67
+ const lexer = new Lexer()
68
+ const tokens = lexer.lex(markdown)
69
+ const segments: ContentSegment[] = []
70
+ let textBuffer = ''
71
+
72
+ for (const token of tokens) {
73
+ if (token.type === 'table') {
74
+ if (textBuffer.trim()) {
75
+ segments.push({ type: 'text', text: textBuffer })
76
+ textBuffer = ''
77
+ }
78
+ const componentSegments = buildTableComponents(token as Tokens.Table, options)
79
+ segments.push(...componentSegments)
80
+ } else {
81
+ textBuffer += token.raw
82
+ }
83
+ }
84
+
85
+ if (textBuffer.trim()) {
86
+ segments.push({ type: 'text', text: textBuffer })
87
+ }
88
+
89
+ return segments
90
+ }
91
+
92
+ /**
93
+ * Build CV2 components for a table. Plain rows render as one TextDisplay with
94
+ * bold key-value lines. Rows with resolved button cells render as a TextDisplay
95
+ * plus an Action Row so wide tables do not violate Section's 1-3 text child
96
+ * limit. Large tables are split into multiple Containers using a dynamic
97
+ * component-budget check.
98
+ */
99
+ export function buildTableComponents(
100
+ table: Tokens.Table,
101
+ options: TableRenderOptions = {},
102
+ ): ContentSegment[] {
103
+ const headers = table.header.map((cell) => {
104
+ return extractCellText(cell.tokens)
105
+ })
106
+ const rows = table.rows.map((row) => {
107
+ return buildRenderedRow({
108
+ headers,
109
+ row,
110
+ options,
111
+ })
112
+ })
113
+
114
+ const chunks = chunkRowsByComponentLimit({ rows })
115
+
116
+ return chunks.map((chunkRows) => {
117
+ const children: Array<
118
+ | APITextDisplayComponent
119
+ | APIActionRowComponent<APIButtonComponent>
120
+ | APISeparatorComponent
121
+ > = []
122
+
123
+ for (let i = 0; i < chunkRows.length; i++) {
124
+ if (i > 0) {
125
+ children.push({
126
+ type: ComponentType.Separator,
127
+ divider: true,
128
+ spacing: SeparatorSpacingSize.Small,
129
+ })
130
+ }
131
+ children.push(...chunkRows[i]!.components)
132
+ }
133
+
134
+ const container: APIContainerComponent = {
135
+ type: ComponentType.Container,
136
+ components: children,
137
+ }
138
+
139
+ return {
140
+ type: 'components' as const,
141
+ components: [container] as APIMessageTopLevelComponent[],
142
+ }
143
+ })
144
+ }
145
+
146
+ function buildRenderedRow({
147
+ headers,
148
+ row,
149
+ options,
150
+ }: {
151
+ headers: string[]
152
+ row: Tokens.TableCell[]
153
+ options: TableRenderOptions
154
+ }): RenderedTableRow {
155
+ const renderedCells = row.map((cell) => {
156
+ return renderTableCell({ cell, options })
157
+ })
158
+ const buttonCellCount = renderedCells.filter((cell) => {
159
+ return cell.type === 'button'
160
+ }).length
161
+
162
+ if (buttonCellCount > 0) {
163
+ return buildButtonRow({
164
+ headers,
165
+ cells: renderedCells,
166
+ })
167
+ }
168
+
169
+ return buildTextRow({
170
+ headers,
171
+ cells: renderedCells,
172
+ })
173
+ }
174
+
175
+ function buildTextRow({
176
+ headers,
177
+ cells,
178
+ }: {
179
+ headers: string[]
180
+ cells: RenderedTableCell[]
181
+ }): RenderedTableRow {
182
+ const lines = headers.map((key, index) => {
183
+ const cell = cells[index]
184
+ const value = cell ? getRenderedCellText({ cell }) : ''
185
+ return `**${key}** ${value}`
186
+ })
187
+
188
+ return {
189
+ components: [
190
+ {
191
+ type: ComponentType.TextDisplay,
192
+ content: lines.join('\n'),
193
+ },
194
+ ],
195
+ componentCost: 1,
196
+ }
197
+ }
198
+
199
+ function buildButtonRow({
200
+ headers,
201
+ cells,
202
+ }: {
203
+ headers: string[]
204
+ cells: RenderedTableCell[]
205
+ }): RenderedTableRow {
206
+ const buttonCells = cells.filter((cell) => {
207
+ return cell.type === 'button'
208
+ })
209
+ if (buttonCells.length === 0 || buttonCells.length > 5) {
210
+ return buildTextRow({ headers, cells })
211
+ }
212
+
213
+ const lines = headers.flatMap((header, index) => {
214
+ const cell = cells[index]
215
+ if (!cell || cell.type === 'button') {
216
+ return []
217
+ }
218
+
219
+ return [`**${header}** ${cell.text}`]
220
+ })
221
+ if (lines.length === 0) {
222
+ return buildTextRow({ headers, cells })
223
+ }
224
+
225
+ const buttons: APIButtonComponent[] = buttonCells.map((buttonCell) => {
226
+ return {
227
+ type: ComponentType.Button,
228
+ custom_id: buttonCell.customId,
229
+ label: buttonCell.label,
230
+ style: toButtonStyle({ variant: buttonCell.variant }),
231
+ disabled: buttonCell.disabled,
232
+ }
233
+ })
234
+
235
+ const actionRow: APIActionRowComponent<APIButtonComponent> = {
236
+ type: ComponentType.ActionRow,
237
+ components: buttons,
238
+ }
239
+
240
+ return {
241
+ components: [
242
+ {
243
+ type: ComponentType.TextDisplay,
244
+ content: lines.join('\n'),
245
+ },
246
+ actionRow,
247
+ ],
248
+ componentCost: 2 + buttons.length,
249
+ }
250
+ }
251
+
252
+ function chunkRowsByComponentLimit({
253
+ rows,
254
+ }: {
255
+ rows: RenderedTableRow[]
256
+ }): RenderedTableRow[][] {
257
+ const chunks: RenderedTableRow[][] = []
258
+ let currentChunk: RenderedTableRow[] = []
259
+ let currentCost = 1
260
+
261
+ for (const row of rows) {
262
+ const separatorCost = currentChunk.length > 0 ? 1 : 0
263
+ const nextCost = currentCost + separatorCost + row.componentCost
264
+
265
+ if (currentChunk.length > 0 && nextCost > MAX_COMPONENTS) {
266
+ chunks.push(currentChunk)
267
+ currentChunk = [row]
268
+ currentCost = 1 + row.componentCost
269
+ continue
270
+ }
271
+
272
+ currentChunk.push(row)
273
+ currentCost = nextCost
274
+ }
275
+
276
+ if (currentChunk.length > 0) {
277
+ chunks.push(currentChunk)
278
+ }
279
+
280
+ return chunks
281
+ }
282
+
283
+ function renderTableCell({
284
+ cell,
285
+ options,
286
+ }: {
287
+ cell: Tokens.TableCell
288
+ options: TableRenderOptions
289
+ }): RenderedTableCell {
290
+ const hasHtmlToken = cell.tokens.some((token) => {
291
+ return token.type === 'html'
292
+ })
293
+ if (!hasHtmlToken) {
294
+ return {
295
+ type: 'text',
296
+ text: extractCellText(cell.tokens),
297
+ }
298
+ }
299
+
300
+ const renderables = parseInlineHtmlRenderables({ html: cell.text })
301
+ if (renderables instanceof Error) {
302
+ return {
303
+ type: 'text',
304
+ text: extractRenderableText({ renderables: undefined, fallbackText: cell.text }),
305
+ }
306
+ }
307
+
308
+ const buttonRenderables = renderables.filter((renderable) => {
309
+ return renderable.type === 'button'
310
+ })
311
+ if (buttonRenderables.length !== 1) {
312
+ return {
313
+ type: 'text',
314
+ text: extractRenderableText({ renderables, fallbackText: cell.text }),
315
+ }
316
+ }
317
+
318
+ const hasNonWhitespaceText = renderables.some((renderable) => {
319
+ if (renderable.type !== 'text') {
320
+ return false
321
+ }
322
+ return renderable.text.trim().length > 0
323
+ })
324
+ if (hasNonWhitespaceText) {
325
+ return {
326
+ type: 'text',
327
+ text: extractRenderableText({ renderables, fallbackText: cell.text }),
328
+ }
329
+ }
330
+
331
+ const button = buttonRenderables[0]!
332
+ const customId = options.resolveButtonCustomId?.({ button })
333
+ if (!customId || customId instanceof Error) {
334
+ return {
335
+ type: 'text',
336
+ text: button.label,
337
+ }
338
+ }
339
+
340
+ return {
341
+ type: 'button',
342
+ label: button.label,
343
+ customId,
344
+ variant: button.variant,
345
+ disabled: button.disabled,
346
+ }
347
+ }
348
+
349
+ function getRenderedCellText({
350
+ cell,
351
+ }: {
352
+ cell: RenderedTableCell
353
+ }): string {
354
+ if (cell.type === 'button') {
355
+ return cell.label
356
+ }
357
+ return cell.text
358
+ }
359
+
360
+ function extractRenderableText({
361
+ renderables,
362
+ fallbackText,
363
+ }: {
364
+ renderables?: HtmlRenderable[]
365
+ fallbackText: string
366
+ }): string {
367
+ if (!renderables) {
368
+ return fallbackText.replace(/\s+/g, ' ').trim()
369
+ }
370
+
371
+ const text = renderables
372
+ .map((renderable) => {
373
+ if (renderable.type === 'button') {
374
+ return renderable.label
375
+ }
376
+ return renderable.text
377
+ })
378
+ .join(' ')
379
+ .replace(/\s+/g, ' ')
380
+ .trim()
381
+
382
+ if (text.length > 0) {
383
+ return text
384
+ }
385
+
386
+ return fallbackText.replace(/\s+/g, ' ').trim()
387
+ }
388
+
389
+ function toButtonStyle({
390
+ variant,
391
+ }: {
392
+ variant: HtmlButtonRenderable['variant']
393
+ }):
394
+ | ButtonStyle.Primary
395
+ | ButtonStyle.Secondary
396
+ | ButtonStyle.Success
397
+ | ButtonStyle.Danger {
398
+ if (variant === 'primary') {
399
+ return ButtonStyle.Primary
400
+ }
401
+ if (variant === 'success') {
402
+ return ButtonStyle.Success
403
+ }
404
+ if (variant === 'danger') {
405
+ return ButtonStyle.Danger
406
+ }
407
+ return ButtonStyle.Secondary
408
+ }
409
+
410
+ function extractCellText(tokens: Token[]): string {
411
+ const parts: string[] = []
412
+ for (const token of tokens) {
413
+ parts.push(extractTokenText(token))
414
+ }
415
+ return parts.join('').trim()
416
+ }
417
+
418
+ function extractTokenText(token: Token): string {
419
+ switch (token.type) {
420
+ case 'text':
421
+ case 'codespan':
422
+ case 'escape':
423
+ return token.text
424
+ case 'link':
425
+ return token.href
426
+ case 'image':
427
+ return token.href
428
+ case 'strong':
429
+ case 'em':
430
+ case 'del':
431
+ return token.tokens ? extractCellText(token.tokens) : token.text
432
+ case 'br':
433
+ return ' '
434
+ default: {
435
+ const tokenAny = token as { tokens?: Token[]; text?: string }
436
+ if (tokenAny.tokens && Array.isArray(tokenAny.tokens)) {
437
+ return extractCellText(tokenAny.tokens)
438
+ }
439
+ if (typeof tokenAny.text === 'string') {
440
+ return tokenAny.text
441
+ }
442
+ return ''
443
+ }
444
+ }
445
+ }
@@ -0,0 +1,92 @@
1
+ // Forum sync configuration from SQLite database.
2
+ // Reads forum_sync_configs table and resolves relative output dirs.
3
+ // On first run, migrates any existing forum-sync.json into the DB.
4
+
5
+ import fs from 'node:fs'
6
+ import path from 'node:path'
7
+ import YAML from 'yaml'
8
+ import { getDataDir } from '../config.js'
9
+ import { getForumSyncConfigs, upsertForumSyncConfig } from '../database.js'
10
+ import { createLogger } from '../logger.js'
11
+ import type { ForumSyncDirection, LoadedForumConfig } from './types.js'
12
+
13
+ const forumLogger = createLogger('FORUM')
14
+
15
+ const LEGACY_CONFIG_FILE = 'forum-sync.json'
16
+
17
+ function isForumSyncDirection(value: unknown): value is ForumSyncDirection {
18
+ return value === 'discord-to-files' || value === 'bidirectional'
19
+ }
20
+
21
+ function resolveOutputDir(outputDir: string): string {
22
+ if (path.isAbsolute(outputDir)) return outputDir
23
+ return path.resolve(getDataDir(), outputDir)
24
+ }
25
+
26
+ /**
27
+ * One-time migration: if the legacy forum-sync.json exists, import its entries
28
+ * into the DB and rename the file so it's not re-imported on next startup.
29
+ */
30
+ async function migrateLegacyConfig({ appId }: { appId: string }) {
31
+ const configPath = path.join(getDataDir(), LEGACY_CONFIG_FILE)
32
+ if (!fs.existsSync(configPath)) return
33
+
34
+ forumLogger.log(`Migrating legacy ${LEGACY_CONFIG_FILE} into database...`)
35
+
36
+ const raw = fs.readFileSync(configPath, 'utf8')
37
+ let parsed: unknown
38
+ try {
39
+ parsed = YAML.parse(raw)
40
+ } catch {
41
+ forumLogger.warn(
42
+ `Failed to parse legacy ${LEGACY_CONFIG_FILE}, skipping migration`,
43
+ )
44
+ return
45
+ }
46
+
47
+ if (!parsed || typeof parsed !== 'object') return
48
+ const forums = (parsed as Record<string, unknown>).forums
49
+ if (!Array.isArray(forums)) return
50
+
51
+ for (const item of forums) {
52
+ if (!item || typeof item !== 'object') continue
53
+ const entry = item as Record<string, unknown>
54
+ const forumChannelId =
55
+ typeof entry.forumChannelId === 'string' ? entry.forumChannelId : ''
56
+ const outputDir = typeof entry.outputDir === 'string' ? entry.outputDir : ''
57
+ const direction = isForumSyncDirection(entry.direction)
58
+ ? entry.direction
59
+ : 'bidirectional'
60
+ if (!forumChannelId || !outputDir) continue
61
+
62
+ await upsertForumSyncConfig({
63
+ appId,
64
+ forumChannelId,
65
+ outputDir: resolveOutputDir(outputDir),
66
+ direction,
67
+ })
68
+ }
69
+
70
+ // Rename so we don't re-import next time
71
+ const backupPath = configPath + '.migrated'
72
+ fs.renameSync(configPath, backupPath)
73
+ forumLogger.log(
74
+ `Legacy config migrated and renamed to ${path.basename(backupPath)}`,
75
+ )
76
+ }
77
+
78
+ export async function readForumSyncConfig({ appId }: { appId?: string }) {
79
+ if (!appId) return []
80
+
81
+ // Migrate legacy JSON file on first run
82
+ await migrateLegacyConfig({ appId })
83
+
84
+ const rows = await getForumSyncConfigs({ appId })
85
+ return rows.map<LoadedForumConfig>((row) => ({
86
+ forumChannelId: row.forumChannelId,
87
+ outputDir: resolveOutputDir(row.outputDir),
88
+ direction: isForumSyncDirection(row.direction)
89
+ ? row.direction
90
+ : 'bidirectional',
91
+ }))
92
+ }