@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,373 @@
|
|
|
1
|
+
// Measures time-to-ready for the kimaki Discord bot startup.
|
|
2
|
+
// Used as a baseline to track startup performance and guide optimizations
|
|
3
|
+
// for scale-to-zero deployments where cold start time is critical.
|
|
4
|
+
//
|
|
5
|
+
// Measures each phase independently:
|
|
6
|
+
// 1. Hrana server start (DB + lock port)
|
|
7
|
+
// 2. Database init (Prisma connect via HTTP)
|
|
8
|
+
// 3. Discord.js client creation + login (Gateway READY)
|
|
9
|
+
// 4. startDiscordBot (event handlers + markDiscordGatewayReady)
|
|
10
|
+
// 5. OpenCode server startup (spawn + health poll)
|
|
11
|
+
// 6. Total wall-clock time from zero to "bot ready"
|
|
12
|
+
//
|
|
13
|
+
// Uses discord-digital-twin so Gateway READY is instant (no real Discord).
|
|
14
|
+
// OpenCode startup uses deterministic provider (no real LLM).
|
|
15
|
+
|
|
16
|
+
import fs from 'node:fs'
|
|
17
|
+
import path from 'node:path'
|
|
18
|
+
import url from 'node:url'
|
|
19
|
+
import { describe, test, expect, afterAll } from 'vitest'
|
|
20
|
+
import { ChannelType, Client, GatewayIntentBits, Partials } from 'discord.js'
|
|
21
|
+
import { DigitalDiscord } from 'discord-digital-twin/src'
|
|
22
|
+
import {
|
|
23
|
+
buildDeterministicOpencodeConfig,
|
|
24
|
+
type DeterministicMatcher,
|
|
25
|
+
} from 'opencode-deterministic-provider'
|
|
26
|
+
import { setDataDir } from './config.js'
|
|
27
|
+
import { startDiscordBot } from './discord-bot.js'
|
|
28
|
+
import {
|
|
29
|
+
setBotToken,
|
|
30
|
+
initDatabase,
|
|
31
|
+
closeDatabase,
|
|
32
|
+
setChannelDirectory,
|
|
33
|
+
} from './database.js'
|
|
34
|
+
import { startHranaServer, stopHranaServer } from './hrana-server.js'
|
|
35
|
+
import { initializeOpencodeForDirectory, stopOpencodeServer } from './opencode.js'
|
|
36
|
+
import { chooseLockPort, cleanupTestSessions, initTestGitRepo } from './test-utils.js'
|
|
37
|
+
|
|
38
|
+
interface PhaseTimings {
|
|
39
|
+
hranaServerMs: number
|
|
40
|
+
databaseInitMs: number
|
|
41
|
+
discordLoginMs: number
|
|
42
|
+
startDiscordBotMs: number
|
|
43
|
+
opencodeServerMs: number
|
|
44
|
+
totalMs: number
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function createRunDirectories() {
|
|
48
|
+
const root = path.resolve(process.cwd(), 'tmp', 'startup-time-e2e')
|
|
49
|
+
fs.mkdirSync(root, { recursive: true })
|
|
50
|
+
|
|
51
|
+
const dataDir = fs.mkdtempSync(path.join(root, 'data-'))
|
|
52
|
+
const projectDirectory = path.join(root, 'project')
|
|
53
|
+
fs.mkdirSync(projectDirectory, { recursive: true })
|
|
54
|
+
initTestGitRepo(projectDirectory)
|
|
55
|
+
|
|
56
|
+
return { root, dataDir, projectDirectory }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function createDiscordJsClient({ restUrl }: { restUrl: string }) {
|
|
60
|
+
return new Client({
|
|
61
|
+
intents: [
|
|
62
|
+
GatewayIntentBits.Guilds,
|
|
63
|
+
GatewayIntentBits.GuildMessages,
|
|
64
|
+
GatewayIntentBits.MessageContent,
|
|
65
|
+
GatewayIntentBits.GuildVoiceStates,
|
|
66
|
+
],
|
|
67
|
+
partials: [
|
|
68
|
+
Partials.Channel,
|
|
69
|
+
Partials.Message,
|
|
70
|
+
Partials.User,
|
|
71
|
+
Partials.ThreadMember,
|
|
72
|
+
],
|
|
73
|
+
rest: {
|
|
74
|
+
api: restUrl,
|
|
75
|
+
version: '10',
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function createMinimalMatchers(): DeterministicMatcher[] {
|
|
81
|
+
return [
|
|
82
|
+
{
|
|
83
|
+
id: 'startup-test-reply',
|
|
84
|
+
priority: 10,
|
|
85
|
+
when: {
|
|
86
|
+
lastMessageRole: 'user',
|
|
87
|
+
rawPromptIncludes: 'startup-test',
|
|
88
|
+
},
|
|
89
|
+
then: {
|
|
90
|
+
parts: [
|
|
91
|
+
{ type: 'stream-start', warnings: [] },
|
|
92
|
+
{ type: 'text-start', id: 'startup-reply' },
|
|
93
|
+
{ type: 'text-delta', id: 'startup-reply', delta: 'ok' },
|
|
94
|
+
{ type: 'text-end', id: 'startup-reply' },
|
|
95
|
+
{
|
|
96
|
+
type: 'finish',
|
|
97
|
+
finishReason: 'stop',
|
|
98
|
+
usage: { inputTokens: 1, outputTokens: 1, totalTokens: 2 },
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const TEST_USER_ID = '900000000000000777'
|
|
107
|
+
const TEXT_CHANNEL_ID = '900000000000000778'
|
|
108
|
+
|
|
109
|
+
describe('startup time measurement', () => {
|
|
110
|
+
let directories: ReturnType<typeof createRunDirectories>
|
|
111
|
+
let discord: DigitalDiscord
|
|
112
|
+
let botClient: Client | null = null
|
|
113
|
+
const testStartTime = Date.now()
|
|
114
|
+
|
|
115
|
+
afterAll(async () => {
|
|
116
|
+
if (directories) {
|
|
117
|
+
await cleanupTestSessions({
|
|
118
|
+
projectDirectory: directories.projectDirectory,
|
|
119
|
+
testStartTime,
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (botClient) {
|
|
124
|
+
botClient.destroy()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
await Promise.all([
|
|
128
|
+
stopOpencodeServer().catch(() => {}),
|
|
129
|
+
closeDatabase().catch(() => {}),
|
|
130
|
+
stopHranaServer().catch(() => {}),
|
|
131
|
+
discord?.stop().catch(() => {}),
|
|
132
|
+
])
|
|
133
|
+
|
|
134
|
+
delete process.env['KIMAKI_LOCK_PORT']
|
|
135
|
+
delete process.env['KIMAKI_DB_URL']
|
|
136
|
+
|
|
137
|
+
if (directories) {
|
|
138
|
+
fs.rmSync(directories.dataDir, { recursive: true, force: true })
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
test('measures per-phase startup timings', async () => {
|
|
143
|
+
directories = createRunDirectories()
|
|
144
|
+
const lockPort = chooseLockPort({ key: 'startup-time-e2e' })
|
|
145
|
+
|
|
146
|
+
process.env['KIMAKI_LOCK_PORT'] = String(lockPort)
|
|
147
|
+
setDataDir(directories.dataDir)
|
|
148
|
+
|
|
149
|
+
const digitalDiscordDbPath = path.join(
|
|
150
|
+
directories.dataDir,
|
|
151
|
+
'digital-discord.db',
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
discord = new DigitalDiscord({
|
|
155
|
+
guild: {
|
|
156
|
+
name: 'Startup Time Guild',
|
|
157
|
+
ownerId: TEST_USER_ID,
|
|
158
|
+
},
|
|
159
|
+
channels: [
|
|
160
|
+
{
|
|
161
|
+
id: TEXT_CHANNEL_ID,
|
|
162
|
+
name: 'startup-time',
|
|
163
|
+
type: ChannelType.GuildText,
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
users: [
|
|
167
|
+
{
|
|
168
|
+
id: TEST_USER_ID,
|
|
169
|
+
username: 'startup-tester',
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
dbUrl: `file:${digitalDiscordDbPath}`,
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
await discord.start()
|
|
176
|
+
|
|
177
|
+
// Write deterministic opencode config
|
|
178
|
+
const providerNpm = url
|
|
179
|
+
.pathToFileURL(
|
|
180
|
+
path.resolve(
|
|
181
|
+
process.cwd(),
|
|
182
|
+
'..',
|
|
183
|
+
'opencode-deterministic-provider',
|
|
184
|
+
'src',
|
|
185
|
+
'index.ts',
|
|
186
|
+
),
|
|
187
|
+
)
|
|
188
|
+
.toString()
|
|
189
|
+
|
|
190
|
+
const opencodeConfig = buildDeterministicOpencodeConfig({
|
|
191
|
+
providerName: 'deterministic-provider',
|
|
192
|
+
providerNpm,
|
|
193
|
+
model: 'deterministic-v2',
|
|
194
|
+
smallModel: 'deterministic-v2',
|
|
195
|
+
settings: {
|
|
196
|
+
strict: false,
|
|
197
|
+
matchers: createMinimalMatchers(),
|
|
198
|
+
},
|
|
199
|
+
})
|
|
200
|
+
fs.writeFileSync(
|
|
201
|
+
path.join(directories.projectDirectory, 'opencode.json'),
|
|
202
|
+
JSON.stringify(opencodeConfig, null, 2),
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
// ── Phase timings ──
|
|
206
|
+
const totalStart = performance.now()
|
|
207
|
+
|
|
208
|
+
// Phase 1: Hrana server
|
|
209
|
+
const hranaStart = performance.now()
|
|
210
|
+
const dbPath = path.join(directories.dataDir, 'discord-sessions.db')
|
|
211
|
+
const hranaResult = await startHranaServer({ dbPath })
|
|
212
|
+
if (hranaResult instanceof Error) {
|
|
213
|
+
throw hranaResult
|
|
214
|
+
}
|
|
215
|
+
process.env['KIMAKI_DB_URL'] = hranaResult
|
|
216
|
+
const hranaMs = performance.now() - hranaStart
|
|
217
|
+
|
|
218
|
+
// Phase 2: Database init
|
|
219
|
+
const dbStart = performance.now()
|
|
220
|
+
await initDatabase()
|
|
221
|
+
await setBotToken(discord.botUserId, discord.botToken)
|
|
222
|
+
await setChannelDirectory({
|
|
223
|
+
channelId: TEXT_CHANNEL_ID,
|
|
224
|
+
directory: directories.projectDirectory,
|
|
225
|
+
channelType: 'text',
|
|
226
|
+
})
|
|
227
|
+
const dbMs = performance.now() - dbStart
|
|
228
|
+
|
|
229
|
+
// Phase 3+4: Discord.js login + startDiscordBot
|
|
230
|
+
// In the real cli.ts flow, login happens first (line 2077), then
|
|
231
|
+
// startDiscordBot is called with the already-logged-in client (line 2130).
|
|
232
|
+
// startDiscordBot calls login() again internally (line 1069) which is
|
|
233
|
+
// a no-op on already-connected clients. We measure them together since
|
|
234
|
+
// that's the real critical path.
|
|
235
|
+
const loginStart = performance.now()
|
|
236
|
+
botClient = createDiscordJsClient({ restUrl: discord.restUrl })
|
|
237
|
+
// Don't pre-login — let startDiscordBot handle login internally.
|
|
238
|
+
// This avoids the double-login overhead that inflates measurements.
|
|
239
|
+
const loginMs = Math.round(performance.now() - loginStart)
|
|
240
|
+
|
|
241
|
+
const botStart = performance.now()
|
|
242
|
+
await startDiscordBot({
|
|
243
|
+
token: discord.botToken,
|
|
244
|
+
appId: discord.botUserId,
|
|
245
|
+
discordClient: botClient,
|
|
246
|
+
})
|
|
247
|
+
const botMs = performance.now() - botStart
|
|
248
|
+
|
|
249
|
+
// Phase 5: OpenCode server startup (biggest bottleneck)
|
|
250
|
+
const opencodeStart = performance.now()
|
|
251
|
+
const opencodeResult = await initializeOpencodeForDirectory(
|
|
252
|
+
directories.projectDirectory,
|
|
253
|
+
)
|
|
254
|
+
if (opencodeResult instanceof Error) {
|
|
255
|
+
throw opencodeResult
|
|
256
|
+
}
|
|
257
|
+
const opencodeMs = performance.now() - opencodeStart
|
|
258
|
+
|
|
259
|
+
const totalMs = performance.now() - totalStart
|
|
260
|
+
|
|
261
|
+
const timings: PhaseTimings = {
|
|
262
|
+
hranaServerMs: Math.round(hranaMs),
|
|
263
|
+
databaseInitMs: Math.round(dbMs),
|
|
264
|
+
discordLoginMs: Math.round(loginMs),
|
|
265
|
+
startDiscordBotMs: Math.round(botMs),
|
|
266
|
+
opencodeServerMs: Math.round(opencodeMs),
|
|
267
|
+
totalMs: Math.round(totalMs),
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Print timings for CI/local visibility
|
|
271
|
+
console.log('\n┌─────────────────────────────────────────────┐')
|
|
272
|
+
console.log('│ Kimaki Startup Time Breakdown │')
|
|
273
|
+
console.log('├─────────────────────────────────────────────┤')
|
|
274
|
+
console.log(`│ Hrana server: ${String(timings.hranaServerMs).padStart(6)} ms │`)
|
|
275
|
+
console.log(`│ Database init: ${String(timings.databaseInitMs).padStart(6)} ms │`)
|
|
276
|
+
console.log(`│ Discord.js login: ${String(timings.discordLoginMs).padStart(6)} ms │`)
|
|
277
|
+
console.log(`│ startDiscordBot: ${String(timings.startDiscordBotMs).padStart(6)} ms │`)
|
|
278
|
+
console.log(`│ OpenCode server: ${String(timings.opencodeServerMs).padStart(6)} ms │`)
|
|
279
|
+
console.log('├─────────────────────────────────────────────┤')
|
|
280
|
+
console.log(`│ TOTAL: ${String(timings.totalMs).padStart(6)} ms │`)
|
|
281
|
+
console.log('└─────────────────────────────────────────────┘\n')
|
|
282
|
+
|
|
283
|
+
// Sanity assertions — these are baselines, not targets yet.
|
|
284
|
+
// Each phase should complete (no infinite hang).
|
|
285
|
+
expect(timings.hranaServerMs).toBeLessThan(5_000)
|
|
286
|
+
expect(timings.databaseInitMs).toBeLessThan(5_000)
|
|
287
|
+
expect(timings.discordLoginMs).toBeLessThan(10_000)
|
|
288
|
+
expect(timings.startDiscordBotMs).toBeLessThan(5_000)
|
|
289
|
+
expect(timings.opencodeServerMs).toBeLessThan(30_000)
|
|
290
|
+
expect(timings.totalMs).toBeLessThan(60_000)
|
|
291
|
+
|
|
292
|
+
// Verify the bot is actually functional by sending a message
|
|
293
|
+
// and getting a response (validates the full pipeline works)
|
|
294
|
+
await discord.channel(TEXT_CHANNEL_ID).user(TEST_USER_ID).sendMessage({
|
|
295
|
+
content: 'startup-test ping',
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
const thread = await discord.channel(TEXT_CHANNEL_ID).waitForThread({
|
|
299
|
+
timeout: 10_000,
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
const reply = await discord.thread(thread.id).waitForBotReply({
|
|
303
|
+
timeout: 30_000,
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
expect(reply.content.length).toBeGreaterThan(0)
|
|
307
|
+
expect(thread.id.length).toBeGreaterThan(0)
|
|
308
|
+
}, 120_000)
|
|
309
|
+
|
|
310
|
+
test('measures parallel startup (discord + opencode simultaneously)', async () => {
|
|
311
|
+
// This test reuses the infrastructure from test 1 (hrana, db already up)
|
|
312
|
+
// to measure what happens when we run Discord login + OpenCode in parallel.
|
|
313
|
+
// In a fresh cold start, hrana+db init would add ~50ms on top.
|
|
314
|
+
|
|
315
|
+
// Stop opencode server from test 1 so we get a fresh measurement
|
|
316
|
+
await stopOpencodeServer().catch(() => {})
|
|
317
|
+
|
|
318
|
+
// Destroy and recreate bot client for a clean login measurement
|
|
319
|
+
if (botClient) {
|
|
320
|
+
botClient.destroy()
|
|
321
|
+
botClient = null
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// ── Parallel phase: Discord login + OpenCode server simultaneously ──
|
|
325
|
+
const parallelStart = performance.now()
|
|
326
|
+
|
|
327
|
+
const [discordResult, opencodeResult] = await Promise.all([
|
|
328
|
+
// Discord path: create client, login, start bot
|
|
329
|
+
(async () => {
|
|
330
|
+
const loginStart = performance.now()
|
|
331
|
+
const client = createDiscordJsClient({ restUrl: discord.restUrl })
|
|
332
|
+
await startDiscordBot({
|
|
333
|
+
token: discord.botToken,
|
|
334
|
+
appId: discord.botUserId,
|
|
335
|
+
discordClient: client,
|
|
336
|
+
})
|
|
337
|
+
return {
|
|
338
|
+
client,
|
|
339
|
+
totalMs: Math.round(performance.now() - loginStart),
|
|
340
|
+
}
|
|
341
|
+
})(),
|
|
342
|
+
// OpenCode path: spawn server + wait for health
|
|
343
|
+
(async () => {
|
|
344
|
+
const start = performance.now()
|
|
345
|
+
const result = await initializeOpencodeForDirectory(
|
|
346
|
+
directories.projectDirectory,
|
|
347
|
+
)
|
|
348
|
+
if (result instanceof Error) {
|
|
349
|
+
throw result
|
|
350
|
+
}
|
|
351
|
+
return { ms: Math.round(performance.now() - start) }
|
|
352
|
+
})(),
|
|
353
|
+
])
|
|
354
|
+
|
|
355
|
+
const parallelMs = Math.round(performance.now() - parallelStart)
|
|
356
|
+
botClient = discordResult.client
|
|
357
|
+
|
|
358
|
+
console.log('\n┌─────────────────────────────────────────────┐')
|
|
359
|
+
console.log('│ Parallel Startup Time Breakdown │')
|
|
360
|
+
console.log('├─────────────────────────────────────────────┤')
|
|
361
|
+
console.log(`│ Discord login+bot: ${String(discordResult.totalMs).padStart(6)} ms │`)
|
|
362
|
+
console.log(`│ OpenCode server: ${String(opencodeResult.ms).padStart(6)} ms │`)
|
|
363
|
+
console.log('├─────────────────────────────────────────────┤')
|
|
364
|
+
console.log(`│ PARALLEL TOTAL: ${String(parallelMs).padStart(6)} ms │`)
|
|
365
|
+
console.log(`│ (vs sequential: ${String(discordResult.totalMs + opencodeResult.ms).padStart(6)} ms) │`)
|
|
366
|
+
console.log('└─────────────────────────────────────────────┘\n')
|
|
367
|
+
|
|
368
|
+
// Parallel total should be dominated by the slower path,
|
|
369
|
+
// not the sum of both.
|
|
370
|
+
const maxSingle = Math.max(discordResult.totalMs, opencodeResult.ms)
|
|
371
|
+
expect(parallelMs).toBeLessThan(maxSingle + 500)
|
|
372
|
+
}, 120_000)
|
|
373
|
+
})
|
package/src/store.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// Centralized zustand/vanilla store for global bot state.
|
|
2
|
+
// Replaces scattered module-level `let` variables, process.env mutations,
|
|
3
|
+
// and mutable arrays with a single immutable state atom.
|
|
4
|
+
// See cli/skills/zustand-centralized-state/SKILL.md for the pattern.
|
|
5
|
+
|
|
6
|
+
import { createStore } from 'zustand/vanilla'
|
|
7
|
+
import type { VerbosityLevel } from './generated/client.js'
|
|
8
|
+
import type { ThreadRunState } from './session-handler/thread-runtime-state.js'
|
|
9
|
+
|
|
10
|
+
// Registered user commands, populated by registerCommands() in cli.ts.
|
|
11
|
+
// discordCommandName is the full sanitized Discord slash command name
|
|
12
|
+
// (including -cmd or -skill suffix), while name is the original OpenCode
|
|
13
|
+
// command name (may contain :, /, etc).
|
|
14
|
+
export type RegisteredUserCommand = {
|
|
15
|
+
name: string
|
|
16
|
+
discordCommandName: string
|
|
17
|
+
description: string
|
|
18
|
+
source?: 'command' | 'mcp' | 'skill'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Deterministic transcription config for e2e tests.
|
|
22
|
+
// When set, processVoiceAttachment() skips the real AI model call and
|
|
23
|
+
// returns this canned result after sleeping for delayMs. This lets tests
|
|
24
|
+
// control transcription output, timing, and queue behavior deterministically.
|
|
25
|
+
export type DeterministicTranscriptionConfig = {
|
|
26
|
+
transcription: string
|
|
27
|
+
queueMessage: boolean
|
|
28
|
+
/** Agent name extracted from voice message. Only set if user explicitly requested an agent. */
|
|
29
|
+
agent?: string
|
|
30
|
+
/** Artificial delay before returning the result (ms). Default 0. */
|
|
31
|
+
delayMs?: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type KimakiState = {
|
|
35
|
+
// ── Config state (set once at CLI startup, read everywhere) ──────────
|
|
36
|
+
|
|
37
|
+
// Path to the kimaki data directory (default ~/.kimaki).
|
|
38
|
+
// Changes: set once at startup by setDataDir() or auto-created on first
|
|
39
|
+
// getDataDir() call. Under vitest, auto-creates a temp dir.
|
|
40
|
+
// Read by: database paths, heap snapshot dir, log file path, hrana server.
|
|
41
|
+
dataDir: string | null
|
|
42
|
+
|
|
43
|
+
// Custom projects directory override (default: <dataDir>/projects).
|
|
44
|
+
// When set via --projects-dir CLI flag, project create commands will
|
|
45
|
+
// create new project folders here instead of ~/.kimaki/projects/.
|
|
46
|
+
// Changes: set once at startup from --projects-dir CLI flag.
|
|
47
|
+
// Read by: config.ts getProjectsDir().
|
|
48
|
+
projectsDir: string | null
|
|
49
|
+
|
|
50
|
+
// Default output verbosity for sessions when no channel-level override
|
|
51
|
+
// exists in the DB. Controls which tool outputs are shown in Discord.
|
|
52
|
+
// Changes: set once at startup from --verbosity CLI flag.
|
|
53
|
+
// Read by: database.ts (fallback in getChannelVerbosity), message formatting.
|
|
54
|
+
defaultVerbosity: VerbosityLevel
|
|
55
|
+
|
|
56
|
+
// When true, the bot only responds to messages that @mention it in text
|
|
57
|
+
// channels (threads are unaffected). Fallback when no channel override in DB.
|
|
58
|
+
// Changes: set once at startup from --mention-mode CLI flag.
|
|
59
|
+
// Read by: database.ts (fallback in getChannelMentionMode), discord-bot.ts guard.
|
|
60
|
+
defaultMentionMode: boolean
|
|
61
|
+
|
|
62
|
+
// Whether critique.work diff URL generation is enabled. When false,
|
|
63
|
+
// the system message omits critique instructions from the AI context.
|
|
64
|
+
// Changes: set once at startup from --no-critique CLI flag.
|
|
65
|
+
// Read by: system-message.ts (conditionally appends critique instructions).
|
|
66
|
+
critiqueEnabled: boolean
|
|
67
|
+
|
|
68
|
+
// Base URL for Discord REST API calls (default https://discord.com).
|
|
69
|
+
// Overridden when using a gateway-proxy or gateway Discord mode.
|
|
70
|
+
// Changes: set by getBotTokenWithMode() which runs at startup and on
|
|
71
|
+
// multiple runtime paths (CLI init, opencode spawn). May be updated
|
|
72
|
+
// whenever bot credentials are re-read from the DB.
|
|
73
|
+
// Read by: discord-urls.ts (getDiscordRestApiUrl), REST client construction.
|
|
74
|
+
discordBaseUrl: string
|
|
75
|
+
|
|
76
|
+
// Service auth token (client_id:client_secret) used to authenticate
|
|
77
|
+
// control-plane requests like /kimaki/wake. Always set at startup in all
|
|
78
|
+
// modes so localhost and internet paths share one auth model.
|
|
79
|
+
// Changes: set in cli.ts after credential resolution and persisted in sqlite.
|
|
80
|
+
// Read by: hrana-server.ts to validate Authorization bearer token.
|
|
81
|
+
gatewayToken: string | null
|
|
82
|
+
|
|
83
|
+
// User-defined slash commands registered with Discord, populated after
|
|
84
|
+
// registerCommands() completes during startup. Maps sanitized Discord
|
|
85
|
+
// command names back to original OpenCode command names.
|
|
86
|
+
// Changes: set once during startup after Discord API registration.
|
|
87
|
+
// Read by: /queue-command autocomplete, user-command handler dispatch.
|
|
88
|
+
registeredUserCommands: RegisteredUserCommand[]
|
|
89
|
+
|
|
90
|
+
// ── Per-thread runtime state ────────────────────────────────────────
|
|
91
|
+
// The main mutable state at runtime. One ThreadRunState per active thread.
|
|
92
|
+
// All mutations are immutable: each updateThread() creates a new Map + new
|
|
93
|
+
// ThreadRunState object via store.setState(). See thread-runtime-state.ts.
|
|
94
|
+
// Changes: on every message enqueue, prompt dispatch, phase transition,
|
|
95
|
+
// abort, and finish.
|
|
96
|
+
// Read by: runtime state helpers (isRunActive, canDispatchNext), session
|
|
97
|
+
// orchestration in ThreadSessionRuntime, /abort and /queue via runtime APIs.
|
|
98
|
+
threads: Map<string, ThreadRunState>
|
|
99
|
+
|
|
100
|
+
// ── Test-only state ─────────────────────────────────────────────────
|
|
101
|
+
test: {
|
|
102
|
+
// When set, processVoiceAttachment() skips the real AI transcription
|
|
103
|
+
// call and returns this canned result after sleeping delayMs.
|
|
104
|
+
// Lets e2e tests control transcription output and timing.
|
|
105
|
+
// Changes: set/cleared by e2e test setup/teardown only.
|
|
106
|
+
// Read by: voice-handler.ts processVoiceAttachment().
|
|
107
|
+
deterministicTranscription: DeterministicTranscriptionConfig | null
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const store = createStore<KimakiState>(() => ({
|
|
112
|
+
dataDir: null,
|
|
113
|
+
projectsDir: null,
|
|
114
|
+
defaultVerbosity: 'text_and_essential_tools',
|
|
115
|
+
defaultMentionMode: false,
|
|
116
|
+
critiqueEnabled: true,
|
|
117
|
+
discordBaseUrl: 'https://discord.com',
|
|
118
|
+
gatewayToken: null,
|
|
119
|
+
registeredUserCommands: [],
|
|
120
|
+
threads: new Map(),
|
|
121
|
+
test: { deterministicTranscription: null },
|
|
122
|
+
}))
|