@sunerpy/opencode-kiro-auth 0.6.2 → 0.7.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 (33) hide show
  1. package/dist/core/auth/auth-handler.js +4 -2
  2. package/dist/core/auth/idc-auth-method.js +15 -3
  3. package/dist/core/auth/token-keepalive.d.ts +27 -0
  4. package/dist/core/auth/token-keepalive.js +137 -0
  5. package/dist/core/auth/token-refresher.d.ts +20 -1
  6. package/dist/core/auth/token-refresher.js +124 -22
  7. package/dist/core/request/error-handler.d.ts +6 -3
  8. package/dist/core/request/error-handler.js +50 -24
  9. package/dist/core/request/request-handler.d.ts +2 -0
  10. package/dist/core/request/request-handler.js +5 -2
  11. package/dist/infrastructure/transformers/event-stream-parser.js +1 -1
  12. package/dist/infrastructure/transformers/tool-call-parser.js +1 -1
  13. package/dist/kiro/oauth-idc.js +54 -59
  14. package/dist/plugin/accounts.js +13 -8
  15. package/dist/plugin/config/schema.d.ts +14 -0
  16. package/dist/plugin/config/schema.js +14 -2
  17. package/dist/plugin/health.d.ts +22 -0
  18. package/dist/plugin/health.js +56 -1
  19. package/dist/plugin/image-handler.js +1 -1
  20. package/dist/plugin/logger.js +2 -2
  21. package/dist/plugin/request.js +1 -1
  22. package/dist/plugin/response.js +1 -1
  23. package/dist/plugin/storage/locked-operations.d.ts +7 -0
  24. package/dist/plugin/storage/locked-operations.js +93 -1
  25. package/dist/plugin/storage/migrations.js +1 -1
  26. package/dist/plugin/storage/sqlite.d.ts +4 -0
  27. package/dist/plugin/storage/sqlite.js +65 -3
  28. package/dist/plugin/streaming/sdk-stream-transformer.js +233 -244
  29. package/dist/plugin/streaming/stream-transformer.js +1 -1
  30. package/dist/plugin/sync/kiro-cli.js +0 -2
  31. package/dist/plugin.d.ts +2 -0
  32. package/dist/plugin.js +28 -1
  33. package/package.json +1 -1
@@ -17,7 +17,6 @@ export async function* transformSdkStream(sdkResponse, model, conversationId) {
17
17
  nextBlockIndex: 0,
18
18
  stoppedBlocks: new Set()
19
19
  };
20
- let totalContent = '';
21
20
  let textOnlyContent = '';
22
21
  let outputTokens = 0;
23
22
  let inputTokens = 0;
@@ -46,297 +45,287 @@ export async function* transformSdkStream(sdkResponse, model, conversationId) {
46
45
  if (!eventStream) {
47
46
  throw new Error('SDK response has no event stream');
48
47
  }
49
- try {
50
- for await (const event of eventStream) {
51
- if (event.reasoningContentEvent?.text) {
52
- const reasoningText = event.reasoningContentEvent.text;
53
- if (reasoningClosed) {
54
- // Defensive, normally unreached (probe: reasoning is contiguous-before-text).
55
- // The stopped thinking index cannot be reused, so open a fresh one.
56
- streamState.thinkingBlockIndex = null;
57
- reasoningClosed = false;
58
- }
59
- reasoningStarted = true;
60
- for (const ev of createThinkingDeltaEvents(reasoningText, streamState)) {
48
+ for await (const event of eventStream) {
49
+ if (event.reasoningContentEvent?.text) {
50
+ const reasoningText = event.reasoningContentEvent.text;
51
+ if (reasoningClosed) {
52
+ // Defensive, normally unreached (probe: reasoning is contiguous-before-text).
53
+ // The stopped thinking index cannot be reused, so open a fresh one.
54
+ streamState.thinkingBlockIndex = null;
55
+ reasoningClosed = false;
56
+ }
57
+ reasoningStarted = true;
58
+ for (const ev of createThinkingDeltaEvents(reasoningText, streamState)) {
59
+ const _c = convertToOpenAI(ev, conversationId, model);
60
+ if (_c !== null)
61
+ yield _c;
62
+ }
63
+ continue;
64
+ }
65
+ if (event.assistantResponseEvent?.content) {
66
+ const text = event.assistantResponseEvent.content;
67
+ textOnlyContent += text;
68
+ if (reasoningStarted && !reasoningClosed) {
69
+ for (const ev of stopBlock(streamState.thinkingBlockIndex, streamState)) {
61
70
  const _c = convertToOpenAI(ev, conversationId, model);
62
71
  if (_c !== null)
63
72
  yield _c;
64
73
  }
65
- continue;
74
+ reasoningClosed = true;
66
75
  }
67
- if (event.assistantResponseEvent?.content) {
68
- const text = event.assistantResponseEvent.content;
69
- totalContent += text;
70
- textOnlyContent += text;
71
- if (reasoningStarted && !reasoningClosed) {
72
- for (const ev of stopBlock(streamState.thinkingBlockIndex, streamState)) {
73
- const _c = convertToOpenAI(ev, conversationId, model);
74
- if (_c !== null)
75
- yield _c;
76
- }
77
- reasoningClosed = true;
76
+ if (reasoningStarted) {
77
+ for (const ev of createTextDeltaEvents(text, streamState)) {
78
+ const _c = toChunk(ev);
79
+ if (_c !== null)
80
+ yield _c;
78
81
  }
79
- if (reasoningStarted) {
80
- for (const ev of createTextDeltaEvents(text, streamState)) {
82
+ continue;
83
+ }
84
+ if (!thinkingRequested) {
85
+ for (const ev of createTextDeltaEvents(text, streamState)) {
86
+ {
81
87
  const _c = toChunk(ev);
82
88
  if (_c !== null)
83
89
  yield _c;
84
90
  }
85
- continue;
86
91
  }
87
- if (!thinkingRequested) {
88
- for (const ev of createTextDeltaEvents(text, streamState)) {
89
- {
90
- const _c = toChunk(ev);
91
- if (_c !== null)
92
- yield _c;
92
+ continue;
93
+ }
94
+ streamState.buffer += text;
95
+ const deltaEvents = [];
96
+ while (streamState.buffer.length > 0) {
97
+ if (!streamState.inThinking && !streamState.thinkingExtracted) {
98
+ const startPos = findRealTag(streamState.buffer, THINKING_START_TAG);
99
+ if (startPos !== -1) {
100
+ const before = streamState.buffer.slice(0, startPos);
101
+ if (before) {
102
+ deltaEvents.push(...createTextDeltaEvents(before, streamState));
93
103
  }
104
+ streamState.buffer = streamState.buffer.slice(startPos + THINKING_START_TAG.length);
105
+ streamState.inThinking = true;
106
+ continue;
94
107
  }
95
- continue;
96
- }
97
- streamState.buffer += text;
98
- const deltaEvents = [];
99
- while (streamState.buffer.length > 0) {
100
- if (!streamState.inThinking && !streamState.thinkingExtracted) {
101
- const startPos = findRealTag(streamState.buffer, THINKING_START_TAG);
102
- if (startPos !== -1) {
103
- const before = streamState.buffer.slice(0, startPos);
104
- if (before) {
105
- deltaEvents.push(...createTextDeltaEvents(before, streamState));
106
- }
107
- streamState.buffer = streamState.buffer.slice(startPos + THINKING_START_TAG.length);
108
- streamState.inThinking = true;
109
- continue;
110
- }
111
- const safeLen = Math.max(0, streamState.buffer.length - THINKING_START_TAG.length);
112
- if (safeLen > 0) {
113
- const safeText = streamState.buffer.slice(0, safeLen);
114
- if (safeText) {
115
- deltaEvents.push(...createTextDeltaEvents(safeText, streamState));
116
- }
117
- streamState.buffer = streamState.buffer.slice(safeLen);
108
+ const safeLen = Math.max(0, streamState.buffer.length - THINKING_START_TAG.length);
109
+ if (safeLen > 0) {
110
+ const safeText = streamState.buffer.slice(0, safeLen);
111
+ if (safeText) {
112
+ deltaEvents.push(...createTextDeltaEvents(safeText, streamState));
118
113
  }
119
- break;
114
+ streamState.buffer = streamState.buffer.slice(safeLen);
120
115
  }
121
- if (streamState.inThinking) {
122
- const endPos = findRealTag(streamState.buffer, THINKING_END_TAG);
123
- if (endPos !== -1) {
124
- const thinkingPart = streamState.buffer.slice(0, endPos);
125
- if (thinkingPart) {
126
- deltaEvents.push(...createThinkingDeltaEvents(thinkingPart, streamState));
127
- }
128
- streamState.buffer = streamState.buffer.slice(endPos + THINKING_END_TAG.length);
129
- streamState.inThinking = false;
130
- streamState.thinkingExtracted = true;
131
- deltaEvents.push(...createThinkingDeltaEvents('', streamState));
132
- deltaEvents.push(...stopBlock(streamState.thinkingBlockIndex, streamState));
133
- if (streamState.buffer.startsWith('\n\n')) {
134
- streamState.buffer = streamState.buffer.slice(2);
135
- }
136
- continue;
116
+ break;
117
+ }
118
+ if (streamState.inThinking) {
119
+ const endPos = findRealTag(streamState.buffer, THINKING_END_TAG);
120
+ if (endPos !== -1) {
121
+ const thinkingPart = streamState.buffer.slice(0, endPos);
122
+ if (thinkingPart) {
123
+ deltaEvents.push(...createThinkingDeltaEvents(thinkingPart, streamState));
137
124
  }
138
- const safeLen = Math.max(0, streamState.buffer.length - THINKING_END_TAG.length);
139
- if (safeLen > 0) {
140
- const safeThinking = streamState.buffer.slice(0, safeLen);
141
- if (safeThinking) {
142
- deltaEvents.push(...createThinkingDeltaEvents(safeThinking, streamState));
143
- }
144
- streamState.buffer = streamState.buffer.slice(safeLen);
125
+ streamState.buffer = streamState.buffer.slice(endPos + THINKING_END_TAG.length);
126
+ streamState.inThinking = false;
127
+ streamState.thinkingExtracted = true;
128
+ deltaEvents.push(...createThinkingDeltaEvents('', streamState));
129
+ deltaEvents.push(...stopBlock(streamState.thinkingBlockIndex, streamState));
130
+ if (streamState.buffer.startsWith('\n\n')) {
131
+ streamState.buffer = streamState.buffer.slice(2);
145
132
  }
146
- break;
133
+ continue;
147
134
  }
148
- if (streamState.thinkingExtracted) {
149
- const rest = streamState.buffer;
150
- streamState.buffer = '';
151
- if (rest) {
152
- deltaEvents.push(...createTextDeltaEvents(rest, streamState));
135
+ const safeLen = Math.max(0, streamState.buffer.length - THINKING_END_TAG.length);
136
+ if (safeLen > 0) {
137
+ const safeThinking = streamState.buffer.slice(0, safeLen);
138
+ if (safeThinking) {
139
+ deltaEvents.push(...createThinkingDeltaEvents(safeThinking, streamState));
153
140
  }
154
- break;
141
+ streamState.buffer = streamState.buffer.slice(safeLen);
155
142
  }
143
+ break;
156
144
  }
157
- for (const ev of deltaEvents) {
158
- const chunk = toChunk(ev);
159
- if (chunk !== null)
160
- yield chunk;
145
+ if (streamState.thinkingExtracted) {
146
+ const rest = streamState.buffer;
147
+ streamState.buffer = '';
148
+ if (rest) {
149
+ deltaEvents.push(...createTextDeltaEvents(rest, streamState));
150
+ }
151
+ break;
161
152
  }
162
153
  }
163
- else if (event.toolUseEvent) {
164
- const tc = event.toolUseEvent;
165
- if (tc.name)
166
- totalContent += tc.name;
167
- if (tc.input)
168
- totalContent += tc.input;
169
- if (tc.name && tc.toolUseId) {
170
- if (currentToolCall && currentToolCall.toolUseId === tc.toolUseId) {
171
- currentToolCall.input += tc.input || '';
172
- }
173
- else {
174
- if (currentToolCall)
175
- toolCalls.push(currentToolCall);
176
- currentToolCall = {
177
- toolUseId: tc.toolUseId,
178
- name: tc.name,
179
- input: tc.input || ''
180
- };
181
- }
182
- if (tc.stop && currentToolCall) {
154
+ for (const ev of deltaEvents) {
155
+ const chunk = toChunk(ev);
156
+ if (chunk !== null)
157
+ yield chunk;
158
+ }
159
+ }
160
+ else if (event.toolUseEvent) {
161
+ const tc = event.toolUseEvent;
162
+ if (tc.name && tc.toolUseId) {
163
+ if (currentToolCall && currentToolCall.toolUseId === tc.toolUseId) {
164
+ currentToolCall.input += tc.input || '';
165
+ }
166
+ else {
167
+ if (currentToolCall)
183
168
  toolCalls.push(currentToolCall);
184
- currentToolCall = null;
185
- }
169
+ currentToolCall = {
170
+ toolUseId: tc.toolUseId,
171
+ name: tc.name,
172
+ input: tc.input || ''
173
+ };
186
174
  }
187
- }
188
- else if (event.metadataEvent) {
189
- if (event.metadataEvent.contextUsagePercentage) {
190
- contextUsagePercentage = event.metadataEvent.contextUsagePercentage;
175
+ if (tc.stop && currentToolCall) {
176
+ toolCalls.push(currentToolCall);
177
+ currentToolCall = null;
191
178
  }
192
179
  }
193
- else if (event.contextUsageEvent) {
194
- const cue = event.contextUsageEvent;
195
- if (cue.contextUsagePercentage) {
196
- contextUsagePercentage = cue.contextUsagePercentage;
197
- }
180
+ }
181
+ else if (event.metadataEvent) {
182
+ if (event.metadataEvent.contextUsagePercentage) {
183
+ contextUsagePercentage = event.metadataEvent.contextUsagePercentage;
198
184
  }
199
185
  }
200
- if (currentToolCall) {
201
- toolCalls.push(currentToolCall);
202
- currentToolCall = null;
186
+ else if (event.contextUsageEvent) {
187
+ const cue = event.contextUsageEvent;
188
+ if (cue.contextUsagePercentage) {
189
+ contextUsagePercentage = cue.contextUsagePercentage;
190
+ }
203
191
  }
204
- // Reasoning-only responses (reasoning but no reply text): close the thinking block.
205
- if (reasoningStarted && !reasoningClosed) {
206
- for (const ev of stopBlock(streamState.thinkingBlockIndex, streamState)) {
192
+ }
193
+ if (currentToolCall) {
194
+ toolCalls.push(currentToolCall);
195
+ currentToolCall = null;
196
+ }
197
+ // Reasoning-only responses (reasoning but no reply text): close the thinking block.
198
+ if (reasoningStarted && !reasoningClosed) {
199
+ for (const ev of stopBlock(streamState.thinkingBlockIndex, streamState)) {
200
+ const _c = convertToOpenAI(ev, conversationId, model);
201
+ if (_c !== null)
202
+ yield _c;
203
+ }
204
+ reasoningClosed = true;
205
+ }
206
+ if (thinkingRequested && streamState.buffer) {
207
+ if (streamState.inThinking) {
208
+ for (const ev of createThinkingDeltaEvents(streamState.buffer, streamState)) {
207
209
  const _c = convertToOpenAI(ev, conversationId, model);
208
210
  if (_c !== null)
209
211
  yield _c;
210
212
  }
211
- reasoningClosed = true;
212
- }
213
- if (thinkingRequested && streamState.buffer) {
214
- if (streamState.inThinking) {
215
- for (const ev of createThinkingDeltaEvents(streamState.buffer, streamState)) {
216
- const _c = convertToOpenAI(ev, conversationId, model);
217
- if (_c !== null)
218
- yield _c;
219
- }
220
- streamState.buffer = '';
221
- for (const ev of createThinkingDeltaEvents('', streamState)) {
222
- const _c = convertToOpenAI(ev, conversationId, model);
223
- if (_c !== null)
224
- yield _c;
225
- }
226
- for (const ev of stopBlock(streamState.thinkingBlockIndex, streamState)) {
227
- const _c = convertToOpenAI(ev, conversationId, model);
228
- if (_c !== null)
229
- yield _c;
230
- }
213
+ streamState.buffer = '';
214
+ for (const ev of createThinkingDeltaEvents('', streamState)) {
215
+ const _c = convertToOpenAI(ev, conversationId, model);
216
+ if (_c !== null)
217
+ yield _c;
231
218
  }
232
- else {
233
- for (const ev of createTextDeltaEvents(streamState.buffer, streamState)) {
234
- const _c = toChunk(ev);
235
- if (_c !== null)
236
- yield _c;
237
- }
238
- streamState.buffer = '';
219
+ for (const ev of stopBlock(streamState.thinkingBlockIndex, streamState)) {
220
+ const _c = convertToOpenAI(ev, conversationId, model);
221
+ if (_c !== null)
222
+ yield _c;
239
223
  }
240
224
  }
241
- const { toolCalls: dialectToolCalls, remainderText } = dialectGate.finalize();
242
- if (remainderText) {
243
- for (const ev of createTextDeltaEvents(remainderText, streamState)) {
244
- const _c = convertToOpenAI(ev, conversationId, model);
225
+ else {
226
+ for (const ev of createTextDeltaEvents(streamState.buffer, streamState)) {
227
+ const _c = toChunk(ev);
245
228
  if (_c !== null)
246
229
  yield _c;
247
230
  }
231
+ streamState.buffer = '';
248
232
  }
249
- for (const ev of stopBlock(streamState.textBlockIndex, streamState)) {
233
+ }
234
+ const { toolCalls: dialectToolCalls, remainderText } = dialectGate.finalize();
235
+ if (remainderText) {
236
+ for (const ev of createTextDeltaEvents(remainderText, streamState)) {
250
237
  const _c = convertToOpenAI(ev, conversationId, model);
251
238
  if (_c !== null)
252
239
  yield _c;
253
240
  }
254
- if (dialectToolCalls.length > 0) {
255
- for (const btc of dialectToolCalls) {
256
- toolCalls.push({
257
- toolUseId: btc.toolUseId,
258
- name: btc.name,
259
- input: typeof btc.input === 'string' ? btc.input : JSON.stringify(btc.input)
260
- });
261
- }
241
+ }
242
+ for (const ev of stopBlock(streamState.textBlockIndex, streamState)) {
243
+ const _c = convertToOpenAI(ev, conversationId, model);
244
+ if (_c !== null)
245
+ yield _c;
246
+ }
247
+ if (dialectToolCalls.length > 0) {
248
+ for (const btc of dialectToolCalls) {
249
+ toolCalls.push({
250
+ toolUseId: btc.toolUseId,
251
+ name: btc.name,
252
+ input: typeof btc.input === 'string' ? btc.input : JSON.stringify(btc.input)
253
+ });
262
254
  }
263
- if (toolCalls.length > 0) {
264
- // OpenAI tool_calls[].index must be the tool call's own 0-based ordinal,
265
- // NOT the Anthropic content_block global index (offset by reasoning/text
266
- // blocks) a global index misaligns the AI-SDK accumulator and drops the call.
267
- for (let i = 0; i < toolCalls.length; i++) {
268
- const tc = toolCalls[i];
269
- if (!tc)
270
- continue;
271
- const blockIndex = i;
272
- {
273
- const _c = convertToOpenAI({
274
- type: 'content_block_start',
275
- index: blockIndex,
276
- content_block: {
277
- type: 'tool_use',
278
- id: tc.toolUseId,
279
- name: tc.name,
280
- input: {}
281
- }
282
- }, conversationId, model);
283
- if (_c !== null)
284
- yield _c;
285
- }
286
- let inputJson;
287
- try {
288
- const parsed = JSON.parse(tc.input);
289
- inputJson = JSON.stringify(parsed);
290
- }
291
- catch (e) {
292
- inputJson = tc.input;
293
- }
294
- {
295
- const _c = convertToOpenAI({
296
- type: 'content_block_delta',
297
- index: blockIndex,
298
- delta: {
299
- type: 'input_json_delta',
300
- partial_json: inputJson
301
- }
302
- }, conversationId, model);
303
- if (_c !== null)
304
- yield _c;
305
- }
306
- {
307
- const _c = convertToOpenAI({ type: 'content_block_stop', index: blockIndex }, conversationId, model);
308
- if (_c !== null)
309
- yield _c;
310
- }
255
+ }
256
+ if (toolCalls.length > 0) {
257
+ // OpenAI tool_calls[].index must be the tool call's own 0-based ordinal,
258
+ // NOT the Anthropic content_block global index (offset by reasoning/text
259
+ // blocks) a global index misaligns the AI-SDK accumulator and drops the call.
260
+ for (let i = 0; i < toolCalls.length; i++) {
261
+ const tc = toolCalls[i];
262
+ if (!tc)
263
+ continue;
264
+ const blockIndex = i;
265
+ {
266
+ const _c = convertToOpenAI({
267
+ type: 'content_block_start',
268
+ index: blockIndex,
269
+ content_block: {
270
+ type: 'tool_use',
271
+ id: tc.toolUseId,
272
+ name: tc.name,
273
+ input: {}
274
+ }
275
+ }, conversationId, model);
276
+ if (_c !== null)
277
+ yield _c;
278
+ }
279
+ let inputJson;
280
+ try {
281
+ const parsed = JSON.parse(tc.input);
282
+ inputJson = JSON.stringify(parsed);
283
+ }
284
+ catch {
285
+ inputJson = tc.input;
286
+ }
287
+ {
288
+ const _c = convertToOpenAI({
289
+ type: 'content_block_delta',
290
+ index: blockIndex,
291
+ delta: {
292
+ type: 'input_json_delta',
293
+ partial_json: inputJson
294
+ }
295
+ }, conversationId, model);
296
+ if (_c !== null)
297
+ yield _c;
298
+ }
299
+ {
300
+ const _c = convertToOpenAI({ type: 'content_block_stop', index: blockIndex }, conversationId, model);
301
+ if (_c !== null)
302
+ yield _c;
311
303
  }
312
304
  }
313
- outputTokens = estimateTokens(textOnlyContent);
314
- if (contextUsagePercentage !== null && contextUsagePercentage > 0) {
315
- const contextWindow = getContextWindowSize(model);
316
- const totalTokens = Math.round((contextWindow * contextUsagePercentage) / 100);
317
- inputTokens = Math.max(0, totalTokens - outputTokens);
318
- }
319
- {
320
- const _c = convertToOpenAI({
321
- type: 'message_delta',
322
- delta: { stop_reason: toolCalls.length > 0 ? 'tool_use' : 'end_turn' },
323
- usage: {
324
- input_tokens: inputTokens,
325
- output_tokens: outputTokens,
326
- cache_creation_input_tokens: 0,
327
- cache_read_input_tokens: 0
328
- }
329
- }, conversationId, model);
330
- if (_c !== null)
331
- yield _c;
332
- }
333
- {
334
- const _c = convertToOpenAI({ type: 'message_stop' }, conversationId, model);
335
- if (_c !== null)
336
- yield _c;
337
- }
338
305
  }
339
- catch (e) {
340
- throw e;
306
+ outputTokens = estimateTokens(textOnlyContent);
307
+ if (contextUsagePercentage !== null && contextUsagePercentage > 0) {
308
+ const contextWindow = getContextWindowSize(model);
309
+ const totalTokens = Math.round((contextWindow * contextUsagePercentage) / 100);
310
+ inputTokens = Math.max(0, totalTokens - outputTokens);
311
+ }
312
+ {
313
+ const _c = convertToOpenAI({
314
+ type: 'message_delta',
315
+ delta: { stop_reason: toolCalls.length > 0 ? 'tool_use' : 'end_turn' },
316
+ usage: {
317
+ input_tokens: inputTokens,
318
+ output_tokens: outputTokens,
319
+ cache_creation_input_tokens: 0,
320
+ cache_read_input_tokens: 0
321
+ }
322
+ }, conversationId, model);
323
+ if (_c !== null)
324
+ yield _c;
325
+ }
326
+ {
327
+ const _c = convertToOpenAI({ type: 'message_stop' }, conversationId, model);
328
+ if (_c !== null)
329
+ yield _c;
341
330
  }
342
331
  }
@@ -243,7 +243,7 @@ export async function* transformKiroStream(response, model, conversationId) {
243
243
  const parsed = JSON.parse(tc.input);
244
244
  inputJson = JSON.stringify(parsed);
245
245
  }
246
- catch (e) {
246
+ catch {
247
247
  inputJson = tc.input;
248
248
  }
249
249
  {
@@ -65,7 +65,6 @@ export async function syncFromKiroCli() {
65
65
  let usedCount = 0;
66
66
  let limitCount = 0;
67
67
  let email;
68
- let usageOk = false;
69
68
  try {
70
69
  const authForUsage = {
71
70
  refresh: '',
@@ -83,7 +82,6 @@ export async function syncFromKiroCli() {
83
82
  limitCount = u.limitCount || 0;
84
83
  if (typeof u.email === 'string' && u.email) {
85
84
  email = u.email;
86
- usageOk = true;
87
85
  }
88
86
  }
89
87
  catch (e) {
package/dist/plugin.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { KeepAliveController } from './core/auth/token-keepalive.js';
2
+ export declare function __getActiveKeepAliveControllerForTest(): KeepAliveController | null;
1
3
  export declare const createKiroPlugin: (id: string) => ({ client, directory }: any) => Promise<{
2
4
  config: (input: any) => Promise<void>;
3
5
  auth: {
package/dist/plugin.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { KIRO_CONSTANTS } from './constants.js';
2
2
  import { AuthHandler } from './core/auth/auth-handler.js';
3
+ import { KeepAliveController } from './core/auth/token-keepalive.js';
3
4
  import { RequestHandler } from './core/request/request-handler.js';
4
5
  import { AccountCache } from './infrastructure/database/account-cache.js';
5
6
  import { AccountRepository } from './infrastructure/database/account-repository.js';
@@ -7,6 +8,31 @@ import { AccountManager } from './plugin/accounts.js';
7
8
  import { bootstrapAuthIfNeeded } from './plugin/auth-bootstrap.js';
8
9
  import { loadConfig } from './plugin/config/index.js';
9
10
  const KIRO_PROVIDER_ID = 'kiro-auth';
11
+ let activeKeepAliveController = null;
12
+ let keepAliveTeardownRegistered = false;
13
+ function disposeActiveKeepAliveController() {
14
+ activeKeepAliveController?.dispose();
15
+ activeKeepAliveController = null;
16
+ }
17
+ function registerKeepAliveTeardown() {
18
+ if (keepAliveTeardownRegistered) {
19
+ return;
20
+ }
21
+ keepAliveTeardownRegistered = true;
22
+ process.once('beforeExit', disposeActiveKeepAliveController);
23
+ process.once('SIGTERM', disposeActiveKeepAliveController);
24
+ }
25
+ function installKeepAliveController(controller, enabled) {
26
+ disposeActiveKeepAliveController();
27
+ activeKeepAliveController = controller;
28
+ if (enabled) {
29
+ registerKeepAliveTeardown();
30
+ }
31
+ controller.start();
32
+ }
33
+ export function __getActiveKeepAliveControllerForTest() {
34
+ return activeKeepAliveController;
35
+ }
10
36
  export const createKiroPlugin = (id) => async ({ client, directory }) => {
11
37
  const config = loadConfig(directory);
12
38
  const showToast = (message, variant) => {
@@ -21,6 +47,7 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
21
47
  });
22
48
  authHandler.setAccountManager(accountManager);
23
49
  const requestHandler = new RequestHandler(accountManager, config, repository, client);
50
+ installKeepAliveController(new KeepAliveController(config, accountManager, requestHandler.sharedTokenRefresher, repository), config.token_keepalive_enabled);
24
51
  // Compute the base URL once so both the config hook and auth loader use the same value
25
52
  const baseURL = KIRO_CONSTANTS.BASE_URL.replace('/generateAssistantResponse', '').replace('{{region}}', config.default_region || 'us-east-1');
26
53
  return {
@@ -251,7 +278,7 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
251
278
  normalized[modelID] = {
252
279
  ...modelInfo,
253
280
  api: {
254
- ...(modelInfo.api || {}),
281
+ ...modelInfo.api,
255
282
  npm: '@ai-sdk/openai-compatible',
256
283
  // Ensure url is always set. modelInfo.api.url should already be
257
284
  // populated from the config hook's provider.api field, but we
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sunerpy/opencode-kiro-auth",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "OpenCode plugin for AWS Kiro (CodeWhisperer) providing access to Claude models",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",