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.
Files changed (214) hide show
  1. package/dist/agent-model.e2e.test.js +25 -122
  2. package/dist/anthropic-account-identity.js +1 -0
  3. package/dist/anthropic-auth-plugin.js +1 -0
  4. package/dist/anthropic-auth-state.js +1 -0
  5. package/dist/bin.js +73 -19
  6. package/dist/cli-commands/maintenance.js +46 -7
  7. package/dist/cli-commands/send.js +24 -0
  8. package/dist/cli-commands/session.js +183 -8
  9. package/dist/cli-commands/task.js +13 -1
  10. package/dist/cli-parsing.test.js +59 -3
  11. package/dist/cli-runner.js +28 -4
  12. package/dist/cli-runner.test.js +27 -0
  13. package/dist/cli-send-thread.e2e.test.js +1 -1
  14. package/dist/cli.js +32 -0
  15. package/dist/commands/abort.js +5 -1
  16. package/dist/commands/agent.js +6 -8
  17. package/dist/commands/ask-question.js +21 -32
  18. package/dist/commands/ask-question.test.js +43 -1
  19. package/dist/commands/login.js +6 -0
  20. package/dist/commands/merge-worktree.js +36 -10
  21. package/dist/commands/model-variant.js +7 -1
  22. package/dist/commands/model.js +14 -8
  23. package/dist/commands/multioauth.js +1 -0
  24. package/dist/commands/new-worktree.js +170 -102
  25. package/dist/commands/user-command.js +6 -8
  26. package/dist/commands/worktrees.js +5 -13
  27. package/dist/config.js +16 -1
  28. package/dist/database.js +124 -3
  29. package/dist/db.js +22 -0
  30. package/dist/db.test.js +167 -1
  31. package/dist/discord-bot.js +34 -32
  32. package/dist/discord-command-registration.js +9 -1
  33. package/dist/discord-utils.js +13 -5
  34. package/dist/discord-utils.test.js +17 -1
  35. package/dist/errors.js +5 -0
  36. package/dist/exec-async.js +17 -5
  37. package/dist/external-directory-permissions.e2e.test.js +2 -2
  38. package/dist/file-edit-log.js +197 -0
  39. package/dist/file-edit-log.test.js +258 -0
  40. package/dist/format-tables.js +52 -0
  41. package/dist/format-tables.test.js +93 -0
  42. package/dist/gateway-proxy-reconnect.e2e.test.js +28 -8
  43. package/dist/gateway-proxy.e2e.test.js +5 -5
  44. package/dist/git-worktree-core.js +182 -17
  45. package/dist/ipc-tools-plugin.js +63 -3
  46. package/dist/kimaki-opencode-plugin-loading.e2e.test.js +122 -58
  47. package/dist/kimaki-opencode-plugin.js +7 -3
  48. package/dist/kimaki-workspace-adaptor.js +33 -10
  49. package/dist/logger.js +10 -1
  50. package/dist/markdown.js +3 -1
  51. package/dist/markdown.test.js +11 -3
  52. package/dist/message-formatting.js +18 -7
  53. package/dist/message-formatting.test.js +56 -9
  54. package/dist/oauth-rotation-shared.js +10 -0
  55. package/dist/openai-auth-plugin.js +1 -0
  56. package/dist/openai-auth-state.js +1 -0
  57. package/dist/opencode-command.test.js +60 -0
  58. package/dist/opencode.js +53 -12
  59. package/dist/question-abort-clears-dropdown.e2e.test.js +89 -0
  60. package/dist/question-text-before-dropdown.e2e.test.js +52 -0
  61. package/dist/queue-advanced-abort.e2e.test.js +1 -1
  62. package/dist/queue-advanced-action-buttons.e2e.test.js +3 -3
  63. package/dist/queue-advanced-e2e-setup.js +78 -5
  64. package/dist/queue-advanced-footer.e2e.test.js +40 -246
  65. package/dist/queue-advanced-model-switch.e2e.test.js +2 -2
  66. package/dist/queue-advanced-permissions-typing.e2e.test.js +7 -9
  67. package/dist/queue-advanced-question.e2e.test.js +31 -26
  68. package/dist/queue-advanced-typing-interrupt.e2e.test.js +2 -2
  69. package/dist/queue-delete-message.e2e.test.js +1 -1
  70. package/dist/queue-drain-after-interactive-ui.e2e.test.js +2 -2
  71. package/dist/queue-interrupt-drain.e2e.test.js +112 -2
  72. package/dist/queue-question-select-drain.e2e.test.js +30 -128
  73. package/dist/runtime-lifecycle.e2e.test.js +10 -37
  74. package/dist/schema.js +34 -0
  75. package/dist/session-handler/event-stream-state.js +267 -50
  76. package/dist/session-handler/event-stream-state.test.js +415 -8
  77. package/dist/session-handler/model-utils.js +159 -5
  78. package/dist/session-handler/model-utils.test.js +345 -0
  79. package/dist/session-handler/thread-session-runtime.js +252 -182
  80. package/dist/session-sleep.test.js +224 -0
  81. package/dist/session-title-rename.test.js +7 -39
  82. package/dist/sleep.e2e.test.js +491 -0
  83. package/dist/startup-time.e2e.test.js +2 -1
  84. package/dist/store.js +3 -0
  85. package/dist/system-message.js +59 -6
  86. package/dist/system-message.test.js +76 -6
  87. package/dist/task-runner.js +94 -4
  88. package/dist/task-schedule.js +56 -0
  89. package/dist/task-schedule.test.js +71 -1
  90. package/dist/thread-message-queue.e2e.test.js +10 -169
  91. package/dist/undo-redo.e2e.test.js +2 -2
  92. package/dist/voice-attachment.js +23 -1
  93. package/dist/voice-message.e2e.test.js +10 -10
  94. package/dist/voice.test.js +55 -29
  95. package/dist/worktree-clone-isolation.e2e.test.js +188 -0
  96. package/dist/worktree-lifecycle.e2e.test.js +29 -10
  97. package/dist/worktrees.js +226 -443
  98. package/dist/worktrees.test.js +435 -58
  99. package/dist/xai-auth-plugin.js +1 -0
  100. package/dist/xai-auth-state.js +1 -0
  101. package/package.json +8 -6
  102. package/skills/errore/SKILL.md +18 -0
  103. package/skills/goke/SKILL.md +150 -10
  104. package/skills/holocron/SKILL.md +37 -0
  105. package/skills/npm-package/SKILL.md +55 -35
  106. package/skills/profano/SKILL.md +17 -2
  107. package/skills/spiceflow/SKILL.md +39 -3
  108. package/skills/strada/SKILL.md +39 -0
  109. package/skills/zele/SKILL.md +19 -0
  110. package/src/agent-model.e2e.test.ts +25 -151
  111. package/src/anthropic-account-identity.ts +1 -0
  112. package/src/anthropic-auth-plugin.ts +1 -0
  113. package/src/anthropic-auth-state.ts +1 -0
  114. package/src/bin.ts +78 -26
  115. package/src/cli-commands/maintenance.ts +59 -13
  116. package/src/cli-commands/send.ts +25 -0
  117. package/src/cli-commands/session.ts +203 -9
  118. package/src/cli-commands/task.ts +13 -1
  119. package/src/cli-parsing.test.ts +69 -3
  120. package/src/cli-runner.test.ts +49 -0
  121. package/src/cli-runner.ts +28 -4
  122. package/src/cli-send-thread.e2e.test.ts +1 -1
  123. package/src/cli.ts +53 -0
  124. package/src/commands/abort.ts +6 -1
  125. package/src/commands/agent.ts +6 -6
  126. package/src/commands/ask-question.test.ts +48 -1
  127. package/src/commands/ask-question.ts +21 -32
  128. package/src/commands/login.ts +6 -0
  129. package/src/commands/merge-worktree.ts +43 -12
  130. package/src/commands/model-variant.ts +8 -1
  131. package/src/commands/model.ts +18 -8
  132. package/src/commands/multioauth.ts +1 -0
  133. package/src/commands/new-worktree.ts +138 -55
  134. package/src/commands/user-command.ts +6 -6
  135. package/src/commands/worktrees.ts +5 -12
  136. package/src/config.ts +18 -1
  137. package/src/database.ts +195 -3
  138. package/src/db.test.ts +188 -0
  139. package/src/db.ts +26 -0
  140. package/src/discord-bot.ts +35 -29
  141. package/src/discord-command-registration.ts +15 -1
  142. package/src/discord-utils.test.ts +19 -0
  143. package/src/discord-utils.ts +21 -6
  144. package/src/errors.ts +5 -0
  145. package/src/exec-async.ts +20 -11
  146. package/src/external-directory-permissions.e2e.test.ts +2 -2
  147. package/src/file-edit-log.test.ts +287 -0
  148. package/src/file-edit-log.ts +283 -0
  149. package/src/format-tables.test.ts +101 -0
  150. package/src/format-tables.ts +75 -0
  151. package/src/gateway-proxy-reconnect.e2e.test.ts +38 -8
  152. package/src/gateway-proxy.e2e.test.ts +5 -5
  153. package/src/git-worktree-core.ts +247 -20
  154. package/src/ipc-tools-plugin.ts +75 -5
  155. package/src/kimaki-opencode-plugin-loading.e2e.test.ts +188 -97
  156. package/src/kimaki-opencode-plugin.ts +7 -3
  157. package/src/kimaki-workspace-adaptor.ts +40 -11
  158. package/src/logger.ts +13 -4
  159. package/src/markdown.test.ts +13 -3
  160. package/src/markdown.ts +4 -1
  161. package/src/message-formatting.test.ts +86 -12
  162. package/src/message-formatting.ts +19 -7
  163. package/src/oauth-rotation-shared.ts +10 -0
  164. package/src/openai-auth-plugin.ts +1 -0
  165. package/src/openai-auth-state.ts +1 -0
  166. package/src/opencode-command.test.ts +81 -0
  167. package/src/opencode.ts +71 -11
  168. package/src/question-abort-clears-dropdown.e2e.test.ts +109 -0
  169. package/src/question-text-before-dropdown.e2e.test.ts +67 -0
  170. package/src/queue-advanced-abort.e2e.test.ts +1 -1
  171. package/src/queue-advanced-action-buttons.e2e.test.ts +3 -3
  172. package/src/queue-advanced-e2e-setup.ts +83 -4
  173. package/src/queue-advanced-footer.e2e.test.ts +47 -294
  174. package/src/queue-advanced-model-switch.e2e.test.ts +2 -2
  175. package/src/queue-advanced-permissions-typing.e2e.test.ts +7 -9
  176. package/src/queue-advanced-question.e2e.test.ts +35 -29
  177. package/src/queue-advanced-typing-interrupt.e2e.test.ts +2 -2
  178. package/src/queue-delete-message.e2e.test.ts +1 -1
  179. package/src/queue-drain-after-interactive-ui.e2e.test.ts +2 -2
  180. package/src/queue-interrupt-drain.e2e.test.ts +123 -2
  181. package/src/queue-question-select-drain.e2e.test.ts +32 -157
  182. package/src/runtime-lifecycle.e2e.test.ts +10 -41
  183. package/src/schema.sql +14 -1
  184. package/src/schema.ts +36 -0
  185. package/src/session-handler/event-stream-state.test.ts +437 -7
  186. package/src/session-handler/event-stream-state.ts +389 -53
  187. package/src/session-handler/model-utils.test.ts +415 -0
  188. package/src/session-handler/model-utils.ts +249 -5
  189. package/src/session-handler/thread-session-runtime.ts +300 -215
  190. package/src/session-sleep.test.ts +294 -0
  191. package/src/session-title-rename.test.ts +9 -48
  192. package/src/sleep.e2e.test.ts +562 -0
  193. package/src/startup-time.e2e.test.ts +5 -1
  194. package/src/store.ts +21 -0
  195. package/src/system-message.test.ts +86 -6
  196. package/src/system-message.ts +66 -7
  197. package/src/task-runner.ts +136 -2
  198. package/src/task-schedule.test.ts +76 -0
  199. package/src/task-schedule.ts +95 -0
  200. package/src/thread-message-queue.e2e.test.ts +10 -202
  201. package/src/undo-redo.e2e.test.ts +2 -2
  202. package/src/voice-attachment.ts +29 -1
  203. package/src/voice-message.e2e.test.ts +10 -10
  204. package/src/voice.test.ts +63 -29
  205. package/src/worktree-clone-isolation.e2e.test.ts +213 -0
  206. package/src/worktree-lifecycle.e2e.test.ts +29 -9
  207. package/src/worktrees.test.ts +505 -64
  208. package/src/worktrees.ts +257 -603
  209. package/src/xai-auth-plugin.ts +1 -0
  210. package/src/xai-auth-state.ts +1 -0
  211. package/dist/message-finish-field.e2e.test.js +0 -169
  212. package/dist/subagent-rate-limit-plugin.js +0 -184
  213. package/src/message-finish-field.e2e.test.ts +0 -196
  214. 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
- }