kimaki 0.28.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-model.e2e.test.js +33 -33
- package/dist/anthropic-account-identity.js +1 -1
- package/dist/anthropic-auth-plugin.js +5 -5
- package/dist/anthropic-auth-plugin.test.js +30 -2
- package/dist/anthropic-auth-state.js +1 -1
- package/dist/bash-tool-schema-plugin.js +18 -0
- package/dist/bash-tool-schema-plugin.test.js +20 -1
- package/dist/bin.js +7 -3
- package/dist/bot-lifecycle.test.js +206 -0
- package/dist/cache-drift-plugin.js +25 -18
- package/dist/cache-rewrite.js +39 -0
- package/dist/cache-rewrite.test.js +41 -0
- package/dist/channel-management.js +113 -51
- package/dist/cli-commands/misc.js +4 -1
- package/dist/cli-commands/project.js +7 -4
- package/dist/cli-commands/session.js +118 -36
- package/dist/cli-commands/thread.js +63 -0
- package/dist/cli-parsing.test.js +3 -3
- package/dist/cli-runner.js +11 -1
- package/dist/cli-send-thread.e2e.test.js +2 -2
- package/dist/cli.js +6 -4
- package/dist/commands/ask-question.js +72 -23
- package/dist/commands/queue.js +84 -36
- package/dist/commands/queue.test.js +15 -0
- package/dist/commands/restart-opencode-server.js +7 -1
- package/dist/commands/session-id.js +5 -5
- package/dist/database.js +149 -6
- package/dist/db.js +34 -0
- package/dist/db.test.js +199 -1
- package/dist/default-channel-provisioning.test.js +2 -1
- package/dist/discord-bot.js +220 -146
- package/dist/discord-command-registration.js +1 -1
- package/dist/external-directory-permissions.e2e.test.js +3 -3
- package/dist/external-directory-project-deny.e2e.test.js +1 -1
- package/dist/forum-sync/watchers.js +15 -0
- package/dist/gateway-proxy.e2e.test.js +9 -9
- package/dist/guild-categories.test.js +225 -0
- package/dist/hrana-server.js +68 -14
- package/dist/interaction-handler.js +5 -1
- package/dist/kimaki-opencode-plugin.js +2 -0
- package/dist/kimaki-opencode-plugin.test.js +28 -0
- package/dist/list-channel-threads.js +163 -0
- package/dist/list-channel-threads.test.js +80 -0
- package/dist/markdown.js +164 -102
- package/dist/markdown.test.js +88 -20
- package/dist/message-formatting.js +29 -18
- package/dist/message-formatting.test.js +111 -3
- package/dist/opencode.js +27 -12
- package/dist/question-abort-clears-dropdown.e2e.test.js +1 -1
- package/dist/question-abort-resume.e2e.test.js +100 -0
- package/dist/question-abort-retry-text-before-dropdown.e2e.test.js +1 -1
- package/dist/question-text-before-dropdown.e2e.test.js +1 -1
- package/dist/queue-advanced-abort.e2e.test.js +3 -3
- package/dist/queue-advanced-action-buttons.e2e.test.js +5 -5
- package/dist/queue-advanced-e2e-setup.js +63 -0
- package/dist/queue-advanced-footer.e2e.test.js +18 -18
- package/dist/queue-advanced-model-switch.e2e.test.js +3 -4
- package/dist/queue-advanced-permissions-typing.e2e.test.js +2 -2
- package/dist/queue-advanced-typing-interrupt.e2e.test.js +3 -3
- package/dist/queue-delete-message.e2e.test.js +4 -4
- package/dist/queue-drain-after-interactive-ui.e2e.test.js +3 -3
- package/dist/queue-interrupt-drain.e2e.test.js +10 -10
- package/dist/queue-question-select-drain.e2e.test.js +5 -5
- package/dist/runtime-lifecycle.e2e.test.js +95 -11
- package/dist/schema.js +21 -0
- package/dist/session-handler/event-stream-state.js +240 -6
- package/dist/session-handler/event-stream-state.test.js +1116 -130
- package/dist/session-handler/thread-runtime-state.js +4 -0
- package/dist/session-handler/thread-session-runtime.js +499 -89
- package/dist/sleep.e2e.test.js +7 -7
- package/dist/store.js +1 -1
- package/dist/system-message.js +64 -23
- package/dist/system-message.test.js +69 -23
- package/dist/task-id-plugin.js +16 -0
- package/dist/task-runner.js +7 -0
- package/dist/task-schedule.test.js +1 -1
- package/dist/test-utils.js +5 -3
- package/dist/thread-message-queue.e2e.test.js +30 -31
- package/dist/undo-redo.e2e.test.js +3 -3
- package/dist/voice-message.e2e.test.js +64 -26
- package/dist/voice-routing-input.e2e.test.js +4 -4
- package/dist/voice-routing-question.e2e.test.js +4 -4
- package/dist/voice.js +107 -21
- package/dist/voice.test.js +52 -1
- package/dist/wait-session.js +24 -2
- package/dist/worktree-lifecycle.e2e.test.js +8 -8
- package/package.json +7 -7
- package/skills/egaki/SKILL.md +14 -0
- package/skills/holocron/SKILL.md +125 -42
- package/skills/opensrc/SKILL.md +20 -3
- package/skills/spiceflow/SKILL.md +53 -172
- package/skills/strada/SKILL.md +61 -232
- package/src/agent-model.e2e.test.ts +33 -33
- package/src/anthropic-account-identity.ts +1 -1
- package/src/anthropic-auth-plugin.test.ts +37 -2
- package/src/anthropic-auth-plugin.ts +9 -7
- package/src/anthropic-auth-state.ts +1 -0
- package/src/bash-tool-schema-plugin.test.ts +29 -0
- package/src/bash-tool-schema-plugin.ts +31 -0
- package/src/bin.ts +7 -3
- package/src/bot-lifecycle.test.ts +252 -0
- package/src/cache-drift-plugin.ts +34 -24
- package/src/cache-rewrite.test.ts +49 -0
- package/src/cache-rewrite.ts +96 -0
- package/src/channel-management.ts +144 -65
- package/src/cli-commands/misc.ts +4 -1
- package/src/cli-commands/project.ts +9 -4
- package/src/cli-commands/session.ts +167 -38
- package/src/cli-commands/thread.ts +86 -0
- package/src/cli-parsing.test.ts +3 -3
- package/src/cli-runner.ts +11 -0
- package/src/cli-send-thread.e2e.test.ts +2 -2
- package/src/cli.ts +8 -6
- package/src/commands/ask-question.ts +88 -25
- package/src/commands/queue.test.ts +19 -0
- package/src/commands/queue.ts +111 -45
- package/src/commands/restart-opencode-server.ts +12 -1
- package/src/commands/session-id.ts +5 -5
- package/src/database.ts +219 -6
- package/src/db.test.ts +236 -0
- package/src/db.ts +38 -0
- package/src/default-channel-provisioning.test.ts +2 -1
- package/src/discord-bot.ts +272 -185
- package/src/discord-command-registration.ts +3 -1
- package/src/external-directory-permissions.e2e.test.ts +3 -3
- package/src/external-directory-project-deny.e2e.test.ts +1 -1
- package/src/forum-sync/watchers.ts +20 -0
- package/src/gateway-proxy.e2e.test.ts +9 -9
- package/src/guild-categories.test.ts +260 -0
- package/src/hrana-server.ts +96 -16
- package/src/interaction-handler.ts +7 -0
- package/src/kimaki-opencode-plugin.test.ts +34 -0
- package/src/kimaki-opencode-plugin.ts +2 -0
- package/src/list-channel-threads.test.ts +90 -0
- package/src/list-channel-threads.ts +252 -0
- package/src/markdown.test.ts +108 -22
- package/src/markdown.ts +216 -103
- package/src/message-formatting.test.ts +129 -2
- package/src/message-formatting.ts +28 -14
- package/src/opencode.ts +28 -13
- package/src/question-abort-clears-dropdown.e2e.test.ts +1 -1
- package/src/question-abort-resume.e2e.test.ts +121 -0
- package/src/question-abort-retry-text-before-dropdown.e2e.test.ts +1 -1
- package/src/question-text-before-dropdown.e2e.test.ts +1 -1
- package/src/queue-advanced-abort.e2e.test.ts +3 -3
- package/src/queue-advanced-action-buttons.e2e.test.ts +5 -5
- package/src/queue-advanced-e2e-setup.ts +65 -0
- package/src/queue-advanced-footer.e2e.test.ts +18 -18
- package/src/queue-advanced-model-switch.e2e.test.ts +3 -4
- package/src/queue-advanced-permissions-typing.e2e.test.ts +2 -2
- package/src/queue-advanced-typing-interrupt.e2e.test.ts +3 -3
- package/src/queue-delete-message.e2e.test.ts +4 -4
- package/src/queue-drain-after-interactive-ui.e2e.test.ts +3 -3
- package/src/queue-interrupt-drain.e2e.test.ts +10 -10
- package/src/queue-question-select-drain.e2e.test.ts +5 -5
- package/src/runtime-lifecycle.e2e.test.ts +104 -10
- package/src/schema.sql +16 -0
- package/src/schema.ts +23 -0
- package/src/session-handler/event-stream-state.test.ts +1184 -133
- package/src/session-handler/event-stream-state.ts +322 -8
- package/src/session-handler/thread-runtime-state.ts +5 -0
- package/src/session-handler/thread-session-runtime.ts +597 -95
- package/src/sleep.e2e.test.ts +7 -7
- package/src/store.ts +2 -2
- package/src/system-message.test.ts +70 -23
- package/src/system-message.ts +67 -22
- package/src/task-id-plugin.ts +17 -0
- package/src/task-runner.ts +8 -0
- package/src/task-schedule.test.ts +1 -1
- package/src/test-utils.ts +5 -3
- package/src/thread-message-queue.e2e.test.ts +30 -31
- package/src/undo-redo.e2e.test.ts +3 -3
- package/src/voice-message.e2e.test.ts +70 -26
- package/src/voice-routing-input.e2e.test.ts +4 -4
- package/src/voice-routing-question.e2e.test.ts +4 -4
- package/src/voice.test.ts +56 -0
- package/src/voice.ts +135 -25
- package/src/wait-session.ts +25 -2
- package/src/worktree-lifecycle.e2e.test.ts +8 -8
package/src/voice.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Audio transcription service using AI SDK providers.
|
|
2
2
|
// Both providers use LanguageModelV3 (chat model) with audio file parts + tool calling,
|
|
3
3
|
// so we can pass full context (file tree, session info) for better word recognition.
|
|
4
|
-
// - OpenAI:
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// - Gemini: gemini-
|
|
4
|
+
// - OpenAI: plain fetch to the Chat Completions API. The AI SDK chat schema
|
|
5
|
+
// rejects message.audio, so we parse transcript and tool_calls ourselves.
|
|
6
|
+
// https://github.com/vercel/ai/issues/21289
|
|
7
|
+
// - Gemini: gemini-flash-latest natively accepts audio file parts in chat.
|
|
8
8
|
// Calls model.doGenerate() directly without the `ai` npm package.
|
|
9
9
|
// Uses errore for type-safe error handling.
|
|
10
10
|
|
|
@@ -35,7 +35,78 @@ import {
|
|
|
35
35
|
|
|
36
36
|
const voiceLogger = createLogger(LogPrefix.VOICE)
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
const OPENAI_AUDIO_CHAT_MODEL = 'gpt-audio-1.5'
|
|
39
|
+
// https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create
|
|
40
|
+
const OPENAI_CHAT_COMPLETIONS_URL = 'https://api.openai.com/v1/chat/completions'
|
|
41
|
+
|
|
42
|
+
export async function requestOpenAIAudioTranscription({
|
|
43
|
+
apiKey,
|
|
44
|
+
prompt,
|
|
45
|
+
audioBase64,
|
|
46
|
+
mediaType,
|
|
47
|
+
temperature,
|
|
48
|
+
tool,
|
|
49
|
+
}: {
|
|
50
|
+
apiKey: string
|
|
51
|
+
prompt: string
|
|
52
|
+
audioBase64: string
|
|
53
|
+
mediaType: string
|
|
54
|
+
temperature: number
|
|
55
|
+
tool: LanguageModelV3FunctionTool
|
|
56
|
+
}): Promise<TranscriptionLoopError | TranscriptionResult> {
|
|
57
|
+
const audioFormat = mediaType.includes('wav') ? 'wav' : 'mp3'
|
|
58
|
+
const response = await fetch(OPENAI_CHAT_COMPLETIONS_URL, {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: {
|
|
61
|
+
Authorization: `Bearer ${apiKey}`,
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
},
|
|
64
|
+
body: JSON.stringify({
|
|
65
|
+
model: OPENAI_AUDIO_CHAT_MODEL,
|
|
66
|
+
temperature,
|
|
67
|
+
max_completion_tokens: 2048,
|
|
68
|
+
user: 'kimaki:voice-transcription',
|
|
69
|
+
safety_identifier: 'kimaki:voice-transcription',
|
|
70
|
+
tools: [
|
|
71
|
+
{
|
|
72
|
+
type: 'function',
|
|
73
|
+
function: {
|
|
74
|
+
name: tool.name,
|
|
75
|
+
description: tool.description,
|
|
76
|
+
parameters: tool.inputSchema,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
tool_choice: { type: 'function', function: { name: 'transcriptionResult' } },
|
|
81
|
+
messages: [
|
|
82
|
+
{
|
|
83
|
+
role: 'user',
|
|
84
|
+
content: [
|
|
85
|
+
{ type: 'text', text: prompt },
|
|
86
|
+
{
|
|
87
|
+
type: 'input_audio',
|
|
88
|
+
input_audio: { data: audioBase64, format: audioFormat },
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
}),
|
|
94
|
+
}).catch(
|
|
95
|
+
(cause) =>
|
|
96
|
+
new TranscriptionError({
|
|
97
|
+
reason: `API call failed: ${String(cause)}`,
|
|
98
|
+
cause,
|
|
99
|
+
}),
|
|
100
|
+
)
|
|
101
|
+
if (response instanceof Error) return response
|
|
102
|
+
const raw = await response.text()
|
|
103
|
+
if (!response.ok) {
|
|
104
|
+
return new TranscriptionError({ reason: `API call failed: ${response.status} ${raw.slice(0, 300)}` })
|
|
105
|
+
}
|
|
106
|
+
return parseOpenAIAudioChatResponse(raw)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// OpenAI input_audio supports only wav and mp3. Other formats (OGG Opus, etc)
|
|
39
110
|
// must be converted before sending.
|
|
40
111
|
const OPENAI_SUPPORTED_AUDIO_TYPES = new Set([
|
|
41
112
|
'audio/mpeg',
|
|
@@ -438,6 +509,45 @@ async function runTranscriptionOnce({
|
|
|
438
509
|
return extractTranscription(response.content)
|
|
439
510
|
}
|
|
440
511
|
|
|
512
|
+
type OpenAIAudioChatMessage = {
|
|
513
|
+
content?: string | null
|
|
514
|
+
audio?: { transcript?: string | null } | null
|
|
515
|
+
tool_calls?: Array<{
|
|
516
|
+
id?: string
|
|
517
|
+
function?: { name?: string; arguments?: string }
|
|
518
|
+
}> | null
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Response shape: https://developers.openai.com/api/docs/guides/audio-chat-completions
|
|
522
|
+
export function parseOpenAIAudioChatResponse(
|
|
523
|
+
body: string,
|
|
524
|
+
): TranscriptionLoopError | TranscriptionResult {
|
|
525
|
+
let parsed: { choices?: Array<{ message?: OpenAIAudioChatMessage }> }
|
|
526
|
+
try {
|
|
527
|
+
parsed = JSON.parse(body) as { choices?: Array<{ message?: OpenAIAudioChatMessage }> }
|
|
528
|
+
} catch (cause) {
|
|
529
|
+
return new TranscriptionError({ reason: 'Invalid JSON response', cause })
|
|
530
|
+
}
|
|
531
|
+
const message = parsed.choices?.[0]?.message
|
|
532
|
+
if (!message) return new NoResponseContentError()
|
|
533
|
+
const toolCall = message.tool_calls?.find((call) => {
|
|
534
|
+
return call.function?.name === 'transcriptionResult'
|
|
535
|
+
})
|
|
536
|
+
if (toolCall?.function?.arguments) {
|
|
537
|
+
return extractTranscription([
|
|
538
|
+
{
|
|
539
|
+
type: 'tool-call',
|
|
540
|
+
toolCallId: toolCall.id || 'transcriptionResult',
|
|
541
|
+
toolName: 'transcriptionResult',
|
|
542
|
+
input: toolCall.function.arguments,
|
|
543
|
+
},
|
|
544
|
+
])
|
|
545
|
+
}
|
|
546
|
+
const transcript = message.audio?.transcript?.trim() || message.content?.trim() || ''
|
|
547
|
+
if (!transcript) return new NoResponseContentError()
|
|
548
|
+
return { transcription: transcript, queueMessage: false }
|
|
549
|
+
}
|
|
550
|
+
|
|
441
551
|
export type TranscribeAudioErrors =
|
|
442
552
|
| ApiKeyMissingError
|
|
443
553
|
| InvalidAudioFormatError
|
|
@@ -446,32 +556,17 @@ export type TranscribeAudioErrors =
|
|
|
446
556
|
export type TranscriptionProvider = 'openai' | 'gemini'
|
|
447
557
|
|
|
448
558
|
/**
|
|
449
|
-
* Create
|
|
450
|
-
*
|
|
451
|
-
* context (prompt, session info, tool calling) for better word recognition.
|
|
452
|
-
*
|
|
453
|
-
* OpenAI: must use .chat() to get the Chat Completions API model, because the
|
|
454
|
-
* default callable (Responses API) doesn't support audio file parts. Use the
|
|
455
|
-
* GA audio model instead of older gpt-4o audio preview snapshots.
|
|
456
|
-
* Gemini: language models natively accept audio in chat.
|
|
559
|
+
* Create the Gemini chat model for transcription.
|
|
560
|
+
* OpenAI does not use this. Its chat schema rejects message.audio.
|
|
457
561
|
*/
|
|
458
562
|
export function createTranscriptionModel({
|
|
459
563
|
apiKey,
|
|
460
|
-
provider,
|
|
461
564
|
}: {
|
|
462
565
|
apiKey: string
|
|
463
566
|
provider?: TranscriptionProvider
|
|
464
567
|
}): LanguageModelV3 {
|
|
465
|
-
const resolvedProvider: TranscriptionProvider =
|
|
466
|
-
provider || (apiKey.startsWith('sk-') ? 'openai' : 'gemini')
|
|
467
|
-
|
|
468
|
-
if (resolvedProvider === 'openai') {
|
|
469
|
-
const openai = createOpenAI({ apiKey })
|
|
470
|
-
return openai.chat('gpt-audio')
|
|
471
|
-
}
|
|
472
|
-
|
|
473
568
|
const google = createGoogleGenerativeAI({ apiKey })
|
|
474
|
-
return google('gemini-
|
|
569
|
+
return google('gemini-flash-latest')
|
|
475
570
|
}
|
|
476
571
|
|
|
477
572
|
export async function transcribeAudio({
|
|
@@ -520,7 +615,7 @@ export async function transcribeAudio({
|
|
|
520
615
|
return 'gemini'
|
|
521
616
|
})()
|
|
522
617
|
|
|
523
|
-
const languageModel
|
|
618
|
+
const languageModel =
|
|
524
619
|
model || createTranscriptionModel({ apiKey: apiKey!, provider: resolvedProvider })
|
|
525
620
|
|
|
526
621
|
// Convert audio to Buffer for potential format conversion
|
|
@@ -653,6 +748,21 @@ Note: "critique" is a CLI tool for showing diffs in the browser.`
|
|
|
653
748
|
const agentNames = agents
|
|
654
749
|
?.map((a) => { return a.name })
|
|
655
750
|
.filter((name) => { return name.length > 0 })
|
|
751
|
+
const resolvedAgentNames = agentNames && agentNames.length > 0 ? agentNames : undefined
|
|
752
|
+
|
|
753
|
+
if (resolvedProvider === 'openai') {
|
|
754
|
+
return requestOpenAIAudioTranscription({
|
|
755
|
+
apiKey: apiKey!,
|
|
756
|
+
prompt: transcriptionPrompt,
|
|
757
|
+
audioBase64: finalAudioBase64,
|
|
758
|
+
mediaType,
|
|
759
|
+
temperature: temperature ?? 0.3,
|
|
760
|
+
tool: buildTranscriptionTool({
|
|
761
|
+
agentNames: resolvedAgentNames,
|
|
762
|
+
canForkSession,
|
|
763
|
+
}),
|
|
764
|
+
})
|
|
765
|
+
}
|
|
656
766
|
|
|
657
767
|
return runTranscriptionOnce({
|
|
658
768
|
model: languageModel,
|
|
@@ -660,7 +770,7 @@ Note: "critique" is a CLI tool for showing diffs in the browser.`
|
|
|
660
770
|
audioBase64: finalAudioBase64,
|
|
661
771
|
mediaType,
|
|
662
772
|
temperature: temperature ?? 0.3,
|
|
663
|
-
agentNames:
|
|
773
|
+
agentNames: resolvedAgentNames,
|
|
664
774
|
canForkSession,
|
|
665
775
|
provider: resolvedProvider,
|
|
666
776
|
})
|
package/src/wait-session.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Wait utilities for polling session completion.
|
|
2
2
|
// Used by `kimaki send --wait` and `kimaki session wait` to block until a
|
|
3
|
-
// session
|
|
3
|
+
// session completes (idle, latest turn finished naturally, no pending
|
|
4
|
+
// permission) OR pauses for a user question. A session parked on a `question`
|
|
5
|
+
// tool never completes on its own, so it is treated as done for automation.
|
|
4
6
|
|
|
5
7
|
import type { Message as OpenCodeMessage } from '@opencode-ai/sdk/v2'
|
|
6
8
|
import { getSessionEventSnapshot, getThreadSession } from './database.js'
|
|
@@ -49,7 +51,9 @@ export async function waitForSessionId({
|
|
|
49
51
|
|
|
50
52
|
/**
|
|
51
53
|
* Poll the OpenCode SDK and persisted Kimaki events until the session is idle,
|
|
52
|
-
* its latest user turn completed naturally, and no
|
|
54
|
+
* its latest user turn completed naturally, and no permission prompt is pending
|
|
55
|
+
* -- or until the session pauses on a user question (which never completes on
|
|
56
|
+
* its own and is treated as done for automation).
|
|
53
57
|
*/
|
|
54
58
|
export async function waitForSessionComplete({
|
|
55
59
|
projectDirectory,
|
|
@@ -84,6 +88,25 @@ export async function waitForSessionComplete({
|
|
|
84
88
|
throw new Error('Failed to check session status')
|
|
85
89
|
}
|
|
86
90
|
const sessionStatus = statusResponse.data?.[sessionId]
|
|
91
|
+
const isBusy = Boolean(sessionStatus && sessionStatus.type !== 'idle')
|
|
92
|
+
|
|
93
|
+
// A session parked on a `question` tool reports busy but will never complete
|
|
94
|
+
// on its own, so treat a live question as done for automation and stop
|
|
95
|
+
// waiting. Guard on `busy`: an orphaned question left after an abort
|
|
96
|
+
// (session idle) must fall through to the normal idle/completion checks
|
|
97
|
+
// instead of returning early.
|
|
98
|
+
if (isBusy) {
|
|
99
|
+
const questionsResponse = await getClient().question
|
|
100
|
+
.list({ directory: projectDirectory })
|
|
101
|
+
.catch(() => null)
|
|
102
|
+
const hasPendingQuestion = (questionsResponse?.data || []).some((request) => {
|
|
103
|
+
return request.sessionID === sessionId
|
|
104
|
+
})
|
|
105
|
+
if (hasPendingQuestion) {
|
|
106
|
+
waitLogger.log(`Session ${sessionId} is showing a user question; treating as complete`)
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
}
|
|
87
110
|
|
|
88
111
|
const messagesResponse = await getClient().session.messages({
|
|
89
112
|
sessionID: sessionId,
|
|
@@ -545,15 +545,15 @@ describe('worktree lifecycle', () => {
|
|
|
545
545
|
"--- from: user (worktree-tester)
|
|
546
546
|
Reply with exactly: before-worktree
|
|
547
547
|
--- from: assistant (TestBot)
|
|
548
|
-
|
|
548
|
+
-# *using deterministic-provider/deterministic-v2*
|
|
549
549
|
> ok
|
|
550
550
|
Creating worktree in <#THREAD_ID>
|
|
551
|
-
|
|
551
|
+
-# *project ⋅ main ⋅ Ns ⋅ N% ⋅ deterministic-v2*
|
|
552
552
|
--- from: user (worktree-tester)
|
|
553
553
|
Reply with exactly: after-source-thread
|
|
554
554
|
--- from: assistant (TestBot)
|
|
555
555
|
> ok
|
|
556
|
-
|
|
556
|
+
-# *project ⋅ main ⋅ Ns ⋅ N% ⋅ source-model-v2*"
|
|
557
557
|
`)
|
|
558
558
|
expect(sourceText).toContain('Reply with exactly: before-worktree')
|
|
559
559
|
expect(sourceText).toContain('Reply with exactly: after-source-thread')
|
|
@@ -571,7 +571,7 @@ describe('worktree lifecycle', () => {
|
|
|
571
571
|
Reply with exactly: after-worktree-thread
|
|
572
572
|
--- from: assistant (TestBot)
|
|
573
573
|
> ok
|
|
574
|
-
|
|
574
|
+
-# *WORKTREE_NAME ⋅ opencode/kimaki-WORKTREE_NAME ⋅ Ns ⋅ N% ⋅ source-model-v2*"
|
|
575
575
|
`)
|
|
576
576
|
expect(worktreeText).toContain('Worktree:')
|
|
577
577
|
expect(worktreeText).toContain('Branch:')
|
|
@@ -666,7 +666,7 @@ describe('worktree lifecycle', () => {
|
|
|
666
666
|
--- from: user (worktree-tester)
|
|
667
667
|
Reply with exactly: channel-worktree-msg
|
|
668
668
|
--- from: assistant (TestBot)
|
|
669
|
-
|
|
669
|
+
-# *using deterministic-provider/deterministic-v2*
|
|
670
670
|
> ok"
|
|
671
671
|
`)
|
|
672
672
|
expect(worktreeText).toContain('Branch:')
|
|
@@ -797,12 +797,12 @@ describe('worktree lifecycle', () => {
|
|
|
797
797
|
"--- from: user (worktree-tester)
|
|
798
798
|
Reply with exactly: non-git-first
|
|
799
799
|
--- from: assistant (TestBot)
|
|
800
|
-
|
|
800
|
+
-# *using deterministic-provider/deterministic-v2*
|
|
801
801
|
> ok
|
|
802
802
|
--- from: user (worktree-tester)
|
|
803
803
|
Reply with exactly: non-git-second
|
|
804
804
|
--- from: assistant (TestBot)
|
|
805
|
-
|
|
805
|
+
-# *non-git-project ⋅ main ⋅ Ns ⋅ N% ⋅ deterministic-v2*
|
|
806
806
|
> ok"
|
|
807
807
|
`)
|
|
808
808
|
expect(text).toContain('Reply with exactly: non-git-first')
|
|
@@ -880,7 +880,7 @@ describe('worktree lifecycle', () => {
|
|
|
880
880
|
🌳 **Worktree: AUTO_WORKTREE_BRANCH**
|
|
881
881
|
📁 \`/tmp/worktrees/WORKTREE_NAME\`
|
|
882
882
|
🌿 Branch: \`AUTO_WORKTREE_BRANCH\`
|
|
883
|
-
|
|
883
|
+
-# *using deterministic-provider/deterministic-v2*
|
|
884
884
|
> ok"
|
|
885
885
|
`)
|
|
886
886
|
|