@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,282 @@
1
+ import type { Plugin } from '@opencode-ai/plugin'
2
+ import * as fs from 'node:fs/promises'
3
+ import { homedir } from 'node:os'
4
+ import path from 'node:path'
5
+
6
+ const AUTH_LOCK_STALE_MS = 30_000
7
+ const AUTH_LOCK_RETRY_MS = 100
8
+
9
+ export type OAuthStored = {
10
+ type: 'oauth'
11
+ refresh: string
12
+ access: string
13
+ expires: number
14
+ }
15
+
16
+ type AccountRecord = OAuthStored & {
17
+ addedAt: number
18
+ lastUsed: number
19
+ }
20
+
21
+ type AccountStore = {
22
+ version: number
23
+ activeIndex: number
24
+ accounts: AccountRecord[]
25
+ }
26
+
27
+ async function readJson<T>(filePath: string, fallback: T): Promise<T> {
28
+ try {
29
+ return JSON.parse(await fs.readFile(filePath, 'utf8')) as T
30
+ } catch {
31
+ return fallback
32
+ }
33
+ }
34
+
35
+ async function writeJson(filePath: string, value: unknown) {
36
+ await fs.mkdir(path.dirname(filePath), { recursive: true })
37
+ await fs.writeFile(filePath, JSON.stringify(value, null, 2), 'utf8')
38
+ await fs.chmod(filePath, 0o600)
39
+ }
40
+
41
+ function getErrorCode(error: unknown) {
42
+ if (!(error instanceof Error)) return undefined
43
+ return (error as NodeJS.ErrnoException).code
44
+ }
45
+
46
+ async function sleep(ms: number) {
47
+ await new Promise<void>((resolve) => {
48
+ setTimeout(resolve, ms)
49
+ })
50
+ }
51
+
52
+ export function authFilePath() {
53
+ if (process.env.XDG_DATA_HOME) {
54
+ return path.join(process.env.XDG_DATA_HOME, 'opencode', 'auth.json')
55
+ }
56
+ return path.join(homedir(), '.local', 'share', 'opencode', 'auth.json')
57
+ }
58
+
59
+ export function accountsFilePath() {
60
+ if (process.env.XDG_DATA_HOME) {
61
+ return path.join(process.env.XDG_DATA_HOME, 'opencode', 'anthropic-oauth-accounts.json')
62
+ }
63
+ return path.join(homedir(), '.local', 'share', 'opencode', 'anthropic-oauth-accounts.json')
64
+ }
65
+
66
+ export async function withAuthStateLock<T>(fn: () => Promise<T>) {
67
+ const file = authFilePath()
68
+ const lockDir = `${file}.lock`
69
+ const deadline = Date.now() + AUTH_LOCK_STALE_MS
70
+
71
+ await fs.mkdir(path.dirname(file), { recursive: true })
72
+
73
+ while (true) {
74
+ try {
75
+ await fs.mkdir(lockDir)
76
+ break
77
+ } catch (error) {
78
+ const code = getErrorCode(error)
79
+ if (code !== 'EEXIST') {
80
+ throw error
81
+ }
82
+
83
+ const stats = await fs.stat(lockDir).catch(() => {
84
+ return null
85
+ })
86
+ if (stats && Date.now() - stats.mtimeMs > AUTH_LOCK_STALE_MS) {
87
+ await fs.rm(lockDir, { force: true, recursive: true }).catch(() => {})
88
+ continue
89
+ }
90
+
91
+ if (Date.now() >= deadline) {
92
+ throw new Error(`Timed out waiting for auth lock: ${lockDir}`)
93
+ }
94
+
95
+ await sleep(AUTH_LOCK_RETRY_MS)
96
+ }
97
+ }
98
+
99
+ try {
100
+ return await fn()
101
+ } finally {
102
+ await fs.rm(lockDir, { force: true, recursive: true }).catch(() => {})
103
+ }
104
+ }
105
+
106
+ export function normalizeAccountStore(
107
+ input: Partial<AccountStore> | null | undefined,
108
+ ): AccountStore {
109
+ const accounts = Array.isArray(input?.accounts)
110
+ ? input.accounts.filter(
111
+ (account): account is AccountRecord =>
112
+ !!account &&
113
+ account.type === 'oauth' &&
114
+ typeof account.refresh === 'string' &&
115
+ typeof account.access === 'string' &&
116
+ typeof account.expires === 'number' &&
117
+ typeof account.addedAt === 'number' &&
118
+ typeof account.lastUsed === 'number',
119
+ )
120
+ : []
121
+ const rawIndex = typeof input?.activeIndex === 'number' ? Math.floor(input.activeIndex) : 0
122
+ const activeIndex =
123
+ accounts.length === 0 ? 0 : ((rawIndex % accounts.length) + accounts.length) % accounts.length
124
+ return { version: 1, activeIndex, accounts }
125
+ }
126
+
127
+ export async function loadAccountStore() {
128
+ const raw = await readJson<Partial<AccountStore> | null>(accountsFilePath(), null)
129
+ return normalizeAccountStore(raw)
130
+ }
131
+
132
+ export async function saveAccountStore(store: AccountStore) {
133
+ await writeJson(accountsFilePath(), normalizeAccountStore(store))
134
+ }
135
+
136
+ function findCurrentAccountIndex(store: AccountStore, auth: OAuthStored) {
137
+ if (!store.accounts.length) return 0
138
+ const byRefresh = store.accounts.findIndex((account) => {
139
+ return account.refresh === auth.refresh
140
+ })
141
+ if (byRefresh >= 0) return byRefresh
142
+ const byAccess = store.accounts.findIndex((account) => {
143
+ return account.access === auth.access
144
+ })
145
+ if (byAccess >= 0) return byAccess
146
+ return store.activeIndex
147
+ }
148
+
149
+ export function upsertAccount(store: AccountStore, auth: OAuthStored, now = Date.now()) {
150
+ const index = store.accounts.findIndex((account) => {
151
+ return account.refresh === auth.refresh || account.access === auth.access
152
+ })
153
+ const nextAccount: AccountRecord = {
154
+ type: 'oauth',
155
+ refresh: auth.refresh,
156
+ access: auth.access,
157
+ expires: auth.expires,
158
+ addedAt: now,
159
+ lastUsed: now,
160
+ }
161
+
162
+ if (index < 0) {
163
+ store.accounts.push(nextAccount)
164
+ store.activeIndex = store.accounts.length - 1
165
+ return store.activeIndex
166
+ }
167
+
168
+ const existing = store.accounts[index]
169
+ if (!existing) return index
170
+ store.accounts[index] = {
171
+ ...existing,
172
+ ...nextAccount,
173
+ addedAt: existing.addedAt,
174
+ }
175
+ store.activeIndex = index
176
+ return index
177
+ }
178
+
179
+ export async function rememberAnthropicOAuth(auth: OAuthStored) {
180
+ await withAuthStateLock(async () => {
181
+ const store = await loadAccountStore()
182
+ upsertAccount(store, auth)
183
+ await saveAccountStore(store)
184
+ })
185
+ }
186
+
187
+ async function writeAnthropicAuthFile(auth: OAuthStored | undefined) {
188
+ const file = authFilePath()
189
+ const data = await readJson<Record<string, unknown>>(file, {})
190
+ if (auth) {
191
+ data.anthropic = auth
192
+ } else {
193
+ delete data.anthropic
194
+ }
195
+ await writeJson(file, data)
196
+ }
197
+
198
+ export async function setAnthropicAuth(
199
+ auth: OAuthStored,
200
+ client: Parameters<Plugin>[0]['client'],
201
+ ) {
202
+ await writeAnthropicAuthFile(auth)
203
+ await client.auth.set({ path: { id: 'anthropic' }, body: auth })
204
+ }
205
+
206
+ export async function rotateAnthropicAccount(
207
+ auth: OAuthStored,
208
+ client: Parameters<Plugin>[0]['client'],
209
+ ) {
210
+ return withAuthStateLock(async () => {
211
+ const store = await loadAccountStore()
212
+ if (store.accounts.length < 2) return undefined
213
+
214
+ const currentIndex = findCurrentAccountIndex(store, auth)
215
+ const nextIndex = (currentIndex + 1) % store.accounts.length
216
+ const nextAccount = store.accounts[nextIndex]
217
+ if (!nextAccount) return undefined
218
+
219
+ nextAccount.lastUsed = Date.now()
220
+ store.activeIndex = nextIndex
221
+ await saveAccountStore(store)
222
+
223
+ const nextAuth: OAuthStored = {
224
+ type: 'oauth',
225
+ refresh: nextAccount.refresh,
226
+ access: nextAccount.access,
227
+ expires: nextAccount.expires,
228
+ }
229
+ await setAnthropicAuth(nextAuth, client)
230
+ return nextAuth
231
+ })
232
+ }
233
+
234
+ export async function removeAccount(index: number) {
235
+ return withAuthStateLock(async () => {
236
+ const store = await loadAccountStore()
237
+ if (!Number.isInteger(index) || index < 0 || index >= store.accounts.length) {
238
+ throw new Error(`Account ${index + 1} does not exist`)
239
+ }
240
+
241
+ store.accounts.splice(index, 1)
242
+ if (store.accounts.length === 0) {
243
+ store.activeIndex = 0
244
+ await saveAccountStore(store)
245
+ await writeAnthropicAuthFile(undefined)
246
+ return { store, active: undefined }
247
+ }
248
+
249
+ if (store.activeIndex > index) {
250
+ store.activeIndex -= 1
251
+ } else if (store.activeIndex >= store.accounts.length) {
252
+ store.activeIndex = 0
253
+ }
254
+
255
+ const active = store.accounts[store.activeIndex]
256
+ if (!active) throw new Error('Active Anthropic account disappeared during removal')
257
+ active.lastUsed = Date.now()
258
+ await saveAccountStore(store)
259
+ const nextAuth: OAuthStored = {
260
+ type: 'oauth',
261
+ refresh: active.refresh,
262
+ access: active.access,
263
+ expires: active.expires,
264
+ }
265
+ await writeAnthropicAuthFile(nextAuth)
266
+ return { store, active: nextAuth }
267
+ })
268
+ }
269
+
270
+ export function shouldRotateAuth(status: number, bodyText: string) {
271
+ const haystack = bodyText.toLowerCase()
272
+ if (status === 429) return true
273
+ if (status === 401 || status === 403) return true
274
+ return (
275
+ haystack.includes('rate_limit') ||
276
+ haystack.includes('rate limit') ||
277
+ haystack.includes('invalid api key') ||
278
+ haystack.includes('authentication_error') ||
279
+ haystack.includes('permission_error') ||
280
+ haystack.includes('oauth')
281
+ )
282
+ }
package/src/bin.ts ADDED
@@ -0,0 +1,111 @@
1
+ // Respawn wrapper for the kimaki bot process.
2
+ // When running the default command (no subcommand) with --auto-restart,
3
+ // spawns cli.js as a child process and restarts it on non-zero exit codes
4
+ // (crash, OOM kill, etc). Intentional exits (code 0 or EXIT_NO_RESTART=64)
5
+ // are not restarted.
6
+ //
7
+ // Subcommands (send, tunnel, project, etc.) run directly without the wrapper
8
+ // since they are short-lived and don't need crash recovery.
9
+ //
10
+ // When __KIMAKI_CHILD is set, we're the child process -- just run cli.js directly.
11
+ //
12
+ // V8 heap snapshot flags:
13
+ // Injects --heapsnapshot-near-heap-limit=3 and --diagnostic-dir so V8 writes
14
+ // heap snapshots internally as it approaches the heap limit. This catches OOM
15
+ // situations where SIGKILL (exit 137) would kill the process before our
16
+ // heap-monitor.ts polling can react. The polling monitor is kept as an early
17
+ // warning system at 85% usage; the V8 flag is the last-resort safety net.
18
+
19
+ import { spawn } from 'node:child_process'
20
+ import fs from 'node:fs'
21
+ import os from 'node:os'
22
+ import path from 'node:path'
23
+
24
+ const HEAP_SNAPSHOT_DIR = path.join(os.homedir(), '.kimaki', 'heap-snapshots')
25
+
26
+ // First arg after node + script is either a subcommand or a flag.
27
+ // If it doesn't start with '-', it's a subcommand (e.g. "send", "tunnel", "project").
28
+ const firstArg = process.argv[2]
29
+ const isSubcommand = firstArg && !firstArg.startsWith('-')
30
+ const isHelpFlag = process.argv.includes('--help')
31
+
32
+ if (process.env.__KIMAKI_CHILD || isSubcommand || isHelpFlag) {
33
+ await import('./cli.js')
34
+ } else {
35
+ console.error('no subcommand detected. kimaki will automatically restart on crash')
36
+ console.error()
37
+ const EXIT_NO_RESTART = 64
38
+ const MAX_RAPID_RESTARTS = 5
39
+ const RAPID_RESTART_WINDOW_MS = 60_000
40
+ const RESTART_DELAY_MS = 2_000
41
+
42
+ const restartTimestamps: number[] = []
43
+ let child: ReturnType<typeof spawn> | null = null
44
+ // Track when we forwarded a termination signal so we don't restart after graceful shutdown
45
+ let shutdownRequested = false
46
+
47
+ function start() {
48
+ if (!fs.existsSync(HEAP_SNAPSHOT_DIR)) {
49
+ fs.mkdirSync(HEAP_SNAPSHOT_DIR, { recursive: true })
50
+ }
51
+ const heapArgs = [
52
+ `--heapsnapshot-near-heap-limit=3`,
53
+ `--diagnostic-dir=${HEAP_SNAPSHOT_DIR}`,
54
+ ]
55
+ const args = [...heapArgs, ...process.execArgv, ...process.argv.slice(1)]
56
+ child = spawn(
57
+ process.argv[0]!,
58
+ args,
59
+ {
60
+ stdio: 'inherit',
61
+ env: { ...process.env, __KIMAKI_CHILD: '1' },
62
+ },
63
+ )
64
+
65
+ child.on('exit', (code, signal) => {
66
+ if (code === 0 || code === EXIT_NO_RESTART || shutdownRequested) {
67
+ process.exit(code ?? 0)
68
+ return
69
+ }
70
+
71
+ const now = Date.now()
72
+ restartTimestamps.push(now)
73
+ while (
74
+ restartTimestamps.length > 0 &&
75
+ restartTimestamps[0]! < now - RAPID_RESTART_WINDOW_MS
76
+ ) {
77
+ restartTimestamps.shift()
78
+ }
79
+
80
+ if (restartTimestamps.length > MAX_RAPID_RESTARTS) {
81
+ console.error(
82
+ `[kimaki] Crash loop detected (${MAX_RAPID_RESTARTS} crashes in ${RAPID_RESTART_WINDOW_MS / 1000}s), exiting`,
83
+ )
84
+ process.exit(1)
85
+ return
86
+ }
87
+
88
+ const reason = signal ? `signal ${signal}` : `code ${code}`
89
+ console.error(
90
+ `[kimaki] Process exited with ${reason}, restarting in ${RESTART_DELAY_MS / 1000}s...`,
91
+ )
92
+ setTimeout(start, RESTART_DELAY_MS)
93
+ })
94
+ }
95
+
96
+ // Forward signals to child so graceful shutdown and heap snapshots work.
97
+ // SIGTERM/SIGINT mark shutdownRequested so we don't restart after graceful exit.
98
+ for (const sig of ['SIGTERM', 'SIGINT'] as const) {
99
+ process.on(sig, () => {
100
+ shutdownRequested = true
101
+ child?.kill(sig)
102
+ })
103
+ }
104
+ for (const sig of ['SIGUSR1', 'SIGUSR2'] as const) {
105
+ process.on(sig, () => {
106
+ child?.kill(sig)
107
+ })
108
+ }
109
+
110
+ start()
111
+ }