ns-kiro-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +51 -0
  3. package/dist/blocks.d.ts +32 -0
  4. package/dist/blocks.js +83 -0
  5. package/dist/blocks.js.map +1 -0
  6. package/dist/bracket-tool-parser.d.ts +11 -0
  7. package/dist/bracket-tool-parser.js +78 -0
  8. package/dist/bracket-tool-parser.js.map +1 -0
  9. package/dist/cost.d.ts +3 -0
  10. package/dist/cost.js +10 -0
  11. package/dist/cost.js.map +1 -0
  12. package/dist/debug.d.ts +6 -0
  13. package/dist/debug.js +63 -0
  14. package/dist/debug.js.map +1 -0
  15. package/dist/effort.d.ts +36 -0
  16. package/dist/effort.js +138 -0
  17. package/dist/effort.js.map +1 -0
  18. package/dist/endpoints.d.ts +8 -0
  19. package/dist/endpoints.js +43 -0
  20. package/dist/endpoints.js.map +1 -0
  21. package/dist/event-parser.d.ts +49 -0
  22. package/dist/event-parser.js +56 -0
  23. package/dist/event-parser.js.map +1 -0
  24. package/dist/history-validator.d.ts +91 -0
  25. package/dist/history-validator.js +370 -0
  26. package/dist/history-validator.js.map +1 -0
  27. package/dist/history.d.ts +21 -0
  28. package/dist/history.js +130 -0
  29. package/dist/history.js.map +1 -0
  30. package/dist/index.d.ts +22 -0
  31. package/dist/index.js +28 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/invoke-tool-parser.d.ts +16 -0
  34. package/dist/invoke-tool-parser.js +152 -0
  35. package/dist/invoke-tool-parser.js.map +1 -0
  36. package/dist/kiro-cli.d.ts +31 -0
  37. package/dist/kiro-cli.js +308 -0
  38. package/dist/kiro-cli.js.map +1 -0
  39. package/dist/kiro-ide.d.ts +12 -0
  40. package/dist/kiro-ide.js +74 -0
  41. package/dist/kiro-ide.js.map +1 -0
  42. package/dist/management.d.ts +34 -0
  43. package/dist/management.js +226 -0
  44. package/dist/management.js.map +1 -0
  45. package/dist/models.d.ts +58 -0
  46. package/dist/models.js +462 -0
  47. package/dist/models.js.map +1 -0
  48. package/dist/oauth.d.ts +50 -0
  49. package/dist/oauth.js +295 -0
  50. package/dist/oauth.js.map +1 -0
  51. package/dist/retry.d.ts +74 -0
  52. package/dist/retry.js +156 -0
  53. package/dist/retry.js.map +1 -0
  54. package/dist/stream.d.ts +36 -0
  55. package/dist/stream.js +898 -0
  56. package/dist/stream.js.map +1 -0
  57. package/dist/thinking-parser.d.ts +21 -0
  58. package/dist/thinking-parser.js +150 -0
  59. package/dist/thinking-parser.js.map +1 -0
  60. package/dist/token-type.d.ts +18 -0
  61. package/dist/token-type.js +45 -0
  62. package/dist/token-type.js.map +1 -0
  63. package/dist/tokenizer.d.ts +1 -0
  64. package/dist/tokenizer.js +19 -0
  65. package/dist/tokenizer.js.map +1 -0
  66. package/dist/transform.d.ts +111 -0
  67. package/dist/transform.js +268 -0
  68. package/dist/transform.js.map +1 -0
  69. package/dist/truncation.d.ts +3 -0
  70. package/dist/truncation.js +12 -0
  71. package/dist/truncation.js.map +1 -0
  72. package/dist/types.d.ts +159 -0
  73. package/dist/types.js +4 -0
  74. package/dist/types.js.map +1 -0
  75. package/dist/usage.d.ts +86 -0
  76. package/dist/usage.js +85 -0
  77. package/dist/usage.js.map +1 -0
  78. package/package.json +31 -0
@@ -0,0 +1,308 @@
1
+ // ABOUTME: Reads and writes credentials from the kiro-cli SQLite database.
2
+ // ABOUTME: Provides fallback auth and write-back to keep kiro-cli in sync after refresh.
3
+ import { execFileSync, execSync } from "node:child_process";
4
+ import { existsSync } from "node:fs";
5
+ import { createRequire } from "node:module";
6
+ import { homedir, platform } from "node:os";
7
+ import { join } from "node:path";
8
+ import { formatSafeError } from "./debug.js";
9
+ const require = createRequire(import.meta.url);
10
+ /** kiro-cli's secret-store key for an enterprise external IdP (OIDC) session. */
11
+ const EXTERNAL_IDP_TOKEN_KEY = "kirocli:external-idp:token";
12
+ export function getKiroCliDbPath() {
13
+ const p = platform();
14
+ let dbPath;
15
+ if (p === "win32")
16
+ dbPath = join(process.env.APPDATA || join(homedir(), "AppData", "Roaming"), "kiro-cli", "data.sqlite3");
17
+ else if (p === "darwin")
18
+ dbPath = join(homedir(), "Library", "Application Support", "kiro-cli", "data.sqlite3");
19
+ else
20
+ dbPath = join(homedir(), ".local", "share", "kiro-cli", "data.sqlite3");
21
+ return existsSync(dbPath) ? dbPath : undefined;
22
+ }
23
+ function getNodeSqlite() {
24
+ try {
25
+ return require("node:sqlite");
26
+ }
27
+ catch {
28
+ return undefined;
29
+ }
30
+ }
31
+ function queryKiroCliDb(dbPath, sql) {
32
+ const sqlite = getNodeSqlite();
33
+ if (sqlite) {
34
+ try {
35
+ const db = new sqlite.DatabaseSync(dbPath, { readOnly: true });
36
+ try {
37
+ const rows = db.prepare(sql).all();
38
+ const result = JSON.stringify(rows);
39
+ return result === "[]" ? undefined : result;
40
+ }
41
+ finally {
42
+ db.close();
43
+ }
44
+ }
45
+ catch {
46
+ // Fall through to sqlite3 CLI fallback
47
+ }
48
+ }
49
+ try {
50
+ const result = execSync(`sqlite3 -json "${dbPath}" "${sql}"`, {
51
+ encoding: "utf-8",
52
+ timeout: 5000,
53
+ stdio: ["pipe", "pipe", "pipe"],
54
+ }).trim();
55
+ return result || undefined;
56
+ }
57
+ catch {
58
+ return undefined;
59
+ }
60
+ }
61
+ function execKiroCliDb(dbPath, sql) {
62
+ const sqlite = getNodeSqlite();
63
+ if (sqlite) {
64
+ try {
65
+ const db = new sqlite.DatabaseSync(dbPath);
66
+ try {
67
+ db.exec(sql);
68
+ return true;
69
+ }
70
+ finally {
71
+ db.close();
72
+ }
73
+ }
74
+ catch {
75
+ // Fall through to sqlite3 CLI fallback
76
+ }
77
+ }
78
+ try {
79
+ execSync(`sqlite3 "${dbPath}"`, {
80
+ input: sql,
81
+ encoding: "utf-8",
82
+ timeout: 5000,
83
+ stdio: ["pipe", "pipe", "pipe"],
84
+ });
85
+ return true;
86
+ }
87
+ catch {
88
+ return false;
89
+ }
90
+ }
91
+ export function getKiroCliCredentials() {
92
+ const dbPath = getKiroCliDbPath();
93
+ if (!dbPath)
94
+ return undefined;
95
+ try {
96
+ // Try IDC token first (preferred — has clientId/clientSecret for refresh)
97
+ const idcCreds = tryKiroCliToken(dbPath, "kirocli:odic:token", "idc");
98
+ if (idcCreds)
99
+ return idcCreds;
100
+ // Fall back to desktop/social token
101
+ const desktopCreds = tryKiroCliToken(dbPath, "kirocli:social:token", "desktop");
102
+ if (desktopCreds)
103
+ return desktopCreds;
104
+ // Enterprise external IdP (OIDC) login — refreshed against the customer's
105
+ // own token endpoint rather than AWS SSO
106
+ const externalIdpCreds = tryKiroCliToken(dbPath, EXTERNAL_IDP_TOKEN_KEY, "external-idp");
107
+ if (externalIdpCreds)
108
+ return externalIdpCreds;
109
+ return undefined;
110
+ }
111
+ catch {
112
+ return undefined;
113
+ }
114
+ }
115
+ /**
116
+ * Like getKiroCliCredentials but returns credentials even when the access token
117
+ * is expired, as long as a refresh token exists. Used to attempt a token refresh
118
+ * before falling back to the full device code login flow.
119
+ */
120
+ export function getKiroCliCredentialsAllowExpired() {
121
+ const dbPath = getKiroCliDbPath();
122
+ if (!dbPath)
123
+ return undefined;
124
+ try {
125
+ const idcCreds = tryKiroCliToken(dbPath, "kirocli:odic:token", "idc", true);
126
+ if (idcCreds)
127
+ return idcCreds;
128
+ const desktopCreds = tryKiroCliToken(dbPath, "kirocli:social:token", "desktop", true);
129
+ if (desktopCreds)
130
+ return desktopCreds;
131
+ const externalIdpCreds = tryKiroCliToken(dbPath, EXTERNAL_IDP_TOKEN_KEY, "external-idp", true);
132
+ if (externalIdpCreds)
133
+ return externalIdpCreds;
134
+ return undefined;
135
+ }
136
+ catch {
137
+ return undefined;
138
+ }
139
+ }
140
+ function tryKiroCliToken(dbPath, tokenKey, authMethod, allowExpired = false) {
141
+ const tokenResult = queryKiroCliDb(dbPath, `SELECT value FROM auth_kv WHERE key = '${tokenKey}'`);
142
+ if (!tokenResult)
143
+ return undefined;
144
+ const rows = JSON.parse(tokenResult);
145
+ if (!rows[0]?.value)
146
+ return undefined;
147
+ const tokenData = JSON.parse(rows[0].value);
148
+ if (!tokenData.access_token || !tokenData.refresh_token)
149
+ return undefined;
150
+ let expiresAt = Date.now() + 3600000;
151
+ if (tokenData.expires_at)
152
+ expiresAt = new Date(tokenData.expires_at).getTime();
153
+ if (!allowExpired && Date.now() >= expiresAt - 2 * 60 * 1000)
154
+ return undefined;
155
+ const region = tokenData.region || "us-east-1";
156
+ if (authMethod === "desktop") {
157
+ return {
158
+ refresh: `${tokenData.refresh_token}|desktop`,
159
+ access: tokenData.access_token,
160
+ expires: expiresAt,
161
+ clientId: "",
162
+ clientSecret: "",
163
+ region,
164
+ authMethod: "desktop",
165
+ profileArn: tokenData.profile_arn || tokenData.profileArn,
166
+ };
167
+ }
168
+ // External IdP — the customer's own OIDC app. It is a public PKCE client, so
169
+ // there is no client secret; carry the token endpoint through the refresh
170
+ // string because it is per-tenant and not derivable from a region.
171
+ if (authMethod === "external-idp") {
172
+ const idpClientId = tokenData.client_id || tokenData.clientId || "";
173
+ const issuerUrl = tokenData.issuer_url || "";
174
+ const tokenEndpoint = tokenData.token_endpoint ||
175
+ tokenData.tokenEndpoint ||
176
+ (issuerUrl ? `${issuerUrl.replace(/\/+$/, "")}/v1/token` : "");
177
+ return {
178
+ refresh: `${tokenData.refresh_token}|${idpClientId}|${tokenEndpoint}|external-idp`,
179
+ access: tokenData.access_token,
180
+ expires: expiresAt,
181
+ clientId: idpClientId,
182
+ clientSecret: "",
183
+ region,
184
+ authMethod: "external-idp",
185
+ profileArn: tokenData.profile_arn || tokenData.profileArn,
186
+ };
187
+ }
188
+ // IDC — need device registration credentials for refresh
189
+ let clientId = "";
190
+ let clientSecret = "";
191
+ // Match the device-registration key to the same prefix as the token key
192
+ const keyPrefix = tokenKey.split(":")[0]; // "kirocli" or "codewhisperer"
193
+ const deviceResult = queryKiroCliDb(dbPath, `SELECT value FROM auth_kv WHERE key = '${keyPrefix}:odic:device-registration'`);
194
+ if (deviceResult) {
195
+ try {
196
+ const d = JSON.parse(JSON.parse(deviceResult)[0]?.value);
197
+ clientId = d.client_id || d.clientId || "";
198
+ clientSecret = d.client_secret || d.clientSecret || "";
199
+ }
200
+ catch { }
201
+ }
202
+ return {
203
+ refresh: `${tokenData.refresh_token}|${clientId}|${clientSecret}|idc`,
204
+ access: tokenData.access_token,
205
+ expires: expiresAt,
206
+ clientId,
207
+ clientSecret,
208
+ region,
209
+ authMethod: "idc",
210
+ profileArn: tokenData.profile_arn || tokenData.profileArn,
211
+ };
212
+ }
213
+ // Re-export the internal function for use by getKiroCliSocialToken
214
+ export { tryKiroCliToken };
215
+ /**
216
+ * Get the social token (Google/GitHub) from kiro-cli if available.
217
+ * Returns undefined if no valid social token exists.
218
+ * This is used to prefer social login when the user has logged in that way.
219
+ */
220
+ export function getKiroCliSocialToken() {
221
+ const dbPath = getKiroCliDbPath();
222
+ if (!dbPath)
223
+ return undefined;
224
+ try {
225
+ return tryKiroCliToken(dbPath, "kirocli:social:token", "desktop");
226
+ }
227
+ catch {
228
+ return undefined;
229
+ }
230
+ }
231
+ /**
232
+ * Like getKiroCliSocialToken but returns credentials even when the access token
233
+ * is expired, as long as a refresh token exists.
234
+ */
235
+ export function getKiroCliSocialTokenAllowExpired() {
236
+ const dbPath = getKiroCliDbPath();
237
+ if (!dbPath)
238
+ return undefined;
239
+ try {
240
+ return tryKiroCliToken(dbPath, "kirocli:social:token", "desktop", true);
241
+ }
242
+ catch {
243
+ return undefined;
244
+ }
245
+ }
246
+ const TOKEN_KEY_BY_AUTH_METHOD = {
247
+ idc: ["kirocli:odic:token", "codewhisperer:odic:token"],
248
+ desktop: ["kirocli:social:token"],
249
+ "external-idp": [EXTERNAL_IDP_TOKEN_KEY],
250
+ apikey: [],
251
+ };
252
+ export function saveKiroCliCredentials(creds) {
253
+ const dbPath = getKiroCliDbPath();
254
+ if (!dbPath)
255
+ return;
256
+ const rawRefreshToken = creds.refresh.split("|")[0] ?? "";
257
+ // Our expires has a 5-min buffer subtracted; restore approximate actual expiry for kiro-cli
258
+ const expiresAt = new Date(creds.expires + 5 * 60 * 1000).toISOString();
259
+ const tokenKeys = TOKEN_KEY_BY_AUTH_METHOD[creds.authMethod] ?? [];
260
+ for (const key of tokenKeys) {
261
+ const existing = queryKiroCliDb(dbPath, `SELECT value FROM auth_kv WHERE key = '${key}'`);
262
+ if (!existing)
263
+ continue;
264
+ try {
265
+ const rows = JSON.parse(existing);
266
+ if (!rows[0]?.value)
267
+ continue;
268
+ const tokenData = JSON.parse(rows[0].value);
269
+ tokenData.access_token = creds.access;
270
+ tokenData.refresh_token = rawRefreshToken;
271
+ tokenData.expires_at = expiresAt;
272
+ // kiro-cli's ExternalIdpToken record has no region/profile_arn fields;
273
+ // don't add keys it never wrote.
274
+ if (creds.authMethod !== "external-idp") {
275
+ if (creds.region)
276
+ tokenData.region = creds.region;
277
+ if (creds.profileArn)
278
+ tokenData.profile_arn = creds.profileArn;
279
+ }
280
+ const escaped = JSON.stringify(tokenData).replace(/'/g, "''");
281
+ const sql = `UPDATE auth_kv SET value = '${escaped}' WHERE key = '${key}';`;
282
+ if (execKiroCliDb(dbPath, sql))
283
+ return;
284
+ }
285
+ catch { }
286
+ }
287
+ }
288
+ /**
289
+ * Ask kiro-cli to refresh its own tokens via `kiro-cli debug refresh-auth-token`,
290
+ * then re-read the SQLite DB for fresh credentials.
291
+ *
292
+ * Returns refreshed credentials on success, or undefined if kiro-cli is not
293
+ * installed, the command fails, or the DB still has no valid tokens afterward.
294
+ */
295
+ export function refreshViaKiroCli() {
296
+ try {
297
+ execFileSync("kiro-cli", ["debug", "refresh-auth-token"], {
298
+ timeout: 15000,
299
+ stdio: ["pipe", "pipe", "pipe"],
300
+ });
301
+ return getKiroCliCredentials();
302
+ }
303
+ catch (error) {
304
+ console.warn(`[kiro-core] kiro-cli refresh failed: ${formatSafeError(error)}`);
305
+ return undefined;
306
+ }
307
+ }
308
+ //# sourceMappingURL=kiro-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kiro-cli.js","sourceRoot":"","sources":["../src/kiro-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { KiroCredentials } from "./oauth.js";
2
+ /**
3
+ * Returns valid (non-expired) Kiro IDE credentials read from
4
+ * ~/.aws/sso/cache/kiro-auth-token.json, or undefined if the IDE has not
5
+ * logged in or the token has already expired.
6
+ */
7
+ export declare function getKiroIdeCredentials(): KiroCredentials | undefined;
8
+ /**
9
+ * Like getKiroIdeCredentials but also returns expired tokens so the caller can
10
+ * attempt a silent OIDC refresh before falling back to the full login flow.
11
+ */
12
+ export declare function getKiroIdeCredentialsAllowExpired(): KiroCredentials | undefined;
@@ -0,0 +1,74 @@
1
+ // ABOUTME: Reads credentials written by the Kiro IDE.
2
+ // ABOUTME: The IDE stores its auth token at ~/.aws/sso/cache/kiro-auth-token.json
3
+ // ABOUTME: on all platforms (Windows, macOS, Linux) after every successful login,
4
+ // ABOUTME: including IAM Identity Center (authMethod: "IdC") and Builder ID.
5
+ // ABOUTME: A companion file, ~/.aws/sso/cache/{clientIdHash}.json, holds the
6
+ // ABOUTME: OIDC clientId/clientSecret needed to silently refresh the access token
7
+ // ABOUTME: via the standard AWS OIDC /token endpoint — no extra login flow needed.
8
+ import { existsSync, readFileSync } from "node:fs";
9
+ import { homedir } from "node:os";
10
+ import { join } from "node:path";
11
+ // ~/.aws/sso/cache is the standard AWS SSO cache directory on all platforms.
12
+ // Node's os.homedir() returns the correct home directory on Windows, macOS and Linux.
13
+ const SSO_CACHE_DIR = join(homedir(), ".aws", "sso", "cache");
14
+ const KIRO_IDE_TOKEN_PATH = join(SSO_CACHE_DIR, "kiro-auth-token.json");
15
+ function readKiroIdeToken(allowExpired) {
16
+ try {
17
+ if (!existsSync(KIRO_IDE_TOKEN_PATH))
18
+ return undefined;
19
+ const tokenData = JSON.parse(readFileSync(KIRO_IDE_TOKEN_PATH, "utf-8"));
20
+ if (!tokenData.accessToken || !tokenData.refreshToken)
21
+ return undefined;
22
+ const expiresAt = new Date(tokenData.expiresAt).getTime();
23
+ if (!allowExpired && Date.now() >= expiresAt - 2 * 60 * 1000)
24
+ return undefined;
25
+ const region = tokenData.region ?? "us-east-1";
26
+ // Load the OIDC client registration so refreshKiroTokenDirect can call the
27
+ // AWS OIDC /token endpoint with a refresh_token grant without prompting the user.
28
+ let clientId = "";
29
+ let clientSecret = "";
30
+ if (tokenData.clientIdHash) {
31
+ const regPath = join(SSO_CACHE_DIR, `${tokenData.clientIdHash}.json`);
32
+ if (existsSync(regPath)) {
33
+ try {
34
+ const reg = JSON.parse(readFileSync(regPath, "utf-8"));
35
+ clientId = reg.clientId ?? "";
36
+ clientSecret = reg.clientSecret ?? "";
37
+ }
38
+ catch {
39
+ // Ignore — we can still use the token without a refresh client
40
+ }
41
+ }
42
+ }
43
+ return {
44
+ // Pack into the same pipe-delimited format used by the rest of the refresh chain
45
+ refresh: `${tokenData.refreshToken}|${clientId}|${clientSecret}|idc`,
46
+ access: tokenData.accessToken,
47
+ // Subtract 2-min buffer so we refresh before the actual AWS expiry
48
+ expires: expiresAt - 2 * 60 * 1000,
49
+ clientId,
50
+ clientSecret,
51
+ region,
52
+ authMethod: "idc",
53
+ };
54
+ }
55
+ catch {
56
+ return undefined;
57
+ }
58
+ }
59
+ /**
60
+ * Returns valid (non-expired) Kiro IDE credentials read from
61
+ * ~/.aws/sso/cache/kiro-auth-token.json, or undefined if the IDE has not
62
+ * logged in or the token has already expired.
63
+ */
64
+ export function getKiroIdeCredentials() {
65
+ return readKiroIdeToken(false);
66
+ }
67
+ /**
68
+ * Like getKiroIdeCredentials but also returns expired tokens so the caller can
69
+ * attempt a silent OIDC refresh before falling back to the full login flow.
70
+ */
71
+ export function getKiroIdeCredentialsAllowExpired() {
72
+ return readKiroIdeToken(true);
73
+ }
74
+ //# sourceMappingURL=kiro-ide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kiro-ide.js","sourceRoot":"","sources":["../src/kiro-ide.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,kFAAkF;AAClF,kFAAkF;AAClF,6EAA6E;AAC7E,6EAA6E;AAC7E,kFAAkF;AAClF,mFAAmF;AAEnF,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,6EAA6E;AAC7E,sFAAsF;AACtF,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;AAC9D,MAAM,mBAAmB,GAAG,IAAI,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAC;AAkBxE,SAAS,gBAAgB,CAAC,YAAqB;IAC7C,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC;YAAE,OAAO,SAAS,CAAC;QAEvD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAqB,CAAC;QAC7F,IAAI,CAAC,SAAS,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,YAAY;YAAE,OAAO,SAAS,CAAC;QAExE,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;QAC1D,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI;YAAE,OAAO,SAAS,CAAC;QAE/E,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,IAAI,WAAW,CAAC;QAE/C,2EAA2E;QAC3E,kFAAkF;QAClF,IAAI,QAAQ,GAAG,EAAE,CAAC;QAClB,IAAI,YAAY,GAAG,EAAE,CAAC;QACtB,IAAI,SAAS,CAAC,YAAY,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,EAAE,GAAG,SAAS,CAAC,YAAY,OAAO,CAAC,CAAC;YACtE,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBACxB,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAsB,CAAC;oBAC5E,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC;oBAC9B,YAAY,GAAG,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;gBACxC,CAAC;gBAAC,MAAM,CAAC;oBACP,+DAA+D;gBACjE,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO;YACL,iFAAiF;YACjF,OAAO,EAAE,GAAG,SAAS,CAAC,YAAY,IAAI,QAAQ,IAAI,YAAY,MAAM;YACpE,MAAM,EAAE,SAAS,CAAC,WAAW;YAC7B,mEAAmE;YACnE,OAAO,EAAE,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI;YAClC,QAAQ;YACR,YAAY;YACZ,MAAM;YACN,UAAU,EAAE,KAAK;SAClB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iCAAiC;IAC/C,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,34 @@
1
+ export interface KiroManagementAuth {
2
+ accessToken: string;
3
+ region: string;
4
+ }
5
+ export interface KiroCatalogModel {
6
+ modelId: string;
7
+ tokenLimits?: {
8
+ maxInputTokens?: number;
9
+ maxOutputTokens?: number;
10
+ [key: string]: unknown;
11
+ };
12
+ additionalModelRequestFieldsSchema?: Record<string, unknown> | null;
13
+ [key: string]: unknown;
14
+ }
15
+ export interface KiroListAvailableModelsResponse {
16
+ models: KiroCatalogModel[];
17
+ [key: string]: unknown;
18
+ }
19
+ export interface KiroGetUsageLimitsRequest {
20
+ profileArn?: string;
21
+ origin: "KIRO_CLI";
22
+ resourceType: "CREDIT";
23
+ isEmailRequired: false;
24
+ }
25
+ export declare class KiroManagementHttpError extends Error {
26
+ readonly status: number;
27
+ constructor(message: string, status: number);
28
+ }
29
+ export declare function resetKiroProfileArnCache(): void;
30
+ export declare function invalidateKiroProfileArn(auth: KiroManagementAuth): void;
31
+ export declare function resolveKiroProfileArn(auth: KiroManagementAuth, providedArn?: string): Promise<string>;
32
+ export declare function listAvailableModels(auth: KiroManagementAuth, profileArn: string): Promise<KiroListAvailableModelsResponse>;
33
+ export declare function fetchKiroModelCatalog(auth: KiroManagementAuth, providedProfileArn?: string): Promise<KiroListAvailableModelsResponse>;
34
+ export declare function getUsageLimits<TResponse>(auth: KiroManagementAuth, request: KiroGetUsageLimitsRequest): Promise<TResponse>;
@@ -0,0 +1,226 @@
1
+ // ABOUTME: Calls the authenticated Kiro management control plane.
2
+ // ABOUTME: Resolves profiles and discovers the current per-profile model catalog.
3
+ import { createHash } from "node:crypto";
4
+ import { debugLog, redactSensitiveText } from "./debug.js";
5
+ import { getKiroEndpoints } from "./endpoints.js";
6
+ import { kiroAuthHeaders } from "./oauth.js";
7
+ import { kiroTokenTypeHeaders } from "./token-type.js";
8
+ const LIST_PROFILES_PATH = "List-Available-Profiles";
9
+ const LIST_MODELS_PATH = "List-Available-Models";
10
+ const profileArnCache = new Map();
11
+ const pendingProfileRequests = new Map();
12
+ /**
13
+ * Region where the token actually has a profile, keyed like profileArnCache.
14
+ * Populated when resolveKiroProfileArn finds the ARN on a non-primary region so
15
+ * callers can route profile-dependent management calls (ListAvailableModels) to
16
+ * the same region where the profile exists.
17
+ */
18
+ const profileRegionCache = new Map();
19
+ /**
20
+ * Canonical Kiro management regions. `resolveApiRegion` funnels every SSO region
21
+ * into one of these, but a user's actual Kiro profile may live in the other one
22
+ * (see #104: SSO eu-west-2 -> eu-central-1 while the profile is in us-east-1).
23
+ * ListAvailableProfiles is regional, so probe the canonical set when the primary
24
+ * region comes back empty before giving up.
25
+ */
26
+ const CANONICAL_MANAGEMENT_REGIONS = ["us-east-1", "eu-central-1"];
27
+ function candidateManagementRegions(primary) {
28
+ const seen = new Set([primary]);
29
+ const candidates = [primary];
30
+ for (const region of CANONICAL_MANAGEMENT_REGIONS) {
31
+ if (!seen.has(region)) {
32
+ seen.add(region);
33
+ candidates.push(region);
34
+ }
35
+ }
36
+ return candidates;
37
+ }
38
+ /**
39
+ * Explicit user override for which Kiro profile to resolve/use. When set, it
40
+ * wins over any token-carried or network-discovered profile, fixing #110's
41
+ * "wrong profile picked among several -> reduced model catalog" for users who
42
+ * have multiple profiles and know which one they want.
43
+ */
44
+ const ENV_PROFILE_ARN = "KIRO_PROFILE_ARN";
45
+ export class KiroManagementHttpError extends Error {
46
+ status;
47
+ constructor(message, status) {
48
+ super(message);
49
+ this.status = status;
50
+ this.name = "KiroManagementHttpError";
51
+ }
52
+ }
53
+ async function requestManagement(auth, operation, path, method, body) {
54
+ const url = new URL(path, getKiroEndpoints(auth.region).management);
55
+ const request = {
56
+ method,
57
+ headers: {
58
+ Accept: "application/json",
59
+ ...kiroAuthHeaders(auth.accessToken),
60
+ ...kiroTokenTypeHeaders(auth.accessToken),
61
+ },
62
+ };
63
+ if (method === "GET") {
64
+ for (const [name, value] of Object.entries(body)) {
65
+ if (value !== undefined)
66
+ url.searchParams.set(name, String(value));
67
+ }
68
+ }
69
+ else {
70
+ request.headers = { ...request.headers, "Content-Type": "application/json" };
71
+ request.body = JSON.stringify(body);
72
+ }
73
+ let response;
74
+ try {
75
+ response = await fetch(url.toString(), request);
76
+ }
77
+ catch (error) {
78
+ throw new Error(`Kiro management ${operation} request failed in ${auth.region}`, { cause: error });
79
+ }
80
+ return parseManagementResponse(response, operation, auth.region);
81
+ }
82
+ function profileCacheKey(auth) {
83
+ const tokenHash = createHash("sha256").update(auth.accessToken).digest("base64url");
84
+ return `${auth.region}:${tokenHash}`;
85
+ }
86
+ async function parseManagementResponse(response, operation, region) {
87
+ if (!response.ok) {
88
+ const statusText = response.statusText ? ` ${redactSensitiveText(response.statusText)}` : "";
89
+ throw new KiroManagementHttpError(`Kiro management ${operation} failed in ${region}: ${response.status}${statusText}`, response.status);
90
+ }
91
+ try {
92
+ return (await response.json());
93
+ }
94
+ catch (error) {
95
+ throw new Error(`Kiro management ${operation} returned invalid JSON in ${region}`, { cause: error });
96
+ }
97
+ }
98
+ export function resetKiroProfileArnCache() {
99
+ profileArnCache.clear();
100
+ profileRegionCache.clear();
101
+ pendingProfileRequests.clear();
102
+ }
103
+ export function invalidateKiroProfileArn(auth) {
104
+ const key = profileCacheKey(auth);
105
+ profileArnCache.delete(key);
106
+ profileRegionCache.delete(key);
107
+ pendingProfileRequests.delete(key);
108
+ }
109
+ export async function resolveKiroProfileArn(auth, providedArn) {
110
+ // Explicit user override (#110). Highest precedence: a user who pins
111
+ // KIRO_PROFILE_ARN knows which profile they want, even if the token or the
112
+ // profile list contains several candidates.
113
+ const envArn = process.env[ENV_PROFILE_ARN]?.trim();
114
+ if (envArn) {
115
+ debugLog("profile.resolve", { source: "env", arn: envArn });
116
+ return envArn;
117
+ }
118
+ if (providedArn) {
119
+ debugLog("profile.resolve", { source: "provided", arn: providedArn });
120
+ return providedArn;
121
+ }
122
+ const key = profileCacheKey(auth);
123
+ const cachedArn = profileArnCache.get(key);
124
+ if (cachedArn)
125
+ return cachedArn;
126
+ const pending = pendingProfileRequests.get(key);
127
+ if (pending)
128
+ return pending;
129
+ const request = (async () => {
130
+ // ListAvailableProfiles is regional to where the profile actually lives, not
131
+ // to the SSO-derived API region. Probe the primary region first, then the
132
+ // remaining canonical management regions, so a region-mismatched token still
133
+ // resolves a profile instead of failing hard (#104, #131).
134
+ let lastResponse;
135
+ let lastHttpError;
136
+ for (const region of candidateManagementRegions(auth.region)) {
137
+ let response;
138
+ try {
139
+ response = await requestManagement({ ...auth, region }, "ListAvailableProfiles", LIST_PROFILES_PATH, "POST", {});
140
+ }
141
+ catch (error) {
142
+ // A regional 403 means the token has no profile *in this region*, not
143
+ // that it is globally rejected. The profile can live in another
144
+ // canonical region, so keep probing; only rethrow if no region yields
145
+ // a profile, so callers that treat a 403 as "refresh credentials and
146
+ // retry" (#107) still see the auth-plane signal when it is genuine.
147
+ if (error instanceof KiroManagementHttpError && error.status === 403) {
148
+ lastHttpError = error;
149
+ continue;
150
+ }
151
+ throw error;
152
+ }
153
+ lastResponse = response;
154
+ const arn = response.profiles?.find((profile) => profile.arn)?.arn;
155
+ if (arn) {
156
+ profileArnCache.set(key, arn);
157
+ profileRegionCache.set(key, region);
158
+ debugLog("profile.resolve", { source: "network", region, arn });
159
+ return arn;
160
+ }
161
+ }
162
+ if (lastHttpError)
163
+ throw lastHttpError;
164
+ const attemptedRegions = candidateManagementRegions(auth.region).join(", ");
165
+ throw new Error(`Kiro management ListAvailableProfiles returned no profile in ${attemptedRegions} ` +
166
+ `(SSO-derived region: ${auth.region}). If kiro-cli works, verify your profile region with \`kiro-cli whoami\`; ` +
167
+ `the management API is regional to the profile, not to your login region.`, ...(lastResponse ? [{ cause: lastResponse }] : []));
168
+ })();
169
+ pendingProfileRequests.set(key, request);
170
+ try {
171
+ return await request;
172
+ }
173
+ finally {
174
+ if (pendingProfileRequests.get(key) === request)
175
+ pendingProfileRequests.delete(key);
176
+ }
177
+ }
178
+ export async function listAvailableModels(auth, profileArn) {
179
+ const response = await requestManagement(auth, "ListAvailableModels", LIST_MODELS_PATH, "GET", {
180
+ origin: "KIRO_CLI",
181
+ profileArn,
182
+ });
183
+ if (!Array.isArray(response.models) || response.models.length === 0) {
184
+ throw new Error(`Kiro management ListAvailableModels returned no models in ${auth.region}`);
185
+ }
186
+ if (response.models.some((model) => !model || typeof model.modelId !== "string" || !model.modelId)) {
187
+ throw new Error(`Kiro management ListAvailableModels returned an invalid catalog in ${auth.region}`);
188
+ }
189
+ return response;
190
+ }
191
+ export async function fetchKiroModelCatalog(auth, providedProfileArn) {
192
+ const profileArn = await resolveKiroProfileArn(auth, providedProfileArn);
193
+ // Route the models query to the region where the profile actually lives — it
194
+ // may differ from the SSO-derived region (#104), and ListAvailableModels is
195
+ // regional to the profile too, not to the login region.
196
+ const region = profileRegionCache.get(profileCacheKey(auth)) ?? auth.region;
197
+ if (region !== auth.region) {
198
+ return listAvailableModels({ ...auth, region }, profileArn);
199
+ }
200
+ return listAvailableModels(auth, profileArn);
201
+ }
202
+ export async function getUsageLimits(auth, request) {
203
+ const operation = "GetUsageLimits";
204
+ const url = new URL("Get-Usage-Limits", getKiroEndpoints(auth.region).management);
205
+ for (const [name, value] of Object.entries(request)) {
206
+ if (value !== undefined)
207
+ url.searchParams.set(name, String(value));
208
+ }
209
+ let response;
210
+ try {
211
+ response = await fetch(url.toString(), {
212
+ method: "GET",
213
+ headers: {
214
+ Accept: "application/json",
215
+ ...kiroAuthHeaders(auth.accessToken),
216
+ ...kiroTokenTypeHeaders(auth.accessToken),
217
+ "User-Agent": "ns-kiro-provider",
218
+ },
219
+ });
220
+ }
221
+ catch (error) {
222
+ throw new Error(`Kiro management ${operation} request failed in ${auth.region}`, { cause: error });
223
+ }
224
+ return parseManagementResponse(response, operation, auth.region);
225
+ }
226
+ //# sourceMappingURL=management.js.map