kimaki 0.4.39 → 0.4.40
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/cli.js +19 -21
- package/dist/commands/abort.js +1 -1
- package/dist/commands/add-project.js +2 -2
- package/dist/commands/agent.js +2 -2
- package/dist/commands/fork.js +2 -2
- package/dist/commands/model.js +2 -2
- package/dist/commands/remove-project.js +2 -2
- package/dist/commands/resume.js +2 -2
- package/dist/commands/session.js +4 -4
- package/dist/commands/share.js +1 -1
- package/dist/commands/undo-redo.js +2 -2
- package/dist/commands/worktree.js +180 -0
- package/dist/database.js +49 -1
- package/dist/discord-bot.js +29 -4
- package/dist/discord-utils.js +36 -0
- package/dist/errors.js +86 -87
- package/dist/genai-worker.js +1 -1
- package/dist/interaction-handler.js +6 -2
- package/dist/markdown.js +5 -1
- package/dist/message-formatting.js +2 -2
- package/dist/opencode.js +4 -4
- package/dist/session-handler.js +2 -2
- package/dist/tools.js +3 -3
- package/dist/voice-handler.js +3 -3
- package/dist/voice.js +4 -4
- package/package.json +4 -3
- package/src/cli.ts +20 -30
- package/src/commands/abort.ts +1 -1
- package/src/commands/add-project.ts +2 -2
- package/src/commands/agent.ts +2 -2
- package/src/commands/fork.ts +2 -2
- package/src/commands/model.ts +2 -2
- package/src/commands/remove-project.ts +2 -2
- package/src/commands/resume.ts +2 -2
- package/src/commands/session.ts +4 -4
- package/src/commands/share.ts +1 -1
- package/src/commands/undo-redo.ts +2 -2
- package/src/commands/worktree.ts +243 -0
- package/src/database.ts +96 -1
- package/src/discord-bot.ts +30 -4
- package/src/discord-utils.ts +50 -0
- package/src/errors.ts +90 -160
- package/src/genai-worker.ts +1 -1
- package/src/interaction-handler.ts +7 -2
- package/src/markdown.ts +5 -4
- package/src/message-formatting.ts +2 -2
- package/src/opencode.ts +4 -4
- package/src/session-handler.ts +2 -2
- package/src/tools.ts +3 -3
- package/src/voice-handler.ts +3 -3
- package/src/voice.ts +4 -4
package/src/errors.ts
CHANGED
|
@@ -2,190 +2,117 @@
|
|
|
2
2
|
// Errors are grouped by category: infrastructure, domain, and validation.
|
|
3
3
|
// Use errore.matchError() for exhaustive error handling in command handlers.
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import { createTaggedError } from 'errore'
|
|
6
6
|
|
|
7
7
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
8
8
|
// INFRASTRUCTURE ERRORS - Server, filesystem, external services
|
|
9
9
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
10
10
|
|
|
11
|
-
export class DirectoryNotAccessibleError extends
|
|
12
|
-
|
|
13
|
-
message:
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
message:
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
super({ ...args, message: `OpenCode server not found for directory: ${args.directory}` })
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export class ServerNotReadyError extends errore.TaggedError('ServerNotReadyError')<{
|
|
40
|
-
directory: string
|
|
41
|
-
message: string
|
|
42
|
-
}>() {
|
|
43
|
-
constructor(args: { directory: string }) {
|
|
44
|
-
super({
|
|
45
|
-
...args,
|
|
46
|
-
message: `OpenCode server for directory "${args.directory}" is in an error state (no client available)`,
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export class ApiKeyMissingError extends errore.TaggedError('ApiKeyMissingError')<{
|
|
52
|
-
service: string
|
|
53
|
-
message: string
|
|
54
|
-
}>() {
|
|
55
|
-
constructor(args: { service: string }) {
|
|
56
|
-
super({ ...args, message: `${args.service} API key is required` })
|
|
57
|
-
}
|
|
58
|
-
}
|
|
11
|
+
export class DirectoryNotAccessibleError extends createTaggedError({
|
|
12
|
+
name: 'DirectoryNotAccessibleError',
|
|
13
|
+
message: 'Directory does not exist or is not accessible: $directory',
|
|
14
|
+
}) {}
|
|
15
|
+
|
|
16
|
+
export class ServerStartError extends createTaggedError({
|
|
17
|
+
name: 'ServerStartError',
|
|
18
|
+
message: 'Server failed to start on port $port: $reason',
|
|
19
|
+
}) {}
|
|
20
|
+
|
|
21
|
+
export class ServerNotFoundError extends createTaggedError({
|
|
22
|
+
name: 'ServerNotFoundError',
|
|
23
|
+
message: 'OpenCode server not found for directory: $directory',
|
|
24
|
+
}) {}
|
|
25
|
+
|
|
26
|
+
export class ServerNotReadyError extends createTaggedError({
|
|
27
|
+
name: 'ServerNotReadyError',
|
|
28
|
+
message: 'OpenCode server for directory "$directory" is in an error state (no client available)',
|
|
29
|
+
}) {}
|
|
30
|
+
|
|
31
|
+
export class ApiKeyMissingError extends createTaggedError({
|
|
32
|
+
name: 'ApiKeyMissingError',
|
|
33
|
+
message: '$service API key is required',
|
|
34
|
+
}) {}
|
|
59
35
|
|
|
60
36
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
61
37
|
// DOMAIN ERRORS - Sessions, messages, transcription
|
|
62
38
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
63
39
|
|
|
64
|
-
export class SessionNotFoundError extends
|
|
65
|
-
|
|
66
|
-
message:
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
super({ ...args, message: `Transcription failed: ${args.reason}` })
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export class GrepSearchError extends errore.TaggedError('GrepSearchError')<{
|
|
98
|
-
pattern: string
|
|
99
|
-
message: string
|
|
100
|
-
cause?: unknown
|
|
101
|
-
}>() {
|
|
102
|
-
constructor(args: { pattern: string; cause?: unknown }) {
|
|
103
|
-
super({ ...args, message: `Grep search failed for pattern: ${args.pattern}` })
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export class GlobSearchError extends errore.TaggedError('GlobSearchError')<{
|
|
108
|
-
pattern: string
|
|
109
|
-
message: string
|
|
110
|
-
cause?: unknown
|
|
111
|
-
}>() {
|
|
112
|
-
constructor(args: { pattern: string; cause?: unknown }) {
|
|
113
|
-
super({ ...args, message: `Glob search failed for pattern: ${args.pattern}` })
|
|
114
|
-
}
|
|
115
|
-
}
|
|
40
|
+
export class SessionNotFoundError extends createTaggedError({
|
|
41
|
+
name: 'SessionNotFoundError',
|
|
42
|
+
message: 'Session $sessionId not found',
|
|
43
|
+
}) {}
|
|
44
|
+
|
|
45
|
+
export class SessionCreateError extends createTaggedError({
|
|
46
|
+
name: 'SessionCreateError',
|
|
47
|
+
message: '$message',
|
|
48
|
+
}) {}
|
|
49
|
+
|
|
50
|
+
export class MessagesNotFoundError extends createTaggedError({
|
|
51
|
+
name: 'MessagesNotFoundError',
|
|
52
|
+
message: 'No messages found for session $sessionId',
|
|
53
|
+
}) {}
|
|
54
|
+
|
|
55
|
+
export class TranscriptionError extends createTaggedError({
|
|
56
|
+
name: 'TranscriptionError',
|
|
57
|
+
message: 'Transcription failed: $reason',
|
|
58
|
+
}) {}
|
|
59
|
+
|
|
60
|
+
export class GrepSearchError extends createTaggedError({
|
|
61
|
+
name: 'GrepSearchError',
|
|
62
|
+
message: 'Grep search failed for pattern: $pattern',
|
|
63
|
+
}) {}
|
|
64
|
+
|
|
65
|
+
export class GlobSearchError extends createTaggedError({
|
|
66
|
+
name: 'GlobSearchError',
|
|
67
|
+
message: 'Glob search failed for pattern: $pattern',
|
|
68
|
+
}) {}
|
|
116
69
|
|
|
117
70
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
118
71
|
// VALIDATION ERRORS - Input validation, format checks
|
|
119
72
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
120
73
|
|
|
121
|
-
export class InvalidAudioFormatError extends
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
message:
|
|
139
|
-
}
|
|
140
|
-
constructor() {
|
|
141
|
-
super({ message: 'No response content from model' })
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export class NoToolResponseError extends errore.TaggedError('NoToolResponseError')<{
|
|
146
|
-
message: string
|
|
147
|
-
}>() {
|
|
148
|
-
constructor() {
|
|
149
|
-
super({ message: 'No valid tool responses' })
|
|
150
|
-
}
|
|
151
|
-
}
|
|
74
|
+
export class InvalidAudioFormatError extends createTaggedError({
|
|
75
|
+
name: 'InvalidAudioFormatError',
|
|
76
|
+
message: 'Invalid audio format',
|
|
77
|
+
}) {}
|
|
78
|
+
|
|
79
|
+
export class EmptyTranscriptionError extends createTaggedError({
|
|
80
|
+
name: 'EmptyTranscriptionError',
|
|
81
|
+
message: 'Model returned empty transcription',
|
|
82
|
+
}) {}
|
|
83
|
+
|
|
84
|
+
export class NoResponseContentError extends createTaggedError({
|
|
85
|
+
name: 'NoResponseContentError',
|
|
86
|
+
message: 'No response content from model',
|
|
87
|
+
}) {}
|
|
88
|
+
|
|
89
|
+
export class NoToolResponseError extends createTaggedError({
|
|
90
|
+
name: 'NoToolResponseError',
|
|
91
|
+
message: 'No valid tool responses',
|
|
92
|
+
}) {}
|
|
152
93
|
|
|
153
94
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
154
95
|
// NETWORK ERRORS - Fetch and HTTP
|
|
155
96
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
156
97
|
|
|
157
|
-
export class FetchError extends
|
|
158
|
-
|
|
159
|
-
message:
|
|
160
|
-
|
|
161
|
-
}>() {
|
|
162
|
-
constructor(args: { url: string; cause?: unknown }) {
|
|
163
|
-
const causeMsg = args.cause instanceof Error ? args.cause.message : String(args.cause)
|
|
164
|
-
super({ ...args, message: `Fetch failed for ${args.url}: ${causeMsg}` })
|
|
165
|
-
}
|
|
166
|
-
}
|
|
98
|
+
export class FetchError extends createTaggedError({
|
|
99
|
+
name: 'FetchError',
|
|
100
|
+
message: 'Fetch failed for $url',
|
|
101
|
+
}) {}
|
|
167
102
|
|
|
168
103
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
169
104
|
// API ERRORS - External service responses
|
|
170
105
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
171
106
|
|
|
172
|
-
export class DiscordApiError extends
|
|
173
|
-
|
|
174
|
-
message:
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
export class OpenCodeApiError extends errore.TaggedError('OpenCodeApiError')<{
|
|
182
|
-
status: number
|
|
183
|
-
message: string
|
|
184
|
-
}>() {
|
|
185
|
-
constructor(args: { status: number; body?: string }) {
|
|
186
|
-
super({ ...args, message: `OpenCode API error (${args.status})${args.body ? `: ${args.body}` : ''}` })
|
|
187
|
-
}
|
|
188
|
-
}
|
|
107
|
+
export class DiscordApiError extends createTaggedError({
|
|
108
|
+
name: 'DiscordApiError',
|
|
109
|
+
message: 'Discord API error: $status $body',
|
|
110
|
+
}) {}
|
|
111
|
+
|
|
112
|
+
export class OpenCodeApiError extends createTaggedError({
|
|
113
|
+
name: 'OpenCodeApiError',
|
|
114
|
+
message: 'OpenCode API error ($status): $body',
|
|
115
|
+
}) {}
|
|
189
116
|
|
|
190
117
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
191
118
|
// UNION TYPES - For function signatures
|
|
@@ -205,4 +132,7 @@ export type OpenCodeErrors =
|
|
|
205
132
|
| ServerNotFoundError
|
|
206
133
|
| ServerNotReadyError
|
|
207
134
|
|
|
208
|
-
export type SessionErrors =
|
|
135
|
+
export type SessionErrors =
|
|
136
|
+
| SessionNotFoundError
|
|
137
|
+
| MessagesNotFoundError
|
|
138
|
+
| OpenCodeApiError
|
package/src/genai-worker.ts
CHANGED
|
@@ -132,7 +132,7 @@ async function createAssistantAudioLogStream(
|
|
|
132
132
|
try: () => mkdir(audioDir, { recursive: true }),
|
|
133
133
|
catch: (e) => e as Error,
|
|
134
134
|
})
|
|
135
|
-
if (
|
|
135
|
+
if (mkdirError instanceof Error) {
|
|
136
136
|
workerLogger.error(`Failed to create audio log directory:`, mkdirError.message)
|
|
137
137
|
return null
|
|
138
138
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { Events, type Client, type Interaction } from 'discord.js'
|
|
6
6
|
import { handleSessionCommand, handleSessionAutocomplete } from './commands/session.js'
|
|
7
|
+
import { handleNewWorktreeCommand } from './commands/worktree.js'
|
|
7
8
|
import { handleResumeCommand, handleResumeAutocomplete } from './commands/resume.js'
|
|
8
9
|
import { handleAddProjectCommand, handleAddProjectAutocomplete } from './commands/add-project.js'
|
|
9
10
|
import {
|
|
@@ -52,7 +53,7 @@ export function registerInteractionHandler({
|
|
|
52
53
|
|
|
53
54
|
if (interaction.isAutocomplete()) {
|
|
54
55
|
switch (interaction.commandName) {
|
|
55
|
-
case 'session':
|
|
56
|
+
case 'new-session':
|
|
56
57
|
await handleSessionAutocomplete({ interaction, appId })
|
|
57
58
|
return
|
|
58
59
|
|
|
@@ -78,10 +79,14 @@ export function registerInteractionHandler({
|
|
|
78
79
|
interactionLogger.log(`[COMMAND] Processing: ${interaction.commandName}`)
|
|
79
80
|
|
|
80
81
|
switch (interaction.commandName) {
|
|
81
|
-
case 'session':
|
|
82
|
+
case 'new-session':
|
|
82
83
|
await handleSessionCommand({ command: interaction, appId })
|
|
83
84
|
return
|
|
84
85
|
|
|
86
|
+
case 'new-worktree':
|
|
87
|
+
await handleNewWorktreeCommand({ command: interaction, appId })
|
|
88
|
+
return
|
|
89
|
+
|
|
85
90
|
case 'resume':
|
|
86
91
|
await handleResumeCommand({ command: interaction, appId })
|
|
87
92
|
return
|
package/src/markdown.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { OpencodeClient } from '@opencode-ai/sdk'
|
|
7
7
|
import * as errore from 'errore'
|
|
8
|
+
import { createTaggedError } from 'errore'
|
|
8
9
|
import * as yaml from 'js-yaml'
|
|
9
10
|
import { formatDateTime } from './utils.js'
|
|
10
11
|
import { extractNonXmlContent } from './xml.js'
|
|
@@ -12,10 +13,10 @@ import { createLogger } from './logger.js'
|
|
|
12
13
|
import { SessionNotFoundError, MessagesNotFoundError } from './errors.js'
|
|
13
14
|
|
|
14
15
|
// Generic error for unexpected exceptions in async operations
|
|
15
|
-
class UnexpectedError extends
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
16
|
+
class UnexpectedError extends createTaggedError({
|
|
17
|
+
name: 'UnexpectedError',
|
|
18
|
+
message: '$message',
|
|
19
|
+
}) {}
|
|
19
20
|
|
|
20
21
|
const markdownLogger = createLogger('MARKDOWN')
|
|
21
22
|
|
|
@@ -93,7 +93,7 @@ export async function getTextAttachments(message: Message): Promise<string> {
|
|
|
93
93
|
try: () => fetch(attachment.url),
|
|
94
94
|
catch: (e) => new FetchError({ url: attachment.url, cause: e }),
|
|
95
95
|
})
|
|
96
|
-
if (
|
|
96
|
+
if (response instanceof Error) {
|
|
97
97
|
return `<attachment filename="${attachment.name}" error="${response.message}" />`
|
|
98
98
|
}
|
|
99
99
|
if (!response.ok) {
|
|
@@ -128,7 +128,7 @@ export async function getFileAttachments(message: Message): Promise<FilePartInpu
|
|
|
128
128
|
try: () => fetch(attachment.url),
|
|
129
129
|
catch: (e) => new FetchError({ url: attachment.url, cause: e }),
|
|
130
130
|
})
|
|
131
|
-
if (
|
|
131
|
+
if (response instanceof Error) {
|
|
132
132
|
logger.error(`Error downloading attachment ${attachment.name}:`, response.message)
|
|
133
133
|
return null
|
|
134
134
|
}
|
package/src/opencode.ts
CHANGED
|
@@ -66,7 +66,7 @@ async function waitForServer(port: number, maxAttempts = 30): Promise<ServerStar
|
|
|
66
66
|
try: () => fetch(endpoint),
|
|
67
67
|
catch: (e) => new FetchError({ url: endpoint, cause: e }),
|
|
68
68
|
})
|
|
69
|
-
if (
|
|
69
|
+
if (response instanceof Error) {
|
|
70
70
|
// Connection refused or other transient errors - continue polling
|
|
71
71
|
opencodeLogger.debug(`Server polling attempt failed: ${response.message}`)
|
|
72
72
|
continue
|
|
@@ -107,7 +107,7 @@ export async function initializeOpencodeForDirectory(directory: string): Promise
|
|
|
107
107
|
},
|
|
108
108
|
catch: () => new DirectoryNotAccessibleError({ directory }),
|
|
109
109
|
})
|
|
110
|
-
if (
|
|
110
|
+
if (accessCheck instanceof Error) {
|
|
111
111
|
return accessCheck
|
|
112
112
|
}
|
|
113
113
|
|
|
@@ -164,7 +164,7 @@ export async function initializeOpencodeForDirectory(directory: string): Promise
|
|
|
164
164
|
`Restarting server for directory: ${directory} (attempt ${retryCount + 1}/5)`,
|
|
165
165
|
)
|
|
166
166
|
initializeOpencodeForDirectory(directory).then((result) => {
|
|
167
|
-
if (
|
|
167
|
+
if (result instanceof Error) {
|
|
168
168
|
opencodeLogger.error(`Failed to restart opencode server:`, result)
|
|
169
169
|
}
|
|
170
170
|
})
|
|
@@ -177,7 +177,7 @@ export async function initializeOpencodeForDirectory(directory: string): Promise
|
|
|
177
177
|
})
|
|
178
178
|
|
|
179
179
|
const waitResult = await waitForServer(port)
|
|
180
|
-
if (
|
|
180
|
+
if (waitResult instanceof Error) {
|
|
181
181
|
// Dump buffered logs on failure
|
|
182
182
|
opencodeLogger.error(`Server failed to start for ${directory}:`)
|
|
183
183
|
for (const line of logBuffer) {
|
package/src/session-handler.ts
CHANGED
|
@@ -105,7 +105,7 @@ export async function abortAndRetrySession({
|
|
|
105
105
|
|
|
106
106
|
// Also call the API abort endpoint
|
|
107
107
|
const getClient = await initializeOpencodeForDirectory(projectDirectory)
|
|
108
|
-
if (
|
|
108
|
+
if (getClient instanceof Error) {
|
|
109
109
|
sessionLogger.error(`[ABORT+RETRY] Failed to initialize OpenCode client:`, getClient.message)
|
|
110
110
|
return false
|
|
111
111
|
}
|
|
@@ -188,7 +188,7 @@ export async function handleOpencodeSession({
|
|
|
188
188
|
sessionLogger.log(`Using directory: ${directory}`)
|
|
189
189
|
|
|
190
190
|
const getClient = await initializeOpencodeForDirectory(directory)
|
|
191
|
-
if (
|
|
191
|
+
if (getClient instanceof Error) {
|
|
192
192
|
await sendThreadMessage(thread, `✗ ${getClient.message}`)
|
|
193
193
|
return
|
|
194
194
|
}
|
package/src/tools.ts
CHANGED
|
@@ -36,7 +36,7 @@ export async function getTools({
|
|
|
36
36
|
}) => void
|
|
37
37
|
}) {
|
|
38
38
|
const getClient = await initializeOpencodeForDirectory(directory)
|
|
39
|
-
if (
|
|
39
|
+
if (getClient instanceof Error) {
|
|
40
40
|
throw new Error(getClient.message)
|
|
41
41
|
}
|
|
42
42
|
const client = getClient()
|
|
@@ -298,7 +298,7 @@ export async function getTools({
|
|
|
298
298
|
sessionID: sessionId,
|
|
299
299
|
lastAssistantOnly: true,
|
|
300
300
|
})
|
|
301
|
-
if (
|
|
301
|
+
if (markdownResult instanceof Error) {
|
|
302
302
|
throw new Error(markdownResult.message)
|
|
303
303
|
}
|
|
304
304
|
|
|
@@ -311,7 +311,7 @@ export async function getTools({
|
|
|
311
311
|
const markdownResult = await markdownRenderer.generate({
|
|
312
312
|
sessionID: sessionId,
|
|
313
313
|
})
|
|
314
|
-
if (
|
|
314
|
+
if (markdownResult instanceof Error) {
|
|
315
315
|
throw new Error(markdownResult.message)
|
|
316
316
|
}
|
|
317
317
|
|
package/src/voice-handler.ts
CHANGED
|
@@ -450,7 +450,7 @@ export async function processVoiceAttachment({
|
|
|
450
450
|
try: () => fetch(audioAttachment.url),
|
|
451
451
|
catch: (e) => new FetchError({ url: audioAttachment.url, cause: e }),
|
|
452
452
|
})
|
|
453
|
-
if (
|
|
453
|
+
if (audioResponse instanceof Error) {
|
|
454
454
|
voiceLogger.error(`Failed to download audio attachment:`, audioResponse.message)
|
|
455
455
|
await sendThreadMessage(thread, `⚠️ Failed to download audio: ${audioResponse.message}`)
|
|
456
456
|
return null
|
|
@@ -498,7 +498,7 @@ export async function processVoiceAttachment({
|
|
|
498
498
|
lastSessionContext,
|
|
499
499
|
})
|
|
500
500
|
|
|
501
|
-
if (
|
|
501
|
+
if (transcription instanceof Error) {
|
|
502
502
|
const errMsg = errore.matchError(transcription, {
|
|
503
503
|
ApiKeyMissingError: (e) => e.message,
|
|
504
504
|
InvalidAudioFormatError: (e) => e.message,
|
|
@@ -532,7 +532,7 @@ export async function processVoiceAttachment({
|
|
|
532
532
|
])
|
|
533
533
|
if (renamed === null) {
|
|
534
534
|
voiceLogger.log(`Thread name update timed out`)
|
|
535
|
-
} else if (
|
|
535
|
+
} else if (renamed instanceof Error) {
|
|
536
536
|
voiceLogger.log(`Could not update thread name:`, renamed.message)
|
|
537
537
|
} else {
|
|
538
538
|
voiceLogger.log(`Updated thread name to: "${threadName}"`)
|
package/src/voice.ts
CHANGED
|
@@ -145,7 +145,7 @@ function createToolRunner({ directory }: { directory?: string }): TranscriptionT
|
|
|
145
145
|
voiceLogger.log(`Grep search: "${pattern}"`)
|
|
146
146
|
const result = await runGrep({ pattern, directory })
|
|
147
147
|
const output = (() => {
|
|
148
|
-
if (
|
|
148
|
+
if (result instanceof Error) {
|
|
149
149
|
voiceLogger.error('grep search failed:', result)
|
|
150
150
|
return 'grep search failed'
|
|
151
151
|
}
|
|
@@ -160,7 +160,7 @@ function createToolRunner({ directory }: { directory?: string }): TranscriptionT
|
|
|
160
160
|
voiceLogger.log(`Glob search: "${pattern}"`)
|
|
161
161
|
const result = await runGlob({ pattern, directory })
|
|
162
162
|
const output = (() => {
|
|
163
|
-
if (
|
|
163
|
+
if (result instanceof Error) {
|
|
164
164
|
voiceLogger.error('glob search failed:', result)
|
|
165
165
|
return 'glob search failed'
|
|
166
166
|
}
|
|
@@ -214,7 +214,7 @@ export async function runTranscriptionLoop({
|
|
|
214
214
|
catch: (e) => new TranscriptionError({ reason: `API call failed: ${String(e)}`, cause: e }),
|
|
215
215
|
})
|
|
216
216
|
|
|
217
|
-
if (
|
|
217
|
+
if (initialResponse instanceof Error) {
|
|
218
218
|
return initialResponse
|
|
219
219
|
}
|
|
220
220
|
|
|
@@ -323,7 +323,7 @@ export async function runTranscriptionLoop({
|
|
|
323
323
|
catch: (e) => new TranscriptionError({ reason: `API call failed: ${String(e)}`, cause: e }),
|
|
324
324
|
})
|
|
325
325
|
|
|
326
|
-
if (
|
|
326
|
+
if (nextResponse instanceof Error) {
|
|
327
327
|
return nextResponse
|
|
328
328
|
}
|
|
329
329
|
|