@javargasm/opencode-kiro-auth 0.1.2 → 0.2.1

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/index.js CHANGED
@@ -117,13 +117,430 @@ var init_debug = __esm(() => {
117
117
  };
118
118
  });
119
119
 
120
+ // src/models.ts
121
+ var exports_models = {};
122
+ __export(exports_models, {
123
+ setCachedDynamicModels: () => setCachedDynamicModels,
124
+ seedProfileArn: () => seedProfileArn,
125
+ resolveProfileArn: () => resolveProfileArn,
126
+ resolveKiroModel: () => resolveKiroModel,
127
+ resolveApiRegion: () => resolveApiRegion,
128
+ resetProfileArnCache: () => resetProfileArnCache,
129
+ kiroModels: () => kiroModels,
130
+ getCachedDynamicModels: () => getCachedDynamicModels,
131
+ fetchAvailableModels: () => fetchAvailableModels,
132
+ dotToDash: () => dotToDash,
133
+ buildModelsFromApi: () => buildModelsFromApi,
134
+ KIRO_MODEL_IDS: () => KIRO_MODEL_IDS
135
+ });
136
+ function dotToDash(modelId) {
137
+ return modelId.replace(/(\d)\.(\d)/g, "$1-$2");
138
+ }
139
+ function resolveKiroModel(modelId) {
140
+ const kiroId = modelId.replace(/(\d)-(\d)/g, "$1.$2");
141
+ if (!KIRO_MODEL_IDS.has(kiroId)) {
142
+ throw new Error(`Unknown Kiro model ID: ${modelId}`);
143
+ }
144
+ return kiroId;
145
+ }
146
+ function resolveApiRegion(ssoRegion) {
147
+ if (!ssoRegion)
148
+ return "us-east-1";
149
+ return API_REGION_MAP[ssoRegion] ?? ssoRegion;
150
+ }
151
+ function resetProfileArnCache(skipResolution = false) {
152
+ cachedProfileArn = null;
153
+ profileArnSkipResolution = skipResolution;
154
+ }
155
+ function seedProfileArn(arn) {
156
+ cachedProfileArn = arn;
157
+ }
158
+ async function resolveProfileArn(accessToken, apiRegion) {
159
+ if (profileArnSkipResolution)
160
+ return null;
161
+ if (cachedProfileArn !== null)
162
+ return cachedProfileArn;
163
+ const endpoint = `https://management.${apiRegion}.kiro.dev/`;
164
+ const resp = await fetch(endpoint, {
165
+ method: "POST",
166
+ headers: {
167
+ Authorization: `Bearer ${accessToken}`,
168
+ "Content-Type": "application/x-amz-json-1.0",
169
+ "X-Amz-Target": "AmazonCodeWhispererService.ListAvailableProfiles",
170
+ "user-agent": "aws-sdk-rust/1.3.15 ua/2.1 api/codewhispererruntime/0.1.16551 os/macos lang/rust/1.92.0 md/appVersion-2.7.1 app/AmazonQ-For-CLI"
171
+ },
172
+ body: "{}"
173
+ });
174
+ if (!resp || !resp.ok)
175
+ return null;
176
+ const data = await resp.json();
177
+ const profiles = data.profiles ?? [];
178
+ const kiroProfile = profiles.find((p) => p.profileType === "KIRO" && p.status === "ACTIVE");
179
+ const arn = kiroProfile?.arn ?? profiles[0]?.arn ?? null;
180
+ if (arn) {
181
+ cachedProfileArn = arn;
182
+ }
183
+ return arn;
184
+ }
185
+ async function fetchAvailableModels(accessToken, apiRegion, profileArn) {
186
+ const url = `https://management.${apiRegion}.kiro.dev/?origin=KIRO_CLI&profileArn=${encodeURIComponent(profileArn)}`;
187
+ const resp = await fetch(url, {
188
+ method: "POST",
189
+ headers: {
190
+ Authorization: `Bearer ${accessToken}`,
191
+ "Content-Type": "application/x-amz-json-1.0",
192
+ "X-Amz-Target": "AmazonCodeWhispererService.ListAvailableModels",
193
+ "user-agent": "aws-sdk-rust/1.3.15 ua/2.1 api/codewhispererruntime/0.1.16551 os/macos lang/rust/1.92.0 md/appVersion-2.7.1 app/AmazonQ-For-CLI"
194
+ },
195
+ body: "{}"
196
+ });
197
+ if (!resp.ok) {
198
+ throw new Error(`ListAvailableModels failed: HTTP ${resp.status}`);
199
+ }
200
+ const data = await resp.json();
201
+ return (data.models ?? []).filter((m) => m.modelId !== "auto");
202
+ }
203
+ function isReasoningModel(dotId) {
204
+ for (const family of REASONING_FAMILIES) {
205
+ if (dotId.startsWith(family))
206
+ return true;
207
+ }
208
+ return false;
209
+ }
210
+ function firstTokenTimeout(dotId) {
211
+ if (dotId.startsWith("claude-fable") || dotId.startsWith("claude-opus"))
212
+ return 180000;
213
+ return 90000;
214
+ }
215
+ function buildModelsFromApi(apiModels) {
216
+ return apiModels.map((m) => {
217
+ KIRO_MODEL_IDS.add(m.modelId);
218
+ const dashId = dotToDash(m.modelId);
219
+ const supportedTypes = m.supportedInputTypes ?? ["TEXT"];
220
+ const input = supportedTypes.includes("IMAGE") ? ["text", "image"] : ["text"];
221
+ const effortEnum = m.additionalModelRequestFieldsSchema?.properties?.output_config?.properties?.effort?.enum;
222
+ const supportedEfforts = Array.isArray(effortEnum) && effortEnum.length > 0 ? effortEnum : undefined;
223
+ const supportsThinkingConfig = !!m.additionalModelRequestFieldsSchema?.properties?.thinking;
224
+ return {
225
+ ...KIRO_DEFAULTS,
226
+ id: dashId,
227
+ name: m.modelName,
228
+ reasoning: isReasoningModel(m.modelId),
229
+ input,
230
+ contextWindow: m.tokenLimits?.maxInputTokens ?? 200000,
231
+ maxTokens: m.tokenLimits?.maxOutputTokens ?? 8192,
232
+ firstTokenTimeout: firstTokenTimeout(m.modelId),
233
+ ...supportedEfforts ? { supportedEfforts } : {},
234
+ ...supportsThinkingConfig ? { supportsThinkingConfig } : {}
235
+ };
236
+ });
237
+ }
238
+ function getCachedDynamicModels() {
239
+ return cachedDynamicModels;
240
+ }
241
+ function setCachedDynamicModels(models) {
242
+ cachedDynamicModels = models;
243
+ }
244
+ var KIRO_MODEL_IDS, API_REGION_MAP, BASE_URL = "https://runtime.us-east-1.kiro.dev", ZERO_COST, KIRO_DEFAULTS, MULTIMODAL, TEXT_ONLY, kiroModels, cachedProfileArn = null, profileArnSkipResolution = false, REASONING_FAMILIES, cachedDynamicModels = null;
245
+ var init_models = __esm(() => {
246
+ KIRO_MODEL_IDS = new Set([
247
+ "claude-fable-5",
248
+ "claude-opus-4.8",
249
+ "claude-opus-4.7",
250
+ "claude-opus-4.6",
251
+ "claude-opus-4.6-1m",
252
+ "claude-sonnet-4.6",
253
+ "claude-sonnet-4.6-1m",
254
+ "claude-opus-4.5",
255
+ "claude-sonnet-4.5",
256
+ "claude-sonnet-4.5-1m",
257
+ "claude-sonnet-4",
258
+ "claude-haiku-4.5",
259
+ "deepseek-3.2",
260
+ "kimi-k2.5",
261
+ "minimax-m2.1",
262
+ "minimax-m2.5",
263
+ "glm-4.7",
264
+ "glm-4.7-flash",
265
+ "qwen3-coder-next",
266
+ "agi-nova-beta-1m",
267
+ "qwen3-coder-480b",
268
+ "auto"
269
+ ]);
270
+ API_REGION_MAP = {
271
+ "us-west-1": "us-east-1",
272
+ "us-west-2": "us-east-1",
273
+ "us-east-2": "us-east-1",
274
+ "eu-west-1": "eu-central-1",
275
+ "eu-west-2": "eu-central-1",
276
+ "eu-west-3": "eu-central-1",
277
+ "eu-north-1": "eu-central-1",
278
+ "eu-south-1": "eu-central-1",
279
+ "eu-south-2": "eu-central-1",
280
+ "eu-central-2": "eu-central-1",
281
+ "ap-northeast-1": "us-east-1",
282
+ "ap-northeast-2": "us-east-1",
283
+ "ap-northeast-3": "us-east-1",
284
+ "ap-southeast-1": "us-east-1",
285
+ "ap-southeast-2": "us-east-1",
286
+ "ap-south-1": "us-east-1",
287
+ "ap-east-1": "us-east-1",
288
+ "ap-south-2": "us-east-1",
289
+ "ap-southeast-3": "us-east-1",
290
+ "ap-southeast-4": "us-east-1"
291
+ };
292
+ ZERO_COST = Object.freeze({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0 });
293
+ KIRO_DEFAULTS = {
294
+ api: "kiro-api",
295
+ provider: "kiro",
296
+ baseUrl: BASE_URL,
297
+ cost: ZERO_COST
298
+ };
299
+ MULTIMODAL = ["text", "image"];
300
+ TEXT_ONLY = ["text"];
301
+ kiroModels = [
302
+ {
303
+ ...KIRO_DEFAULTS,
304
+ id: "claude-fable-5",
305
+ name: "Claude Fable 5",
306
+ reasoning: true,
307
+ input: MULTIMODAL,
308
+ contextWindow: 1e6,
309
+ maxTokens: 128000,
310
+ firstTokenTimeout: 180000,
311
+ supportedEfforts: ["low", "medium", "high", "xhigh", "max"],
312
+ supportsThinkingConfig: true
313
+ },
314
+ {
315
+ ...KIRO_DEFAULTS,
316
+ id: "claude-opus-4-8",
317
+ name: "Claude Opus 4.8",
318
+ reasoning: true,
319
+ input: MULTIMODAL,
320
+ contextWindow: 1e6,
321
+ maxTokens: 128000,
322
+ firstTokenTimeout: 180000,
323
+ supportedEfforts: ["low", "medium", "high", "xhigh", "max"],
324
+ supportsThinkingConfig: true
325
+ },
326
+ {
327
+ ...KIRO_DEFAULTS,
328
+ id: "claude-opus-4-7",
329
+ name: "Claude Opus 4.7",
330
+ reasoning: true,
331
+ input: MULTIMODAL,
332
+ contextWindow: 1e6,
333
+ maxTokens: 128000,
334
+ firstTokenTimeout: 180000,
335
+ supportedEfforts: ["low", "medium", "high", "xhigh", "max"],
336
+ supportsThinkingConfig: true
337
+ },
338
+ {
339
+ ...KIRO_DEFAULTS,
340
+ id: "claude-opus-4-6",
341
+ name: "Claude Opus 4.6",
342
+ reasoning: true,
343
+ input: MULTIMODAL,
344
+ contextWindow: 1e6,
345
+ maxTokens: 64000,
346
+ supportedEfforts: ["low", "medium", "high", "max"],
347
+ supportsThinkingConfig: true
348
+ },
349
+ {
350
+ ...KIRO_DEFAULTS,
351
+ id: "claude-opus-4-6-1m",
352
+ name: "Claude Opus 4.6 (1M)",
353
+ reasoning: true,
354
+ input: MULTIMODAL,
355
+ contextWindow: 1e6,
356
+ maxTokens: 64000,
357
+ supportedEfforts: ["low", "medium", "high", "max"],
358
+ supportsThinkingConfig: true
359
+ },
360
+ {
361
+ ...KIRO_DEFAULTS,
362
+ id: "claude-sonnet-4-6",
363
+ name: "Claude Sonnet 4.6",
364
+ reasoning: true,
365
+ input: MULTIMODAL,
366
+ contextWindow: 1e6,
367
+ maxTokens: 64000,
368
+ supportedEfforts: ["low", "medium", "high", "max"],
369
+ supportsThinkingConfig: true
370
+ },
371
+ {
372
+ ...KIRO_DEFAULTS,
373
+ id: "claude-sonnet-4-6-1m",
374
+ name: "Claude Sonnet 4.6 (1M)",
375
+ reasoning: true,
376
+ input: MULTIMODAL,
377
+ contextWindow: 1e6,
378
+ maxTokens: 64000,
379
+ supportedEfforts: ["low", "medium", "high", "max"],
380
+ supportsThinkingConfig: true
381
+ },
382
+ {
383
+ ...KIRO_DEFAULTS,
384
+ id: "claude-opus-4-5",
385
+ name: "Claude Opus 4.5",
386
+ reasoning: true,
387
+ input: MULTIMODAL,
388
+ contextWindow: 200000,
389
+ maxTokens: 64000
390
+ },
391
+ {
392
+ ...KIRO_DEFAULTS,
393
+ id: "claude-sonnet-4-5",
394
+ name: "Claude Sonnet 4.5",
395
+ reasoning: true,
396
+ input: MULTIMODAL,
397
+ contextWindow: 200000,
398
+ maxTokens: 65536
399
+ },
400
+ {
401
+ ...KIRO_DEFAULTS,
402
+ id: "claude-sonnet-4-5-1m",
403
+ name: "Claude Sonnet 4.5 (1M)",
404
+ reasoning: true,
405
+ input: MULTIMODAL,
406
+ contextWindow: 1e6,
407
+ maxTokens: 65536
408
+ },
409
+ {
410
+ ...KIRO_DEFAULTS,
411
+ id: "claude-sonnet-4",
412
+ name: "Claude Sonnet 4",
413
+ reasoning: true,
414
+ input: MULTIMODAL,
415
+ contextWindow: 200000,
416
+ maxTokens: 65536
417
+ },
418
+ {
419
+ ...KIRO_DEFAULTS,
420
+ id: "claude-haiku-4-5",
421
+ name: "Claude Haiku 4.5",
422
+ reasoning: false,
423
+ input: MULTIMODAL,
424
+ contextWindow: 200000,
425
+ maxTokens: 65536
426
+ },
427
+ {
428
+ ...KIRO_DEFAULTS,
429
+ id: "deepseek-3-2",
430
+ name: "DeepSeek 3.2",
431
+ reasoning: true,
432
+ input: TEXT_ONLY,
433
+ contextWindow: 128000,
434
+ maxTokens: 8192
435
+ },
436
+ {
437
+ ...KIRO_DEFAULTS,
438
+ id: "kimi-k2-5",
439
+ name: "Kimi K2.5",
440
+ reasoning: true,
441
+ input: TEXT_ONLY,
442
+ contextWindow: 200000,
443
+ maxTokens: 8192
444
+ },
445
+ {
446
+ ...KIRO_DEFAULTS,
447
+ id: "minimax-m2-5",
448
+ name: "MiniMax M2.5",
449
+ reasoning: false,
450
+ input: TEXT_ONLY,
451
+ contextWindow: 196000,
452
+ maxTokens: 64000
453
+ },
454
+ {
455
+ ...KIRO_DEFAULTS,
456
+ id: "minimax-m2-1",
457
+ name: "MiniMax M2.1",
458
+ reasoning: false,
459
+ input: MULTIMODAL,
460
+ contextWindow: 196000,
461
+ maxTokens: 64000
462
+ },
463
+ {
464
+ ...KIRO_DEFAULTS,
465
+ id: "glm-4-7",
466
+ name: "GLM 4.7",
467
+ reasoning: true,
468
+ input: TEXT_ONLY,
469
+ contextWindow: 128000,
470
+ maxTokens: 8192
471
+ },
472
+ {
473
+ ...KIRO_DEFAULTS,
474
+ id: "glm-4-7-flash",
475
+ name: "GLM 4.7 Flash",
476
+ reasoning: false,
477
+ input: TEXT_ONLY,
478
+ contextWindow: 128000,
479
+ maxTokens: 8192
480
+ },
481
+ {
482
+ ...KIRO_DEFAULTS,
483
+ id: "qwen3-coder-next",
484
+ name: "Qwen3 Coder Next",
485
+ reasoning: true,
486
+ input: MULTIMODAL,
487
+ contextWindow: 256000,
488
+ maxTokens: 64000
489
+ },
490
+ {
491
+ ...KIRO_DEFAULTS,
492
+ id: "qwen3-coder-480b",
493
+ name: "Qwen3 Coder 480B",
494
+ reasoning: true,
495
+ input: TEXT_ONLY,
496
+ contextWindow: 128000,
497
+ maxTokens: 8192
498
+ },
499
+ {
500
+ ...KIRO_DEFAULTS,
501
+ id: "agi-nova-beta-1m",
502
+ name: "AGI Nova Beta (1M)",
503
+ reasoning: true,
504
+ input: MULTIMODAL,
505
+ contextWindow: 1e6,
506
+ maxTokens: 65536
507
+ },
508
+ {
509
+ ...KIRO_DEFAULTS,
510
+ id: "auto",
511
+ name: "Auto",
512
+ reasoning: true,
513
+ input: MULTIMODAL,
514
+ contextWindow: 200000,
515
+ maxTokens: 65536
516
+ }
517
+ ];
518
+ REASONING_FAMILIES = new Set([
519
+ "claude-fable",
520
+ "claude-sonnet",
521
+ "claude-opus",
522
+ "deepseek",
523
+ "kimi",
524
+ "glm",
525
+ "qwen",
526
+ "agi-nova",
527
+ "minimax"
528
+ ]);
529
+ });
530
+
120
531
  // src/kiro-cli-sync.ts
121
532
  var exports_kiro_cli_sync = {};
122
533
  __export(exports_kiro_cli_sync, {
123
- importFromKiroCli: () => importFromKiroCli
534
+ selectKiroTokenRowForWrite: () => selectKiroTokenRowForWrite,
535
+ saveKiroCliCredentials: () => saveKiroCliCredentials,
536
+ sameKiroCliCredential: () => sameKiroCliCredential,
537
+ importFromKiroSsoCache: () => importFromKiroSsoCache,
538
+ importFromKiroCli: () => importFromKiroCli,
539
+ getKiroCliCredentialsAllowExpired: () => getKiroCliCredentialsAllowExpired
124
540
  });
125
541
  import { homedir } from "node:os";
126
542
  import { join } from "node:path";
543
+ import { spawn } from "node:child_process";
127
544
  import { existsSync, readFileSync } from "node:fs";
128
545
  function getKiroDbPath() {
129
546
  const home = homedir();
@@ -155,6 +572,105 @@ function safeJsonParse(value) {
155
572
  return null;
156
573
  }
157
574
  }
575
+ function sqliteQuote(value) {
576
+ return `'${value.replaceAll("'", "''")}'`;
577
+ }
578
+ function runSqliteCli(dbPath, sql, options) {
579
+ return new Promise((resolve2) => {
580
+ const args = [
581
+ ...options.readonly ? ["-readonly"] : [],
582
+ "-cmd",
583
+ `.timeout ${SQLITE_CLI_TIMEOUT_MS}`,
584
+ ...options.json ? ["-json"] : [],
585
+ dbPath
586
+ ];
587
+ const child = spawn("sqlite3", args, { stdio: "pipe" });
588
+ let stdout = "";
589
+ let settled = false;
590
+ const finish = (result) => {
591
+ if (settled)
592
+ return;
593
+ settled = true;
594
+ clearTimeout(timeout);
595
+ resolve2(result);
596
+ };
597
+ const timeout = setTimeout(() => {
598
+ child.kill();
599
+ log.debug("sqlite3 CLI timed out while reading Kiro DB");
600
+ finish(null);
601
+ }, SQLITE_CLI_TIMEOUT_MS);
602
+ child.stdout?.setEncoding("utf8");
603
+ child.stdout?.on("data", (chunk) => {
604
+ stdout += chunk;
605
+ });
606
+ child.on("error", () => {
607
+ log.debug("sqlite3 CLI unavailable for Kiro DB access");
608
+ finish(null);
609
+ });
610
+ child.on("close", (code) => {
611
+ if (code === 0)
612
+ finish(stdout);
613
+ else {
614
+ log.debug("sqlite3 CLI failed while accessing Kiro DB");
615
+ finish(null);
616
+ }
617
+ });
618
+ child.stdin?.end(`${sql}
619
+ `);
620
+ });
621
+ }
622
+ function parseAuthKvRows(value) {
623
+ if (!Array.isArray(value))
624
+ return null;
625
+ const rows = [];
626
+ for (const item of value) {
627
+ if (!item || typeof item !== "object")
628
+ continue;
629
+ const record = item;
630
+ if (typeof record.key === "string" && typeof record.value === "string") {
631
+ rows.push({ key: record.key, value: record.value });
632
+ }
633
+ }
634
+ return rows;
635
+ }
636
+ function extractActiveProfileArnFromStateRows(value) {
637
+ if (!Array.isArray(value))
638
+ return;
639
+ const first = value[0];
640
+ if (!first || typeof first !== "object")
641
+ return;
642
+ const record = first;
643
+ const parsed = safeJsonParse(record.value);
644
+ const arn = parsed?.arn || parsed?.profileArn || parsed?.profile_arn;
645
+ return typeof arn === "string" && arn.trim() ? arn.trim() : undefined;
646
+ }
647
+ function parseSqliteChanges(value) {
648
+ if (!Array.isArray(value))
649
+ return 0;
650
+ const first = value[0];
651
+ if (!first || typeof first !== "object")
652
+ return 0;
653
+ const changes = first.changes;
654
+ return typeof changes === "number" ? changes : 0;
655
+ }
656
+ async function readKiroAuthKvRowsWithSqliteCli(dbPath) {
657
+ const rowsRaw = await runSqliteCli(dbPath, "SELECT key, value FROM auth_kv", { readonly: true, json: true });
658
+ if (!rowsRaw)
659
+ return null;
660
+ return parseAuthKvRows(safeJsonParse(rowsRaw));
661
+ }
662
+ async function readKiroDbWithSqliteCli(dbPath) {
663
+ const rows = await readKiroAuthKvRowsWithSqliteCli(dbPath);
664
+ if (!rows)
665
+ return null;
666
+ const stateRaw = await runSqliteCli(dbPath, "SELECT value FROM state WHERE key = 'api.codewhisperer.profile'", { readonly: true, json: true });
667
+ const activeProfileArn = stateRaw ? extractActiveProfileArnFromStateRows(safeJsonParse(stateRaw)) : undefined;
668
+ return { rows, activeProfileArn };
669
+ }
670
+ async function writeKiroDbWithSqliteCli(dbPath, tokenKey, updatedValue) {
671
+ const resultRaw = await runSqliteCli(dbPath, `UPDATE auth_kv SET value = ${sqliteQuote(updatedValue)} WHERE key = ${sqliteQuote(tokenKey)}; ` + "SELECT changes() AS changes", { readonly: false, json: true });
672
+ return parseSqliteChanges(safeJsonParse(resultRaw)) > 0;
673
+ }
158
674
  function findClientCreds(obj) {
159
675
  if (!obj || typeof obj !== "object")
160
676
  return {};
@@ -173,6 +689,23 @@ function findClientCreds(obj) {
173
689
  function isIdcTokenKey(key) {
174
690
  return key.includes("odic") || key.includes("oidc") || key.includes("idc");
175
691
  }
692
+ function isTokenRow(row) {
693
+ return row.key.includes(":token");
694
+ }
695
+ function tokenReadRank(row) {
696
+ return isIdcTokenKey(row.key) ? 0 : 1;
697
+ }
698
+ function selectKiroTokenRowForWrite(rows, creds) {
699
+ const tokenRows = rows.filter(isTokenRow);
700
+ if (!creds.tokenKey)
701
+ return;
702
+ return tokenRows.find((row) => row.key === creds.tokenKey);
703
+ }
704
+ function sameKiroCliCredential(left, right) {
705
+ if (!left || !right)
706
+ return false;
707
+ return left.source === right.source && left.tokenKey === right.tokenKey && left.accessToken === right.accessToken && left.refreshToken === right.refreshToken && left.region === right.region && left.authMethod === right.authMethod;
708
+ }
176
709
  function extractRegionFromArn(arn) {
177
710
  if (!arn)
178
711
  return;
@@ -189,37 +722,56 @@ async function importFromKiroDb() {
189
722
  return null;
190
723
  }
191
724
  try {
192
- const { Database } = await import("bun:sqlite");
193
- const db = new Database(dbPath, { readonly: true });
194
- try {
195
- db.exec("PRAGMA busy_timeout = 5000");
196
- } catch {}
197
725
  let rows;
726
+ let activeProfileArn;
727
+ let Database = null;
198
728
  try {
199
- rows = db.prepare("SELECT key, value FROM auth_kv").all();
729
+ Database = (await import("bun:sqlite")).Database;
200
730
  } catch {
201
- log.debug("Failed to read auth_kv table from Kiro DB");
731
+ try {
732
+ Database = (await import("better-sqlite3")).default;
733
+ } catch {
734
+ log.debug("No SQLite driver available (need bun:sqlite or better-sqlite3); trying sqlite3 CLI");
735
+ }
736
+ }
737
+ if (Database) {
738
+ const db = new Database(dbPath, { readonly: true });
739
+ try {
740
+ db.run?.("PRAGMA busy_timeout = 5000") ?? db.exec?.("PRAGMA busy_timeout = 5000");
741
+ } catch {}
742
+ try {
743
+ const stmt = db.prepare("SELECT key, value FROM auth_kv");
744
+ rows = stmt.all();
745
+ } catch {
746
+ log.debug("Failed to read auth_kv table from Kiro DB");
747
+ try {
748
+ db.close();
749
+ } catch {}
750
+ return null;
751
+ }
752
+ try {
753
+ const stateStmt = db.prepare("SELECT value FROM state WHERE key = ?");
754
+ const stateRow = stateStmt.get("api.codewhisperer.profile");
755
+ const parsed = safeJsonParse(stateRow?.value);
756
+ const arn = parsed?.arn || parsed?.profileArn || parsed?.profile_arn;
757
+ if (typeof arn === "string" && arn.trim()) {
758
+ activeProfileArn = arn.trim();
759
+ }
760
+ } catch {}
202
761
  try {
203
762
  db.close();
204
763
  } catch {}
205
- return null;
764
+ } else {
765
+ const snapshot = await readKiroDbWithSqliteCli(dbPath);
766
+ if (!snapshot)
767
+ return null;
768
+ rows = snapshot.rows;
769
+ activeProfileArn = snapshot.activeProfileArn;
206
770
  }
207
- let activeProfileArn;
208
- try {
209
- const stateRow = db.prepare("SELECT value FROM state WHERE key = ?").get("api.codewhisperer.profile");
210
- const parsed = safeJsonParse(stateRow?.value);
211
- const arn = parsed?.arn || parsed?.profileArn || parsed?.profile_arn;
212
- if (typeof arn === "string" && arn.trim()) {
213
- activeProfileArn = arn.trim();
214
- }
215
- } catch {}
216
- try {
217
- db.close();
218
- } catch {}
219
771
  const deviceRegRow = rows.find((r) => typeof r?.key === "string" && r.key.includes("device-registration"));
220
772
  const deviceReg = safeJsonParse(deviceRegRow?.value);
221
773
  const regCreds = deviceReg ? findClientCreds(deviceReg) : {};
222
- const tokenRows = rows.filter((r) => r.key.includes(":token")).sort((a, b) => (isIdcTokenKey(a.key) ? 0 : 1) - (isIdcTokenKey(b.key) ? 0 : 1));
774
+ const tokenRows = rows.filter(isTokenRow).sort((a, b) => tokenReadRank(a) - tokenReadRank(b));
223
775
  for (const row of tokenRows) {
224
776
  const data = safeJsonParse(row.value);
225
777
  if (!data)
@@ -232,16 +784,19 @@ async function importFromKiroDb() {
232
784
  const authMethod = isIdc ? "idc" : "desktop";
233
785
  const oidcRegion = data.region || "us-east-1";
234
786
  let profileArn = data.profile_arn || data.profileArn;
235
- if (!profileArn)
787
+ if (!profileArn && isIdc) {
236
788
  profileArn = activeProfileArn;
789
+ }
237
790
  const serviceRegion = extractRegionFromArn(profileArn) || oidcRegion;
238
791
  const result = {
239
792
  accessToken: accessToken || "",
240
793
  refreshToken: refreshToken || "",
241
794
  region: serviceRegion,
242
795
  authMethod,
796
+ profileArn,
243
797
  email: data.email || data.emailAddress,
244
- profileArn
798
+ source: "kiro-cli-db",
799
+ tokenKey: row.key
245
800
  };
246
801
  if (isIdc && regCreds.clientId) {
247
802
  result.clientId = regCreds.clientId;
@@ -257,30 +812,48 @@ async function importFromKiroDb() {
257
812
  return null;
258
813
  }
259
814
  }
815
+ function mapSsoCacheAuthMethod(value) {
816
+ if (typeof value !== "string")
817
+ return "idc";
818
+ const v = value.toLowerCase();
819
+ if (v === "builderid" || v === "builder-id")
820
+ return "desktop";
821
+ return "idc";
822
+ }
260
823
  async function importFromKiroSsoCache() {
261
- const cachePath = getKiroSsoCachePath();
262
- if (!existsSync(cachePath)) {
263
- log.debug(`Kiro SSO cache not found at ${cachePath}`);
824
+ const path = getKiroSsoCachePath();
825
+ if (!existsSync(path)) {
826
+ log.debug(`Kiro SSO cache not found at ${path}`);
264
827
  return null;
265
828
  }
266
829
  let raw;
267
830
  try {
268
- raw = readFileSync(cachePath, "utf8");
831
+ raw = readFileSync(path, "utf8");
269
832
  } catch (err) {
270
- log.warn(`Failed to read Kiro SSO cache at ${cachePath}: ${err}`);
833
+ log.warn(`Failed to read Kiro SSO cache at ${path}: ${err}`);
271
834
  return null;
272
835
  }
273
836
  const token = safeJsonParse(raw);
274
- if (!token || typeof token !== "object")
837
+ if (!token || typeof token !== "object") {
838
+ log.debug(`Kiro SSO cache at ${path} is not valid JSON`);
275
839
  return null;
840
+ }
276
841
  const accessToken = typeof token.accessToken === "string" ? token.accessToken : "";
277
842
  const refreshToken = typeof token.refreshToken === "string" ? token.refreshToken : "";
278
- if (!accessToken && !refreshToken)
843
+ if (!accessToken && !refreshToken) {
844
+ log.debug(`Kiro SSO cache at ${path} has no tokens`);
279
845
  return null;
846
+ }
280
847
  const region = typeof token.region === "string" && token.region.length > 0 ? token.region : "us-east-1";
281
- const authMethod = "desktop";
282
- log.info(`Imported Kiro SSO cache credentials (region=${region})`);
283
- return { accessToken, refreshToken, region, authMethod };
848
+ const authMethod = mapSsoCacheAuthMethod(token.authMethod);
849
+ log.info(`Imported Kiro SSO cache credentials (method=${authMethod}, region=${region})`);
850
+ return {
851
+ accessToken,
852
+ refreshToken,
853
+ region,
854
+ authMethod,
855
+ source: "kiro-sso-cache"
856
+ };
284
857
  }
285
858
  async function importFromKiroCli() {
286
859
  const dbResult = await importFromKiroDb();
@@ -288,6 +861,98 @@ async function importFromKiroCli() {
288
861
  return dbResult;
289
862
  return importFromKiroSsoCache();
290
863
  }
864
+ async function getKiroCliCredentialsAllowExpired(exclude) {
865
+ const imported = await importFromKiroCli();
866
+ return sameKiroCliCredential(imported, exclude ?? null) ? null : imported;
867
+ }
868
+ async function saveKiroCliCredentials(creds) {
869
+ if (creds.source !== "kiro-cli-db" || !creds.tokenKey) {
870
+ log.debug("Credential write-back skipped: credential did not originate from kiro-cli DB");
871
+ return false;
872
+ }
873
+ const dbPath = getKiroDbPath();
874
+ if (!existsSync(dbPath)) {
875
+ log.debug(`Kiro CLI DB not found at ${dbPath} — cannot save credentials`);
876
+ return false;
877
+ }
878
+ try {
879
+ let Database = null;
880
+ try {
881
+ Database = (await import("bun:sqlite")).Database;
882
+ } catch {
883
+ try {
884
+ Database = (await import("better-sqlite3")).default;
885
+ } catch {
886
+ log.debug("No SQLite driver available for credential write-back; trying sqlite3 CLI");
887
+ }
888
+ }
889
+ let rows;
890
+ let db = null;
891
+ if (Database) {
892
+ db = new Database(dbPath);
893
+ try {
894
+ db.run?.("PRAGMA busy_timeout = 5000") ?? db.exec?.("PRAGMA busy_timeout = 5000");
895
+ } catch {}
896
+ try {
897
+ const stmt = db.prepare("SELECT key, value FROM auth_kv");
898
+ rows = stmt.all();
899
+ } catch {
900
+ log.debug("Failed to read auth_kv table for credential write-back");
901
+ try {
902
+ db.close();
903
+ } catch {}
904
+ return false;
905
+ }
906
+ } else {
907
+ const cliRows = await readKiroAuthKvRowsWithSqliteCli(dbPath);
908
+ if (!cliRows)
909
+ return false;
910
+ rows = cliRows;
911
+ }
912
+ const tokenRow = selectKiroTokenRowForWrite(rows, creds);
913
+ if (!tokenRow) {
914
+ log.debug("No matching token entry found in auth_kv — cannot write back");
915
+ try {
916
+ db?.close();
917
+ } catch {}
918
+ return false;
919
+ }
920
+ const existing = safeJsonParse(tokenRow.value) ?? {};
921
+ const updated = {
922
+ ...existing,
923
+ accessToken: creds.accessToken,
924
+ access_token: creds.accessToken,
925
+ refreshToken: creds.refreshToken,
926
+ refresh_token: creds.refreshToken
927
+ };
928
+ const updatedValue = JSON.stringify(updated);
929
+ if (db) {
930
+ try {
931
+ const updateStmt = db.prepare("UPDATE auth_kv SET value = ? WHERE key = ?");
932
+ updateStmt.run(updatedValue, tokenRow.key);
933
+ } catch (err) {
934
+ log.warn(`Failed to write credentials back to Kiro CLI DB: ${err}`);
935
+ try {
936
+ db.close();
937
+ } catch {}
938
+ return false;
939
+ }
940
+ try {
941
+ db.close();
942
+ } catch {}
943
+ } else {
944
+ const wrote = await writeKiroDbWithSqliteCli(dbPath, tokenRow.key, updatedValue);
945
+ if (!wrote)
946
+ return false;
947
+ }
948
+ log.info("Wrote refreshed credentials back to Kiro CLI DB");
949
+ return true;
950
+ } catch (err) {
951
+ log.warn(`Failed to save credentials to Kiro CLI: ${err}`);
952
+ return false;
953
+ }
954
+ }
955
+ var SQLITE_CLI_TIMEOUT_MS = 5000;
291
956
  var init_kiro_cli_sync = __esm(() => {
292
957
  init_debug();
293
958
  });
@@ -616,372 +1281,8 @@ function isPermanentError(reason) {
616
1281
  return PERMANENT_PATTERNS.some((p) => reason.includes(p));
617
1282
  }
618
1283
 
619
- // src/models.ts
620
- var KIRO_MODEL_IDS = new Set([
621
- "claude-fable-5",
622
- "claude-opus-4.8",
623
- "claude-opus-4.7",
624
- "claude-opus-4.6",
625
- "claude-opus-4.6-1m",
626
- "claude-sonnet-4.6",
627
- "claude-sonnet-4.6-1m",
628
- "claude-opus-4.5",
629
- "claude-sonnet-4.5",
630
- "claude-sonnet-4.5-1m",
631
- "claude-sonnet-4",
632
- "claude-haiku-4.5",
633
- "deepseek-3.2",
634
- "kimi-k2.5",
635
- "minimax-m2.1",
636
- "minimax-m2.5",
637
- "glm-4.7",
638
- "glm-4.7-flash",
639
- "qwen3-coder-next",
640
- "agi-nova-beta-1m",
641
- "qwen3-coder-480b",
642
- "auto"
643
- ]);
644
- function dotToDash(modelId) {
645
- return modelId.replace(/(\d)\.(\d)/g, "$1-$2");
646
- }
647
- function resolveKiroModel(modelId) {
648
- const kiroId = modelId.replace(/(\d)-(\d)/g, "$1.$2");
649
- if (!KIRO_MODEL_IDS.has(kiroId)) {
650
- throw new Error(`Unknown Kiro model ID: ${modelId}`);
651
- }
652
- return kiroId;
653
- }
654
- var API_REGION_MAP = {
655
- "us-west-1": "us-east-1",
656
- "us-west-2": "us-east-1",
657
- "us-east-2": "us-east-1",
658
- "eu-west-1": "eu-central-1",
659
- "eu-west-2": "eu-central-1",
660
- "eu-west-3": "eu-central-1",
661
- "eu-north-1": "eu-central-1",
662
- "eu-south-1": "eu-central-1",
663
- "eu-south-2": "eu-central-1",
664
- "eu-central-2": "eu-central-1",
665
- "ap-northeast-1": "us-east-1",
666
- "ap-northeast-2": "us-east-1",
667
- "ap-northeast-3": "us-east-1",
668
- "ap-southeast-1": "us-east-1",
669
- "ap-southeast-2": "us-east-1",
670
- "ap-south-1": "us-east-1",
671
- "ap-east-1": "us-east-1",
672
- "ap-south-2": "us-east-1",
673
- "ap-southeast-3": "us-east-1",
674
- "ap-southeast-4": "us-east-1"
675
- };
676
- function resolveApiRegion(ssoRegion) {
677
- if (!ssoRegion)
678
- return "us-east-1";
679
- return API_REGION_MAP[ssoRegion] ?? ssoRegion;
680
- }
681
- var BASE_URL = "https://runtime.us-east-1.kiro.dev";
682
- var ZERO_COST = Object.freeze({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0 });
683
- var KIRO_DEFAULTS = {
684
- api: "kiro-api",
685
- provider: "kiro",
686
- baseUrl: BASE_URL,
687
- cost: ZERO_COST
688
- };
689
- var MULTIMODAL = ["text", "image"];
690
- var TEXT_ONLY = ["text"];
691
- var kiroModels = [
692
- {
693
- ...KIRO_DEFAULTS,
694
- id: "claude-fable-5",
695
- name: "Claude Fable 5",
696
- reasoning: true,
697
- input: MULTIMODAL,
698
- contextWindow: 1e6,
699
- maxTokens: 128000,
700
- firstTokenTimeout: 180000,
701
- supportedEfforts: ["low", "medium", "high", "xhigh", "max"],
702
- supportsThinkingConfig: true
703
- },
704
- {
705
- ...KIRO_DEFAULTS,
706
- id: "claude-opus-4-8",
707
- name: "Claude Opus 4.8",
708
- reasoning: true,
709
- input: MULTIMODAL,
710
- contextWindow: 1e6,
711
- maxTokens: 128000,
712
- firstTokenTimeout: 180000,
713
- supportedEfforts: ["low", "medium", "high", "xhigh", "max"],
714
- supportsThinkingConfig: true
715
- },
716
- {
717
- ...KIRO_DEFAULTS,
718
- id: "claude-opus-4-7",
719
- name: "Claude Opus 4.7",
720
- reasoning: true,
721
- input: MULTIMODAL,
722
- contextWindow: 1e6,
723
- maxTokens: 128000,
724
- firstTokenTimeout: 180000,
725
- supportedEfforts: ["low", "medium", "high", "xhigh", "max"],
726
- supportsThinkingConfig: true
727
- },
728
- {
729
- ...KIRO_DEFAULTS,
730
- id: "claude-opus-4-6",
731
- name: "Claude Opus 4.6",
732
- reasoning: true,
733
- input: MULTIMODAL,
734
- contextWindow: 1e6,
735
- maxTokens: 64000,
736
- supportedEfforts: ["low", "medium", "high", "max"],
737
- supportsThinkingConfig: true
738
- },
739
- {
740
- ...KIRO_DEFAULTS,
741
- id: "claude-opus-4-6-1m",
742
- name: "Claude Opus 4.6 (1M)",
743
- reasoning: true,
744
- input: MULTIMODAL,
745
- contextWindow: 1e6,
746
- maxTokens: 64000,
747
- supportedEfforts: ["low", "medium", "high", "max"],
748
- supportsThinkingConfig: true
749
- },
750
- {
751
- ...KIRO_DEFAULTS,
752
- id: "claude-sonnet-4-6",
753
- name: "Claude Sonnet 4.6",
754
- reasoning: true,
755
- input: MULTIMODAL,
756
- contextWindow: 1e6,
757
- maxTokens: 64000,
758
- supportedEfforts: ["low", "medium", "high", "max"],
759
- supportsThinkingConfig: true
760
- },
761
- {
762
- ...KIRO_DEFAULTS,
763
- id: "claude-sonnet-4-6-1m",
764
- name: "Claude Sonnet 4.6 (1M)",
765
- reasoning: true,
766
- input: MULTIMODAL,
767
- contextWindow: 1e6,
768
- maxTokens: 64000,
769
- supportedEfforts: ["low", "medium", "high", "max"],
770
- supportsThinkingConfig: true
771
- },
772
- {
773
- ...KIRO_DEFAULTS,
774
- id: "claude-opus-4-5",
775
- name: "Claude Opus 4.5",
776
- reasoning: true,
777
- input: MULTIMODAL,
778
- contextWindow: 200000,
779
- maxTokens: 64000
780
- },
781
- {
782
- ...KIRO_DEFAULTS,
783
- id: "claude-sonnet-4-5",
784
- name: "Claude Sonnet 4.5",
785
- reasoning: true,
786
- input: MULTIMODAL,
787
- contextWindow: 200000,
788
- maxTokens: 65536
789
- },
790
- {
791
- ...KIRO_DEFAULTS,
792
- id: "claude-sonnet-4-5-1m",
793
- name: "Claude Sonnet 4.5 (1M)",
794
- reasoning: true,
795
- input: MULTIMODAL,
796
- contextWindow: 1e6,
797
- maxTokens: 65536
798
- },
799
- {
800
- ...KIRO_DEFAULTS,
801
- id: "claude-sonnet-4",
802
- name: "Claude Sonnet 4",
803
- reasoning: true,
804
- input: MULTIMODAL,
805
- contextWindow: 200000,
806
- maxTokens: 65536
807
- },
808
- {
809
- ...KIRO_DEFAULTS,
810
- id: "claude-haiku-4-5",
811
- name: "Claude Haiku 4.5",
812
- reasoning: false,
813
- input: MULTIMODAL,
814
- contextWindow: 200000,
815
- maxTokens: 65536
816
- },
817
- {
818
- ...KIRO_DEFAULTS,
819
- id: "deepseek-3-2",
820
- name: "DeepSeek 3.2",
821
- reasoning: true,
822
- input: TEXT_ONLY,
823
- contextWindow: 128000,
824
- maxTokens: 8192
825
- },
826
- {
827
- ...KIRO_DEFAULTS,
828
- id: "kimi-k2-5",
829
- name: "Kimi K2.5",
830
- reasoning: true,
831
- input: TEXT_ONLY,
832
- contextWindow: 200000,
833
- maxTokens: 8192
834
- },
835
- {
836
- ...KIRO_DEFAULTS,
837
- id: "minimax-m2-5",
838
- name: "MiniMax M2.5",
839
- reasoning: false,
840
- input: TEXT_ONLY,
841
- contextWindow: 196000,
842
- maxTokens: 64000
843
- },
844
- {
845
- ...KIRO_DEFAULTS,
846
- id: "minimax-m2-1",
847
- name: "MiniMax M2.1",
848
- reasoning: false,
849
- input: MULTIMODAL,
850
- contextWindow: 196000,
851
- maxTokens: 64000
852
- },
853
- {
854
- ...KIRO_DEFAULTS,
855
- id: "glm-4-7",
856
- name: "GLM 4.7",
857
- reasoning: true,
858
- input: TEXT_ONLY,
859
- contextWindow: 128000,
860
- maxTokens: 8192
861
- },
862
- {
863
- ...KIRO_DEFAULTS,
864
- id: "glm-4-7-flash",
865
- name: "GLM 4.7 Flash",
866
- reasoning: false,
867
- input: TEXT_ONLY,
868
- contextWindow: 128000,
869
- maxTokens: 8192
870
- },
871
- {
872
- ...KIRO_DEFAULTS,
873
- id: "qwen3-coder-next",
874
- name: "Qwen3 Coder Next",
875
- reasoning: true,
876
- input: MULTIMODAL,
877
- contextWindow: 256000,
878
- maxTokens: 64000
879
- },
880
- {
881
- ...KIRO_DEFAULTS,
882
- id: "qwen3-coder-480b",
883
- name: "Qwen3 Coder 480B",
884
- reasoning: true,
885
- input: TEXT_ONLY,
886
- contextWindow: 128000,
887
- maxTokens: 8192
888
- },
889
- {
890
- ...KIRO_DEFAULTS,
891
- id: "agi-nova-beta-1m",
892
- name: "AGI Nova Beta (1M)",
893
- reasoning: true,
894
- input: MULTIMODAL,
895
- contextWindow: 1e6,
896
- maxTokens: 65536
897
- },
898
- {
899
- ...KIRO_DEFAULTS,
900
- id: "auto",
901
- name: "Auto",
902
- reasoning: true,
903
- input: MULTIMODAL,
904
- contextWindow: 200000,
905
- maxTokens: 65536
906
- }
907
- ];
908
- async function fetchAvailableModels(accessToken, apiRegion, fallbackProfileArn) {
909
- const runtimeUrl = `https://runtime.${apiRegion}.kiro.dev/`;
910
- let profileArn = await resolveProfileArn(accessToken, runtimeUrl);
911
- if (!profileArn && fallbackProfileArn) {
912
- profileArn = fallbackProfileArn;
913
- }
914
- if (!profileArn) {
915
- throw new Error("Missing profileArn: cannot fetch available models.");
916
- }
917
- const url = `https://management.${apiRegion}.kiro.dev/ListAvailableModels?origin=KIRO_CLI&profileArn=${encodeURIComponent(profileArn)}`;
918
- const resp = await fetch(url, {
919
- method: "GET",
920
- headers: {
921
- Authorization: `Bearer ${accessToken}`,
922
- Accept: "application/json",
923
- "User-Agent": "opencode-kiro"
924
- }
925
- });
926
- if (!resp.ok) {
927
- throw new Error(`ListAvailableModels failed: HTTP ${resp.status}`);
928
- }
929
- const data = await resp.json();
930
- return (data.models ?? []).filter((m) => m.modelId !== "auto");
931
- }
932
- var REASONING_FAMILIES = new Set([
933
- "claude-fable",
934
- "claude-sonnet",
935
- "claude-opus",
936
- "deepseek",
937
- "kimi",
938
- "glm",
939
- "qwen",
940
- "agi-nova",
941
- "minimax"
942
- ]);
943
- function isReasoningModel(dotId) {
944
- for (const family of REASONING_FAMILIES) {
945
- if (dotId.startsWith(family))
946
- return true;
947
- }
948
- return false;
949
- }
950
- function firstTokenTimeout(dotId) {
951
- if (dotId.startsWith("claude-fable") || dotId.startsWith("claude-opus"))
952
- return 180000;
953
- return 90000;
954
- }
955
- function buildModelsFromApi(apiModels) {
956
- return apiModels.map((m) => {
957
- KIRO_MODEL_IDS.add(m.modelId);
958
- const dashId = dotToDash(m.modelId);
959
- const supportedTypes = m.supportedInputTypes ?? ["TEXT"];
960
- const input = supportedTypes.includes("IMAGE") ? ["text", "image"] : ["text"];
961
- const effortEnum = m.additionalModelRequestFieldsSchema?.properties?.output_config?.properties?.effort?.enum;
962
- const supportedEfforts = Array.isArray(effortEnum) && effortEnum.length > 0 ? effortEnum : undefined;
963
- const supportsThinkingConfig = !!m.additionalModelRequestFieldsSchema?.properties?.thinking;
964
- return {
965
- ...KIRO_DEFAULTS,
966
- id: dashId,
967
- name: m.modelName,
968
- reasoning: isReasoningModel(m.modelId),
969
- input,
970
- contextWindow: m.tokenLimits?.maxInputTokens ?? 200000,
971
- maxTokens: m.tokenLimits?.maxOutputTokens ?? 8192,
972
- firstTokenTimeout: firstTokenTimeout(m.modelId),
973
- ...supportedEfforts ? { supportedEfforts } : {},
974
- ...supportsThinkingConfig ? { supportsThinkingConfig } : {}
975
- };
976
- });
977
- }
978
- var cachedDynamicModels = null;
979
- function getCachedDynamicModels() {
980
- return cachedDynamicModels;
981
- }
982
- function setCachedDynamicModels(models) {
983
- cachedDynamicModels = models;
984
- }
1284
+ // src/stream.ts
1285
+ init_models();
985
1286
 
986
1287
  // src/thinking-parser.ts
987
1288
  init_debug();
@@ -1218,7 +1519,9 @@ function countTokens(text) {
1218
1519
 
1219
1520
  // src/oauth.ts
1220
1521
  init_debug();
1221
- var BUILDER_ID_START_URL = "https://view.awsapps.com/start";
1522
+ init_models();
1523
+ import { createServer } from "node:http";
1524
+ import { randomBytes, createHash } from "node:crypto";
1222
1525
  var BUILDER_ID_REGION = "us-east-1";
1223
1526
  var SSO_SCOPES = [
1224
1527
  "codewhisperer:completions",
@@ -1337,10 +1640,12 @@ async function refreshKiroToken(refreshTokenPacked, region, authMethod) {
1337
1640
  const refreshToken = parts[0] ?? "";
1338
1641
  const clientId = parts[1] ?? "";
1339
1642
  const clientSecret = parts[2] ?? "";
1643
+ const source = parts[4] ?? "";
1644
+ const tokenKey = parts[5] ?? "";
1340
1645
  if (!refreshToken || !region) {
1341
1646
  throw new Error("Refresh token or region is missing — re-login required");
1342
1647
  }
1343
- if (authMethod === "desktop") {
1648
+ if (authMethod === "desktop" || authMethod === "social") {
1344
1649
  const desktopEndpoint = `https://prod.${region}.auth.desktop.kiro.dev/refreshToken`;
1345
1650
  const resp2 = await fetch(desktopEndpoint, {
1346
1651
  method: "POST",
@@ -1352,9 +1657,23 @@ async function refreshKiroToken(refreshTokenPacked, region, authMethod) {
1352
1657
  throw new Error(`Desktop token refresh failed: ${resp2.status} ${body}`);
1353
1658
  }
1354
1659
  const data2 = await resp2.json();
1660
+ const newPacked2 = `${data2.refreshToken}|||${authMethod}|${source}|${tokenKey}`;
1661
+ if (source === "kiro-cli-db" && tokenKey) {
1662
+ const { saveKiroCliCredentials: saveKiroCliCredentials2 } = await Promise.resolve().then(() => (init_kiro_cli_sync(), exports_kiro_cli_sync));
1663
+ await saveKiroCliCredentials2({
1664
+ accessToken: data2.accessToken,
1665
+ refreshToken: data2.refreshToken,
1666
+ clientId: "",
1667
+ clientSecret: "",
1668
+ region,
1669
+ authMethod,
1670
+ source: "kiro-cli-db",
1671
+ tokenKey
1672
+ });
1673
+ }
1355
1674
  return {
1356
1675
  access: data2.accessToken,
1357
- refresh: `${data2.refreshToken}|||desktop`,
1676
+ refresh: newPacked2,
1358
1677
  expires: Date.now() + (data2.expiresIn ?? 3600) * 1000 - EXPIRES_BUFFER_MS
1359
1678
  };
1360
1679
  }
@@ -1372,15 +1691,489 @@ async function refreshKiroToken(refreshTokenPacked, region, authMethod) {
1372
1691
  throw new Error(`Token refresh failed: ${resp.status} ${body}`);
1373
1692
  }
1374
1693
  const data = await resp.json();
1694
+ const newPacked = `${data.refreshToken}|${clientId}|${clientSecret}|${authMethod}|${source}|${tokenKey}`;
1695
+ if (source === "kiro-cli-db" && tokenKey) {
1696
+ const { saveKiroCliCredentials: saveKiroCliCredentials2 } = await Promise.resolve().then(() => (init_kiro_cli_sync(), exports_kiro_cli_sync));
1697
+ await saveKiroCliCredentials2({
1698
+ accessToken: data.accessToken,
1699
+ refreshToken: data.refreshToken,
1700
+ clientId,
1701
+ clientSecret,
1702
+ region,
1703
+ authMethod,
1704
+ source: "kiro-cli-db",
1705
+ tokenKey
1706
+ });
1707
+ }
1375
1708
  return {
1376
1709
  access: data.accessToken,
1377
- refresh: `${data.refreshToken}|${clientId}|${clientSecret}|${authMethod}`,
1710
+ refresh: newPacked,
1378
1711
  expires: Date.now() + (data.expiresIn ?? 3600) * 1000 - EXPIRES_BUFFER_MS
1379
1712
  };
1380
1713
  }
1714
+ var KIRO_SOCIAL_PORTAL = "https://app.kiro.dev";
1715
+ var KIRO_SOCIAL_AUTH_ENDPOINT = `https://prod.${BUILDER_ID_REGION}.auth.desktop.kiro.dev`;
1716
+ var SOCIAL_REDIRECT_PORT = 49153;
1717
+ var SOCIAL_REDIRECT_URI = `http://localhost:${SOCIAL_REDIRECT_PORT}`;
1718
+ function generateRandomState() {
1719
+ return randomBytes(16).toString("base64url");
1720
+ }
1721
+ function generateCodeVerifier() {
1722
+ return randomBytes(32).toString("base64url");
1723
+ }
1724
+ function generateCodeChallenge(verifier) {
1725
+ return createHash("sha256").update(verifier).digest("base64url");
1726
+ }
1727
+ function buildSocialSignInURL(redirectUri, codeChallenge, state) {
1728
+ const params = new URLSearchParams;
1729
+ params.set("code_challenge", codeChallenge);
1730
+ params.set("code_challenge_method", "S256");
1731
+ params.set("redirect_from", "kirocli");
1732
+ params.set("redirect_uri", redirectUri);
1733
+ params.set("state", state);
1734
+ return `${KIRO_SOCIAL_PORTAL}/signin?${params.toString()}`;
1735
+ }
1736
+ function buildTokenRedirectUri(callbackPath, loginOption) {
1737
+ const path = callbackPath || "/oauth/callback";
1738
+ const base = `${SOCIAL_REDIRECT_URI}${path}`;
1739
+ if (loginOption) {
1740
+ return `${base}?login_option=${encodeURIComponent(loginOption)}`;
1741
+ }
1742
+ return base;
1743
+ }
1744
+ function oauthCallbackPage(kind, title, message, redirectUrl = "https://app.kiro.dev") {
1745
+ const borderColor = kind === "success" ? "#22c55e" : "#ef4444";
1746
+ const iconSvg = kind === "success" ? `<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M16.67 5L7.5 14.17 3.33 10" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>` : `<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M15 5L5 15M5 5l10 10" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/></svg>`;
1747
+ const ghostSvg = `<svg width="56" height="56" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
1748
+ <path d="M50 5C28.5 5 11 22.5 11 44v36c0 2.8 1.2 5.4 3.2 7.2 2 1.8 4.7 2.6 7.4 2.2l3.4-.5c3.2-.5 6.5.4 9 2.5l2.2 1.8c2.4 2 5.4 3 8.5 3h10.6c3.1 0 6.1-1.1 8.5-3l2.2-1.8c2.5-2.1 5.8-3 9-2.5l3.4.5c2.7.4 5.4-.4 7.4-2.2 2-1.8 3.2-4.4 3.2-7.2V44C89 22.5 71.5 5 50 5z" fill="white"/>
1749
+ <circle cx="37" cy="45" r="7" fill="#0a0a0a"/>
1750
+ <circle cx="63" cy="45" r="7" fill="#0a0a0a"/>
1751
+ </svg>`;
1752
+ const redirectHost = (() => {
1753
+ try {
1754
+ return new URL(redirectUrl).hostname;
1755
+ } catch {
1756
+ return redirectUrl;
1757
+ }
1758
+ })();
1759
+ const countdownHtml = kind === "success" ? `
1760
+ <div class="countdown" id="countdown">
1761
+ <svg class="ring" viewBox="0 0 60 60">
1762
+ <circle cx="30" cy="30" r="26" stroke="#1a1a1a" stroke-width="3" fill="none"/>
1763
+ <circle id="ring-progress" cx="30" cy="30" r="26" stroke="#22c55e" stroke-width="3" fill="none"
1764
+ stroke-dasharray="163.36" stroke-dashoffset="0" stroke-linecap="round"
1765
+ transform="rotate(-90 30 30)" style="transition:stroke-dashoffset 1s linear"/>
1766
+ </svg>
1767
+ <span class="countdown-num" id="countdown-num">3</span>
1768
+ </div>
1769
+ <p class="subtitle">Redirecting to <strong>${redirectHost}</strong>…</p>
1770
+ <script>
1771
+ (function(){
1772
+ var n=3, el=document.getElementById('countdown-num'),
1773
+ ring=document.getElementById('ring-progress'), circ=163.36;
1774
+ function tick(){
1775
+ if(n<=0){window.location.href=${JSON.stringify(redirectUrl)};return}
1776
+ el.textContent=n;
1777
+ ring.setAttribute('stroke-dashoffset', String(circ*(1-n/3)));
1778
+ n--;
1779
+ setTimeout(tick,1000);
1780
+ }
1781
+ tick();
1782
+ })();
1783
+ </script>` : `<p class="subtitle">Please close this window and try again</p>`;
1784
+ return `<!DOCTYPE html>
1785
+ <html lang="en">
1786
+ <head>
1787
+ <meta charset="utf-8">
1788
+ <meta name="viewport" content="width=device-width, initial-scale=1">
1789
+ <title>OPENCODE-KIRO — Authentication</title>
1790
+ <style>
1791
+ *{margin:0;padding:0;box-sizing:border-box}
1792
+ body{background:#0a0a0a;color:#e5e5e5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;text-align:center}
1793
+ .container{max-width:420px;padding:2rem}
1794
+ .logo{display:flex;align-items:center;justify-content:center;gap:16px;margin-bottom:48px}
1795
+ .logo-text{font-size:32px;font-weight:700;letter-spacing:4px;color:#7c3aed;font-family:'Courier New',monospace}
1796
+ .status-box{border:1.5px solid ${borderColor};border-radius:12px;padding:20px 28px;display:flex;align-items:flex-start;gap:14px;text-align:left;margin-bottom:20px;background:rgba(${kind === "success" ? "34,197,94" : "239,68,68"},0.04)}
1797
+ .status-icon{flex-shrink:0;margin-top:2px}
1798
+ .status-title{font-size:15px;font-weight:600;color:${borderColor};margin-bottom:4px}
1799
+ .status-msg{font-size:13px;color:#a3a3a3;line-height:1.4}
1800
+ .subtitle{font-size:13px;color:#737373;margin-top:4px}
1801
+ .subtitle strong{color:#a3a3a3}
1802
+ .countdown{position:relative;width:60px;height:60px;margin:24px auto 12px}
1803
+ .ring{width:60px;height:60px}
1804
+ .countdown-num{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:24px;font-weight:700;color:#22c55e;font-variant-numeric:tabular-nums}
1805
+ </style>
1806
+ </head>
1807
+ <body>
1808
+ <div class="container">
1809
+ <div class="logo">
1810
+ ${ghostSvg}
1811
+ <span class="logo-text">OPENCODE-KIRO</span>
1812
+ </div>
1813
+ <div class="status-box">
1814
+ <span class="status-icon">${iconSvg}</span>
1815
+ <div>
1816
+ <div class="status-title">${title}</div>
1817
+ <div class="status-msg">${message}</div>
1818
+ </div>
1819
+ </div>
1820
+ ${countdownHtml}
1821
+ </div>
1822
+ </body>
1823
+ </html>`;
1824
+ }
1825
+ function oauthIdcDelegationPage() {
1826
+ const ghostSvg = `<svg width="56" height="56" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
1827
+ <path d="M50 5C28.5 5 11 22.5 11 44v36c0 2.8 1.2 5.4 3.2 7.2 2 1.8 4.7 2.6 7.4 2.2l3.4-.5c3.2-.5 6.5.4 9 2.5l2.2 1.8c2.4 2 5.4 3 8.5 3h10.6c3.1 0 6.1-1.1 8.5-3l2.2-1.8c2.5-2.1 5.8-3 9-2.5l3.4.5c2.7.4 5.4-.4 7.4-2.2 2-1.8 3.2-4.4 3.2-7.2V44C89 22.5 71.5 5 50 5z" fill="white"/>
1828
+ <circle cx="37" cy="45" r="7" fill="#0a0a0a"/>
1829
+ <circle cx="63" cy="45" r="7" fill="#0a0a0a"/>
1830
+ </svg>`;
1831
+ return `<!DOCTYPE html>
1832
+ <html lang="en">
1833
+ <head>
1834
+ <meta charset="utf-8">
1835
+ <meta name="viewport" content="width=device-width, initial-scale=1">
1836
+ <title>OPENCODE-KIRO — Enterprise Sign-In</title>
1837
+ <style>
1838
+ *{margin:0;padding:0;box-sizing:border-box}
1839
+ body{background:#0a0a0a;color:#e5e5e5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;text-align:center}
1840
+ .container{max-width:420px;padding:2rem}
1841
+ .logo{display:flex;align-items:center;justify-content:center;gap:16px;margin-bottom:48px}
1842
+ .logo-text{font-size:32px;font-weight:700;letter-spacing:4px;color:#7c3aed;font-family:'Courier New',monospace}
1843
+ .status-box{border:1.5px solid #22c55e;border-radius:12px;padding:20px 28px;display:flex;align-items:flex-start;gap:14px;text-align:left;margin-bottom:20px;background:rgba(34,197,94,0.04)}
1844
+ .status-icon{flex-shrink:0;margin-top:2px}
1845
+ .status-title{font-size:15px;font-weight:600;color:#22c55e;margin-bottom:4px}
1846
+ .status-msg{font-size:13px;color:#a3a3a3;line-height:1.4}
1847
+ .subtitle{font-size:13px;color:#737373;margin-top:4px}
1848
+ .subtitle strong{color:#a3a3a3}
1849
+ .spinner{width:28px;height:28px;border:3px solid #1a1a1a;border-top-color:#22c55e;border-radius:50%;animation:spin 0.8s linear infinite;margin:24px auto 12px}
1850
+ @keyframes spin{to{transform:rotate(360deg)}}
1851
+ .countdown{position:relative;width:60px;height:60px;margin:24px auto 12px;display:none}
1852
+ .ring{width:60px;height:60px}
1853
+ .countdown-num{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:24px;font-weight:700;color:#22c55e;font-variant-numeric:tabular-nums}
1854
+ </style>
1855
+ </head>
1856
+ <body>
1857
+ <div class="container">
1858
+ <div class="logo">
1859
+ ${ghostSvg}
1860
+ <span class="logo-text">OPENCODE-KIRO</span>
1861
+ </div>
1862
+ <div class="status-box">
1863
+ <span class="status-icon"><svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M16.67 5L7.5 14.17 3.33 10" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
1864
+ <div>
1865
+ <div class="status-title">Enterprise sign-in</div>
1866
+ <div class="status-msg" id="status-msg">Preparing device authorization…</div>
1867
+ </div>
1868
+ </div>
1869
+ <div class="spinner" id="spinner"></div>
1870
+ <div class="countdown" id="countdown">
1871
+ <svg class="ring" viewBox="0 0 60 60">
1872
+ <circle cx="30" cy="30" r="26" stroke="#1a1a1a" stroke-width="3" fill="none"/>
1873
+ <circle id="ring-progress" cx="30" cy="30" r="26" stroke="#22c55e" stroke-width="3" fill="none"
1874
+ stroke-dasharray="163.36" stroke-dashoffset="0" stroke-linecap="round"
1875
+ transform="rotate(-90 30 30)" style="transition:stroke-dashoffset 1s linear"/>
1876
+ </svg>
1877
+ <span class="countdown-num" id="countdown-num">3</span>
1878
+ </div>
1879
+ <p class="subtitle" id="subtitle">Waiting for device authorization…</p>
1880
+ <script>
1881
+ (function(){
1882
+ var msg=document.getElementById('status-msg'),
1883
+ spinner=document.getElementById('spinner'),
1884
+ cd=document.getElementById('countdown'),
1885
+ cdNum=document.getElementById('countdown-num'),
1886
+ ring=document.getElementById('ring-progress'),
1887
+ sub=document.getElementById('subtitle'),
1888
+ circ=163.36;
1889
+
1890
+ function poll(){
1891
+ fetch('/idc-verify').then(function(r){return r.json()}).then(function(d){
1892
+ if(d.url){
1893
+ spinner.style.display='none';
1894
+ cd.style.display='block';
1895
+ msg.textContent='Device authorization ready';
1896
+ try{sub.innerHTML='Redirecting to <strong>'+new URL(d.url).hostname+'</strong>…'}catch(e){}
1897
+ countdown(3,d.url);
1898
+ } else {
1899
+ setTimeout(poll,500);
1900
+ }
1901
+ }).catch(function(){setTimeout(poll,1000)});
1902
+ }
1903
+
1904
+ function countdown(n,url){
1905
+ if(n<=0){window.location.href=url;return}
1906
+ cdNum.textContent=n;
1907
+ ring.setAttribute('stroke-dashoffset',String(circ*(1-n/3)));
1908
+ setTimeout(function(){countdown(n-1,url)},1000);
1909
+ }
1910
+
1911
+ poll();
1912
+ })();
1913
+ </script>
1914
+ </div>
1915
+ </body>
1916
+ </html>`;
1917
+ }
1918
+ function startCallbackServer(expectedState) {
1919
+ return new Promise((resolve2, reject) => {
1920
+ let settleWait;
1921
+ const waitForCodePromise = new Promise((res) => {
1922
+ settleWait = res;
1923
+ });
1924
+ let idcVerifyUrl = null;
1925
+ const server = createServer((req, res) => {
1926
+ try {
1927
+ const url = new URL(req.url ?? "", SOCIAL_REDIRECT_URI);
1928
+ if (url.pathname === "/idc-verify") {
1929
+ res.writeHead(200, {
1930
+ "Content-Type": "application/json",
1931
+ "Access-Control-Allow-Origin": "*",
1932
+ "Cache-Control": "no-store"
1933
+ });
1934
+ res.end(JSON.stringify({ url: idcVerifyUrl }));
1935
+ return;
1936
+ }
1937
+ const code = url.searchParams.get("code");
1938
+ const state = url.searchParams.get("state");
1939
+ const loginOption = url.searchParams.get("login_option");
1940
+ const issuerUrl = url.searchParams.get("issuer_url");
1941
+ const idcRegion = url.searchParams.get("idc_region");
1942
+ const isIdcDelegation = loginOption === "awsidc" && !!issuerUrl && !!state;
1943
+ if (!state || !code && !isIdcDelegation) {
1944
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
1945
+ res.end("");
1946
+ return;
1947
+ }
1948
+ if (state !== expectedState) {
1949
+ res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
1950
+ res.end(oauthCallbackPage("error", "State mismatch", "The OAuth state parameter did not match. Please try logging in again."));
1951
+ return;
1952
+ }
1953
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
1954
+ if (isIdcDelegation) {
1955
+ res.end(oauthIdcDelegationPage());
1956
+ } else {
1957
+ res.end(oauthCallbackPage("success", "Request approved", "OPENCODE-KIRO has been given requested permissions."));
1958
+ }
1959
+ settleWait?.({
1960
+ code,
1961
+ state,
1962
+ callbackPath: url.pathname,
1963
+ loginOption,
1964
+ issuerUrl: issuerUrl ?? undefined,
1965
+ idcRegion: idcRegion ?? undefined
1966
+ });
1967
+ } catch {
1968
+ res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
1969
+ res.end("Internal error");
1970
+ }
1971
+ });
1972
+ server.on("error", (err) => {
1973
+ reject(err);
1974
+ });
1975
+ server.listen(SOCIAL_REDIRECT_PORT, "localhost", () => {
1976
+ resolve2({
1977
+ server,
1978
+ redirectUri: SOCIAL_REDIRECT_URI,
1979
+ cancelWait: () => {
1980
+ settleWait?.(null);
1981
+ },
1982
+ waitForCode: () => waitForCodePromise,
1983
+ setIdcVerifyUrl: (url) => {
1984
+ idcVerifyUrl = url;
1985
+ }
1986
+ });
1987
+ });
1988
+ });
1989
+ }
1990
+ async function startSocialLogin() {
1991
+ const verifier = generateCodeVerifier();
1992
+ const challenge = generateCodeChallenge(verifier);
1993
+ const state = generateRandomState();
1994
+ const callbackServer = await startCallbackServer(state);
1995
+ const signInUrl = buildSocialSignInURL(callbackServer.redirectUri, challenge, state);
1996
+ const waitForCredentials = async () => {
1997
+ try {
1998
+ const result = await callbackServer.waitForCode();
1999
+ if (result?.loginOption === "awsidc" && result.issuerUrl) {
2000
+ log.info("[social-login] Enterprise IdC delegation detected");
2001
+ const idcRegion = result.idcRegion || BUILDER_ID_REGION;
2002
+ const regions = [idcRegion];
2003
+ let regResult = null;
2004
+ let detectedRegion = "";
2005
+ for (const region of regions) {
2006
+ regResult = await tryRegisterAndAuthorize(result.issuerUrl, region);
2007
+ if (regResult) {
2008
+ detectedRegion = region;
2009
+ break;
2010
+ }
2011
+ }
2012
+ if (!regResult || !detectedRegion) {
2013
+ throw new Error(`Could not authorize ${result.issuerUrl} in ${regions.join(", ")}. Check your start URL and region and try again.`);
2014
+ }
2015
+ callbackServer.setIdcVerifyUrl(regResult.devAuth.verificationUriComplete);
2016
+ log.info(`[social-login] IdC device auth ready, verification URL sent to browser`);
2017
+ const tok = await pollForToken(regResult.oidcEndpoint, regResult.clientId, regResult.clientSecret, regResult.devAuth, undefined);
2018
+ if (!tok.accessToken || !tok.refreshToken) {
2019
+ throw new Error("IdC authorization completed but no tokens returned");
2020
+ }
2021
+ let profileArn;
2022
+ try {
2023
+ const apiRegion = resolveApiRegion(detectedRegion);
2024
+ const { resolveProfileArn: resolveProfileArn2 } = await Promise.resolve().then(() => (init_models(), exports_models));
2025
+ const resolved = await resolveProfileArn2(tok.accessToken, apiRegion);
2026
+ if (resolved) {
2027
+ profileArn = resolved;
2028
+ try {
2029
+ const apiModels = await fetchAvailableModels(tok.accessToken, apiRegion, profileArn);
2030
+ setCachedDynamicModels(buildModelsFromApi(apiModels));
2031
+ log.info(`[social-login] IdC: fetched and cached ${apiModels.length} models`);
2032
+ } catch (err) {
2033
+ log.warn(`[social-login] IdC: failed to fetch models: ${err}`);
2034
+ }
2035
+ }
2036
+ } catch (err) {
2037
+ log.warn(`[social-login] IdC: failed to resolve profileArn: ${err}`);
2038
+ }
2039
+ return {
2040
+ accessToken: tok.accessToken,
2041
+ refreshToken: tok.refreshToken,
2042
+ refreshPacked: `${tok.refreshToken}|${regResult.clientId}|${regResult.clientSecret}|idc`,
2043
+ profileArn,
2044
+ region: detectedRegion,
2045
+ authMethod: "idc",
2046
+ expiresAt: Date.now() + (tok.expiresIn ?? 3600) * 1000 - EXPIRES_BUFFER_MS
2047
+ };
2048
+ }
2049
+ if (!result?.code) {
2050
+ throw new Error("Missing authorization code — sign-in was not completed");
2051
+ }
2052
+ const tokenRedirectUri = buildTokenRedirectUri(result.callbackPath, result.loginOption);
2053
+ log.info("[social-login] Exchanging authorization code…");
2054
+ const resp = await fetch(`${KIRO_SOCIAL_AUTH_ENDPOINT}/oauth/token`, {
2055
+ method: "POST",
2056
+ headers: { "Content-Type": "application/json", "User-Agent": "opencode-kiro" },
2057
+ body: JSON.stringify({
2058
+ code: result.code,
2059
+ code_verifier: verifier,
2060
+ redirect_uri: tokenRedirectUri
2061
+ })
2062
+ });
2063
+ if (!resp.ok) {
2064
+ const body = await resp.text().catch(() => "");
2065
+ throw new Error(`Token exchange failed: ${resp.status} ${body}`);
2066
+ }
2067
+ const data = await resp.json();
2068
+ if (!data.accessToken || !data.refreshToken) {
2069
+ throw new Error("Token exchange returned no tokens");
2070
+ }
2071
+ if (data.profileArn) {
2072
+ try {
2073
+ const apiRegion = resolveApiRegion(BUILDER_ID_REGION);
2074
+ const apiModels = await fetchAvailableModels(data.accessToken, apiRegion, data.profileArn);
2075
+ setCachedDynamicModels(buildModelsFromApi(apiModels));
2076
+ log.info(`[social-login] Fetched and cached ${apiModels.length} models`);
2077
+ } catch (err) {
2078
+ log.warn(`[social-login] Failed to fetch models: ${err}`);
2079
+ }
2080
+ }
2081
+ return {
2082
+ accessToken: data.accessToken,
2083
+ refreshToken: data.refreshToken,
2084
+ refreshPacked: `${data.refreshToken}|||social`,
2085
+ profileArn: data.profileArn,
2086
+ region: BUILDER_ID_REGION,
2087
+ authMethod: "social",
2088
+ expiresAt: Date.now() + (data.expiresIn ?? 3600) * 1000 - EXPIRES_BUFFER_MS
2089
+ };
2090
+ } finally {
2091
+ callbackServer.server.close();
2092
+ }
2093
+ };
2094
+ return { signInUrl, waitForCredentials };
2095
+ }
2096
+
2097
+ // src/file-logger.ts
2098
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
2099
+ var LOG_DIR = "/tmp/kiro-logs";
2100
+ var REQUESTS_FILE = `${LOG_DIR}/requests.log`;
2101
+ var RESPONSES_FILE = `${LOG_DIR}/responses.log`;
2102
+ var ERRORS_FILE = `${LOG_DIR}/errors.log`;
2103
+ var dirEnsured = false;
2104
+ function isEnabled() {
2105
+ return true;
2106
+ }
2107
+ function ensureDir() {
2108
+ if (dirEnsured)
2109
+ return;
2110
+ try {
2111
+ mkdirSync2(LOG_DIR, { recursive: true });
2112
+ dirEnsured = true;
2113
+ } catch {}
2114
+ }
2115
+ function writeLine(file, data) {
2116
+ if (!isEnabled())
2117
+ return;
2118
+ ensureDir();
2119
+ const entry = {
2120
+ ts: new Date().toISOString(),
2121
+ ...data
2122
+ };
2123
+ try {
2124
+ appendFileSync2(file, JSON.stringify(entry) + `
2125
+ `);
2126
+ } catch {}
2127
+ }
2128
+ function logRequest(meta, requestBody) {
2129
+ writeLine(REQUESTS_FILE, {
2130
+ type: "request",
2131
+ ...meta,
2132
+ body: safeParseJson(requestBody)
2133
+ });
2134
+ }
2135
+ function logResponseEvent(event) {
2136
+ writeLine(RESPONSES_FILE, {
2137
+ type: "response_event",
2138
+ eventType: event.type,
2139
+ seq: event.eventSeq,
2140
+ data: event.data
2141
+ });
2142
+ }
2143
+ function logResponseDone(meta) {
2144
+ writeLine(RESPONSES_FILE, {
2145
+ type: "response_done",
2146
+ ...meta
2147
+ });
2148
+ }
2149
+ function logHttpError(meta) {
2150
+ writeLine(ERRORS_FILE, {
2151
+ type: "http_error",
2152
+ ...meta
2153
+ });
2154
+ }
2155
+ function logStreamError(meta) {
2156
+ writeLine(ERRORS_FILE, {
2157
+ type: "stream_error",
2158
+ ...meta
2159
+ });
2160
+ }
2161
+ function logCaughtError(meta) {
2162
+ writeLine(ERRORS_FILE, {
2163
+ type: "caught_error",
2164
+ ...meta
2165
+ });
2166
+ }
2167
+ function safeParseJson(s) {
2168
+ try {
2169
+ return JSON.parse(s);
2170
+ } catch {
2171
+ return s;
2172
+ }
2173
+ }
1381
2174
 
1382
2175
  // src/transform.ts
1383
- import { createHash } from "node:crypto";
2176
+ import { createHash as createHash2 } from "node:crypto";
1384
2177
 
1385
2178
  // src/kiro-defaults.ts
1386
2179
  var SYSTEM_SEED_INSTRUCTION = `Follow this instruction: # Kiro CLI Default Agent
@@ -1463,7 +2256,7 @@ var KIRO_TOOL_USE_ID_RE = /^tooluse_[A-Za-z0-9]+$/;
1463
2256
  function toKiroToolUseId(id) {
1464
2257
  if (KIRO_TOOL_USE_ID_RE.test(id))
1465
2258
  return id;
1466
- const digest = createHash("sha256").update(id).digest("hex").slice(0, 22);
2259
+ const digest = createHash2("sha256").update(id).digest("hex").slice(0, 22);
1467
2260
  return `tooluse_${digest}`;
1468
2261
  }
1469
2262
  var ALLOWED_SCHEMA_KEYS = new Set([
@@ -1598,15 +2391,18 @@ ${uim.content}`;
1598
2391
  }
1599
2392
  if (msg.role === "assistant") {
1600
2393
  let armContent = "";
2394
+ let armReasoningText = "";
2395
+ let armReasoningSignature = "";
1601
2396
  const armToolUses = [];
1602
2397
  if (Array.isArray(msg.content)) {
1603
2398
  for (const block of msg.content) {
1604
2399
  if (block.type === "text") {
1605
2400
  armContent += block.text;
1606
2401
  } else if (block.type === "thinking") {
1607
- armContent = `<thinking>${block.thinking}</thinking>
1608
-
1609
- ${armContent}`;
2402
+ const tb = block;
2403
+ armReasoningText += tb.thinking;
2404
+ if (tb.thinkingSignature)
2405
+ armReasoningSignature = tb.thinkingSignature;
1610
2406
  } else if (block.type === "toolCall") {
1611
2407
  const tc = block;
1612
2408
  armToolUses.push({
@@ -1617,12 +2413,15 @@ ${armContent}`;
1617
2413
  }
1618
2414
  }
1619
2415
  }
1620
- if (!armContent && armToolUses.length === 0)
2416
+ const hasReasoning = armReasoningText.length > 0;
2417
+ if (!armContent && armToolUses.length === 0 && !hasReasoning)
1621
2418
  continue;
2419
+ const reasoningContent = hasReasoning && armReasoningSignature ? { reasoningText: { text: armReasoningText, signature: armReasoningSignature } } : undefined;
1622
2420
  history.push({
1623
2421
  assistantResponseMessage: {
1624
2422
  content: armContent,
1625
- ...armToolUses.length > 0 ? { toolUses: armToolUses } : {}
2423
+ ...armToolUses.length > 0 ? { toolUses: armToolUses } : {},
2424
+ ...reasoningContent ? { reasoningContent } : {}
1626
2425
  }
1627
2426
  });
1628
2427
  continue;
@@ -1794,49 +2593,6 @@ function emitHiddenReasoningLate(output, stream) {
1794
2593
  partial: output
1795
2594
  });
1796
2595
  }
1797
- var profileArnCache = new Map;
1798
- var profileArnSkipResolution = false;
1799
- function seedProfileArn(endpoint, arn) {
1800
- profileArnCache.set(endpoint, arn);
1801
- }
1802
- async function resolveProfileArn(accessToken, endpoint) {
1803
- if (profileArnSkipResolution)
1804
- return;
1805
- const cached = profileArnCache.get(endpoint);
1806
- if (cached !== undefined)
1807
- return cached;
1808
- try {
1809
- const ep = new URL(endpoint);
1810
- ep.hostname = ep.hostname.replace("runtime.", "management.");
1811
- ep.pathname = "/";
1812
- ep.search = "";
1813
- ep.hash = "";
1814
- const resp = await fetch(ep.toString(), {
1815
- method: "POST",
1816
- headers: {
1817
- "Content-Type": "application/x-amz-json-1.0",
1818
- Authorization: `Bearer ${accessToken}`,
1819
- "X-Amz-Target": "AmazonCodeWhispererService.ListAvailableProfiles"
1820
- },
1821
- body: "{}"
1822
- });
1823
- if (!resp.ok) {
1824
- log.debug(`profileArn resolution failed: ${resp.status} ${resp.statusText}`);
1825
- return;
1826
- }
1827
- const j = await resp.json();
1828
- const arn = j.profiles?.find((p) => p.arn)?.arn;
1829
- if (!arn) {
1830
- log.debug("profileArn resolution returned no profile ARN");
1831
- return;
1832
- }
1833
- profileArnCache.set(endpoint, arn);
1834
- return arn;
1835
- } catch (error) {
1836
- log.debug(`profileArn resolution threw: ${error instanceof Error ? error.message : String(error)}`);
1837
- return;
1838
- }
1839
- }
1840
2596
  function emitToolCall(state, output, stream) {
1841
2597
  if (!state.input.trim())
1842
2598
  state.input = "{}";
@@ -1922,9 +2678,9 @@ ${systemPrompt}` : ""}`;
1922
2678
  const normalized = normalizeMessages(context.messages);
1923
2679
  const {
1924
2680
  history,
1925
- systemPrepended,
2681
+ systemPrepended: _systemPrepended,
1926
2682
  currentMsgStartIdx
1927
- } = buildHistory(normalized, kiroModelId, systemPrompt);
2683
+ } = buildHistory(normalized, kiroModelId);
1928
2684
  const seedInstruction = SYSTEM_SEED_INSTRUCTION.replace("{{modelId}}", kiroModelId);
1929
2685
  const seedPair = [
1930
2686
  { userInputMessage: { content: seedInstruction, origin: "KIRO_CLI" } },
@@ -1964,7 +2720,7 @@ ${systemPrompt}` : ""}`;
1964
2720
  const hasReasoning = armReasoningText.length > 0;
1965
2721
  if (armContent || armToolUses.length > 0 || hasReasoning) {
1966
2722
  const last = history[history.length - 1];
1967
- const reasoningContent = hasReasoning ? { reasoningText: { text: armReasoningText, signature: armReasoningSignature } } : undefined;
2723
+ const reasoningContent = hasReasoning && armReasoningSignature ? { reasoningText: { text: armReasoningText, signature: armReasoningSignature } } : undefined;
1968
2724
  if (last && !last.userInputMessage && last.assistantResponseMessage) {
1969
2725
  last.assistantResponseMessage.content += `
1970
2726
 
@@ -2040,7 +2796,7 @@ ${armContent}`;
2040
2796
  currentContent = "Tool results provided.";
2041
2797
  } else if (firstMsg?.role === "user") {
2042
2798
  currentContent = typeof firstMsg.content === "string" ? firstMsg.content : getContentText(firstMsg);
2043
- if (systemPrompt && !systemPrepended) {
2799
+ if (systemPrompt) {
2044
2800
  currentContent = `${systemPrompt}
2045
2801
 
2046
2802
  ${currentContent}`;
@@ -2138,6 +2894,14 @@ ${currentContent}`;
2138
2894
  __require("fs").writeFileSync("/tmp/kiro-last-request.json", requestBody);
2139
2895
  } catch {}
2140
2896
  }
2897
+ logRequest({
2898
+ endpoint,
2899
+ model: model.id,
2900
+ historyLength: history.length,
2901
+ requestBodyChars: requestBody.length,
2902
+ attempt: retryCount,
2903
+ conversationId
2904
+ }, requestBody);
2141
2905
  response = await fetch(endpoint, {
2142
2906
  method: "POST",
2143
2907
  headers: {
@@ -2169,6 +2933,15 @@ ${currentContent}`;
2169
2933
  status: response.status,
2170
2934
  body: errText
2171
2935
  });
2936
+ logHttpError({
2937
+ status: response.status,
2938
+ statusText: response.statusText,
2939
+ body: errText,
2940
+ endpoint,
2941
+ model: model.id,
2942
+ attempt: retryCount,
2943
+ historyLength: history.length
2944
+ });
2172
2945
  if (isCapacityError(errText) && capacityRetryCount < CAPACITY_MAX_RETRIES) {
2173
2946
  capacityRetryCount++;
2174
2947
  const delayMs = exponentialBackoff(capacityRetryCount - 1, CAPACITY_BASE_DELAY_MS, CAPACITY_MAX_DELAY_MS);
@@ -2202,12 +2975,12 @@ ${currentContent}`;
2202
2975
  if (response.status === 401) {
2203
2976
  const permanent = isPermanentError(errText);
2204
2977
  if (permanent) {
2205
- profileArnCache.delete(endpoint);
2978
+ resetProfileArnCache();
2206
2979
  throw new Error(`Kiro API error: credentials permanently invalid — run /login kiro to re-authenticate. ${errText}`);
2207
2980
  }
2208
2981
  }
2209
2982
  if (response.status === 403) {
2210
- profileArnCache.delete(endpoint);
2983
+ resetProfileArnCache();
2211
2984
  throw new Error(`Kiro API error: access token rejected (403) — run /login kiro to re-authenticate. ${errText}`);
2212
2985
  }
2213
2986
  throw new Error(`Kiro API error: ${response.status} ${response.statusText} ${errText}`);
@@ -2312,6 +3085,9 @@ ${currentContent}`;
2312
3085
  log.debug("stream.event", { seq: eventSeq++, event: ev });
2313
3086
  }
2314
3087
  }
3088
+ for (const ev of events) {
3089
+ logResponseEvent({ type: ev.type, data: ev.data, eventSeq });
3090
+ }
2315
3091
  for (const event of events) {
2316
3092
  switch (event.type) {
2317
3093
  case "contextUsage": {
@@ -2402,6 +3178,12 @@ ${currentContent}`;
2402
3178
  }
2403
3179
  case "error": {
2404
3180
  streamError = event.data.message ? `${event.data.error}: ${event.data.message}` : event.data.error;
3181
+ logStreamError({
3182
+ error: streamError,
3183
+ context: "stream_event",
3184
+ model: model.id,
3185
+ attempt: retryCount
3186
+ });
2405
3187
  reader.cancel().catch(() => {});
2406
3188
  break;
2407
3189
  }
@@ -2416,7 +3198,14 @@ ${currentContent}`;
2416
3198
  if (retryCount < MAX_RETRIES) {
2417
3199
  retryCount++;
2418
3200
  const delayMs = exponentialBackoff(retryCount - 1, 1000, MAX_RETRY_DELAY_MS);
2419
- log.info(`stream ${firstTokenTimedOut ? "first-token timed out" : idleCancelled ? "idle timed out" : `error: ${streamError}`} — retrying (${retryCount}/${MAX_RETRIES})`);
3201
+ const streamErrDesc = firstTokenTimedOut ? "first-token timed out" : idleCancelled ? "idle timed out" : `error: ${streamError}`;
3202
+ logStreamError({
3203
+ error: streamErrDesc,
3204
+ context: "retry",
3205
+ model: model.id,
3206
+ attempt: retryCount
3207
+ });
3208
+ log.info(`stream ${streamErrDesc} — retrying (${retryCount}/${MAX_RETRIES})`);
2420
3209
  cancelHiddenShim();
2421
3210
  await abortableDelay(delayMs, options?.signal);
2422
3211
  output.content = [];
@@ -2491,6 +3280,13 @@ ${currentContent}`;
2491
3280
  sawAnyToolCalls,
2492
3281
  usage: output.usage
2493
3282
  });
3283
+ logResponseDone({
3284
+ stopReason: output.stopReason,
3285
+ emittedToolCalls,
3286
+ usage: output.usage,
3287
+ contentBlocks: output.content.length,
3288
+ model: model.id
3289
+ });
2494
3290
  stream.end();
2495
3291
  return;
2496
3292
  }
@@ -2498,6 +3294,11 @@ ${currentContent}`;
2498
3294
  output.stopReason = options?.signal?.aborted ? "aborted" : "error";
2499
3295
  output.errorMessage = error instanceof Error ? error.message : String(error);
2500
3296
  log.debug("response.caught", { stopReason: output.stopReason, error: output.errorMessage });
3297
+ logCaughtError({
3298
+ stopReason: output.stopReason,
3299
+ errorMessage: output.errorMessage,
3300
+ model: model.id
3301
+ });
2501
3302
  if (hiddenShimTimer) {
2502
3303
  clearTimeout(hiddenShimTimer);
2503
3304
  hiddenShimTimer = null;
@@ -2515,6 +3316,8 @@ ${currentContent}`;
2515
3316
 
2516
3317
  // src/server.ts
2517
3318
  init_debug();
3319
+ init_models();
3320
+ init_models();
2518
3321
 
2519
3322
  // src/dashboard-stats.ts
2520
3323
  var MAX_HISTORY = 100;
@@ -2887,11 +3690,29 @@ async function initGatewayAuth() {
2887
3690
  expiresAt: Date.now() + 3500000
2888
3691
  };
2889
3692
  log.info(`[gateway-auth] Initialized (method=${imported.authMethod}, region=${imported.region})`);
3693
+ let activeAccessToken = imported.accessToken;
3694
+ if (imported.refreshToken) {
3695
+ try {
3696
+ log.info("[gateway-auth] Refreshing token at startup…");
3697
+ const refreshed = await refreshKiroToken(_creds.refreshPacked, _creds.region, _creds.authMethod);
3698
+ _creds.accessToken = refreshed.access;
3699
+ _creds.refreshPacked = refreshed.refresh;
3700
+ _creds.expiresAt = refreshed.expires;
3701
+ activeAccessToken = refreshed.access;
3702
+ log.info("[gateway-auth] Token refreshed on startup successfully");
3703
+ } catch (err) {
3704
+ log.warn("[gateway-auth] Startup token refresh failed, trying with existing token", err);
3705
+ }
3706
+ }
2890
3707
  try {
2891
- const apiModels = await fetchAvailableModels(imported.accessToken, imported.region, imported.profileArn);
2892
- const built = buildModelsFromApi(apiModels);
2893
- setCachedDynamicModels(built);
2894
- log.info(`[kiro-models.fetched] Found ${built.length} available models`);
3708
+ if (imported.profileArn) {
3709
+ const apiModels = await fetchAvailableModels(activeAccessToken, imported.region, imported.profileArn);
3710
+ const built = buildModelsFromApi(apiModels);
3711
+ setCachedDynamicModels(built);
3712
+ log.info(`[kiro-models.fetched] Found ${built.length} available models`);
3713
+ } else {
3714
+ log.info(`[kiro-models.fetched] Skipping fetch, no profileArn available`);
3715
+ }
2895
3716
  } catch (err) {
2896
3717
  log.warn("[gateway-auth] Failed to fetch dynamic models (will fallback to static list)", err);
2897
3718
  }
@@ -2952,6 +3773,36 @@ function startGatewayServer(port = 0) {
2952
3773
  headers: { "Content-Type": "application/json" }
2953
3774
  });
2954
3775
  }
3776
+ if (url.pathname === "/auth/login" && req.method === "GET") {
3777
+ try {
3778
+ const { signInUrl, waitForCredentials } = await startSocialLogin();
3779
+ log.info("[gateway] Social login initiated, redirecting to Kiro sign-in");
3780
+ waitForCredentials().then((creds) => {
3781
+ _creds = {
3782
+ accessToken: creds.accessToken,
3783
+ refreshPacked: creds.refreshPacked,
3784
+ region: creds.region,
3785
+ authMethod: creds.authMethod,
3786
+ profileArn: creds.profileArn,
3787
+ expiresAt: creds.expiresAt
3788
+ };
3789
+ if (creds.profileArn) {
3790
+ seedProfileArn(creds.profileArn);
3791
+ }
3792
+ log.info(`[gateway] Login completed (${creds.authMethod}) — credentials updated`);
3793
+ }).catch((err) => {
3794
+ log.error("[gateway] Login failed:", err);
3795
+ });
3796
+ return new Response(null, {
3797
+ status: 302,
3798
+ headers: { Location: signInUrl }
3799
+ });
3800
+ } catch (err) {
3801
+ const msg = err instanceof Error ? err.message : String(err);
3802
+ log.error("[gateway] Failed to start social login:", msg);
3803
+ return anthropicError(500, "api_error", `Failed to start login: ${msg}`);
3804
+ }
3805
+ }
2955
3806
  if ((url.pathname === "/v1/messages" || url.pathname === "/messages") && req.method === "POST") {
2956
3807
  let accessToken;
2957
3808
  try {
@@ -3003,7 +3854,7 @@ function startGatewayServer(port = 0) {
3003
3854
  const reasoningEffort = body.output_config?.effort ?? body.reasoning_effort ?? undefined;
3004
3855
  log.info(`[gateway] → ${kiroEndpoint} model=${anthropicModelId} region=${apiRegion} stream=${streamRequested}`);
3005
3856
  if (_creds.profileArn) {
3006
- seedProfileArn(kiroEndpoint, _creds.profileArn);
3857
+ seedProfileArn(_creds.profileArn);
3007
3858
  }
3008
3859
  const kiroStream = streamKiro(piModel, context, {
3009
3860
  apiKey: accessToken,
@@ -3374,6 +4225,7 @@ function translateAnthropicToolsToPi(tools) {
3374
4225
 
3375
4226
  // src/index.ts
3376
4227
  init_debug();
4228
+ init_models();
3377
4229
  process.env.KIRO_LOG = process.env.KIRO_LOG || "debug";
3378
4230
  process.env.KIRO_LOG_FILE = process.env.KIRO_LOG_FILE || "/tmp/opencode-kiro.log";
3379
4231
  var gatewayServer = null;
@@ -3422,30 +4274,28 @@ var KiroPlugin = async (input) => {
3422
4274
  label: "AWS Builder ID (personal account)",
3423
4275
  prompts: [],
3424
4276
  authorize: async () => {
3425
- const result = await tryRegisterAndAuthorize(BUILDER_ID_START_URL, BUILDER_ID_REGION);
3426
- if (!result) {
3427
- throw new Error("Could not authorize with AWS Builder ID.");
3428
- }
4277
+ const { signInUrl, waitForCredentials } = await startSocialLogin();
3429
4278
  return {
3430
- url: result.devAuth.verificationUriComplete,
3431
- instructions: `AWS Verification Code: ${result.devAuth.userCode}
3432
- Complete authorization in your browser, then OpenCode will continue automatically.`,
4279
+ url: signInUrl,
4280
+ instructions: "Complete sign-in in your browser. OpenCode will continue automatically.",
3433
4281
  method: "auto",
3434
4282
  callback: async () => {
3435
- const tok = await pollForToken(result.oidcEndpoint, result.clientId, result.clientSecret, result.devAuth, undefined);
3436
- if (!tok.accessToken || !tok.refreshToken) {
4283
+ try {
4284
+ const creds = await waitForCredentials();
4285
+ return {
4286
+ type: "success",
4287
+ access: creds.accessToken,
4288
+ refresh: creds.refreshPacked,
4289
+ expires: creds.expiresAt,
4290
+ metadata: {
4291
+ region: creds.region,
4292
+ authMethod: creds.authMethod,
4293
+ profileArn: creds.profileArn
4294
+ }
4295
+ };
4296
+ } catch {
3437
4297
  return { type: "failed" };
3438
4298
  }
3439
- return {
3440
- type: "success",
3441
- access: tok.accessToken,
3442
- refresh: `${tok.refreshToken}|${result.clientId}|${result.clientSecret}|builder-id`,
3443
- expires: Date.now() + (tok.expiresIn ?? 3600) * 1000 - EXPIRES_BUFFER_MS,
3444
- metadata: {
3445
- region: BUILDER_ID_REGION,
3446
- authMethod: "builder-id"
3447
- }
3448
- };
3449
4299
  }
3450
4300
  };
3451
4301
  }
@@ -3496,14 +4346,25 @@ Complete authorization in your browser, then OpenCode will continue automaticall
3496
4346
  if (!tok.accessToken || !tok.refreshToken) {
3497
4347
  return { type: "failed" };
3498
4348
  }
4349
+ const apiRegion = resolveApiRegion(detectedRegion);
4350
+ const arn = await resolveProfileArn(tok.accessToken, apiRegion);
4351
+ if (arn) {
4352
+ try {
4353
+ const models = await fetchAvailableModels(tok.accessToken, apiRegion, arn);
4354
+ setCachedDynamicModels(buildModelsFromApi(models));
4355
+ } catch (e) {
4356
+ log.warn("Failed to precache models", e);
4357
+ }
4358
+ }
3499
4359
  return {
3500
4360
  type: "success",
3501
4361
  access: tok.accessToken,
3502
- refresh: `${tok.refreshToken}|${result.clientId}|${result.clientSecret}|idc`,
4362
+ refresh: `${tok.refreshToken}|${result.clientId}|${result.clientSecret}|idc||`,
3503
4363
  expires: Date.now() + (tok.expiresIn ?? 3600) * 1000 - EXPIRES_BUFFER_MS,
3504
4364
  metadata: {
3505
4365
  region: detectedRegion,
3506
- authMethod: "idc"
4366
+ authMethod: "idc",
4367
+ profileArn: arn
3507
4368
  }
3508
4369
  };
3509
4370
  }
@@ -3527,7 +4388,9 @@ Make sure Kiro CLI or IDE is installed and you're logged in, then try again.`);
3527
4388
  imported.refreshToken,
3528
4389
  imported.clientId || "",
3529
4390
  imported.clientSecret || "",
3530
- authMethod
4391
+ authMethod,
4392
+ imported.source || "",
4393
+ imported.tokenKey || ""
3531
4394
  ];
3532
4395
  return {
3533
4396
  url: "",
@@ -3583,7 +4446,7 @@ Make sure Kiro CLI or IDE is installed and you're logged in, then try again.`);
3583
4446
  throw new Error("No refresh token provided.");
3584
4447
  }
3585
4448
  const region = inputs.region?.trim() || "us-east-1";
3586
- const packed = `${refreshToken}|||desktop`;
4449
+ const packed = `${refreshToken}|||desktop||`;
3587
4450
  return {
3588
4451
  url: "",
3589
4452
  method: "auto",
@@ -3611,7 +4474,7 @@ Make sure Kiro CLI or IDE is installed and you're logged in, then try again.`);
3611
4474
  cfg.provider = cfg.provider ?? {};
3612
4475
  cfg.provider.kiro = cfg.provider.kiro ?? {};
3613
4476
  const kiro = cfg.provider.kiro;
3614
- kiro.name = kiro.name ?? "Kiro";
4477
+ kiro.name = kiro.name ?? "Kiro AWS";
3615
4478
  kiro.npm = kiro.npm ?? "@ai-sdk/anthropic";
3616
4479
  kiro.api = kiro.api ?? `http://127.0.0.1:${localPort}/v1`;
3617
4480
  kiro.models = kiro.models ?? {};