@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,608 @@
1
+ // Pure event-stream derivation functions for session lifecycle state.
2
+ // These functions derive lifecycle decisions from an event buffer array.
3
+ // Zero imports from thread-session-runtime.ts, store.ts, or state.ts.
4
+ // Only types from @opencode-ai/sdk/v2 and the getOpencodeEventSessionId helper.
5
+
6
+ import type {
7
+ Event as OpenCodeEvent,
8
+ Message as OpenCodeMessage,
9
+ Part,
10
+ } from '@opencode-ai/sdk/v2'
11
+ import { getOpencodeEventSessionId } from './opencode-session-event-log.js'
12
+
13
+ export type EventBufferEntry = {
14
+ event: OpenCodeEvent
15
+ timestamp: number
16
+ eventIndex?: number
17
+ }
18
+
19
+ type AssistantMessage = Extract<OpenCodeMessage, { role: 'assistant' }>
20
+ type UserMessage = Extract<OpenCodeMessage, { role: 'user' }>
21
+
22
+ function getTaskChildSessionId({
23
+ part,
24
+ }: {
25
+ part: Extract<Part, { type: 'tool' }>
26
+ }): string | undefined {
27
+ // Event-shape reference:
28
+ // - cli/src/session-handler/event-stream-fixtures/real-session-task-three-parallel-sleeps.jsonl
29
+ // - In real task events, state.metadata.sessionId appears on running/completed
30
+ // tool updates and is the canonical child-session identifier.
31
+ // We intentionally do not parse state.output because it is user-facing text
32
+ // and can change format across providers/versions.
33
+ const metadataValue = (part.state as { metadata?: unknown }).metadata
34
+ const metadataSessionId =
35
+ metadataValue && typeof metadataValue === 'object'
36
+ ? (metadataValue as { sessionId?: unknown }).sessionId
37
+ : undefined
38
+ if (typeof metadataSessionId === 'string' && metadataSessionId.length > 0) {
39
+ return metadataSessionId
40
+ }
41
+ return undefined
42
+ }
43
+
44
+ function getTaskCandidateFromEvent({
45
+ event,
46
+ mainSessionId,
47
+ }: {
48
+ event: OpenCodeEvent
49
+ mainSessionId: string
50
+ }): { assistantMessageId: string; childSessionId: string; subagentType?: string } | undefined {
51
+ if (event.type !== 'message.part.updated') {
52
+ return undefined
53
+ }
54
+
55
+ const part = event.properties.part
56
+ if (part.sessionID !== mainSessionId) {
57
+ return undefined
58
+ }
59
+ if (part.type !== 'tool' || part.tool !== 'task') {
60
+ return undefined
61
+ }
62
+
63
+ const childSessionId = getTaskChildSessionId({ part })
64
+ if (!childSessionId) {
65
+ return undefined
66
+ }
67
+
68
+ const subagentType = part.state.input?.subagent_type
69
+ return {
70
+ assistantMessageId: part.messageID,
71
+ childSessionId,
72
+ subagentType: typeof subagentType === 'string' ? subagentType : undefined,
73
+ }
74
+ }
75
+
76
+ // Scans backward for most recent session-scoped lifecycle event.
77
+ // Returns true if the latest lifecycle event for sessionId is session.status busy.
78
+ export function isSessionBusy({
79
+ events,
80
+ sessionId,
81
+ upToIndex,
82
+ }: {
83
+ events: EventBufferEntry[]
84
+ sessionId: string
85
+ upToIndex?: number
86
+ }): boolean {
87
+ const end = upToIndex ?? events.length - 1
88
+ for (let i = end; i >= 0; i--) {
89
+ const entry = events[i]
90
+ if (!entry) {
91
+ continue
92
+ }
93
+ const e = entry.event
94
+ const eid = getOpencodeEventSessionId(e)
95
+ if (eid !== sessionId) {
96
+ continue
97
+ }
98
+ if (e.type === 'session.idle') {
99
+ return false
100
+ }
101
+ if (e.type === 'session.status') {
102
+ return e.properties.status.type === 'busy'
103
+ }
104
+ }
105
+ return false
106
+ }
107
+
108
+ export function isAssistantMessageNaturalCompletion({
109
+ message,
110
+ }: {
111
+ message: AssistantMessage
112
+ }): boolean {
113
+ if (typeof message.time.completed !== 'number') {
114
+ return false
115
+ }
116
+ if (message.error) {
117
+ return false
118
+ }
119
+ // finish="tool-calls" means the model's last step was tool execution.
120
+ // Mid-turn tool-call steps don't get footers — the footer comes from the
121
+ // final text response (finish="stop") that follows. If the turn ends with
122
+ // only tool-calls and no text follow-up, no footer is emitted. This is
123
+ // acceptable since models almost always follow up with text after tools.
124
+ return message.finish !== 'tool-calls'
125
+ }
126
+
127
+ export function hasAssistantMessageCompletedBefore({
128
+ events,
129
+ sessionId,
130
+ messageId,
131
+ upToIndex,
132
+ }: {
133
+ events: EventBufferEntry[]
134
+ sessionId: string
135
+ messageId: string
136
+ upToIndex?: number
137
+ }): boolean {
138
+ const end = upToIndex ?? events.length - 1
139
+ for (let i = end; i >= 0; i--) {
140
+ const entry = events[i]
141
+ if (!entry) {
142
+ continue
143
+ }
144
+ const event = entry.event
145
+ if (event.type !== 'message.updated') {
146
+ continue
147
+ }
148
+ const info = event.properties.info
149
+ if (info.sessionID !== sessionId || info.role !== 'assistant' || info.id !== messageId) {
150
+ continue
151
+ }
152
+ return typeof info.time.completed === 'number'
153
+ }
154
+ return false
155
+ }
156
+
157
+ export function getLatestUserMessage({
158
+ events,
159
+ sessionId,
160
+ upToIndex,
161
+ }: {
162
+ events: EventBufferEntry[]
163
+ sessionId: string
164
+ upToIndex?: number
165
+ }): UserMessage | undefined {
166
+ const end = upToIndex ?? events.length - 1
167
+ let latestUserMessage: UserMessage | undefined
168
+ for (let i = end; i >= 0; i--) {
169
+ const entry = events[i]
170
+ if (!entry) {
171
+ continue
172
+ }
173
+ const event = entry.event
174
+ if (event.type !== 'message.updated') {
175
+ continue
176
+ }
177
+ const info = event.properties.info
178
+ if (info.sessionID !== sessionId || info.role !== 'user') {
179
+ continue
180
+ }
181
+ if (!latestUserMessage) {
182
+ latestUserMessage = info
183
+ continue
184
+ }
185
+ if (info.time.created > latestUserMessage.time.created) {
186
+ latestUserMessage = info
187
+ }
188
+ }
189
+ return latestUserMessage
190
+ }
191
+
192
+ export function getCurrentTurnStartTime({
193
+ events,
194
+ sessionId,
195
+ upToIndex,
196
+ }: {
197
+ events: EventBufferEntry[]
198
+ sessionId: string
199
+ upToIndex?: number
200
+ }): number | undefined {
201
+ const latestUserMessage = getLatestUserMessage({
202
+ events,
203
+ sessionId,
204
+ upToIndex,
205
+ })
206
+ return latestUserMessage?.time.created
207
+ }
208
+
209
+ // Token total helper — sum of input + output + reasoning + cache.read + cache.write
210
+ function getTokenTotal(tokens: {
211
+ input: number
212
+ output: number
213
+ reasoning: number
214
+ cache: { read: number; write: number }
215
+ }): number {
216
+ return tokens.input + tokens.output + tokens.reasoning + tokens.cache.read + tokens.cache.write
217
+ }
218
+
219
+ // Scans backward for most recent message.updated with role=assistant for sessionId.
220
+ // Extracts model, providerID, agent, tokensUsed.
221
+ export function getLatestRunInfo({
222
+ events,
223
+ sessionId,
224
+ upToIndex,
225
+ }: {
226
+ events: EventBufferEntry[]
227
+ sessionId: string
228
+ upToIndex?: number
229
+ }): {
230
+ model: string | undefined
231
+ providerID: string | undefined
232
+ agent: string | undefined
233
+ tokensUsed: number
234
+ } {
235
+ const result = {
236
+ model: undefined as string | undefined,
237
+ providerID: undefined as string | undefined,
238
+ agent: undefined as string | undefined,
239
+ tokensUsed: 0,
240
+ }
241
+ const end = upToIndex ?? events.length - 1
242
+ for (let i = end; i >= 0; i--) {
243
+ const entry = events[i]
244
+ if (!entry) {
245
+ continue
246
+ }
247
+ const e = entry.event
248
+ if (e.type !== 'message.updated') {
249
+ continue
250
+ }
251
+ const msg = e.properties.info
252
+ if (msg.sessionID !== sessionId || msg.role !== 'assistant') {
253
+ continue
254
+ }
255
+ return {
256
+ model: 'modelID' in msg ? (msg.modelID as string) : undefined,
257
+ providerID: 'providerID' in msg ? (msg.providerID as string) : undefined,
258
+ agent: 'mode' in msg ? (msg.mode as string) : undefined,
259
+ tokensUsed: 'tokens' in msg && msg.tokens
260
+ ? getTokenTotal(msg.tokens as { input: number; output: number; reasoning: number; cache: { read: number; write: number } })
261
+ : 0,
262
+ }
263
+ }
264
+ return result
265
+ }
266
+
267
+ export function getAssistantMessageIdsForLatestUserTurn({
268
+ events,
269
+ sessionId,
270
+ upToIndex,
271
+ }: {
272
+ events: EventBufferEntry[]
273
+ sessionId: string
274
+ upToIndex?: number
275
+ }): Set<string> {
276
+ const latestUserMessage = getLatestUserMessage({
277
+ events,
278
+ sessionId,
279
+ upToIndex,
280
+ })
281
+ if (!latestUserMessage) {
282
+ return new Set<string>()
283
+ }
284
+ const end = upToIndex === undefined ? events.length : upToIndex + 1
285
+ const assistantMessageIds = new Set<string>()
286
+ for (let i = 0; i < end; i++) {
287
+ const entry = events[i]
288
+ if (!entry) {
289
+ continue
290
+ }
291
+ const e = entry.event
292
+ if (e.type !== 'message.updated') {
293
+ continue
294
+ }
295
+ const msg = e.properties.info
296
+ if (msg.sessionID !== sessionId || msg.role !== 'assistant') {
297
+ continue
298
+ }
299
+ if (msg.parentID === latestUserMessage.id) {
300
+ assistantMessageIds.add(msg.id)
301
+ }
302
+ }
303
+ return assistantMessageIds
304
+ }
305
+
306
+ export function getLatestAssistantMessageIdForLatestUserTurn({
307
+ events,
308
+ sessionId,
309
+ upToIndex,
310
+ }: {
311
+ events: EventBufferEntry[]
312
+ sessionId: string
313
+ upToIndex?: number
314
+ }): string | undefined {
315
+ const latestUserMessage = getLatestUserMessage({
316
+ events,
317
+ sessionId,
318
+ upToIndex,
319
+ })
320
+ if (!latestUserMessage) {
321
+ return undefined
322
+ }
323
+ const end = upToIndex ?? events.length - 1
324
+ let latestAssistantMessage:
325
+ | Extract<OpenCodeMessage, { role: 'assistant' }>
326
+ | undefined
327
+ for (let i = end; i >= 0; i--) {
328
+ const entry = events[i]
329
+ if (!entry) {
330
+ continue
331
+ }
332
+ const event = entry.event
333
+ if (event.type !== 'message.updated') {
334
+ continue
335
+ }
336
+ const info = event.properties.info
337
+ if (info.sessionID !== sessionId || info.role !== 'assistant') {
338
+ continue
339
+ }
340
+ if (info.parentID !== latestUserMessage.id) {
341
+ continue
342
+ }
343
+ if (!latestAssistantMessage) {
344
+ latestAssistantMessage = info
345
+ continue
346
+ }
347
+ if (info.time.created > latestAssistantMessage.time.created) {
348
+ latestAssistantMessage = info
349
+ }
350
+ }
351
+ return latestAssistantMessage?.id
352
+ }
353
+
354
+ type EventBufferedAssistantMessage = AssistantMessage & {
355
+ partsSummary?: Array<{ id: string; type: string }>
356
+ }
357
+
358
+ function hasRenderablePartSummary(message: EventBufferedAssistantMessage): boolean {
359
+ if (!('partsSummary' in message) || !Array.isArray(message.partsSummary)) {
360
+ return false
361
+ }
362
+ return message.partsSummary.some((part) => {
363
+ return part.type === 'text' || part.type === 'tool'
364
+ })
365
+ }
366
+
367
+ function hasAssistantPartEvidence({
368
+ events,
369
+ sessionId,
370
+ messageId,
371
+ upToIndex,
372
+ }: {
373
+ events: EventBufferEntry[]
374
+ sessionId: string
375
+ messageId: string
376
+ upToIndex?: number
377
+ }): boolean {
378
+ const end = upToIndex ?? events.length - 1
379
+ for (let i = end; i >= 0; i--) {
380
+ const entry = events[i]
381
+ if (!entry) {
382
+ continue
383
+ }
384
+ const event = entry.event
385
+ if (event.type === 'message.updated') {
386
+ const info = event.properties.info as EventBufferedAssistantMessage
387
+ if (info.sessionID !== sessionId || info.role !== 'assistant' || info.id !== messageId) {
388
+ continue
389
+ }
390
+ if (hasRenderablePartSummary(info)) {
391
+ return true
392
+ }
393
+ continue
394
+ }
395
+ if (event.type !== 'message.part.updated') {
396
+ continue
397
+ }
398
+ const { part } = event.properties
399
+ if (part.messageID !== messageId) {
400
+ continue
401
+ }
402
+ if (part.type === 'text' || part.type === 'tool') {
403
+ return true
404
+ }
405
+ }
406
+ return false
407
+ }
408
+
409
+ function hasAssistantStepFinished({
410
+ events,
411
+ messageId,
412
+ upToIndex,
413
+ }: {
414
+ events: EventBufferEntry[]
415
+ messageId: string
416
+ upToIndex?: number
417
+ }): boolean {
418
+ const end = upToIndex ?? events.length - 1
419
+ for (let i = end; i >= 0; i--) {
420
+ const entry = events[i]
421
+ if (!entry || entry.event.type !== 'message.part.updated') {
422
+ continue
423
+ }
424
+ const { part } = entry.event.properties
425
+ if (part.messageID !== messageId) {
426
+ continue
427
+ }
428
+ if (part.type === 'step-finish') {
429
+ return true
430
+ }
431
+ }
432
+ return false
433
+ }
434
+
435
+ export function doesLatestUserTurnHaveNaturalCompletion({
436
+ events,
437
+ sessionId,
438
+ upToIndex,
439
+ }: {
440
+ events: EventBufferEntry[]
441
+ sessionId: string
442
+ upToIndex?: number
443
+ }): boolean {
444
+ const latestAssistantMessageId = getLatestAssistantMessageIdForLatestUserTurn({
445
+ events,
446
+ sessionId,
447
+ upToIndex,
448
+ })
449
+ if (!latestAssistantMessageId) {
450
+ return false
451
+ }
452
+
453
+ const end = upToIndex ?? events.length - 1
454
+ let latestAssistantMessage: EventBufferedAssistantMessage | undefined
455
+ for (let i = end; i >= 0; i--) {
456
+ const entry = events[i]
457
+ if (!entry) {
458
+ continue
459
+ }
460
+ const event = entry.event
461
+ if (event.type !== 'message.updated') {
462
+ continue
463
+ }
464
+ const info = event.properties.info
465
+ if (info.sessionID !== sessionId || info.role !== 'assistant') {
466
+ continue
467
+ }
468
+ if (info.id !== latestAssistantMessageId) {
469
+ continue
470
+ }
471
+ latestAssistantMessage = info as EventBufferedAssistantMessage
472
+ if (isAssistantMessageNaturalCompletion({ message: info })) {
473
+ return true
474
+ }
475
+ break
476
+ }
477
+
478
+ if (!latestAssistantMessage) {
479
+ return false
480
+ }
481
+ if (latestAssistantMessage.error) {
482
+ return false
483
+ }
484
+ if (latestAssistantMessage.finish === 'tool-calls') {
485
+ return false
486
+ }
487
+ return hasAssistantStepFinished({
488
+ events,
489
+ messageId: latestAssistantMessageId,
490
+ upToIndex,
491
+ }) && hasAssistantPartEvidence({
492
+ events,
493
+ sessionId,
494
+ messageId: latestAssistantMessageId,
495
+ upToIndex,
496
+ })
497
+ }
498
+
499
+ export function isAssistantMessageInLatestUserTurn({
500
+ events,
501
+ sessionId,
502
+ messageId,
503
+ upToIndex,
504
+ }: {
505
+ events: EventBufferEntry[]
506
+ sessionId: string
507
+ messageId: string
508
+ upToIndex?: number
509
+ }): boolean {
510
+ const assistantMessageIds = getAssistantMessageIdsForLatestUserTurn({
511
+ events,
512
+ sessionId,
513
+ upToIndex,
514
+ })
515
+ return assistantMessageIds.has(messageId)
516
+ }
517
+
518
+ // Returns a stable 1-based subtask index for candidateSessionId.
519
+ // Indexing scope is the parent assistant message that spawned the task tool calls,
520
+ // so numbering restarts at 1 for each assistant message.
521
+ export function getDerivedSubtaskIndex({
522
+ events,
523
+ mainSessionId,
524
+ candidateSessionId,
525
+ upToIndex,
526
+ }: {
527
+ events: EventBufferEntry[]
528
+ mainSessionId: string
529
+ candidateSessionId: string
530
+ upToIndex?: number
531
+ }): number | undefined {
532
+ const end = upToIndex ?? events.length - 1
533
+ let parentAssistantMessageId: string | undefined
534
+
535
+ for (let i = end; i >= 0; i--) {
536
+ const entry = events[i]
537
+ if (!entry) {
538
+ continue
539
+ }
540
+ const candidate = getTaskCandidateFromEvent({
541
+ event: entry.event,
542
+ mainSessionId,
543
+ })
544
+ if (!candidate) {
545
+ continue
546
+ }
547
+ if (candidate.childSessionId !== candidateSessionId) {
548
+ continue
549
+ }
550
+ parentAssistantMessageId = candidate.assistantMessageId
551
+ break
552
+ }
553
+
554
+ if (!parentAssistantMessageId) {
555
+ return undefined
556
+ }
557
+
558
+ const indexByChildSessionId = new Map<string, number>()
559
+ for (let i = 0; i <= end; i++) {
560
+ const entry = events[i]
561
+ if (!entry) {
562
+ continue
563
+ }
564
+ const candidate = getTaskCandidateFromEvent({
565
+ event: entry.event,
566
+ mainSessionId,
567
+ })
568
+ if (!candidate || candidate.assistantMessageId !== parentAssistantMessageId) {
569
+ continue
570
+ }
571
+ if (!indexByChildSessionId.has(candidate.childSessionId)) {
572
+ indexByChildSessionId.set(
573
+ candidate.childSessionId,
574
+ indexByChildSessionId.size + 1,
575
+ )
576
+ }
577
+ }
578
+
579
+ return indexByChildSessionId.get(candidateSessionId)
580
+ }
581
+
582
+ // Returns the subagent_type (e.g. "explore", "general") for a given child session.
583
+ // Used to build labels like "explore-1" instead of generic "task-1".
584
+ export function getDerivedSubtaskAgentType({
585
+ events,
586
+ mainSessionId,
587
+ candidateSessionId,
588
+ }: {
589
+ events: EventBufferEntry[]
590
+ mainSessionId: string
591
+ candidateSessionId: string
592
+ }): string | undefined {
593
+ for (let i = events.length - 1; i >= 0; i--) {
594
+ const entry = events[i]
595
+ if (!entry) {
596
+ continue
597
+ }
598
+ const candidate = getTaskCandidateFromEvent({
599
+ event: entry.event,
600
+ mainSessionId,
601
+ })
602
+ if (!candidate || candidate.childSessionId !== candidateSessionId) {
603
+ continue
604
+ }
605
+ return candidate.subagentType
606
+ }
607
+ return undefined
608
+ }