@javargasm/pi-kiro 0.4.4 → 0.4.5

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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.5
4
+
5
+ ### Patch Changes
6
+
7
+ - fix: resolve profileArn automatically for Builder ID accounts
8
+
9
+ Builder ID device-code login never receives a profileArn, which prevented
10
+ model fetching and streaming. Now the startup resolves it via
11
+ `ListAvailableProfiles` and persists it to auth.json.
12
+
3
13
  ## 0.4.4
4
14
 
5
15
  ### Patch Changes
package/dist/core.js CHANGED
@@ -897,6 +897,24 @@ var kiroModels = [
897
897
  maxTokens: 65536
898
898
  }
899
899
  ];
900
+ async function resolveProfileArn(accessToken, apiRegion) {
901
+ const resp = await fetch(`https://management.${apiRegion}.kiro.dev/`, {
902
+ method: "POST",
903
+ headers: {
904
+ Authorization: `Bearer ${accessToken}`,
905
+ "Content-Type": "application/x-amz-json-1.0",
906
+ "X-Amz-Target": "AmazonCodeWhispererService.ListAvailableProfiles",
907
+ "User-Agent": "pi-kiro"
908
+ },
909
+ body: "{}"
910
+ });
911
+ if (!resp.ok)
912
+ return null;
913
+ const data = await resp.json();
914
+ const profiles = data.profiles ?? [];
915
+ const kiroProfile = profiles.find((p) => p.profileType === "KIRO" && p.status === "ACTIVE");
916
+ return kiroProfile?.arn ?? profiles[0]?.arn ?? null;
917
+ }
900
918
  async function fetchAvailableModels(accessToken, apiRegion, profileArn) {
901
919
  const url = `https://management.${apiRegion}.kiro.dev/?origin=KIRO_CLI&profileArn=${encodeURIComponent(profileArn)}`;
902
920
  const resp = await fetch(url, {
@@ -980,6 +998,8 @@ function setCachedDynamicModels(models) {
980
998
  }
981
999
 
982
1000
  // src/oauth.ts
1001
+ import { createServer } from "node:http";
1002
+ import { randomBytes, createHash } from "node:crypto";
983
1003
  var BUILDER_ID_START_URL = "https://view.awsapps.com/start";
984
1004
  var BUILDER_ID_REGION = "us-east-1";
985
1005
  var SSO_SCOPES = [
@@ -1089,6 +1109,415 @@ async function pollForToken(oidcEndpoint, clientId, clientSecret, devAuth, signa
1089
1109
  }
1090
1110
  throw new Error("Authorization timed out");
1091
1111
  }
1112
+ var KIRO_SOCIAL_PORTAL = "https://app.kiro.dev";
1113
+ var KIRO_SOCIAL_AUTH_ENDPOINT = `https://prod.${BUILDER_ID_REGION}.auth.desktop.kiro.dev`;
1114
+ var SOCIAL_REDIRECT_PORT = 49153;
1115
+ var SOCIAL_REDIRECT_URI = `http://localhost:${SOCIAL_REDIRECT_PORT}`;
1116
+ function generateRandomState() {
1117
+ return randomBytes(16).toString("base64url");
1118
+ }
1119
+ function generateCodeVerifier() {
1120
+ return randomBytes(32).toString("base64url");
1121
+ }
1122
+ function generateCodeChallenge(verifier) {
1123
+ return createHash("sha256").update(verifier).digest("base64url");
1124
+ }
1125
+ function buildSocialSignInURL(redirectUri, codeChallenge, state) {
1126
+ const params = new URLSearchParams;
1127
+ params.set("code_challenge", codeChallenge);
1128
+ params.set("code_challenge_method", "S256");
1129
+ params.set("redirect_from", "kirocli");
1130
+ params.set("redirect_uri", redirectUri);
1131
+ params.set("state", state);
1132
+ return `${KIRO_SOCIAL_PORTAL}/signin?${params.toString()}`;
1133
+ }
1134
+ function parseAuthRedirectInput(input) {
1135
+ const trimmed = input.trim();
1136
+ if (!trimmed)
1137
+ return {};
1138
+ try {
1139
+ const url = new URL(trimmed);
1140
+ return {
1141
+ code: url.searchParams.get("code") ?? undefined,
1142
+ state: url.searchParams.get("state") ?? undefined
1143
+ };
1144
+ } catch {
1145
+ return { code: trimmed };
1146
+ }
1147
+ }
1148
+ function buildTokenRedirectUri(callbackPath, loginOption) {
1149
+ const path = callbackPath || "/oauth/callback";
1150
+ const base = `${SOCIAL_REDIRECT_URI}${path}`;
1151
+ if (loginOption) {
1152
+ return `${base}?login_option=${encodeURIComponent(loginOption)}`;
1153
+ }
1154
+ return base;
1155
+ }
1156
+ function oauthCallbackPage(kind, title, message, redirectUrl = "https://app.kiro.dev") {
1157
+ const borderColor = kind === "success" ? "#22c55e" : "#ef4444";
1158
+ 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>`;
1159
+ const ghostSvg = `<svg width="56" height="56" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
1160
+ <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"/>
1161
+ <circle cx="37" cy="45" r="7" fill="#0a0a0a"/>
1162
+ <circle cx="63" cy="45" r="7" fill="#0a0a0a"/>
1163
+ </svg>`;
1164
+ const redirectHost = (() => {
1165
+ try {
1166
+ return new URL(redirectUrl).hostname;
1167
+ } catch {
1168
+ return redirectUrl;
1169
+ }
1170
+ })();
1171
+ const countdownHtml = kind === "success" ? `
1172
+ <div class="countdown" id="countdown">
1173
+ <svg class="ring" viewBox="0 0 60 60">
1174
+ <circle cx="30" cy="30" r="26" stroke="#1a1a1a" stroke-width="3" fill="none"/>
1175
+ <circle id="ring-progress" cx="30" cy="30" r="26" stroke="#22c55e" stroke-width="3" fill="none"
1176
+ stroke-dasharray="163.36" stroke-dashoffset="0" stroke-linecap="round"
1177
+ transform="rotate(-90 30 30)" style="transition:stroke-dashoffset 1s linear"/>
1178
+ </svg>
1179
+ <span class="countdown-num" id="countdown-num">3</span>
1180
+ </div>
1181
+ <p class="subtitle">Redirecting to <strong>${redirectHost}</strong>…</p>
1182
+ <script>
1183
+ (function(){
1184
+ var n=3, el=document.getElementById('countdown-num'),
1185
+ ring=document.getElementById('ring-progress'), circ=163.36;
1186
+ function tick(){
1187
+ if(n<=0){window.location.href=${JSON.stringify(redirectUrl)};return}
1188
+ el.textContent=n;
1189
+ ring.setAttribute('stroke-dashoffset', String(circ*(1-n/3)));
1190
+ n--;
1191
+ setTimeout(tick,1000);
1192
+ }
1193
+ tick();
1194
+ })();
1195
+ </script>` : `<p class="subtitle">Please close this window and try again</p>`;
1196
+ return `<!DOCTYPE html>
1197
+ <html lang="en">
1198
+ <head>
1199
+ <meta charset="utf-8">
1200
+ <meta name="viewport" content="width=device-width, initial-scale=1">
1201
+ <title>PI-KIRO — Authentication</title>
1202
+ <style>
1203
+ *{margin:0;padding:0;box-sizing:border-box}
1204
+ 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}
1205
+ .container{max-width:420px;padding:2rem}
1206
+ .logo{display:flex;align-items:center;justify-content:center;gap:16px;margin-bottom:48px}
1207
+ .logo-text{font-size:42px;font-weight:700;letter-spacing:6px;color:#7c3aed;font-family:'Courier New',monospace}
1208
+ .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)}
1209
+ .status-icon{flex-shrink:0;margin-top:2px}
1210
+ .status-title{font-size:15px;font-weight:600;color:${borderColor};margin-bottom:4px}
1211
+ .status-msg{font-size:13px;color:#a3a3a3;line-height:1.4}
1212
+ .subtitle{font-size:13px;color:#737373;margin-top:4px}
1213
+ .subtitle strong{color:#a3a3a3}
1214
+ .countdown{position:relative;width:60px;height:60px;margin:24px auto 12px}
1215
+ .ring{width:60px;height:60px}
1216
+ .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}
1217
+ </style>
1218
+ </head>
1219
+ <body>
1220
+ <div class="container">
1221
+ <div class="logo">
1222
+ ${ghostSvg}
1223
+ <span class="logo-text">PI-KIRO</span>
1224
+ </div>
1225
+ <div class="status-box">
1226
+ <span class="status-icon">${iconSvg}</span>
1227
+ <div>
1228
+ <div class="status-title">${title}</div>
1229
+ <div class="status-msg">${message}</div>
1230
+ </div>
1231
+ </div>
1232
+ ${countdownHtml}
1233
+ </div>
1234
+ </body>
1235
+ </html>`;
1236
+ }
1237
+ function oauthIdcDelegationPage() {
1238
+ const ghostSvg = `<svg width="56" height="56" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
1239
+ <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"/>
1240
+ <circle cx="37" cy="45" r="7" fill="#0a0a0a"/>
1241
+ <circle cx="63" cy="45" r="7" fill="#0a0a0a"/>
1242
+ </svg>`;
1243
+ return `<!DOCTYPE html>
1244
+ <html lang="en">
1245
+ <head>
1246
+ <meta charset="utf-8">
1247
+ <meta name="viewport" content="width=device-width, initial-scale=1">
1248
+ <title>PI-KIRO — Enterprise Sign-In</title>
1249
+ <style>
1250
+ *{margin:0;padding:0;box-sizing:border-box}
1251
+ 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}
1252
+ .container{max-width:420px;padding:2rem}
1253
+ .logo{display:flex;align-items:center;justify-content:center;gap:16px;margin-bottom:48px}
1254
+ .logo-text{font-size:42px;font-weight:700;letter-spacing:6px;color:#7c3aed;font-family:'Courier New',monospace}
1255
+ .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)}
1256
+ .status-icon{flex-shrink:0;margin-top:2px}
1257
+ .status-title{font-size:15px;font-weight:600;color:#22c55e;margin-bottom:4px}
1258
+ .status-msg{font-size:13px;color:#a3a3a3;line-height:1.4}
1259
+ .subtitle{font-size:13px;color:#737373;margin-top:4px}
1260
+ .subtitle strong{color:#a3a3a3}
1261
+ .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}
1262
+ @keyframes spin{to{transform:rotate(360deg)}}
1263
+ .countdown{position:relative;width:60px;height:60px;margin:24px auto 12px;display:none}
1264
+ .ring{width:60px;height:60px}
1265
+ .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}
1266
+ </style>
1267
+ </head>
1268
+ <body>
1269
+ <div class="container">
1270
+ <div class="logo">
1271
+ ${ghostSvg}
1272
+ <span class="logo-text">PI-KIRO</span>
1273
+ </div>
1274
+ <div class="status-box">
1275
+ <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>
1276
+ <div>
1277
+ <div class="status-title">Enterprise sign-in</div>
1278
+ <div class="status-msg" id="status-msg">Preparing device authorization…</div>
1279
+ </div>
1280
+ </div>
1281
+ <div class="spinner" id="spinner"></div>
1282
+ <div class="countdown" id="countdown">
1283
+ <svg class="ring" viewBox="0 0 60 60">
1284
+ <circle cx="30" cy="30" r="26" stroke="#1a1a1a" stroke-width="3" fill="none"/>
1285
+ <circle id="ring-progress" cx="30" cy="30" r="26" stroke="#22c55e" stroke-width="3" fill="none"
1286
+ stroke-dasharray="163.36" stroke-dashoffset="0" stroke-linecap="round"
1287
+ transform="rotate(-90 30 30)" style="transition:stroke-dashoffset 1s linear"/>
1288
+ </svg>
1289
+ <span class="countdown-num" id="countdown-num">3</span>
1290
+ </div>
1291
+ <p class="subtitle" id="subtitle">Waiting for device authorization…</p>
1292
+ <script>
1293
+ (function(){
1294
+ var msg=document.getElementById('status-msg'),
1295
+ spinner=document.getElementById('spinner'),
1296
+ cd=document.getElementById('countdown'),
1297
+ cdNum=document.getElementById('countdown-num'),
1298
+ ring=document.getElementById('ring-progress'),
1299
+ sub=document.getElementById('subtitle'),
1300
+ circ=163.36;
1301
+
1302
+ function poll(){
1303
+ fetch('/idc-verify').then(function(r){return r.json()}).then(function(d){
1304
+ if(d.url){
1305
+ spinner.style.display='none';
1306
+ cd.style.display='block';
1307
+ msg.textContent='Device authorization ready';
1308
+ try{sub.innerHTML='Redirecting to <strong>'+new URL(d.url).hostname+'</strong>…'}catch(e){}
1309
+ countdown(3,d.url);
1310
+ } else {
1311
+ setTimeout(poll,500);
1312
+ }
1313
+ }).catch(function(){setTimeout(poll,1000)});
1314
+ }
1315
+
1316
+ function countdown(n,url){
1317
+ if(n<=0){window.location.href=url;return}
1318
+ cdNum.textContent=n;
1319
+ ring.setAttribute('stroke-dashoffset',String(circ*(1-n/3)));
1320
+ setTimeout(function(){countdown(n-1,url)},1000);
1321
+ }
1322
+
1323
+ poll();
1324
+ })();
1325
+ </script>
1326
+ </div>
1327
+ </body>
1328
+ </html>`;
1329
+ }
1330
+ function startCallbackServer(expectedState) {
1331
+ return new Promise((resolve2, reject) => {
1332
+ let settleWait;
1333
+ const waitForCodePromise = new Promise((res) => {
1334
+ settleWait = res;
1335
+ });
1336
+ let idcVerifyUrl = null;
1337
+ const server = createServer((req, res) => {
1338
+ try {
1339
+ const url = new URL(req.url ?? "", SOCIAL_REDIRECT_URI);
1340
+ if (url.pathname === "/idc-verify") {
1341
+ res.writeHead(200, {
1342
+ "Content-Type": "application/json",
1343
+ "Access-Control-Allow-Origin": "*",
1344
+ "Cache-Control": "no-store"
1345
+ });
1346
+ res.end(JSON.stringify({ url: idcVerifyUrl }));
1347
+ return;
1348
+ }
1349
+ const code = url.searchParams.get("code");
1350
+ const state = url.searchParams.get("state");
1351
+ const loginOption = url.searchParams.get("login_option");
1352
+ const issuerUrl = url.searchParams.get("issuer_url");
1353
+ const idcRegion = url.searchParams.get("idc_region");
1354
+ const isIdcDelegation = loginOption === "awsidc" && !!issuerUrl && !!state;
1355
+ if (!state || !code && !isIdcDelegation) {
1356
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
1357
+ res.end("");
1358
+ return;
1359
+ }
1360
+ if (state !== expectedState) {
1361
+ res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
1362
+ res.end(oauthCallbackPage("error", "State mismatch", "The OAuth state parameter did not match. Please try logging in again."));
1363
+ return;
1364
+ }
1365
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
1366
+ if (isIdcDelegation) {
1367
+ res.end(oauthIdcDelegationPage());
1368
+ } else {
1369
+ res.end(oauthCallbackPage("success", "Request approved", "PI-KIRO has been given requested permissions."));
1370
+ }
1371
+ settleWait?.({
1372
+ code,
1373
+ state,
1374
+ callbackPath: url.pathname,
1375
+ loginOption,
1376
+ issuerUrl: issuerUrl ?? undefined,
1377
+ idcRegion: idcRegion ?? undefined
1378
+ });
1379
+ } catch {
1380
+ res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
1381
+ res.end("Internal error");
1382
+ }
1383
+ });
1384
+ server.on("error", (err) => {
1385
+ reject(err);
1386
+ });
1387
+ server.listen(SOCIAL_REDIRECT_PORT, "localhost", () => {
1388
+ resolve2({
1389
+ server,
1390
+ redirectUri: SOCIAL_REDIRECT_URI,
1391
+ cancelWait: () => {
1392
+ settleWait?.(null);
1393
+ },
1394
+ waitForCode: () => waitForCodePromise,
1395
+ setIdcVerifyUrl: (url) => {
1396
+ idcVerifyUrl = url;
1397
+ }
1398
+ });
1399
+ });
1400
+ });
1401
+ }
1402
+ async function runSocialSignInFlow(callbacks) {
1403
+ const verifier = generateCodeVerifier();
1404
+ const challenge = generateCodeChallenge(verifier);
1405
+ const state = generateRandomState();
1406
+ const callbackServer = await startCallbackServer(state);
1407
+ try {
1408
+ const signInUrl = buildSocialSignInURL(callbackServer.redirectUri, challenge, state);
1409
+ callbacks.onAuth({
1410
+ url: signInUrl,
1411
+ instructions: "Complete sign-in in your browser."
1412
+ });
1413
+ callbacks.onProgress?.("Waiting for browser sign-in…");
1414
+ let code;
1415
+ let tokenRedirectUri = SOCIAL_REDIRECT_URI;
1416
+ let callbackResult = null;
1417
+ if (callbacks.onManualCodeInput) {
1418
+ let manualInput;
1419
+ let manualError;
1420
+ const manualPromise = callbacks.onManualCodeInput().then((input) => {
1421
+ manualInput = input;
1422
+ callbackServer.cancelWait();
1423
+ }).catch((err) => {
1424
+ manualError = err instanceof Error ? err : new Error(String(err));
1425
+ callbackServer.cancelWait();
1426
+ });
1427
+ callbackResult = await callbackServer.waitForCode();
1428
+ if (manualError)
1429
+ throw manualError;
1430
+ if (callbackResult?.loginOption !== "awsidc" || !callbackResult.issuerUrl) {
1431
+ if (callbackResult?.code) {
1432
+ code = callbackResult.code;
1433
+ tokenRedirectUri = buildTokenRedirectUri(callbackResult.callbackPath, callbackResult.loginOption);
1434
+ } else if (manualInput) {
1435
+ code = parseAuthRedirectInput(manualInput).code;
1436
+ }
1437
+ if (!code) {
1438
+ await manualPromise;
1439
+ if (manualError)
1440
+ throw manualError;
1441
+ if (manualInput) {
1442
+ code = parseAuthRedirectInput(manualInput).code;
1443
+ }
1444
+ }
1445
+ }
1446
+ } else {
1447
+ callbackResult = await callbackServer.waitForCode();
1448
+ if (callbackResult?.code) {
1449
+ code = callbackResult.code;
1450
+ tokenRedirectUri = buildTokenRedirectUri(callbackResult.callbackPath, callbackResult.loginOption);
1451
+ }
1452
+ }
1453
+ if (callbackResult?.loginOption === "awsidc" && callbackResult.issuerUrl) {
1454
+ callbacks.onProgress?.("Enterprise sign-in detected — starting device authorization…");
1455
+ const idcRegion = callbackResult.idcRegion || BUILDER_ID_REGION;
1456
+ const wrappedCallbacks = {
1457
+ ...callbacks,
1458
+ onAuth: (info) => {
1459
+ callbackServer.setIdcVerifyUrl(info.url);
1460
+ callbacks.onAuth(info);
1461
+ }
1462
+ };
1463
+ try {
1464
+ return await runDeviceCodeFlow(wrappedCallbacks, callbackResult.issuerUrl, [idcRegion], "idc");
1465
+ } finally {
1466
+ callbackServer.server.close();
1467
+ }
1468
+ }
1469
+ if (!code) {
1470
+ const input = await callbacks.onPrompt({
1471
+ message: "Paste the authorization code or the full redirect URL:",
1472
+ placeholder: SOCIAL_REDIRECT_URI
1473
+ });
1474
+ code = parseAuthRedirectInput(input).code;
1475
+ }
1476
+ if (!code) {
1477
+ throw new Error("Missing authorization code — sign-in was not completed");
1478
+ }
1479
+ callbacks.onProgress?.("Exchanging authorization code…");
1480
+ const resp = await fetch(`${KIRO_SOCIAL_AUTH_ENDPOINT}/oauth/token`, {
1481
+ method: "POST",
1482
+ headers: { "Content-Type": "application/json", "User-Agent": "pi-kiro" },
1483
+ body: JSON.stringify({
1484
+ code,
1485
+ code_verifier: verifier,
1486
+ redirect_uri: tokenRedirectUri
1487
+ })
1488
+ });
1489
+ if (!resp.ok) {
1490
+ const body = await resp.text().catch(() => "");
1491
+ throw new Error(`Token exchange failed: ${resp.status} ${body}`);
1492
+ }
1493
+ const data = await resp.json();
1494
+ if (!data.accessToken || !data.refreshToken) {
1495
+ throw new Error("Token exchange returned no tokens");
1496
+ }
1497
+ if (data.profileArn) {
1498
+ try {
1499
+ const apiRegion = resolveApiRegion(BUILDER_ID_REGION);
1500
+ const apiModels = await fetchAvailableModels(data.accessToken, apiRegion, data.profileArn);
1501
+ setCachedDynamicModels(buildModelsFromApi(apiModels));
1502
+ log.info(`Fetched and cached ${apiModels.length} models after social sign-in`);
1503
+ } catch (err) {
1504
+ log.warn(`Failed to fetch models after social sign-in: ${err}`);
1505
+ }
1506
+ }
1507
+ return {
1508
+ refresh: `${data.refreshToken}|||social`,
1509
+ access: data.accessToken,
1510
+ expires: Date.now() + (data.expiresIn ?? 3600) * 1000 - EXPIRES_BUFFER_MS,
1511
+ clientId: "",
1512
+ clientSecret: "",
1513
+ region: BUILDER_ID_REGION,
1514
+ authMethod: "social",
1515
+ profileArn: data.profileArn
1516
+ };
1517
+ } finally {
1518
+ callbackServer.server.close();
1519
+ }
1520
+ }
1092
1521
  async function loginKiro(callbacks) {
1093
1522
  const method = await callbacks.onSelect({
1094
1523
  message: "Select login method:",
@@ -1108,7 +1537,7 @@ async function loginKiro(callbacks) {
1108
1537
  return loginDesktopManual(callbacks);
1109
1538
  }
1110
1539
  if (method === "builder-id") {
1111
- return runDeviceCodeFlow(callbacks, BUILDER_ID_START_URL, [BUILDER_ID_REGION], "builder-id");
1540
+ return runSocialSignInFlow(callbacks);
1112
1541
  }
1113
1542
  const startUrl = (await callbacks.onPrompt({
1114
1543
  message: "Paste your IAM Identity Center start URL:",
@@ -1226,7 +1655,7 @@ async function syncBackToKiroCli(result) {
1226
1655
  accessToken: result.access,
1227
1656
  refreshToken: result.refresh.split("|")[0] ?? "",
1228
1657
  region: result.region,
1229
- authMethod: result.authMethod === "builder-id" ? "idc" : result.authMethod,
1658
+ authMethod: result.authMethod === "builder-id" || result.authMethod === "social" ? "desktop" : result.authMethod,
1230
1659
  source: result.kiroSyncSource,
1231
1660
  tokenKey: result.kiroSyncTokenKey
1232
1661
  });
@@ -1263,10 +1692,10 @@ async function refreshTokenInner(credentials) {
1263
1692
  if (!refreshToken || !region) {
1264
1693
  throw new Error("Refresh token is missing region — re-login required");
1265
1694
  }
1266
- if (authMethod !== "desktop" && (!clientId || !clientSecret)) {
1695
+ if (authMethod !== "desktop" && authMethod !== "social" && (!clientId || !clientSecret)) {
1267
1696
  throw new Error("Refresh token is missing clientId/clientSecret — re-login required");
1268
1697
  }
1269
- if (authMethod === "desktop") {
1698
+ if (authMethod === "desktop" || authMethod === "social") {
1270
1699
  const desktopEndpoint = `https://prod.${region}.auth.desktop.kiro.dev/refreshToken`;
1271
1700
  const resp2 = await fetch(desktopEndpoint, {
1272
1701
  method: "POST",
@@ -1289,13 +1718,13 @@ async function refreshTokenInner(credentials) {
1289
1718
  }
1290
1719
  }
1291
1720
  return {
1292
- refresh: `${data2.refreshToken}|||desktop`,
1721
+ refresh: `${data2.refreshToken}|||${authMethod}`,
1293
1722
  access: data2.accessToken,
1294
1723
  expires: Date.now() + (data2.expiresIn ?? 3600) * 1000 - EXPIRES_BUFFER_MS,
1295
1724
  clientId: "",
1296
1725
  clientSecret: "",
1297
1726
  region,
1298
- authMethod: "desktop",
1727
+ authMethod,
1299
1728
  profileArn: credentials.profileArn,
1300
1729
  kiroSyncSource: credentials.kiroSyncSource,
1301
1730
  kiroSyncTokenKey: credentials.kiroSyncTokenKey
@@ -1337,8 +1766,8 @@ async function refreshTokenInner(credentials) {
1337
1766
  }
1338
1767
  async function refreshKiroToken(credentials) {
1339
1768
  const inputMethod = credentials.authMethod;
1340
- const authMethod = inputMethod === "builder-id" || inputMethod === "idc" || inputMethod === "desktop" ? inputMethod : "idc";
1341
- if (inputMethod !== undefined && inputMethod !== "builder-id" && inputMethod !== "idc" && inputMethod !== "desktop") {
1769
+ const authMethod = inputMethod === "builder-id" || inputMethod === "idc" || inputMethod === "desktop" || inputMethod === "social" ? inputMethod : "idc";
1770
+ if (inputMethod !== undefined && inputMethod !== "builder-id" && inputMethod !== "idc" && inputMethod !== "desktop" && inputMethod !== "social") {
1342
1771
  log.warn(`refreshKiroToken: unrecognized authMethod "${String(inputMethod)}" — defaulting to "idc"`);
1343
1772
  }
1344
1773
  const baseCreds = {
@@ -1868,7 +2297,7 @@ function countTokens(text) {
1868
2297
  }
1869
2298
 
1870
2299
  // src/transform.ts
1871
- import { createHash } from "node:crypto";
2300
+ import { createHash as createHash2 } from "node:crypto";
1872
2301
  function normalizeMessages(messages) {
1873
2302
  return messages.filter((msg) => msg.role !== "assistant" || msg.stopReason !== "error" && msg.stopReason !== "aborted");
1874
2303
  }
@@ -1921,7 +2350,7 @@ var KIRO_TOOL_USE_ID_RE = /^tooluse_[A-Za-z0-9]+$/;
1921
2350
  function toKiroToolUseId(id) {
1922
2351
  if (KIRO_TOOL_USE_ID_RE.test(id))
1923
2352
  return id;
1924
- const digest = createHash("sha256").update(id).digest("hex").slice(0, 22);
2353
+ const digest = createHash2("sha256").update(id).digest("hex").slice(0, 22);
1925
2354
  return `tooluse_${digest}`;
1926
2355
  }
1927
2356
  function convertImagesToKiro(images) {
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACV,GAAG,EACH,2BAA2B,EAC3B,OAAO,EACP,KAAK,EACL,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAsB/B,UAAU,mBAAmB;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IAC5B,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/E,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;CAC3D;AAED,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,YAAY,CAAC,EAAE,CACb,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,KAC1B,2BAA2B,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC/B,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,CAAC,SAAS,EAAE,mBAAmB,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACrE,YAAY,EAAE,CAAC,WAAW,EAAE,gBAAgB,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC3E,SAAS,EAAE,CAAC,WAAW,EAAE,gBAAgB,KAAK,MAAM,CAAC;QACrD,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,EAAE,gBAAgB,KAAK,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;KACtF,CAAC;CACH;AAED,UAAU,YAAY;IACpB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;CAC9D;AA8GD,yBAA+B,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA+E9D"}
1
+ {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACV,GAAG,EACH,2BAA2B,EAC3B,OAAO,EACP,KAAK,EACL,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,uBAAuB,CAAC;AAuB/B,UAAU,mBAAmB;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IAC5B,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/E,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;CAC3D;AAED,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,YAAY,CAAC,EAAE,CACb,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,KAC1B,2BAA2B,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC/B,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,CAAC,SAAS,EAAE,mBAAmB,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACrE,YAAY,EAAE,CAAC,WAAW,EAAE,gBAAgB,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC3E,SAAS,EAAE,CAAC,WAAW,EAAE,gBAAgB,KAAK,MAAM,CAAC;QACrD,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,EAAE,gBAAgB,KAAK,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;KACtF,CAAC;CACH;AAED,UAAU,YAAY;IACpB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;CAC9D;AA4HD,yBAA+B,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAmG9D"}
package/dist/extension.js CHANGED
@@ -899,6 +899,24 @@ var kiroModels = [
899
899
  maxTokens: 65536
900
900
  }
901
901
  ];
902
+ async function resolveProfileArn(accessToken, apiRegion) {
903
+ const resp = await fetch(`https://management.${apiRegion}.kiro.dev/`, {
904
+ method: "POST",
905
+ headers: {
906
+ Authorization: `Bearer ${accessToken}`,
907
+ "Content-Type": "application/x-amz-json-1.0",
908
+ "X-Amz-Target": "AmazonCodeWhispererService.ListAvailableProfiles",
909
+ "User-Agent": "pi-kiro"
910
+ },
911
+ body: "{}"
912
+ });
913
+ if (!resp.ok)
914
+ return null;
915
+ const data = await resp.json();
916
+ const profiles = data.profiles ?? [];
917
+ const kiroProfile = profiles.find((p) => p.profileType === "KIRO" && p.status === "ACTIVE");
918
+ return kiroProfile?.arn ?? profiles[0]?.arn ?? null;
919
+ }
902
920
  async function fetchAvailableModels(accessToken, apiRegion, profileArn) {
903
921
  const url = `https://management.${apiRegion}.kiro.dev/?origin=KIRO_CLI&profileArn=${encodeURIComponent(profileArn)}`;
904
922
  const resp = await fetch(url, {
@@ -983,6 +1001,8 @@ function setCachedDynamicModels(models) {
983
1001
 
984
1002
  // src/oauth.ts
985
1003
  init_debug();
1004
+ import { createServer } from "node:http";
1005
+ import { randomBytes, createHash } from "node:crypto";
986
1006
  var BUILDER_ID_START_URL = "https://view.awsapps.com/start";
987
1007
  var BUILDER_ID_REGION = "us-east-1";
988
1008
  var SSO_SCOPES = [
@@ -1092,6 +1112,415 @@ async function pollForToken(oidcEndpoint, clientId, clientSecret, devAuth, signa
1092
1112
  }
1093
1113
  throw new Error("Authorization timed out");
1094
1114
  }
1115
+ var KIRO_SOCIAL_PORTAL = "https://app.kiro.dev";
1116
+ var KIRO_SOCIAL_AUTH_ENDPOINT = `https://prod.${BUILDER_ID_REGION}.auth.desktop.kiro.dev`;
1117
+ var SOCIAL_REDIRECT_PORT = 49153;
1118
+ var SOCIAL_REDIRECT_URI = `http://localhost:${SOCIAL_REDIRECT_PORT}`;
1119
+ function generateRandomState() {
1120
+ return randomBytes(16).toString("base64url");
1121
+ }
1122
+ function generateCodeVerifier() {
1123
+ return randomBytes(32).toString("base64url");
1124
+ }
1125
+ function generateCodeChallenge(verifier) {
1126
+ return createHash("sha256").update(verifier).digest("base64url");
1127
+ }
1128
+ function buildSocialSignInURL(redirectUri, codeChallenge, state) {
1129
+ const params = new URLSearchParams;
1130
+ params.set("code_challenge", codeChallenge);
1131
+ params.set("code_challenge_method", "S256");
1132
+ params.set("redirect_from", "kirocli");
1133
+ params.set("redirect_uri", redirectUri);
1134
+ params.set("state", state);
1135
+ return `${KIRO_SOCIAL_PORTAL}/signin?${params.toString()}`;
1136
+ }
1137
+ function parseAuthRedirectInput(input) {
1138
+ const trimmed = input.trim();
1139
+ if (!trimmed)
1140
+ return {};
1141
+ try {
1142
+ const url = new URL(trimmed);
1143
+ return {
1144
+ code: url.searchParams.get("code") ?? undefined,
1145
+ state: url.searchParams.get("state") ?? undefined
1146
+ };
1147
+ } catch {
1148
+ return { code: trimmed };
1149
+ }
1150
+ }
1151
+ function buildTokenRedirectUri(callbackPath, loginOption) {
1152
+ const path = callbackPath || "/oauth/callback";
1153
+ const base = `${SOCIAL_REDIRECT_URI}${path}`;
1154
+ if (loginOption) {
1155
+ return `${base}?login_option=${encodeURIComponent(loginOption)}`;
1156
+ }
1157
+ return base;
1158
+ }
1159
+ function oauthCallbackPage(kind, title, message, redirectUrl = "https://app.kiro.dev") {
1160
+ const borderColor = kind === "success" ? "#22c55e" : "#ef4444";
1161
+ 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>`;
1162
+ const ghostSvg = `<svg width="56" height="56" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
1163
+ <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"/>
1164
+ <circle cx="37" cy="45" r="7" fill="#0a0a0a"/>
1165
+ <circle cx="63" cy="45" r="7" fill="#0a0a0a"/>
1166
+ </svg>`;
1167
+ const redirectHost = (() => {
1168
+ try {
1169
+ return new URL(redirectUrl).hostname;
1170
+ } catch {
1171
+ return redirectUrl;
1172
+ }
1173
+ })();
1174
+ const countdownHtml = kind === "success" ? `
1175
+ <div class="countdown" id="countdown">
1176
+ <svg class="ring" viewBox="0 0 60 60">
1177
+ <circle cx="30" cy="30" r="26" stroke="#1a1a1a" stroke-width="3" fill="none"/>
1178
+ <circle id="ring-progress" cx="30" cy="30" r="26" stroke="#22c55e" stroke-width="3" fill="none"
1179
+ stroke-dasharray="163.36" stroke-dashoffset="0" stroke-linecap="round"
1180
+ transform="rotate(-90 30 30)" style="transition:stroke-dashoffset 1s linear"/>
1181
+ </svg>
1182
+ <span class="countdown-num" id="countdown-num">3</span>
1183
+ </div>
1184
+ <p class="subtitle">Redirecting to <strong>${redirectHost}</strong>…</p>
1185
+ <script>
1186
+ (function(){
1187
+ var n=3, el=document.getElementById('countdown-num'),
1188
+ ring=document.getElementById('ring-progress'), circ=163.36;
1189
+ function tick(){
1190
+ if(n<=0){window.location.href=${JSON.stringify(redirectUrl)};return}
1191
+ el.textContent=n;
1192
+ ring.setAttribute('stroke-dashoffset', String(circ*(1-n/3)));
1193
+ n--;
1194
+ setTimeout(tick,1000);
1195
+ }
1196
+ tick();
1197
+ })();
1198
+ </script>` : `<p class="subtitle">Please close this window and try again</p>`;
1199
+ return `<!DOCTYPE html>
1200
+ <html lang="en">
1201
+ <head>
1202
+ <meta charset="utf-8">
1203
+ <meta name="viewport" content="width=device-width, initial-scale=1">
1204
+ <title>PI-KIRO — Authentication</title>
1205
+ <style>
1206
+ *{margin:0;padding:0;box-sizing:border-box}
1207
+ 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}
1208
+ .container{max-width:420px;padding:2rem}
1209
+ .logo{display:flex;align-items:center;justify-content:center;gap:16px;margin-bottom:48px}
1210
+ .logo-text{font-size:42px;font-weight:700;letter-spacing:6px;color:#7c3aed;font-family:'Courier New',monospace}
1211
+ .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)}
1212
+ .status-icon{flex-shrink:0;margin-top:2px}
1213
+ .status-title{font-size:15px;font-weight:600;color:${borderColor};margin-bottom:4px}
1214
+ .status-msg{font-size:13px;color:#a3a3a3;line-height:1.4}
1215
+ .subtitle{font-size:13px;color:#737373;margin-top:4px}
1216
+ .subtitle strong{color:#a3a3a3}
1217
+ .countdown{position:relative;width:60px;height:60px;margin:24px auto 12px}
1218
+ .ring{width:60px;height:60px}
1219
+ .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}
1220
+ </style>
1221
+ </head>
1222
+ <body>
1223
+ <div class="container">
1224
+ <div class="logo">
1225
+ ${ghostSvg}
1226
+ <span class="logo-text">PI-KIRO</span>
1227
+ </div>
1228
+ <div class="status-box">
1229
+ <span class="status-icon">${iconSvg}</span>
1230
+ <div>
1231
+ <div class="status-title">${title}</div>
1232
+ <div class="status-msg">${message}</div>
1233
+ </div>
1234
+ </div>
1235
+ ${countdownHtml}
1236
+ </div>
1237
+ </body>
1238
+ </html>`;
1239
+ }
1240
+ function oauthIdcDelegationPage() {
1241
+ const ghostSvg = `<svg width="56" height="56" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
1242
+ <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"/>
1243
+ <circle cx="37" cy="45" r="7" fill="#0a0a0a"/>
1244
+ <circle cx="63" cy="45" r="7" fill="#0a0a0a"/>
1245
+ </svg>`;
1246
+ return `<!DOCTYPE html>
1247
+ <html lang="en">
1248
+ <head>
1249
+ <meta charset="utf-8">
1250
+ <meta name="viewport" content="width=device-width, initial-scale=1">
1251
+ <title>PI-KIRO — Enterprise Sign-In</title>
1252
+ <style>
1253
+ *{margin:0;padding:0;box-sizing:border-box}
1254
+ 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}
1255
+ .container{max-width:420px;padding:2rem}
1256
+ .logo{display:flex;align-items:center;justify-content:center;gap:16px;margin-bottom:48px}
1257
+ .logo-text{font-size:42px;font-weight:700;letter-spacing:6px;color:#7c3aed;font-family:'Courier New',monospace}
1258
+ .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)}
1259
+ .status-icon{flex-shrink:0;margin-top:2px}
1260
+ .status-title{font-size:15px;font-weight:600;color:#22c55e;margin-bottom:4px}
1261
+ .status-msg{font-size:13px;color:#a3a3a3;line-height:1.4}
1262
+ .subtitle{font-size:13px;color:#737373;margin-top:4px}
1263
+ .subtitle strong{color:#a3a3a3}
1264
+ .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}
1265
+ @keyframes spin{to{transform:rotate(360deg)}}
1266
+ .countdown{position:relative;width:60px;height:60px;margin:24px auto 12px;display:none}
1267
+ .ring{width:60px;height:60px}
1268
+ .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}
1269
+ </style>
1270
+ </head>
1271
+ <body>
1272
+ <div class="container">
1273
+ <div class="logo">
1274
+ ${ghostSvg}
1275
+ <span class="logo-text">PI-KIRO</span>
1276
+ </div>
1277
+ <div class="status-box">
1278
+ <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>
1279
+ <div>
1280
+ <div class="status-title">Enterprise sign-in</div>
1281
+ <div class="status-msg" id="status-msg">Preparing device authorization…</div>
1282
+ </div>
1283
+ </div>
1284
+ <div class="spinner" id="spinner"></div>
1285
+ <div class="countdown" id="countdown">
1286
+ <svg class="ring" viewBox="0 0 60 60">
1287
+ <circle cx="30" cy="30" r="26" stroke="#1a1a1a" stroke-width="3" fill="none"/>
1288
+ <circle id="ring-progress" cx="30" cy="30" r="26" stroke="#22c55e" stroke-width="3" fill="none"
1289
+ stroke-dasharray="163.36" stroke-dashoffset="0" stroke-linecap="round"
1290
+ transform="rotate(-90 30 30)" style="transition:stroke-dashoffset 1s linear"/>
1291
+ </svg>
1292
+ <span class="countdown-num" id="countdown-num">3</span>
1293
+ </div>
1294
+ <p class="subtitle" id="subtitle">Waiting for device authorization…</p>
1295
+ <script>
1296
+ (function(){
1297
+ var msg=document.getElementById('status-msg'),
1298
+ spinner=document.getElementById('spinner'),
1299
+ cd=document.getElementById('countdown'),
1300
+ cdNum=document.getElementById('countdown-num'),
1301
+ ring=document.getElementById('ring-progress'),
1302
+ sub=document.getElementById('subtitle'),
1303
+ circ=163.36;
1304
+
1305
+ function poll(){
1306
+ fetch('/idc-verify').then(function(r){return r.json()}).then(function(d){
1307
+ if(d.url){
1308
+ spinner.style.display='none';
1309
+ cd.style.display='block';
1310
+ msg.textContent='Device authorization ready';
1311
+ try{sub.innerHTML='Redirecting to <strong>'+new URL(d.url).hostname+'</strong>…'}catch(e){}
1312
+ countdown(3,d.url);
1313
+ } else {
1314
+ setTimeout(poll,500);
1315
+ }
1316
+ }).catch(function(){setTimeout(poll,1000)});
1317
+ }
1318
+
1319
+ function countdown(n,url){
1320
+ if(n<=0){window.location.href=url;return}
1321
+ cdNum.textContent=n;
1322
+ ring.setAttribute('stroke-dashoffset',String(circ*(1-n/3)));
1323
+ setTimeout(function(){countdown(n-1,url)},1000);
1324
+ }
1325
+
1326
+ poll();
1327
+ })();
1328
+ </script>
1329
+ </div>
1330
+ </body>
1331
+ </html>`;
1332
+ }
1333
+ function startCallbackServer(expectedState) {
1334
+ return new Promise((resolve2, reject) => {
1335
+ let settleWait;
1336
+ const waitForCodePromise = new Promise((res) => {
1337
+ settleWait = res;
1338
+ });
1339
+ let idcVerifyUrl = null;
1340
+ const server = createServer((req, res) => {
1341
+ try {
1342
+ const url = new URL(req.url ?? "", SOCIAL_REDIRECT_URI);
1343
+ if (url.pathname === "/idc-verify") {
1344
+ res.writeHead(200, {
1345
+ "Content-Type": "application/json",
1346
+ "Access-Control-Allow-Origin": "*",
1347
+ "Cache-Control": "no-store"
1348
+ });
1349
+ res.end(JSON.stringify({ url: idcVerifyUrl }));
1350
+ return;
1351
+ }
1352
+ const code = url.searchParams.get("code");
1353
+ const state = url.searchParams.get("state");
1354
+ const loginOption = url.searchParams.get("login_option");
1355
+ const issuerUrl = url.searchParams.get("issuer_url");
1356
+ const idcRegion = url.searchParams.get("idc_region");
1357
+ const isIdcDelegation = loginOption === "awsidc" && !!issuerUrl && !!state;
1358
+ if (!state || !code && !isIdcDelegation) {
1359
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
1360
+ res.end("");
1361
+ return;
1362
+ }
1363
+ if (state !== expectedState) {
1364
+ res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
1365
+ res.end(oauthCallbackPage("error", "State mismatch", "The OAuth state parameter did not match. Please try logging in again."));
1366
+ return;
1367
+ }
1368
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
1369
+ if (isIdcDelegation) {
1370
+ res.end(oauthIdcDelegationPage());
1371
+ } else {
1372
+ res.end(oauthCallbackPage("success", "Request approved", "PI-KIRO has been given requested permissions."));
1373
+ }
1374
+ settleWait?.({
1375
+ code,
1376
+ state,
1377
+ callbackPath: url.pathname,
1378
+ loginOption,
1379
+ issuerUrl: issuerUrl ?? undefined,
1380
+ idcRegion: idcRegion ?? undefined
1381
+ });
1382
+ } catch {
1383
+ res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
1384
+ res.end("Internal error");
1385
+ }
1386
+ });
1387
+ server.on("error", (err) => {
1388
+ reject(err);
1389
+ });
1390
+ server.listen(SOCIAL_REDIRECT_PORT, "localhost", () => {
1391
+ resolve2({
1392
+ server,
1393
+ redirectUri: SOCIAL_REDIRECT_URI,
1394
+ cancelWait: () => {
1395
+ settleWait?.(null);
1396
+ },
1397
+ waitForCode: () => waitForCodePromise,
1398
+ setIdcVerifyUrl: (url) => {
1399
+ idcVerifyUrl = url;
1400
+ }
1401
+ });
1402
+ });
1403
+ });
1404
+ }
1405
+ async function runSocialSignInFlow(callbacks) {
1406
+ const verifier = generateCodeVerifier();
1407
+ const challenge = generateCodeChallenge(verifier);
1408
+ const state = generateRandomState();
1409
+ const callbackServer = await startCallbackServer(state);
1410
+ try {
1411
+ const signInUrl = buildSocialSignInURL(callbackServer.redirectUri, challenge, state);
1412
+ callbacks.onAuth({
1413
+ url: signInUrl,
1414
+ instructions: "Complete sign-in in your browser."
1415
+ });
1416
+ callbacks.onProgress?.("Waiting for browser sign-in…");
1417
+ let code;
1418
+ let tokenRedirectUri = SOCIAL_REDIRECT_URI;
1419
+ let callbackResult = null;
1420
+ if (callbacks.onManualCodeInput) {
1421
+ let manualInput;
1422
+ let manualError;
1423
+ const manualPromise = callbacks.onManualCodeInput().then((input) => {
1424
+ manualInput = input;
1425
+ callbackServer.cancelWait();
1426
+ }).catch((err) => {
1427
+ manualError = err instanceof Error ? err : new Error(String(err));
1428
+ callbackServer.cancelWait();
1429
+ });
1430
+ callbackResult = await callbackServer.waitForCode();
1431
+ if (manualError)
1432
+ throw manualError;
1433
+ if (callbackResult?.loginOption !== "awsidc" || !callbackResult.issuerUrl) {
1434
+ if (callbackResult?.code) {
1435
+ code = callbackResult.code;
1436
+ tokenRedirectUri = buildTokenRedirectUri(callbackResult.callbackPath, callbackResult.loginOption);
1437
+ } else if (manualInput) {
1438
+ code = parseAuthRedirectInput(manualInput).code;
1439
+ }
1440
+ if (!code) {
1441
+ await manualPromise;
1442
+ if (manualError)
1443
+ throw manualError;
1444
+ if (manualInput) {
1445
+ code = parseAuthRedirectInput(manualInput).code;
1446
+ }
1447
+ }
1448
+ }
1449
+ } else {
1450
+ callbackResult = await callbackServer.waitForCode();
1451
+ if (callbackResult?.code) {
1452
+ code = callbackResult.code;
1453
+ tokenRedirectUri = buildTokenRedirectUri(callbackResult.callbackPath, callbackResult.loginOption);
1454
+ }
1455
+ }
1456
+ if (callbackResult?.loginOption === "awsidc" && callbackResult.issuerUrl) {
1457
+ callbacks.onProgress?.("Enterprise sign-in detected — starting device authorization…");
1458
+ const idcRegion = callbackResult.idcRegion || BUILDER_ID_REGION;
1459
+ const wrappedCallbacks = {
1460
+ ...callbacks,
1461
+ onAuth: (info) => {
1462
+ callbackServer.setIdcVerifyUrl(info.url);
1463
+ callbacks.onAuth(info);
1464
+ }
1465
+ };
1466
+ try {
1467
+ return await runDeviceCodeFlow(wrappedCallbacks, callbackResult.issuerUrl, [idcRegion], "idc");
1468
+ } finally {
1469
+ callbackServer.server.close();
1470
+ }
1471
+ }
1472
+ if (!code) {
1473
+ const input = await callbacks.onPrompt({
1474
+ message: "Paste the authorization code or the full redirect URL:",
1475
+ placeholder: SOCIAL_REDIRECT_URI
1476
+ });
1477
+ code = parseAuthRedirectInput(input).code;
1478
+ }
1479
+ if (!code) {
1480
+ throw new Error("Missing authorization code — sign-in was not completed");
1481
+ }
1482
+ callbacks.onProgress?.("Exchanging authorization code…");
1483
+ const resp = await fetch(`${KIRO_SOCIAL_AUTH_ENDPOINT}/oauth/token`, {
1484
+ method: "POST",
1485
+ headers: { "Content-Type": "application/json", "User-Agent": "pi-kiro" },
1486
+ body: JSON.stringify({
1487
+ code,
1488
+ code_verifier: verifier,
1489
+ redirect_uri: tokenRedirectUri
1490
+ })
1491
+ });
1492
+ if (!resp.ok) {
1493
+ const body = await resp.text().catch(() => "");
1494
+ throw new Error(`Token exchange failed: ${resp.status} ${body}`);
1495
+ }
1496
+ const data = await resp.json();
1497
+ if (!data.accessToken || !data.refreshToken) {
1498
+ throw new Error("Token exchange returned no tokens");
1499
+ }
1500
+ if (data.profileArn) {
1501
+ try {
1502
+ const apiRegion = resolveApiRegion(BUILDER_ID_REGION);
1503
+ const apiModels = await fetchAvailableModels(data.accessToken, apiRegion, data.profileArn);
1504
+ setCachedDynamicModels(buildModelsFromApi(apiModels));
1505
+ log.info(`Fetched and cached ${apiModels.length} models after social sign-in`);
1506
+ } catch (err) {
1507
+ log.warn(`Failed to fetch models after social sign-in: ${err}`);
1508
+ }
1509
+ }
1510
+ return {
1511
+ refresh: `${data.refreshToken}|||social`,
1512
+ access: data.accessToken,
1513
+ expires: Date.now() + (data.expiresIn ?? 3600) * 1000 - EXPIRES_BUFFER_MS,
1514
+ clientId: "",
1515
+ clientSecret: "",
1516
+ region: BUILDER_ID_REGION,
1517
+ authMethod: "social",
1518
+ profileArn: data.profileArn
1519
+ };
1520
+ } finally {
1521
+ callbackServer.server.close();
1522
+ }
1523
+ }
1095
1524
  async function loginKiro(callbacks) {
1096
1525
  const method = await callbacks.onSelect({
1097
1526
  message: "Select login method:",
@@ -1111,7 +1540,7 @@ async function loginKiro(callbacks) {
1111
1540
  return loginDesktopManual(callbacks);
1112
1541
  }
1113
1542
  if (method === "builder-id") {
1114
- return runDeviceCodeFlow(callbacks, BUILDER_ID_START_URL, [BUILDER_ID_REGION], "builder-id");
1543
+ return runSocialSignInFlow(callbacks);
1115
1544
  }
1116
1545
  const startUrl = (await callbacks.onPrompt({
1117
1546
  message: "Paste your IAM Identity Center start URL:",
@@ -1229,7 +1658,7 @@ async function syncBackToKiroCli(result) {
1229
1658
  accessToken: result.access,
1230
1659
  refreshToken: result.refresh.split("|")[0] ?? "",
1231
1660
  region: result.region,
1232
- authMethod: result.authMethod === "builder-id" ? "idc" : result.authMethod,
1661
+ authMethod: result.authMethod === "builder-id" || result.authMethod === "social" ? "desktop" : result.authMethod,
1233
1662
  source: result.kiroSyncSource,
1234
1663
  tokenKey: result.kiroSyncTokenKey
1235
1664
  });
@@ -1266,10 +1695,10 @@ async function refreshTokenInner(credentials) {
1266
1695
  if (!refreshToken || !region) {
1267
1696
  throw new Error("Refresh token is missing region — re-login required");
1268
1697
  }
1269
- if (authMethod !== "desktop" && (!clientId || !clientSecret)) {
1698
+ if (authMethod !== "desktop" && authMethod !== "social" && (!clientId || !clientSecret)) {
1270
1699
  throw new Error("Refresh token is missing clientId/clientSecret — re-login required");
1271
1700
  }
1272
- if (authMethod === "desktop") {
1701
+ if (authMethod === "desktop" || authMethod === "social") {
1273
1702
  const desktopEndpoint = `https://prod.${region}.auth.desktop.kiro.dev/refreshToken`;
1274
1703
  const resp2 = await fetch(desktopEndpoint, {
1275
1704
  method: "POST",
@@ -1292,13 +1721,13 @@ async function refreshTokenInner(credentials) {
1292
1721
  }
1293
1722
  }
1294
1723
  return {
1295
- refresh: `${data2.refreshToken}|||desktop`,
1724
+ refresh: `${data2.refreshToken}|||${authMethod}`,
1296
1725
  access: data2.accessToken,
1297
1726
  expires: Date.now() + (data2.expiresIn ?? 3600) * 1000 - EXPIRES_BUFFER_MS,
1298
1727
  clientId: "",
1299
1728
  clientSecret: "",
1300
1729
  region,
1301
- authMethod: "desktop",
1730
+ authMethod,
1302
1731
  profileArn: credentials.profileArn,
1303
1732
  kiroSyncSource: credentials.kiroSyncSource,
1304
1733
  kiroSyncTokenKey: credentials.kiroSyncTokenKey
@@ -1340,8 +1769,8 @@ async function refreshTokenInner(credentials) {
1340
1769
  }
1341
1770
  async function refreshKiroToken(credentials) {
1342
1771
  const inputMethod = credentials.authMethod;
1343
- const authMethod = inputMethod === "builder-id" || inputMethod === "idc" || inputMethod === "desktop" ? inputMethod : "idc";
1344
- if (inputMethod !== undefined && inputMethod !== "builder-id" && inputMethod !== "idc" && inputMethod !== "desktop") {
1772
+ const authMethod = inputMethod === "builder-id" || inputMethod === "idc" || inputMethod === "desktop" || inputMethod === "social" ? inputMethod : "idc";
1773
+ if (inputMethod !== undefined && inputMethod !== "builder-id" && inputMethod !== "idc" && inputMethod !== "desktop" && inputMethod !== "social") {
1345
1774
  log.warn(`refreshKiroToken: unrecognized authMethod "${String(inputMethod)}" — defaulting to "idc"`);
1346
1775
  }
1347
1776
  const baseCreds = {
@@ -1872,7 +2301,7 @@ function countTokens(text) {
1872
2301
  }
1873
2302
 
1874
2303
  // src/transform.ts
1875
- import { createHash } from "node:crypto";
2304
+ import { createHash as createHash2 } from "node:crypto";
1876
2305
  function normalizeMessages(messages) {
1877
2306
  return messages.filter((msg) => msg.role !== "assistant" || msg.stopReason !== "error" && msg.stopReason !== "aborted");
1878
2307
  }
@@ -1925,7 +2354,7 @@ var KIRO_TOOL_USE_ID_RE = /^tooluse_[A-Za-z0-9]+$/;
1925
2354
  function toKiroToolUseId(id) {
1926
2355
  if (KIRO_TOOL_USE_ID_RE.test(id))
1927
2356
  return id;
1928
- const digest = createHash("sha256").update(id).digest("hex").slice(0, 22);
2357
+ const digest = createHash2("sha256").update(id).digest("hex").slice(0, 22);
1929
2358
  return `tooluse_${digest}`;
1930
2359
  }
1931
2360
  function convertImagesToKiro(images) {
@@ -3012,10 +3441,22 @@ function writeKiroCredentials(refreshed) {
3012
3441
  log.warn(`Failed to persist refreshed credentials: ${err}`);
3013
3442
  }
3014
3443
  }
3444
+ function writeKiroCredentialsPartial(fields) {
3445
+ try {
3446
+ const authPath = join2(homedir2(), ".pi", "agent", "auth.json");
3447
+ const raw = existsSync2(authPath) ? readFileSync2(authPath, "utf-8") : "{}";
3448
+ const data = JSON.parse(raw);
3449
+ const existing = data["kiro"] ?? {};
3450
+ data["kiro"] = { ...existing, ...fields };
3451
+ writeFileSync(authPath, JSON.stringify(data, null, 2), { mode: 384 });
3452
+ } catch (err) {
3453
+ log.warn(`Failed to persist partial credentials: ${err}`);
3454
+ }
3455
+ }
3015
3456
  async function extension_default(pi) {
3016
3457
  let modelDefs = toProviderModels(kiroModels);
3017
3458
  const creds = readKiroCredentials();
3018
- if (creds?.profileArn) {
3459
+ if (creds?.access || creds?.refresh) {
3019
3460
  let accessToken = creds.access;
3020
3461
  if (creds.refresh) {
3021
3462
  try {
@@ -3027,16 +3468,34 @@ async function extension_default(pi) {
3027
3468
  log.warn(`Startup token refresh failed, trying with existing token: ${err}`);
3028
3469
  }
3029
3470
  }
3030
- try {
3031
- const apiRegion = resolveApiRegion(creds.region);
3032
- seedProfileArn(creds.profileArn);
3033
- const apiModels = await fetchAvailableModels(accessToken, apiRegion, creds.profileArn);
3034
- const dynamicDefs = buildModelsFromApi(apiModels);
3035
- setCachedDynamicModels(dynamicDefs);
3036
- modelDefs = toProviderModels(dynamicDefs);
3037
- log.info(`Loaded ${modelDefs.length} models dynamically from Kiro API`);
3038
- } catch (err) {
3039
- log.warn(`Failed to fetch models at startup, using hardcoded fallback: ${err}`);
3471
+ let profileArn = creds.profileArn;
3472
+ if (!profileArn && accessToken) {
3473
+ try {
3474
+ const apiRegion = resolveApiRegion(creds.region);
3475
+ log.info("profileArn missing, resolving via ListAvailableProfiles…");
3476
+ profileArn = await resolveProfileArn(accessToken, apiRegion) ?? undefined;
3477
+ if (profileArn) {
3478
+ log.info(`Resolved profileArn: ${profileArn}`);
3479
+ writeKiroCredentialsPartial({ profileArn });
3480
+ } else {
3481
+ log.warn("Could not resolve profileArn — model fetch and streaming will fail");
3482
+ }
3483
+ } catch (err) {
3484
+ log.warn(`profileArn resolution failed: ${err}`);
3485
+ }
3486
+ }
3487
+ if (profileArn) {
3488
+ seedProfileArn(profileArn);
3489
+ try {
3490
+ const apiRegion = resolveApiRegion(creds.region);
3491
+ const apiModels = await fetchAvailableModels(accessToken, apiRegion, profileArn);
3492
+ const dynamicDefs = buildModelsFromApi(apiModels);
3493
+ setCachedDynamicModels(dynamicDefs);
3494
+ modelDefs = toProviderModels(dynamicDefs);
3495
+ log.info(`Loaded ${modelDefs.length} models dynamically from Kiro API`);
3496
+ } catch (err) {
3497
+ log.warn(`Failed to fetch models at startup, using hardcoded fallback: ${err}`);
3498
+ }
3040
3499
  }
3041
3500
  } else {
3042
3501
  log.warn("Run 'kiro login' to authenticate and fetch models dynamically. Note: This extension does not have the same authentication mechanism as other Kiro tools.");
package/dist/models.d.ts CHANGED
@@ -93,6 +93,12 @@ export interface KiroApiModel {
93
93
  };
94
94
  };
95
95
  }
96
+ /**
97
+ * Resolve the Kiro profile ARN by calling ListAvailableProfiles.
98
+ * Builder ID device-code login doesn't receive a profileArn, so we
99
+ * discover it here. Returns null on failure (graceful fallback).
100
+ */
101
+ export declare function resolveProfileArn(accessToken: string, apiRegion: string): Promise<string | null>;
96
102
  /**
97
103
  * Fetch the list of models actually available for this account from Kiro.
98
104
  * Filters out "auto" — it appears in ListAvailableModels but is rejected
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAOA,gEAAgE;AAChE,eAAO,MAAM,cAAc,aAuBzB,CAAC;AAEH,0EAA0E;AAC1E,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMxD;AA8BD,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAGtE;AAiDD,wBAAgB,oBAAoB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAC3D,MAAM,EAAE,CAAC,EAAE,EACX,SAAS,EAAE,MAAM,GAChB,CAAC,EAAE,CASL;AAQD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3D;AAaD,KAAK,KAAK,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;AAIlC,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,UAAU,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/E,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,iEAAiE;IACjE,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,eAAO,MAAM,UAAU,EAAE,SAAS,EAwNjC,CAAC;AAIF,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,qEAAqE;IACrE,kCAAkC,CAAC,EAAE;QACnC,UAAU,CAAC,EAAE;YACX,aAAa,CAAC,EAAE;gBAAE,UAAU,CAAC,EAAE;oBAAE,MAAM,CAAC,EAAE;wBAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;qBAAE,CAAA;iBAAE,CAAA;aAAE,CAAC;YAClE,QAAQ,CAAC,EAAE;gBAAE,UAAU,CAAC,EAAE;oBAAE,IAAI,CAAC,EAAE;wBAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;qBAAE,CAAA;iBAAE,CAAA;aAAE,CAAC;SAC5D,CAAC;KACH,CAAC;CACH;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CA6BzB;AAqBD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAiC5E;AAKD,wBAAgB,sBAAsB,IAAI,YAAY,EAAE,GAAG,IAAI,CAE9D;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,GAAG,IAAI,CAE1E"}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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"}
package/dist/oauth.d.ts CHANGED
@@ -21,7 +21,7 @@ export interface KiroCredentials extends OAuthCredentials {
21
21
  * - `idc`: IAM Identity Center (enterprise SSO, any region).
22
22
  * - `desktop`: Kiro IDE native install (bare refresh token, no clientId/clientSecret).
23
23
  */
24
- authMethod: "builder-id" | "idc" | "desktop";
24
+ authMethod: "builder-id" | "idc" | "desktop" | "social";
25
25
  /** Profile ARN from Kiro, used to scope API calls. */
26
26
  profileArn?: string;
27
27
  /** Local Kiro source, used only to decide safe CLI DB write-back. */
@@ -1 +1 @@
1
- {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AASnF,OAAO,KAAK,EAAsB,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEhF,eAAO,MAAM,oBAAoB,mCAAmC,CAAC;AACrE,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAC7C,eAAO,MAAM,UAAU,UAMtB,CAAC;AAmBF,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,UAAU,EAAE,YAAY,GAAG,KAAK,GAAG,SAAS,CAAC;IAC7C,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AA2ID;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,eAAe,CAAC,CAsDxF;AA8TD;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,gBAAgB,GAC5B,OAAO,CAAC,eAAe,CAAC,CAiH1B"}
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AASnF,OAAO,KAAK,EAAsB,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAIhF,eAAO,MAAM,oBAAoB,mCAAmC,CAAC;AACrE,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAC7C,eAAO,MAAM,UAAU,UAMtB,CAAC;AAmBF,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,UAAU,EAAE,YAAY,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAC;IACxD,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AA8pBD;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,eAAe,CAAC,CAsDxF;AA8TD;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,gBAAgB,GAC5B,OAAO,CAAC,eAAe,CAAC,CAkH1B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@javargasm/pi-kiro",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "Kiro provider for the pi coding agent: AWS Builder ID / IAM Identity Center login and the CodeWhisperer streaming API, exposing the Kiro Claude model family.",
5
5
  "type": "module",
6
6
  "license": "MIT",