@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.
- package/bin.js +2 -0
- package/dist/agent-model.e2e.test.js +755 -0
- package/dist/ai-tool-to-genai.js +233 -0
- package/dist/ai-tool-to-genai.test.js +267 -0
- package/dist/ai-tool.js +6 -0
- package/dist/anthropic-auth-plugin.js +728 -0
- package/dist/anthropic-auth-plugin.test.js +125 -0
- package/dist/anthropic-auth-state.js +231 -0
- package/dist/bin.js +90 -0
- package/dist/channel-management.js +227 -0
- package/dist/cli-parsing.test.js +137 -0
- package/dist/cli-send-thread.e2e.test.js +356 -0
- package/dist/cli.js +3276 -0
- package/dist/commands/abort.js +65 -0
- package/dist/commands/action-buttons.js +245 -0
- package/dist/commands/add-project.js +113 -0
- package/dist/commands/agent.js +335 -0
- package/dist/commands/ask-question.js +274 -0
- package/dist/commands/btw.js +116 -0
- package/dist/commands/compact.js +120 -0
- package/dist/commands/context-usage.js +140 -0
- package/dist/commands/create-new-project.js +130 -0
- package/dist/commands/diff.js +63 -0
- package/dist/commands/file-upload.js +275 -0
- package/dist/commands/fork.js +220 -0
- package/dist/commands/gemini-apikey.js +70 -0
- package/dist/commands/login.js +885 -0
- package/dist/commands/mcp.js +239 -0
- package/dist/commands/memory-snapshot.js +24 -0
- package/dist/commands/mention-mode.js +44 -0
- package/dist/commands/merge-worktree.js +159 -0
- package/dist/commands/model-variant.js +364 -0
- package/dist/commands/model.js +776 -0
- package/dist/commands/new-worktree.js +366 -0
- package/dist/commands/paginated-select.js +57 -0
- package/dist/commands/permissions.js +274 -0
- package/dist/commands/queue.js +206 -0
- package/dist/commands/remove-project.js +115 -0
- package/dist/commands/restart-opencode-server.js +127 -0
- package/dist/commands/resume.js +149 -0
- package/dist/commands/run-command.js +79 -0
- package/dist/commands/screenshare.js +303 -0
- package/dist/commands/screenshare.test.js +20 -0
- package/dist/commands/session-id.js +78 -0
- package/dist/commands/session.js +176 -0
- package/dist/commands/share.js +80 -0
- package/dist/commands/tasks.js +205 -0
- package/dist/commands/types.js +2 -0
- package/dist/commands/undo-redo.js +305 -0
- package/dist/commands/unset-model.js +138 -0
- package/dist/commands/upgrade.js +42 -0
- package/dist/commands/user-command.js +155 -0
- package/dist/commands/verbosity.js +125 -0
- package/dist/commands/worktree-settings.js +43 -0
- package/dist/commands/worktrees.js +410 -0
- package/dist/condense-memory.js +33 -0
- package/dist/config.js +94 -0
- package/dist/context-awareness-plugin.js +363 -0
- package/dist/context-awareness-plugin.test.js +124 -0
- package/dist/critique-utils.js +95 -0
- package/dist/database.js +1310 -0
- package/dist/db.js +251 -0
- package/dist/db.test.js +138 -0
- package/dist/debounce-timeout.js +28 -0
- package/dist/debounced-process-flush.js +77 -0
- package/dist/discord-bot.js +1008 -0
- package/dist/discord-command-registration.js +524 -0
- package/dist/discord-urls.js +81 -0
- package/dist/discord-utils.js +591 -0
- package/dist/discord-utils.test.js +134 -0
- package/dist/errors.js +157 -0
- package/dist/escape-backticks.test.js +429 -0
- package/dist/event-stream-real-capture.e2e.test.js +533 -0
- package/dist/eventsource-parser.test.js +327 -0
- package/dist/exec-async.js +26 -0
- package/dist/external-opencode-sync.js +480 -0
- package/dist/format-tables.js +302 -0
- package/dist/format-tables.test.js +308 -0
- package/dist/forum-sync/config.js +79 -0
- package/dist/forum-sync/discord-operations.js +154 -0
- package/dist/forum-sync/index.js +5 -0
- package/dist/forum-sync/markdown.js +113 -0
- package/dist/forum-sync/sync-to-discord.js +417 -0
- package/dist/forum-sync/sync-to-files.js +190 -0
- package/dist/forum-sync/types.js +53 -0
- package/dist/forum-sync/watchers.js +307 -0
- package/dist/gateway-proxy-reconnect.e2e.test.js +394 -0
- package/dist/gateway-proxy.e2e.test.js +483 -0
- package/dist/genai-worker-wrapper.js +111 -0
- package/dist/genai-worker.js +311 -0
- package/dist/genai.js +232 -0
- package/dist/generated/browser.js +17 -0
- package/dist/generated/client.js +37 -0
- package/dist/generated/commonInputTypes.js +10 -0
- package/dist/generated/enums.js +52 -0
- package/dist/generated/internal/class.js +49 -0
- package/dist/generated/internal/prismaNamespace.js +253 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js +223 -0
- package/dist/generated/models/bot_api_keys.js +1 -0
- package/dist/generated/models/bot_tokens.js +1 -0
- package/dist/generated/models/channel_agents.js +1 -0
- package/dist/generated/models/channel_directories.js +1 -0
- package/dist/generated/models/channel_mention_mode.js +1 -0
- package/dist/generated/models/channel_models.js +1 -0
- package/dist/generated/models/channel_verbosity.js +1 -0
- package/dist/generated/models/channel_worktrees.js +1 -0
- package/dist/generated/models/forum_sync_configs.js +1 -0
- package/dist/generated/models/global_models.js +1 -0
- package/dist/generated/models/ipc_requests.js +1 -0
- package/dist/generated/models/part_messages.js +1 -0
- package/dist/generated/models/scheduled_tasks.js +1 -0
- package/dist/generated/models/session_agents.js +1 -0
- package/dist/generated/models/session_events.js +1 -0
- package/dist/generated/models/session_models.js +1 -0
- package/dist/generated/models/session_start_sources.js +1 -0
- package/dist/generated/models/thread_sessions.js +1 -0
- package/dist/generated/models/thread_worktrees.js +1 -0
- package/dist/generated/models.js +1 -0
- package/dist/heap-monitor.js +122 -0
- package/dist/hrana-server.js +263 -0
- package/dist/hrana-server.test.js +370 -0
- package/dist/html-actions.js +123 -0
- package/dist/html-actions.test.js +70 -0
- package/dist/html-components.js +117 -0
- package/dist/html-components.test.js +34 -0
- package/dist/image-optimizer-plugin.js +153 -0
- package/dist/image-utils.js +112 -0
- package/dist/interaction-handler.js +397 -0
- package/dist/ipc-polling.js +252 -0
- package/dist/ipc-tools-plugin.js +193 -0
- package/dist/kimaki-digital-twin.e2e.test.js +161 -0
- package/dist/kimaki-opencode-plugin-loading.e2e.test.js +87 -0
- package/dist/kimaki-opencode-plugin.js +17 -0
- package/dist/kimaki-opencode-plugin.test.js +98 -0
- package/dist/limit-heading-depth.js +25 -0
- package/dist/limit-heading-depth.test.js +105 -0
- package/dist/logger.js +165 -0
- package/dist/markdown.js +342 -0
- package/dist/markdown.test.js +257 -0
- package/dist/message-finish-field.e2e.test.js +165 -0
- package/dist/message-formatting.js +413 -0
- package/dist/message-formatting.test.js +73 -0
- package/dist/message-preprocessing.js +330 -0
- package/dist/onboarding-tutorial.js +172 -0
- package/dist/onboarding-welcome.js +37 -0
- package/dist/openai-realtime.js +224 -0
- package/dist/opencode-command-detection.js +65 -0
- package/dist/opencode-command-detection.test.js +240 -0
- package/dist/opencode-command.js +129 -0
- package/dist/opencode-command.test.js +48 -0
- package/dist/opencode-interrupt-plugin.js +361 -0
- package/dist/opencode-interrupt-plugin.test.js +458 -0
- package/dist/opencode.js +861 -0
- package/dist/otto/branding.js +22 -0
- package/dist/otto/index.js +21 -0
- package/dist/parse-permission-rules.test.js +117 -0
- package/dist/patch-text-parser.js +97 -0
- package/dist/plugin-logger.js +59 -0
- package/dist/privacy-sanitizer.js +105 -0
- package/dist/queue-advanced-abort.e2e.test.js +293 -0
- package/dist/queue-advanced-action-buttons.e2e.test.js +206 -0
- package/dist/queue-advanced-e2e-setup.js +786 -0
- package/dist/queue-advanced-footer.e2e.test.js +472 -0
- package/dist/queue-advanced-model-switch.e2e.test.js +299 -0
- package/dist/queue-advanced-permissions-typing.e2e.test.js +180 -0
- package/dist/queue-advanced-question.e2e.test.js +261 -0
- package/dist/queue-advanced-typing-interrupt.e2e.test.js +114 -0
- package/dist/queue-advanced-typing.e2e.test.js +153 -0
- package/dist/queue-drain-after-interactive-ui.e2e.test.js +119 -0
- package/dist/queue-interrupt-drain.e2e.test.js +135 -0
- package/dist/queue-question-select-drain.e2e.test.js +120 -0
- package/dist/runtime-idle-sweeper.js +52 -0
- package/dist/runtime-lifecycle.e2e.test.js +508 -0
- package/dist/sentry.js +23 -0
- package/dist/session-handler/agent-utils.js +67 -0
- package/dist/session-handler/event-stream-state.js +420 -0
- package/dist/session-handler/event-stream-state.test.js +563 -0
- package/dist/session-handler/model-utils.js +124 -0
- package/dist/session-handler/opencode-session-event-log.js +94 -0
- package/dist/session-handler/thread-runtime-state.js +104 -0
- package/dist/session-handler/thread-session-runtime.js +3258 -0
- package/dist/session-handler.js +9 -0
- package/dist/session-search.js +100 -0
- package/dist/session-search.test.js +40 -0
- package/dist/session-title-rename.test.js +80 -0
- package/dist/startup-service.js +153 -0
- package/dist/startup-time.e2e.test.js +296 -0
- package/dist/store.js +17 -0
- package/dist/system-message.js +613 -0
- package/dist/system-message.test.js +602 -0
- package/dist/task-runner.js +295 -0
- package/dist/task-schedule.js +209 -0
- package/dist/task-schedule.test.js +71 -0
- package/dist/test-utils.js +299 -0
- package/dist/thinking-utils.js +35 -0
- package/dist/thread-message-queue.e2e.test.js +999 -0
- package/dist/tools.js +357 -0
- package/dist/undo-redo.e2e.test.js +161 -0
- package/dist/unnest-code-blocks.js +146 -0
- package/dist/unnest-code-blocks.test.js +673 -0
- package/dist/upgrade.js +114 -0
- package/dist/utils.js +144 -0
- package/dist/voice-attachment.js +34 -0
- package/dist/voice-handler.js +646 -0
- package/dist/voice-message.e2e.test.js +1021 -0
- package/dist/voice.js +447 -0
- package/dist/voice.test.js +235 -0
- package/dist/wait-session.js +94 -0
- package/dist/websockify.js +69 -0
- package/dist/worker-types.js +4 -0
- package/dist/worktree-lifecycle.e2e.test.js +308 -0
- package/dist/worktree-utils.js +3 -0
- package/dist/worktrees.js +929 -0
- package/dist/worktrees.test.js +189 -0
- package/dist/xml.js +92 -0
- package/dist/xml.test.js +32 -0
- package/package.json +98 -0
- package/schema.prisma +295 -0
- package/skills/batch/SKILL.md +87 -0
- package/skills/critique/SKILL.md +112 -0
- package/skills/egaki/SKILL.md +100 -0
- package/skills/errore/SKILL.md +647 -0
- package/skills/event-sourcing-state/SKILL.md +252 -0
- package/skills/gitchamber/SKILL.md +93 -0
- package/skills/goke/SKILL.md +644 -0
- package/skills/jitter/EDITOR.md +219 -0
- package/skills/jitter/EXPORT-INTERNALS.md +309 -0
- package/skills/jitter/SKILL.md +158 -0
- package/skills/jitter/jitter-clipboard.json +1042 -0
- package/skills/jitter/package.json +14 -0
- package/skills/jitter/tsconfig.json +15 -0
- package/skills/jitter/utils/actions.ts +212 -0
- package/skills/jitter/utils/export.ts +114 -0
- package/skills/jitter/utils/index.ts +141 -0
- package/skills/jitter/utils/snapshot.ts +154 -0
- package/skills/jitter/utils/traverse.ts +246 -0
- package/skills/jitter/utils/types.ts +279 -0
- package/skills/jitter/utils/wait.ts +133 -0
- package/skills/lintcn/SKILL.md +873 -0
- package/skills/new-skill/SKILL.md +211 -0
- package/skills/npm-package/SKILL.md +239 -0
- package/skills/playwriter/SKILL.md +35 -0
- package/skills/proxyman/SKILL.md +215 -0
- package/skills/security-review/SKILL.md +208 -0
- package/skills/simplify/SKILL.md +58 -0
- package/skills/spiceflow/SKILL.md +14 -0
- package/skills/termcast/SKILL.md +945 -0
- package/skills/tuistory/SKILL.md +250 -0
- package/skills/usecomputer/SKILL.md +264 -0
- package/skills/x-articles/SKILL.md +554 -0
- package/skills/zele/SKILL.md +112 -0
- package/skills/zustand-centralized-state/SKILL.md +1004 -0
- package/src/agent-model.e2e.test.ts +976 -0
- package/src/ai-tool-to-genai.test.ts +296 -0
- package/src/ai-tool-to-genai.ts +283 -0
- package/src/ai-tool.ts +39 -0
- package/src/anthropic-auth-plugin.test.ts +159 -0
- package/src/anthropic-auth-plugin.ts +861 -0
- package/src/anthropic-auth-state.ts +282 -0
- package/src/bin.ts +111 -0
- package/src/channel-management.ts +334 -0
- package/src/cli-parsing.test.ts +195 -0
- package/src/cli-send-thread.e2e.test.ts +464 -0
- package/src/cli.ts +4581 -0
- package/src/commands/abort.ts +89 -0
- package/src/commands/action-buttons.ts +364 -0
- package/src/commands/add-project.ts +149 -0
- package/src/commands/agent.ts +473 -0
- package/src/commands/ask-question.ts +390 -0
- package/src/commands/btw.ts +164 -0
- package/src/commands/compact.ts +157 -0
- package/src/commands/context-usage.ts +199 -0
- package/src/commands/create-new-project.ts +190 -0
- package/src/commands/diff.ts +91 -0
- package/src/commands/file-upload.ts +389 -0
- package/src/commands/fork.ts +321 -0
- package/src/commands/gemini-apikey.ts +104 -0
- package/src/commands/login.ts +1173 -0
- package/src/commands/mcp.ts +307 -0
- package/src/commands/memory-snapshot.ts +30 -0
- package/src/commands/mention-mode.ts +68 -0
- package/src/commands/merge-worktree.ts +223 -0
- package/src/commands/model-variant.ts +483 -0
- package/src/commands/model.ts +1053 -0
- package/src/commands/new-worktree.ts +510 -0
- package/src/commands/paginated-select.ts +81 -0
- package/src/commands/permissions.ts +397 -0
- package/src/commands/queue.ts +271 -0
- package/src/commands/remove-project.ts +155 -0
- package/src/commands/restart-opencode-server.ts +162 -0
- package/src/commands/resume.ts +230 -0
- package/src/commands/run-command.ts +123 -0
- package/src/commands/screenshare.test.ts +30 -0
- package/src/commands/screenshare.ts +366 -0
- package/src/commands/session-id.ts +109 -0
- package/src/commands/session.ts +227 -0
- package/src/commands/share.ts +106 -0
- package/src/commands/tasks.ts +293 -0
- package/src/commands/types.ts +25 -0
- package/src/commands/undo-redo.ts +386 -0
- package/src/commands/unset-model.ts +173 -0
- package/src/commands/upgrade.ts +52 -0
- package/src/commands/user-command.ts +198 -0
- package/src/commands/verbosity.ts +173 -0
- package/src/commands/worktree-settings.ts +70 -0
- package/src/commands/worktrees.ts +552 -0
- package/src/condense-memory.ts +36 -0
- package/src/config.ts +111 -0
- package/src/context-awareness-plugin.test.ts +142 -0
- package/src/context-awareness-plugin.ts +510 -0
- package/src/critique-utils.ts +139 -0
- package/src/database.ts +1876 -0
- package/src/db.test.ts +162 -0
- package/src/db.ts +286 -0
- package/src/debounce-timeout.ts +43 -0
- package/src/debounced-process-flush.ts +104 -0
- package/src/discord-bot.ts +1330 -0
- package/src/discord-command-registration.ts +693 -0
- package/src/discord-urls.ts +88 -0
- package/src/discord-utils.test.ts +153 -0
- package/src/discord-utils.ts +800 -0
- package/src/errors.ts +201 -0
- package/src/escape-backticks.test.ts +469 -0
- package/src/event-stream-real-capture.e2e.test.ts +692 -0
- package/src/eventsource-parser.test.ts +351 -0
- package/src/exec-async.ts +35 -0
- package/src/external-opencode-sync.ts +685 -0
- package/src/format-tables.test.ts +335 -0
- package/src/format-tables.ts +445 -0
- package/src/forum-sync/config.ts +92 -0
- package/src/forum-sync/discord-operations.ts +241 -0
- package/src/forum-sync/index.ts +9 -0
- package/src/forum-sync/markdown.ts +172 -0
- package/src/forum-sync/sync-to-discord.ts +595 -0
- package/src/forum-sync/sync-to-files.ts +294 -0
- package/src/forum-sync/types.ts +175 -0
- package/src/forum-sync/watchers.ts +454 -0
- package/src/gateway-proxy-reconnect.e2e.test.ts +523 -0
- package/src/gateway-proxy.e2e.test.ts +640 -0
- package/src/genai-worker-wrapper.ts +164 -0
- package/src/genai-worker.ts +386 -0
- package/src/genai.ts +321 -0
- package/src/generated/browser.ts +114 -0
- package/src/generated/client.ts +138 -0
- package/src/generated/commonInputTypes.ts +736 -0
- package/src/generated/enums.ts +88 -0
- package/src/generated/internal/class.ts +384 -0
- package/src/generated/internal/prismaNamespace.ts +2386 -0
- package/src/generated/internal/prismaNamespaceBrowser.ts +326 -0
- package/src/generated/models/bot_api_keys.ts +1288 -0
- package/src/generated/models/bot_tokens.ts +1656 -0
- package/src/generated/models/channel_agents.ts +1256 -0
- package/src/generated/models/channel_directories.ts +1859 -0
- package/src/generated/models/channel_mention_mode.ts +1300 -0
- package/src/generated/models/channel_models.ts +1288 -0
- package/src/generated/models/channel_verbosity.ts +1228 -0
- package/src/generated/models/channel_worktrees.ts +1300 -0
- package/src/generated/models/forum_sync_configs.ts +1452 -0
- package/src/generated/models/global_models.ts +1288 -0
- package/src/generated/models/ipc_requests.ts +1485 -0
- package/src/generated/models/part_messages.ts +1302 -0
- package/src/generated/models/scheduled_tasks.ts +2320 -0
- package/src/generated/models/session_agents.ts +1086 -0
- package/src/generated/models/session_events.ts +1439 -0
- package/src/generated/models/session_models.ts +1114 -0
- package/src/generated/models/session_start_sources.ts +1408 -0
- package/src/generated/models/thread_sessions.ts +1781 -0
- package/src/generated/models/thread_worktrees.ts +1356 -0
- package/src/generated/models.ts +30 -0
- package/src/heap-monitor.ts +152 -0
- package/src/hrana-server.test.ts +434 -0
- package/src/hrana-server.ts +314 -0
- package/src/html-actions.test.ts +87 -0
- package/src/html-actions.ts +174 -0
- package/src/html-components.test.ts +38 -0
- package/src/html-components.ts +181 -0
- package/src/image-optimizer-plugin.ts +194 -0
- package/src/image-utils.ts +149 -0
- package/src/interaction-handler.ts +576 -0
- package/src/ipc-polling.ts +326 -0
- package/src/ipc-tools-plugin.ts +236 -0
- package/src/kimaki-digital-twin.e2e.test.ts +199 -0
- package/src/kimaki-opencode-plugin-loading.e2e.test.ts +109 -0
- package/src/kimaki-opencode-plugin.test.ts +108 -0
- package/src/kimaki-opencode-plugin.ts +18 -0
- package/src/limit-heading-depth.test.ts +116 -0
- package/src/limit-heading-depth.ts +26 -0
- package/src/logger.ts +208 -0
- package/src/markdown.test.ts +308 -0
- package/src/markdown.ts +410 -0
- package/src/message-finish-field.e2e.test.ts +192 -0
- package/src/message-formatting.test.ts +81 -0
- package/src/message-formatting.ts +533 -0
- package/src/message-preprocessing.ts +455 -0
- package/src/onboarding-tutorial.ts +176 -0
- package/src/onboarding-welcome.ts +49 -0
- package/src/openai-realtime.ts +358 -0
- package/src/opencode-command-detection.test.ts +307 -0
- package/src/opencode-command-detection.ts +76 -0
- package/src/opencode-command.test.ts +70 -0
- package/src/opencode-command.ts +188 -0
- package/src/opencode-interrupt-plugin.test.ts +677 -0
- package/src/opencode-interrupt-plugin.ts +477 -0
- package/src/opencode.ts +1110 -0
- package/src/otto/branding.ts +23 -0
- package/src/otto/index.ts +22 -0
- package/src/parse-permission-rules.test.ts +127 -0
- package/src/patch-text-parser.ts +107 -0
- package/src/plugin-logger.ts +68 -0
- package/src/privacy-sanitizer.ts +142 -0
- package/src/queue-advanced-abort.e2e.test.ts +382 -0
- package/src/queue-advanced-action-buttons.e2e.test.ts +268 -0
- package/src/queue-advanced-e2e-setup.ts +873 -0
- package/src/queue-advanced-footer.e2e.test.ts +576 -0
- package/src/queue-advanced-model-switch.e2e.test.ts +383 -0
- package/src/queue-advanced-permissions-typing.e2e.test.ts +245 -0
- package/src/queue-advanced-question.e2e.test.ts +316 -0
- package/src/queue-advanced-typing-interrupt.e2e.test.ts +146 -0
- package/src/queue-advanced-typing.e2e.test.ts +199 -0
- package/src/queue-drain-after-interactive-ui.e2e.test.ts +151 -0
- package/src/queue-interrupt-drain.e2e.test.ts +166 -0
- package/src/queue-question-select-drain.e2e.test.ts +152 -0
- package/src/runtime-idle-sweeper.ts +76 -0
- package/src/runtime-lifecycle.e2e.test.ts +641 -0
- package/src/schema.sql +173 -0
- package/src/sentry.ts +26 -0
- package/src/session-handler/agent-utils.ts +97 -0
- package/src/session-handler/event-stream-fixtures/real-session-action-buttons.jsonl +45 -0
- package/src/session-handler/event-stream-fixtures/real-session-footer-suppressed-on-pre-idle-interrupt.jsonl +40 -0
- package/src/session-handler/event-stream-fixtures/real-session-permission-external-file.jsonl +23 -0
- package/src/session-handler/event-stream-fixtures/real-session-task-normal.jsonl +22 -0
- package/src/session-handler/event-stream-fixtures/real-session-task-three-parallel-sleeps.jsonl +277 -0
- package/src/session-handler/event-stream-fixtures/real-session-task-user-interruption.jsonl +46 -0
- package/src/session-handler/event-stream-fixtures/session-abort-after-idle-race.jsonl +21 -0
- package/src/session-handler/event-stream-fixtures/session-concurrent-messages-serialized.jsonl +56 -0
- package/src/session-handler/event-stream-fixtures/session-explicit-abort.jsonl +44 -0
- package/src/session-handler/event-stream-fixtures/session-normal-completion.jsonl +29 -0
- package/src/session-handler/event-stream-fixtures/session-tool-call-noisy-stream.jsonl +29 -0
- package/src/session-handler/event-stream-fixtures/session-two-completions-same-session.jsonl +50 -0
- package/src/session-handler/event-stream-fixtures/session-user-interruption.jsonl +59 -0
- package/src/session-handler/event-stream-fixtures/session-voice-queued-followup.jsonl +52 -0
- package/src/session-handler/event-stream-state.test.ts +645 -0
- package/src/session-handler/event-stream-state.ts +608 -0
- package/src/session-handler/model-utils.ts +183 -0
- package/src/session-handler/opencode-session-event-log.ts +130 -0
- package/src/session-handler/thread-runtime-state.ts +212 -0
- package/src/session-handler/thread-session-runtime.ts +4281 -0
- package/src/session-handler.ts +15 -0
- package/src/session-search.test.ts +50 -0
- package/src/session-search.ts +148 -0
- package/src/session-title-rename.test.ts +112 -0
- package/src/startup-service.ts +200 -0
- package/src/startup-time.e2e.test.ts +373 -0
- package/src/store.ts +122 -0
- package/src/system-message.test.ts +612 -0
- package/src/system-message.ts +723 -0
- package/src/task-runner.ts +421 -0
- package/src/task-schedule.test.ts +84 -0
- package/src/task-schedule.ts +311 -0
- package/src/test-utils.ts +435 -0
- package/src/thinking-utils.ts +61 -0
- package/src/thread-message-queue.e2e.test.ts +1219 -0
- package/src/tools.ts +430 -0
- package/src/undici.d.ts +12 -0
- package/src/undo-redo.e2e.test.ts +209 -0
- package/src/unnest-code-blocks.test.ts +713 -0
- package/src/unnest-code-blocks.ts +185 -0
- package/src/upgrade.ts +127 -0
- package/src/utils.ts +212 -0
- package/src/voice-attachment.ts +51 -0
- package/src/voice-handler.ts +908 -0
- package/src/voice-message.e2e.test.ts +1255 -0
- package/src/voice.test.ts +281 -0
- package/src/voice.ts +627 -0
- package/src/wait-session.ts +147 -0
- package/src/websockify.ts +101 -0
- package/src/worker-types.ts +64 -0
- package/src/worktree-lifecycle.e2e.test.ts +391 -0
- package/src/worktree-utils.ts +4 -0
- package/src/worktrees.test.ts +223 -0
- package/src/worktrees.ts +1294 -0
- package/src/xml.test.ts +38 -0
- package/src/xml.ts +121 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// E2e test for queue + interrupt interaction.
|
|
2
|
+
// Validates that a user can queue a command via /queue while a slow session
|
|
3
|
+
// is in progress, then send a normal (non-queued) message to interrupt.
|
|
4
|
+
//
|
|
5
|
+
// Expected behavior:
|
|
6
|
+
// 1. Slow session is running
|
|
7
|
+
// 2. User queues a message via /queue (enters kimaki local queue)
|
|
8
|
+
// 3. User sends a normal message (interrupt)
|
|
9
|
+
// 4. Session aborts the slow task, processes the interrupt message immediately
|
|
10
|
+
// 5. Interrupt response appears in Discord with a ⬥ ok reply
|
|
11
|
+
// 6. When interrupt response completes, the queued message drains and runs
|
|
12
|
+
//
|
|
13
|
+
// Uses opencode-deterministic-provider (no real LLM calls).
|
|
14
|
+
// Poll timeouts: 4s max, 100ms interval. Slow matcher uses 100s delay.
|
|
15
|
+
import { describe, test, expect } from 'vitest';
|
|
16
|
+
import { setupQueueAdvancedSuite, TEST_USER_ID, } from './queue-advanced-e2e-setup.js';
|
|
17
|
+
import { waitForFooterMessage, waitForBotMessageContaining, waitForMessageById, } from './test-utils.js';
|
|
18
|
+
const TEXT_CHANNEL_ID = '200000000000001099';
|
|
19
|
+
const e2eTest = describe;
|
|
20
|
+
e2eTest('queue + interrupt drain ordering', () => {
|
|
21
|
+
const ctx = setupQueueAdvancedSuite({
|
|
22
|
+
channelId: TEXT_CHANNEL_ID,
|
|
23
|
+
channelName: 'qa-interrupt-drain-e2e',
|
|
24
|
+
dirName: 'qa-interrupt-drain-e2e',
|
|
25
|
+
username: 'interrupt-tester',
|
|
26
|
+
});
|
|
27
|
+
test('queued message via /queue + normal interrupt: interrupt reply should appear, then queue drains', async () => {
|
|
28
|
+
// 1. Establish session with a quick first message
|
|
29
|
+
await ctx.discord.channel(TEXT_CHANNEL_ID).user(TEST_USER_ID).sendMessage({
|
|
30
|
+
content: 'Reply with exactly: setup-interrupt-drain',
|
|
31
|
+
});
|
|
32
|
+
const thread = await ctx.discord.channel(TEXT_CHANNEL_ID).waitForThread({
|
|
33
|
+
timeout: 4_000,
|
|
34
|
+
predicate: (t) => {
|
|
35
|
+
return t.name === 'Reply with exactly: setup-interrupt-drain';
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
const th = ctx.discord.thread(thread.id);
|
|
39
|
+
await th.waitForBotReply({ timeout: 4_000 });
|
|
40
|
+
// Wait for first run to fully complete (footer) so state is clean
|
|
41
|
+
await waitForFooterMessage({
|
|
42
|
+
discord: ctx.discord,
|
|
43
|
+
threadId: thread.id,
|
|
44
|
+
timeout: 4_000,
|
|
45
|
+
});
|
|
46
|
+
// 2. Start a slow session — PLUGIN_TIMEOUT_SLEEP_MARKER has a 100s delay
|
|
47
|
+
// before the finish event, guaranteeing the session stays busy.
|
|
48
|
+
await th.user(TEST_USER_ID).sendMessage({
|
|
49
|
+
content: 'PLUGIN_TIMEOUT_SLEEP_MARKER',
|
|
50
|
+
});
|
|
51
|
+
// Wait for the slow matcher to start streaming (text appears before delay)
|
|
52
|
+
await waitForBotMessageContaining({
|
|
53
|
+
discord: ctx.discord,
|
|
54
|
+
threadId: thread.id,
|
|
55
|
+
userId: TEST_USER_ID,
|
|
56
|
+
text: 'starting sleep',
|
|
57
|
+
afterUserMessageIncludes: 'PLUGIN_TIMEOUT_SLEEP_MARKER',
|
|
58
|
+
timeout: 4_000,
|
|
59
|
+
});
|
|
60
|
+
// 3. Queue a message via /queue while the slow session is running
|
|
61
|
+
const { id: queueInteractionId } = await th.user(TEST_USER_ID)
|
|
62
|
+
.runSlashCommand({
|
|
63
|
+
name: 'queue',
|
|
64
|
+
options: [{ name: 'message', type: 3, value: 'Reply with exactly: queued-behind-slow' }],
|
|
65
|
+
});
|
|
66
|
+
const queueAck = await th.waitForInteractionAck({
|
|
67
|
+
interactionId: queueInteractionId,
|
|
68
|
+
timeout: 4_000,
|
|
69
|
+
});
|
|
70
|
+
if (!queueAck.messageId) {
|
|
71
|
+
throw new Error('Expected /queue response message id');
|
|
72
|
+
}
|
|
73
|
+
const queueStatusMessage = await waitForMessageById({
|
|
74
|
+
discord: ctx.discord,
|
|
75
|
+
threadId: thread.id,
|
|
76
|
+
messageId: queueAck.messageId,
|
|
77
|
+
timeout: 4_000,
|
|
78
|
+
});
|
|
79
|
+
// The /queue message should be queued (session is busy with the 100s task)
|
|
80
|
+
expect(queueStatusMessage.content).toContain('Queued message');
|
|
81
|
+
// 4. Send a normal (non-queued) message — this should interrupt the slow
|
|
82
|
+
// session and be processed immediately
|
|
83
|
+
await th.user(TEST_USER_ID).sendMessage({
|
|
84
|
+
content: 'Reply with exactly: interrupt-now',
|
|
85
|
+
});
|
|
86
|
+
// 5. Wait for the final state: the interrupt message should get its own
|
|
87
|
+
// ⬥ ok reply, then the queued message should drain and get processed.
|
|
88
|
+
// We wait for the queued message's footer as the final signal.
|
|
89
|
+
await waitForFooterMessage({
|
|
90
|
+
discord: ctx.discord,
|
|
91
|
+
threadId: thread.id,
|
|
92
|
+
timeout: 12_000,
|
|
93
|
+
afterMessageIncludes: 'queued-behind-slow',
|
|
94
|
+
afterAuthorId: ctx.discord.botUserId,
|
|
95
|
+
});
|
|
96
|
+
// 6. Capture the full interaction in an inline snapshot.
|
|
97
|
+
expect(await th.text()).toMatchInlineSnapshot(`
|
|
98
|
+
"--- from: user (interrupt-tester)
|
|
99
|
+
Reply with exactly: setup-interrupt-drain
|
|
100
|
+
--- from: assistant (TestBot)
|
|
101
|
+
⬥ ok
|
|
102
|
+
*project ⋅ main ⋅ Ns ⋅ N% ⋅ deterministic-v2*
|
|
103
|
+
--- from: user (interrupt-tester)
|
|
104
|
+
PLUGIN_TIMEOUT_SLEEP_MARKER
|
|
105
|
+
--- from: assistant (TestBot)
|
|
106
|
+
⬥ starting sleep 100
|
|
107
|
+
Queued message (position 1)
|
|
108
|
+
--- from: user (interrupt-tester)
|
|
109
|
+
Reply with exactly: interrupt-now
|
|
110
|
+
--- from: assistant (TestBot)
|
|
111
|
+
⬥ ok
|
|
112
|
+
*project ⋅ main ⋅ Ns ⋅ N% ⋅ deterministic-v2*
|
|
113
|
+
» **interrupt-tester:** Reply with exactly: queued-behind-slow
|
|
114
|
+
⬥ ok
|
|
115
|
+
*project ⋅ main ⋅ Ns ⋅ N% ⋅ deterministic-v2*"
|
|
116
|
+
`);
|
|
117
|
+
// 7. Assert the interrupt message got its own ⬥ ok reply between the
|
|
118
|
+
// user's interrupt message and the queue dispatch indicator.
|
|
119
|
+
const text = await th.text();
|
|
120
|
+
const lines = text.split('\n');
|
|
121
|
+
const interruptUserLine = lines.findIndex((line) => {
|
|
122
|
+
return line.includes('Reply with exactly: interrupt-now');
|
|
123
|
+
});
|
|
124
|
+
expect(interruptUserLine).toBeGreaterThan(-1);
|
|
125
|
+
const queueDispatchLine = lines.findIndex((line) => {
|
|
126
|
+
return line.includes('» **interrupt-tester:** Reply with exactly: queued-behind-slow');
|
|
127
|
+
});
|
|
128
|
+
expect(queueDispatchLine).toBeGreaterThan(-1);
|
|
129
|
+
const linesBetween = lines.slice(interruptUserLine + 1, queueDispatchLine);
|
|
130
|
+
const hasInterruptReply = linesBetween.some((line) => {
|
|
131
|
+
return line.includes('⬥ ok');
|
|
132
|
+
});
|
|
133
|
+
expect(hasInterruptReply).toBe(true);
|
|
134
|
+
}, 20_000);
|
|
135
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// E2e test: queued message must drain after the user answers a pending question
|
|
2
|
+
// via the Discord dropdown select menu. Reproduces a bug where answering via
|
|
3
|
+
// select (not text) leaves queued messages stuck because the session continues
|
|
4
|
+
// processing after the answer and may enter another blocking state.
|
|
5
|
+
import { describe, test, expect } from 'vitest';
|
|
6
|
+
import { setupQueueAdvancedSuite, TEST_USER_ID, } from './queue-advanced-e2e-setup.js';
|
|
7
|
+
import { waitForBotMessageContaining, waitForFooterMessage, } from './test-utils.js';
|
|
8
|
+
import { pendingQuestionContexts } from './commands/ask-question.js';
|
|
9
|
+
const TEXT_CHANNEL_ID = '200000000000001030';
|
|
10
|
+
async function waitForPendingQuestion({ threadId, timeoutMs, }) {
|
|
11
|
+
const start = Date.now();
|
|
12
|
+
while (Date.now() - start < timeoutMs) {
|
|
13
|
+
const entry = [...pendingQuestionContexts.entries()].find(([, context]) => {
|
|
14
|
+
return context.thread.id === threadId;
|
|
15
|
+
});
|
|
16
|
+
if (entry) {
|
|
17
|
+
return { contextHash: entry[0] };
|
|
18
|
+
}
|
|
19
|
+
await new Promise((resolve) => {
|
|
20
|
+
setTimeout(resolve, 100);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
throw new Error('Timed out waiting for pending question context');
|
|
24
|
+
}
|
|
25
|
+
describe('queue drain after question select answer', () => {
|
|
26
|
+
const ctx = setupQueueAdvancedSuite({
|
|
27
|
+
channelId: TEXT_CHANNEL_ID,
|
|
28
|
+
channelName: 'qa-question-select-drain',
|
|
29
|
+
dirName: 'qa-question-select-drain',
|
|
30
|
+
username: 'question-select-tester',
|
|
31
|
+
});
|
|
32
|
+
test('queued message drains after answering question via dropdown select', async () => {
|
|
33
|
+
// 1. Send a message that triggers the question tool
|
|
34
|
+
await ctx.discord.channel(TEXT_CHANNEL_ID).user(TEST_USER_ID).sendMessage({
|
|
35
|
+
content: 'QUESTION_SELECT_QUEUE_MARKER',
|
|
36
|
+
});
|
|
37
|
+
const thread = await ctx.discord.channel(TEXT_CHANNEL_ID).waitForThread({
|
|
38
|
+
timeout: 8_000,
|
|
39
|
+
predicate: (t) => {
|
|
40
|
+
return t.name === 'QUESTION_SELECT_QUEUE_MARKER';
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
const th = ctx.discord.thread(thread.id);
|
|
44
|
+
// 2. Wait for the question dropdown message to appear in Discord.
|
|
45
|
+
// Uses visible message wait instead of internal Map polling which
|
|
46
|
+
// is too timing-sensitive on CI.
|
|
47
|
+
const questionMessages = await waitForBotMessageContaining({
|
|
48
|
+
discord: ctx.discord,
|
|
49
|
+
threadId: thread.id,
|
|
50
|
+
text: 'How to proceed?',
|
|
51
|
+
timeout: 12_000,
|
|
52
|
+
});
|
|
53
|
+
// Get the pending question context hash from the internal map.
|
|
54
|
+
// By this point the question message is visible so the context must exist.
|
|
55
|
+
const pending = (() => {
|
|
56
|
+
const entry = [...pendingQuestionContexts.entries()].find(([, context]) => {
|
|
57
|
+
return context.thread.id === thread.id;
|
|
58
|
+
});
|
|
59
|
+
return entry ? { contextHash: entry[0] } : null;
|
|
60
|
+
})();
|
|
61
|
+
expect(pending).toBeTruthy();
|
|
62
|
+
if (!pending) {
|
|
63
|
+
throw new Error('Expected pending question context');
|
|
64
|
+
}
|
|
65
|
+
const questionMsg = questionMessages.find((m) => {
|
|
66
|
+
return m.content.includes('How to proceed?');
|
|
67
|
+
});
|
|
68
|
+
expect(questionMsg).toBeTruthy();
|
|
69
|
+
// 3. Queue a message while question is pending
|
|
70
|
+
const { id: queueInteractionId } = await th.user(TEST_USER_ID)
|
|
71
|
+
.runSlashCommand({
|
|
72
|
+
name: 'queue',
|
|
73
|
+
options: [{ name: 'message', type: 3, value: 'Reply with exactly: post-question-drain' }],
|
|
74
|
+
});
|
|
75
|
+
const queueAck = await th.waitForInteractionAck({
|
|
76
|
+
interactionId: queueInteractionId,
|
|
77
|
+
timeout: 8_000,
|
|
78
|
+
});
|
|
79
|
+
if (!queueAck.messageId) {
|
|
80
|
+
throw new Error('Expected /queue response message id');
|
|
81
|
+
}
|
|
82
|
+
// 4. Answer the question via dropdown select (pick first option "Alpha")
|
|
83
|
+
const interaction = await th.user(TEST_USER_ID).selectMenu({
|
|
84
|
+
messageId: questionMsg.id,
|
|
85
|
+
customId: `ask_question:${pending.contextHash}:0`,
|
|
86
|
+
values: ['0'],
|
|
87
|
+
});
|
|
88
|
+
await th.waitForInteractionAck({
|
|
89
|
+
interactionId: interaction.id,
|
|
90
|
+
timeout: 8_000,
|
|
91
|
+
});
|
|
92
|
+
// 5. Queued message should be handed off to OpenCode's own prompt queue
|
|
93
|
+
// after the question reply, so the dispatch indicator appears without
|
|
94
|
+
// waiting for a later natural idle.
|
|
95
|
+
await waitForBotMessageContaining({
|
|
96
|
+
discord: ctx.discord,
|
|
97
|
+
threadId: thread.id,
|
|
98
|
+
text: '» **question-select-tester:** Reply with exactly: post-question-drain',
|
|
99
|
+
timeout: 8_000,
|
|
100
|
+
});
|
|
101
|
+
// 6. Wait for footer from the drained queued message
|
|
102
|
+
await waitForFooterMessage({
|
|
103
|
+
discord: ctx.discord,
|
|
104
|
+
threadId: thread.id,
|
|
105
|
+
timeout: 8_000,
|
|
106
|
+
afterMessageIncludes: '» **question-select-tester:**',
|
|
107
|
+
afterAuthorId: ctx.discord.botUserId,
|
|
108
|
+
});
|
|
109
|
+
// Assert key invariants instead of exact snapshot — on CI the deterministic
|
|
110
|
+
// matcher can fire a second time after the drained message (rawPromptIncludes
|
|
111
|
+
// scans full history), adding an extra question to the timeline.
|
|
112
|
+
const timeline = await th.text({ showInteractions: true });
|
|
113
|
+
expect(timeline).toContain('QUESTION_SELECT_QUEUE_MARKER');
|
|
114
|
+
expect(timeline).toContain('How to proceed?');
|
|
115
|
+
expect(timeline).toContain('[user selects dropdown: 0]');
|
|
116
|
+
expect(timeline).toContain('» **question-select-tester:** Reply with exactly: post-question-drain');
|
|
117
|
+
expect(timeline).toContain('⬥ ok');
|
|
118
|
+
expect(timeline).toContain('*project ⋅ main ⋅');
|
|
119
|
+
}, 20_000);
|
|
120
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Runtime inactivity sweeper.
|
|
2
|
+
// Periodically disposes thread runtimes that stayed idle past a timeout.
|
|
3
|
+
import { createLogger, LogPrefix } from './logger.js';
|
|
4
|
+
import { disposeInactiveRuntimes, } from './session-handler/thread-session-runtime.js';
|
|
5
|
+
const logger = createLogger(LogPrefix.SESSION);
|
|
6
|
+
// 24 hours — users often return the next day to click buttons/selects,
|
|
7
|
+
// so runtimes (and their in-memory context maps) must stay alive that long.
|
|
8
|
+
export const DEFAULT_RUNTIME_IDLE_MS = 24 * 60 * 60 * 1000;
|
|
9
|
+
export const DEFAULT_SWEEP_INTERVAL_MS = 60 * 1000;
|
|
10
|
+
export function startRuntimeIdleSweeper({ runtimeIdleMs = DEFAULT_RUNTIME_IDLE_MS, sweepIntervalMs = DEFAULT_SWEEP_INTERVAL_MS, } = {}) {
|
|
11
|
+
let stopped = false;
|
|
12
|
+
let sweeping = false;
|
|
13
|
+
let sweepPromise = null;
|
|
14
|
+
const sweep = async () => {
|
|
15
|
+
if (stopped || sweeping) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
sweeping = true;
|
|
19
|
+
const currentSweepPromise = (async () => {
|
|
20
|
+
const nowMs = Date.now();
|
|
21
|
+
const disposeResult = disposeInactiveRuntimes({
|
|
22
|
+
idleMs: runtimeIdleMs,
|
|
23
|
+
nowMs,
|
|
24
|
+
});
|
|
25
|
+
if (disposeResult.disposedThreadIds.length > 0) {
|
|
26
|
+
logger.log(`[IDLE SWEEP] Disposed ${disposeResult.disposedThreadIds.length} inactive runtime(s) after ${runtimeIdleMs}ms`);
|
|
27
|
+
}
|
|
28
|
+
})();
|
|
29
|
+
sweepPromise = currentSweepPromise;
|
|
30
|
+
await currentSweepPromise.finally(() => {
|
|
31
|
+
sweeping = false;
|
|
32
|
+
sweepPromise = null;
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
const interval = setInterval(() => {
|
|
36
|
+
void sweep();
|
|
37
|
+
}, sweepIntervalMs);
|
|
38
|
+
void sweep();
|
|
39
|
+
logger.log(`[IDLE SWEEP] Started (runtimeIdleMs=${runtimeIdleMs}, intervalMs=${sweepIntervalMs})`);
|
|
40
|
+
return async () => {
|
|
41
|
+
if (stopped) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
stopped = true;
|
|
45
|
+
clearInterval(interval);
|
|
46
|
+
if (sweepPromise) {
|
|
47
|
+
await sweepPromise;
|
|
48
|
+
sweepPromise = null;
|
|
49
|
+
}
|
|
50
|
+
logger.log('[IDLE SWEEP] Stopped');
|
|
51
|
+
};
|
|
52
|
+
}
|