kimaki 0.26.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/dist/agent-model.e2e.test.js +250 -164
  2. package/dist/anthropic-account-identity.js +9 -1
  3. package/dist/anthropic-auth-plugin.js +10 -13
  4. package/dist/anthropic-auth-plugin.test.js +17 -0
  5. package/dist/anthropic-auth-state.js +1 -0
  6. package/dist/bash-tool-schema-plugin.js +32 -0
  7. package/dist/bash-tool-schema-plugin.test.js +49 -0
  8. package/dist/bin.js +73 -19
  9. package/dist/cli-commands/maintenance.js +46 -7
  10. package/dist/cli-commands/project.js +11 -27
  11. package/dist/cli-commands/send.js +30 -1
  12. package/dist/cli-commands/session.js +322 -90
  13. package/dist/cli-commands/task.js +34 -15
  14. package/dist/cli-parsing.test.js +83 -4
  15. package/dist/cli-runner.js +44 -8
  16. package/dist/cli-runner.test.js +27 -0
  17. package/dist/cli-send-thread.e2e.test.js +9 -9
  18. package/dist/cli.js +32 -0
  19. package/dist/commands/abort.js +5 -1
  20. package/dist/commands/action-buttons.js +2 -1
  21. package/dist/commands/add-project.js +4 -7
  22. package/dist/commands/agent.js +164 -32
  23. package/dist/commands/ask-question.js +23 -33
  24. package/dist/commands/ask-question.test.js +43 -1
  25. package/dist/commands/btw.js +28 -6
  26. package/dist/commands/file-upload.js +2 -1
  27. package/dist/commands/fork-subagent.js +2 -4
  28. package/dist/commands/fork.js +4 -4
  29. package/dist/commands/last-sessions.js +17 -10
  30. package/dist/commands/login.js +6 -0
  31. package/dist/commands/merge-worktree.js +47 -14
  32. package/dist/commands/model-variant.js +8 -1
  33. package/dist/commands/model.js +16 -9
  34. package/dist/commands/multioauth.js +1 -0
  35. package/dist/commands/new-worktree.js +170 -102
  36. package/dist/commands/queue.js +3 -2
  37. package/dist/commands/resume.js +4 -4
  38. package/dist/commands/session.js +78 -63
  39. package/dist/commands/user-command.js +6 -8
  40. package/dist/commands/worktrees.js +5 -13
  41. package/dist/config.js +16 -1
  42. package/dist/cpu-profiler.js +211 -0
  43. package/dist/cpu-profiler.test.js +160 -0
  44. package/dist/database.js +152 -3
  45. package/dist/db.js +33 -0
  46. package/dist/db.test.js +267 -1
  47. package/dist/default-channel-provisioning.test.js +148 -0
  48. package/dist/discord-bot.js +517 -488
  49. package/dist/discord-command-registration.js +25 -10
  50. package/dist/discord-command-registration.test.js +17 -0
  51. package/dist/discord-utils.js +97 -5
  52. package/dist/discord-utils.test.js +151 -1
  53. package/dist/errors.js +10 -0
  54. package/dist/exec-async.js +17 -5
  55. package/dist/external-directory-permissions.e2e.test.js +11 -7
  56. package/dist/external-directory-project-deny.e2e.test.js +5 -3
  57. package/dist/external-opencode-sync.js +94 -17
  58. package/dist/external-opencode-sync.test.js +206 -0
  59. package/dist/extract-sdk-error-message.test.js +13 -0
  60. package/dist/file-edit-log.js +197 -0
  61. package/dist/file-edit-log.test.js +258 -0
  62. package/dist/format-tables.js +52 -0
  63. package/dist/format-tables.test.js +93 -0
  64. package/dist/gateway-proxy-reconnect.e2e.test.js +28 -8
  65. package/dist/gateway-proxy.e2e.test.js +18 -18
  66. package/dist/git-worktree-core.js +182 -17
  67. package/dist/interaction-handler.js +416 -398
  68. package/dist/ipc-tools-plugin.js +68 -3
  69. package/dist/kimaki-opencode-plugin-loading.e2e.test.js +122 -58
  70. package/dist/kimaki-opencode-plugin.js +9 -3
  71. package/dist/kimaki-workspace-adaptor.js +33 -10
  72. package/dist/logger.js +11 -1
  73. package/dist/markdown.js +3 -1
  74. package/dist/markdown.test.js +11 -3
  75. package/dist/message-formatting.js +181 -51
  76. package/dist/message-formatting.test.js +529 -22
  77. package/dist/message-preprocessing.js +105 -1
  78. package/dist/oauth-rotation-shared.js +10 -0
  79. package/dist/openai-auth-plugin.js +1 -0
  80. package/dist/openai-auth-state.js +1 -0
  81. package/dist/opencode-command.js +28 -0
  82. package/dist/opencode-command.test.js +109 -1
  83. package/dist/opencode-interrupt-plugin.js +4 -0
  84. package/dist/opencode-interrupt-plugin.test.js +24 -0
  85. package/dist/opencode.js +82 -15
  86. package/dist/project-add.test.js +62 -0
  87. package/dist/question-abort-clears-dropdown.e2e.test.js +89 -0
  88. package/dist/question-abort-retry-text-before-dropdown.e2e.test.js +150 -0
  89. package/dist/question-text-before-dropdown.e2e.test.js +52 -0
  90. package/dist/queue-advanced-abort.e2e.test.js +8 -10
  91. package/dist/queue-advanced-action-buttons.e2e.test.js +8 -8
  92. package/dist/queue-advanced-e2e-setup.js +78 -5
  93. package/dist/queue-advanced-footer.e2e.test.js +60 -269
  94. package/dist/queue-advanced-model-switch.e2e.test.js +9 -11
  95. package/dist/queue-advanced-permissions-typing.e2e.test.js +15 -15
  96. package/dist/queue-advanced-question.e2e.test.js +32 -27
  97. package/dist/queue-advanced-typing-interrupt.e2e.test.js +10 -12
  98. package/dist/queue-advanced-typing.e2e.test.js +7 -9
  99. package/dist/queue-delete-message.e2e.test.js +3 -3
  100. package/dist/queue-drain-after-interactive-ui.e2e.test.js +5 -5
  101. package/dist/queue-interrupt-drain.e2e.test.js +122 -12
  102. package/dist/queue-question-select-drain.e2e.test.js +34 -132
  103. package/dist/runtime-lifecycle.e2e.test.js +21 -51
  104. package/dist/schema.js +35 -1
  105. package/dist/session-handler/event-stream-state.js +391 -50
  106. package/dist/session-handler/event-stream-state.test.js +736 -8
  107. package/dist/session-handler/model-utils.js +172 -5
  108. package/dist/session-handler/model-utils.test.js +445 -0
  109. package/dist/session-handler/opencode-session-event-log.js +30 -1
  110. package/dist/session-handler/thread-ingress.test.js +41 -0
  111. package/dist/session-handler/thread-runtime-state.js +2 -0
  112. package/dist/session-handler/thread-session-runtime-summary.test.js +121 -0
  113. package/dist/session-handler/thread-session-runtime.js +574 -299
  114. package/dist/session-search.js +123 -4
  115. package/dist/session-search.test.js +248 -1
  116. package/dist/session-sleep.test.js +224 -0
  117. package/dist/session-title-rename.test.js +37 -39
  118. package/dist/sleep.e2e.test.js +494 -0
  119. package/dist/startup-time.e2e.test.js +2 -1
  120. package/dist/store.js +3 -0
  121. package/dist/system-message.js +102 -16
  122. package/dist/system-message.test.js +192 -15
  123. package/dist/task-runner.js +96 -5
  124. package/dist/task-schedule.js +87 -1
  125. package/dist/task-schedule.test.js +149 -1
  126. package/dist/test-utils.js +17 -9
  127. package/dist/thinking-utils.js +10 -0
  128. package/dist/thinking-utils.test.js +35 -0
  129. package/dist/thread-message-queue.e2e.test.js +65 -213
  130. package/dist/undo-redo.e2e.test.js +17 -9
  131. package/dist/voice-attachment.js +23 -1
  132. package/dist/voice-handler.js +21 -4
  133. package/dist/voice-message.e2e.test.js +144 -30
  134. package/dist/voice-routing-input.e2e.test.js +195 -0
  135. package/dist/voice-routing-question.e2e.test.js +125 -0
  136. package/dist/voice.js +28 -8
  137. package/dist/voice.test.js +96 -30
  138. package/dist/worktree-clone-isolation.e2e.test.js +188 -0
  139. package/dist/worktree-lifecycle.e2e.test.js +55 -36
  140. package/dist/worktrees.js +226 -443
  141. package/dist/worktrees.test.js +435 -58
  142. package/dist/xai-auth-plugin.js +1 -0
  143. package/dist/xai-auth-state.js +1 -0
  144. package/package.json +8 -6
  145. package/skills/bump-holocron-consumers/SKILL.md +137 -0
  146. package/skills/critique/SKILL.md +4 -4
  147. package/skills/errore/SKILL.md +60 -218
  148. package/skills/goke/SKILL.md +150 -10
  149. package/skills/holocron/SKILL.md +154 -17
  150. package/skills/npm-package/SKILL.md +55 -35
  151. package/skills/profano/SKILL.md +17 -2
  152. package/skills/spiceflow/SKILL.md +39 -3
  153. package/skills/strada/SKILL.md +39 -0
  154. package/skills/zele/SKILL.md +19 -0
  155. package/src/agent-model.e2e.test.ts +287 -186
  156. package/src/anthropic-account-identity.ts +20 -1
  157. package/src/anthropic-auth-plugin.test.ts +19 -0
  158. package/src/anthropic-auth-plugin.ts +12 -16
  159. package/src/anthropic-auth-state.ts +1 -0
  160. package/src/bash-tool-schema-plugin.test.ts +55 -0
  161. package/src/bash-tool-schema-plugin.ts +46 -0
  162. package/src/bin.ts +78 -26
  163. package/src/cli-commands/maintenance.ts +59 -13
  164. package/src/cli-commands/project.ts +14 -35
  165. package/src/cli-commands/send.ts +31 -1
  166. package/src/cli-commands/session.ts +374 -114
  167. package/src/cli-commands/task.ts +34 -15
  168. package/src/cli-parsing.test.ts +103 -4
  169. package/src/cli-runner.test.ts +49 -0
  170. package/src/cli-runner.ts +44 -7
  171. package/src/cli-send-thread.e2e.test.ts +9 -11
  172. package/src/cli.ts +53 -0
  173. package/src/commands/abort.ts +6 -1
  174. package/src/commands/action-buttons.ts +2 -1
  175. package/src/commands/add-project.ts +4 -8
  176. package/src/commands/agent.ts +205 -29
  177. package/src/commands/ask-question.test.ts +48 -1
  178. package/src/commands/ask-question.ts +23 -33
  179. package/src/commands/btw.ts +40 -5
  180. package/src/commands/file-upload.ts +2 -1
  181. package/src/commands/fork-subagent.ts +2 -3
  182. package/src/commands/fork.ts +4 -3
  183. package/src/commands/last-sessions.ts +10 -4
  184. package/src/commands/login.ts +6 -0
  185. package/src/commands/merge-worktree.ts +54 -16
  186. package/src/commands/model-variant.ts +9 -1
  187. package/src/commands/model.ts +20 -9
  188. package/src/commands/multioauth.ts +1 -0
  189. package/src/commands/new-worktree.ts +138 -55
  190. package/src/commands/queue.ts +3 -2
  191. package/src/commands/resume.ts +4 -3
  192. package/src/commands/session.ts +94 -70
  193. package/src/commands/user-command.ts +6 -6
  194. package/src/commands/worktrees.ts +5 -12
  195. package/src/config.ts +18 -1
  196. package/src/cpu-profiler.test.ts +183 -0
  197. package/src/cpu-profiler.ts +293 -0
  198. package/src/database.ts +235 -3
  199. package/src/db.test.ts +293 -0
  200. package/src/db.ts +38 -0
  201. package/src/default-channel-provisioning.test.ts +155 -0
  202. package/src/discord-bot.ts +78 -36
  203. package/src/discord-command-registration.test.ts +20 -0
  204. package/src/discord-command-registration.ts +42 -12
  205. package/src/discord-utils.test.ts +176 -0
  206. package/src/discord-utils.ts +152 -7
  207. package/src/errors.ts +12 -0
  208. package/src/exec-async.ts +20 -11
  209. package/src/external-directory-permissions.e2e.test.ts +11 -7
  210. package/src/external-directory-project-deny.e2e.test.ts +5 -3
  211. package/src/external-opencode-sync.test.ts +248 -0
  212. package/src/external-opencode-sync.ts +122 -19
  213. package/src/extract-sdk-error-message.test.ts +18 -0
  214. package/src/file-edit-log.test.ts +287 -0
  215. package/src/file-edit-log.ts +283 -0
  216. package/src/format-tables.test.ts +101 -0
  217. package/src/format-tables.ts +75 -0
  218. package/src/gateway-proxy-reconnect.e2e.test.ts +38 -8
  219. package/src/gateway-proxy.e2e.test.ts +18 -17
  220. package/src/git-worktree-core.ts +247 -20
  221. package/src/interaction-handler.ts +36 -13
  222. package/src/ipc-tools-plugin.ts +82 -5
  223. package/src/kimaki-opencode-plugin-loading.e2e.test.ts +188 -97
  224. package/src/kimaki-opencode-plugin.ts +9 -3
  225. package/src/kimaki-workspace-adaptor.ts +40 -11
  226. package/src/logger.ts +14 -4
  227. package/src/markdown.test.ts +13 -3
  228. package/src/markdown.ts +4 -1
  229. package/src/message-formatting.test.ts +672 -25
  230. package/src/message-formatting.ts +242 -53
  231. package/src/message-preprocessing.ts +116 -1
  232. package/src/oauth-rotation-shared.ts +10 -0
  233. package/src/openai-auth-plugin.ts +1 -0
  234. package/src/openai-auth-state.ts +1 -0
  235. package/src/opencode-command.test.ts +140 -0
  236. package/src/opencode-command.ts +38 -0
  237. package/src/opencode-interrupt-plugin.test.ts +32 -0
  238. package/src/opencode-interrupt-plugin.ts +3 -0
  239. package/src/opencode.ts +115 -15
  240. package/src/project-add.test.ts +80 -0
  241. package/src/question-abort-clears-dropdown.e2e.test.ts +109 -0
  242. package/src/question-abort-retry-text-before-dropdown.e2e.test.ts +172 -0
  243. package/src/question-text-before-dropdown.e2e.test.ts +67 -0
  244. package/src/queue-advanced-abort.e2e.test.ts +8 -9
  245. package/src/queue-advanced-action-buttons.e2e.test.ts +8 -8
  246. package/src/queue-advanced-e2e-setup.ts +83 -4
  247. package/src/queue-advanced-footer.e2e.test.ts +67 -315
  248. package/src/queue-advanced-model-switch.e2e.test.ts +9 -10
  249. package/src/queue-advanced-permissions-typing.e2e.test.ts +15 -15
  250. package/src/queue-advanced-question.e2e.test.ts +36 -30
  251. package/src/queue-advanced-typing-interrupt.e2e.test.ts +11 -11
  252. package/src/queue-advanced-typing.e2e.test.ts +8 -8
  253. package/src/queue-delete-message.e2e.test.ts +3 -3
  254. package/src/queue-drain-after-interactive-ui.e2e.test.ts +5 -5
  255. package/src/queue-interrupt-drain.e2e.test.ts +133 -12
  256. package/src/queue-question-select-drain.e2e.test.ts +36 -161
  257. package/src/runtime-lifecycle.e2e.test.ts +21 -54
  258. package/src/schema.sql +15 -2
  259. package/src/schema.ts +37 -1
  260. package/src/session-handler/event-stream-state.test.ts +790 -7
  261. package/src/session-handler/event-stream-state.ts +568 -53
  262. package/src/session-handler/model-utils.test.ts +537 -0
  263. package/src/session-handler/model-utils.ts +281 -5
  264. package/src/session-handler/opencode-session-event-log.ts +31 -1
  265. package/src/session-handler/thread-ingress.test.ts +54 -0
  266. package/src/session-handler/thread-runtime-state.ts +3 -0
  267. package/src/session-handler/thread-session-runtime-summary.test.ts +169 -0
  268. package/src/session-handler/thread-session-runtime.ts +712 -358
  269. package/src/session-search.test.ts +281 -0
  270. package/src/session-search.ts +241 -7
  271. package/src/session-sleep.test.ts +294 -0
  272. package/src/session-title-rename.test.ts +54 -48
  273. package/src/sleep.e2e.test.ts +565 -0
  274. package/src/startup-time.e2e.test.ts +5 -1
  275. package/src/store.ts +22 -0
  276. package/src/system-message.test.ts +226 -15
  277. package/src/system-message.ts +130 -16
  278. package/src/task-runner.ts +138 -3
  279. package/src/task-schedule.test.ts +170 -0
  280. package/src/task-schedule.ts +141 -1
  281. package/src/test-utils.ts +21 -10
  282. package/src/thinking-utils.test.ts +46 -0
  283. package/src/thinking-utils.ts +21 -0
  284. package/src/thread-message-queue.e2e.test.ts +65 -245
  285. package/src/undo-redo.e2e.test.ts +17 -9
  286. package/src/voice-attachment.ts +29 -1
  287. package/src/voice-handler.ts +23 -4
  288. package/src/voice-message.e2e.test.ts +149 -29
  289. package/src/voice-routing-input.e2e.test.ts +203 -0
  290. package/src/voice-routing-question.e2e.test.ts +131 -0
  291. package/src/voice.test.ts +107 -29
  292. package/src/voice.ts +34 -6
  293. package/src/worktree-clone-isolation.e2e.test.ts +213 -0
  294. package/src/worktree-lifecycle.e2e.test.ts +55 -35
  295. package/src/worktrees.test.ts +505 -64
  296. package/src/worktrees.ts +257 -603
  297. package/src/xai-auth-plugin.ts +1 -0
  298. package/src/xai-auth-state.ts +1 -0
  299. package/dist/message-finish-field.e2e.test.js +0 -169
  300. package/dist/subagent-rate-limit-plugin.js +0 -184
  301. package/src/message-finish-field.e2e.test.ts +0 -196
  302. package/src/subagent-rate-limit-plugin.ts +0 -228
@@ -17,7 +17,7 @@ import { setDataDir } from './config.js';
17
17
  import { store } from './store.js';
18
18
  import { startDiscordBot } from './discord-bot.js';
19
19
  import { getRuntime } from './session-handler/thread-session-runtime.js';
20
- import { setBotToken, initDatabase, closeDatabase, setChannelDirectory, setChannelVerbosity, setChannelWorktreesEnabled, getThreadSession, getThreadWorktreeOrWorkspace, } from './database.js';
20
+ import { setBotToken, initDatabase, closeDatabase, setChannelDirectory, setChannelVerbosity, setChannelWorktreesEnabled, getThreadSession, getThreadWorktreeOrWorkspace, getSessionModel, setSessionModel, } from './database.js';
21
21
  import { startHranaServer, stopHranaServer } from './hrana-server.js';
22
22
  import { initializeOpencodeForDirectory, stopOpencodeServer, } from './opencode.js';
23
23
  import { chooseLockPort, cleanupTestSessions, waitForBotMessageContaining, } from './test-utils.js';
@@ -31,6 +31,7 @@ const WORKTREE_SUFFIX = Date.now().toString(36).slice(-6);
31
31
  const WORKTREE_NAME = `wt-e2e-${WORKTREE_SUFFIX}`;
32
32
  const CHANNEL_WORKTREE_NAME = `wt-chan-${WORKTREE_SUFFIX}`;
33
33
  const AUTO_WORKTREE_SUFFIX = `wt-auto-${WORKTREE_SUFFIX}`;
34
+ const SOURCE_MODEL = 'source-model-v2';
34
35
  function normalizeWorktreeLifecycleText(text) {
35
36
  return text
36
37
  .replaceAll(CHANNEL_WORKTREE_NAME, 'CHANNEL_WORKTREE_NAME')
@@ -172,6 +173,10 @@ describe('worktree lifecycle', () => {
172
173
  matchers: createDeterministicMatchers(),
173
174
  },
174
175
  });
176
+ const providerConfig = opencodeConfig.provider['deterministic-provider'];
177
+ if (!providerConfig)
178
+ throw new Error('Missing deterministic provider config');
179
+ providerConfig.models[SOURCE_MODEL] = { name: SOURCE_MODEL };
175
180
  fs.writeFileSync(path.join(directories.projectDirectory, 'opencode.json'), JSON.stringify(opencodeConfig, null, 2));
176
181
  fs.writeFileSync(path.join(directories.nonGitDirectory, 'opencode.json'), JSON.stringify(opencodeConfig, null, 2));
177
182
  // Initialize git repo after writing opencode.json so the initial commit
@@ -296,7 +301,7 @@ describe('worktree lifecycle', () => {
296
301
  discord,
297
302
  threadId: thread.id,
298
303
  userId: TEST_USER_ID,
299
- text: '⬥ ok',
304
+ text: 'ok',
300
305
  afterUserMessageIncludes: 'before-worktree',
301
306
  timeout: 10_000,
302
307
  });
@@ -306,6 +311,12 @@ describe('worktree lifecycle', () => {
306
311
  expect(runtimeBefore.sdkDirectory).toBe(directories.projectDirectory);
307
312
  const sessionBefore = await getThreadSession(thread.id);
308
313
  expect(sessionBefore).toBeTruthy();
314
+ if (!sessionBefore)
315
+ throw new Error('Source session was not persisted');
316
+ await setSessionModel({
317
+ sessionId: sessionBefore,
318
+ modelId: `deterministic-provider/${SOURCE_MODEL}`,
319
+ });
309
320
  // 2. Run /new-worktree inside the source thread.
310
321
  // This should create a new worktree thread instead of switching this one.
311
322
  const { id: interactionId } = await th
@@ -340,6 +351,11 @@ describe('worktree lifecycle', () => {
340
351
  text: 'Branch:',
341
352
  timeout: 10_000,
342
353
  });
354
+ // Messages sent as soon as the checkout is ready must wait for the
355
+ // source session fork and keep its model.
356
+ await worktreeTh.user(TEST_USER_ID).sendMessage({
357
+ content: 'Reply with exactly: after-worktree-thread',
358
+ });
343
359
  await waitForBotMessageContaining({
344
360
  discord,
345
361
  threadId: worktreeThread.id,
@@ -354,6 +370,12 @@ describe('worktree lifecycle', () => {
354
370
  if (!worktreeSession)
355
371
  throw new Error('Worktree session was not persisted');
356
372
  expect(worktreeSession).not.toBe(sessionBefore);
373
+ await expect(getSessionModel(worktreeSession)).resolves.toMatchInlineSnapshot(`
374
+ {
375
+ "modelId": "deterministic-provider/source-model-v2",
376
+ "variant": null,
377
+ }
378
+ `);
357
379
  await expect(getThreadWorktreeOrWorkspace(thread.id)).resolves.toBeUndefined();
358
380
  const worktreeInfo = await getThreadWorktreeOrWorkspace(worktreeThread.id);
359
381
  expect(worktreeInfo?.status).toBe('ready');
@@ -378,9 +400,6 @@ describe('worktree lifecycle', () => {
378
400
  expect(worktreeRuntime.sdkDirectory).toContain(`${path.sep}worktrees${path.sep}`);
379
401
  // 4. Send messages to both threads. The source continues in the base
380
402
  // checkout, and the new thread runs in the worktree checkout.
381
- await worktreeTh.user(TEST_USER_ID).sendMessage({
382
- content: 'Reply with exactly: after-worktree-thread',
383
- });
384
403
  await th.user(TEST_USER_ID).sendMessage({
385
404
  content: 'Reply with exactly: after-source-thread',
386
405
  });
@@ -388,7 +407,7 @@ describe('worktree lifecycle', () => {
388
407
  discord,
389
408
  threadId: worktreeThread.id,
390
409
  userId: TEST_USER_ID,
391
- text: '⬥ ok',
410
+ text: 'ok',
392
411
  afterUserMessageIncludes: 'after-worktree-thread',
393
412
  timeout: 4_000,
394
413
  });
@@ -396,7 +415,7 @@ describe('worktree lifecycle', () => {
396
415
  discord,
397
416
  threadId: thread.id,
398
417
  userId: TEST_USER_ID,
399
- text: '⬥ ok',
418
+ text: 'ok',
400
419
  afterUserMessageIncludes: 'after-source-thread',
401
420
  timeout: 4_000,
402
421
  });
@@ -405,7 +424,7 @@ describe('worktree lifecycle', () => {
405
424
  discord,
406
425
  threadId: worktreeThread.id,
407
426
  userId: TEST_USER_ID,
408
- text: 'deterministic-v2',
427
+ text: SOURCE_MODEL,
409
428
  afterUserMessageIncludes: 'after-worktree-thread',
410
429
  timeout: 4_000,
411
430
  });
@@ -413,7 +432,7 @@ describe('worktree lifecycle', () => {
413
432
  discord,
414
433
  threadId: thread.id,
415
434
  userId: TEST_USER_ID,
416
- text: 'deterministic-v2',
435
+ text: SOURCE_MODEL,
417
436
  afterUserMessageIncludes: 'after-source-thread',
418
437
  timeout: 4_000,
419
438
  });
@@ -422,20 +441,20 @@ describe('worktree lifecycle', () => {
422
441
  "--- from: user (worktree-tester)
423
442
  Reply with exactly: before-worktree
424
443
  --- from: assistant (TestBot)
425
- *using deterministic-provider/deterministic-v2*
426
- ⬥ ok
444
+ > *using deterministic-provider/deterministic-v2*
445
+ > ok
427
446
  Creating worktree in <#THREAD_ID>
428
- *project ⋅ main ⋅ Ns ⋅ N% ⋅ deterministic-v2*
447
+ > *project ⋅ main ⋅ <1s ⋅ 0% ⋅ deterministic-v2* <@200000000000000901>
429
448
  --- from: user (worktree-tester)
430
449
  Reply with exactly: after-source-thread
431
450
  --- from: assistant (TestBot)
432
- ⬥ ok
433
- *project ⋅ main ⋅ Ns ⋅ N% ⋅ deterministic-v2*"
451
+ > ok
452
+ > *project ⋅ main ⋅ <1s ⋅ 0% ⋅ source-model-v2* <@200000000000000901>"
434
453
  `);
435
454
  expect(sourceText).toContain('Reply with exactly: before-worktree');
436
455
  expect(sourceText).toContain('Reply with exactly: after-source-thread');
437
456
  expect(sourceText).not.toContain('Worktree:');
438
- expect((sourceText.match(/⬥ ok/g) || []).length).toBe(2);
457
+ expect((sourceText.match(/ok/g) || []).length).toBe(2);
439
458
  const worktreeText = await worktreeTh.text();
440
459
  expect(normalizeWorktreeLifecycleText(worktreeText)).toMatchInlineSnapshot(`
441
460
  "--- from: assistant (TestBot)
@@ -446,14 +465,14 @@ describe('worktree lifecycle', () => {
446
465
  --- from: user (worktree-tester)
447
466
  Reply with exactly: after-worktree-thread
448
467
  --- from: assistant (TestBot)
449
- ⬥ ok
450
- *WORKTREE_NAME ⋅ opencode/kimaki-WORKTREE_NAME ⋅ Ns ⋅ N% ⋅ deterministic-v2*"
468
+ > ok
469
+ > *WORKTREE_NAME ⋅ opencode/kimaki-WORKTREE_NAME ⋅ <1s ⋅ 0% ⋅ source-model-v2* <@200000000000000901>"
451
470
  `);
452
471
  expect(worktreeText).toContain('Worktree:');
453
472
  expect(worktreeText).toContain('Branch:');
454
473
  expect(worktreeText).toContain('Reusing context from');
455
474
  expect(worktreeText).toContain('Reply with exactly: after-worktree-thread');
456
- expect(worktreeText).toContain('⬥ ok');
475
+ expect(worktreeText).toContain('ok');
457
476
  }, 30_000);
458
477
  test('/new-worktree from a text channel creates a worktree thread that responds to messages', async () => {
459
478
  // 1. Run /new-worktree from the text channel (not inside a thread)
@@ -497,7 +516,7 @@ describe('worktree lifecycle', () => {
497
516
  discord,
498
517
  threadId: worktreeThread.id,
499
518
  userId: TEST_USER_ID,
500
- text: '⬥ ok',
519
+ text: 'ok',
501
520
  afterUserMessageIncludes: 'channel-worktree-msg',
502
521
  timeout: 10_000,
503
522
  });
@@ -525,11 +544,11 @@ describe('worktree lifecycle', () => {
525
544
  --- from: user (worktree-tester)
526
545
  Reply with exactly: channel-worktree-msg
527
546
  --- from: assistant (TestBot)
528
- *using deterministic-provider/deterministic-v2*
529
- ⬥ ok"
547
+ > *using deterministic-provider/deterministic-v2*
548
+ > ok"
530
549
  `);
531
550
  expect(worktreeText).toContain('Branch:');
532
- expect(worktreeText).toContain('⬥ ok');
551
+ expect(worktreeText).toContain('ok');
533
552
  expect(worktreeText).toContain('Reply with exactly: channel-worktree-msg');
534
553
  }, 30_000);
535
554
  test('auto-worktree from user message creates worktree thread and responds', async () => {
@@ -556,7 +575,7 @@ describe('worktree lifecycle', () => {
556
575
  discord,
557
576
  threadId: thread.id,
558
577
  userId: TEST_USER_ID,
559
- text: '⬥ ok',
578
+ text: 'ok',
560
579
  afterUserMessageIncludes: AUTO_WORKTREE_SUFFIX,
561
580
  timeout: 25_000,
562
581
  });
@@ -577,16 +596,16 @@ describe('worktree lifecycle', () => {
577
596
  discord,
578
597
  threadId: thread.id,
579
598
  userId: TEST_USER_ID,
580
- text: '⬥ ok',
599
+ text: 'ok',
581
600
  afterUserMessageIncludes: 'auto-followup',
582
601
  timeout: 4_000,
583
602
  });
584
603
  const text = await th.text();
585
- expect(text).toContain('⬥ ok');
604
+ expect(text).toContain('ok');
586
605
  expect(text).toContain(AUTO_WORKTREE_SUFFIX);
587
606
  expect(text).toContain('Reply with exactly: auto-followup');
588
607
  // Should have at least 2 ok replies
589
- expect((text.match(/⬥ ok/g) || []).length).toBeGreaterThanOrEqual(2);
608
+ expect((text.match(/ok/g) || []).length).toBeGreaterThanOrEqual(2);
590
609
  }, 35_000);
591
610
  test('auto-worktrees fall back to normal sessions outside git repositories', async () => {
592
611
  await discord.channel(NON_GIT_CHANNEL_ID).user(TEST_USER_ID).sendMessage({
@@ -603,7 +622,7 @@ describe('worktree lifecycle', () => {
603
622
  discord,
604
623
  threadId: thread.id,
605
624
  userId: TEST_USER_ID,
606
- text: '⬥ ok',
625
+ text: 'ok',
607
626
  afterUserMessageIncludes: 'non-git-first',
608
627
  timeout: 4_000,
609
628
  });
@@ -614,7 +633,7 @@ describe('worktree lifecycle', () => {
614
633
  discord,
615
634
  threadId: thread.id,
616
635
  userId: TEST_USER_ID,
617
- text: '⬥ ok',
636
+ text: 'ok',
618
637
  afterUserMessageIncludes: 'non-git-second',
619
638
  timeout: 4_000,
620
639
  });
@@ -632,18 +651,18 @@ describe('worktree lifecycle', () => {
632
651
  "--- from: user (worktree-tester)
633
652
  Reply with exactly: non-git-first
634
653
  --- from: assistant (TestBot)
635
- *using deterministic-provider/deterministic-v2*
636
- ⬥ ok
654
+ > *using deterministic-provider/deterministic-v2*
655
+ > ok
637
656
  --- from: user (worktree-tester)
638
657
  Reply with exactly: non-git-second
639
658
  --- from: assistant (TestBot)
640
- *non-git-project ⋅ main ⋅ Ns ⋅ N% ⋅ deterministic-v2*
641
- ⬥ ok"
659
+ > *non-git-project ⋅ main ⋅ <1s ⋅ 0% ⋅ deterministic-v2* <@200000000000000901>
660
+ > ok"
642
661
  `);
643
662
  expect(text).toContain('Reply with exactly: non-git-first');
644
663
  expect(text).toContain('Reply with exactly: non-git-second');
645
664
  expect(text).not.toContain('Worktree creation failed');
646
- const okCount = (text.match(/⬥ ok/g) || []).length;
665
+ const okCount = (text.match(/ok/g) || []).length;
647
666
  expect(okCount).toBe(2);
648
667
  }, 20_000);
649
668
  test('kimaki send --channel auto-creates worktree when channel toggle is enabled', async () => {
@@ -687,7 +706,7 @@ describe('worktree lifecycle', () => {
687
706
  discord,
688
707
  threadId: threadData.id,
689
708
  userId: discord.botUserId,
690
- text: '⬥ ok',
709
+ text: 'ok',
691
710
  timeout: 10_000,
692
711
  });
693
712
  // Snapshot the thread content
@@ -700,8 +719,8 @@ describe('worktree lifecycle', () => {
700
719
  🌳 **Worktree: AUTO_WORKTREE_BRANCH**
701
720
  📁 \`/tmp/worktrees/WORKTREE_NAME\`
702
721
  🌿 Branch: \`AUTO_WORKTREE_BRANCH\`
703
- *using deterministic-provider/deterministic-v2*
704
- ⬥ ok"
722
+ > *using deterministic-provider/deterministic-v2*
723
+ > ok"
705
724
  `);
706
725
  // Verify DB has worktree info
707
726
  const worktreeInfo = await getThreadWorktreeOrWorkspace(threadData.id);