kimaki 0.4.65 → 0.4.67

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.
Files changed (232) hide show
  1. package/dist/bin.js +16 -1
  2. package/dist/cli-parsing.test.js +16 -0
  3. package/dist/cli.js +187 -9
  4. package/dist/commands/abort.js +1 -1
  5. package/dist/commands/agent.js +1 -1
  6. package/dist/commands/ask-question.js +10 -8
  7. package/dist/commands/compact.js +5 -5
  8. package/dist/commands/context-usage.js +4 -4
  9. package/dist/commands/file-upload.js +3 -3
  10. package/dist/commands/fork.js +4 -4
  11. package/dist/commands/login.js +14 -15
  12. package/dist/commands/merge-worktree.js +1 -1
  13. package/dist/commands/model.js +6 -3
  14. package/dist/commands/permissions.js +9 -8
  15. package/dist/commands/restart-opencode-server.js +1 -1
  16. package/dist/commands/resume.js +2 -2
  17. package/dist/commands/session-id.js +78 -0
  18. package/dist/commands/session.js +2 -4
  19. package/dist/commands/share.js +1 -1
  20. package/dist/commands/undo-redo.js +5 -5
  21. package/dist/commands/upgrade.js +4 -0
  22. package/dist/config.js +9 -0
  23. package/dist/discord-bot.js +17 -11
  24. package/dist/discord-utils.js +6 -13
  25. package/dist/heap-monitor.js +3 -0
  26. package/dist/interaction-handler.js +4 -0
  27. package/dist/markdown.js +3 -3
  28. package/dist/markdown.test.js +2 -2
  29. package/dist/message-formatting.js +2 -1
  30. package/dist/opencode-plugin.js +225 -34
  31. package/dist/opencode.js +48 -13
  32. package/dist/session-handler.js +121 -102
  33. package/dist/session-search.js +100 -0
  34. package/dist/session-search.test.js +40 -0
  35. package/dist/system-message.js +25 -5
  36. package/dist/tools.js +18 -26
  37. package/dist/voice-handler.js +1 -1
  38. package/dist/wait-session.js +1 -1
  39. package/package.json +6 -4
  40. package/skills/errore/SKILL.md +1159 -0
  41. package/skills/jitter/EDITOR.md +210 -0
  42. package/skills/jitter/SKILL.md +158 -0
  43. package/skills/jitter/dist/jitter-utils.js +620 -0
  44. package/skills/jitter/jitter-clipboard.json +1042 -0
  45. package/skills/jitter/node_modules/.bin/esbuild +21 -0
  46. package/skills/jitter/node_modules/.bin/tsc +21 -0
  47. package/skills/jitter/node_modules/.bin/tsserver +21 -0
  48. package/skills/jitter/node_modules/typescript/LICENSE.txt +55 -0
  49. package/skills/jitter/node_modules/typescript/README.md +50 -0
  50. package/skills/jitter/node_modules/typescript/SECURITY.md +41 -0
  51. package/skills/jitter/node_modules/typescript/ThirdPartyNoticeText.txt +193 -0
  52. package/skills/jitter/node_modules/typescript/bin/tsc +2 -0
  53. package/skills/jitter/node_modules/typescript/bin/tsserver +2 -0
  54. package/skills/jitter/node_modules/typescript/lib/_tsc.js +133792 -0
  55. package/skills/jitter/node_modules/typescript/lib/_tsserver.js +659 -0
  56. package/skills/jitter/node_modules/typescript/lib/_typingsInstaller.js +222 -0
  57. package/skills/jitter/node_modules/typescript/lib/cs/diagnosticMessages.generated.json +2122 -0
  58. package/skills/jitter/node_modules/typescript/lib/de/diagnosticMessages.generated.json +2122 -0
  59. package/skills/jitter/node_modules/typescript/lib/es/diagnosticMessages.generated.json +2122 -0
  60. package/skills/jitter/node_modules/typescript/lib/fr/diagnosticMessages.generated.json +2122 -0
  61. package/skills/jitter/node_modules/typescript/lib/it/diagnosticMessages.generated.json +2122 -0
  62. package/skills/jitter/node_modules/typescript/lib/ja/diagnosticMessages.generated.json +2122 -0
  63. package/skills/jitter/node_modules/typescript/lib/ko/diagnosticMessages.generated.json +2122 -0
  64. package/skills/jitter/node_modules/typescript/lib/lib.d.ts +22 -0
  65. package/skills/jitter/node_modules/typescript/lib/lib.decorators.d.ts +384 -0
  66. package/skills/jitter/node_modules/typescript/lib/lib.decorators.legacy.d.ts +22 -0
  67. package/skills/jitter/node_modules/typescript/lib/lib.dom.asynciterable.d.ts +41 -0
  68. package/skills/jitter/node_modules/typescript/lib/lib.dom.d.ts +39429 -0
  69. package/skills/jitter/node_modules/typescript/lib/lib.dom.iterable.d.ts +571 -0
  70. package/skills/jitter/node_modules/typescript/lib/lib.es2015.collection.d.ts +147 -0
  71. package/skills/jitter/node_modules/typescript/lib/lib.es2015.core.d.ts +597 -0
  72. package/skills/jitter/node_modules/typescript/lib/lib.es2015.d.ts +28 -0
  73. package/skills/jitter/node_modules/typescript/lib/lib.es2015.generator.d.ts +77 -0
  74. package/skills/jitter/node_modules/typescript/lib/lib.es2015.iterable.d.ts +605 -0
  75. package/skills/jitter/node_modules/typescript/lib/lib.es2015.promise.d.ts +81 -0
  76. package/skills/jitter/node_modules/typescript/lib/lib.es2015.proxy.d.ts +128 -0
  77. package/skills/jitter/node_modules/typescript/lib/lib.es2015.reflect.d.ts +144 -0
  78. package/skills/jitter/node_modules/typescript/lib/lib.es2015.symbol.d.ts +46 -0
  79. package/skills/jitter/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts +326 -0
  80. package/skills/jitter/node_modules/typescript/lib/lib.es2016.array.include.d.ts +116 -0
  81. package/skills/jitter/node_modules/typescript/lib/lib.es2016.d.ts +21 -0
  82. package/skills/jitter/node_modules/typescript/lib/lib.es2016.full.d.ts +23 -0
  83. package/skills/jitter/node_modules/typescript/lib/lib.es2016.intl.d.ts +31 -0
  84. package/skills/jitter/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts +21 -0
  85. package/skills/jitter/node_modules/typescript/lib/lib.es2017.d.ts +26 -0
  86. package/skills/jitter/node_modules/typescript/lib/lib.es2017.date.d.ts +31 -0
  87. package/skills/jitter/node_modules/typescript/lib/lib.es2017.full.d.ts +23 -0
  88. package/skills/jitter/node_modules/typescript/lib/lib.es2017.intl.d.ts +44 -0
  89. package/skills/jitter/node_modules/typescript/lib/lib.es2017.object.d.ts +49 -0
  90. package/skills/jitter/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts +135 -0
  91. package/skills/jitter/node_modules/typescript/lib/lib.es2017.string.d.ts +45 -0
  92. package/skills/jitter/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts +53 -0
  93. package/skills/jitter/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts +77 -0
  94. package/skills/jitter/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts +53 -0
  95. package/skills/jitter/node_modules/typescript/lib/lib.es2018.d.ts +24 -0
  96. package/skills/jitter/node_modules/typescript/lib/lib.es2018.full.d.ts +24 -0
  97. package/skills/jitter/node_modules/typescript/lib/lib.es2018.intl.d.ts +83 -0
  98. package/skills/jitter/node_modules/typescript/lib/lib.es2018.promise.d.ts +30 -0
  99. package/skills/jitter/node_modules/typescript/lib/lib.es2018.regexp.d.ts +37 -0
  100. package/skills/jitter/node_modules/typescript/lib/lib.es2019.array.d.ts +79 -0
  101. package/skills/jitter/node_modules/typescript/lib/lib.es2019.d.ts +24 -0
  102. package/skills/jitter/node_modules/typescript/lib/lib.es2019.full.d.ts +24 -0
  103. package/skills/jitter/node_modules/typescript/lib/lib.es2019.intl.d.ts +23 -0
  104. package/skills/jitter/node_modules/typescript/lib/lib.es2019.object.d.ts +33 -0
  105. package/skills/jitter/node_modules/typescript/lib/lib.es2019.string.d.ts +37 -0
  106. package/skills/jitter/node_modules/typescript/lib/lib.es2019.symbol.d.ts +24 -0
  107. package/skills/jitter/node_modules/typescript/lib/lib.es2020.bigint.d.ts +765 -0
  108. package/skills/jitter/node_modules/typescript/lib/lib.es2020.d.ts +27 -0
  109. package/skills/jitter/node_modules/typescript/lib/lib.es2020.date.d.ts +42 -0
  110. package/skills/jitter/node_modules/typescript/lib/lib.es2020.full.d.ts +24 -0
  111. package/skills/jitter/node_modules/typescript/lib/lib.es2020.intl.d.ts +474 -0
  112. package/skills/jitter/node_modules/typescript/lib/lib.es2020.number.d.ts +28 -0
  113. package/skills/jitter/node_modules/typescript/lib/lib.es2020.promise.d.ts +47 -0
  114. package/skills/jitter/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts +99 -0
  115. package/skills/jitter/node_modules/typescript/lib/lib.es2020.string.d.ts +44 -0
  116. package/skills/jitter/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts +41 -0
  117. package/skills/jitter/node_modules/typescript/lib/lib.es2021.d.ts +23 -0
  118. package/skills/jitter/node_modules/typescript/lib/lib.es2021.full.d.ts +24 -0
  119. package/skills/jitter/node_modules/typescript/lib/lib.es2021.intl.d.ts +166 -0
  120. package/skills/jitter/node_modules/typescript/lib/lib.es2021.promise.d.ts +48 -0
  121. package/skills/jitter/node_modules/typescript/lib/lib.es2021.string.d.ts +33 -0
  122. package/skills/jitter/node_modules/typescript/lib/lib.es2021.weakref.d.ts +78 -0
  123. package/skills/jitter/node_modules/typescript/lib/lib.es2022.array.d.ts +121 -0
  124. package/skills/jitter/node_modules/typescript/lib/lib.es2022.d.ts +25 -0
  125. package/skills/jitter/node_modules/typescript/lib/lib.es2022.error.d.ts +75 -0
  126. package/skills/jitter/node_modules/typescript/lib/lib.es2022.full.d.ts +24 -0
  127. package/skills/jitter/node_modules/typescript/lib/lib.es2022.intl.d.ts +145 -0
  128. package/skills/jitter/node_modules/typescript/lib/lib.es2022.object.d.ts +26 -0
  129. package/skills/jitter/node_modules/typescript/lib/lib.es2022.regexp.d.ts +39 -0
  130. package/skills/jitter/node_modules/typescript/lib/lib.es2022.string.d.ts +25 -0
  131. package/skills/jitter/node_modules/typescript/lib/lib.es2023.array.d.ts +924 -0
  132. package/skills/jitter/node_modules/typescript/lib/lib.es2023.collection.d.ts +21 -0
  133. package/skills/jitter/node_modules/typescript/lib/lib.es2023.d.ts +22 -0
  134. package/skills/jitter/node_modules/typescript/lib/lib.es2023.full.d.ts +24 -0
  135. package/skills/jitter/node_modules/typescript/lib/lib.es2023.intl.d.ts +56 -0
  136. package/skills/jitter/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts +65 -0
  137. package/skills/jitter/node_modules/typescript/lib/lib.es2024.collection.d.ts +29 -0
  138. package/skills/jitter/node_modules/typescript/lib/lib.es2024.d.ts +26 -0
  139. package/skills/jitter/node_modules/typescript/lib/lib.es2024.full.d.ts +24 -0
  140. package/skills/jitter/node_modules/typescript/lib/lib.es2024.object.d.ts +29 -0
  141. package/skills/jitter/node_modules/typescript/lib/lib.es2024.promise.d.ts +35 -0
  142. package/skills/jitter/node_modules/typescript/lib/lib.es2024.regexp.d.ts +25 -0
  143. package/skills/jitter/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts +68 -0
  144. package/skills/jitter/node_modules/typescript/lib/lib.es2024.string.d.ts +29 -0
  145. package/skills/jitter/node_modules/typescript/lib/lib.es5.d.ts +4601 -0
  146. package/skills/jitter/node_modules/typescript/lib/lib.es6.d.ts +23 -0
  147. package/skills/jitter/node_modules/typescript/lib/lib.esnext.array.d.ts +35 -0
  148. package/skills/jitter/node_modules/typescript/lib/lib.esnext.collection.d.ts +96 -0
  149. package/skills/jitter/node_modules/typescript/lib/lib.esnext.d.ts +29 -0
  150. package/skills/jitter/node_modules/typescript/lib/lib.esnext.decorators.d.ts +28 -0
  151. package/skills/jitter/node_modules/typescript/lib/lib.esnext.disposable.d.ts +193 -0
  152. package/skills/jitter/node_modules/typescript/lib/lib.esnext.error.d.ts +24 -0
  153. package/skills/jitter/node_modules/typescript/lib/lib.esnext.float16.d.ts +443 -0
  154. package/skills/jitter/node_modules/typescript/lib/lib.esnext.full.d.ts +24 -0
  155. package/skills/jitter/node_modules/typescript/lib/lib.esnext.intl.d.ts +21 -0
  156. package/skills/jitter/node_modules/typescript/lib/lib.esnext.iterator.d.ts +148 -0
  157. package/skills/jitter/node_modules/typescript/lib/lib.esnext.promise.d.ts +34 -0
  158. package/skills/jitter/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts +25 -0
  159. package/skills/jitter/node_modules/typescript/lib/lib.scripthost.d.ts +322 -0
  160. package/skills/jitter/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts +41 -0
  161. package/skills/jitter/node_modules/typescript/lib/lib.webworker.d.ts +13150 -0
  162. package/skills/jitter/node_modules/typescript/lib/lib.webworker.importscripts.d.ts +23 -0
  163. package/skills/jitter/node_modules/typescript/lib/lib.webworker.iterable.d.ts +340 -0
  164. package/skills/jitter/node_modules/typescript/lib/pl/diagnosticMessages.generated.json +2122 -0
  165. package/skills/jitter/node_modules/typescript/lib/pt-br/diagnosticMessages.generated.json +2122 -0
  166. package/skills/jitter/node_modules/typescript/lib/ru/diagnosticMessages.generated.json +2122 -0
  167. package/skills/jitter/node_modules/typescript/lib/tr/diagnosticMessages.generated.json +2122 -0
  168. package/skills/jitter/node_modules/typescript/lib/tsc.js +8 -0
  169. package/skills/jitter/node_modules/typescript/lib/tsserver.js +8 -0
  170. package/skills/jitter/node_modules/typescript/lib/tsserverlibrary.d.ts +17 -0
  171. package/skills/jitter/node_modules/typescript/lib/tsserverlibrary.js +21 -0
  172. package/skills/jitter/node_modules/typescript/lib/typesMap.json +497 -0
  173. package/skills/jitter/node_modules/typescript/lib/typescript.d.ts +11438 -0
  174. package/skills/jitter/node_modules/typescript/lib/typescript.js +200253 -0
  175. package/skills/jitter/node_modules/typescript/lib/typingsInstaller.js +8 -0
  176. package/skills/jitter/node_modules/typescript/lib/watchGuard.js +53 -0
  177. package/skills/jitter/node_modules/typescript/lib/zh-cn/diagnosticMessages.generated.json +2122 -0
  178. package/skills/jitter/node_modules/typescript/lib/zh-tw/diagnosticMessages.generated.json +2122 -0
  179. package/skills/jitter/node_modules/typescript/node_modules/.bin/tsc +21 -0
  180. package/skills/jitter/node_modules/typescript/node_modules/.bin/tsserver +21 -0
  181. package/skills/jitter/node_modules/typescript/package.json +120 -0
  182. package/skills/jitter/package.json +14 -0
  183. package/skills/jitter/tsconfig.json +15 -0
  184. package/skills/jitter/utils/actions.ts +208 -0
  185. package/skills/jitter/utils/export.ts +109 -0
  186. package/skills/jitter/utils/index.ts +140 -0
  187. package/skills/jitter/utils/snapshot.ts +140 -0
  188. package/skills/jitter/utils/traverse.ts +228 -0
  189. package/skills/jitter/utils/types.ts +279 -0
  190. package/skills/jitter/utils/wait.ts +131 -0
  191. package/skills/playwriter/SKILL.md +30 -0
  192. package/skills/tuistory/SKILL.md +250 -0
  193. package/src/bin.ts +26 -4
  194. package/src/cli-parsing.test.ts +22 -0
  195. package/src/cli.ts +264 -23
  196. package/src/commands/abort.ts +1 -1
  197. package/src/commands/agent.ts +1 -1
  198. package/src/commands/ask-question.ts +10 -8
  199. package/src/commands/compact.ts +5 -5
  200. package/src/commands/context-usage.ts +4 -4
  201. package/src/commands/file-upload.ts +3 -3
  202. package/src/commands/fork.ts +4 -4
  203. package/src/commands/login.ts +14 -15
  204. package/src/commands/merge-worktree.ts +1 -1
  205. package/src/commands/model.ts +6 -3
  206. package/src/commands/permissions.ts +10 -9
  207. package/src/commands/restart-opencode-server.ts +1 -1
  208. package/src/commands/resume.ts +2 -2
  209. package/src/commands/session-id.ts +95 -0
  210. package/src/commands/session.ts +2 -4
  211. package/src/commands/share.ts +1 -1
  212. package/src/commands/undo-redo.ts +5 -5
  213. package/src/commands/upgrade.ts +4 -0
  214. package/src/config.ts +12 -0
  215. package/src/discord-bot.ts +17 -11
  216. package/src/discord-utils.ts +7 -15
  217. package/src/heap-monitor.ts +4 -0
  218. package/src/interaction-handler.ts +5 -0
  219. package/src/markdown.test.ts +2 -2
  220. package/src/markdown.ts +4 -4
  221. package/src/message-formatting.test.ts +1 -1
  222. package/src/message-formatting.ts +4 -3
  223. package/src/opencode-plugin.ts +260 -33
  224. package/src/opencode.ts +49 -18
  225. package/src/session-handler.ts +125 -89
  226. package/src/session-search.test.ts +50 -0
  227. package/src/session-search.ts +146 -0
  228. package/src/system-message.ts +25 -5
  229. package/src/tools.ts +18 -27
  230. package/src/voice-handler.ts +1 -1
  231. package/src/wait-session.ts +1 -1
  232. package/LICENSE +0 -21
package/dist/bin.js CHANGED
@@ -8,7 +8,18 @@
8
8
  // since they are short-lived and don't need crash recovery.
9
9
  //
10
10
  // When __KIMAKI_CHILD is set, we're the child process -- just run cli.js directly.
11
+ //
12
+ // V8 heap snapshot flags:
13
+ // Injects --heapsnapshot-near-heap-limit=3 and --diagnostic-dir so V8 writes
14
+ // heap snapshots internally as it approaches the heap limit. This catches OOM
15
+ // situations where SIGKILL (exit 137) would kill the process before our
16
+ // heap-monitor.ts polling can react. The polling monitor is kept as an early
17
+ // warning system at 85% usage; the V8 flag is the last-resort safety net.
11
18
  import { spawn } from 'node:child_process';
19
+ import fs from 'node:fs';
20
+ import os from 'node:os';
21
+ import path from 'node:path';
22
+ const HEAP_SNAPSHOT_DIR = path.join(os.homedir(), '.kimaki', 'heap-snapshots');
12
23
  // First arg after node + script is either a subcommand or a flag.
13
24
  // If it doesn't start with '-', it's a subcommand (e.g. "send", "tunnel", "project").
14
25
  const firstArg = process.argv[2];
@@ -27,7 +38,11 @@ else {
27
38
  // Track when we forwarded a termination signal so we don't restart after graceful shutdown
28
39
  let shutdownRequested = false;
29
40
  function start() {
30
- child = spawn(process.argv[0], [...process.execArgv, ...process.argv.slice(1)], {
41
+ if (!fs.existsSync(HEAP_SNAPSHOT_DIR)) {
42
+ fs.mkdirSync(HEAP_SNAPSHOT_DIR, { recursive: true });
43
+ }
44
+ const heapArgs = [`--heapsnapshot-near-heap-limit=3`, `--diagnostic-dir=${HEAP_SNAPSHOT_DIR}`];
45
+ child = spawn(process.argv[0], [...heapArgs, ...process.execArgv, ...process.argv.slice(1)], {
31
46
  stdio: 'inherit',
32
47
  env: { ...process.env, __KIMAKI_CHILD: '1' },
33
48
  });
@@ -9,6 +9,10 @@ function createCliForIdParsing() {
9
9
  .option('--thread <threadId>', 'Thread ID')
10
10
  .option('--session <sessionId>', 'Session ID');
11
11
  cli.command('session archive <threadId>', 'Archive a thread');
12
+ cli
13
+ .command('session search <query>', 'Search sessions')
14
+ .option('--channel <channelId>', 'Discord channel ID')
15
+ .option('--project <path>', 'Project path');
12
16
  cli
13
17
  .command('add-project', 'Add a project')
14
18
  .option('-g, --guild <guildId>', 'Discord guild/server ID');
@@ -50,4 +54,16 @@ describe('goke CLI ID parsing', () => {
50
54
  expect(result.args[0]).toBe(threadId);
51
55
  expect(typeof result.args[0]).toBe('string');
52
56
  });
57
+ test('keeps session search regex and channel ID as strings', () => {
58
+ const cli = createCliForIdParsing();
59
+ const channelId = '0012345678901234567';
60
+ const query = '/error\\s+42/i';
61
+ const result = cli.parse(['node', 'kimaki', 'session', 'search', query, '--channel', channelId], {
62
+ run: false,
63
+ });
64
+ expect(result.args[0]).toBe(query);
65
+ expect(typeof result.args[0]).toBe('string');
66
+ expect(result.options.channel).toBe(channelId);
67
+ expect(typeof result.options.channel).toBe('string');
68
+ });
53
69
  });
package/dist/cli.js CHANGED
@@ -8,6 +8,7 @@ import { deduplicateByKey, generateBotInstallUrl, abbreviatePath } from './utils
8
8
  import { getChannelsWithDescriptions, createDiscordClient, initDatabase, getChannelDirectory, startDiscordBot, initializeOpencodeForDirectory, ensureKimakiCategory, createProjectChannels, } from './discord-bot.js';
9
9
  import { getBotToken, setBotToken, setChannelDirectory, findChannelsByDirectory, findChannelByAppId, getThreadSession, getThreadIdBySessionId, getPrisma, } from './database.js';
10
10
  import { ShareMarkdown } from './markdown.js';
11
+ import { parseSessionSearchPattern, findFirstSessionSearchHit, buildSessionSearchSnippet, getPartSearchTexts, } from './session-search.js';
11
12
  import { formatWorktreeName } from './commands/worktree.js';
12
13
  import { WORKTREE_PREFIX } from './commands/merge-worktree.js';
13
14
  import yaml from 'js-yaml';
@@ -19,7 +20,7 @@ import { createLogger, formatErrorWithStack, LogPrefix } from './logger.js';
19
20
  import { archiveThread, uploadFilesToDiscord, stripMentions } from './discord-utils.js';
20
21
  import { spawn, spawnSync, execSync } from 'node:child_process';
21
22
  import http from 'node:http';
22
- import { setDataDir, getDataDir, getLockPort, setDefaultVerbosity, setDefaultMentionMode, setCritiqueEnabled, getProjectsDir, } from './config.js';
23
+ import { setDataDir, getDataDir, getLockPort, setDefaultVerbosity, setDefaultMentionMode, setCritiqueEnabled, setVerboseOpencodeServer, getProjectsDir, } from './config.js';
23
24
  import { sanitizeAgentName } from './commands/agent.js';
24
25
  import { showFileUploadButton } from './commands/file-upload.js';
25
26
  import { execAsync } from './worktree-utils.js';
@@ -611,6 +612,11 @@ async function registerCommands({ token, appId, userCommands = [], agents = [],
611
612
  .setDescription('Show token usage and context window percentage for this session')
612
613
  .setDMPermission(false)
613
614
  .toJSON(),
615
+ new SlashCommandBuilder()
616
+ .setName('session-id')
617
+ .setDescription('Show current session ID and opencode attach command for this thread')
618
+ .setDMPermission(false)
619
+ .toJSON(),
614
620
  new SlashCommandBuilder()
615
621
  .setName('upgrade-and-restart')
616
622
  .setDescription('Upgrade kimaki to the latest version and restart the bot')
@@ -738,14 +744,14 @@ async function backgroundInit({ currentDir, token, appId, }) {
738
744
  const getClient = opencodeResult;
739
745
  const [userCommands, agents] = await Promise.all([
740
746
  getClient()
741
- .command.list({ query: { directory: currentDir } })
747
+ .command.list({ directory: currentDir })
742
748
  .then((r) => r.data || [])
743
749
  .catch((error) => {
744
750
  cliLogger.warn('Failed to load user commands during background init:', error instanceof Error ? error.message : String(error));
745
751
  return [];
746
752
  }),
747
753
  getClient()
748
- .app.agents({ query: { directory: currentDir } })
754
+ .app.agents({ directory: currentDir })
749
755
  .then((r) => r.data || [])
750
756
  .catch((error) => {
751
757
  cliLogger.warn('Failed to load agents during background init:', error instanceof Error ? error.message : String(error));
@@ -978,7 +984,7 @@ async function run({ restart, addChannels, useWorktrees, enableVoiceChannels })
978
984
  // Fetch projects, commands, and agents in parallel
979
985
  const [projects, allUserCommands, allAgents] = await Promise.all([
980
986
  getClient()
981
- .project.list({})
987
+ .project.list()
982
988
  .then((r) => r.data || [])
983
989
  .catch((error) => {
984
990
  cliLogger.log('Failed to fetch projects');
@@ -987,14 +993,14 @@ async function run({ restart, addChannels, useWorktrees, enableVoiceChannels })
987
993
  process.exit(EXIT_NO_RESTART);
988
994
  }),
989
995
  getClient()
990
- .command.list({ query: { directory: currentDir } })
996
+ .command.list({ directory: currentDir })
991
997
  .then((r) => r.data || [])
992
998
  .catch((error) => {
993
999
  cliLogger.warn('Failed to load user commands during setup:', error instanceof Error ? error.message : String(error));
994
1000
  return [];
995
1001
  }),
996
1002
  getClient()
997
- .app.agents({ query: { directory: currentDir } })
1003
+ .app.agents({ directory: currentDir })
998
1004
  .then((r) => r.data || [])
999
1005
  .catch((error) => {
1000
1006
  cliLogger.warn('Failed to load agents during setup:', error instanceof Error ? error.message : String(error));
@@ -1116,6 +1122,7 @@ cli
1116
1122
  .option('--mention-mode', 'Bot only responds when @mentioned (default for all channels)')
1117
1123
  .option('--no-critique', 'Disable automatic diff upload to critique.work in system prompts')
1118
1124
  .option('--auto-restart', 'Automatically restart the bot on crash or OOM kill')
1125
+ .option('--verbose-opencode-server', 'Forward OpenCode server stdout/stderr to kimaki.log')
1119
1126
  .action(async (options) => {
1120
1127
  try {
1121
1128
  // Set data directory early, before any database access
@@ -1140,6 +1147,10 @@ cli
1140
1147
  setCritiqueEnabled(false);
1141
1148
  cliLogger.log('Critique disabled: diffs will not be auto-uploaded to critique.work');
1142
1149
  }
1150
+ if (options.verboseOpencodeServer) {
1151
+ setVerboseOpencodeServer(true);
1152
+ cliLogger.log('Verbose OpenCode server: stdout/stderr will be forwarded to kimaki.log');
1153
+ }
1143
1154
  if (options.installUrl) {
1144
1155
  await initDatabase();
1145
1156
  const existingBot = await getBotToken();
@@ -1916,7 +1927,7 @@ cli
1916
1927
  cli
1917
1928
  .command('tunnel', 'Expose a local port via tunnel')
1918
1929
  .option('-p, --port <port>', 'Local port to expose (required)')
1919
- .option('-t, --tunnel-id [id]', 'Tunnel ID (random if omitted)')
1930
+ .option('-t, --tunnel-id [id]', 'Custom tunnel ID (only for services safe to expose publicly; prefer random default)')
1920
1931
  .option('-h, --host [host]', 'Local host (default: localhost)')
1921
1932
  .option('-s, --server [url]', 'Tunnel server URL')
1922
1933
  .action(async (options) => {
@@ -2025,7 +2036,7 @@ cli
2025
2036
  // project.list() returns all known projects globally from any OpenCode server,
2026
2037
  // but session.list/get are scoped to the server's own project. So we try each.
2027
2038
  cliLogger.log('Session not in current project, searching all projects...');
2028
- const projectsResponse = await getClient().project.list({});
2039
+ const projectsResponse = await getClient().project.list();
2029
2040
  const projects = projectsResponse.data || [];
2030
2041
  const otherProjects = projects
2031
2042
  .filter((p) => path.resolve(p.worktree) !== projectDirectory)
@@ -2062,6 +2073,157 @@ cli
2062
2073
  process.exit(EXIT_NO_RESTART);
2063
2074
  }
2064
2075
  });
2076
+ cli
2077
+ .command('session search <query>', 'Search past sessions for text or /regex/flags in the selected project')
2078
+ .option('--project <path>', 'Project directory (defaults to cwd)')
2079
+ .option('--channel <channelId>', 'Resolve project from a Discord channel ID')
2080
+ .option('--limit <n>', 'Maximum matched sessions to return (default: 20)')
2081
+ .option('--json', 'Output as JSON')
2082
+ .action(async (query, options) => {
2083
+ try {
2084
+ await initDatabase();
2085
+ if (options.project && options.channel) {
2086
+ cliLogger.error('Use either --project or --channel, not both');
2087
+ process.exit(EXIT_NO_RESTART);
2088
+ }
2089
+ const limit = (() => {
2090
+ const rawLimit = typeof options.limit === 'string' ? options.limit : '20';
2091
+ const parsed = Number.parseInt(rawLimit, 10);
2092
+ if (Number.isNaN(parsed) || parsed < 1) {
2093
+ return new Error(`Invalid --limit value: ${rawLimit}`);
2094
+ }
2095
+ return parsed;
2096
+ })();
2097
+ if (limit instanceof Error) {
2098
+ cliLogger.error(limit.message);
2099
+ process.exit(EXIT_NO_RESTART);
2100
+ }
2101
+ const projectDirectoryResult = await (async () => {
2102
+ if (options.channel) {
2103
+ const channelConfig = await getChannelDirectory(options.channel);
2104
+ if (!channelConfig) {
2105
+ return new Error(`No project mapping found for channel: ${options.channel}`);
2106
+ }
2107
+ return path.resolve(channelConfig.directory);
2108
+ }
2109
+ return path.resolve(options.project || '.');
2110
+ })();
2111
+ if (projectDirectoryResult instanceof Error) {
2112
+ cliLogger.error(projectDirectoryResult.message);
2113
+ process.exit(EXIT_NO_RESTART);
2114
+ }
2115
+ const projectDirectory = projectDirectoryResult;
2116
+ if (!fs.existsSync(projectDirectory)) {
2117
+ cliLogger.error(`Directory does not exist: ${projectDirectory}`);
2118
+ process.exit(EXIT_NO_RESTART);
2119
+ }
2120
+ const searchPattern = parseSessionSearchPattern(query);
2121
+ if (searchPattern instanceof Error) {
2122
+ cliLogger.error(searchPattern.message);
2123
+ process.exit(EXIT_NO_RESTART);
2124
+ }
2125
+ cliLogger.log('Connecting to OpenCode server...');
2126
+ const getClient = await initializeOpencodeForDirectory(projectDirectory);
2127
+ if (getClient instanceof Error) {
2128
+ cliLogger.error('Failed to connect to OpenCode:', getClient.message);
2129
+ process.exit(EXIT_NO_RESTART);
2130
+ }
2131
+ const sessionsResponse = await getClient().session.list();
2132
+ const sessions = sessionsResponse.data || [];
2133
+ if (sessions.length === 0) {
2134
+ cliLogger.log('No sessions found');
2135
+ process.exit(0);
2136
+ }
2137
+ const prisma = await getPrisma();
2138
+ const threadSessions = await prisma.thread_sessions.findMany({
2139
+ select: { thread_id: true, session_id: true },
2140
+ });
2141
+ const sessionToThread = new Map(threadSessions
2142
+ .filter((row) => row.session_id !== '')
2143
+ .map((row) => [row.session_id, row.thread_id]));
2144
+ const sortedSessions = [...sessions].sort((a, b) => {
2145
+ return b.time.updated - a.time.updated;
2146
+ });
2147
+ const matchedSessions = [];
2148
+ let scannedSessions = 0;
2149
+ for (const session of sortedSessions) {
2150
+ scannedSessions++;
2151
+ const messagesResponse = await getClient().session.messages({
2152
+ sessionID: session.id,
2153
+ });
2154
+ const messages = messagesResponse.data || [];
2155
+ const snippets = messages
2156
+ .flatMap((message) => {
2157
+ const rolePrefix = message.info.role === 'assistant'
2158
+ ? 'assistant'
2159
+ : message.info.role === 'user'
2160
+ ? 'user'
2161
+ : 'message';
2162
+ return message.parts.flatMap((part) => {
2163
+ return getPartSearchTexts(part).flatMap((text) => {
2164
+ const hit = findFirstSessionSearchHit({
2165
+ text,
2166
+ searchPattern,
2167
+ });
2168
+ if (!hit) {
2169
+ return [];
2170
+ }
2171
+ const snippet = buildSessionSearchSnippet({ text, hit });
2172
+ if (!snippet) {
2173
+ return [];
2174
+ }
2175
+ return [`${rolePrefix}: ${snippet}`];
2176
+ });
2177
+ });
2178
+ })
2179
+ .slice(0, 3);
2180
+ if (snippets.length === 0) {
2181
+ continue;
2182
+ }
2183
+ const threadId = sessionToThread.get(session.id);
2184
+ matchedSessions.push({
2185
+ id: session.id,
2186
+ title: session.title || 'Untitled Session',
2187
+ directory: session.directory,
2188
+ updated: new Date(session.time.updated).toISOString(),
2189
+ source: threadId ? 'kimaki' : 'opencode',
2190
+ threadId: threadId || null,
2191
+ snippets,
2192
+ });
2193
+ if (matchedSessions.length >= limit) {
2194
+ break;
2195
+ }
2196
+ }
2197
+ if (options.json) {
2198
+ console.log(JSON.stringify({
2199
+ query: searchPattern.raw,
2200
+ mode: searchPattern.mode,
2201
+ projectDirectory,
2202
+ scannedSessions,
2203
+ matches: matchedSessions,
2204
+ }, null, 2));
2205
+ process.exit(0);
2206
+ }
2207
+ if (matchedSessions.length === 0) {
2208
+ cliLogger.log(`No matches found for ${searchPattern.raw} in ${projectDirectory} (${scannedSessions} sessions scanned)`);
2209
+ process.exit(0);
2210
+ }
2211
+ cliLogger.log(`Found ${matchedSessions.length} matching session(s) for ${searchPattern.raw} in ${projectDirectory}`);
2212
+ for (const match of matchedSessions) {
2213
+ const threadInfo = match.threadId ? ` | thread: ${match.threadId}` : '';
2214
+ console.log(`${match.id} | ${match.title} | ${match.updated} | ${match.source}${threadInfo}`);
2215
+ console.log(` Directory: ${match.directory}`);
2216
+ match.snippets.forEach((snippet) => {
2217
+ console.log(` - ${snippet}`);
2218
+ });
2219
+ }
2220
+ process.exit(0);
2221
+ }
2222
+ catch (error) {
2223
+ cliLogger.error('Error:', error instanceof Error ? error.message : String(error));
2224
+ process.exit(EXIT_NO_RESTART);
2225
+ }
2226
+ });
2065
2227
  cli
2066
2228
  .command('session archive <threadId>', 'Archive a Discord thread and stop its mapped OpenCode session')
2067
2229
  .action(async (threadId) => {
@@ -2115,7 +2277,10 @@ cli
2115
2277
  process.exit(EXIT_NO_RESTART);
2116
2278
  }
2117
2279
  });
2118
- cli.command('upgrade', 'Upgrade kimaki to the latest version').action(async () => {
2280
+ cli
2281
+ .command('upgrade', 'Upgrade kimaki to the latest version and restart the running bot')
2282
+ .option('--skip-restart', 'Only upgrade, do not restart the running bot')
2283
+ .action(async (options) => {
2119
2284
  try {
2120
2285
  const current = getCurrentVersion();
2121
2286
  cliLogger.log(`Current version: v${current}`);
@@ -2125,6 +2290,19 @@ cli.command('upgrade', 'Upgrade kimaki to the latest version').action(async () =
2125
2290
  process.exit(0);
2126
2291
  }
2127
2292
  cliLogger.log(`Upgraded to v${newVersion}`);
2293
+ if (options.skipRestart) {
2294
+ process.exit(0);
2295
+ }
2296
+ // Spawn a new kimaki process without args (starts the bot with default command).
2297
+ // The new process kills the old one via the single-instance lock.
2298
+ // No args passed to avoid recursively running `upgrade` again.
2299
+ const child = spawn('kimaki', [], {
2300
+ shell: true,
2301
+ stdio: 'ignore',
2302
+ detached: true,
2303
+ });
2304
+ child.unref();
2305
+ cliLogger.log('Restarting bot with new version...');
2128
2306
  process.exit(0);
2129
2307
  }
2130
2308
  catch (error) {
@@ -63,7 +63,7 @@ export async function handleAbortCommand({ command }) {
63
63
  try {
64
64
  logger.log(`[ABORT-API] reason=user-requested sessionId=${sessionId} channelId=${channel.id} - sending API abort from /abort command`);
65
65
  await getClient().session.abort({
66
- path: { id: sessionId },
66
+ sessionID: sessionId,
67
67
  });
68
68
  await command.reply({
69
69
  content: `🛑 Request **aborted**`,
@@ -126,7 +126,7 @@ export async function handleAgentCommand({ interaction, appId, }) {
126
126
  return;
127
127
  }
128
128
  const agentsResponse = await getClient().app.agents({
129
- query: { directory: context.dir },
129
+ directory: context.dir,
130
130
  });
131
131
  if (!agentsResponse.data || agentsResponse.data.length === 0) {
132
132
  await interaction.editReply({ content: 'No agents available' });
@@ -4,7 +4,7 @@
4
4
  import { StringSelectMenuBuilder, StringSelectMenuInteraction, ActionRowBuilder, MessageFlags, } from 'discord.js';
5
5
  import crypto from 'node:crypto';
6
6
  import { sendThreadMessage, NOTIFY_MESSAGE_FLAGS } from '../discord-utils.js';
7
- import { getOpencodeClientV2 } from '../opencode.js';
7
+ import { getOpencodeClient } from '../opencode.js';
8
8
  import { createLogger, LogPrefix } from '../logger.js';
9
9
  const logger = createLogger(LogPrefix.ASK_QUESTION);
10
10
  // Store pending question contexts by hash
@@ -56,7 +56,7 @@ export async function showAskUserQuestionDropdowns({ thread, sessionId, director
56
56
  }
57
57
  const actionRow = new ActionRowBuilder().addComponents(selectMenu);
58
58
  await thread.send({
59
- content: `**${q.header}**\n${q.question}`,
59
+ content: `**${(q.header || '').slice(0, 200)}**\n${q.question.slice(0, 1700)}`,
60
60
  components: [actionRow],
61
61
  flags: NOTIFY_MESSAGE_FLAGS,
62
62
  });
@@ -129,16 +129,17 @@ export async function handleAskQuestionSelectMenu(interaction) {
129
129
  */
130
130
  async function submitQuestionAnswers(context) {
131
131
  try {
132
- const clientV2 = getOpencodeClientV2(context.directory);
133
- if (!clientV2) {
132
+ const client = getOpencodeClient(context.directory);
133
+ if (!client) {
134
134
  throw new Error('OpenCode server not found for directory');
135
135
  }
136
136
  // Build answers array: each element is an array of selected labels for that question
137
137
  const answers = context.questions.map((_, i) => {
138
138
  return context.answers[i] || [];
139
139
  });
140
- await clientV2.question.reply({
140
+ await client.question.reply({
141
141
  requestID: context.requestId,
142
+ directory: context.directory,
142
143
  answers,
143
144
  });
144
145
  logger.log(`Submitted answers for question ${context.requestId} in session ${context.sessionId}`);
@@ -195,8 +196,8 @@ export async function cancelPendingQuestion(threadId, userMessage) {
195
196
  return false;
196
197
  }
197
198
  try {
198
- const clientV2 = getOpencodeClientV2(context.directory);
199
- if (!clientV2) {
199
+ const client = getOpencodeClient(context.directory);
200
+ if (!client) {
200
201
  throw new Error('OpenCode server not found for directory');
201
202
  }
202
203
  // Use user's message as answer if provided, otherwise mark as "Other"
@@ -204,8 +205,9 @@ export async function cancelPendingQuestion(threadId, userMessage) {
204
205
  const answers = context.questions.map((_, i) => {
205
206
  return context.answers[i] || [customAnswer];
206
207
  });
207
- await clientV2.question.reply({
208
+ await client.question.reply({
208
209
  requestID: context.requestId,
210
+ directory: context.directory,
209
211
  answers,
210
212
  });
211
213
  logger.log(`Answered question ${context.requestId} with user message`);
@@ -1,7 +1,7 @@
1
1
  // /compact command - Trigger context compaction (summarization) for the current session.
2
2
  import { ChannelType, MessageFlags } from 'discord.js';
3
3
  import { getThreadSession } from '../database.js';
4
- import { initializeOpencodeForDirectory, getOpencodeClientV2 } from '../opencode.js';
4
+ import { initializeOpencodeForDirectory, getOpencodeClient } from '../opencode.js';
5
5
  import { resolveWorkingDirectory, SILENT_MESSAGE_FLAGS } from '../discord-utils.js';
6
6
  import { createLogger, LogPrefix } from '../logger.js';
7
7
  const logger = createLogger(LogPrefix.COMPACT);
@@ -54,8 +54,8 @@ export async function handleCompactCommand({ command }) {
54
54
  });
55
55
  return;
56
56
  }
57
- const clientV2 = getOpencodeClientV2(projectDirectory);
58
- if (!clientV2) {
57
+ const client = getOpencodeClient(projectDirectory);
58
+ if (!client) {
59
59
  await command.reply({
60
60
  content: 'Failed to get OpenCode client',
61
61
  flags: MessageFlags.Ephemeral | SILENT_MESSAGE_FLAGS,
@@ -66,7 +66,7 @@ export async function handleCompactCommand({ command }) {
66
66
  await command.deferReply({ flags: SILENT_MESSAGE_FLAGS });
67
67
  try {
68
68
  // Get session messages to find the model from the last user message
69
- const messagesResult = await clientV2.session.messages({
69
+ const messagesResult = await client.session.messages({
70
70
  sessionID: sessionId,
71
71
  directory: workingDirectory,
72
72
  });
@@ -88,7 +88,7 @@ export async function handleCompactCommand({ command }) {
88
88
  return;
89
89
  }
90
90
  const { providerID, modelID } = lastUserMessage.info.model;
91
- const result = await clientV2.session.summarize({
91
+ const result = await client.session.summarize({
92
92
  sessionID: sessionId,
93
93
  directory: workingDirectory,
94
94
  providerID,
@@ -60,8 +60,8 @@ export async function handleContextUsageCommand({ command }) {
60
60
  await command.deferReply({ flags: SILENT_MESSAGE_FLAGS });
61
61
  try {
62
62
  const messagesResponse = await getClient().session.messages({
63
- path: { id: sessionId },
64
- query: { directory: workingDirectory },
63
+ sessionID: sessionId,
64
+ directory: workingDirectory,
65
65
  });
66
66
  const messages = messagesResponse.data || [];
67
67
  const assistantMessages = messages.filter((m) => m.info.role === 'assistant');
@@ -99,7 +99,7 @@ export async function handleContextUsageCommand({ command }) {
99
99
  // Fetch model context limit from provider API
100
100
  let contextLimit;
101
101
  const providersResult = await errore.tryAsync(() => {
102
- return getClient().provider.list({ query: { directory: workingDirectory } });
102
+ return getClient().provider.list({ directory: workingDirectory });
103
103
  });
104
104
  if (providersResult instanceof Error) {
105
105
  logger.error('[CONTEXT-USAGE] Failed to fetch provider info:', providersResult);
@@ -117,7 +117,7 @@ export async function handleContextUsageCommand({ command }) {
117
117
  if (contextLimit) {
118
118
  const percentage = Math.round((totalTokens / contextLimit) * 100);
119
119
  const formattedLimit = contextLimit.toLocaleString('en-US');
120
- lines.push(`**Context usage:** ${formattedTokens} / ${formattedLimit} tokens (${percentage}%)`);
120
+ lines.push(`**Context usage:** ${percentage}%, ${formattedTokens} / ${formattedLimit} tokens`);
121
121
  }
122
122
  else {
123
123
  lines.push(`**Context usage:** ${formattedTokens} tokens (context limit unavailable)`);
@@ -70,7 +70,7 @@ export function showFileUploadButton({ thread, sessionId, directory, prompt, max
70
70
  .fetch(ctx.messageId)
71
71
  .then((msg) => {
72
72
  return msg.edit({
73
- content: `**File Upload Requested**\n${prompt}\n_Timed out_`,
73
+ content: `**File Upload Requested**\n${prompt.slice(0, 1900)}\n_Timed out_`,
74
74
  components: [],
75
75
  });
76
76
  })
@@ -98,7 +98,7 @@ export function showFileUploadButton({ thread, sessionId, directory, prompt, max
98
98
  const actionRow = new ActionRowBuilder().addComponents(uploadButton);
99
99
  thread
100
100
  .send({
101
- content: `**File Upload Requested**\n${prompt}`,
101
+ content: `**File Upload Requested**\n${prompt.slice(0, 1900)}`,
102
102
  components: [actionRow],
103
103
  flags: NOTIFY_MESSAGE_FLAGS,
104
104
  })
@@ -240,7 +240,7 @@ function updateButtonMessage(context, status) {
240
240
  .fetch(context.messageId)
241
241
  .then((msg) => {
242
242
  return msg.edit({
243
- content: `**File Upload Requested**\n${context.prompt}\n${status}`,
243
+ content: `**File Upload Requested**\n${context.prompt.slice(0, 1900)}\n${status}`,
244
244
  components: [],
245
245
  });
246
246
  })
@@ -57,7 +57,7 @@ export async function handleForkCommand(interaction) {
57
57
  }
58
58
  try {
59
59
  const messagesResponse = await getClient().session.messages({
60
- path: { id: sessionId },
60
+ sessionID: sessionId,
61
61
  });
62
62
  if (!messagesResponse.data) {
63
63
  await interaction.editReply({
@@ -143,8 +143,8 @@ export async function handleForkSelectMenu(interaction) {
143
143
  }
144
144
  try {
145
145
  const forkResponse = await getClient().session.fork({
146
- path: { id: sessionId },
147
- body: { messageID: selectedMessageId },
146
+ sessionID: sessionId,
147
+ messageID: selectedMessageId,
148
148
  });
149
149
  if (!forkResponse.data) {
150
150
  await interaction.editReply('Failed to fork session');
@@ -178,7 +178,7 @@ export async function handleForkSelectMenu(interaction) {
178
178
  await sendThreadMessage(thread, `**Forked session created!**\nFrom: \`${sessionId}\`\nNew session: \`${forkedSession.id}\``);
179
179
  // Fetch and display the last assistant messages from the forked session
180
180
  const messagesResponse = await getClient().session.messages({
181
- path: { id: forkedSession.id },
181
+ sessionID: forkedSession.id,
182
182
  });
183
183
  if (messagesResponse.data) {
184
184
  const { partIds, content } = collectLastAssistantParts({
@@ -73,7 +73,7 @@ export async function handleLoginCommand({ interaction, appId, }) {
73
73
  return;
74
74
  }
75
75
  const providersResponse = await getClient().provider.list({
76
- query: { directory: projectDirectory },
76
+ directory: projectDirectory,
77
77
  });
78
78
  if (!providersResponse.data) {
79
79
  await interaction.editReply({
@@ -160,13 +160,13 @@ export async function handleLoginProviderSelectMenu(interaction) {
160
160
  }
161
161
  // Get provider info for display
162
162
  const providersResponse = await getClient().provider.list({
163
- query: { directory: context.dir },
163
+ directory: context.dir,
164
164
  });
165
165
  const provider = providersResponse.data?.all.find((p) => p.id === selectedProviderId);
166
166
  const providerName = provider?.name || selectedProviderId;
167
167
  // Get auth methods for all providers
168
168
  const authMethodsResponse = await getClient().provider.auth({
169
- query: { directory: context.dir },
169
+ directory: context.dir,
170
170
  });
171
171
  if (!authMethodsResponse.data) {
172
172
  await interaction.deferUpdate();
@@ -273,7 +273,7 @@ export async function handleLoginMethodSelectMenu(interaction) {
273
273
  }
274
274
  // Get auth methods again to get the selected one
275
275
  const authMethodsResponse = await getClient().provider.auth({
276
- query: { directory: context.dir },
276
+ directory: context.dir,
277
277
  });
278
278
  const methods = authMethodsResponse.data?.[context.providerId] || [
279
279
  { type: 'api', label: 'API Key' },
@@ -361,9 +361,9 @@ async function startOAuthFlow(interaction, context, contextHash) {
361
361
  });
362
362
  // Start OAuth authorization
363
363
  const authorizeResponse = await getClient().provider.oauth.authorize({
364
- path: { id: context.providerId },
365
- body: { method: context.methodIndex },
366
- query: { directory: context.dir },
364
+ providerID: context.providerId,
365
+ method: context.methodIndex,
366
+ directory: context.dir,
367
367
  });
368
368
  if (!authorizeResponse.data) {
369
369
  const errorData = authorizeResponse.error;
@@ -397,9 +397,9 @@ async function startOAuthFlow(interaction, context, contextHash) {
397
397
  if (method === 'auto') {
398
398
  // Poll for completion (device flow)
399
399
  const callbackResponse = await getClient().provider.oauth.callback({
400
- path: { id: context.providerId },
401
- body: { method: context.methodIndex },
402
- query: { directory: context.dir },
400
+ providerID: context.providerId,
401
+ method: context.methodIndex,
402
+ directory: context.dir,
403
403
  });
404
404
  if (callbackResponse.error) {
405
405
  const errorData = callbackResponse.error;
@@ -410,7 +410,7 @@ async function startOAuthFlow(interaction, context, contextHash) {
410
410
  return;
411
411
  }
412
412
  // Dispose to refresh provider state so new credentials are recognized
413
- await getClient().instance.dispose({ query: { directory: context.dir } });
413
+ await getClient().instance.dispose({ directory: context.dir });
414
414
  await interaction.editReply({
415
415
  content: `✅ **Successfully authenticated with ${context.providerName}!**\n\nYou can now use models from this provider.`,
416
416
  components: [],
@@ -464,15 +464,14 @@ export async function handleApiKeyModalSubmit(interaction) {
464
464
  }
465
465
  // Set the API key
466
466
  await getClient().auth.set({
467
- path: { id: context.providerId },
468
- body: {
467
+ providerID: context.providerId,
468
+ auth: {
469
469
  type: 'api',
470
470
  key: apiKey.trim(),
471
471
  },
472
- query: { directory: context.dir },
473
472
  });
474
473
  // Dispose to refresh provider state so new credentials are recognized
475
- await getClient().instance.dispose({ query: { directory: context.dir } });
474
+ await getClient().instance.dispose({ directory: context.dir });
476
475
  await interaction.editReply({
477
476
  content: `✅ **Successfully authenticated with ${context.providerName}!**\n\nYou can now use models from this provider.`,
478
477
  });
@@ -62,7 +62,7 @@ async function sendPromptToModel({ prompt, thread, projectDirectory, command, ap
62
62
  appId,
63
63
  }).catch((e) => {
64
64
  logger.error(`[merge] Failed to send prompt to model:`, e);
65
- sendThreadMessage(thread, `Failed to send prompt: ${e instanceof Error ? e.message : String(e)}`).catch(() => { });
65
+ sendThreadMessage(thread, `Failed to send prompt: ${(e instanceof Error ? e.message : String(e)).slice(0, 1900)}`).catch(() => { });
66
66
  });
67
67
  }
68
68
  export async function handleMergeWorktreeCommand({ command, appId, }) {