kimaki 0.26.0 → 0.27.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 +25 -122
- package/dist/anthropic-account-identity.js +1 -0
- package/dist/anthropic-auth-plugin.js +1 -0
- package/dist/anthropic-auth-state.js +1 -0
- package/dist/bin.js +73 -19
- package/dist/cli-commands/maintenance.js +46 -7
- package/dist/cli-commands/send.js +24 -0
- package/dist/cli-commands/session.js +183 -8
- package/dist/cli-commands/task.js +13 -1
- package/dist/cli-parsing.test.js +59 -3
- package/dist/cli-runner.js +28 -4
- package/dist/cli-runner.test.js +27 -0
- package/dist/cli-send-thread.e2e.test.js +1 -1
- package/dist/cli.js +32 -0
- package/dist/commands/abort.js +5 -1
- package/dist/commands/agent.js +6 -8
- package/dist/commands/ask-question.js +21 -32
- package/dist/commands/ask-question.test.js +43 -1
- package/dist/commands/login.js +6 -0
- package/dist/commands/merge-worktree.js +36 -10
- package/dist/commands/model-variant.js +7 -1
- package/dist/commands/model.js +14 -8
- package/dist/commands/multioauth.js +1 -0
- package/dist/commands/new-worktree.js +170 -102
- package/dist/commands/user-command.js +6 -8
- package/dist/commands/worktrees.js +5 -13
- package/dist/config.js +16 -1
- package/dist/database.js +124 -3
- package/dist/db.js +22 -0
- package/dist/db.test.js +167 -1
- package/dist/discord-bot.js +34 -32
- package/dist/discord-command-registration.js +9 -1
- package/dist/discord-utils.js +13 -5
- package/dist/discord-utils.test.js +17 -1
- package/dist/errors.js +5 -0
- package/dist/exec-async.js +17 -5
- package/dist/external-directory-permissions.e2e.test.js +2 -2
- package/dist/file-edit-log.js +197 -0
- package/dist/file-edit-log.test.js +258 -0
- package/dist/format-tables.js +52 -0
- package/dist/format-tables.test.js +93 -0
- package/dist/gateway-proxy-reconnect.e2e.test.js +28 -8
- package/dist/gateway-proxy.e2e.test.js +5 -5
- package/dist/git-worktree-core.js +182 -17
- package/dist/ipc-tools-plugin.js +63 -3
- package/dist/kimaki-opencode-plugin-loading.e2e.test.js +122 -58
- package/dist/kimaki-opencode-plugin.js +7 -3
- package/dist/kimaki-workspace-adaptor.js +33 -10
- package/dist/logger.js +10 -1
- package/dist/markdown.js +3 -1
- package/dist/markdown.test.js +11 -3
- package/dist/message-formatting.js +18 -7
- package/dist/message-formatting.test.js +56 -9
- package/dist/oauth-rotation-shared.js +10 -0
- package/dist/openai-auth-plugin.js +1 -0
- package/dist/openai-auth-state.js +1 -0
- package/dist/opencode-command.test.js +60 -0
- package/dist/opencode.js +53 -12
- package/dist/question-abort-clears-dropdown.e2e.test.js +89 -0
- package/dist/question-text-before-dropdown.e2e.test.js +52 -0
- package/dist/queue-advanced-abort.e2e.test.js +1 -1
- package/dist/queue-advanced-action-buttons.e2e.test.js +3 -3
- package/dist/queue-advanced-e2e-setup.js +78 -5
- package/dist/queue-advanced-footer.e2e.test.js +40 -246
- package/dist/queue-advanced-model-switch.e2e.test.js +2 -2
- package/dist/queue-advanced-permissions-typing.e2e.test.js +7 -9
- package/dist/queue-advanced-question.e2e.test.js +31 -26
- package/dist/queue-advanced-typing-interrupt.e2e.test.js +2 -2
- package/dist/queue-delete-message.e2e.test.js +1 -1
- package/dist/queue-drain-after-interactive-ui.e2e.test.js +2 -2
- package/dist/queue-interrupt-drain.e2e.test.js +112 -2
- package/dist/queue-question-select-drain.e2e.test.js +30 -128
- package/dist/runtime-lifecycle.e2e.test.js +10 -37
- package/dist/schema.js +34 -0
- package/dist/session-handler/event-stream-state.js +267 -50
- package/dist/session-handler/event-stream-state.test.js +415 -8
- package/dist/session-handler/model-utils.js +159 -5
- package/dist/session-handler/model-utils.test.js +345 -0
- package/dist/session-handler/thread-session-runtime.js +252 -182
- package/dist/session-sleep.test.js +224 -0
- package/dist/session-title-rename.test.js +7 -39
- package/dist/sleep.e2e.test.js +491 -0
- package/dist/startup-time.e2e.test.js +2 -1
- package/dist/store.js +3 -0
- package/dist/system-message.js +59 -6
- package/dist/system-message.test.js +76 -6
- package/dist/task-runner.js +94 -4
- package/dist/task-schedule.js +56 -0
- package/dist/task-schedule.test.js +71 -1
- package/dist/thread-message-queue.e2e.test.js +10 -169
- package/dist/undo-redo.e2e.test.js +2 -2
- package/dist/voice-attachment.js +23 -1
- package/dist/voice-message.e2e.test.js +10 -10
- package/dist/voice.test.js +55 -29
- package/dist/worktree-clone-isolation.e2e.test.js +188 -0
- package/dist/worktree-lifecycle.e2e.test.js +29 -10
- package/dist/worktrees.js +226 -443
- package/dist/worktrees.test.js +435 -58
- package/dist/xai-auth-plugin.js +1 -0
- package/dist/xai-auth-state.js +1 -0
- package/package.json +8 -6
- package/skills/errore/SKILL.md +18 -0
- package/skills/goke/SKILL.md +150 -10
- package/skills/holocron/SKILL.md +37 -0
- package/skills/npm-package/SKILL.md +55 -35
- package/skills/profano/SKILL.md +17 -2
- package/skills/spiceflow/SKILL.md +39 -3
- package/skills/strada/SKILL.md +39 -0
- package/skills/zele/SKILL.md +19 -0
- package/src/agent-model.e2e.test.ts +25 -151
- package/src/anthropic-account-identity.ts +1 -0
- package/src/anthropic-auth-plugin.ts +1 -0
- package/src/anthropic-auth-state.ts +1 -0
- package/src/bin.ts +78 -26
- package/src/cli-commands/maintenance.ts +59 -13
- package/src/cli-commands/send.ts +25 -0
- package/src/cli-commands/session.ts +203 -9
- package/src/cli-commands/task.ts +13 -1
- package/src/cli-parsing.test.ts +69 -3
- package/src/cli-runner.test.ts +49 -0
- package/src/cli-runner.ts +28 -4
- package/src/cli-send-thread.e2e.test.ts +1 -1
- package/src/cli.ts +53 -0
- package/src/commands/abort.ts +6 -1
- package/src/commands/agent.ts +6 -6
- package/src/commands/ask-question.test.ts +48 -1
- package/src/commands/ask-question.ts +21 -32
- package/src/commands/login.ts +6 -0
- package/src/commands/merge-worktree.ts +43 -12
- package/src/commands/model-variant.ts +8 -1
- package/src/commands/model.ts +18 -8
- package/src/commands/multioauth.ts +1 -0
- package/src/commands/new-worktree.ts +138 -55
- package/src/commands/user-command.ts +6 -6
- package/src/commands/worktrees.ts +5 -12
- package/src/config.ts +18 -1
- package/src/database.ts +195 -3
- package/src/db.test.ts +188 -0
- package/src/db.ts +26 -0
- package/src/discord-bot.ts +35 -29
- package/src/discord-command-registration.ts +15 -1
- package/src/discord-utils.test.ts +19 -0
- package/src/discord-utils.ts +21 -6
- package/src/errors.ts +5 -0
- package/src/exec-async.ts +20 -11
- package/src/external-directory-permissions.e2e.test.ts +2 -2
- package/src/file-edit-log.test.ts +287 -0
- package/src/file-edit-log.ts +283 -0
- package/src/format-tables.test.ts +101 -0
- package/src/format-tables.ts +75 -0
- package/src/gateway-proxy-reconnect.e2e.test.ts +38 -8
- package/src/gateway-proxy.e2e.test.ts +5 -5
- package/src/git-worktree-core.ts +247 -20
- package/src/ipc-tools-plugin.ts +75 -5
- package/src/kimaki-opencode-plugin-loading.e2e.test.ts +188 -97
- package/src/kimaki-opencode-plugin.ts +7 -3
- package/src/kimaki-workspace-adaptor.ts +40 -11
- package/src/logger.ts +13 -4
- package/src/markdown.test.ts +13 -3
- package/src/markdown.ts +4 -1
- package/src/message-formatting.test.ts +86 -12
- package/src/message-formatting.ts +19 -7
- package/src/oauth-rotation-shared.ts +10 -0
- package/src/openai-auth-plugin.ts +1 -0
- package/src/openai-auth-state.ts +1 -0
- package/src/opencode-command.test.ts +81 -0
- package/src/opencode.ts +71 -11
- package/src/question-abort-clears-dropdown.e2e.test.ts +109 -0
- package/src/question-text-before-dropdown.e2e.test.ts +67 -0
- package/src/queue-advanced-abort.e2e.test.ts +1 -1
- package/src/queue-advanced-action-buttons.e2e.test.ts +3 -3
- package/src/queue-advanced-e2e-setup.ts +83 -4
- package/src/queue-advanced-footer.e2e.test.ts +47 -294
- package/src/queue-advanced-model-switch.e2e.test.ts +2 -2
- package/src/queue-advanced-permissions-typing.e2e.test.ts +7 -9
- package/src/queue-advanced-question.e2e.test.ts +35 -29
- package/src/queue-advanced-typing-interrupt.e2e.test.ts +2 -2
- package/src/queue-delete-message.e2e.test.ts +1 -1
- package/src/queue-drain-after-interactive-ui.e2e.test.ts +2 -2
- package/src/queue-interrupt-drain.e2e.test.ts +123 -2
- package/src/queue-question-select-drain.e2e.test.ts +32 -157
- package/src/runtime-lifecycle.e2e.test.ts +10 -41
- package/src/schema.sql +14 -1
- package/src/schema.ts +36 -0
- package/src/session-handler/event-stream-state.test.ts +437 -7
- package/src/session-handler/event-stream-state.ts +389 -53
- package/src/session-handler/model-utils.test.ts +415 -0
- package/src/session-handler/model-utils.ts +249 -5
- package/src/session-handler/thread-session-runtime.ts +300 -215
- package/src/session-sleep.test.ts +294 -0
- package/src/session-title-rename.test.ts +9 -48
- package/src/sleep.e2e.test.ts +562 -0
- package/src/startup-time.e2e.test.ts +5 -1
- package/src/store.ts +21 -0
- package/src/system-message.test.ts +86 -6
- package/src/system-message.ts +66 -7
- package/src/task-runner.ts +136 -2
- package/src/task-schedule.test.ts +76 -0
- package/src/task-schedule.ts +95 -0
- package/src/thread-message-queue.e2e.test.ts +10 -202
- package/src/undo-redo.e2e.test.ts +2 -2
- package/src/voice-attachment.ts +29 -1
- package/src/voice-message.e2e.test.ts +10 -10
- package/src/voice.test.ts +63 -29
- package/src/worktree-clone-isolation.e2e.test.ts +213 -0
- package/src/worktree-lifecycle.e2e.test.ts +29 -9
- package/src/worktrees.test.ts +505 -64
- package/src/worktrees.ts +257 -603
- package/src/xai-auth-plugin.ts +1 -0
- package/src/xai-auth-state.ts +1 -0
- package/dist/message-finish-field.e2e.test.js +0 -169
- package/dist/subagent-rate-limit-plugin.js +0 -184
- package/src/message-finish-field.e2e.test.ts +0 -196
- package/src/subagent-rate-limit-plugin.ts +0 -228
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
// OpenCode plugin that aborts task-created subagent sessions after rate limits.
|
|
2
|
-
|
|
3
|
-
import type { Hooks, Plugin } from '@opencode-ai/plugin'
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
appendToastSessionMarker,
|
|
7
|
-
createPluginLogger,
|
|
8
|
-
formatPluginErrorWithStack,
|
|
9
|
-
setPluginLogFilePath,
|
|
10
|
-
} from './plugin-logger.js'
|
|
11
|
-
import { createPluginClient } from './plugin-opencode-client.js'
|
|
12
|
-
import { initSentry, notifyError } from './sentry.js'
|
|
13
|
-
|
|
14
|
-
const logger = createPluginLogger('SUBMODEL')
|
|
15
|
-
|
|
16
|
-
const RATE_LIMIT_TEXT_PATTERNS = [
|
|
17
|
-
'rate_limit',
|
|
18
|
-
'rate limit',
|
|
19
|
-
'resource exhausted',
|
|
20
|
-
'retry after',
|
|
21
|
-
'too many requests',
|
|
22
|
-
'quota exceeded',
|
|
23
|
-
'balance exhausted',
|
|
24
|
-
'spending-limit',
|
|
25
|
-
'run out of credits',
|
|
26
|
-
] as const
|
|
27
|
-
|
|
28
|
-
type PluginEvent = Parameters<NonNullable<Hooks['event']>>[0]['event']
|
|
29
|
-
|
|
30
|
-
function isRateLimitText(text: string | undefined): boolean {
|
|
31
|
-
if (!text) {
|
|
32
|
-
return false
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const haystack = text.toLowerCase()
|
|
36
|
-
return RATE_LIMIT_TEXT_PATTERNS.some((pattern) => {
|
|
37
|
-
return haystack.includes(pattern)
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function getTaskChildSession(event: PluginEvent) {
|
|
42
|
-
if (event.type !== 'message.part.updated') {
|
|
43
|
-
return undefined
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const part = event.properties.part
|
|
47
|
-
if (part.type !== 'tool' || part.tool !== 'task' || part.state.status === 'pending') {
|
|
48
|
-
return undefined
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const childSessionId = part.state.metadata?.sessionId
|
|
52
|
-
if (typeof childSessionId !== 'string' || childSessionId.length === 0) {
|
|
53
|
-
return undefined
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const subagentType = part.state.input?.subagent_type
|
|
57
|
-
return {
|
|
58
|
-
childSessionId,
|
|
59
|
-
subagentType: typeof subagentType === 'string' ? subagentType : undefined,
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function getEventSessionId(event: PluginEvent): string | undefined {
|
|
64
|
-
if (event.type === 'session.status' || event.type === 'session.idle') {
|
|
65
|
-
return event.properties.sessionID
|
|
66
|
-
}
|
|
67
|
-
if (event.type === 'session.error') {
|
|
68
|
-
return event.properties.sessionID
|
|
69
|
-
}
|
|
70
|
-
if (event.type === 'message.updated') {
|
|
71
|
-
return event.properties.info.sessionID
|
|
72
|
-
}
|
|
73
|
-
if (event.type === 'message.part.updated') {
|
|
74
|
-
return event.properties.part.sessionID
|
|
75
|
-
}
|
|
76
|
-
if (
|
|
77
|
-
event.type === 'session.created'
|
|
78
|
-
|| event.type === 'session.updated'
|
|
79
|
-
|| event.type === 'session.deleted'
|
|
80
|
-
) {
|
|
81
|
-
return event.properties.info.id
|
|
82
|
-
}
|
|
83
|
-
return undefined
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function extractRateLimitReason(event: PluginEvent): string | undefined {
|
|
87
|
-
if (event.type === 'session.status' && event.properties.status.type === 'retry') {
|
|
88
|
-
return isRateLimitText(event.properties.status.message)
|
|
89
|
-
? event.properties.status.message
|
|
90
|
-
: undefined
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (event.type === 'message.part.updated' && event.properties.part.type === 'retry') {
|
|
94
|
-
const retryError = event.properties.part.error
|
|
95
|
-
if (retryError.data.statusCode === 429 || retryError.data.statusCode === 402) {
|
|
96
|
-
return retryError.data.message
|
|
97
|
-
}
|
|
98
|
-
if (isRateLimitText(retryError.data.responseBody)) {
|
|
99
|
-
return retryError.data.responseBody
|
|
100
|
-
}
|
|
101
|
-
return isRateLimitText(retryError.data.message)
|
|
102
|
-
? retryError.data.message
|
|
103
|
-
: undefined
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const apiError = (() => {
|
|
107
|
-
if (event.type === 'session.error' && event.properties.error?.name === 'APIError') {
|
|
108
|
-
return event.properties.error.data
|
|
109
|
-
}
|
|
110
|
-
if (
|
|
111
|
-
event.type === 'message.updated'
|
|
112
|
-
&& event.properties.info.role === 'assistant'
|
|
113
|
-
&& event.properties.info.error?.name === 'APIError'
|
|
114
|
-
) {
|
|
115
|
-
return event.properties.info.error.data
|
|
116
|
-
}
|
|
117
|
-
return undefined
|
|
118
|
-
})()
|
|
119
|
-
|
|
120
|
-
if (!apiError) {
|
|
121
|
-
return undefined
|
|
122
|
-
}
|
|
123
|
-
if (apiError.statusCode === 429 || apiError.statusCode === 402) {
|
|
124
|
-
return apiError.message
|
|
125
|
-
}
|
|
126
|
-
// xAI returns 403 with spending-limit or run out of credits text.
|
|
127
|
-
// Only treat 403 as a usage limit if the body matches specific patterns,
|
|
128
|
-
// not all 403s (which can be auth errors handled elsewhere).
|
|
129
|
-
if (apiError.statusCode === 403) {
|
|
130
|
-
const errorText = [apiError.message, apiError.responseBody].filter(Boolean).join(' ')
|
|
131
|
-
if (isRateLimitText(errorText)) return apiError.message
|
|
132
|
-
}
|
|
133
|
-
if (isRateLimitText(apiError.responseBody)) {
|
|
134
|
-
return apiError.responseBody
|
|
135
|
-
}
|
|
136
|
-
return isRateLimitText(apiError.message) ? apiError.message : undefined
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export const subagentRateLimitPlugin: Plugin = async ({ serverUrl, directory }) => {
|
|
140
|
-
initSentry()
|
|
141
|
-
|
|
142
|
-
const dataDir = process.env.KIMAKI_DATA_DIR
|
|
143
|
-
if (dataDir) {
|
|
144
|
-
setPluginLogFilePath(dataDir)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Build our own v2 client. The plugin-provided ctx.client (v1) does not
|
|
148
|
-
// reliably make REST calls (session.abort silently no-ops) from inside the
|
|
149
|
-
// plugin process. See plugin-opencode-client.ts.
|
|
150
|
-
const client = createPluginClient({ serverUrl, directory })
|
|
151
|
-
logger.bindClient(client)
|
|
152
|
-
|
|
153
|
-
const subagentSessions = new Map<string, {
|
|
154
|
-
subagentType?: string
|
|
155
|
-
aborting: boolean
|
|
156
|
-
}>()
|
|
157
|
-
|
|
158
|
-
return {
|
|
159
|
-
event: async ({ event }) => {
|
|
160
|
-
const taskChild = getTaskChildSession(event)
|
|
161
|
-
if (taskChild) {
|
|
162
|
-
const existing = subagentSessions.get(taskChild.childSessionId)
|
|
163
|
-
if (existing) {
|
|
164
|
-
if (taskChild.subagentType) {
|
|
165
|
-
existing.subagentType = taskChild.subagentType
|
|
166
|
-
}
|
|
167
|
-
} else {
|
|
168
|
-
subagentSessions.set(taskChild.childSessionId, {
|
|
169
|
-
subagentType: taskChild.subagentType,
|
|
170
|
-
aborting: false,
|
|
171
|
-
})
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const eventSessionId = getEventSessionId(event)
|
|
176
|
-
if (!eventSessionId) {
|
|
177
|
-
return
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (event.type === 'session.deleted' || event.type === 'session.idle') {
|
|
181
|
-
subagentSessions.delete(eventSessionId)
|
|
182
|
-
return
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const rateLimitReason = extractRateLimitReason(event)
|
|
186
|
-
if (!rateLimitReason) {
|
|
187
|
-
return
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const subagent = subagentSessions.get(eventSessionId)
|
|
191
|
-
if (!subagent || subagent.aborting) {
|
|
192
|
-
return
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
subagent.aborting = true
|
|
196
|
-
const abortResult = await (async () => {
|
|
197
|
-
await client.session.abort({ sessionID: eventSessionId, directory })
|
|
198
|
-
|
|
199
|
-
await client.tui.showToast({
|
|
200
|
-
message: appendToastSessionMarker({
|
|
201
|
-
message: `Aborting ${subagent.subagentType || 'subagent'} after rate limit so the parent task can recover: ${rateLimitReason}`,
|
|
202
|
-
sessionId: eventSessionId,
|
|
203
|
-
}),
|
|
204
|
-
variant: 'info',
|
|
205
|
-
}).catch(() => {
|
|
206
|
-
return
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
logger.info(
|
|
210
|
-
`Aborted subagent ${eventSessionId} after rate limit`,
|
|
211
|
-
)
|
|
212
|
-
})()
|
|
213
|
-
.catch((error) => {
|
|
214
|
-
return new Error('Subagent rate-limit abort failed', {
|
|
215
|
-
cause: error,
|
|
216
|
-
})
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
subagentSessions.delete(eventSessionId)
|
|
220
|
-
if (!(abortResult instanceof Error)) {
|
|
221
|
-
return
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
logger.warn(`[subagent-rate-limit-plugin] ${formatPluginErrorWithStack(abortResult)}`)
|
|
225
|
-
void notifyError(abortResult, 'subagent rate-limit plugin abort failed')
|
|
226
|
-
},
|
|
227
|
-
}
|
|
228
|
-
}
|