@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,364 @@
|
|
|
1
|
+
// /model-variant command — quickly change the thinking level variant for the current model.
|
|
2
|
+
// Shows both the variant picker and scope picker in a single reply (two action rows)
|
|
3
|
+
// so the user can select both without waiting for sequential menus.
|
|
4
|
+
//
|
|
5
|
+
// Cross-menu state: Discord doesn't expose already-selected values on sibling
|
|
6
|
+
// select menus in the same message. We track partial selections in the context
|
|
7
|
+
// Map. Whichever menu fires second sees the first selection stored and applies.
|
|
8
|
+
import { ChatInputCommandInteraction, StringSelectMenuInteraction, StringSelectMenuBuilder, ActionRowBuilder, ChannelType, MessageFlags, } from 'discord.js';
|
|
9
|
+
import crypto from 'node:crypto';
|
|
10
|
+
import { setChannelModel, setSessionModel, getThreadSession, setGlobalModel, getVariantCascade, } from '../database.js';
|
|
11
|
+
import { initializeOpencodeForDirectory } from '../opencode.js';
|
|
12
|
+
import { resolveTextChannel, getKimakiMetadata } from '../discord-utils.js';
|
|
13
|
+
import { getCurrentModelInfo, ensureSessionPreferencesSnapshot, } from './model.js';
|
|
14
|
+
import { getRuntime } from '../session-handler/thread-session-runtime.js';
|
|
15
|
+
import { getThinkingValuesForModel } from '../thinking-utils.js';
|
|
16
|
+
import { createLogger, LogPrefix } from '../logger.js';
|
|
17
|
+
const logger = createLogger(LogPrefix.MODEL);
|
|
18
|
+
const pendingVariantContexts = new Map();
|
|
19
|
+
/** 10 minute TTL for pending contexts to prevent unbounded map growth */
|
|
20
|
+
const CONTEXT_TTL_MS = 10 * 60 * 1000;
|
|
21
|
+
function isVariantScope(value) {
|
|
22
|
+
return value === 'session' || value === 'channel' || value === 'global';
|
|
23
|
+
}
|
|
24
|
+
function formatSourceLabel(info) {
|
|
25
|
+
switch (info.type) {
|
|
26
|
+
case 'session':
|
|
27
|
+
return 'thread override';
|
|
28
|
+
case 'agent':
|
|
29
|
+
return `agent "${info.agentName}"`;
|
|
30
|
+
case 'channel':
|
|
31
|
+
return 'channel override';
|
|
32
|
+
case 'global':
|
|
33
|
+
return 'global default';
|
|
34
|
+
case 'opencode-config':
|
|
35
|
+
case 'opencode-recent':
|
|
36
|
+
case 'opencode-provider-default':
|
|
37
|
+
return 'opencode default';
|
|
38
|
+
case 'none':
|
|
39
|
+
return 'none';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export async function handleModelVariantCommand({ interaction, appId, }) {
|
|
43
|
+
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
|
|
44
|
+
const channel = interaction.channel;
|
|
45
|
+
if (!channel) {
|
|
46
|
+
await interaction.editReply({
|
|
47
|
+
content: 'This command can only be used in a channel',
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const isThread = [
|
|
52
|
+
ChannelType.PublicThread,
|
|
53
|
+
ChannelType.PrivateThread,
|
|
54
|
+
ChannelType.AnnouncementThread,
|
|
55
|
+
].includes(channel.type);
|
|
56
|
+
let projectDirectory;
|
|
57
|
+
let targetChannelId;
|
|
58
|
+
let sessionId;
|
|
59
|
+
if (isThread) {
|
|
60
|
+
const thread = channel;
|
|
61
|
+
const [textChannel, threadSessionId] = await Promise.all([
|
|
62
|
+
resolveTextChannel(thread),
|
|
63
|
+
getThreadSession(thread.id),
|
|
64
|
+
]);
|
|
65
|
+
const metadata = await getKimakiMetadata(textChannel);
|
|
66
|
+
projectDirectory = metadata.projectDirectory;
|
|
67
|
+
targetChannelId = textChannel?.id || channel.id;
|
|
68
|
+
sessionId = threadSessionId;
|
|
69
|
+
}
|
|
70
|
+
else if (channel.type === ChannelType.GuildText) {
|
|
71
|
+
const textChannel = channel;
|
|
72
|
+
const metadata = await getKimakiMetadata(textChannel);
|
|
73
|
+
projectDirectory = metadata.projectDirectory;
|
|
74
|
+
targetChannelId = channel.id;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
await interaction.editReply({
|
|
78
|
+
content: 'This command can only be used in text channels or threads',
|
|
79
|
+
});
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (!projectDirectory) {
|
|
83
|
+
await interaction.editReply({
|
|
84
|
+
content: 'This channel is not configured with a project directory',
|
|
85
|
+
});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const getClient = await initializeOpencodeForDirectory(projectDirectory);
|
|
89
|
+
if (getClient instanceof Error) {
|
|
90
|
+
await interaction.editReply({ content: getClient.message });
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (isThread && sessionId) {
|
|
94
|
+
await ensureSessionPreferencesSnapshot({
|
|
95
|
+
sessionId,
|
|
96
|
+
channelId: targetChannelId,
|
|
97
|
+
appId,
|
|
98
|
+
getClient,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const [currentModelInfo, cascadeVariant, providersResponse] = await Promise.all([
|
|
102
|
+
getCurrentModelInfo({
|
|
103
|
+
sessionId,
|
|
104
|
+
channelId: targetChannelId,
|
|
105
|
+
appId,
|
|
106
|
+
getClient,
|
|
107
|
+
}),
|
|
108
|
+
getVariantCascade({
|
|
109
|
+
sessionId,
|
|
110
|
+
channelId: targetChannelId,
|
|
111
|
+
appId,
|
|
112
|
+
}),
|
|
113
|
+
getClient().provider.list({ directory: projectDirectory }),
|
|
114
|
+
]);
|
|
115
|
+
if (currentModelInfo.type === 'none') {
|
|
116
|
+
await interaction.editReply({
|
|
117
|
+
content: 'No model configured. Use `/model` to set one first.',
|
|
118
|
+
});
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (!providersResponse.data) {
|
|
122
|
+
await interaction.editReply({ content: 'Failed to fetch providers' });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const { providerID, modelID, model: fullModelId } = currentModelInfo;
|
|
126
|
+
const sourceLabel = formatSourceLabel(currentModelInfo);
|
|
127
|
+
const variantLabel = cascadeVariant ? ` (${cascadeVariant})` : '';
|
|
128
|
+
const provider = providersResponse.data.all.find((p) => {
|
|
129
|
+
return p.id === providerID;
|
|
130
|
+
});
|
|
131
|
+
const providerName = provider?.name || providerID;
|
|
132
|
+
const variants = getThinkingValuesForModel({
|
|
133
|
+
providers: providersResponse.data.all,
|
|
134
|
+
providerId: providerID,
|
|
135
|
+
modelId: modelID,
|
|
136
|
+
});
|
|
137
|
+
const statusText = `**Current model:** \`${fullModelId}\`${variantLabel} — ${sourceLabel}`;
|
|
138
|
+
if (variants.length === 0) {
|
|
139
|
+
await interaction.editReply({
|
|
140
|
+
content: `${statusText}\nThis model doesn't support thinking level variants.`,
|
|
141
|
+
});
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const contextHash = crypto.randomBytes(8).toString('hex');
|
|
145
|
+
pendingVariantContexts.set(contextHash, {
|
|
146
|
+
dir: projectDirectory,
|
|
147
|
+
channelId: targetChannelId,
|
|
148
|
+
sessionId,
|
|
149
|
+
isThread,
|
|
150
|
+
thread: isThread ? channel : undefined,
|
|
151
|
+
appId,
|
|
152
|
+
modelId: fullModelId,
|
|
153
|
+
providerId: providerID,
|
|
154
|
+
modelName: modelID,
|
|
155
|
+
providerName,
|
|
156
|
+
availableVariants: variants,
|
|
157
|
+
currentVariant: cascadeVariant,
|
|
158
|
+
});
|
|
159
|
+
setTimeout(() => {
|
|
160
|
+
pendingVariantContexts.delete(contextHash);
|
|
161
|
+
}, CONTEXT_TTL_MS);
|
|
162
|
+
const variantOptions = [
|
|
163
|
+
{
|
|
164
|
+
label: 'None (default)',
|
|
165
|
+
value: '__none__',
|
|
166
|
+
description: 'Use the model without a specific thinking level',
|
|
167
|
+
default: !cascadeVariant,
|
|
168
|
+
},
|
|
169
|
+
...variants.slice(0, 24).map((v) => ({
|
|
170
|
+
label: v.slice(0, 100),
|
|
171
|
+
value: v,
|
|
172
|
+
description: `Use ${v} thinking`.slice(0, 100),
|
|
173
|
+
default: cascadeVariant === v,
|
|
174
|
+
})),
|
|
175
|
+
];
|
|
176
|
+
const variantMenu = new StringSelectMenuBuilder()
|
|
177
|
+
.setCustomId(`variant_quick:${contextHash}`)
|
|
178
|
+
.setPlaceholder('Select a thinking level')
|
|
179
|
+
.addOptions(variantOptions);
|
|
180
|
+
const scopeOptions = [
|
|
181
|
+
...(isThread && sessionId
|
|
182
|
+
? [
|
|
183
|
+
{
|
|
184
|
+
label: 'This session only',
|
|
185
|
+
value: 'session',
|
|
186
|
+
description: 'Override for this thread session only',
|
|
187
|
+
},
|
|
188
|
+
]
|
|
189
|
+
: []),
|
|
190
|
+
{
|
|
191
|
+
label: 'This channel',
|
|
192
|
+
value: 'channel',
|
|
193
|
+
description: 'Override for this channel (all new sessions)',
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
label: 'Global default',
|
|
197
|
+
value: 'global',
|
|
198
|
+
description: 'Set for this channel and as default for all others',
|
|
199
|
+
},
|
|
200
|
+
];
|
|
201
|
+
const scopeMenu = new StringSelectMenuBuilder()
|
|
202
|
+
.setCustomId(`variant_scope:${contextHash}`)
|
|
203
|
+
.setPlaceholder('Apply to...')
|
|
204
|
+
.addOptions(scopeOptions);
|
|
205
|
+
const variantRow = new ActionRowBuilder().addComponents(variantMenu);
|
|
206
|
+
const scopeRow = new ActionRowBuilder().addComponents(scopeMenu);
|
|
207
|
+
await interaction.editReply({
|
|
208
|
+
content: `${statusText}\nSelect a thinking level and where to apply it:`,
|
|
209
|
+
components: [variantRow, scopeRow],
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Handle the variant quick-select interaction.
|
|
214
|
+
* Stores the chosen variant in context. If scope was already picked, applies immediately.
|
|
215
|
+
*/
|
|
216
|
+
export async function handleVariantQuickSelectMenu(interaction) {
|
|
217
|
+
const contextHash = interaction.customId.replace('variant_quick:', '');
|
|
218
|
+
const context = pendingVariantContexts.get(contextHash);
|
|
219
|
+
if (!context) {
|
|
220
|
+
await interaction.reply({
|
|
221
|
+
content: 'Selection expired. Please run /model-variant again.',
|
|
222
|
+
flags: MessageFlags.Ephemeral,
|
|
223
|
+
});
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
await interaction.deferUpdate();
|
|
227
|
+
const selected = interaction.values[0];
|
|
228
|
+
if (!selected) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const chosenVariant = selected === '__none__' ? null : selected;
|
|
232
|
+
if (chosenVariant !== null && !context.availableVariants.includes(chosenVariant)) {
|
|
233
|
+
pendingVariantContexts.delete(contextHash);
|
|
234
|
+
await interaction.editReply({
|
|
235
|
+
content: 'Invalid variant selection. Please run /model-variant again.',
|
|
236
|
+
components: [],
|
|
237
|
+
});
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
context.selectedVariant = chosenVariant;
|
|
241
|
+
if (context.selectedScope) {
|
|
242
|
+
await applyVariant({
|
|
243
|
+
interaction,
|
|
244
|
+
context,
|
|
245
|
+
variant: chosenVariant,
|
|
246
|
+
scope: context.selectedScope,
|
|
247
|
+
contextHash,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
// Otherwise wait — scope select will see selectedVariant and trigger applyVariant
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Handle the scope select interaction.
|
|
254
|
+
* Stores the chosen scope in context. If variant was already picked, applies immediately.
|
|
255
|
+
*/
|
|
256
|
+
export async function handleVariantScopeSelectMenu(interaction) {
|
|
257
|
+
const contextHash = interaction.customId.replace('variant_scope:', '');
|
|
258
|
+
const context = pendingVariantContexts.get(contextHash);
|
|
259
|
+
if (!context) {
|
|
260
|
+
await interaction.reply({
|
|
261
|
+
content: 'Selection expired. Please run /model-variant again.',
|
|
262
|
+
flags: MessageFlags.Ephemeral,
|
|
263
|
+
});
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
await interaction.deferUpdate();
|
|
267
|
+
const selected = interaction.values[0];
|
|
268
|
+
if (!selected) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (!isVariantScope(selected)) {
|
|
272
|
+
pendingVariantContexts.delete(contextHash);
|
|
273
|
+
await interaction.editReply({
|
|
274
|
+
content: 'Invalid scope selection. Please run /model-variant again.',
|
|
275
|
+
components: [],
|
|
276
|
+
});
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
context.selectedScope = selected;
|
|
280
|
+
if (context.selectedVariant !== undefined) {
|
|
281
|
+
await applyVariant({
|
|
282
|
+
interaction,
|
|
283
|
+
context,
|
|
284
|
+
variant: context.selectedVariant,
|
|
285
|
+
scope: selected,
|
|
286
|
+
contextHash,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
// Otherwise wait — variant select will see selectedScope and trigger applyVariant
|
|
290
|
+
}
|
|
291
|
+
async function applyVariant({ interaction, context, variant, scope, contextHash, }) {
|
|
292
|
+
const modelId = context.modelId;
|
|
293
|
+
const variantSuffix = variant ? ` (${variant})` : '';
|
|
294
|
+
const agentTip = '\n_Tip: create [agent .md files](https://github.com/remorses/kimaki/blob/main/docs/model-switching.md) in .opencode/agent/ for one-command model switching_';
|
|
295
|
+
try {
|
|
296
|
+
if (scope === 'session') {
|
|
297
|
+
if (!context.sessionId) {
|
|
298
|
+
pendingVariantContexts.delete(contextHash);
|
|
299
|
+
await interaction.editReply({
|
|
300
|
+
content: 'No active session in this thread. Please run /model-variant in a thread with a session.',
|
|
301
|
+
components: [],
|
|
302
|
+
});
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
await setSessionModel({
|
|
306
|
+
sessionId: context.sessionId,
|
|
307
|
+
modelId,
|
|
308
|
+
variant,
|
|
309
|
+
});
|
|
310
|
+
logger.log(`Set variant ${variant ?? 'none'} for session ${context.sessionId} (model ${modelId})`);
|
|
311
|
+
let retried = false;
|
|
312
|
+
if (context.thread) {
|
|
313
|
+
const runtime = getRuntime(context.thread.id);
|
|
314
|
+
if (runtime) {
|
|
315
|
+
retried = await runtime.retryLastUserPrompt();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const retryNote = retried
|
|
319
|
+
? '\n_Restarting current request with new variant..._'
|
|
320
|
+
: '';
|
|
321
|
+
await interaction.editReply({
|
|
322
|
+
content: `Variant set for this session:\n**${context.providerName}** / **${context.modelName}**${variantSuffix}\n\`${modelId}\`${retryNote}${agentTip}`,
|
|
323
|
+
flags: MessageFlags.SuppressEmbeds,
|
|
324
|
+
components: [],
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
else if (scope === 'global') {
|
|
328
|
+
await setGlobalModel({ appId: context.appId, modelId, variant });
|
|
329
|
+
await setChannelModel({
|
|
330
|
+
channelId: context.channelId,
|
|
331
|
+
modelId,
|
|
332
|
+
variant,
|
|
333
|
+
});
|
|
334
|
+
logger.log(`Set global variant ${variant ?? 'none'} for app ${context.appId} and channel ${context.channelId} (model ${modelId})`);
|
|
335
|
+
await interaction.editReply({
|
|
336
|
+
content: `Variant set for this channel and as global default:\n**${context.providerName}** / **${context.modelName}**${variantSuffix}\n\`${modelId}\`\nAll channels will use this variant (unless they have their own override).${agentTip}`,
|
|
337
|
+
flags: MessageFlags.SuppressEmbeds,
|
|
338
|
+
components: [],
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
// channel scope
|
|
343
|
+
await setChannelModel({
|
|
344
|
+
channelId: context.channelId,
|
|
345
|
+
modelId,
|
|
346
|
+
variant,
|
|
347
|
+
});
|
|
348
|
+
logger.log(`Set channel variant ${variant ?? 'none'} for channel ${context.channelId} (model ${modelId})`);
|
|
349
|
+
await interaction.editReply({
|
|
350
|
+
content: `Variant set for this channel:\n**${context.providerName}** / **${context.modelName}**${variantSuffix}\n\`${modelId}\`\nAll new sessions in this channel will use this variant.${agentTip}`,
|
|
351
|
+
flags: MessageFlags.SuppressEmbeds,
|
|
352
|
+
components: [],
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
pendingVariantContexts.delete(contextHash);
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
logger.error('Error applying variant:', error);
|
|
359
|
+
await interaction.editReply({
|
|
360
|
+
content: `Failed to apply variant: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
361
|
+
components: [],
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|