@javargasm/pi-kiro 0.3.0 → 0.4.3

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/extension.js CHANGED
@@ -120,19 +120,37 @@ var init_debug = __esm(() => {
120
120
  // src/kiro-cli-sync.ts
121
121
  var exports_kiro_cli_sync = {};
122
122
  __export(exports_kiro_cli_sync, {
123
+ selectKiroTokenRowForWrite: () => selectKiroTokenRowForWrite,
123
124
  saveKiroCliCredentials: () => saveKiroCliCredentials,
125
+ sameKiroCliCredential: () => sameKiroCliCredential,
126
+ importFromKiroSsoCache: () => importFromKiroSsoCache,
124
127
  importFromKiroCli: () => importFromKiroCli,
125
128
  getKiroCliCredentialsAllowExpired: () => getKiroCliCredentialsAllowExpired
126
129
  });
127
130
  import { homedir } from "node:os";
128
131
  import { join } from "node:path";
129
- import { existsSync } from "node:fs";
132
+ import { spawn } from "node:child_process";
133
+ import { existsSync, readFileSync } from "node:fs";
130
134
  function getKiroDbPath() {
131
135
  const home = homedir();
136
+ if (process.platform === "darwin") {
137
+ return join(home, "Library", "Application Support", "kiro-cli", "data.sqlite3");
138
+ }
132
139
  if (process.platform === "win32") {
133
- return join(process.env.APPDATA || join(home, "AppData", "Roaming"), "kiro", "db", "kiro.db");
140
+ return join(process.env.APPDATA || join(home, "AppData", "Roaming"), "kiro-cli", "data.sqlite3");
141
+ }
142
+ const xdgData = process.env.XDG_DATA_HOME;
143
+ if (xdgData && xdgData.length > 0) {
144
+ return join(xdgData, "kiro-cli", "data.sqlite3");
134
145
  }
135
- return join(home, ".kiro", "db", "kiro.db");
146
+ return join(home, ".local", "share", "kiro-cli", "data.sqlite3");
147
+ }
148
+ function getKiroSsoCachePath() {
149
+ const home = homedir();
150
+ if (process.platform === "win32") {
151
+ return join(process.env.USERPROFILE || home, ".aws", "sso", "cache", "kiro-auth-token.json");
152
+ }
153
+ return join(home, ".aws", "sso", "cache", "kiro-auth-token.json");
136
154
  }
137
155
  function safeJsonParse(value) {
138
156
  if (typeof value !== "string")
@@ -143,11 +161,112 @@ function safeJsonParse(value) {
143
161
  return null;
144
162
  }
145
163
  }
164
+ function sqliteQuote(value) {
165
+ return `'${value.replaceAll("'", "''")}'`;
166
+ }
167
+ function runSqliteCli(dbPath, sql, options) {
168
+ return new Promise((resolve2) => {
169
+ const args = [
170
+ ...options.readonly ? ["-readonly"] : [],
171
+ "-cmd",
172
+ `.timeout ${SQLITE_CLI_TIMEOUT_MS}`,
173
+ ...options.json ? ["-json"] : [],
174
+ dbPath
175
+ ];
176
+ const child = spawn("sqlite3", args, { stdio: "pipe" });
177
+ let stdout = "";
178
+ let settled = false;
179
+ const finish = (result) => {
180
+ if (settled)
181
+ return;
182
+ settled = true;
183
+ clearTimeout(timeout);
184
+ resolve2(result);
185
+ };
186
+ const timeout = setTimeout(() => {
187
+ child.kill();
188
+ log.debug("sqlite3 CLI timed out while reading Kiro DB");
189
+ finish(null);
190
+ }, SQLITE_CLI_TIMEOUT_MS);
191
+ child.stdout?.setEncoding("utf8");
192
+ child.stdout?.on("data", (chunk) => {
193
+ stdout += chunk;
194
+ });
195
+ child.on("error", () => {
196
+ log.debug("sqlite3 CLI unavailable for Kiro DB access");
197
+ finish(null);
198
+ });
199
+ child.on("close", (code) => {
200
+ if (code === 0)
201
+ finish(stdout);
202
+ else {
203
+ log.debug("sqlite3 CLI failed while accessing Kiro DB");
204
+ finish(null);
205
+ }
206
+ });
207
+ child.stdin?.end(`${sql}
208
+ `);
209
+ });
210
+ }
211
+ function parseAuthKvRows(value) {
212
+ if (!Array.isArray(value))
213
+ return null;
214
+ const rows = [];
215
+ for (const item of value) {
216
+ if (!item || typeof item !== "object")
217
+ continue;
218
+ const record = item;
219
+ if (typeof record.key === "string" && typeof record.value === "string") {
220
+ rows.push({ key: record.key, value: record.value });
221
+ }
222
+ }
223
+ return rows;
224
+ }
225
+ function extractActiveProfileArnFromStateRows(value) {
226
+ if (!Array.isArray(value))
227
+ return;
228
+ const first = value[0];
229
+ if (!first || typeof first !== "object")
230
+ return;
231
+ const record = first;
232
+ const parsed = safeJsonParse(record.value);
233
+ const arn = parsed?.arn || parsed?.profileArn || parsed?.profile_arn;
234
+ return typeof arn === "string" && arn.trim() ? arn.trim() : undefined;
235
+ }
236
+ function parseSqliteChanges(value) {
237
+ if (!Array.isArray(value))
238
+ return 0;
239
+ const first = value[0];
240
+ if (!first || typeof first !== "object")
241
+ return 0;
242
+ const changes = first.changes;
243
+ return typeof changes === "number" ? changes : 0;
244
+ }
245
+ async function readKiroAuthKvRowsWithSqliteCli(dbPath) {
246
+ const rowsRaw = await runSqliteCli(dbPath, "SELECT key, value FROM auth_kv", { readonly: true, json: true });
247
+ if (!rowsRaw)
248
+ return null;
249
+ return parseAuthKvRows(safeJsonParse(rowsRaw));
250
+ }
251
+ async function readKiroDbWithSqliteCli(dbPath) {
252
+ const rows = await readKiroAuthKvRowsWithSqliteCli(dbPath);
253
+ if (!rows)
254
+ return null;
255
+ const stateRaw = await runSqliteCli(dbPath, "SELECT value FROM state WHERE key = 'api.codewhisperer.profile'", { readonly: true, json: true });
256
+ const activeProfileArn = stateRaw ? extractActiveProfileArnFromStateRows(safeJsonParse(stateRaw)) : undefined;
257
+ return { rows, activeProfileArn };
258
+ }
259
+ async function writeKiroDbWithSqliteCli(dbPath, tokenKey, updatedValue) {
260
+ const resultRaw = await runSqliteCli(dbPath, `UPDATE auth_kv SET value = ${sqliteQuote(updatedValue)} WHERE key = ${sqliteQuote(tokenKey)}; ` + "SELECT changes() AS changes", { readonly: false, json: true });
261
+ return parseSqliteChanges(safeJsonParse(resultRaw)) > 0;
262
+ }
146
263
  function findClientCreds(obj) {
147
264
  if (!obj || typeof obj !== "object")
148
265
  return {};
149
- if (typeof obj.clientId === "string" && typeof obj.clientSecret === "string") {
150
- return { clientId: obj.clientId, clientSecret: obj.clientSecret };
266
+ const id = obj.clientId ?? obj.client_id;
267
+ const secret = obj.clientSecret ?? obj.client_secret;
268
+ if (typeof id === "string" && typeof secret === "string") {
269
+ return { clientId: id, clientSecret: secret };
151
270
  }
152
271
  for (const key of Object.keys(obj)) {
153
272
  const result = findClientCreds(obj[key]);
@@ -156,6 +275,26 @@ function findClientCreds(obj) {
156
275
  }
157
276
  return {};
158
277
  }
278
+ function isIdcTokenKey(key) {
279
+ return key.includes("odic") || key.includes("oidc") || key.includes("idc");
280
+ }
281
+ function isTokenRow(row) {
282
+ return row.key.includes(":token");
283
+ }
284
+ function tokenReadRank(row) {
285
+ return isIdcTokenKey(row.key) ? 0 : 1;
286
+ }
287
+ function selectKiroTokenRowForWrite(rows, creds) {
288
+ const tokenRows = rows.filter(isTokenRow);
289
+ if (!creds.tokenKey)
290
+ return;
291
+ return tokenRows.find((row) => row.key === creds.tokenKey);
292
+ }
293
+ function sameKiroCliCredential(left, right) {
294
+ if (!left || !right)
295
+ return false;
296
+ 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;
297
+ }
159
298
  function extractRegionFromArn(arn) {
160
299
  if (!arn)
161
300
  return;
@@ -165,55 +304,64 @@ function extractRegionFromArn(arn) {
165
304
  const region = parts[3];
166
305
  return region && region.length > 0 ? region : undefined;
167
306
  }
168
- async function importFromKiroCli() {
307
+ async function importFromKiroDb() {
169
308
  const dbPath = getKiroDbPath();
170
309
  if (!existsSync(dbPath)) {
171
310
  log.debug(`Kiro CLI DB not found at ${dbPath}`);
172
311
  return null;
173
312
  }
174
313
  try {
175
- let Database;
314
+ let rows;
315
+ let activeProfileArn;
316
+ let Database = null;
176
317
  try {
177
318
  Database = (await import("bun:sqlite")).Database;
178
319
  } catch {
179
320
  try {
180
321
  Database = (await import("better-sqlite3")).default;
181
322
  } catch {
182
- log.debug("No SQLite driver available (need bun:sqlite or better-sqlite3)");
183
- return null;
323
+ log.debug("No SQLite driver available (need bun:sqlite or better-sqlite3); trying sqlite3 CLI");
184
324
  }
185
325
  }
186
- const db = new Database(dbPath, { readonly: true });
187
- try {
188
- db.run?.("PRAGMA busy_timeout = 5000") ?? db.exec?.("PRAGMA busy_timeout = 5000");
189
- } catch {}
190
- let rows;
191
- try {
192
- const stmt = db.prepare("SELECT key, value FROM auth_kv");
193
- rows = stmt.all();
194
- } catch {
195
- log.debug("Failed to read auth_kv table from Kiro DB");
326
+ if (Database) {
327
+ const db = new Database(dbPath, { readonly: true });
328
+ try {
329
+ db.run?.("PRAGMA busy_timeout = 5000") ?? db.exec?.("PRAGMA busy_timeout = 5000");
330
+ } catch {}
331
+ try {
332
+ const stmt = db.prepare("SELECT key, value FROM auth_kv");
333
+ rows = stmt.all();
334
+ } catch {
335
+ log.debug("Failed to read auth_kv table from Kiro DB");
336
+ try {
337
+ db.close();
338
+ } catch {}
339
+ return null;
340
+ }
341
+ try {
342
+ const stateStmt = db.prepare("SELECT value FROM state WHERE key = ?");
343
+ const stateRow = stateStmt.get("api.codewhisperer.profile");
344
+ const parsed = safeJsonParse(stateRow?.value);
345
+ const arn = parsed?.arn || parsed?.profileArn || parsed?.profile_arn;
346
+ if (typeof arn === "string" && arn.trim()) {
347
+ activeProfileArn = arn.trim();
348
+ }
349
+ } catch {}
196
350
  try {
197
351
  db.close();
198
352
  } catch {}
199
- return null;
353
+ } else {
354
+ const snapshot = await readKiroDbWithSqliteCli(dbPath);
355
+ if (!snapshot)
356
+ return null;
357
+ rows = snapshot.rows;
358
+ activeProfileArn = snapshot.activeProfileArn;
200
359
  }
201
- let activeProfileArn;
202
- try {
203
- const stateStmt = db.prepare("SELECT value FROM state WHERE key = ?");
204
- const stateRow = stateStmt.get("api.codewhisperer.profile");
205
- const parsed = safeJsonParse(stateRow?.value);
206
- const arn = parsed?.arn || parsed?.profileArn || parsed?.profile_arn;
207
- if (typeof arn === "string" && arn.trim()) {
208
- activeProfileArn = arn.trim();
209
- }
210
- } catch {}
211
360
  const deviceRegRow = rows.find((r) => typeof r?.key === "string" && r.key.includes("device-registration"));
212
361
  const deviceReg = safeJsonParse(deviceRegRow?.value);
213
362
  const regCreds = deviceReg ? findClientCreds(deviceReg) : {};
214
- for (const row of rows) {
215
- if (!row.key.includes(":token"))
216
- continue;
363
+ const tokenRows = rows.filter(isTokenRow).sort((a, b) => tokenReadRank(a) - tokenReadRank(b));
364
+ for (const row of tokenRows) {
217
365
  const data = safeJsonParse(row.value);
218
366
  if (!data)
219
367
  continue;
@@ -221,7 +369,7 @@ async function importFromKiroCli() {
221
369
  const refreshToken = data.refreshToken || data.refresh_token;
222
370
  if (!accessToken && !refreshToken)
223
371
  continue;
224
- const isIdc = row.key.includes("oidc") || row.key.includes("idc");
372
+ const isIdc = isIdcTokenKey(row.key);
225
373
  const authMethod = isIdc ? "idc" : "desktop";
226
374
  const oidcRegion = data.region || "us-east-1";
227
375
  let profileArn = data.profile_arn || data.profileArn;
@@ -235,21 +383,17 @@ async function importFromKiroCli() {
235
383
  region: serviceRegion,
236
384
  authMethod,
237
385
  profileArn,
238
- email: data.email || data.emailAddress
386
+ email: data.email || data.emailAddress,
387
+ source: "kiro-cli-db",
388
+ tokenKey: row.key
239
389
  };
240
390
  if (isIdc && regCreds.clientId) {
241
391
  result.clientId = regCreds.clientId;
242
392
  result.clientSecret = regCreds.clientSecret;
243
393
  }
244
- try {
245
- db.close();
246
- } catch {}
247
394
  log.info(`Imported Kiro CLI credentials (method=${authMethod}, region=${serviceRegion}${result.email ? `, email=${result.email}` : ""})`);
248
395
  return result;
249
396
  }
250
- try {
251
- db.close();
252
- } catch {}
253
397
  log.debug("No valid token entries found in Kiro CLI DB");
254
398
  return null;
255
399
  } catch (err) {
@@ -257,47 +401,108 @@ async function importFromKiroCli() {
257
401
  return null;
258
402
  }
259
403
  }
260
- async function getKiroCliCredentialsAllowExpired() {
261
- return importFromKiroCli();
404
+ function mapSsoCacheAuthMethod(value) {
405
+ if (typeof value !== "string")
406
+ return "idc";
407
+ const v = value.toLowerCase();
408
+ if (v === "builderid" || v === "builder-id")
409
+ return "desktop";
410
+ return "idc";
411
+ }
412
+ async function importFromKiroSsoCache() {
413
+ const path = getKiroSsoCachePath();
414
+ if (!existsSync(path)) {
415
+ log.debug(`Kiro SSO cache not found at ${path}`);
416
+ return null;
417
+ }
418
+ let raw;
419
+ try {
420
+ raw = readFileSync(path, "utf8");
421
+ } catch (err) {
422
+ log.warn(`Failed to read Kiro SSO cache at ${path}: ${err}`);
423
+ return null;
424
+ }
425
+ const token = safeJsonParse(raw);
426
+ if (!token || typeof token !== "object") {
427
+ log.debug(`Kiro SSO cache at ${path} is not valid JSON`);
428
+ return null;
429
+ }
430
+ const accessToken = typeof token.accessToken === "string" ? token.accessToken : "";
431
+ const refreshToken = typeof token.refreshToken === "string" ? token.refreshToken : "";
432
+ if (!accessToken && !refreshToken) {
433
+ log.debug(`Kiro SSO cache at ${path} has no tokens`);
434
+ return null;
435
+ }
436
+ const region = typeof token.region === "string" && token.region.length > 0 ? token.region : "us-east-1";
437
+ const authMethod = mapSsoCacheAuthMethod(token.authMethod);
438
+ log.info(`Imported Kiro SSO cache credentials (method=${authMethod}, region=${region})`);
439
+ return {
440
+ accessToken,
441
+ refreshToken,
442
+ region,
443
+ authMethod,
444
+ source: "kiro-sso-cache"
445
+ };
446
+ }
447
+ async function importFromKiroCli() {
448
+ const dbResult = await importFromKiroDb();
449
+ if (dbResult)
450
+ return dbResult;
451
+ return importFromKiroSsoCache();
452
+ }
453
+ async function getKiroCliCredentialsAllowExpired(exclude) {
454
+ const imported = await importFromKiroCli();
455
+ return sameKiroCliCredential(imported, exclude ?? null) ? null : imported;
262
456
  }
263
457
  async function saveKiroCliCredentials(creds) {
458
+ if (creds.source !== "kiro-cli-db" || !creds.tokenKey) {
459
+ log.debug("Credential write-back skipped: credential did not originate from kiro-cli DB");
460
+ return false;
461
+ }
264
462
  const dbPath = getKiroDbPath();
265
463
  if (!existsSync(dbPath)) {
266
464
  log.debug(`Kiro CLI DB not found at ${dbPath} — cannot save credentials`);
267
465
  return false;
268
466
  }
269
467
  try {
270
- let Database;
468
+ let Database = null;
271
469
  try {
272
470
  Database = (await import("bun:sqlite")).Database;
273
471
  } catch {
274
472
  try {
275
473
  Database = (await import("better-sqlite3")).default;
276
474
  } catch {
277
- log.debug("No SQLite driver available for credential write-back");
278
- return false;
475
+ log.debug("No SQLite driver available for credential write-back; trying sqlite3 CLI");
279
476
  }
280
477
  }
281
- const db = new Database(dbPath);
282
- try {
283
- db.run?.("PRAGMA busy_timeout = 5000") ?? db.exec?.("PRAGMA busy_timeout = 5000");
284
- } catch {}
285
478
  let rows;
286
- try {
287
- const stmt = db.prepare("SELECT key, value FROM auth_kv");
288
- rows = stmt.all();
289
- } catch {
290
- log.debug("Failed to read auth_kv table for credential write-back");
479
+ let db = null;
480
+ if (Database) {
481
+ db = new Database(dbPath);
291
482
  try {
292
- db.close();
483
+ db.run?.("PRAGMA busy_timeout = 5000") ?? db.exec?.("PRAGMA busy_timeout = 5000");
293
484
  } catch {}
294
- return false;
485
+ try {
486
+ const stmt = db.prepare("SELECT key, value FROM auth_kv");
487
+ rows = stmt.all();
488
+ } catch {
489
+ log.debug("Failed to read auth_kv table for credential write-back");
490
+ try {
491
+ db.close();
492
+ } catch {}
493
+ return false;
494
+ }
495
+ } else {
496
+ const cliRows = await readKiroAuthKvRowsWithSqliteCli(dbPath);
497
+ if (!cliRows)
498
+ return false;
499
+ rows = cliRows;
295
500
  }
296
- const tokenRow = rows.find((r) => r.key.includes(":token"));
501
+ const tokenRow = selectKiroTokenRowForWrite(rows, creds);
297
502
  if (!tokenRow) {
298
- log.debug("No token entry found in auth_kv — cannot write back");
503
+ log.debug("No matching token entry found in auth_kv — cannot write back");
299
504
  try {
300
- db.close();
505
+ db?.close();
301
506
  } catch {}
302
507
  return false;
303
508
  }
@@ -309,19 +514,26 @@ async function saveKiroCliCredentials(creds) {
309
514
  refreshToken: creds.refreshToken,
310
515
  refresh_token: creds.refreshToken
311
516
  };
312
- try {
313
- const updateStmt = db.prepare("UPDATE auth_kv SET value = ? WHERE key = ?");
314
- updateStmt.run(JSON.stringify(updated), tokenRow.key);
315
- } catch (err) {
316
- log.warn(`Failed to write credentials back to Kiro CLI DB: ${err}`);
517
+ const updatedValue = JSON.stringify(updated);
518
+ if (db) {
519
+ try {
520
+ const updateStmt = db.prepare("UPDATE auth_kv SET value = ? WHERE key = ?");
521
+ updateStmt.run(updatedValue, tokenRow.key);
522
+ } catch (err) {
523
+ log.warn(`Failed to write credentials back to Kiro CLI DB: ${err}`);
524
+ try {
525
+ db.close();
526
+ } catch {}
527
+ return false;
528
+ }
317
529
  try {
318
530
  db.close();
319
531
  } catch {}
320
- return false;
532
+ } else {
533
+ const wrote = await writeKiroDbWithSqliteCli(dbPath, tokenRow.key, updatedValue);
534
+ if (!wrote)
535
+ return false;
321
536
  }
322
- try {
323
- db.close();
324
- } catch {}
325
537
  log.info("Wrote refreshed credentials back to Kiro CLI DB");
326
538
  return true;
327
539
  } catch (err) {
@@ -329,12 +541,13 @@ async function saveKiroCliCredentials(creds) {
329
541
  return false;
330
542
  }
331
543
  }
544
+ var SQLITE_CLI_TIMEOUT_MS = 5000;
332
545
  var init_kiro_cli_sync = __esm(() => {
333
546
  init_debug();
334
547
  });
335
548
 
336
549
  // src/extension.ts
337
- import { existsSync as existsSync2, readFileSync, writeFileSync } from "node:fs";
550
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "node:fs";
338
551
  import { homedir as homedir2 } from "node:os";
339
552
  import { join as join2 } from "node:path";
340
553
 
@@ -1134,6 +1347,9 @@ function abortableDelay(ms, signal) {
1134
1347
  }
1135
1348
  var profileArnCache = new Map;
1136
1349
  var profileArnSkipResolution = false;
1350
+ function seedProfileArn(endpoint, arn) {
1351
+ profileArnCache.set(endpoint, arn);
1352
+ }
1137
1353
  async function resolveProfileArn(accessToken, endpoint) {
1138
1354
  if (profileArnSkipResolution)
1139
1355
  return;
@@ -1613,8 +1829,9 @@ ${currentContent}`;
1613
1829
  let transientRetryCount = 0;
1614
1830
  let contextTruncationAttempt = 0;
1615
1831
  while (true) {
1616
- const mid = crypto.randomUUID().replace(/-/g, "");
1617
- const ua = `aws-sdk-rust/1.0.0 ua/2.1 os/other lang/rust api/codewhispererstreaming#1.28.3 m/E app/AmazonQ-For-CLI md/appVersion-1.28.3-${mid}`;
1832
+ const osName = resolveOS();
1833
+ const ua = `aws-sdk-rust/1.3.15 ua/2.1 api/codewhispererstreaming/0.1.16551 os/${osName} lang/rust/1.92.0 md/appVersion-2.7.1 app/AmazonQ-For-CLI`;
1834
+ const xAmzUa = `aws-sdk-rust/1.3.15 ua/2.1 api/codewhispererstreaming/0.1.16551 os/${osName} lang/rust/1.92.0 m/F app/AmazonQ-For-CLI`;
1618
1835
  const requestBody = JSON.stringify(request);
1619
1836
  const requestShape = log.isDebug() ? summarizeKiroRequest(request, requestBody) : undefined;
1620
1837
  if (requestShape)
@@ -1632,15 +1849,17 @@ ${currentContent}`;
1632
1849
  method: "POST",
1633
1850
  headers: {
1634
1851
  "Content-Type": "application/x-amz-json-1.0",
1635
- Accept: "application/json",
1852
+ Accept: "*/*",
1853
+ "Accept-Encoding": "gzip",
1636
1854
  Authorization: `Bearer ${accessToken}`,
1637
1855
  "X-Amz-Target": "AmazonCodeWhispererStreamingService.GenerateAssistantResponse",
1638
1856
  "x-amzn-codewhisperer-optout": "true",
1639
1857
  "amz-sdk-invocation-id": crypto.randomUUID(),
1640
- "amz-sdk-request": "attempt=1; max=1",
1641
- "x-amzn-kiro-agent-mode": "vibe",
1642
- "x-amz-user-agent": ua,
1643
- "user-agent": ua
1858
+ "amz-sdk-request": "attempt=1; max=3",
1859
+ "user-agent": ua,
1860
+ "x-amz-user-agent": xAmzUa,
1861
+ Pragma: "no-cache",
1862
+ "Cache-Control": "no-cache"
1644
1863
  },
1645
1864
  body: requestBody,
1646
1865
  signal: options?.signal
@@ -2130,7 +2349,8 @@ var kiroModels = [
2130
2349
  contextWindow: 1e6,
2131
2350
  maxTokens: 128000,
2132
2351
  firstTokenTimeout: 180000,
2133
- supportedEfforts: ["low", "medium", "high", "xhigh", "max"]
2352
+ supportedEfforts: ["low", "medium", "high", "xhigh", "max"],
2353
+ supportsThinkingConfig: true
2134
2354
  },
2135
2355
  {
2136
2356
  ...KIRO_DEFAULTS,
@@ -2141,7 +2361,8 @@ var kiroModels = [
2141
2361
  contextWindow: 1e6,
2142
2362
  maxTokens: 128000,
2143
2363
  firstTokenTimeout: 180000,
2144
- supportedEfforts: ["low", "medium", "high", "xhigh", "max"]
2364
+ supportedEfforts: ["low", "medium", "high", "xhigh", "max"],
2365
+ supportsThinkingConfig: true
2145
2366
  },
2146
2367
  {
2147
2368
  ...KIRO_DEFAULTS,
@@ -2152,7 +2373,8 @@ var kiroModels = [
2152
2373
  contextWindow: 1e6,
2153
2374
  maxTokens: 128000,
2154
2375
  firstTokenTimeout: 180000,
2155
- supportedEfforts: ["low", "medium", "high", "xhigh", "max"]
2376
+ supportedEfforts: ["low", "medium", "high", "xhigh", "max"],
2377
+ supportsThinkingConfig: true
2156
2378
  },
2157
2379
  {
2158
2380
  ...KIRO_DEFAULTS,
@@ -2162,7 +2384,8 @@ var kiroModels = [
2162
2384
  input: MULTIMODAL,
2163
2385
  contextWindow: 1e6,
2164
2386
  maxTokens: 64000,
2165
- supportedEfforts: ["low", "medium", "high", "max"]
2387
+ supportedEfforts: ["low", "medium", "high", "max"],
2388
+ supportsThinkingConfig: true
2166
2389
  },
2167
2390
  {
2168
2391
  ...KIRO_DEFAULTS,
@@ -2172,7 +2395,8 @@ var kiroModels = [
2172
2395
  input: MULTIMODAL,
2173
2396
  contextWindow: 1e6,
2174
2397
  maxTokens: 64000,
2175
- supportedEfforts: ["low", "medium", "high", "max"]
2398
+ supportedEfforts: ["low", "medium", "high", "max"],
2399
+ supportsThinkingConfig: true
2176
2400
  },
2177
2401
  {
2178
2402
  ...KIRO_DEFAULTS,
@@ -2182,7 +2406,8 @@ var kiroModels = [
2182
2406
  input: MULTIMODAL,
2183
2407
  contextWindow: 1e6,
2184
2408
  maxTokens: 64000,
2185
- supportedEfforts: ["low", "medium", "high", "max"]
2409
+ supportedEfforts: ["low", "medium", "high", "max"],
2410
+ supportsThinkingConfig: true
2186
2411
  },
2187
2412
  {
2188
2413
  ...KIRO_DEFAULTS,
@@ -2192,7 +2417,8 @@ var kiroModels = [
2192
2417
  input: MULTIMODAL,
2193
2418
  contextWindow: 1e6,
2194
2419
  maxTokens: 64000,
2195
- supportedEfforts: ["low", "medium", "high", "max"]
2420
+ supportedEfforts: ["low", "medium", "high", "max"],
2421
+ supportsThinkingConfig: true
2196
2422
  },
2197
2423
  {
2198
2424
  ...KIRO_DEFAULTS,
@@ -2330,9 +2556,12 @@ var kiroModels = [
2330
2556
  maxTokens: 65536
2331
2557
  }
2332
2558
  ];
2333
- async function fetchAvailableModels(accessToken, apiRegion) {
2559
+ async function fetchAvailableModels(accessToken, apiRegion, fallbackProfileArn) {
2334
2560
  const runtimeUrl = `https://runtime.${apiRegion}.kiro.dev/`;
2335
- const profileArn = await resolveProfileArn(accessToken, runtimeUrl);
2561
+ let profileArn = await resolveProfileArn(accessToken, runtimeUrl);
2562
+ if (!profileArn && fallbackProfileArn) {
2563
+ profileArn = fallbackProfileArn;
2564
+ }
2336
2565
  if (!profileArn) {
2337
2566
  throw new Error("Missing profileArn: cannot fetch available models.");
2338
2567
  }
@@ -2521,7 +2750,7 @@ async function loginKiro(callbacks) {
2521
2750
  options: [
2522
2751
  { id: "builder-id", label: "AWS Builder ID (personal account)" },
2523
2752
  { id: "idc", label: "IAM Identity Center (enterprise SSO)" },
2524
- { id: "sync", label: "Import from Kiro IDE (auto-sync local DB)" },
2753
+ { id: "sync", label: "Import from Kiro CLI/IDE (auto-sync local DB)" },
2525
2754
  { id: "desktop", label: "Desktop refresh token (manual)" }
2526
2755
  ]
2527
2756
  });
@@ -2567,22 +2796,13 @@ Alternatively, use 'desktop' to paste a refresh token manually.`);
2567
2796
  callbacks.onProgress?.(`Imported from Kiro IDE (${imported.authMethod}, ${imported.region}${imported.email ? `, ${imported.email}` : ""})`);
2568
2797
  try {
2569
2798
  const apiRegion = resolveApiRegion(imported.region);
2570
- const apiModels = await fetchAvailableModels(imported.accessToken, apiRegion);
2799
+ const apiModels = await fetchAvailableModels(imported.accessToken, apiRegion, imported.profileArn);
2571
2800
  setCachedDynamicModels(buildModelsFromApi(apiModels));
2572
2801
  log.info(`Fetched and cached ${apiModels.length} models after CLI sync`);
2573
2802
  } catch (err) {
2574
2803
  log.warn(`Failed to fetch models after CLI sync: ${err}`);
2575
2804
  }
2576
- const refreshPacked = imported.clientId ? `${imported.refreshToken}|${imported.clientId}|${imported.clientSecret ?? ""}|${imported.authMethod}` : `${imported.refreshToken}|||desktop`;
2577
- return {
2578
- refresh: refreshPacked,
2579
- access: imported.accessToken,
2580
- expires: Date.now() + 3600000 - EXPIRES_BUFFER_MS,
2581
- clientId: imported.clientId ?? "",
2582
- clientSecret: imported.clientSecret ?? "",
2583
- region: imported.region,
2584
- authMethod: imported.authMethod
2585
- };
2805
+ return kiroCredsFromCliImport(imported);
2586
2806
  }
2587
2807
  async function loginDesktopManual(callbacks) {
2588
2808
  const refreshRaw = await callbacks.onPrompt({
@@ -2657,13 +2877,19 @@ Complete authorization within 10 minutes.`
2657
2877
  };
2658
2878
  }
2659
2879
  async function syncBackToKiroCli(result) {
2880
+ if (result.kiroSyncSource !== "kiro-cli-db" || !result.kiroSyncTokenKey) {
2881
+ log.debug("Credential sync-back skipped: credential did not originate from kiro-cli DB");
2882
+ return;
2883
+ }
2660
2884
  try {
2661
2885
  const { saveKiroCliCredentials: saveKiroCliCredentials2 } = await Promise.resolve().then(() => (init_kiro_cli_sync(), exports_kiro_cli_sync));
2662
2886
  const synced = await saveKiroCliCredentials2({
2663
2887
  accessToken: result.access,
2664
2888
  refreshToken: result.refresh.split("|")[0] ?? "",
2665
2889
  region: result.region,
2666
- authMethod: result.authMethod === "builder-id" ? "idc" : result.authMethod
2890
+ authMethod: result.authMethod === "builder-id" ? "idc" : result.authMethod,
2891
+ source: result.kiroSyncSource,
2892
+ tokenKey: result.kiroSyncTokenKey
2667
2893
  });
2668
2894
  if (synced)
2669
2895
  log.info("Synced refreshed credentials back to Kiro CLI DB");
@@ -2672,8 +2898,9 @@ async function syncBackToKiroCli(result) {
2672
2898
  }
2673
2899
  }
2674
2900
  function kiroCredsFromCliImport(imported) {
2675
- const authMethod = imported.authMethod === "idc" ? "idc" : "desktop";
2676
- const refreshPacked = imported.clientId ? `${imported.refreshToken}|${imported.clientId}|${imported.clientSecret ?? ""}|${authMethod}` : `${imported.refreshToken}|||desktop`;
2901
+ const hasOidcCreds = !!imported.clientId && !!imported.clientSecret;
2902
+ const authMethod = hasOidcCreds && imported.authMethod === "idc" ? "idc" : "desktop";
2903
+ const refreshPacked = hasOidcCreds ? `${imported.refreshToken}|${imported.clientId}|${imported.clientSecret ?? ""}|${authMethod}` : `${imported.refreshToken}|||desktop`;
2677
2904
  return {
2678
2905
  refresh: refreshPacked,
2679
2906
  access: imported.accessToken,
@@ -2681,7 +2908,9 @@ function kiroCredsFromCliImport(imported) {
2681
2908
  clientId: imported.clientId ?? "",
2682
2909
  clientSecret: imported.clientSecret ?? "",
2683
2910
  region: imported.region,
2684
- authMethod
2911
+ authMethod,
2912
+ kiroSyncSource: imported.source,
2913
+ kiroSyncTokenKey: imported.tokenKey
2685
2914
  };
2686
2915
  }
2687
2916
  async function refreshTokenInner(credentials) {
@@ -2724,7 +2953,9 @@ async function refreshTokenInner(credentials) {
2724
2953
  clientId: "",
2725
2954
  clientSecret: "",
2726
2955
  region,
2727
- authMethod: "desktop"
2956
+ authMethod: "desktop",
2957
+ kiroSyncSource: credentials.kiroSyncSource,
2958
+ kiroSyncTokenKey: credentials.kiroSyncTokenKey
2728
2959
  };
2729
2960
  }
2730
2961
  const endpoint = `https://oidc.${region}.amazonaws.com/token`;
@@ -2753,7 +2984,9 @@ async function refreshTokenInner(credentials) {
2753
2984
  clientId,
2754
2985
  clientSecret,
2755
2986
  region,
2756
- authMethod
2987
+ authMethod,
2988
+ kiroSyncSource: credentials.kiroSyncSource,
2989
+ kiroSyncTokenKey: credentials.kiroSyncTokenKey
2757
2990
  };
2758
2991
  }
2759
2992
  async function refreshKiroToken(credentials) {
@@ -2815,14 +3048,15 @@ async function refreshKiroToken(credentials) {
2815
3048
  try {
2816
3049
  log.debug("refresh.cascade: layer 4 — expired kiro-cli import");
2817
3050
  const { getKiroCliCredentialsAllowExpired: getKiroCliCredentialsAllowExpired2 } = await Promise.resolve().then(() => (init_kiro_cli_sync(), exports_kiro_cli_sync));
2818
- expiredImport = await getKiroCliCredentialsAllowExpired2();
2819
- if (expiredImport?.accessToken && expiredImport !== freshImport) {
3051
+ expiredImport = await getKiroCliCredentialsAllowExpired2(freshImport);
3052
+ if (expiredImport?.accessToken) {
2820
3053
  const result = kiroCredsFromCliImport(expiredImport);
2821
3054
  log.info("refresh.cascade: layer 4 succeeded — using expired kiro-cli credentials");
2822
3055
  return result;
3056
+ } else {
3057
+ errors.push("L4(expired-import): no different expired credentials");
3058
+ log.debug("refresh.cascade: layer 4 — no additional expired credentials");
2823
3059
  }
2824
- errors.push("L4(expired-import): no different expired credentials");
2825
- log.debug("refresh.cascade: layer 4 — no additional expired credentials");
2826
3060
  } catch (err) {
2827
3061
  const msg = err instanceof Error ? err.message : String(err);
2828
3062
  errors.push(`L4(expired-import): ${msg}`);
@@ -2879,7 +3113,7 @@ function readKiroCredentials() {
2879
3113
  const authPath = join2(homedir2(), ".pi", "agent", "auth.json");
2880
3114
  if (!existsSync2(authPath))
2881
3115
  return null;
2882
- const raw = readFileSync(authPath, "utf-8");
3116
+ const raw = readFileSync2(authPath, "utf-8");
2883
3117
  const data = JSON.parse(raw);
2884
3118
  const kiro = data["kiro"];
2885
3119
  if (!kiro?.access || typeof kiro.access !== "string")
@@ -2893,9 +3127,12 @@ function readKiroCredentials() {
2893
3127
  log.warn(`Failed to self-heal auth.json: ${e}`);
2894
3128
  }
2895
3129
  }
3130
+ const metadata = kiro.metadata;
3131
+ const profileArn = typeof metadata?.profileArn === "string" ? metadata.profileArn : undefined;
2896
3132
  return {
2897
3133
  access: kiro.access,
2898
- region: kiro.region || "us-east-1"
3134
+ region: kiro.region || "us-east-1",
3135
+ profileArn
2899
3136
  };
2900
3137
  } catch {
2901
3138
  return null;
@@ -2907,7 +3144,11 @@ async function extension_default(pi) {
2907
3144
  if (creds) {
2908
3145
  try {
2909
3146
  const apiRegion = resolveApiRegion(creds.region);
2910
- const apiModels = await fetchAvailableModels(creds.access, apiRegion);
3147
+ if (creds.profileArn) {
3148
+ const runtimeUrl = resolveRuntimeUrl(apiRegion);
3149
+ seedProfileArn(runtimeUrl + "/", creds.profileArn);
3150
+ }
3151
+ const apiModels = await fetchAvailableModels(creds.access, apiRegion, creds.profileArn);
2911
3152
  const dynamicDefs = buildModelsFromApi(apiModels);
2912
3153
  setCachedDynamicModels(dynamicDefs);
2913
3154
  modelDefs = toProviderModels(dynamicDefs);