kimaki 0.31.0 → 1.1.0
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/dist/agent-ui.d.ts +33 -0
- package/dist/agent-ui.e2e.test.d.ts +1 -0
- package/dist/agent-ui.e2e.test.js +140 -0
- package/dist/agent-ui.e2e.test.js.map +1 -0
- package/dist/agent-ui.js +199 -0
- package/dist/agent-ui.js.map +1 -0
- package/dist/analytics.d.ts +42 -0
- package/dist/analytics.e2e.test.d.ts +1 -0
- package/dist/analytics.e2e.test.js +112 -0
- package/dist/analytics.e2e.test.js.map +1 -0
- package/dist/analytics.js +162 -223
- package/dist/analytics.js.map +1 -0
- package/dist/analytics.test.d.ts +1 -0
- package/dist/analytics.test.js +121 -157
- package/dist/analytics.test.js.map +1 -0
- package/dist/autostart.d.ts +7 -0
- package/dist/autostart.js +87 -0
- package/dist/autostart.js.map +1 -0
- package/dist/bot.d.ts +91 -0
- package/dist/bot.js +120 -0
- package/dist/bot.js.map +1 -0
- package/dist/btw.e2e.test.d.ts +1 -0
- package/dist/btw.e2e.test.js +102 -0
- package/dist/btw.e2e.test.js.map +1 -0
- package/dist/builtin-skills.d.ts +18 -0
- package/dist/builtin-skills.js +51 -0
- package/dist/builtin-skills.js.map +1 -0
- package/dist/builtin-skills.test.d.ts +1 -0
- package/dist/builtin-skills.test.js +28 -0
- package/dist/builtin-skills.test.js.map +1 -0
- package/dist/catalog-refresh.e2e.test.d.ts +1 -0
- package/dist/catalog-refresh.e2e.test.js +90 -0
- package/dist/catalog-refresh.e2e.test.js.map +1 -0
- package/dist/cli/bot.d.ts +5 -0
- package/dist/cli/bot.js +434 -0
- package/dist/cli/bot.js.map +1 -0
- package/dist/cli/discord.d.ts +3 -0
- package/dist/cli/discord.js +118 -0
- package/dist/cli/discord.js.map +1 -0
- package/dist/cli/project.d.ts +5 -0
- package/dist/cli/project.js +143 -0
- package/dist/cli/project.js.map +1 -0
- package/dist/cli/schedule.d.ts +3 -0
- package/dist/cli/schedule.js +156 -0
- package/dist/cli/schedule.js.map +1 -0
- package/dist/cli/session.d.ts +4 -0
- package/dist/cli/session.js +245 -0
- package/dist/cli/session.js.map +1 -0
- package/dist/cli/shared.d.ts +55 -0
- package/dist/cli/shared.js +138 -0
- package/dist/cli/shared.js.map +1 -0
- package/dist/cli-discord.e2e.test.d.ts +1 -0
- package/dist/cli-discord.e2e.test.js +82 -0
- package/dist/cli-discord.e2e.test.js.map +1 -0
- package/dist/cli-lock.e2e.test.d.ts +1 -0
- package/dist/cli-lock.e2e.test.js +520 -0
- package/dist/cli-lock.e2e.test.js.map +1 -0
- package/dist/cli-read.e2e.test.d.ts +1 -0
- package/dist/cli-read.e2e.test.js +86 -0
- package/dist/cli-read.e2e.test.js.map +1 -0
- package/dist/cli-sessions.e2e.test.d.ts +1 -0
- package/dist/cli-sessions.e2e.test.js +116 -0
- package/dist/cli-sessions.e2e.test.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +34 -263
- package/dist/cli.js.map +1 -0
- package/dist/commands/login-commands.d.ts +59 -0
- package/dist/commands/login-commands.js +341 -0
- package/dist/commands/login-commands.js.map +1 -0
- package/dist/commands/preference-commands.d.ts +44 -0
- package/dist/commands/preference-commands.js +565 -0
- package/dist/commands/preference-commands.js.map +1 -0
- package/dist/commands/session-commands.d.ts +8 -0
- package/dist/commands/session-commands.js +267 -0
- package/dist/commands/session-commands.js.map +1 -0
- package/dist/commands/thread-commands.d.ts +16 -0
- package/dist/commands/thread-commands.js +285 -0
- package/dist/commands/thread-commands.js.map +1 -0
- package/dist/commands/worktree-commands.d.ts +41 -0
- package/dist/commands/worktree-commands.js +279 -0
- package/dist/commands/worktree-commands.js.map +1 -0
- package/dist/commands.e2e.test.d.ts +1 -0
- package/dist/commands.e2e.test.js +255 -0
- package/dist/commands.e2e.test.js.map +1 -0
- package/dist/credentials.d.ts +84 -0
- package/dist/credentials.js +320 -0
- package/dist/credentials.js.map +1 -0
- package/dist/db.d.ts +1532 -0
- package/dist/db.js +57 -245
- package/dist/db.js.map +1 -0
- package/dist/db.test.d.ts +1 -0
- package/dist/db.test.js +351 -682
- package/dist/db.test.js.map +1 -0
- package/dist/duration.d.ts +2 -0
- package/dist/duration.js +18 -0
- package/dist/duration.js.map +1 -0
- package/dist/effects.d.ts +15 -0
- package/dist/effects.js +315 -0
- package/dist/effects.js.map +1 -0
- package/dist/errors.d.ts +38 -0
- package/dist/errors.js +40 -175
- package/dist/errors.js.map +1 -0
- package/dist/event-loop.d.ts +41 -0
- package/dist/event-loop.js +418 -0
- package/dist/event-loop.js.map +1 -0
- package/dist/file-edit-log.d.ts +41 -0
- package/dist/file-edit-log.js +122 -164
- package/dist/file-edit-log.js.map +1 -0
- package/dist/file-edit-log.test.d.ts +1 -0
- package/dist/file-edit-log.test.js +68 -244
- package/dist/file-edit-log.test.js.map +1 -0
- package/dist/format-parts.d.ts +137 -0
- package/dist/format-parts.js +300 -0
- package/dist/format-parts.js.map +1 -0
- package/dist/format-parts.test.d.ts +1 -0
- package/dist/format-parts.test.js +144 -0
- package/dist/format-parts.test.js.map +1 -0
- package/dist/gateway-replay.e2e.test.d.ts +1 -0
- package/dist/gateway-replay.e2e.test.js +95 -0
- package/dist/gateway-replay.e2e.test.js.map +1 -0
- package/dist/harness.e2e.test.d.ts +1 -0
- package/dist/harness.e2e.test.js +107 -0
- package/dist/harness.e2e.test.js.map +1 -0
- package/dist/hello-thread.e2e.test.d.ts +1 -0
- package/dist/hello-thread.e2e.test.js +194 -0
- package/dist/hello-thread.e2e.test.js.map +1 -0
- package/dist/ingress.d.ts +7 -0
- package/dist/ingress.js +337 -0
- package/dist/ingress.js.map +1 -0
- package/dist/interaction-context.d.ts +45 -0
- package/dist/interaction-context.js +77 -0
- package/dist/interaction-context.js.map +1 -0
- package/dist/interrupt.e2e.test.d.ts +1 -0
- package/dist/interrupt.e2e.test.js +124 -0
- package/dist/interrupt.e2e.test.js.map +1 -0
- package/dist/legacy.e2e.test.d.ts +1 -0
- package/dist/legacy.e2e.test.js +85 -0
- package/dist/legacy.e2e.test.js.map +1 -0
- package/dist/live-call.d.ts +51 -0
- package/dist/live-call.js +207 -0
- package/dist/live-call.js.map +1 -0
- package/dist/lock-routes.d.ts +812 -0
- package/dist/lock-routes.js +635 -0
- package/dist/lock-routes.js.map +1 -0
- package/dist/lock-server.d.ts +36 -0
- package/dist/lock-server.js +223 -0
- package/dist/lock-server.js.map +1 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.js +112 -162
- package/dist/logger.js.map +1 -0
- package/dist/login.e2e.test.d.ts +1 -0
- package/dist/login.e2e.test.js +83 -0
- package/dist/login.e2e.test.js.map +1 -0
- package/dist/main.d.ts +33 -0
- package/dist/main.js +261 -0
- package/dist/main.js.map +1 -0
- package/dist/markdown/components.d.ts +10 -0
- package/dist/markdown/components.js +77 -0
- package/dist/markdown/components.js.map +1 -0
- package/dist/markdown/markdown.test.d.ts +1 -0
- package/dist/markdown/markdown.test.js +393 -0
- package/dist/markdown/markdown.test.js.map +1 -0
- package/dist/markdown/render-markdown.d.ts +30 -0
- package/dist/markdown/render-markdown.js +265 -0
- package/dist/markdown/render-markdown.js.map +1 -0
- package/dist/message-tool.e2e.test.d.ts +1 -0
- package/dist/message-tool.e2e.test.js +39 -0
- package/dist/message-tool.e2e.test.js.map +1 -0
- package/dist/migrations.d.ts +8 -0
- package/dist/migrations.js +187 -0
- package/dist/migrations.js.map +1 -0
- package/dist/onboarding-cli.e2e.test.d.ts +1 -0
- package/dist/onboarding-cli.e2e.test.js +178 -0
- package/dist/onboarding-cli.e2e.test.js.map +1 -0
- package/dist/onboarding.d.ts +36 -0
- package/dist/onboarding.e2e.test.d.ts +1 -0
- package/dist/onboarding.e2e.test.js +148 -0
- package/dist/onboarding.e2e.test.js.map +1 -0
- package/dist/onboarding.js +261 -0
- package/dist/onboarding.js.map +1 -0
- package/dist/opencode-server.d.ts +54 -0
- package/dist/opencode-server.js +417 -0
- package/dist/opencode-server.js.map +1 -0
- package/dist/opencode-server.test.d.ts +1 -0
- package/dist/opencode-server.test.js +21 -0
- package/dist/opencode-server.test.js.map +1 -0
- package/dist/permissions.d.ts +31 -0
- package/dist/permissions.e2e.test.d.ts +1 -0
- package/dist/permissions.e2e.test.js +166 -0
- package/dist/permissions.e2e.test.js.map +1 -0
- package/dist/permissions.js +95 -0
- package/dist/permissions.js.map +1 -0
- package/dist/plugin/anthropic/index.d.ts +13 -0
- package/dist/plugin/anthropic/index.js +201 -0
- package/dist/plugin/anthropic/index.js.map +1 -0
- package/dist/plugin/anthropic/index.test.d.ts +1 -0
- package/dist/plugin/anthropic/index.test.js +39 -0
- package/dist/plugin/anthropic/index.test.js.map +1 -0
- package/dist/plugin/index.d.ts +3 -0
- package/dist/plugin/index.js +124 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/read-media.d.ts +23 -0
- package/dist/plugin/read-media.js +72 -0
- package/dist/plugin/read-media.js.map +1 -0
- package/dist/plugin/session-id/index.d.ts +3 -0
- package/dist/plugin/session-id/index.js +18 -0
- package/dist/plugin/session-id/index.js.map +1 -0
- package/dist/plugin.e2e.test.d.ts +1 -0
- package/dist/plugin.e2e.test.js +92 -0
- package/dist/plugin.e2e.test.js.map +1 -0
- package/dist/preference-commands.e2e.test.d.ts +1 -0
- package/dist/preference-commands.e2e.test.js +555 -0
- package/dist/preference-commands.e2e.test.js.map +1 -0
- package/dist/probe-live.tmp.d.ts +1 -0
- package/dist/probe-live.tmp.js +82 -0
- package/dist/probe-live.tmp.js.map +1 -0
- package/dist/project.d.ts +58 -0
- package/dist/project.js +169 -0
- package/dist/project.js.map +1 -0
- package/dist/prompt.d.ts +112 -0
- package/dist/prompt.js +577 -0
- package/dist/prompt.js.map +1 -0
- package/dist/questions.d.ts +59 -0
- package/dist/questions.e2e.test.d.ts +1 -0
- package/dist/questions.e2e.test.js +290 -0
- package/dist/questions.e2e.test.js.map +1 -0
- package/dist/questions.js +231 -0
- package/dist/questions.js.map +1 -0
- package/dist/queue.d.ts +45 -0
- package/dist/queue.e2e.test.d.ts +1 -0
- package/dist/queue.e2e.test.js +220 -0
- package/dist/queue.e2e.test.js.map +1 -0
- package/dist/queue.js +132 -0
- package/dist/queue.js.map +1 -0
- package/dist/remote-send.d.ts +32 -0
- package/dist/remote-send.e2e.test.d.ts +1 -0
- package/dist/remote-send.e2e.test.js +89 -0
- package/dist/remote-send.e2e.test.js.map +1 -0
- package/dist/remote-send.js +105 -0
- package/dist/remote-send.js.map +1 -0
- package/dist/renderer.e2e.test.d.ts +1 -0
- package/dist/renderer.e2e.test.js +357 -0
- package/dist/renderer.e2e.test.js.map +1 -0
- package/dist/restart.e2e.test.d.ts +1 -0
- package/dist/restart.e2e.test.js +68 -0
- package/dist/restart.e2e.test.js.map +1 -0
- package/dist/routes.d.ts +24 -0
- package/dist/routes.js +42 -0
- package/dist/routes.js.map +1 -0
- package/dist/routes.test.d.ts +1 -0
- package/dist/routes.test.js +79 -0
- package/dist/routes.test.js.map +1 -0
- package/dist/routines.e2e.test.d.ts +1 -0
- package/dist/routines.e2e.test.js +188 -0
- package/dist/routines.e2e.test.js.map +1 -0
- package/dist/scheduler.d.ts +116 -0
- package/dist/scheduler.e2e.test.d.ts +1 -0
- package/dist/scheduler.e2e.test.js +163 -0
- package/dist/scheduler.e2e.test.js.map +1 -0
- package/dist/scheduler.js +602 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/scheduler.test.d.ts +1 -0
- package/dist/scheduler.test.js +180 -0
- package/dist/scheduler.test.js.map +1 -0
- package/dist/schema-sql.d.ts +1 -0
- package/dist/schema-sql.js +3 -0
- package/dist/schema-sql.js.map +1 -0
- package/dist/schema.d.ts +2968 -0
- package/dist/schema.js +95 -252
- package/dist/schema.js.map +1 -0
- package/dist/session-commands.e2e.test.d.ts +1 -0
- package/dist/session-commands.e2e.test.js +285 -0
- package/dist/session-commands.e2e.test.js.map +1 -0
- package/dist/session-events.d.ts +83 -0
- package/dist/session-events.js +260 -0
- package/dist/session-events.js.map +1 -0
- package/dist/session-ops.e2e.test.d.ts +1 -0
- package/dist/session-ops.e2e.test.js +114 -0
- package/dist/session-ops.e2e.test.js.map +1 -0
- package/dist/sessions.d.ts +121 -0
- package/dist/sessions.js +663 -0
- package/dist/sessions.js.map +1 -0
- package/dist/shell.e2e.test.d.ts +1 -0
- package/dist/shell.e2e.test.js +147 -0
- package/dist/shell.e2e.test.js.map +1 -0
- package/dist/slash-commands.d.ts +62 -0
- package/dist/slash-commands.js +476 -0
- package/dist/slash-commands.js.map +1 -0
- package/dist/slash-commands.test.d.ts +1 -0
- package/dist/slash-commands.test.js +87 -0
- package/dist/slash-commands.test.js.map +1 -0
- package/dist/sleep.e2e.test.d.ts +1 -0
- package/dist/sleep.e2e.test.js +115 -487
- package/dist/sleep.e2e.test.js.map +1 -0
- package/dist/sleeps.d.ts +37 -0
- package/dist/sleeps.js +220 -0
- package/dist/sleeps.js.map +1 -0
- package/dist/store.d.ts +10 -0
- package/dist/store.js +8 -28
- package/dist/store.js.map +1 -0
- package/dist/system-prompt.d.ts +76 -0
- package/dist/system-prompt.js +852 -0
- package/dist/system-prompt.js.map +1 -0
- package/dist/tasks.e2e.test.d.ts +1 -0
- package/dist/tasks.e2e.test.js +173 -0
- package/dist/tasks.e2e.test.js.map +1 -0
- package/dist/test/auth-plugin/index.d.ts +3 -0
- package/dist/test/auth-plugin/index.js +18 -0
- package/dist/test/auth-plugin/index.js.map +1 -0
- package/dist/test/fake-mcp-server.d.ts +1 -0
- package/dist/test/fake-mcp-server.js +45 -0
- package/dist/test/fake-mcp-server.js.map +1 -0
- package/dist/test/harness.d.ts +246 -0
- package/dist/test/harness.js +704 -0
- package/dist/test/harness.js.map +1 -0
- package/dist/test/replay.d.ts +14 -0
- package/dist/test/replay.js +75 -0
- package/dist/test/replay.js.map +1 -0
- package/dist/thread-reducer.d.ts +172 -0
- package/dist/thread-reducer.fixtures.test.d.ts +1 -0
- package/dist/thread-reducer.fixtures.test.js +360 -0
- package/dist/thread-reducer.fixtures.test.js.map +1 -0
- package/dist/thread-reducer.js +497 -0
- package/dist/thread-reducer.js.map +1 -0
- package/dist/thread-reducer.test.d.ts +1 -0
- package/dist/thread-reducer.test.js +369 -0
- package/dist/thread-reducer.test.js.map +1 -0
- package/dist/tts.test.d.ts +1 -0
- package/dist/tts.test.js +147 -0
- package/dist/tts.test.js.map +1 -0
- package/dist/voice-agent.d.ts +33 -0
- package/dist/voice-agent.js +159 -0
- package/dist/voice-agent.js.map +1 -0
- package/dist/voice-attachments.e2e.test.d.ts +1 -0
- package/dist/voice-attachments.e2e.test.js +256 -0
- package/dist/voice-attachments.e2e.test.js.map +1 -0
- package/dist/voice-call.d.ts +59 -0
- package/dist/voice-call.e2e.test.d.ts +1 -0
- package/dist/voice-call.e2e.test.js +259 -0
- package/dist/voice-call.e2e.test.js.map +1 -0
- package/dist/voice-call.js +760 -0
- package/dist/voice-call.js.map +1 -0
- package/dist/voice-openai.e2e.test.d.ts +1 -0
- package/dist/voice-openai.e2e.test.js +161 -0
- package/dist/voice-openai.e2e.test.js.map +1 -0
- package/dist/voice.d.ts +116 -0
- package/dist/voice.js +619 -717
- package/dist/voice.js.map +1 -0
- package/dist/working-directory.e2e.test.d.ts +1 -0
- package/dist/working-directory.e2e.test.js +231 -0
- package/dist/working-directory.e2e.test.js.map +1 -0
- package/dist/worktrees.d.ts +54 -0
- package/dist/worktrees.js +247 -709
- package/dist/worktrees.js.map +1 -0
- package/dist/worktrees.test.d.ts +1 -0
- package/dist/worktrees.test.js +97 -952
- package/dist/worktrees.test.js.map +1 -0
- package/package.json +38 -73
- package/skills/kimaki-debug/SKILL.md +44 -0
- package/skills/kimaki-tunnel/SKILL.md +34 -0
- package/src/agent-ui.e2e.test.ts +134 -0
- package/src/agent-ui.ts +216 -0
- package/src/analytics.e2e.test.ts +138 -0
- package/src/analytics.test.ts +122 -182
- package/src/analytics.ts +206 -258
- package/src/autostart.ts +90 -0
- package/src/bot.ts +196 -0
- package/src/btw.e2e.test.ts +130 -0
- package/src/builtin-skills.test.ts +29 -0
- package/src/builtin-skills.ts +59 -0
- package/src/catalog-refresh.e2e.test.ts +112 -0
- package/src/cli/bot.ts +425 -0
- package/src/cli/discord.ts +116 -0
- package/src/cli/project.ts +147 -0
- package/src/cli/schedule.ts +151 -0
- package/src/cli/session.ts +252 -0
- package/src/cli/shared.ts +139 -0
- package/src/cli-discord.e2e.test.ts +79 -0
- package/src/cli-lock.e2e.test.ts +530 -0
- package/src/cli-read.e2e.test.ts +83 -0
- package/src/cli-sessions.e2e.test.ts +120 -0
- package/src/cli.ts +35 -418
- package/src/commands/login-commands.ts +360 -0
- package/src/commands/preference-commands.ts +599 -0
- package/src/commands/session-commands.ts +289 -0
- package/src/commands/thread-commands.ts +324 -0
- package/src/commands/worktree-commands.ts +288 -0
- package/src/commands.e2e.test.ts +290 -0
- package/src/credentials.ts +425 -0
- package/src/db.test.ts +344 -759
- package/src/db.ts +66 -284
- package/src/duration.ts +18 -0
- package/src/effects.ts +337 -0
- package/src/errors.ts +39 -228
- package/src/event-loop.ts +471 -0
- package/src/file-edit-log.test.ts +68 -272
- package/src/file-edit-log.ts +108 -231
- package/src/fixtures/v1-schema.sql +241 -0
- package/src/fixtures/voice.ogg +0 -0
- package/src/format-parts.test.ts +150 -0
- package/src/format-parts.ts +405 -0
- package/src/gateway-replay.e2e.test.ts +116 -0
- package/src/harness.e2e.test.ts +124 -0
- package/src/hello-thread.e2e.test.ts +223 -0
- package/src/ingress.ts +334 -0
- package/src/interaction-context.ts +131 -0
- package/src/interrupt.e2e.test.ts +151 -0
- package/src/legacy.e2e.test.ts +105 -0
- package/src/live-call.ts +249 -0
- package/src/lock-routes.ts +625 -0
- package/src/lock-server.ts +233 -0
- package/src/logger.ts +120 -207
- package/src/login.e2e.test.ts +86 -0
- package/src/main.ts +238 -0
- package/src/markdown/components.ts +102 -0
- package/src/markdown/markdown.test.ts +414 -0
- package/src/markdown/render-markdown.ts +288 -0
- package/src/migrations.ts +198 -0
- package/src/onboarding-cli.e2e.test.ts +215 -0
- package/src/onboarding.e2e.test.ts +171 -0
- package/src/onboarding.ts +297 -0
- package/src/opencode-server.test.ts +24 -0
- package/src/opencode-server.ts +464 -0
- package/src/permissions.e2e.test.ts +191 -0
- package/src/permissions.ts +121 -0
- package/src/plugin/anthropic/index.test.ts +39 -0
- package/src/plugin/anthropic/index.ts +213 -0
- package/src/plugin/index.ts +112 -0
- package/src/plugin.e2e.test.ts +117 -0
- package/src/preference-commands.e2e.test.ts +597 -0
- package/src/project.ts +216 -0
- package/src/prompt.ts +664 -0
- package/src/questions.e2e.test.ts +328 -0
- package/src/questions.ts +322 -0
- package/src/queue.e2e.test.ts +253 -0
- package/src/queue.ts +158 -0
- package/src/remote-send.e2e.test.ts +91 -0
- package/src/remote-send.ts +110 -0
- package/src/renderer.e2e.test.ts +390 -0
- package/src/restart.e2e.test.ts +90 -0
- package/src/routes.test.ts +81 -0
- package/src/routes.ts +48 -0
- package/src/routines.e2e.test.ts +210 -0
- package/src/scheduler.e2e.test.ts +182 -0
- package/src/scheduler.test.ts +183 -0
- package/src/scheduler.ts +648 -0
- package/src/schema-sql.ts +3 -0
- package/src/schema.ts +95 -271
- package/src/session-commands.e2e.test.ts +326 -0
- package/src/session-events.ts +301 -0
- package/src/session-ops.e2e.test.ts +141 -0
- package/src/sessions.ts +804 -0
- package/src/shell.e2e.test.ts +173 -0
- package/src/slash-commands.test.ts +89 -0
- package/src/slash-commands.ts +540 -0
- package/src/sleep.e2e.test.ts +135 -552
- package/src/sleeps.ts +230 -0
- package/src/store.ts +19 -217
- package/src/system-prompt.ts +923 -0
- package/src/test/auth-plugin/index.ts +17 -0
- package/src/test/fake-mcp-server.ts +49 -0
- package/src/test/harness.ts +957 -0
- package/src/test/replay.ts +90 -0
- package/src/thread-reducer.fixtures.test.ts +374 -0
- package/src/thread-reducer.test.ts +380 -0
- package/src/thread-reducer.ts +671 -0
- package/src/tts.test.ts +150 -0
- package/src/voice-agent.ts +196 -0
- package/src/voice-attachments.e2e.test.ts +301 -0
- package/src/voice-call.e2e.test.ts +293 -0
- package/src/voice-call.ts +764 -0
- package/src/voice-openai.e2e.test.ts +191 -0
- package/src/voice.ts +668 -988
- package/src/working-directory.e2e.test.ts +226 -0
- package/src/worktrees.test.ts +89 -1115
- package/src/worktrees.ts +195 -957
- package/bin.js +0 -2
- package/dist/agent-model.e2e.test.js +0 -1223
- package/dist/ai-tool-to-genai.js +0 -233
- package/dist/ai-tool-to-genai.test.js +0 -267
- package/dist/ai-tool.js +0 -6
- package/dist/anthropic-account-identity.js +0 -70
- package/dist/anthropic-account-identity.test.js +0 -38
- package/dist/anthropic-auth-plugin.js +0 -958
- package/dist/anthropic-auth-plugin.test.js +0 -115
- package/dist/anthropic-auth-state.js +0 -186
- package/dist/anthropic-auth-state.test.js +0 -203
- package/dist/bash-tool-schema-plugin.js +0 -50
- package/dist/bash-tool-schema-plugin.test.js +0 -68
- package/dist/bin.js +0 -151
- package/dist/bot-lifecycle.test.js +0 -206
- package/dist/btw-prefix-detection.js +0 -24
- package/dist/btw-prefix-detection.test.js +0 -130
- package/dist/cache-drift-plugin.js +0 -183
- package/dist/cache-rewrite.js +0 -39
- package/dist/cache-rewrite.test.js +0 -41
- package/dist/channel-management.js +0 -347
- package/dist/cli-commands/bot.js +0 -254
- package/dist/cli-commands/maintenance.js +0 -171
- package/dist/cli-commands/misc.js +0 -153
- package/dist/cli-commands/project.js +0 -510
- package/dist/cli-commands/send.js +0 -659
- package/dist/cli-commands/session.js +0 -889
- package/dist/cli-commands/task.js +0 -277
- package/dist/cli-commands/thread.js +0 -63
- package/dist/cli-commands/user.js +0 -145
- package/dist/cli-parsing.test.js +0 -226
- package/dist/cli-runner.js +0 -1591
- package/dist/cli-runner.test.js +0 -119
- package/dist/cli-send-thread.e2e.test.js +0 -470
- package/dist/cloudflare-transcription.js +0 -56
- package/dist/commands/abort.js +0 -84
- package/dist/commands/action-buttons.js +0 -248
- package/dist/commands/add-project.js +0 -111
- package/dist/commands/agent.js +0 -658
- package/dist/commands/ask-question.js +0 -371
- package/dist/commands/ask-question.test.js +0 -150
- package/dist/commands/btw.js +0 -275
- package/dist/commands/compact.js +0 -117
- package/dist/commands/context-usage.js +0 -194
- package/dist/commands/context-usage.test.js +0 -49
- package/dist/commands/create-new-project.js +0 -138
- package/dist/commands/diff.js +0 -63
- package/dist/commands/file-upload.js +0 -280
- package/dist/commands/fork-subagent.js +0 -175
- package/dist/commands/fork.js +0 -291
- package/dist/commands/gemini-apikey.js +0 -123
- package/dist/commands/last-sessions.js +0 -129
- package/dist/commands/login.js +0 -893
- package/dist/commands/mcp.js +0 -239
- package/dist/commands/memory-snapshot.js +0 -24
- package/dist/commands/mention-mode.js +0 -42
- package/dist/commands/merge-worktree.js +0 -205
- package/dist/commands/model-variant.js +0 -390
- package/dist/commands/model.js +0 -1012
- package/dist/commands/multioauth.js +0 -425
- package/dist/commands/new-worktree.js +0 -625
- package/dist/commands/paginated-select.js +0 -57
- package/dist/commands/permissions.js +0 -327
- package/dist/commands/queue.js +0 -347
- package/dist/commands/queue.test.js +0 -15
- package/dist/commands/remove-project.js +0 -111
- package/dist/commands/restart-opencode-server.js +0 -133
- package/dist/commands/resume.js +0 -148
- package/dist/commands/run-command.js +0 -79
- package/dist/commands/screenshare.js +0 -307
- package/dist/commands/screenshare.test.js +0 -20
- package/dist/commands/session-id.js +0 -78
- package/dist/commands/session.js +0 -248
- package/dist/commands/share.js +0 -80
- package/dist/commands/tasks.js +0 -296
- package/dist/commands/types.js +0 -2
- package/dist/commands/undo-redo.js +0 -313
- package/dist/commands/unset-model.js +0 -116
- package/dist/commands/upgrade.js +0 -41
- package/dist/commands/user-command.js +0 -196
- package/dist/commands/verbosity.js +0 -124
- package/dist/commands/vscode.js +0 -295
- package/dist/commands/worktrees.js +0 -548
- package/dist/condense-memory.js +0 -33
- package/dist/config.js +0 -126
- package/dist/context-awareness-plugin.js +0 -357
- package/dist/context-awareness-plugin.test.js +0 -126
- package/dist/cpu-profiler.js +0 -211
- package/dist/cpu-profiler.test.js +0 -160
- package/dist/critique-utils.js +0 -95
- package/dist/database.js +0 -1074
- package/dist/debounce-timeout.js +0 -28
- package/dist/debounced-process-flush.js +0 -77
- package/dist/default-channel-provisioning.test.js +0 -149
- package/dist/discord-bot.js +0 -1432
- package/dist/discord-command-registration.js +0 -519
- package/dist/discord-command-registration.test.js +0 -17
- package/dist/discord-urls.js +0 -81
- package/dist/discord-utils.js +0 -789
- package/dist/discord-utils.test.js +0 -400
- package/dist/escape-backticks.test.js +0 -429
- package/dist/event-stream-real-capture.e2e.test.js +0 -533
- package/dist/eventsource-parser.test.js +0 -327
- package/dist/exec-async.js +0 -38
- package/dist/external-directory-permissions.e2e.test.js +0 -86
- package/dist/external-directory-project-deny.e2e.test.js +0 -70
- package/dist/external-opencode-sync.js +0 -620
- package/dist/external-opencode-sync.test.js +0 -206
- package/dist/extract-sdk-error-message.test.js +0 -13
- package/dist/format-tables.js +0 -728
- package/dist/format-tables.test.js +0 -915
- package/dist/forum-sync/config.js +0 -79
- package/dist/forum-sync/discord-operations.js +0 -157
- package/dist/forum-sync/index.js +0 -5
- package/dist/forum-sync/markdown.js +0 -110
- package/dist/forum-sync/sync-to-discord.js +0 -417
- package/dist/forum-sync/sync-to-files.js +0 -190
- package/dist/forum-sync/types.js +0 -53
- package/dist/forum-sync/watchers.js +0 -322
- package/dist/gateway-proxy-reconnect.e2e.test.js +0 -414
- package/dist/gateway-proxy.e2e.test.js +0 -488
- package/dist/genai-worker-wrapper.js +0 -111
- package/dist/genai-worker.js +0 -309
- package/dist/genai.js +0 -232
- package/dist/git-worktree-core.js +0 -461
- package/dist/guild-categories.test.js +0 -225
- package/dist/heap-monitor.js +0 -122
- package/dist/hrana-server.js +0 -322
- package/dist/hrana-server.test.js +0 -99
- package/dist/html-actions.js +0 -123
- package/dist/html-actions.test.js +0 -70
- package/dist/html-components.js +0 -115
- package/dist/html-components.test.js +0 -34
- package/dist/image-optimizer-plugin.js +0 -153
- package/dist/image-utils.js +0 -112
- package/dist/interaction-handler.js +0 -578
- package/dist/ipc-polling.js +0 -245
- package/dist/ipc-tools-plugin.js +0 -251
- package/dist/kimaki-digital-twin.e2e.test.js +0 -161
- package/dist/kimaki-opencode-plugin-loading.e2e.test.js +0 -158
- package/dist/kimaki-opencode-plugin.js +0 -33
- package/dist/kimaki-opencode-plugin.test.js +0 -126
- package/dist/kimaki-workspace-adaptor.js +0 -118
- package/dist/limit-heading-depth.js +0 -25
- package/dist/limit-heading-depth.test.js +0 -105
- package/dist/list-channel-threads.js +0 -163
- package/dist/list-channel-threads.test.js +0 -80
- package/dist/markdown.js +0 -455
- package/dist/markdown.test.js +0 -411
- package/dist/memory-overview-plugin.js +0 -123
- package/dist/message-formatting.js +0 -788
- package/dist/message-formatting.test.js +0 -1132
- package/dist/message-preprocessing.js +0 -419
- package/dist/oauth-rotation-shared.js +0 -253
- package/dist/onboarding-tutorial.js +0 -163
- package/dist/onboarding-welcome.js +0 -37
- package/dist/openai-auth-plugin.js +0 -125
- package/dist/openai-auth-state.js +0 -237
- package/dist/openai-realtime.js +0 -224
- package/dist/opencode-command-detection.js +0 -65
- package/dist/opencode-command-detection.test.js +0 -240
- package/dist/opencode-command.js +0 -181
- package/dist/opencode-command.test.js +0 -218
- package/dist/opencode-interrupt-plugin.js +0 -253
- package/dist/opencode-interrupt-plugin.test.js +0 -293
- package/dist/opencode.js +0 -1217
- package/dist/parse-permission-rules.test.js +0 -117
- package/dist/patch-text-parser.js +0 -97
- package/dist/plugin-logger.js +0 -105
- package/dist/plugin-opencode-client.js +0 -54
- package/dist/privacy-sanitizer.js +0 -105
- package/dist/project-add.test.js +0 -62
- package/dist/question-abort-clears-dropdown.e2e.test.js +0 -89
- package/dist/question-abort-resume.e2e.test.js +0 -100
- package/dist/question-abort-retry-text-before-dropdown.e2e.test.js +0 -150
- package/dist/question-text-before-dropdown.e2e.test.js +0 -52
- package/dist/queue-advanced-abort.e2e.test.js +0 -348
- package/dist/queue-advanced-action-buttons.e2e.test.js +0 -209
- package/dist/queue-advanced-e2e-setup.js +0 -1043
- package/dist/queue-advanced-footer.e2e.test.js +0 -286
- package/dist/queue-advanced-model-switch.e2e.test.js +0 -297
- package/dist/queue-advanced-permissions-typing.e2e.test.js +0 -189
- package/dist/queue-advanced-question.e2e.test.js +0 -266
- package/dist/queue-advanced-typing-interrupt.e2e.test.js +0 -113
- package/dist/queue-advanced-typing.e2e.test.js +0 -151
- package/dist/queue-delete-message.e2e.test.js +0 -216
- package/dist/queue-drain-after-interactive-ui.e2e.test.js +0 -120
- package/dist/queue-interrupt-drain.e2e.test.js +0 -256
- package/dist/queue-question-select-drain.e2e.test.js +0 -162
- package/dist/runtime-idle-sweeper.js +0 -52
- package/dist/runtime-lifecycle.e2e.test.js +0 -570
- package/dist/sentry.js +0 -23
- package/dist/session-handler/agent-utils.js +0 -65
- package/dist/session-handler/event-stream-state.js +0 -1225
- package/dist/session-handler/event-stream-state.test.js +0 -3160
- package/dist/session-handler/global-event-listener.js +0 -212
- package/dist/session-handler/model-utils.js +0 -311
- package/dist/session-handler/model-utils.test.js +0 -445
- package/dist/session-handler/opencode-session-event-log.js +0 -121
- package/dist/session-handler/thread-ingress.test.js +0 -41
- package/dist/session-handler/thread-runtime-state.js +0 -209
- package/dist/session-handler/thread-session-runtime-summary.test.js +0 -121
- package/dist/session-handler/thread-session-runtime.js +0 -4320
- package/dist/session-handler.js +0 -9
- package/dist/session-search.js +0 -219
- package/dist/session-search.test.js +0 -287
- package/dist/session-sleep.test.js +0 -224
- package/dist/session-title-rename.test.js +0 -128
- package/dist/skill-filter.js +0 -43
- package/dist/skill-filter.test.js +0 -86
- package/dist/startup-service.js +0 -153
- package/dist/startup-time.e2e.test.js +0 -297
- package/dist/system-message.js +0 -806
- package/dist/system-message.test.js +0 -917
- package/dist/task-id-plugin.js +0 -16
- package/dist/task-runner.js +0 -554
- package/dist/task-schedule.js +0 -298
- package/dist/task-schedule.test.js +0 -366
- package/dist/test-utils.js +0 -385
- package/dist/thinking-utils.js +0 -45
- package/dist/thinking-utils.test.js +0 -35
- package/dist/thread-message-queue.e2e.test.js +0 -1227
- package/dist/tools.js +0 -357
- package/dist/undo-redo.e2e.test.js +0 -171
- package/dist/unnest-code-blocks.js +0 -146
- package/dist/unnest-code-blocks.test.js +0 -673
- package/dist/upgrade.js +0 -114
- package/dist/utils.js +0 -148
- package/dist/voice-attachment.js +0 -56
- package/dist/voice-handler.js +0 -727
- package/dist/voice-message.e2e.test.js +0 -1254
- package/dist/voice-routing-input.e2e.test.js +0 -195
- package/dist/voice-routing-question.e2e.test.js +0 -182
- package/dist/voice.test.js +0 -500
- package/dist/wait-session.js +0 -193
- package/dist/websockify.js +0 -69
- package/dist/worker-types.js +0 -4
- package/dist/worktree-clone-isolation.e2e.test.js +0 -188
- package/dist/worktree-lifecycle.e2e.test.js +0 -735
- package/dist/worktree-utils.js +0 -3
- package/dist/xai-auth-plugin.js +0 -238
- package/dist/xai-auth-state.js +0 -234
- package/dist/xai-auth-state.test.js +0 -183
- package/dist/xml.js +0 -92
- package/dist/xml.test.js +0 -32
- package/skills/bump-holocron-consumers/SKILL.md +0 -137
- package/skills/critique/SKILL.md +0 -116
- package/skills/egaki/SKILL.md +0 -86
- package/skills/errore/SKILL.md +0 -501
- package/skills/goke/SKILL.md +0 -695
- package/skills/holocron/SKILL.md +0 -942
- package/skills/lintcn/SKILL.md +0 -873
- package/skills/new-skill/SKILL.md +0 -339
- package/skills/npm-package/SKILL.md +0 -692
- package/skills/opensrc/SKILL.md +0 -102
- package/skills/playwriter/SKILL.md +0 -35
- package/skills/profano/SKILL.md +0 -33
- package/skills/readme.md +0 -20
- package/skills/sigillo/SKILL.md +0 -370
- package/skills/spiceflow/SKILL.md +0 -80
- package/skills/strada/SKILL.md +0 -104
- package/skills/termcast/SKILL.md +0 -133
- package/skills/tuistory/SKILL.md +0 -237
- package/skills/usecomputer/SKILL.md +0 -264
- package/skills/zele/SKILL.md +0 -81
- package/src/agent-model.e2e.test.ts +0 -1557
- package/src/ai-tool-to-genai.test.ts +0 -296
- package/src/ai-tool-to-genai.ts +0 -283
- package/src/ai-tool.ts +0 -39
- package/src/anthropic-account-identity.test.ts +0 -52
- package/src/anthropic-account-identity.ts +0 -96
- package/src/anthropic-auth-plugin.test.ts +0 -135
- package/src/anthropic-auth-plugin.ts +0 -1180
- package/src/anthropic-auth-state.test.ts +0 -259
- package/src/anthropic-auth-state.ts +0 -272
- package/src/bash-tool-schema-plugin.test.ts +0 -84
- package/src/bash-tool-schema-plugin.ts +0 -77
- package/src/bin.ts +0 -173
- package/src/bot-lifecycle.test.ts +0 -252
- package/src/btw-prefix-detection.test.ts +0 -142
- package/src/btw-prefix-detection.ts +0 -30
- package/src/cache-drift-plugin.ts +0 -249
- package/src/cache-rewrite.test.ts +0 -49
- package/src/cache-rewrite.ts +0 -96
- package/src/channel-management.ts +0 -494
- package/src/cli-commands/bot.ts +0 -374
- package/src/cli-commands/maintenance.ts +0 -237
- package/src/cli-commands/misc.ts +0 -208
- package/src/cli-commands/project.ts +0 -680
- package/src/cli-commands/send.ts +0 -885
- package/src/cli-commands/session.ts +0 -1181
- package/src/cli-commands/task.ts +0 -358
- package/src/cli-commands/thread.ts +0 -86
- package/src/cli-commands/user.ts +0 -195
- package/src/cli-parsing.test.ts +0 -305
- package/src/cli-runner.test.ts +0 -166
- package/src/cli-runner.ts +0 -2157
- package/src/cli-send-thread.e2e.test.ts +0 -609
- package/src/cloudflare-transcription.ts +0 -76
- package/src/commands/abort.ts +0 -113
- package/src/commands/action-buttons.ts +0 -371
- package/src/commands/add-project.ts +0 -146
- package/src/commands/agent.ts +0 -911
- package/src/commands/ask-question.test.ts +0 -177
- package/src/commands/ask-question.ts +0 -532
- package/src/commands/btw.ts +0 -356
- package/src/commands/compact.ts +0 -154
- package/src/commands/context-usage.test.ts +0 -57
- package/src/commands/context-usage.ts +0 -267
- package/src/commands/create-new-project.ts +0 -203
- package/src/commands/diff.ts +0 -91
- package/src/commands/file-upload.ts +0 -398
- package/src/commands/fork-subagent.ts +0 -262
- package/src/commands/fork.ts +0 -421
- package/src/commands/gemini-apikey.ts +0 -205
- package/src/commands/last-sessions.ts +0 -176
- package/src/commands/login.ts +0 -1182
- package/src/commands/mcp.ts +0 -307
- package/src/commands/memory-snapshot.ts +0 -30
- package/src/commands/mention-mode.ts +0 -66
- package/src/commands/merge-worktree.ts +0 -282
- package/src/commands/model-variant.ts +0 -522
- package/src/commands/model.ts +0 -1377
- package/src/commands/multioauth.ts +0 -508
- package/src/commands/new-worktree.ts +0 -835
- package/src/commands/paginated-select.ts +0 -81
- package/src/commands/permissions.ts +0 -458
- package/src/commands/queue.test.ts +0 -19
- package/src/commands/queue.ts +0 -471
- package/src/commands/remove-project.ts +0 -152
- package/src/commands/restart-opencode-server.ts +0 -173
- package/src/commands/resume.ts +0 -229
- package/src/commands/run-command.ts +0 -123
- package/src/commands/screenshare.test.ts +0 -30
- package/src/commands/screenshare.ts +0 -388
- package/src/commands/session-id.ts +0 -109
- package/src/commands/session.ts +0 -319
- package/src/commands/share.ts +0 -106
- package/src/commands/tasks.ts +0 -399
- package/src/commands/types.ts +0 -25
- package/src/commands/undo-redo.ts +0 -394
- package/src/commands/unset-model.ts +0 -152
- package/src/commands/upgrade.ts +0 -51
- package/src/commands/user-command.ts +0 -260
- package/src/commands/verbosity.ts +0 -172
- package/src/commands/vscode.ts +0 -378
- package/src/commands/worktrees.ts +0 -762
- package/src/condense-memory.ts +0 -36
- package/src/config.ts +0 -147
- package/src/context-awareness-plugin.test.ts +0 -144
- package/src/context-awareness-plugin.ts +0 -508
- package/src/cpu-profiler.test.ts +0 -183
- package/src/cpu-profiler.ts +0 -293
- package/src/critique-utils.ts +0 -139
- package/src/database.ts +0 -1484
- package/src/debounce-timeout.ts +0 -43
- package/src/debounced-process-flush.ts +0 -104
- package/src/default-channel-provisioning.test.ts +0 -156
- package/src/discord-bot.ts +0 -1852
- package/src/discord-command-registration.test.ts +0 -20
- package/src/discord-command-registration.ts +0 -704
- package/src/discord-urls.ts +0 -88
- package/src/discord-utils.test.ts +0 -470
- package/src/discord-utils.ts +0 -1079
- package/src/escape-backticks.test.ts +0 -469
- package/src/event-stream-real-capture.e2e.test.ts +0 -692
- package/src/eventsource-parser.test.ts +0 -351
- package/src/exec-async.ts +0 -44
- package/src/external-directory-permissions.e2e.test.ts +0 -103
- package/src/external-directory-project-deny.e2e.test.ts +0 -84
- package/src/external-opencode-sync.test.ts +0 -248
- package/src/external-opencode-sync.ts +0 -867
- package/src/extract-sdk-error-message.test.ts +0 -18
- package/src/format-tables.test.ts +0 -988
- package/src/format-tables.ts +0 -1031
- package/src/forum-sync/config.ts +0 -92
- package/src/forum-sync/discord-operations.ts +0 -245
- package/src/forum-sync/index.ts +0 -9
- package/src/forum-sync/markdown.ts +0 -172
- package/src/forum-sync/sync-to-discord.ts +0 -595
- package/src/forum-sync/sync-to-files.ts +0 -294
- package/src/forum-sync/types.ts +0 -175
- package/src/forum-sync/watchers.ts +0 -474
- package/src/gateway-proxy-reconnect.e2e.test.ts +0 -553
- package/src/gateway-proxy.e2e.test.ts +0 -648
- package/src/genai-worker-wrapper.ts +0 -164
- package/src/genai-worker.ts +0 -385
- package/src/genai.ts +0 -318
- package/src/git-worktree-core.ts +0 -616
- package/src/guild-categories.test.ts +0 -260
- package/src/heap-monitor.ts +0 -152
- package/src/hrana-server.test.ts +0 -130
- package/src/hrana-server.ts +0 -399
- package/src/html-actions.test.ts +0 -87
- package/src/html-actions.ts +0 -174
- package/src/html-components.test.ts +0 -38
- package/src/html-components.ts +0 -177
- package/src/image-optimizer-plugin.ts +0 -194
- package/src/image-utils.ts +0 -150
- package/src/interaction-handler.ts +0 -775
- package/src/ipc-polling.ts +0 -325
- package/src/ipc-tools-plugin.ts +0 -306
- package/src/kimaki-digital-twin.e2e.test.ts +0 -199
- package/src/kimaki-opencode-plugin-loading.e2e.test.ts +0 -208
- package/src/kimaki-opencode-plugin.test.ts +0 -142
- package/src/kimaki-opencode-plugin.ts +0 -34
- package/src/kimaki-workspace-adaptor.ts +0 -144
- package/src/limit-heading-depth.test.ts +0 -116
- package/src/limit-heading-depth.ts +0 -26
- package/src/list-channel-threads.test.ts +0 -90
- package/src/list-channel-threads.ts +0 -252
- package/src/markdown.test.ts +0 -498
- package/src/markdown.ts +0 -577
- package/src/memory-overview-plugin.ts +0 -159
- package/src/message-formatting.test.ts +0 -1401
- package/src/message-formatting.ts +0 -999
- package/src/message-preprocessing.ts +0 -557
- package/src/oauth-rotation-shared.ts +0 -332
- package/src/onboarding-tutorial.ts +0 -167
- package/src/onboarding-welcome.ts +0 -49
- package/src/openai-auth-plugin.ts +0 -158
- package/src/openai-auth-state.ts +0 -297
- package/src/openai-realtime.ts +0 -358
- package/src/opencode-command-detection.test.ts +0 -307
- package/src/opencode-command-detection.ts +0 -76
- package/src/opencode-command.test.ts +0 -290
- package/src/opencode-command.ts +0 -251
- package/src/opencode-interrupt-plugin.test.ts +0 -419
- package/src/opencode-interrupt-plugin.ts +0 -306
- package/src/opencode.ts +0 -1590
- package/src/parse-permission-rules.test.ts +0 -127
- package/src/patch-text-parser.ts +0 -107
- package/src/plugin-logger.ts +0 -139
- package/src/plugin-opencode-client.ts +0 -71
- package/src/privacy-sanitizer.ts +0 -142
- package/src/project-add.test.ts +0 -80
- package/src/question-abort-clears-dropdown.e2e.test.ts +0 -109
- package/src/question-abort-resume.e2e.test.ts +0 -121
- package/src/question-abort-retry-text-before-dropdown.e2e.test.ts +0 -172
- package/src/question-text-before-dropdown.e2e.test.ts +0 -67
- package/src/queue-advanced-abort.e2e.test.ts +0 -449
- package/src/queue-advanced-action-buttons.e2e.test.ts +0 -271
- package/src/queue-advanced-e2e-setup.ts +0 -1164
- package/src/queue-advanced-footer.e2e.test.ts +0 -357
- package/src/queue-advanced-model-switch.e2e.test.ts +0 -382
- package/src/queue-advanced-permissions-typing.e2e.test.ts +0 -256
- package/src/queue-advanced-question.e2e.test.ts +0 -322
- package/src/queue-advanced-typing-interrupt.e2e.test.ts +0 -147
- package/src/queue-advanced-typing.e2e.test.ts +0 -199
- package/src/queue-delete-message.e2e.test.ts +0 -262
- package/src/queue-drain-after-interactive-ui.e2e.test.ts +0 -152
- package/src/queue-interrupt-drain.e2e.test.ts +0 -299
- package/src/queue-question-select-drain.e2e.test.ts +0 -209
- package/src/runtime-idle-sweeper.ts +0 -76
- package/src/runtime-lifecycle.e2e.test.ts +0 -714
- package/src/schema.sql +0 -251
- package/src/sentry.ts +0 -26
- package/src/session-handler/agent-utils.ts +0 -104
- package/src/session-handler/event-stream-fixtures/real-session-action-buttons.jsonl +0 -45
- package/src/session-handler/event-stream-fixtures/real-session-footer-suppressed-on-pre-idle-interrupt.jsonl +0 -40
- package/src/session-handler/event-stream-fixtures/real-session-permission-external-file.jsonl +0 -23
- package/src/session-handler/event-stream-fixtures/real-session-task-normal.jsonl +0 -22
- package/src/session-handler/event-stream-fixtures/real-session-task-three-parallel-sleeps.jsonl +0 -277
- package/src/session-handler/event-stream-fixtures/real-session-task-user-interruption.jsonl +0 -46
- package/src/session-handler/event-stream-fixtures/session-abort-after-idle-race.jsonl +0 -21
- package/src/session-handler/event-stream-fixtures/session-concurrent-messages-serialized.jsonl +0 -56
- package/src/session-handler/event-stream-fixtures/session-explicit-abort.jsonl +0 -44
- package/src/session-handler/event-stream-fixtures/session-normal-completion.jsonl +0 -29
- package/src/session-handler/event-stream-fixtures/session-tool-call-noisy-stream.jsonl +0 -29
- package/src/session-handler/event-stream-fixtures/session-two-completions-same-session.jsonl +0 -50
- package/src/session-handler/event-stream-fixtures/session-user-interruption.jsonl +0 -59
- package/src/session-handler/event-stream-fixtures/session-voice-queued-followup.jsonl +0 -52
- package/src/session-handler/event-stream-state.test.ts +0 -3431
- package/src/session-handler/event-stream-state.ts +0 -1792
- package/src/session-handler/global-event-listener.ts +0 -258
- package/src/session-handler/model-utils.test.ts +0 -537
- package/src/session-handler/model-utils.ts +0 -489
- package/src/session-handler/opencode-session-event-log.ts +0 -159
- package/src/session-handler/thread-ingress.test.ts +0 -54
- package/src/session-handler/thread-runtime-state.ts +0 -358
- package/src/session-handler/thread-session-runtime-summary.test.ts +0 -169
- package/src/session-handler/thread-session-runtime.ts +0 -5696
- package/src/session-handler.ts +0 -15
- package/src/session-search.test.ts +0 -331
- package/src/session-search.ts +0 -382
- package/src/session-sleep.test.ts +0 -294
- package/src/session-title-rename.test.ts +0 -186
- package/src/skill-filter.test.ts +0 -110
- package/src/skill-filter.ts +0 -63
- package/src/startup-service.ts +0 -200
- package/src/startup-time.e2e.test.ts +0 -377
- package/src/system-message.test.ts +0 -1013
- package/src/system-message.ts +0 -1043
- package/src/task-id-plugin.ts +0 -17
- package/src/task-runner.ts +0 -768
- package/src/task-schedule.test.ts +0 -424
- package/src/task-schedule.ts +0 -470
- package/src/test-utils.ts +0 -549
- package/src/thinking-utils.test.ts +0 -46
- package/src/thinking-utils.ts +0 -82
- package/src/thread-message-queue.e2e.test.ts +0 -1468
- package/src/tools.ts +0 -430
- package/src/undici.d.ts +0 -12
- package/src/undo-redo.e2e.test.ts +0 -219
- package/src/unnest-code-blocks.test.ts +0 -713
- package/src/unnest-code-blocks.ts +0 -185
- package/src/upgrade.ts +0 -127
- package/src/utils.ts +0 -216
- package/src/voice-attachment.ts +0 -79
- package/src/voice-handler.ts +0 -1000
- package/src/voice-message.e2e.test.ts +0 -1513
- package/src/voice-routing-input.e2e.test.ts +0 -203
- package/src/voice-routing-question.e2e.test.ts +0 -188
- package/src/voice.test.ts +0 -565
- package/src/wait-session.ts +0 -291
- package/src/websockify.ts +0 -101
- package/src/worker-types.ts +0 -64
- package/src/worktree-clone-isolation.e2e.test.ts +0 -213
- package/src/worktree-lifecycle.e2e.test.ts +0 -900
- package/src/worktree-utils.ts +0 -4
- package/src/xai-auth-plugin.ts +0 -303
- package/src/xai-auth-state.test.ts +0 -224
- package/src/xai-auth-state.ts +0 -294
- package/src/xml.test.ts +0 -38
- package/src/xml.ts +0 -121
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
// Slash commands and component interactions (spec 14). Registered per guild
|
|
2
|
+
// with one bulk overwrite (guild-scoped route: gateway-proxy rejects global
|
|
3
|
+
// application command routes). Every interaction passes the same permission
|
|
4
|
+
// gate as messages, then goes to its handler with one lookup:
|
|
5
|
+
//
|
|
6
|
+
// feature files ─▶ InteractionRoutes ─▶ createInteractionRegistry (this file)
|
|
7
|
+
// chat command ─▶ commands[name] (else a dynamic command below)
|
|
8
|
+
// button ─▶ buttons[prefix] select ─▶ selects[prefix] modal ─▶ modals[prefix]
|
|
9
|
+
//
|
|
10
|
+
// Handlers only collect input and call the writers (prompt.ts, sessions.ts,
|
|
11
|
+
// ...); session output comes from events.
|
|
12
|
+
//
|
|
13
|
+
// Dynamic commands come from the global OpenCode catalog: one location (the
|
|
14
|
+
// OpenCode global config dir) that loads no project config, so every guild
|
|
15
|
+
// gets the same list. Project-only entries stay reachable through /agent, /command, /skill.
|
|
16
|
+
//
|
|
17
|
+
// agent.list primary agents ─▶ /<agent>-agent prompt?
|
|
18
|
+
// command.list commands ─▶ /<cmd>-cmd arguments?
|
|
19
|
+
// skill.list skills ─▶ /<skill>-skill arguments?
|
|
20
|
+
//
|
|
21
|
+
// Like the OpenCode TUI (client/src/solid/data.ts), the catalog is re-read
|
|
22
|
+
// when agent/command/skill.updated arrive, and after every reconnect (events
|
|
23
|
+
// sent while disconnected are lost):
|
|
24
|
+
//
|
|
25
|
+
// agent|command|skill.updated ─▶ read catalog ─▶ buildCommands ─▶ PUT guild commands (if changed)
|
|
26
|
+
// server.connected ─┘
|
|
27
|
+
//
|
|
28
|
+
// Commands with a colon get no slash command. OpenCode names MCP prompts
|
|
29
|
+
// "server:prompt" and command.list has no source field, so the colon is the
|
|
30
|
+
// only way to leave them out. They still run as `/server:prompt args`
|
|
31
|
+
// messages and from /queue-command.
|
|
32
|
+
//
|
|
33
|
+
// Discord allows 100 commands per guild; skills are cut first.
|
|
34
|
+
|
|
35
|
+
import { isBuiltinSkill } from './builtin-skills.ts'
|
|
36
|
+
import {
|
|
37
|
+
Events,
|
|
38
|
+
MessageFlags,
|
|
39
|
+
PermissionFlagsBits,
|
|
40
|
+
SlashCommandBuilder,
|
|
41
|
+
type AutocompleteInteraction,
|
|
42
|
+
type ButtonInteraction,
|
|
43
|
+
type ChatInputCommandInteraction,
|
|
44
|
+
type Guild,
|
|
45
|
+
type Interaction,
|
|
46
|
+
type ModalSubmitInteraction,
|
|
47
|
+
type RESTPostAPIChatInputApplicationCommandsJSONBody,
|
|
48
|
+
type StringSelectMenuInteraction,
|
|
49
|
+
} from 'discord.js'
|
|
50
|
+
|
|
51
|
+
import { agentUiRoutes } from './agent-ui.ts'
|
|
52
|
+
import { oc, projectOf, type Bot, type ModelChoice } from './bot.ts'
|
|
53
|
+
import { createLoginRoutes } from './commands/login-commands.ts'
|
|
54
|
+
import { applyAgent, createPreferenceRoutes, switchModel, variantChoices, variantModel } from './commands/preference-commands.ts'
|
|
55
|
+
import { sessionRoutes } from './commands/session-commands.ts'
|
|
56
|
+
import { SKIPPED_COMMANDS, threadRoutes } from './commands/thread-commands.ts'
|
|
57
|
+
import { worktreeRoutes } from './commands/worktree-commands.ts'
|
|
58
|
+
import { ConfigError, DiscordError } from './errors.ts'
|
|
59
|
+
import { canUseKimaki } from './ingress.ts'
|
|
60
|
+
import {
|
|
61
|
+
authorOf,
|
|
62
|
+
replyError,
|
|
63
|
+
replyWithEcho,
|
|
64
|
+
resolveTarget,
|
|
65
|
+
respondChoices,
|
|
66
|
+
sessionTarget,
|
|
67
|
+
type InteractionHandler,
|
|
68
|
+
type InteractionRoutes,
|
|
69
|
+
type SlashCommand,
|
|
70
|
+
} from './interaction-context.ts'
|
|
71
|
+
import { createLogger } from './logger.ts'
|
|
72
|
+
import { permissionRoutes } from './permissions.ts'
|
|
73
|
+
import { dispatch } from './prompt.ts'
|
|
74
|
+
import { createQuestionHandlers } from './questions.ts'
|
|
75
|
+
import type { Route } from './routes.ts'
|
|
76
|
+
import { taskRoutes } from './scheduler.ts'
|
|
77
|
+
import { catalogReady, startSession } from './sessions.ts'
|
|
78
|
+
|
|
79
|
+
const logger = createLogger('COMMANDS')
|
|
80
|
+
|
|
81
|
+
const MAX_COMMANDS = 100
|
|
82
|
+
const NAME_LIMIT = 32
|
|
83
|
+
const CATALOG_EVENTS: ReadonlySet<string> = new Set(['server.connected', 'agent.updated', 'command.updated', 'skill.updated'])
|
|
84
|
+
|
|
85
|
+
// --- The registry: every feature's tables, combined once per bot.
|
|
86
|
+
|
|
87
|
+
type PrefixRoute<I> = { prefix: string; run: InteractionHandler<I>; admin: boolean }
|
|
88
|
+
|
|
89
|
+
export type InteractionRegistry = {
|
|
90
|
+
commands: ReadonlyMap<string, SlashCommand & { admin: boolean }>
|
|
91
|
+
// Static command JSON in table order; registered before the dynamic ones.
|
|
92
|
+
definitions: readonly RESTPostAPIChatInputApplicationCommandsJSONBody[]
|
|
93
|
+
buttons: ReadonlyArray<PrefixRoute<ButtonInteraction>>
|
|
94
|
+
selects: ReadonlyArray<PrefixRoute<StringSelectMenuInteraction>>
|
|
95
|
+
modals: ReadonlyArray<PrefixRoute<ModalSubmitInteraction>>
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function prefixRoutes<I>(
|
|
99
|
+
features: readonly InteractionRoutes[],
|
|
100
|
+
table: (feature: InteractionRoutes) => Readonly<Record<string, InteractionHandler<I>>> | undefined,
|
|
101
|
+
): Array<PrefixRoute<I>> {
|
|
102
|
+
const routes = features.flatMap((feature) =>
|
|
103
|
+
Object.entries(table(feature) ?? {}).map(([prefix, run]) => ({ prefix, run, admin: feature.admin === true })),
|
|
104
|
+
)
|
|
105
|
+
const prefixes = routes.map((route) => route.prefix)
|
|
106
|
+
const duplicate = prefixes.find((prefix, index) => prefixes.indexOf(prefix) !== index)
|
|
107
|
+
if (duplicate !== undefined) throw new Error(`Two interaction routes use the custom ID prefix ${duplicate}`)
|
|
108
|
+
// Longest first: a prefix that starts another prefix never hides it.
|
|
109
|
+
return routes.sort((a, b) => b.prefix.length - a.prefix.length)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function byPrefix<I>(routes: ReadonlyArray<PrefixRoute<I>>, customId: string): PrefixRoute<I> | null {
|
|
113
|
+
return routes.find((route) => customId.startsWith(route.prefix)) ?? null
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function combineRoutes(features: readonly InteractionRoutes[]): InteractionRegistry {
|
|
117
|
+
const commands = new Map<string, SlashCommand & { admin: boolean }>()
|
|
118
|
+
const definitions: RESTPostAPIChatInputApplicationCommandsJSONBody[] = []
|
|
119
|
+
for (const feature of features) {
|
|
120
|
+
for (const [name, command] of Object.entries(feature.commands ?? {})) {
|
|
121
|
+
const json = command.definition.toJSON()
|
|
122
|
+
if (json.name !== name) throw new Error(`Slash command ${json.name} is registered under ${name}`)
|
|
123
|
+
if (commands.has(name)) throw new Error(`Two features define /${name}`)
|
|
124
|
+
commands.set(name, { ...command, admin: feature.admin === true })
|
|
125
|
+
definitions.push({ ...json, dm_permission: false })
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
commands,
|
|
130
|
+
definitions,
|
|
131
|
+
buttons: prefixRoutes(features, (feature) => feature.buttons),
|
|
132
|
+
selects: prefixRoutes(features, (feature) => feature.selects),
|
|
133
|
+
modals: prefixRoutes(features, (feature) => feature.modals),
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// One per bot: the wizard and form features keep per-bot state in their closures.
|
|
138
|
+
export function createInteractionRegistry(): InteractionRegistry {
|
|
139
|
+
return combineRoutes([
|
|
140
|
+
worktreeRoutes,
|
|
141
|
+
createLoginRoutes(),
|
|
142
|
+
sessionRoutes,
|
|
143
|
+
threadRoutes,
|
|
144
|
+
createPreferenceRoutes(),
|
|
145
|
+
taskRoutes,
|
|
146
|
+
agentUiRoutes,
|
|
147
|
+
permissionRoutes,
|
|
148
|
+
createQuestionHandlers(),
|
|
149
|
+
catalogRoutes(),
|
|
150
|
+
])
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// --- Dynamic commands
|
|
154
|
+
|
|
155
|
+
export type DynamicCommand =
|
|
156
|
+
| { kind: 'agent'; name: string }
|
|
157
|
+
| { kind: 'command'; name: string }
|
|
158
|
+
| { kind: 'skill'; id: string }
|
|
159
|
+
|
|
160
|
+
export type Catalog = {
|
|
161
|
+
agents: ReadonlyArray<{ id: string; name: string; description?: string; mode: string; hidden: boolean }>
|
|
162
|
+
commands: ReadonlyArray<{ name: string; description?: string }>
|
|
163
|
+
skills: ReadonlyArray<{ id: string; description?: string }>
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function readCatalog(bot: Pick<Bot, 'opencode'>, directory: string): Promise<Error | Catalog> {
|
|
167
|
+
// Waits for plugin activation, so a cold location returns its full catalog.
|
|
168
|
+
const ready = await catalogReady(bot, directory)
|
|
169
|
+
if (ready instanceof Error) return ready
|
|
170
|
+
const location = { directory }
|
|
171
|
+
const [agents, commands, skills] = await Promise.all([
|
|
172
|
+
oc(bot, 'agent.list', (client) => client.agent.list({ location })),
|
|
173
|
+
oc(bot, 'command.list', (client) => client.command.list({ location })),
|
|
174
|
+
oc(bot, 'skill.list', (client) => client.skill.list({ location })),
|
|
175
|
+
])
|
|
176
|
+
if (agents instanceof Error) return agents
|
|
177
|
+
if (commands instanceof Error) return commands
|
|
178
|
+
if (skills instanceof Error) return skills
|
|
179
|
+
return { agents: agents.data, commands: commands.data, skills: skills.data.filter((skill) => !isBuiltinSkill(skill.id)) }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Autocomplete keeps the whole project catalog reachable beyond Discord's shortcut limit.
|
|
183
|
+
function catalogRoutes(): InteractionRoutes {
|
|
184
|
+
const commands: Record<string, SlashCommand> = {}
|
|
185
|
+
for (const kind of ['command', 'skill'] as const) {
|
|
186
|
+
const entries = async (bot: Bot, directory: string) => {
|
|
187
|
+
const location = { directory }
|
|
188
|
+
if (kind === 'skill') {
|
|
189
|
+
const skills = await oc(bot, 'skill.list', (client) => client.skill.list({ location }))
|
|
190
|
+
if (skills instanceof Error) return skills
|
|
191
|
+
return skills.data.filter((skill) => !isBuiltinSkill(skill.id)).map((skill) => ({ name: skill.id, description: skill.description }))
|
|
192
|
+
}
|
|
193
|
+
const list = await oc(bot, 'command.list', (client) => client.command.list({ location }))
|
|
194
|
+
if (list instanceof Error) return list
|
|
195
|
+
return list.data.filter((command) => !SKIPPED_COMMANDS.has(command.name))
|
|
196
|
+
}
|
|
197
|
+
commands[kind] = {
|
|
198
|
+
definition: new SlashCommandBuilder()
|
|
199
|
+
.setName(kind)
|
|
200
|
+
.setDescription(`Run any OpenCode ${kind} in this project`)
|
|
201
|
+
.addStringOption((option) => option.setName('name').setDescription(`${kind} name`).setRequired(true).setAutocomplete(true))
|
|
202
|
+
.addStringOption((option) => option.setName('arguments').setDescription(`Arguments to pass to the ${kind}`)),
|
|
203
|
+
async autocomplete(bot, interaction) {
|
|
204
|
+
const where = await resolveTarget(bot, interaction.channelId)
|
|
205
|
+
if (where instanceof Error) return respondChoices(interaction, where)
|
|
206
|
+
const list = await entries(bot, where.directory)
|
|
207
|
+
if (list instanceof Error) return respondChoices(interaction, list)
|
|
208
|
+
const query = interaction.options.getFocused().toLowerCase()
|
|
209
|
+
return respondChoices(interaction, list.filter((entry) => entry.name.toLowerCase().includes(query)).map((entry) => ({
|
|
210
|
+
name: `/${entry.name}${entry.description ? ` - ${entry.description}` : ''}`,
|
|
211
|
+
value: entry.name,
|
|
212
|
+
})))
|
|
213
|
+
},
|
|
214
|
+
async run(bot, interaction) {
|
|
215
|
+
const where = await resolveTarget(bot, interaction.channelId)
|
|
216
|
+
if (where instanceof Error) return replyError(interaction, where)
|
|
217
|
+
const list = await entries(bot, where.directory)
|
|
218
|
+
if (list instanceof Error) return replyError(interaction, list)
|
|
219
|
+
const name = interaction.options.getString('name', true).trim().replace(/^\//, '')
|
|
220
|
+
if (!list.some((entry) => entry.name === name)) return replyError(interaction, new ConfigError({ reason: `Unknown ${kind} \`${name}\`. Use /${kind} autocomplete to select one.` }))
|
|
221
|
+
const args = (interaction.options.getString('arguments') ?? '').trim()
|
|
222
|
+
return sendInput(bot, {
|
|
223
|
+
interaction,
|
|
224
|
+
route: kind === 'skill' ? { kind, id: name, arguments: args } : { kind, name, arguments: args, queue: false },
|
|
225
|
+
echo: `/${name} ${args}`.trim(),
|
|
226
|
+
})
|
|
227
|
+
},
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return { commands }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Lowercase letters, digits and hyphens; the suffix always survives the 32-char limit.
|
|
234
|
+
export function discordCommandName(name: string, suffix: string): string | null {
|
|
235
|
+
const base = name
|
|
236
|
+
.toLowerCase()
|
|
237
|
+
.replace(/[^a-z0-9-]/g, '-')
|
|
238
|
+
.replace(/-+/g, '-')
|
|
239
|
+
.replace(/^-|-$/g, '')
|
|
240
|
+
if (!base) return null
|
|
241
|
+
return `${base.slice(0, NAME_LIMIT - suffix.length).replace(/-$/, '')}${suffix}`
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Pure: the full command list for a guild (the fixed commands first) plus the owner of each dynamic name.
|
|
245
|
+
export function buildCommands({ fixed, catalog }: { fixed: readonly RESTPostAPIChatInputApplicationCommandsJSONBody[]; catalog: Catalog }): {
|
|
246
|
+
commands: RESTPostAPIChatInputApplicationCommandsJSONBody[]
|
|
247
|
+
dynamic: Map<string, DynamicCommand>
|
|
248
|
+
// Commands past the Discord limit that were left out.
|
|
249
|
+
dropped: number
|
|
250
|
+
} {
|
|
251
|
+
const taken = new Set(fixed.map((command) => command.name))
|
|
252
|
+
const dynamic = new Map<string, DynamicCommand>()
|
|
253
|
+
const commands = [...fixed]
|
|
254
|
+
// Every dynamic command has one optional text option.
|
|
255
|
+
const add = ({ name, target, text }: { name: string | null; target: DynamicCommand; text: string }) => {
|
|
256
|
+
if (!name || taken.has(name)) return
|
|
257
|
+
taken.add(name)
|
|
258
|
+
dynamic.set(name, target)
|
|
259
|
+
const builder = new SlashCommandBuilder()
|
|
260
|
+
.setName(name)
|
|
261
|
+
.setDescription(text.replace(/\s+/g, ' ').trim().slice(0, 100) || '-')
|
|
262
|
+
.setDMPermission(false)
|
|
263
|
+
if (target.kind === 'agent') {
|
|
264
|
+
builder
|
|
265
|
+
.addStringOption((option) => option.setName('prompt').setDescription('Send a prompt with this agent'))
|
|
266
|
+
.addStringOption((option) =>
|
|
267
|
+
option.setName('variant').setDescription('Thinking level of the current model').setAutocomplete(true),
|
|
268
|
+
)
|
|
269
|
+
} else {
|
|
270
|
+
builder.addStringOption((option) => option.setName('arguments').setDescription('Arguments to pass to the command'))
|
|
271
|
+
}
|
|
272
|
+
commands.push(builder.toJSON())
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Sorted: the same catalog always keeps the same commands under the limit,
|
|
276
|
+
// whatever order OpenCode lists them in.
|
|
277
|
+
const sorted = <T>(items: readonly T[], key: (item: T) => string) =>
|
|
278
|
+
items.toSorted((a, b) => (key(a) < key(b) ? -1 : key(a) > key(b) ? 1 : 0))
|
|
279
|
+
for (const agent of sorted(catalog.agents, (agent) => agent.id)) {
|
|
280
|
+
if (agent.mode === 'subagent' || agent.hidden) continue
|
|
281
|
+
add({
|
|
282
|
+
name: discordCommandName(agent.id, '-agent'),
|
|
283
|
+
target: { kind: 'agent', name: agent.id },
|
|
284
|
+
text: agent.description || `Switch to the ${agent.name} agent`,
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
|
+
for (const command of sorted(catalog.commands, (command) => command.name)) {
|
|
288
|
+
if (SKIPPED_COMMANDS.has(command.name) || command.name.includes(':')) continue
|
|
289
|
+
add({
|
|
290
|
+
name: discordCommandName(command.name, '-cmd'),
|
|
291
|
+
target: { kind: 'command', name: command.name },
|
|
292
|
+
text: command.description || `Run /${command.name}`,
|
|
293
|
+
})
|
|
294
|
+
}
|
|
295
|
+
for (const skill of sorted(catalog.skills, (skill) => skill.id)) {
|
|
296
|
+
add({
|
|
297
|
+
name: discordCommandName(skill.id, '-skill'),
|
|
298
|
+
target: { kind: 'skill', id: skill.id },
|
|
299
|
+
text: skill.description || `Use the ${skill.id} skill`,
|
|
300
|
+
})
|
|
301
|
+
}
|
|
302
|
+
for (const dropped of commands.slice(MAX_COMMANDS)) dynamic.delete(dropped.name)
|
|
303
|
+
return { commands: commands.slice(0, MAX_COMMANDS), dynamic, dropped: Math.max(0, commands.length - MAX_COMMANDS) }
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// An input from a command: a prompt in the thread, or a new session in a channel.
|
|
307
|
+
async function sendInput(
|
|
308
|
+
bot: Bot,
|
|
309
|
+
{
|
|
310
|
+
interaction,
|
|
311
|
+
route,
|
|
312
|
+
echo,
|
|
313
|
+
model = null,
|
|
314
|
+
}: {
|
|
315
|
+
interaction: ChatInputCommandInteraction
|
|
316
|
+
route: Exclude<Route, { kind: 'btw' | 'new-session' | 'queue' }>
|
|
317
|
+
echo: string
|
|
318
|
+
// A model for this session only (`/<agent>-agent variant:`).
|
|
319
|
+
model?: ModelChoice | null
|
|
320
|
+
},
|
|
321
|
+
) {
|
|
322
|
+
const target = await resolveTarget(bot, interaction.channelId)
|
|
323
|
+
if (target instanceof Error) return replyError(interaction, target)
|
|
324
|
+
const author = authorOf(interaction)
|
|
325
|
+
if (target.thread && target.sessionId) {
|
|
326
|
+
const reply = await replyWithEcho(interaction, { author, text: echo })
|
|
327
|
+
if (reply instanceof Error) return replyError(interaction, reply)
|
|
328
|
+
if (model && !(route.kind === 'steer' && route.agent)) {
|
|
329
|
+
const switched = await switchModel(bot, { sessionId: target.sessionId, model })
|
|
330
|
+
if (switched instanceof Error) return replyError(interaction, switched)
|
|
331
|
+
}
|
|
332
|
+
const result = await dispatch(bot, { thread: target.thread, route, author, messageId: reply.id, model })
|
|
333
|
+
if (result instanceof Error) return replyError(interaction, result)
|
|
334
|
+
return
|
|
335
|
+
}
|
|
336
|
+
if (target.thread) {
|
|
337
|
+
await interaction.reply({ content: 'Use this command in a thread with a Kimaki session', flags: MessageFlags.Ephemeral })
|
|
338
|
+
return
|
|
339
|
+
}
|
|
340
|
+
await interaction.deferReply()
|
|
341
|
+
const started = await startSession(bot, {
|
|
342
|
+
channelId: target.channelId,
|
|
343
|
+
directory: target.directory,
|
|
344
|
+
route,
|
|
345
|
+
author,
|
|
346
|
+
messageId: interaction.id,
|
|
347
|
+
startMessageId: null,
|
|
348
|
+
...(model && { model }),
|
|
349
|
+
})
|
|
350
|
+
if (started instanceof Error) return replyError(interaction, started)
|
|
351
|
+
await interaction.editReply({ content: `Started a new session in <#${started.threadId}>` })
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async function handleDynamic(bot: Bot, { interaction, target }: { interaction: ChatInputCommandInteraction; target: DynamicCommand }) {
|
|
355
|
+
const text = (interaction.options.getString(target.kind === 'agent' ? 'prompt' : 'arguments') ?? '').trim()
|
|
356
|
+
if (target.kind === 'agent') {
|
|
357
|
+
const variant = interaction.options.getString('variant')?.trim()
|
|
358
|
+
const where = await resolveTarget(bot, interaction.channelId)
|
|
359
|
+
if (where instanceof Error) return replyError(interaction, where)
|
|
360
|
+
const model = variant ? await variantModel(bot, { target: where, variant, agent: target.name }) : null
|
|
361
|
+
if (model instanceof Error) return replyError(interaction, model)
|
|
362
|
+
if (!text) return applyAgent(bot, { interaction, target: where, agent: target.name, model })
|
|
363
|
+
const label = model ? `${target.name}, ${model.variant}` : target.name
|
|
364
|
+
return sendInput(bot, { interaction, route: { kind: 'steer', text, agent: target.name }, echo: `(${label}) ${text}`, model })
|
|
365
|
+
}
|
|
366
|
+
if (target.kind === 'skill') {
|
|
367
|
+
return sendInput(bot, { interaction, route: { kind: 'skill', id: target.id, arguments: text }, echo: `/${target.id} ${text}`.trim() })
|
|
368
|
+
}
|
|
369
|
+
return sendInput(bot, {
|
|
370
|
+
interaction,
|
|
371
|
+
route: { kind: 'command', name: target.name, arguments: text, queue: false },
|
|
372
|
+
echo: `/${target.name} ${text}`.trim(),
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// --- Listener and registration
|
|
377
|
+
|
|
378
|
+
// Registers the interaction listener and keeps every guild's commands in line
|
|
379
|
+
// with the OpenCode catalog. Returns registerAll and stop.
|
|
380
|
+
export function registerSlashCommands(
|
|
381
|
+
bot: Bot,
|
|
382
|
+
registry: InteractionRegistry,
|
|
383
|
+
{
|
|
384
|
+
globalDirectory,
|
|
385
|
+
}: {
|
|
386
|
+
// OpenCode's global config dir. As a location, OpenCode skips the project
|
|
387
|
+
// config walk for it (core/src/config/discovery.ts), so its catalog is the
|
|
388
|
+
// global one. Any other directory also loads the config of its ancestors.
|
|
389
|
+
globalDirectory: string
|
|
390
|
+
},
|
|
391
|
+
) {
|
|
392
|
+
const { discord } = bot
|
|
393
|
+
// Guild -> Discord name -> OpenCode agent, command or skill, from the last registration.
|
|
394
|
+
const dynamic = new Map<string, ReadonlyMap<string, DynamicCommand>>()
|
|
395
|
+
|
|
396
|
+
// Last commands set per guild: an unchanged list is not sent again (Discord
|
|
397
|
+
// limits command creates to 200 per day per guild).
|
|
398
|
+
const registered = new Map<string, string>()
|
|
399
|
+
|
|
400
|
+
async function registerGuild(guild: Guild, built: ReturnType<typeof buildCommands>): Promise<void> {
|
|
401
|
+
const signature = JSON.stringify(built.commands)
|
|
402
|
+
if (registered.get(guild.id) === signature) {
|
|
403
|
+
// Another Kimaki on the same app can overwrite the list, so compare with Discord.
|
|
404
|
+
const live = await discord.application?.commands.fetch({ guildId: guild.id }).catch(() => null)
|
|
405
|
+
const same = !live || (live.size === built.commands.length && built.commands.every((command) => live.some((entry) => entry.name === command.name)))
|
|
406
|
+
if (same) {
|
|
407
|
+
dynamic.set(guild.id, built.dynamic)
|
|
408
|
+
return
|
|
409
|
+
}
|
|
410
|
+
logger.warn(`commands in guild ${guild.id} changed outside this bot, registering again`)
|
|
411
|
+
}
|
|
412
|
+
const result = await discord.application?.commands
|
|
413
|
+
.set(built.commands, guild.id)
|
|
414
|
+
.catch((e) => new DiscordError({ operation: `register commands in ${guild.id}`, cause: e }))
|
|
415
|
+
if (result instanceof Error) {
|
|
416
|
+
logger.warn(result)
|
|
417
|
+
return
|
|
418
|
+
}
|
|
419
|
+
registered.set(guild.id, signature)
|
|
420
|
+
dynamic.set(guild.id, built.dynamic)
|
|
421
|
+
logger.info(`registered ${built.commands.length} commands in guild ${guild.id}`)
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function dynamicCommand(interaction: { guildId: string | null; commandName: string }) {
|
|
425
|
+
return interaction.guildId ? dynamic.get(interaction.guildId)?.get(interaction.commandName) : undefined
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
async function runCommand(interaction: ChatInputCommandInteraction) {
|
|
429
|
+
const command = registry.commands.get(interaction.commandName)
|
|
430
|
+
if (command) return command.run(bot, interaction)
|
|
431
|
+
const target = dynamicCommand(interaction)
|
|
432
|
+
if (target) return handleDynamic(bot, { interaction, target })
|
|
433
|
+
// A catalog command removed since the last registration: only told where commands work.
|
|
434
|
+
await sessionTarget(bot, interaction)
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
async function autocomplete(interaction: AutocompleteInteraction) {
|
|
438
|
+
const command = registry.commands.get(interaction.commandName)
|
|
439
|
+
if (command?.autocomplete) return command.autocomplete(bot, interaction)
|
|
440
|
+
const target = dynamicCommand(interaction)
|
|
441
|
+
if (target?.kind !== 'agent') return respondChoices(interaction, [])
|
|
442
|
+
const where = await resolveTarget(bot, interaction.channelId)
|
|
443
|
+
if (where instanceof Error) return respondChoices(interaction, where)
|
|
444
|
+
return respondChoices(interaction, await variantChoices(bot, { target: where, query: interaction.options.getFocused(), agent: target.name }))
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Provider logins and audio keys are secrets of the whole bot.
|
|
448
|
+
function adminOnly(interaction: Interaction): boolean {
|
|
449
|
+
if (interaction.isChatInputCommand() || interaction.isAutocomplete()) return registry.commands.get(interaction.commandName)?.admin === true
|
|
450
|
+
if (interaction.isButton()) return byPrefix(registry.buttons, interaction.customId)?.admin === true
|
|
451
|
+
if (interaction.isStringSelectMenu()) return byPrefix(registry.selects, interaction.customId)?.admin === true
|
|
452
|
+
if (interaction.isModalSubmit()) return byPrefix(registry.modals, interaction.customId)?.admin === true
|
|
453
|
+
return false
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
async function handle(interaction: Interaction) {
|
|
457
|
+
if (!interaction.guildId) return
|
|
458
|
+
const channel = interaction.channel ?? (interaction.channelId ? await discord.channels.fetch(interaction.channelId).catch(() => null) : null)
|
|
459
|
+
const projectId = channel?.isThread() ? channel.parentId : channel?.id
|
|
460
|
+
const project = projectId ? await projectOf(bot, projectId) : null
|
|
461
|
+
if (project instanceof Error) return logger.warn(project)
|
|
462
|
+
if (!project) return
|
|
463
|
+
const guild = interaction.guild ?? (await discord.guilds.fetch(interaction.guildId).catch(() => null))
|
|
464
|
+
if (!guild || !(await canUseKimaki({ guild, userId: interaction.user.id }))) {
|
|
465
|
+
if (interaction.isAutocomplete()) return respondChoices(interaction, [])
|
|
466
|
+
if (interaction.isRepliable()) {
|
|
467
|
+
await interaction.reply({ content: 'You do not have permission to use Kimaki', flags: MessageFlags.Ephemeral })
|
|
468
|
+
}
|
|
469
|
+
return
|
|
470
|
+
}
|
|
471
|
+
if (adminOnly(interaction) && guild.ownerId !== interaction.user.id) {
|
|
472
|
+
const member = await guild.members.fetch(interaction.user.id).catch(() => null)
|
|
473
|
+
if (!member?.permissions.has(PermissionFlagsBits.Administrator)) {
|
|
474
|
+
if (interaction.isRepliable()) await interaction.reply({ content: 'Provider login requires the server owner or an administrator', flags: MessageFlags.Ephemeral })
|
|
475
|
+
return
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (interaction.isChatInputCommand()) return runCommand(interaction)
|
|
479
|
+
if (interaction.isAutocomplete()) return autocomplete(interaction)
|
|
480
|
+
if (interaction.isButton()) return byPrefix(registry.buttons, interaction.customId)?.run(bot, interaction)
|
|
481
|
+
if (interaction.isStringSelectMenu()) return byPrefix(registry.selects, interaction.customId)?.run(bot, interaction)
|
|
482
|
+
if (interaction.isModalSubmit()) return byPrefix(registry.modals, interaction.customId)?.run(bot, interaction)
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
discord.on(Events.InteractionCreate, (interaction) => {
|
|
486
|
+
handle(interaction).catch((error: Error) => logger.error(`interaction failed`, error))
|
|
487
|
+
})
|
|
488
|
+
// One registration pass at a time; a request made during a pass runs one more
|
|
489
|
+
// pass, so an older catalog read never overwrites a newer one.
|
|
490
|
+
const passes: { active: Promise<void> | null; dirty: boolean; closed: boolean } = { active: null, dirty: false, closed: false }
|
|
491
|
+
|
|
492
|
+
// Brings every guild's commands in line with the current OpenCode catalog.
|
|
493
|
+
function registerAll(): Promise<void> {
|
|
494
|
+
passes.dirty = true
|
|
495
|
+
if (passes.active) return passes.active
|
|
496
|
+
const pass = (async () => {
|
|
497
|
+
try {
|
|
498
|
+
while (passes.dirty && !passes.closed) {
|
|
499
|
+
passes.dirty = false
|
|
500
|
+
const read = await readCatalog(bot, globalDirectory)
|
|
501
|
+
if (passes.closed) return
|
|
502
|
+
if (read instanceof Error) {
|
|
503
|
+
// An event that arrived during the read still gets its pass; else the next event or reconnect retries.
|
|
504
|
+
logger.warn('global catalog', read)
|
|
505
|
+
continue
|
|
506
|
+
}
|
|
507
|
+
const built = buildCommands({ fixed: registry.definitions, catalog: read })
|
|
508
|
+
if (built.dropped > 0) {
|
|
509
|
+
logger.log(`${built.dropped} catalog shortcuts do not fit in Discord's 100 commands; all entries remain available through /agent, /command and /skill`)
|
|
510
|
+
}
|
|
511
|
+
await Promise.all([...discord.guilds.cache.values()].map((guild) => registerGuild(guild, built)))
|
|
512
|
+
}
|
|
513
|
+
} finally {
|
|
514
|
+
passes.active = null
|
|
515
|
+
}
|
|
516
|
+
})()
|
|
517
|
+
passes.active = pass
|
|
518
|
+
return pass
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
discord.on(Events.GuildCreate, () => void registerAll())
|
|
522
|
+
// agent/command/skill.updated are ephemeral hints (no payload) sent on every
|
|
523
|
+
// catalog change of one location: plugin activation after a cold boot, edited
|
|
524
|
+
// skill or agent files. Events of any location count: OpenCode unloads idle
|
|
525
|
+
// locations, so a global change may only show up in a project location.
|
|
526
|
+
// server.connected follows each reconnect: hints sent while disconnected are lost.
|
|
527
|
+
const unsubscribe = bot.opencode.subscribe((event) => {
|
|
528
|
+
if (CATALOG_EVENTS.has(event.type)) void registerAll()
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
return {
|
|
532
|
+
registerAll,
|
|
533
|
+
// Waits for a running pass so nothing writes after Discord is destroyed.
|
|
534
|
+
async stop(): Promise<void> {
|
|
535
|
+
unsubscribe()
|
|
536
|
+
passes.closed = true
|
|
537
|
+
await passes.active
|
|
538
|
+
},
|
|
539
|
+
}
|
|
540
|
+
}
|