kimaki 0.4.82 ā 0.4.83
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/LICENSE +21 -0
- package/dist/anthropic-auth-plugin.js +7 -0
- package/dist/cli.js +42 -5
- package/dist/commands/abort.js +5 -16
- package/dist/commands/action-buttons.js +3 -3
- package/dist/commands/add-project.js +1 -1
- package/dist/commands/ask-question.js +3 -3
- package/dist/commands/context-usage.js +1 -1
- package/dist/commands/create-new-project.js +1 -1
- package/dist/commands/fork.js +11 -8
- package/dist/commands/merge-worktree.js +1 -1
- package/dist/commands/new-worktree.js +63 -44
- package/dist/commands/remove-project.js +1 -1
- package/dist/commands/resume.js +11 -8
- package/dist/commands/session.js +1 -1
- package/dist/commands/undo-redo.js +91 -7
- package/dist/commands/user-command.js +1 -1
- package/dist/database.js +53 -2
- package/dist/db.js +6 -0
- package/dist/discord-bot.js +104 -90
- package/dist/external-opencode-sync.js +538 -0
- package/dist/external-opencode-sync.test.js +151 -0
- package/dist/gateway-proxy.e2e.test.js +51 -0
- package/dist/genai.js +1 -1
- package/dist/generated/enums.js +4 -0
- package/dist/generated/internal/class.js +4 -4
- package/dist/generated/internal/prismaNamespace.js +1 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js +1 -0
- package/dist/generated/models/external_session_pending_prompts.js +1 -0
- package/dist/hrana-server.js +14 -285
- package/dist/hrana-server.test.js +4 -2
- package/dist/kimaki-opencode-plugin-loading.e2e.test.js +7 -0
- package/dist/kimaki-opencode-plugin.js +2 -0
- package/dist/kitty-graphics-parser.js +3 -0
- package/dist/kitty-graphics-parser.test.js +276 -0
- package/dist/kitty-graphics-plugin.js +3 -0
- package/dist/markdown.js +4 -4
- package/dist/markdown.test.js +1 -1
- package/dist/message-formatting.js +54 -15
- package/dist/openai-realtime.js +9 -13
- package/dist/opencode.js +28 -5
- package/dist/queue-advanced-e2e-setup.js +53 -0
- package/dist/queue-advanced-permissions-typing.e2e.test.js +5 -5
- package/dist/queue-advanced-typing.e2e.test.js +9 -22
- package/dist/session-handler/event-stream-state.js +101 -7
- package/dist/session-handler/event-stream-state.test.js +7 -3
- package/dist/session-handler/thread-session-runtime.js +77 -9
- package/dist/system-message.js +6 -0
- package/dist/system-message.test.js +19 -0
- package/dist/task-runner.js +1 -1
- package/dist/thread-message-queue.e2e.test.js +8 -14
- package/dist/tools.js +1 -1
- package/dist/undo-redo.e2e.test.js +20 -25
- package/package.json +9 -6
- package/schema.prisma +6 -0
- package/skills/npm-package/SKILL.md +1 -0
- package/skills/proxyman/SKILL.md +215 -0
- package/skills/usecomputer/SKILL.md +339 -0
- package/src/ai-tool-to-genai.ts +1 -0
- package/src/anthropic-auth-plugin.ts +7 -0
- package/src/cli.ts +44 -5
- package/src/commands/abort.ts +6 -16
- package/src/commands/action-buttons.ts +5 -1
- package/src/commands/add-project.ts +1 -1
- package/src/commands/ask-question.ts +5 -2
- package/src/commands/context-usage.ts +1 -1
- package/src/commands/create-new-project.ts +1 -1
- package/src/commands/fork.ts +12 -11
- package/src/commands/merge-worktree.ts +1 -1
- package/src/commands/new-worktree.ts +74 -55
- package/src/commands/remove-project.ts +1 -1
- package/src/commands/resume.ts +12 -10
- package/src/commands/session.ts +1 -1
- package/src/commands/undo-redo.ts +108 -10
- package/src/commands/user-command.ts +1 -1
- package/src/database.ts +72 -3
- package/src/db.ts +8 -0
- package/src/discord-bot.ts +125 -97
- package/src/external-opencode-sync.ts +760 -0
- package/src/gateway-proxy.e2e.test.ts +63 -0
- package/src/genai.ts +1 -1
- package/src/generated/commonInputTypes.ts +34 -0
- package/src/generated/enums.ts +8 -0
- package/src/generated/internal/class.ts +4 -4
- package/src/generated/internal/prismaNamespace.ts +8 -0
- package/src/generated/internal/prismaNamespaceBrowser.ts +1 -0
- package/src/generated/models/thread_sessions.ts +53 -1
- package/src/hrana-server.test.ts +8 -2
- package/src/hrana-server.ts +18 -390
- package/src/kimaki-opencode-plugin-loading.e2e.test.ts +7 -0
- package/src/kimaki-opencode-plugin.ts +2 -0
- package/src/markdown.test.ts +1 -1
- package/src/markdown.ts +4 -4
- package/src/message-formatting.ts +66 -17
- package/src/openai-realtime.ts +6 -10
- package/src/opencode.ts +31 -7
- package/src/queue-advanced-e2e-setup.ts +55 -0
- package/src/queue-advanced-permissions-typing.e2e.test.ts +5 -5
- package/src/queue-advanced-typing.e2e.test.ts +9 -22
- package/src/schema.sql +1 -0
- package/src/session-handler/event-stream-state.test.ts +7 -2
- package/src/session-handler/event-stream-state.ts +128 -7
- package/src/session-handler/thread-runtime-state.ts +5 -0
- package/src/session-handler/thread-session-runtime.ts +93 -11
- package/src/system-message.ts +11 -0
- package/src/task-runner.ts +1 -1
- package/src/thread-message-queue.e2e.test.ts +8 -14
- package/src/tools.ts +1 -1
- package/src/undo-redo.e2e.test.ts +28 -26
- package/skills/jitter/node_modules/.bin/esbuild +0 -21
- package/skills/jitter/node_modules/.bin/tsc +0 -21
- package/skills/jitter/node_modules/.bin/tsserver +0 -21
- package/skills/jitter/node_modules/typescript/LICENSE.txt +0 -55
- package/skills/jitter/node_modules/typescript/README.md +0 -50
- package/skills/jitter/node_modules/typescript/SECURITY.md +0 -41
- package/skills/jitter/node_modules/typescript/ThirdPartyNoticeText.txt +0 -193
- package/skills/jitter/node_modules/typescript/bin/tsc +0 -2
- package/skills/jitter/node_modules/typescript/bin/tsserver +0 -2
- package/skills/jitter/node_modules/typescript/lib/_tsc.js +0 -133792
- package/skills/jitter/node_modules/typescript/lib/_tsserver.js +0 -659
- package/skills/jitter/node_modules/typescript/lib/_typingsInstaller.js +0 -222
- package/skills/jitter/node_modules/typescript/lib/cs/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/lib/de/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/lib/es/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/lib/fr/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/lib/it/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/lib/ja/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/lib/ko/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/lib/lib.d.ts +0 -22
- package/skills/jitter/node_modules/typescript/lib/lib.decorators.d.ts +0 -384
- package/skills/jitter/node_modules/typescript/lib/lib.decorators.legacy.d.ts +0 -22
- package/skills/jitter/node_modules/typescript/lib/lib.dom.asynciterable.d.ts +0 -41
- package/skills/jitter/node_modules/typescript/lib/lib.dom.d.ts +0 -39429
- package/skills/jitter/node_modules/typescript/lib/lib.dom.iterable.d.ts +0 -571
- package/skills/jitter/node_modules/typescript/lib/lib.es2015.collection.d.ts +0 -147
- package/skills/jitter/node_modules/typescript/lib/lib.es2015.core.d.ts +0 -597
- package/skills/jitter/node_modules/typescript/lib/lib.es2015.d.ts +0 -28
- package/skills/jitter/node_modules/typescript/lib/lib.es2015.generator.d.ts +0 -77
- package/skills/jitter/node_modules/typescript/lib/lib.es2015.iterable.d.ts +0 -605
- package/skills/jitter/node_modules/typescript/lib/lib.es2015.promise.d.ts +0 -81
- package/skills/jitter/node_modules/typescript/lib/lib.es2015.proxy.d.ts +0 -128
- package/skills/jitter/node_modules/typescript/lib/lib.es2015.reflect.d.ts +0 -144
- package/skills/jitter/node_modules/typescript/lib/lib.es2015.symbol.d.ts +0 -46
- package/skills/jitter/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts +0 -326
- package/skills/jitter/node_modules/typescript/lib/lib.es2016.array.include.d.ts +0 -116
- package/skills/jitter/node_modules/typescript/lib/lib.es2016.d.ts +0 -21
- package/skills/jitter/node_modules/typescript/lib/lib.es2016.full.d.ts +0 -23
- package/skills/jitter/node_modules/typescript/lib/lib.es2016.intl.d.ts +0 -31
- package/skills/jitter/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts +0 -21
- package/skills/jitter/node_modules/typescript/lib/lib.es2017.d.ts +0 -26
- package/skills/jitter/node_modules/typescript/lib/lib.es2017.date.d.ts +0 -31
- package/skills/jitter/node_modules/typescript/lib/lib.es2017.full.d.ts +0 -23
- package/skills/jitter/node_modules/typescript/lib/lib.es2017.intl.d.ts +0 -44
- package/skills/jitter/node_modules/typescript/lib/lib.es2017.object.d.ts +0 -49
- package/skills/jitter/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts +0 -135
- package/skills/jitter/node_modules/typescript/lib/lib.es2017.string.d.ts +0 -45
- package/skills/jitter/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts +0 -53
- package/skills/jitter/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts +0 -77
- package/skills/jitter/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts +0 -53
- package/skills/jitter/node_modules/typescript/lib/lib.es2018.d.ts +0 -24
- package/skills/jitter/node_modules/typescript/lib/lib.es2018.full.d.ts +0 -24
- package/skills/jitter/node_modules/typescript/lib/lib.es2018.intl.d.ts +0 -83
- package/skills/jitter/node_modules/typescript/lib/lib.es2018.promise.d.ts +0 -30
- package/skills/jitter/node_modules/typescript/lib/lib.es2018.regexp.d.ts +0 -37
- package/skills/jitter/node_modules/typescript/lib/lib.es2019.array.d.ts +0 -79
- package/skills/jitter/node_modules/typescript/lib/lib.es2019.d.ts +0 -24
- package/skills/jitter/node_modules/typescript/lib/lib.es2019.full.d.ts +0 -24
- package/skills/jitter/node_modules/typescript/lib/lib.es2019.intl.d.ts +0 -23
- package/skills/jitter/node_modules/typescript/lib/lib.es2019.object.d.ts +0 -33
- package/skills/jitter/node_modules/typescript/lib/lib.es2019.string.d.ts +0 -37
- package/skills/jitter/node_modules/typescript/lib/lib.es2019.symbol.d.ts +0 -24
- package/skills/jitter/node_modules/typescript/lib/lib.es2020.bigint.d.ts +0 -765
- package/skills/jitter/node_modules/typescript/lib/lib.es2020.d.ts +0 -27
- package/skills/jitter/node_modules/typescript/lib/lib.es2020.date.d.ts +0 -42
- package/skills/jitter/node_modules/typescript/lib/lib.es2020.full.d.ts +0 -24
- package/skills/jitter/node_modules/typescript/lib/lib.es2020.intl.d.ts +0 -474
- package/skills/jitter/node_modules/typescript/lib/lib.es2020.number.d.ts +0 -28
- package/skills/jitter/node_modules/typescript/lib/lib.es2020.promise.d.ts +0 -47
- package/skills/jitter/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts +0 -99
- package/skills/jitter/node_modules/typescript/lib/lib.es2020.string.d.ts +0 -44
- package/skills/jitter/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts +0 -41
- package/skills/jitter/node_modules/typescript/lib/lib.es2021.d.ts +0 -23
- package/skills/jitter/node_modules/typescript/lib/lib.es2021.full.d.ts +0 -24
- package/skills/jitter/node_modules/typescript/lib/lib.es2021.intl.d.ts +0 -166
- package/skills/jitter/node_modules/typescript/lib/lib.es2021.promise.d.ts +0 -48
- package/skills/jitter/node_modules/typescript/lib/lib.es2021.string.d.ts +0 -33
- package/skills/jitter/node_modules/typescript/lib/lib.es2021.weakref.d.ts +0 -78
- package/skills/jitter/node_modules/typescript/lib/lib.es2022.array.d.ts +0 -121
- package/skills/jitter/node_modules/typescript/lib/lib.es2022.d.ts +0 -25
- package/skills/jitter/node_modules/typescript/lib/lib.es2022.error.d.ts +0 -75
- package/skills/jitter/node_modules/typescript/lib/lib.es2022.full.d.ts +0 -24
- package/skills/jitter/node_modules/typescript/lib/lib.es2022.intl.d.ts +0 -145
- package/skills/jitter/node_modules/typescript/lib/lib.es2022.object.d.ts +0 -26
- package/skills/jitter/node_modules/typescript/lib/lib.es2022.regexp.d.ts +0 -39
- package/skills/jitter/node_modules/typescript/lib/lib.es2022.string.d.ts +0 -25
- package/skills/jitter/node_modules/typescript/lib/lib.es2023.array.d.ts +0 -924
- package/skills/jitter/node_modules/typescript/lib/lib.es2023.collection.d.ts +0 -21
- package/skills/jitter/node_modules/typescript/lib/lib.es2023.d.ts +0 -22
- package/skills/jitter/node_modules/typescript/lib/lib.es2023.full.d.ts +0 -24
- package/skills/jitter/node_modules/typescript/lib/lib.es2023.intl.d.ts +0 -56
- package/skills/jitter/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts +0 -65
- package/skills/jitter/node_modules/typescript/lib/lib.es2024.collection.d.ts +0 -29
- package/skills/jitter/node_modules/typescript/lib/lib.es2024.d.ts +0 -26
- package/skills/jitter/node_modules/typescript/lib/lib.es2024.full.d.ts +0 -24
- package/skills/jitter/node_modules/typescript/lib/lib.es2024.object.d.ts +0 -29
- package/skills/jitter/node_modules/typescript/lib/lib.es2024.promise.d.ts +0 -35
- package/skills/jitter/node_modules/typescript/lib/lib.es2024.regexp.d.ts +0 -25
- package/skills/jitter/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts +0 -68
- package/skills/jitter/node_modules/typescript/lib/lib.es2024.string.d.ts +0 -29
- package/skills/jitter/node_modules/typescript/lib/lib.es5.d.ts +0 -4601
- package/skills/jitter/node_modules/typescript/lib/lib.es6.d.ts +0 -23
- package/skills/jitter/node_modules/typescript/lib/lib.esnext.array.d.ts +0 -35
- package/skills/jitter/node_modules/typescript/lib/lib.esnext.collection.d.ts +0 -96
- package/skills/jitter/node_modules/typescript/lib/lib.esnext.d.ts +0 -29
- package/skills/jitter/node_modules/typescript/lib/lib.esnext.decorators.d.ts +0 -28
- package/skills/jitter/node_modules/typescript/lib/lib.esnext.disposable.d.ts +0 -193
- package/skills/jitter/node_modules/typescript/lib/lib.esnext.error.d.ts +0 -24
- package/skills/jitter/node_modules/typescript/lib/lib.esnext.float16.d.ts +0 -443
- package/skills/jitter/node_modules/typescript/lib/lib.esnext.full.d.ts +0 -24
- package/skills/jitter/node_modules/typescript/lib/lib.esnext.intl.d.ts +0 -21
- package/skills/jitter/node_modules/typescript/lib/lib.esnext.iterator.d.ts +0 -148
- package/skills/jitter/node_modules/typescript/lib/lib.esnext.promise.d.ts +0 -34
- package/skills/jitter/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts +0 -25
- package/skills/jitter/node_modules/typescript/lib/lib.scripthost.d.ts +0 -322
- package/skills/jitter/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts +0 -41
- package/skills/jitter/node_modules/typescript/lib/lib.webworker.d.ts +0 -13150
- package/skills/jitter/node_modules/typescript/lib/lib.webworker.importscripts.d.ts +0 -23
- package/skills/jitter/node_modules/typescript/lib/lib.webworker.iterable.d.ts +0 -340
- package/skills/jitter/node_modules/typescript/lib/pl/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/lib/pt-br/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/lib/ru/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/lib/tr/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/lib/tsc.js +0 -8
- package/skills/jitter/node_modules/typescript/lib/tsserver.js +0 -8
- package/skills/jitter/node_modules/typescript/lib/tsserverlibrary.d.ts +0 -17
- package/skills/jitter/node_modules/typescript/lib/tsserverlibrary.js +0 -21
- package/skills/jitter/node_modules/typescript/lib/typesMap.json +0 -497
- package/skills/jitter/node_modules/typescript/lib/typescript.d.ts +0 -11438
- package/skills/jitter/node_modules/typescript/lib/typescript.js +0 -200253
- package/skills/jitter/node_modules/typescript/lib/typingsInstaller.js +0 -8
- package/skills/jitter/node_modules/typescript/lib/watchGuard.js +0 -53
- package/skills/jitter/node_modules/typescript/lib/zh-cn/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/lib/zh-tw/diagnosticMessages.generated.json +0 -2122
- package/skills/jitter/node_modules/typescript/node_modules/.bin/tsc +0 -21
- package/skills/jitter/node_modules/typescript/node_modules/.bin/tsserver +0 -21
- package/skills/jitter/node_modules/typescript/package.json +0 -120
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Kimaki
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Anthropic OAuth authentication plugin for OpenCode.
|
|
3
3
|
*
|
|
4
|
+
* If you're copy-pasting this plugin into your OpenCode config folder,
|
|
5
|
+
* you need to install the runtime dependencies first:
|
|
6
|
+
*
|
|
7
|
+
* cd ~/.config/opencode
|
|
8
|
+
* bun init -y
|
|
9
|
+
* bun add @openauthjs/openauth proper-lockfile
|
|
10
|
+
*
|
|
4
11
|
* Handles two concerns:
|
|
5
12
|
* 1. OAuth login + token refresh (PKCE flow against claude.ai)
|
|
6
13
|
* 2. Request/response rewriting (tool names, system prompt, beta headers)
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { z } from 'zod';
|
|
|
7
7
|
import { intro, outro, text, password, note, cancel, isCancel, confirm, log, multiselect, select, spinner, } from '@clack/prompts';
|
|
8
8
|
import { deduplicateByKey, generateBotInstallUrl, generateDiscordInstallUrlForBot, KIMAKI_GATEWAY_APP_ID, KIMAKI_WEBSITE_URL, abbreviatePath, } from './utils.js';
|
|
9
9
|
import { getChannelsWithDescriptions, createDiscordClient, initDatabase, getChannelDirectory, startDiscordBot, initializeOpencodeForDirectory, ensureKimakiCategory, createProjectChannels, createDefaultKimakiChannel, } from './discord-bot.js';
|
|
10
|
-
import { getBotTokenWithMode, ensureServiceAuthToken, setBotToken, setBotMode, setChannelDirectory, findChannelsByDirectory, getThreadSession, getThreadIdBySessionId, getSessionEventSnapshot, getPrisma, createScheduledTask, listScheduledTasks, cancelScheduledTask, getScheduledTask, updateScheduledTask, getSessionStartSourcesBySessionIds, } from './database.js';
|
|
10
|
+
import { getBotTokenWithMode, ensureServiceAuthToken, setBotToken, setBotMode, setChannelDirectory, findChannelsByDirectory, getThreadSession, getThreadIdBySessionId, getSessionEventSnapshot, getPrisma, createScheduledTask, listScheduledTasks, cancelScheduledTask, getScheduledTask, updateScheduledTask, getSessionStartSourcesBySessionIds, deleteChannelDirectoryById, } from './database.js';
|
|
11
11
|
import { ShareMarkdown } from './markdown.js';
|
|
12
12
|
import { parseSessionSearchPattern, findFirstSessionSearchHit, buildSessionSearchSnippet, getPartSearchTexts, } from './session-search.js';
|
|
13
13
|
import { formatWorktreeName } from './commands/new-worktree.js';
|
|
@@ -2353,6 +2353,7 @@ cli
|
|
|
2353
2353
|
cli
|
|
2354
2354
|
.command('project list', 'List all registered projects with their Discord channels')
|
|
2355
2355
|
.option('--json', 'Output as JSON')
|
|
2356
|
+
.option('--prune', 'Remove stale entries whose Discord channel no longer exists')
|
|
2356
2357
|
.action(async (options) => {
|
|
2357
2358
|
await initDatabase();
|
|
2358
2359
|
const prisma = await getPrisma();
|
|
@@ -2369,31 +2370,67 @@ cli
|
|
|
2369
2370
|
const rest = botRow ? createDiscordRest(botRow.token) : null;
|
|
2370
2371
|
const enriched = await Promise.all(channels.map(async (ch) => {
|
|
2371
2372
|
let channelName = '';
|
|
2373
|
+
let deleted = false;
|
|
2372
2374
|
if (rest) {
|
|
2373
2375
|
try {
|
|
2374
2376
|
const data = (await rest.get(Routes.channel(ch.channel_id)));
|
|
2375
2377
|
channelName = data.name || '';
|
|
2376
2378
|
}
|
|
2377
|
-
catch {
|
|
2378
|
-
//
|
|
2379
|
+
catch (error) {
|
|
2380
|
+
// Only mark as deleted for Unknown Channel (10003) or 404,
|
|
2381
|
+
// not transient errors like rate limits or 5xx
|
|
2382
|
+
const isUnknownChannel = error instanceof Error &&
|
|
2383
|
+
'code' in error &&
|
|
2384
|
+
'status' in error &&
|
|
2385
|
+
(error.code === 10003 ||
|
|
2386
|
+
error.status === 404);
|
|
2387
|
+
deleted = isUnknownChannel;
|
|
2379
2388
|
}
|
|
2380
2389
|
}
|
|
2381
|
-
return { ...ch, channelName };
|
|
2390
|
+
return { ...ch, channelName, deleted };
|
|
2382
2391
|
}));
|
|
2392
|
+
// Prune stale entries if requested
|
|
2393
|
+
if (options.prune) {
|
|
2394
|
+
const stale = enriched.filter((ch) => {
|
|
2395
|
+
return ch.deleted;
|
|
2396
|
+
});
|
|
2397
|
+
if (stale.length === 0) {
|
|
2398
|
+
cliLogger.log('No stale channels to prune');
|
|
2399
|
+
}
|
|
2400
|
+
else {
|
|
2401
|
+
for (const ch of stale) {
|
|
2402
|
+
await deleteChannelDirectoryById(ch.channel_id);
|
|
2403
|
+
cliLogger.log(`Pruned stale channel ${ch.channel_id} (${path.basename(ch.directory)})`);
|
|
2404
|
+
}
|
|
2405
|
+
cliLogger.log(`Pruned ${stale.length} stale channel(s)`);
|
|
2406
|
+
}
|
|
2407
|
+
// Re-filter to only show live entries after pruning
|
|
2408
|
+
const live = enriched.filter((ch) => {
|
|
2409
|
+
return !ch.deleted;
|
|
2410
|
+
});
|
|
2411
|
+
if (live.length === 0) {
|
|
2412
|
+
cliLogger.log('No projects registered');
|
|
2413
|
+
process.exit(0);
|
|
2414
|
+
}
|
|
2415
|
+
enriched.length = 0;
|
|
2416
|
+
enriched.push(...live);
|
|
2417
|
+
}
|
|
2383
2418
|
if (options.json) {
|
|
2384
2419
|
const output = enriched.map((ch) => ({
|
|
2385
2420
|
channel_id: ch.channel_id,
|
|
2386
2421
|
channel_name: ch.channelName,
|
|
2387
2422
|
directory: ch.directory,
|
|
2388
2423
|
folder_name: path.basename(ch.directory),
|
|
2424
|
+
deleted: ch.deleted,
|
|
2389
2425
|
}));
|
|
2390
2426
|
console.log(JSON.stringify(output, null, 2));
|
|
2391
2427
|
process.exit(0);
|
|
2392
2428
|
}
|
|
2393
2429
|
for (const ch of enriched) {
|
|
2394
2430
|
const folderName = path.basename(ch.directory);
|
|
2431
|
+
const deletedTag = ch.deleted ? ' (deleted from Discord)' : '';
|
|
2395
2432
|
const channelLabel = ch.channelName ? `#${ch.channelName}` : ch.channel_id;
|
|
2396
|
-
console.log(`\n${channelLabel}`);
|
|
2433
|
+
console.log(`\n${channelLabel}${deletedTag}`);
|
|
2397
2434
|
console.log(` Folder: ${folderName}`);
|
|
2398
2435
|
console.log(` Directory: ${ch.directory}`);
|
|
2399
2436
|
console.log(` Channel ID: ${ch.channel_id}`);
|
package/dist/commands/abort.js
CHANGED
|
@@ -27,23 +27,18 @@ export async function handleAbortCommand({ command, }) {
|
|
|
27
27
|
});
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
|
+
await command.deferReply({ flags: SILENT_MESSAGE_FLAGS });
|
|
30
31
|
const resolved = await resolveWorkingDirectory({
|
|
31
32
|
channel: channel,
|
|
32
33
|
});
|
|
33
34
|
if (!resolved) {
|
|
34
|
-
await command.
|
|
35
|
-
content: 'Could not determine project directory for this channel',
|
|
36
|
-
flags: MessageFlags.Ephemeral | SILENT_MESSAGE_FLAGS,
|
|
37
|
-
});
|
|
35
|
+
await command.editReply('Could not determine project directory for this channel');
|
|
38
36
|
return;
|
|
39
37
|
}
|
|
40
38
|
const { projectDirectory } = resolved;
|
|
41
39
|
const sessionId = await getThreadSession(channel.id);
|
|
42
40
|
if (!sessionId) {
|
|
43
|
-
await command.
|
|
44
|
-
content: 'No active session in this thread',
|
|
45
|
-
flags: MessageFlags.Ephemeral | SILENT_MESSAGE_FLAGS,
|
|
46
|
-
});
|
|
41
|
+
await command.editReply('No active session in this thread');
|
|
47
42
|
return;
|
|
48
43
|
}
|
|
49
44
|
// abortActiveRun delegates to session.abort(), run settlement stays event-driven.
|
|
@@ -55,10 +50,7 @@ export async function handleAbortCommand({ command, }) {
|
|
|
55
50
|
// No runtime but session exists ā fall back to direct API abort
|
|
56
51
|
const getClient = await initializeOpencodeForDirectory(projectDirectory);
|
|
57
52
|
if (getClient instanceof Error) {
|
|
58
|
-
await command.
|
|
59
|
-
content: `Failed to abort: ${getClient.message}`,
|
|
60
|
-
flags: MessageFlags.Ephemeral | SILENT_MESSAGE_FLAGS,
|
|
61
|
-
});
|
|
53
|
+
await command.editReply(`Failed to abort: ${getClient.message}`);
|
|
62
54
|
return;
|
|
63
55
|
}
|
|
64
56
|
try {
|
|
@@ -68,9 +60,6 @@ export async function handleAbortCommand({ command, }) {
|
|
|
68
60
|
logger.error('[ABORT] API abort failed:', error);
|
|
69
61
|
}
|
|
70
62
|
}
|
|
71
|
-
await command.
|
|
72
|
-
content: `Request **aborted**`,
|
|
73
|
-
flags: SILENT_MESSAGE_FLAGS,
|
|
74
|
-
});
|
|
63
|
+
await command.editReply('Request **aborted**');
|
|
75
64
|
logger.log(`Session ${sessionId} aborted by user`);
|
|
76
65
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, MessageFlags, } from 'discord.js';
|
|
5
5
|
import crypto from 'node:crypto';
|
|
6
6
|
import { getThreadSession } from '../database.js';
|
|
7
|
-
import { NOTIFY_MESSAGE_FLAGS, resolveWorkingDirectory, sendThreadMessage, } from '../discord-utils.js';
|
|
7
|
+
import { NOTIFY_MESSAGE_FLAGS, SILENT_MESSAGE_FLAGS, resolveWorkingDirectory, sendThreadMessage, } from '../discord-utils.js';
|
|
8
8
|
import { createLogger } from '../logger.js';
|
|
9
9
|
import { notifyError } from '../sentry.js';
|
|
10
10
|
import { getOrCreateRuntime, } from '../session-handler/thread-session-runtime.js';
|
|
@@ -101,7 +101,7 @@ async function sendClickedActionToModel({ interaction, thread, prompt, }) {
|
|
|
101
101
|
mode: 'opencode',
|
|
102
102
|
});
|
|
103
103
|
}
|
|
104
|
-
export async function showActionButtons({ thread, sessionId, directory, buttons, }) {
|
|
104
|
+
export async function showActionButtons({ thread, sessionId, directory, buttons, silent, }) {
|
|
105
105
|
const safeButtons = buttons
|
|
106
106
|
.slice(0, 3)
|
|
107
107
|
.map((button) => {
|
|
@@ -145,7 +145,7 @@ export async function showActionButtons({ thread, sessionId, directory, buttons,
|
|
|
145
145
|
const message = await thread.send({
|
|
146
146
|
content: '**Action Required**',
|
|
147
147
|
components: [row],
|
|
148
|
-
flags: NOTIFY_MESSAGE_FLAGS,
|
|
148
|
+
flags: silent ? SILENT_MESSAGE_FLAGS : NOTIFY_MESSAGE_FLAGS,
|
|
149
149
|
});
|
|
150
150
|
context.messageId = message.id;
|
|
151
151
|
logger.log(`Showed ${safeButtons.length} action button(s) for session ${sessionId}`);
|
|
@@ -9,7 +9,7 @@ import { abbreviatePath } from '../utils.js';
|
|
|
9
9
|
import * as errore from 'errore';
|
|
10
10
|
const logger = createLogger(LogPrefix.ADD_PROJECT);
|
|
11
11
|
export async function handleAddProjectCommand({ command, }) {
|
|
12
|
-
await command.deferReply(
|
|
12
|
+
await command.deferReply();
|
|
13
13
|
const projectId = command.options.getString('project', true);
|
|
14
14
|
const guild = command.guild;
|
|
15
15
|
if (!guild) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// for each question and collects user responses.
|
|
4
4
|
import { StringSelectMenuBuilder, StringSelectMenuInteraction, ActionRowBuilder, MessageFlags, } from 'discord.js';
|
|
5
5
|
import crypto from 'node:crypto';
|
|
6
|
-
import { sendThreadMessage, NOTIFY_MESSAGE_FLAGS } from '../discord-utils.js';
|
|
6
|
+
import { sendThreadMessage, NOTIFY_MESSAGE_FLAGS, SILENT_MESSAGE_FLAGS } from '../discord-utils.js';
|
|
7
7
|
import { getOpencodeClient } from '../opencode.js';
|
|
8
8
|
import { createLogger, LogPrefix } from '../logger.js';
|
|
9
9
|
const logger = createLogger(LogPrefix.ASK_QUESTION);
|
|
@@ -15,7 +15,7 @@ export const pendingQuestionContexts = new Map();
|
|
|
15
15
|
* Show dropdown menus for question tool input.
|
|
16
16
|
* Sends one message per question with the dropdown directly under the question text.
|
|
17
17
|
*/
|
|
18
|
-
export async function showAskUserQuestionDropdowns({ thread, sessionId, directory, requestId, input, }) {
|
|
18
|
+
export async function showAskUserQuestionDropdowns({ thread, sessionId, directory, requestId, input, silent, }) {
|
|
19
19
|
const contextHash = crypto.randomBytes(8).toString('hex');
|
|
20
20
|
const context = {
|
|
21
21
|
sessionId,
|
|
@@ -83,7 +83,7 @@ export async function showAskUserQuestionDropdowns({ thread, sessionId, director
|
|
|
83
83
|
await thread.send({
|
|
84
84
|
content: `**${(q.header || '').slice(0, 200)}**\n${q.question.slice(0, 1700)}`,
|
|
85
85
|
components: [actionRow],
|
|
86
|
-
flags: NOTIFY_MESSAGE_FLAGS,
|
|
86
|
+
flags: silent ? SILENT_MESSAGE_FLAGS : NOTIFY_MESSAGE_FLAGS,
|
|
87
87
|
});
|
|
88
88
|
}
|
|
89
89
|
logger.log(`Showed ${input.questions.length} question dropdown(s) for session ${sessionId}`);
|
|
@@ -75,7 +75,7 @@ export async function handleContextUsageCommand({ command, }) {
|
|
|
75
75
|
if (m.info.role !== 'assistant') {
|
|
76
76
|
return false;
|
|
77
77
|
}
|
|
78
|
-
if (!
|
|
78
|
+
if (!m.info.tokens) {
|
|
79
79
|
return false;
|
|
80
80
|
}
|
|
81
81
|
return getTokenTotal(m.info.tokens) > 0;
|
|
@@ -58,7 +58,7 @@ export async function createNewProject({ guild, projectName, botName, }) {
|
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
export async function handleCreateNewProjectCommand({ command, appId, }) {
|
|
61
|
-
await command.deferReply(
|
|
61
|
+
await command.deferReply();
|
|
62
62
|
const projectName = command.options.getString('name', true);
|
|
63
63
|
const guild = command.guild;
|
|
64
64
|
const channel = command.channel;
|
package/dist/commands/fork.js
CHANGED
|
@@ -3,7 +3,7 @@ import { ChatInputCommandInteraction, StringSelectMenuInteraction, StringSelectM
|
|
|
3
3
|
import { getThreadSession, setThreadSession, setPartMessagesBatch, } from '../database.js';
|
|
4
4
|
import { initializeOpencodeForDirectory } from '../opencode.js';
|
|
5
5
|
import { resolveWorkingDirectory, resolveTextChannel, sendThreadMessage, } from '../discord-utils.js';
|
|
6
|
-
import {
|
|
6
|
+
import { collectSessionChunks, batchChunksForDiscord } from '../message-formatting.js';
|
|
7
7
|
import { createLogger, LogPrefix } from '../logger.js';
|
|
8
8
|
import * as errore from 'errore';
|
|
9
9
|
const sessionLogger = createLogger(LogPrefix.SESSION);
|
|
@@ -135,7 +135,7 @@ export async function handleForkSelectMenu(interaction) {
|
|
|
135
135
|
});
|
|
136
136
|
return;
|
|
137
137
|
}
|
|
138
|
-
await interaction.deferReply(
|
|
138
|
+
await interaction.deferReply();
|
|
139
139
|
const threadChannel = interaction.channel;
|
|
140
140
|
if (!threadChannel) {
|
|
141
141
|
await interaction.editReply('Could not access thread channel');
|
|
@@ -184,9 +184,11 @@ export async function handleForkSelectMenu(interaction) {
|
|
|
184
184
|
autoArchiveDuration: ThreadAutoArchiveDuration.OneDay,
|
|
185
185
|
reason: `Forked from session ${sessionId}`,
|
|
186
186
|
});
|
|
187
|
+
// Claim the forked session immediately so external polling does not race
|
|
188
|
+
// and create a duplicate Sync thread before the rest of this setup runs.
|
|
189
|
+
await setThreadSession(thread.id, forkedSession.id);
|
|
187
190
|
// Add user to thread so it appears in their sidebar
|
|
188
191
|
await thread.members.add(interaction.user.id);
|
|
189
|
-
await setThreadSession(thread.id, forkedSession.id);
|
|
190
192
|
sessionLogger.log(`Created forked session ${forkedSession.id} in thread ${thread.id}`);
|
|
191
193
|
await sendThreadMessage(thread, `**Forked session created!**\nFrom: \`${sessionId}\`\nNew session: \`${forkedSession.id}\``);
|
|
192
194
|
// Fetch and display the last assistant messages from the forked session
|
|
@@ -194,13 +196,14 @@ export async function handleForkSelectMenu(interaction) {
|
|
|
194
196
|
sessionID: forkedSession.id,
|
|
195
197
|
});
|
|
196
198
|
if (messagesResponse.data) {
|
|
197
|
-
const {
|
|
199
|
+
const { chunks } = collectSessionChunks({
|
|
198
200
|
messages: messagesResponse.data,
|
|
201
|
+
limit: 30,
|
|
199
202
|
});
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
await setPartMessagesBatch(partIds.map((partId) => ({
|
|
203
|
+
const batched = batchChunksForDiscord(chunks);
|
|
204
|
+
for (const batch of batched) {
|
|
205
|
+
const discordMessage = await sendThreadMessage(thread, batch.content);
|
|
206
|
+
await setPartMessagesBatch(batch.partIds.map((partId) => ({
|
|
204
207
|
partId,
|
|
205
208
|
messageId: discordMessage.id,
|
|
206
209
|
threadId: thread.id,
|
|
@@ -55,7 +55,7 @@ async function sendPromptToModel({ prompt, thread, projectDirectory, command, ap
|
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
export async function handleMergeWorktreeCommand({ command, appId, }) {
|
|
58
|
-
await command.deferReply(
|
|
58
|
+
await command.deferReply();
|
|
59
59
|
const channel = command.channel;
|
|
60
60
|
if (!channel || !channel.isThread()) {
|
|
61
61
|
await command.editReply('This command can only be used in a thread');
|
|
@@ -11,6 +11,10 @@ import { createWorktreeWithSubmodules, execAsync, listBranchesByLastCommit, vali
|
|
|
11
11
|
import { WORKTREE_PREFIX } from './merge-worktree.js';
|
|
12
12
|
import * as errore from 'errore';
|
|
13
13
|
const logger = createLogger(LogPrefix.WORKTREE);
|
|
14
|
+
/** Status message shown while a worktree is being created. */
|
|
15
|
+
export function worktreeCreatingMessage(worktreeName) {
|
|
16
|
+
return `š³ **Creating worktree: ${worktreeName}**\nā³ Setting up...`;
|
|
17
|
+
}
|
|
14
18
|
class WorktreeError extends Error {
|
|
15
19
|
constructor(message, options) {
|
|
16
20
|
super(message, options);
|
|
@@ -65,37 +69,64 @@ async function getProjectDirectoryFromChannel(channel) {
|
|
|
65
69
|
return channelConfig.directory;
|
|
66
70
|
}
|
|
67
71
|
/**
|
|
68
|
-
* Create worktree
|
|
72
|
+
* Create worktree and update the status message when done.
|
|
73
|
+
* Handles the full lifecycle: pending DB entry, git creation, DB ready/error,
|
|
74
|
+
* tree emoji reaction, and editing the status message.
|
|
75
|
+
*
|
|
76
|
+
* starterMessage is optional ā if omitted, status edits are skipped (creation
|
|
77
|
+
* still proceeds). This keeps worktree creation independent of Discord message
|
|
78
|
+
* delivery, so a transient send failure never silently skips the worktree.
|
|
79
|
+
*
|
|
80
|
+
* Returns the worktree directory on success, or an Error on failure.
|
|
81
|
+
* Never throws ā all internal errors are caught and returned as Error values.
|
|
69
82
|
*/
|
|
70
|
-
async function createWorktreeInBackground({ thread, starterMessage, worktreeName, projectDirectory, baseBranch, rest, }) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
83
|
+
export async function createWorktreeInBackground({ thread, starterMessage, worktreeName, projectDirectory, baseBranch, rest, }) {
|
|
84
|
+
return errore.tryAsync({
|
|
85
|
+
try: async () => {
|
|
86
|
+
logger.log(`Creating worktree "${worktreeName}" for project ${projectDirectory}${baseBranch ? ` from ${baseBranch}` : ''}`);
|
|
87
|
+
await createPendingWorktree({
|
|
88
|
+
threadId: thread.id,
|
|
89
|
+
worktreeName,
|
|
90
|
+
projectDirectory,
|
|
91
|
+
});
|
|
92
|
+
const worktreeResult = await createWorktreeWithSubmodules({
|
|
93
|
+
directory: projectDirectory,
|
|
94
|
+
name: worktreeName,
|
|
95
|
+
baseBranch,
|
|
96
|
+
});
|
|
97
|
+
if (worktreeResult instanceof Error) {
|
|
98
|
+
const errorMsg = worktreeResult.message;
|
|
99
|
+
logger.error('[WORKTREE] Creation failed:', worktreeResult);
|
|
100
|
+
await setWorktreeError({ threadId: thread.id, errorMessage: errorMsg });
|
|
101
|
+
await starterMessage
|
|
102
|
+
?.edit(`š³ **Worktree: ${worktreeName}**\nā ${errorMsg}`)
|
|
103
|
+
.catch(() => { });
|
|
104
|
+
return worktreeResult;
|
|
105
|
+
}
|
|
106
|
+
// Success - update database and edit starter message
|
|
107
|
+
await setWorktreeReady({
|
|
108
|
+
threadId: thread.id,
|
|
109
|
+
worktreeDirectory: worktreeResult.directory,
|
|
110
|
+
});
|
|
111
|
+
// React with tree emoji to mark as worktree thread
|
|
112
|
+
await reactToThread({
|
|
113
|
+
rest,
|
|
114
|
+
threadId: thread.id,
|
|
115
|
+
channelId: thread.parentId || undefined,
|
|
116
|
+
emoji: 'š³',
|
|
117
|
+
});
|
|
118
|
+
await starterMessage
|
|
119
|
+
?.edit(`š³ **Worktree: ${worktreeName}**\n` +
|
|
120
|
+
`š \`${worktreeResult.directory}\`\n` +
|
|
121
|
+
`šæ Branch: \`${worktreeResult.branch}\``)
|
|
122
|
+
.catch(() => { });
|
|
123
|
+
return worktreeResult.directory;
|
|
124
|
+
},
|
|
125
|
+
catch: (e) => {
|
|
126
|
+
logger.error('[WORKTREE] Unexpected error in createWorktreeInBackground:', e);
|
|
127
|
+
return new Error(`Worktree creation failed: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
|
|
128
|
+
},
|
|
95
129
|
});
|
|
96
|
-
await starterMessage.edit(`š³ **Worktree: ${worktreeName}**\n` +
|
|
97
|
-
`š \`${worktreeResult.directory}\`\n` +
|
|
98
|
-
`šæ Branch: \`${worktreeResult.branch}\``);
|
|
99
130
|
}
|
|
100
131
|
async function findExistingWorktreePath({ projectDirectory, worktreeName, }) {
|
|
101
132
|
const listResult = await errore.tryAsync({
|
|
@@ -121,7 +152,7 @@ async function findExistingWorktreePath({ projectDirectory, worktreeName, }) {
|
|
|
121
152
|
return undefined;
|
|
122
153
|
}
|
|
123
154
|
export async function handleNewWorktreeCommand({ command, }) {
|
|
124
|
-
await command.deferReply(
|
|
155
|
+
await command.deferReply();
|
|
125
156
|
const channel = command.channel;
|
|
126
157
|
if (!channel) {
|
|
127
158
|
await command.editReply('Cannot determine channel');
|
|
@@ -187,7 +218,7 @@ export async function handleNewWorktreeCommand({ command, }) {
|
|
|
187
218
|
const result = await errore.tryAsync({
|
|
188
219
|
try: async () => {
|
|
189
220
|
const starterMessage = await textChannel.send({
|
|
190
|
-
content:
|
|
221
|
+
content: worktreeCreatingMessage(worktreeName),
|
|
191
222
|
flags: SILENT_MESSAGE_FLAGS,
|
|
192
223
|
});
|
|
193
224
|
const thread = await starterMessage.startThread({
|
|
@@ -207,12 +238,6 @@ export async function handleNewWorktreeCommand({ command, }) {
|
|
|
207
238
|
return;
|
|
208
239
|
}
|
|
209
240
|
const { thread, starterMessage } = result;
|
|
210
|
-
// Store pending worktree in database
|
|
211
|
-
await createPendingWorktree({
|
|
212
|
-
threadId: thread.id,
|
|
213
|
-
worktreeName,
|
|
214
|
-
projectDirectory,
|
|
215
|
-
});
|
|
216
241
|
await command.editReply(`Creating worktree in ${thread.toString()}`);
|
|
217
242
|
// Create worktree in background (don't await)
|
|
218
243
|
createWorktreeInBackground({
|
|
@@ -282,15 +307,9 @@ async function handleWorktreeInThread({ command, thread, }) {
|
|
|
282
307
|
await command.editReply(`Worktree \`${worktreeName}\` already exists at \`${existingWorktreePath}\``);
|
|
283
308
|
return;
|
|
284
309
|
}
|
|
285
|
-
// Store pending worktree in database for this existing thread
|
|
286
|
-
await createPendingWorktree({
|
|
287
|
-
threadId: thread.id,
|
|
288
|
-
worktreeName,
|
|
289
|
-
projectDirectory,
|
|
290
|
-
});
|
|
291
310
|
// Send status message in thread
|
|
292
311
|
const statusMessage = await thread.send({
|
|
293
|
-
content:
|
|
312
|
+
content: worktreeCreatingMessage(worktreeName),
|
|
294
313
|
flags: SILENT_MESSAGE_FLAGS,
|
|
295
314
|
});
|
|
296
315
|
await command.editReply(`Creating worktree \`${worktreeName}\` for this thread...`);
|
|
@@ -6,7 +6,7 @@ import { createLogger, LogPrefix } from '../logger.js';
|
|
|
6
6
|
import { abbreviatePath } from '../utils.js';
|
|
7
7
|
const logger = createLogger(LogPrefix.REMOVE_PROJECT);
|
|
8
8
|
export async function handleRemoveProjectCommand({ command, appId, }) {
|
|
9
|
-
await command.deferReply(
|
|
9
|
+
await command.deferReply();
|
|
10
10
|
const directory = command.options.getString('project', true);
|
|
11
11
|
const guild = command.guild;
|
|
12
12
|
if (!guild) {
|
package/dist/commands/resume.js
CHANGED
|
@@ -4,12 +4,12 @@ import fs from 'node:fs';
|
|
|
4
4
|
import { getChannelDirectory, setThreadSession, setPartMessagesBatch, getAllThreadSessionIds, } from '../database.js';
|
|
5
5
|
import { initializeOpencodeForDirectory } from '../opencode.js';
|
|
6
6
|
import { sendThreadMessage, resolveProjectDirectoryFromAutocomplete, NOTIFY_MESSAGE_FLAGS, } from '../discord-utils.js';
|
|
7
|
-
import {
|
|
7
|
+
import { collectSessionChunks, batchChunksForDiscord } from '../message-formatting.js';
|
|
8
8
|
import { createLogger, LogPrefix } from '../logger.js';
|
|
9
9
|
import * as errore from 'errore';
|
|
10
10
|
const logger = createLogger(LogPrefix.RESUME);
|
|
11
11
|
export async function handleResumeCommand({ command, }) {
|
|
12
|
-
await command.deferReply(
|
|
12
|
+
await command.deferReply();
|
|
13
13
|
const sessionId = command.options.getString('session', true);
|
|
14
14
|
const channel = command.channel;
|
|
15
15
|
const isThread = channel &&
|
|
@@ -56,9 +56,11 @@ export async function handleResumeCommand({ command, }) {
|
|
|
56
56
|
autoArchiveDuration: ThreadAutoArchiveDuration.OneDay,
|
|
57
57
|
reason: `Resuming session ${sessionId}`,
|
|
58
58
|
});
|
|
59
|
+
// Claim the resumed session immediately so external polling does not race
|
|
60
|
+
// and create a duplicate Sync thread before the rest of this setup runs.
|
|
61
|
+
await setThreadSession(thread.id, sessionId);
|
|
59
62
|
// Add user to thread so it appears in their sidebar
|
|
60
63
|
await thread.members.add(command.user.id);
|
|
61
|
-
await setThreadSession(thread.id, sessionId);
|
|
62
64
|
logger.log(`[RESUME] Created thread ${thread.id} for session ${sessionId}`);
|
|
63
65
|
const messagesResponse = await getClient().session.messages({
|
|
64
66
|
sessionID: sessionId,
|
|
@@ -70,16 +72,17 @@ export async function handleResumeCommand({ command, }) {
|
|
|
70
72
|
await command.editReply(`Resumed session "${sessionTitle}" in ${thread.toString()}`);
|
|
71
73
|
await sendThreadMessage(thread, `**Resumed session:** ${sessionTitle}\n**Created:** ${new Date(sessionResponse.data.time.created).toLocaleString()}\n\n*Loading ${messages.length} messages...*`);
|
|
72
74
|
try {
|
|
73
|
-
const {
|
|
75
|
+
const { chunks, skippedCount } = collectSessionChunks({
|
|
74
76
|
messages,
|
|
77
|
+
limit: 30,
|
|
75
78
|
});
|
|
76
79
|
if (skippedCount > 0) {
|
|
77
80
|
await sendThreadMessage(thread, `*Skipped ${skippedCount} older assistant parts...*`);
|
|
78
81
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
await setPartMessagesBatch(partIds.map((partId) => ({
|
|
82
|
+
const batched = batchChunksForDiscord(chunks);
|
|
83
|
+
for (const batch of batched) {
|
|
84
|
+
const discordMessage = await sendThreadMessage(thread, batch.content);
|
|
85
|
+
await setPartMessagesBatch(batch.partIds.map((partId) => ({
|
|
83
86
|
partId,
|
|
84
87
|
messageId: discordMessage.id,
|
|
85
88
|
threadId: thread.id,
|
package/dist/commands/session.js
CHANGED
|
@@ -10,7 +10,7 @@ import { createLogger, LogPrefix } from '../logger.js';
|
|
|
10
10
|
import * as errore from 'errore';
|
|
11
11
|
const logger = createLogger(LogPrefix.SESSION);
|
|
12
12
|
export async function handleSessionCommand({ command, appId, }) {
|
|
13
|
-
await command.deferReply(
|
|
13
|
+
await command.deferReply();
|
|
14
14
|
const prompt = command.options.getString('prompt', true);
|
|
15
15
|
const filesString = command.options.getString('files') || '';
|
|
16
16
|
const agent = command.options.getString('agent') || undefined;
|