@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/CHANGELOG.md +24 -0
- package/dist/core.js +341 -107
- package/dist/extension.d.ts.map +1 -1
- package/dist/extension.js +352 -111
- package/dist/kiro-cli-sync.d.ts +39 -13
- package/dist/kiro-cli-sync.d.ts.map +1 -1
- package/dist/models.d.ts +1 -1
- package/dist/models.d.ts.map +1 -1
- package/dist/oauth.d.ts +5 -0
- package/dist/oauth.d.ts.map +1 -1
- package/dist/stream.d.ts +8 -0
- package/dist/stream.d.ts.map +1 -1
- package/package.json +1 -1
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 {
|
|
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", "
|
|
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, ".
|
|
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
|
-
|
|
150
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
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
|
-
|
|
215
|
-
|
|
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 =
|
|
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
|
-
|
|
261
|
-
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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.
|
|
483
|
+
db.run?.("PRAGMA busy_timeout = 5000") ?? db.exec?.("PRAGMA busy_timeout = 5000");
|
|
293
484
|
} catch {}
|
|
294
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
-
|
|
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
|
|
1617
|
-
const ua = `aws-sdk-rust/1.
|
|
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: "
|
|
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=
|
|
1641
|
-
"
|
|
1642
|
-
"x-amz-user-agent":
|
|
1643
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2676
|
-
const
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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);
|