@lightharu/krouter 1.8.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.
- package/LICENSE +679 -0
- package/README.md +238 -0
- package/dist-web/assets/index-CM4-0adf.css +1 -0
- package/dist-web/assets/index-DCslvfUR.js +139 -0
- package/dist-web/favicon.svg +9 -0
- package/dist-web/icon.svg +9 -0
- package/dist-web/index.html +19 -0
- package/out-server/main/kiroAuthSync.js +249 -0
- package/out-server/main/kproxy/certManager.js +262 -0
- package/out-server/main/kproxy/index.js +254 -0
- package/out-server/main/kproxy/mitmProxy.js +475 -0
- package/out-server/main/kproxy/types.js +23 -0
- package/out-server/main/proxy/accountPool.js +543 -0
- package/out-server/main/proxy/clientConfig.js +596 -0
- package/out-server/main/proxy/index.js +25 -0
- package/out-server/main/proxy/kiroApi.js +1996 -0
- package/out-server/main/proxy/logger.js +407 -0
- package/out-server/main/proxy/modelCatalog.js +75 -0
- package/out-server/main/proxy/promptCacheTracker.js +301 -0
- package/out-server/main/proxy/proxyServer.js +3543 -0
- package/out-server/main/proxy/selfSignedCert.js +179 -0
- package/out-server/main/proxy/systemProxy.js +250 -0
- package/out-server/main/proxy/tokenCounter.js +164 -0
- package/out-server/main/proxy/toolNameRegistry.js +57 -0
- package/out-server/main/proxy/translator.js +1084 -0
- package/out-server/main/proxy/types.js +3 -0
- package/out-server/main/registration/browser-identity.js +184 -0
- package/out-server/main/registration/chainProxy.js +349 -0
- package/out-server/main/registration/config.js +58 -0
- package/out-server/main/registration/email-service.js +801 -0
- package/out-server/main/registration/fingerprint.js +352 -0
- package/out-server/main/registration/http-utils.js +148 -0
- package/out-server/main/registration/jwe.js +74 -0
- package/out-server/main/registration/names.js +142 -0
- package/out-server/main/registration/proton-mail-window.js +339 -0
- package/out-server/main/registration/registrar.js +1715 -0
- package/out-server/main/registration/tlsClientPool.js +70 -0
- package/out-server/main/registration/xxtea.js +161 -0
- package/out-server/main/runtimePaths.js +19 -0
- package/out-server/main/utils/redact.js +95 -0
- package/out-server/server/index.js +1272 -0
- package/out-server/server/services/accountExtras.js +105 -0
- package/out-server/server/services/accountProfileHydration.js +95 -0
- package/out-server/server/services/authFlows.js +509 -0
- package/out-server/server/services/dashboardTunnel.js +315 -0
- package/out-server/server/services/diagnostics.js +326 -0
- package/out-server/server/services/kiroAccounts.js +431 -0
- package/out-server/server/services/kiroSettings.js +260 -0
- package/out-server/server/services/kproxyRuntime.js +264 -0
- package/out-server/server/services/localKiroCredentials.js +320 -0
- package/out-server/server/services/machineIdRuntime.js +327 -0
- package/out-server/server/services/protonBrowserRuntime.js +724 -0
- package/out-server/server/services/proxyRuntime.js +523 -0
- package/out-server/server/services/registrationRuntime.js +106 -0
- package/out-server/server/store.js +266 -0
- package/package.json +113 -0
- package/resources/tls-client-xgo-1.14.0-windows-amd64.dll +0 -0
- package/scripts/kiro-manager-cli.cjs +3 -0
- package/scripts/krouter-cli.cjs +509 -0
- package/src/renderer/src/assets/krouter-logo.svg +11 -0
- package/src/renderer/src/assets/krouter-mark.svg +9 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SOCIAL_SIGN_IN_PROFILE_ARN = exports.BUILDER_ID_STREAMING_PROFILE_ARN = void 0;
|
|
4
|
+
exports.normalizeProfileArn = normalizeProfileArn;
|
|
5
|
+
exports.refreshTokenByMethod = refreshTokenByMethod;
|
|
6
|
+
exports.listAvailableProfilesRest = listAvailableProfilesRest;
|
|
7
|
+
exports.resolveStreamingProfileArn = resolveStreamingProfileArn;
|
|
8
|
+
exports.refreshAccountToken = refreshAccountToken;
|
|
9
|
+
exports.verifyAccountCredentials = verifyAccountCredentials;
|
|
10
|
+
exports.checkAccountStatus = checkAccountStatus;
|
|
11
|
+
const KIRO_AUTH_ENDPOINT = 'https://prod.us-east-1.auth.desktop.kiro.dev';
|
|
12
|
+
const KIRO_VERSION = '0.6.18';
|
|
13
|
+
exports.BUILDER_ID_STREAMING_PROFILE_ARN = 'arn:aws:codewhisperer:us-east-1:638616132270:profile/AAAACCCCXXXX';
|
|
14
|
+
exports.SOCIAL_SIGN_IN_PROFILE_ARN = 'arn:aws:codewhisperer:us-east-1:699475941385:profile/EHGA3GRVQMUK';
|
|
15
|
+
const KIRO_REST_API_ENDPOINTS = {
|
|
16
|
+
'us-east-1': 'https://q.us-east-1.amazonaws.com',
|
|
17
|
+
'eu-central-1': 'https://q.eu-central-1.amazonaws.com'
|
|
18
|
+
};
|
|
19
|
+
function normalizeProfileArn(profileArn) {
|
|
20
|
+
let value = profileArn?.trim();
|
|
21
|
+
if (!value || value === exports.BUILDER_ID_STREAMING_PROFILE_ARN)
|
|
22
|
+
return undefined;
|
|
23
|
+
if (!value.startsWith('arn:') && value.includes(':codewhisperer:'))
|
|
24
|
+
value = `arn:${value}`;
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
function fixedProfileArnForProvider(provider, authMethod, profileArn) {
|
|
28
|
+
const providerKey = (provider || '').trim().toLowerCase();
|
|
29
|
+
const authKey = (authMethod || '').trim().toLowerCase();
|
|
30
|
+
const explicit = normalizeProfileArn(profileArn);
|
|
31
|
+
if (authKey === 'social' && explicit)
|
|
32
|
+
return explicit;
|
|
33
|
+
if (providerKey === 'github' || providerKey === 'google')
|
|
34
|
+
return exports.SOCIAL_SIGN_IN_PROFILE_ARN;
|
|
35
|
+
if (providerKey === 'builderid' || providerKey === 'builder_id')
|
|
36
|
+
return exports.BUILDER_ID_STREAMING_PROFILE_ARN;
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
function getRestApiBase(ssoRegion) {
|
|
40
|
+
if (!ssoRegion)
|
|
41
|
+
return KIRO_REST_API_ENDPOINTS['us-east-1'];
|
|
42
|
+
if (KIRO_REST_API_ENDPOINTS[ssoRegion])
|
|
43
|
+
return KIRO_REST_API_ENDPOINTS[ssoRegion];
|
|
44
|
+
if (ssoRegion.startsWith('eu-'))
|
|
45
|
+
return KIRO_REST_API_ENDPOINTS['eu-central-1'];
|
|
46
|
+
return KIRO_REST_API_ENDPOINTS['us-east-1'];
|
|
47
|
+
}
|
|
48
|
+
function getFallbackRestApiBase(ssoRegion) {
|
|
49
|
+
const primary = getRestApiBase(ssoRegion);
|
|
50
|
+
return primary === KIRO_REST_API_ENDPOINTS['eu-central-1']
|
|
51
|
+
? KIRO_REST_API_ENDPOINTS['us-east-1']
|
|
52
|
+
: KIRO_REST_API_ENDPOINTS['eu-central-1'];
|
|
53
|
+
}
|
|
54
|
+
function getKiroUserAgent(machineId) {
|
|
55
|
+
const suffix = machineId ? `KiroIDE-${KIRO_VERSION}-${machineId}` : `KiroIDE-${KIRO_VERSION}`;
|
|
56
|
+
return `aws-sdk-js/1.0.18 ua/2.1 os/linux lang/js md/nodejs#22 api/codewhispererstreaming#1.0.18 m/E ${suffix}`;
|
|
57
|
+
}
|
|
58
|
+
function getKiroAmzUserAgent(machineId) {
|
|
59
|
+
const suffix = machineId ? `KiroIDE ${KIRO_VERSION} ${machineId}` : `KiroIDE-${KIRO_VERSION}`;
|
|
60
|
+
return `aws-sdk-js/1.0.18 ${suffix}`;
|
|
61
|
+
}
|
|
62
|
+
function normalizeDate(value) {
|
|
63
|
+
if (value === undefined || value === null)
|
|
64
|
+
return undefined;
|
|
65
|
+
if (typeof value === 'number')
|
|
66
|
+
return new Date(value * 1000).toISOString();
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
function subscriptionTypeFromTitle(title) {
|
|
70
|
+
const upper = title.toUpperCase();
|
|
71
|
+
if (upper.includes('PRO+') || upper.includes('PRO_PLUS') || upper.includes('PROPLUS'))
|
|
72
|
+
return 'Pro_Plus';
|
|
73
|
+
if (upper.includes('POWER'))
|
|
74
|
+
return 'Enterprise';
|
|
75
|
+
if (upper.includes('PRO'))
|
|
76
|
+
return 'Pro';
|
|
77
|
+
if (upper.includes('ENTERPRISE'))
|
|
78
|
+
return 'Enterprise';
|
|
79
|
+
if (upper.includes('TEAMS'))
|
|
80
|
+
return 'Teams';
|
|
81
|
+
return 'Free';
|
|
82
|
+
}
|
|
83
|
+
async function refreshOidcToken(input) {
|
|
84
|
+
const response = await fetch(`https://oidc.${input.region}.amazonaws.com/token`, {
|
|
85
|
+
method: 'POST',
|
|
86
|
+
headers: { 'Content-Type': 'application/json' },
|
|
87
|
+
body: JSON.stringify({
|
|
88
|
+
clientId: input.clientId,
|
|
89
|
+
clientSecret: input.clientSecret,
|
|
90
|
+
refreshToken: input.refreshToken,
|
|
91
|
+
grantType: 'refresh_token'
|
|
92
|
+
})
|
|
93
|
+
});
|
|
94
|
+
if (!response.ok)
|
|
95
|
+
return { success: false, error: `HTTP ${response.status}: ${await response.text()}` };
|
|
96
|
+
const data = await response.json();
|
|
97
|
+
return {
|
|
98
|
+
success: Boolean(data.accessToken),
|
|
99
|
+
accessToken: data.accessToken,
|
|
100
|
+
refreshToken: data.refreshToken || input.refreshToken,
|
|
101
|
+
expiresIn: data.expiresIn || 3600
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
async function refreshSocialToken(refreshToken, machineId) {
|
|
105
|
+
const response = await fetch(`${KIRO_AUTH_ENDPOINT}/refreshToken`, {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
headers: {
|
|
108
|
+
'Content-Type': 'application/json',
|
|
109
|
+
'User-Agent': getKiroUserAgent(machineId)
|
|
110
|
+
},
|
|
111
|
+
body: JSON.stringify({ refreshToken })
|
|
112
|
+
});
|
|
113
|
+
if (!response.ok)
|
|
114
|
+
return { success: false, error: `HTTP ${response.status}: ${await response.text()}` };
|
|
115
|
+
const data = await response.json();
|
|
116
|
+
return {
|
|
117
|
+
success: Boolean(data.accessToken),
|
|
118
|
+
accessToken: data.accessToken,
|
|
119
|
+
refreshToken: data.refreshToken || refreshToken,
|
|
120
|
+
expiresIn: data.expiresIn || 3600
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
async function refreshTokenByMethod(input) {
|
|
124
|
+
const region = input.region || 'us-east-1';
|
|
125
|
+
if (!input.refreshToken)
|
|
126
|
+
return { success: false, error: 'Missing refresh token' };
|
|
127
|
+
if (input.authMethod === 'social')
|
|
128
|
+
return refreshSocialToken(input.refreshToken, input.machineId);
|
|
129
|
+
if (!input.clientId || !input.clientSecret)
|
|
130
|
+
return { success: false, error: 'Missing OIDC clientId/clientSecret' };
|
|
131
|
+
return refreshOidcToken({
|
|
132
|
+
refreshToken: input.refreshToken,
|
|
133
|
+
clientId: input.clientId,
|
|
134
|
+
clientSecret: input.clientSecret,
|
|
135
|
+
region
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
async function getUsageLimitsRest(input) {
|
|
139
|
+
const params = new URLSearchParams({
|
|
140
|
+
origin: 'AI_EDITOR',
|
|
141
|
+
resourceType: 'AGENTIC_REQUEST',
|
|
142
|
+
isEmailRequired: 'true'
|
|
143
|
+
});
|
|
144
|
+
const profileArn = normalizeProfileArn(input.profileArn);
|
|
145
|
+
if (profileArn)
|
|
146
|
+
params.set('profileArn', profileArn);
|
|
147
|
+
const path = `/getUsageLimits?${params.toString()}`;
|
|
148
|
+
const headers = {
|
|
149
|
+
Accept: 'application/json',
|
|
150
|
+
Authorization: `Bearer ${input.accessToken}`,
|
|
151
|
+
'User-Agent': getKiroUserAgent(input.machineId),
|
|
152
|
+
'x-amz-user-agent': getKiroAmzUserAgent(input.machineId)
|
|
153
|
+
};
|
|
154
|
+
let response = await fetch(`${getRestApiBase(input.region)}${path}`, { method: 'GET', headers });
|
|
155
|
+
if (response.status === 403) {
|
|
156
|
+
response = await fetch(`${getFallbackRestApiBase(input.region)}${path}`, { method: 'GET', headers });
|
|
157
|
+
}
|
|
158
|
+
if (!response.ok)
|
|
159
|
+
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
|
|
160
|
+
return response.json();
|
|
161
|
+
}
|
|
162
|
+
function uniqueEndpoints(region) {
|
|
163
|
+
return Array.from(new Set([
|
|
164
|
+
getRestApiBase(region),
|
|
165
|
+
getFallbackRestApiBase(region)
|
|
166
|
+
]));
|
|
167
|
+
}
|
|
168
|
+
async function postListAvailableProfiles(input) {
|
|
169
|
+
const controller = new AbortController();
|
|
170
|
+
const timeout = setTimeout(() => controller.abort(), input.timeoutMs || 10000);
|
|
171
|
+
try {
|
|
172
|
+
const response = await fetch(`${input.endpoint}/ListAvailableProfiles`, {
|
|
173
|
+
method: 'POST',
|
|
174
|
+
signal: controller.signal,
|
|
175
|
+
headers: {
|
|
176
|
+
Accept: 'application/json',
|
|
177
|
+
'Content-Type': 'application/json',
|
|
178
|
+
Authorization: `Bearer ${input.accessToken}`,
|
|
179
|
+
'User-Agent': getKiroUserAgent(input.machineId),
|
|
180
|
+
'x-amz-user-agent': getKiroAmzUserAgent(input.machineId)
|
|
181
|
+
},
|
|
182
|
+
body: JSON.stringify(input.nextToken ? { nextToken: input.nextToken } : {})
|
|
183
|
+
});
|
|
184
|
+
const text = await response.text();
|
|
185
|
+
if (!response.ok)
|
|
186
|
+
throw new Error(`HTTP ${response.status}: ${text}`);
|
|
187
|
+
return text ? JSON.parse(text) : {};
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
clearTimeout(timeout);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async function listAvailableProfilesRest(input) {
|
|
194
|
+
let lastError;
|
|
195
|
+
for (const endpoint of uniqueEndpoints(input.region || 'us-east-1')) {
|
|
196
|
+
try {
|
|
197
|
+
const profiles = [];
|
|
198
|
+
let nextToken;
|
|
199
|
+
let page = 0;
|
|
200
|
+
do {
|
|
201
|
+
const data = await postListAvailableProfiles({
|
|
202
|
+
endpoint,
|
|
203
|
+
accessToken: input.accessToken,
|
|
204
|
+
machineId: input.machineId,
|
|
205
|
+
nextToken,
|
|
206
|
+
timeoutMs: input.timeoutMs
|
|
207
|
+
});
|
|
208
|
+
profiles.push(...(Array.isArray(data.profiles) ? data.profiles : []));
|
|
209
|
+
nextToken = data.nextToken;
|
|
210
|
+
page++;
|
|
211
|
+
} while (nextToken && page < 20);
|
|
212
|
+
if (profiles.length > 0)
|
|
213
|
+
return profiles;
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (lastError)
|
|
220
|
+
throw lastError;
|
|
221
|
+
return [];
|
|
222
|
+
}
|
|
223
|
+
function getProfileArn(profile) {
|
|
224
|
+
return normalizeProfileArn(profile.arn || profile.profileArn || profile.profile_arn);
|
|
225
|
+
}
|
|
226
|
+
function chooseStreamingProfileArn(profiles) {
|
|
227
|
+
const candidates = profiles
|
|
228
|
+
.map((profile) => ({
|
|
229
|
+
arn: getProfileArn(profile),
|
|
230
|
+
name: String(profile.profileName || profile.name || '').toLowerCase(),
|
|
231
|
+
status: String(profile.status || '').toLowerCase()
|
|
232
|
+
}))
|
|
233
|
+
.filter((profile) => Boolean(profile.arn));
|
|
234
|
+
if (candidates.length === 0)
|
|
235
|
+
return undefined;
|
|
236
|
+
return (candidates.find((profile) => profile.status === 'active' && profile.name.includes('kiroprofile') && profile.arn.includes(':us-east-1:')) ||
|
|
237
|
+
candidates.find((profile) => profile.name.includes('kiroprofile') && profile.arn.includes(':us-east-1:')) ||
|
|
238
|
+
candidates.find((profile) => profile.status === 'active' && profile.arn.includes(':us-east-1:')) ||
|
|
239
|
+
candidates.find((profile) => profile.arn.includes(':us-east-1:')) ||
|
|
240
|
+
candidates.find((profile) => profile.status === 'active') ||
|
|
241
|
+
candidates[0]).arn;
|
|
242
|
+
}
|
|
243
|
+
async function resolveStreamingProfileArn(input) {
|
|
244
|
+
const explicit = normalizeProfileArn(input.profileArn);
|
|
245
|
+
if (explicit)
|
|
246
|
+
return explicit;
|
|
247
|
+
const fixedProfileArn = fixedProfileArnForProvider(input.provider, input.authMethod, input.profileArn);
|
|
248
|
+
if (fixedProfileArn)
|
|
249
|
+
return fixedProfileArn;
|
|
250
|
+
if (!input.accessToken)
|
|
251
|
+
return undefined;
|
|
252
|
+
const providerKey = (input.provider || '').trim().toLowerCase();
|
|
253
|
+
if (providerKey === 'builderid')
|
|
254
|
+
return undefined;
|
|
255
|
+
const profiles = await listAvailableProfilesRest({
|
|
256
|
+
accessToken: input.accessToken,
|
|
257
|
+
machineId: input.machineId,
|
|
258
|
+
region: input.region || 'us-east-1'
|
|
259
|
+
});
|
|
260
|
+
return chooseStreamingProfileArn(profiles);
|
|
261
|
+
}
|
|
262
|
+
function normalizeUsage(usage) {
|
|
263
|
+
const subscriptionTitle = usage.subscriptionInfo?.subscriptionTitle || usage.subscriptionInfo?.subscriptionName || 'Free';
|
|
264
|
+
const creditUsage = usage.usageBreakdownList?.find((item) => item.resourceType === 'CREDIT' || item.type === 'CREDIT');
|
|
265
|
+
const baseLimit = creditUsage?.usageLimitWithPrecision ?? creditUsage?.usageLimit ?? 0;
|
|
266
|
+
const baseCurrent = creditUsage?.currentUsageWithPrecision ?? creditUsage?.currentUsage ?? 0;
|
|
267
|
+
const trial = creditUsage?.freeTrialInfo || creditUsage?.freeTrialUsage;
|
|
268
|
+
const freeTrialActive = trial?.freeTrialStatus === 'ACTIVE';
|
|
269
|
+
const freeTrialLimit = freeTrialActive ? trial?.usageLimitWithPrecision ?? trial?.usageLimit ?? 0 : 0;
|
|
270
|
+
const freeTrialCurrent = freeTrialActive ? trial?.currentUsageWithPrecision ?? trial?.currentUsage ?? 0 : 0;
|
|
271
|
+
const bonuses = (creditUsage?.bonuses || [])
|
|
272
|
+
.filter((bonus) => !bonus.status || bonus.status === 'ACTIVE')
|
|
273
|
+
.map((bonus) => ({
|
|
274
|
+
code: bonus.bonusCode || '',
|
|
275
|
+
name: bonus.displayName || '',
|
|
276
|
+
current: bonus.currentUsageWithPrecision ?? bonus.currentUsage ?? 0,
|
|
277
|
+
limit: bonus.usageLimitWithPrecision ?? bonus.usageLimit ?? 0,
|
|
278
|
+
expiresAt: normalizeDate(bonus.expiresAt)
|
|
279
|
+
}));
|
|
280
|
+
const totalLimit = baseLimit + freeTrialLimit + bonuses.reduce((sum, bonus) => sum + bonus.limit, 0);
|
|
281
|
+
const totalCurrent = baseCurrent + freeTrialCurrent + bonuses.reduce((sum, bonus) => sum + bonus.current, 0);
|
|
282
|
+
const nextResetDate = normalizeDate(usage.nextDateReset);
|
|
283
|
+
const expiresAt = nextResetDate ? new Date(nextResetDate).getTime() : undefined;
|
|
284
|
+
return {
|
|
285
|
+
email: usage.userInfo?.email || '',
|
|
286
|
+
userId: usage.userInfo?.userId || '',
|
|
287
|
+
subscriptionType: subscriptionTypeFromTitle(subscriptionTitle),
|
|
288
|
+
subscriptionTitle,
|
|
289
|
+
subscription: {
|
|
290
|
+
rawType: usage.subscriptionInfo?.type || usage.subscriptionInfo?.subscriptionType,
|
|
291
|
+
managementTarget: usage.subscriptionInfo?.subscriptionManagementTarget,
|
|
292
|
+
upgradeCapability: usage.subscriptionInfo?.upgradeCapability,
|
|
293
|
+
overageCapability: usage.subscriptionInfo?.overageCapability
|
|
294
|
+
},
|
|
295
|
+
usage: {
|
|
296
|
+
current: totalCurrent,
|
|
297
|
+
limit: totalLimit,
|
|
298
|
+
baseLimit,
|
|
299
|
+
baseCurrent,
|
|
300
|
+
freeTrialLimit,
|
|
301
|
+
freeTrialCurrent,
|
|
302
|
+
freeTrialExpiry: normalizeDate(trial?.freeTrialExpiry),
|
|
303
|
+
bonuses,
|
|
304
|
+
nextResetDate,
|
|
305
|
+
resourceDetail: creditUsage ? {
|
|
306
|
+
displayName: creditUsage.displayName,
|
|
307
|
+
displayNamePlural: creditUsage.displayNamePlural,
|
|
308
|
+
resourceType: creditUsage.resourceType || creditUsage.type,
|
|
309
|
+
currency: creditUsage.currency,
|
|
310
|
+
unit: creditUsage.unit,
|
|
311
|
+
overageRate: creditUsage.overageRate,
|
|
312
|
+
overageCap: creditUsage.overageCap,
|
|
313
|
+
overageEnabled: usage.overageConfiguration?.overageStatus === 'ENABLED' || usage.overageConfiguration?.overageEnabled === true || usage.overageSettings?.overageStatus === 'ENABLED'
|
|
314
|
+
} : undefined
|
|
315
|
+
},
|
|
316
|
+
daysRemaining: expiresAt ? Math.max(0, Math.ceil((expiresAt - Date.now()) / 86400000)) : undefined,
|
|
317
|
+
expiresAt
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
async function refreshAccountToken(account) {
|
|
321
|
+
const credentials = account.credentials || {};
|
|
322
|
+
const result = await refreshTokenByMethod({
|
|
323
|
+
refreshToken: credentials.refreshToken || '',
|
|
324
|
+
clientId: credentials.clientId,
|
|
325
|
+
clientSecret: credentials.clientSecret,
|
|
326
|
+
region: credentials.region,
|
|
327
|
+
authMethod: credentials.authMethod,
|
|
328
|
+
machineId: account.machineId
|
|
329
|
+
});
|
|
330
|
+
if (!result.success || !result.accessToken) {
|
|
331
|
+
return { success: false, error: { message: result.error || 'Token refresh failed' } };
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
success: true,
|
|
335
|
+
data: {
|
|
336
|
+
accessToken: result.accessToken,
|
|
337
|
+
refreshToken: result.refreshToken || credentials.refreshToken,
|
|
338
|
+
expiresIn: result.expiresIn || 3600
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
async function verifyAccountCredentials(credentials) {
|
|
343
|
+
const refresh = await refreshTokenByMethod(credentials);
|
|
344
|
+
if (!refresh.success || !refresh.accessToken) {
|
|
345
|
+
return { success: false, error: `Token refresh failed: ${refresh.error || 'unknown error'}` };
|
|
346
|
+
}
|
|
347
|
+
const profileArn = normalizeProfileArn(credentials.profileArn);
|
|
348
|
+
const usage = await getUsageLimitsRest({
|
|
349
|
+
accessToken: refresh.accessToken,
|
|
350
|
+
profileArn,
|
|
351
|
+
machineId: credentials.machineId,
|
|
352
|
+
region: credentials.region || 'us-east-1'
|
|
353
|
+
});
|
|
354
|
+
const resolvedProfileArn = profileArn || await resolveStreamingProfileArn({
|
|
355
|
+
accessToken: refresh.accessToken,
|
|
356
|
+
machineId: credentials.machineId,
|
|
357
|
+
region: credentials.region || 'us-east-1',
|
|
358
|
+
authMethod: credentials.authMethod,
|
|
359
|
+
provider: credentials.provider
|
|
360
|
+
}).catch(() => undefined);
|
|
361
|
+
return {
|
|
362
|
+
success: true,
|
|
363
|
+
data: {
|
|
364
|
+
...normalizeUsage(usage),
|
|
365
|
+
accessToken: refresh.accessToken,
|
|
366
|
+
refreshToken: refresh.refreshToken || credentials.refreshToken,
|
|
367
|
+
expiresIn: refresh.expiresIn || 3600,
|
|
368
|
+
profileArn: resolvedProfileArn
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
async function checkAccountStatus(account) {
|
|
373
|
+
const credentials = account.credentials || {};
|
|
374
|
+
let accessToken = credentials.accessToken;
|
|
375
|
+
let refreshResult;
|
|
376
|
+
const expiresAt = credentials.expiresAt || 0;
|
|
377
|
+
if ((!accessToken || expiresAt < Date.now() + 300000) && credentials.refreshToken) {
|
|
378
|
+
refreshResult = await refreshAccountToken(account);
|
|
379
|
+
if (!refreshResult.success || !refreshResult.data?.accessToken)
|
|
380
|
+
return refreshResult;
|
|
381
|
+
accessToken = refreshResult.data.accessToken;
|
|
382
|
+
}
|
|
383
|
+
if (!accessToken)
|
|
384
|
+
return { success: false, error: { message: 'Missing access token' } };
|
|
385
|
+
const usage = await getUsageLimitsRest({
|
|
386
|
+
accessToken,
|
|
387
|
+
profileArn: account.profileArn,
|
|
388
|
+
machineId: account.machineId,
|
|
389
|
+
region: credentials.region || 'us-east-1'
|
|
390
|
+
});
|
|
391
|
+
const normalized = normalizeUsage(usage);
|
|
392
|
+
const resolvedProfileArn = await resolveStreamingProfileArn({
|
|
393
|
+
accessToken,
|
|
394
|
+
profileArn: account.profileArn,
|
|
395
|
+
machineId: account.machineId,
|
|
396
|
+
region: credentials.region || 'us-east-1',
|
|
397
|
+
authMethod: credentials.authMethod,
|
|
398
|
+
provider: credentials.provider || account.idp
|
|
399
|
+
}).catch(() => normalizeProfileArn(account.profileArn));
|
|
400
|
+
return {
|
|
401
|
+
success: true,
|
|
402
|
+
data: {
|
|
403
|
+
status: 'active',
|
|
404
|
+
email: normalized.email || account.email,
|
|
405
|
+
userId: normalized.userId,
|
|
406
|
+
idp: credentials.provider || account.idp,
|
|
407
|
+
subscriptionType: normalized.subscriptionType,
|
|
408
|
+
subscriptionTitle: normalized.subscriptionTitle,
|
|
409
|
+
subscription: {
|
|
410
|
+
...normalized.subscription,
|
|
411
|
+
type: normalized.subscriptionType,
|
|
412
|
+
title: normalized.subscriptionTitle,
|
|
413
|
+
daysRemaining: normalized.daysRemaining,
|
|
414
|
+
expiresAt: normalized.expiresAt
|
|
415
|
+
},
|
|
416
|
+
daysRemaining: normalized.daysRemaining,
|
|
417
|
+
expiresAt: normalized.expiresAt,
|
|
418
|
+
profileArn: resolvedProfileArn,
|
|
419
|
+
usage: {
|
|
420
|
+
...normalized.usage,
|
|
421
|
+
percentUsed: normalized.usage.limit ? (normalized.usage.current / normalized.usage.limit) * 100 : 0,
|
|
422
|
+
lastUpdated: Date.now()
|
|
423
|
+
},
|
|
424
|
+
newCredentials: refreshResult?.data ? {
|
|
425
|
+
accessToken: refreshResult.data.accessToken,
|
|
426
|
+
refreshToken: refreshResult.data.refreshToken,
|
|
427
|
+
expiresAt: Date.now() + refreshResult.data.expiresIn * 1000
|
|
428
|
+
} : undefined
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getKiroSettings = getKiroSettings;
|
|
7
|
+
exports.saveKiroSettings = saveKiroSettings;
|
|
8
|
+
exports.ensureKiroSettingsFile = ensureKiroSettingsFile;
|
|
9
|
+
exports.ensureMcpConfig = ensureMcpConfig;
|
|
10
|
+
exports.ensureSteeringFolder = ensureSteeringFolder;
|
|
11
|
+
exports.createDefaultRules = createDefaultRules;
|
|
12
|
+
exports.readSteeringFile = readSteeringFile;
|
|
13
|
+
exports.saveSteeringFile = saveSteeringFile;
|
|
14
|
+
exports.deleteSteeringFile = deleteSteeringFile;
|
|
15
|
+
exports.saveMcpServer = saveMcpServer;
|
|
16
|
+
exports.deleteMcpServer = deleteMcpServer;
|
|
17
|
+
const fs_1 = require("fs");
|
|
18
|
+
const os_1 = __importDefault(require("os"));
|
|
19
|
+
const path_1 = __importDefault(require("path"));
|
|
20
|
+
function kiroRoot() {
|
|
21
|
+
return path_1.default.resolve(process.env.KIRO_CONFIG_HOME || path_1.default.join(os_1.default.homedir(), '.kiro'));
|
|
22
|
+
}
|
|
23
|
+
function settingsPath() {
|
|
24
|
+
if (process.platform === 'win32' && !process.env.KIRO_CONFIG_HOME) {
|
|
25
|
+
return path_1.default.join(os_1.default.homedir(), 'AppData', 'Roaming', 'Kiro', 'User', 'settings.json');
|
|
26
|
+
}
|
|
27
|
+
return path_1.default.join(kiroRoot(), 'settings', 'settings.json');
|
|
28
|
+
}
|
|
29
|
+
function mcpPath(type) {
|
|
30
|
+
return type === 'workspace'
|
|
31
|
+
? path_1.default.join(process.cwd(), '.kiro', 'settings', 'mcp.json')
|
|
32
|
+
: path_1.default.join(kiroRoot(), 'settings', 'mcp.json');
|
|
33
|
+
}
|
|
34
|
+
function steeringDir() {
|
|
35
|
+
return path_1.default.join(kiroRoot(), 'steering');
|
|
36
|
+
}
|
|
37
|
+
function steeringFilePath(filename) {
|
|
38
|
+
const safeName = path_1.default.basename(filename);
|
|
39
|
+
if (!safeName.endsWith('.md'))
|
|
40
|
+
throw new Error('Only markdown steering files are allowed');
|
|
41
|
+
return path_1.default.join(steeringDir(), safeName);
|
|
42
|
+
}
|
|
43
|
+
function parseJsonc(content) {
|
|
44
|
+
const cleaned = content
|
|
45
|
+
.replace(/\/\/.*$/gm, '')
|
|
46
|
+
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
47
|
+
.replace(/,(\s*[}\]])/g, '$1');
|
|
48
|
+
return JSON.parse(cleaned);
|
|
49
|
+
}
|
|
50
|
+
async function readJsonFile(filePath, fallback) {
|
|
51
|
+
try {
|
|
52
|
+
return parseJsonc(await fs_1.promises.readFile(filePath, 'utf8'));
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (error.code === 'ENOENT')
|
|
56
|
+
return fallback;
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function writeJsonFile(filePath, value) {
|
|
61
|
+
await fs_1.promises.mkdir(path_1.default.dirname(filePath), { recursive: true });
|
|
62
|
+
await fs_1.promises.writeFile(filePath, JSON.stringify(value, null, 2), 'utf8');
|
|
63
|
+
}
|
|
64
|
+
function uiSettingsFromKiro(parsed) {
|
|
65
|
+
return {
|
|
66
|
+
modelSelection: parsed['kiroAgent.modelSelection'],
|
|
67
|
+
agentAutonomy: parsed['kiroAgent.agentAutonomy'],
|
|
68
|
+
enableDebugLogs: parsed['kiroAgent.enableDebugLogs'],
|
|
69
|
+
enableTabAutocomplete: parsed['kiroAgent.enableTabAutocomplete'],
|
|
70
|
+
enableCodebaseIndexing: parsed['kiroAgent.enableCodebaseIndexing'],
|
|
71
|
+
usageSummary: parsed['kiroAgent.usageSummary'],
|
|
72
|
+
codeReferences: parsed['kiroAgent.codeReferences.referenceTracker'],
|
|
73
|
+
configureMCP: parsed['kiroAgent.configureMCP'],
|
|
74
|
+
trustedCommands: parsed['kiroAgent.trustedCommands'],
|
|
75
|
+
trustedTools: parsed['kiroAgent.trustedTools'],
|
|
76
|
+
commandDenylist: parsed['kiroAgent.commandDenylist'],
|
|
77
|
+
ignoreFiles: parsed['kiroAgent.ignoreFiles'],
|
|
78
|
+
mcpApprovedEnvVars: parsed['kiroAgent.mcpApprovedEnvVars'],
|
|
79
|
+
notificationsActionRequired: parsed['kiroAgent.notifications.agent.actionRequired'],
|
|
80
|
+
notificationsFailure: parsed['kiroAgent.notifications.agent.failure'],
|
|
81
|
+
notificationsSuccess: parsed['kiroAgent.notifications.agent.success'],
|
|
82
|
+
notificationsBilling: parsed['kiroAgent.notifications.billing']
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function kiroSettingsFromUi(existing, settings) {
|
|
86
|
+
return {
|
|
87
|
+
...existing,
|
|
88
|
+
'kiroAgent.modelSelection': settings.modelSelection,
|
|
89
|
+
'kiroAgent.agentAutonomy': settings.agentAutonomy,
|
|
90
|
+
'kiroAgent.enableDebugLogs': settings.enableDebugLogs,
|
|
91
|
+
'kiroAgent.enableTabAutocomplete': settings.enableTabAutocomplete,
|
|
92
|
+
'kiroAgent.enableCodebaseIndexing': settings.enableCodebaseIndexing,
|
|
93
|
+
'kiroAgent.usageSummary': settings.usageSummary,
|
|
94
|
+
'kiroAgent.codeReferences.referenceTracker': settings.codeReferences,
|
|
95
|
+
'kiroAgent.configureMCP': settings.configureMCP,
|
|
96
|
+
'kiroAgent.trustedCommands': settings.trustedCommands,
|
|
97
|
+
'kiroAgent.trustedTools': settings.trustedTools,
|
|
98
|
+
'kiroAgent.commandDenylist': settings.commandDenylist,
|
|
99
|
+
'kiroAgent.ignoreFiles': settings.ignoreFiles,
|
|
100
|
+
'kiroAgent.mcpApprovedEnvVars': settings.mcpApprovedEnvVars,
|
|
101
|
+
'kiroAgent.notifications.agent.actionRequired': settings.notificationsActionRequired,
|
|
102
|
+
'kiroAgent.notifications.agent.failure': settings.notificationsFailure,
|
|
103
|
+
'kiroAgent.notifications.agent.success': settings.notificationsSuccess,
|
|
104
|
+
'kiroAgent.notifications.billing': settings.notificationsBilling
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
async function getKiroSettings() {
|
|
108
|
+
try {
|
|
109
|
+
const rawSettings = await readJsonFile(settingsPath(), {});
|
|
110
|
+
const mcpConfig = await readJsonFile(mcpPath('user'), { mcpServers: {} });
|
|
111
|
+
let steeringFiles = [];
|
|
112
|
+
try {
|
|
113
|
+
steeringFiles = (await fs_1.promises.readdir(steeringDir())).filter((file) => file.endsWith('.md'));
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error.code !== 'ENOENT')
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
settings: uiSettingsFromKiro(rawSettings),
|
|
121
|
+
mcpConfig,
|
|
122
|
+
steeringFiles,
|
|
123
|
+
paths: {
|
|
124
|
+
root: kiroRoot(),
|
|
125
|
+
settings: settingsPath(),
|
|
126
|
+
mcp: mcpPath('user'),
|
|
127
|
+
steering: steeringDir()
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
return { error: error instanceof Error ? error.message : 'Failed to get Kiro settings' };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function saveKiroSettings(settings) {
|
|
136
|
+
try {
|
|
137
|
+
const existing = await readJsonFile(settingsPath(), {});
|
|
138
|
+
await writeJsonFile(settingsPath(), kiroSettingsFromUi(existing, settings));
|
|
139
|
+
return { success: true };
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to save Kiro settings' };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async function ensureKiroSettingsFile() {
|
|
146
|
+
try {
|
|
147
|
+
const filePath = settingsPath();
|
|
148
|
+
try {
|
|
149
|
+
await fs_1.promises.access(filePath);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
await writeJsonFile(filePath, {
|
|
153
|
+
'workbench.colorTheme': 'Kiro Light',
|
|
154
|
+
'kiroAgent.modelSelection': 'claude-haiku-4.5'
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return { success: true, path: filePath };
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to create settings file' };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
async function ensureMcpConfig(type) {
|
|
164
|
+
try {
|
|
165
|
+
const filePath = mcpPath(type);
|
|
166
|
+
try {
|
|
167
|
+
await fs_1.promises.access(filePath);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
await writeJsonFile(filePath, { mcpServers: {} });
|
|
171
|
+
}
|
|
172
|
+
return { success: true, path: filePath };
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to create MCP config' };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async function ensureSteeringFolder() {
|
|
179
|
+
try {
|
|
180
|
+
await fs_1.promises.mkdir(steeringDir(), { recursive: true });
|
|
181
|
+
return { success: true, path: steeringDir() };
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to create steering folder' };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async function createDefaultRules() {
|
|
188
|
+
try {
|
|
189
|
+
await fs_1.promises.mkdir(steeringDir(), { recursive: true });
|
|
190
|
+
const filePath = steeringFilePath('rules.md');
|
|
191
|
+
const content = [
|
|
192
|
+
'# Kiro Rules',
|
|
193
|
+
'',
|
|
194
|
+
'- Keep code modular and maintainable.',
|
|
195
|
+
'- Prefer clear, testable changes.',
|
|
196
|
+
'- Surface uncertainty instead of guessing.'
|
|
197
|
+
].join('\n');
|
|
198
|
+
await fs_1.promises.writeFile(filePath, content, 'utf8');
|
|
199
|
+
return { success: true, path: filePath };
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to create default rules' };
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async function readSteeringFile(filename) {
|
|
206
|
+
try {
|
|
207
|
+
return { success: true, content: await fs_1.promises.readFile(steeringFilePath(filename), 'utf8') };
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to read steering file' };
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function saveSteeringFile(filename, content) {
|
|
214
|
+
try {
|
|
215
|
+
await fs_1.promises.mkdir(steeringDir(), { recursive: true });
|
|
216
|
+
await fs_1.promises.writeFile(steeringFilePath(filename), content, 'utf8');
|
|
217
|
+
return { success: true };
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to save steering file' };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
async function deleteSteeringFile(filename) {
|
|
224
|
+
try {
|
|
225
|
+
await fs_1.promises.unlink(steeringFilePath(filename));
|
|
226
|
+
return { success: true };
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to delete steering file' };
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function saveMcpServer(name, config, oldName) {
|
|
233
|
+
try {
|
|
234
|
+
const filePath = mcpPath('user');
|
|
235
|
+
const current = await readJsonFile(filePath, { mcpServers: {} });
|
|
236
|
+
current.mcpServers = current.mcpServers || {};
|
|
237
|
+
if (oldName && oldName !== name)
|
|
238
|
+
delete current.mcpServers[oldName];
|
|
239
|
+
current.mcpServers[name] = config;
|
|
240
|
+
await writeJsonFile(filePath, current);
|
|
241
|
+
return { success: true };
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to save MCP server' };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
async function deleteMcpServer(name) {
|
|
248
|
+
try {
|
|
249
|
+
const filePath = mcpPath('user');
|
|
250
|
+
const current = await readJsonFile(filePath, { mcpServers: {} });
|
|
251
|
+
if (!current.mcpServers?.[name])
|
|
252
|
+
return { success: false, error: 'MCP server not found' };
|
|
253
|
+
delete current.mcpServers[name];
|
|
254
|
+
await writeJsonFile(filePath, current);
|
|
255
|
+
return { success: true };
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
return { success: false, error: error instanceof Error ? error.message : 'Failed to delete MCP server' };
|
|
259
|
+
}
|
|
260
|
+
}
|