@zhafron/opencode-kiro-auth 1.0.0 → 1.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.
- package/README.md +1 -1
- package/dist/constants.js +7 -1
- package/dist/kiro/oauth-idc.js +4 -1
- package/dist/plugin/accounts.js +11 -2
- package/dist/plugin/auth-page.js +6 -1
- package/dist/plugin/config/loader.js +3 -1
- package/dist/plugin/logger.js +3 -5
- package/dist/plugin/request.js +148 -28
- package/dist/plugin/response.js +9 -2
- package/dist/plugin/server.js +16 -3
- package/dist/plugin/streaming.js +9 -2
- package/dist/plugin/types.d.ts +1 -1
- package/dist/plugin/usage.js +11 -2
- package/dist/plugin.js +30 -6
- package/package.json +2 -2
- package/dist/kiro/oauth-social.d.ts +0 -17
- package/dist/kiro/oauth-social.js +0 -51
- package/dist/plugin/cli.d.ts +0 -6
- package/dist/plugin/cli.js +0 -98
- package/dist/plugin/debug.d.ts +0 -2
- package/dist/plugin/debug.js +0 -9
- package/dist/plugin/oauth-parser.d.ts +0 -5
- package/dist/plugin/oauth-parser.js +0 -23
- package/dist/plugin/quota.d.ts +0 -15
- package/dist/plugin/quota.js +0 -68
- package/dist/plugin/recovery.d.ts +0 -19
- package/dist/plugin/recovery.js +0 -302
- package/dist/plugin/refresh-queue.d.ts +0 -14
- package/dist/plugin/refresh-queue.js +0 -69
- package/dist/src/constants.d.ts +0 -22
- package/dist/src/constants.js +0 -35
- package/dist/src/kiro/auth.d.ts +0 -5
- package/dist/src/kiro/auth.js +0 -69
- package/dist/src/kiro/oauth-idc.d.ts +0 -22
- package/dist/src/kiro/oauth-idc.js +0 -99
- package/dist/src/kiro/oauth-social.d.ts +0 -17
- package/dist/src/kiro/oauth-social.js +0 -69
- package/dist/src/plugin/accounts.d.ts +0 -23
- package/dist/src/plugin/accounts.js +0 -265
- package/dist/src/plugin/cli.d.ts +0 -6
- package/dist/src/plugin/cli.js +0 -98
- package/dist/src/plugin/config/index.d.ts +0 -3
- package/dist/src/plugin/config/index.js +0 -2
- package/dist/src/plugin/config/loader.d.ts +0 -7
- package/dist/src/plugin/config/loader.js +0 -143
- package/dist/src/plugin/config/schema.d.ts +0 -68
- package/dist/src/plugin/config/schema.js +0 -44
- package/dist/src/plugin/debug.d.ts +0 -2
- package/dist/src/plugin/debug.js +0 -9
- package/dist/src/plugin/errors.d.ts +0 -17
- package/dist/src/plugin/errors.js +0 -34
- package/dist/src/plugin/logger.d.ts +0 -4
- package/dist/src/plugin/logger.js +0 -17
- package/dist/src/plugin/models.d.ts +0 -3
- package/dist/src/plugin/models.js +0 -14
- package/dist/src/plugin/oauth-parser.d.ts +0 -5
- package/dist/src/plugin/oauth-parser.js +0 -23
- package/dist/src/plugin/quota.d.ts +0 -25
- package/dist/src/plugin/quota.js +0 -175
- package/dist/src/plugin/recovery.d.ts +0 -19
- package/dist/src/plugin/recovery.js +0 -302
- package/dist/src/plugin/refresh-queue.d.ts +0 -14
- package/dist/src/plugin/refresh-queue.js +0 -69
- package/dist/src/plugin/request.d.ts +0 -35
- package/dist/src/plugin/request.js +0 -411
- package/dist/src/plugin/response.d.ts +0 -6
- package/dist/src/plugin/response.js +0 -246
- package/dist/src/plugin/server.d.ts +0 -10
- package/dist/src/plugin/server.js +0 -203
- package/dist/src/plugin/storage.d.ts +0 -5
- package/dist/src/plugin/storage.js +0 -106
- package/dist/src/plugin/streaming.d.ts +0 -12
- package/dist/src/plugin/streaming.js +0 -444
- package/dist/src/plugin/token.d.ts +0 -8
- package/dist/src/plugin/token.js +0 -130
- package/dist/src/plugin/types.d.ts +0 -144
- package/dist/src/plugin/types.js +0 -0
- package/dist/src/plugin/usage.d.ts +0 -28
- package/dist/src/plugin/usage.js +0 -159
- package/dist/src/plugin.d.ts +0 -2
- package/dist/src/plugin.js +0 -341
package/README.md
CHANGED
package/dist/constants.js
CHANGED
|
@@ -56,5 +56,11 @@ export const KIRO_AUTH_SERVICE = {
|
|
|
56
56
|
ENDPOINT: 'https://prod.{{region}}.auth.desktop.kiro.dev',
|
|
57
57
|
SSO_OIDC_ENDPOINT: 'https://oidc.{{region}}.amazonaws.com',
|
|
58
58
|
BUILDER_ID_START_URL: 'https://view.awsapps.com/start',
|
|
59
|
-
SCOPES: [
|
|
59
|
+
SCOPES: [
|
|
60
|
+
'codewhisperer:completions',
|
|
61
|
+
'codewhisperer:analysis',
|
|
62
|
+
'codewhisperer:conversations',
|
|
63
|
+
'codewhisperer:transformations',
|
|
64
|
+
'codewhisperer:taskassist'
|
|
65
|
+
]
|
|
60
66
|
};
|
package/dist/kiro/oauth-idc.js
CHANGED
|
@@ -120,7 +120,10 @@ export async function pollKiroIDCToken(clientId, clientSecret, deviceCode, inter
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
catch (error) {
|
|
123
|
-
if (error instanceof Error &&
|
|
123
|
+
if (error instanceof Error &&
|
|
124
|
+
(error.message.includes('expired') ||
|
|
125
|
+
error.message.includes('denied') ||
|
|
126
|
+
error.message.includes('failed'))) {
|
|
124
127
|
throw error;
|
|
125
128
|
}
|
|
126
129
|
if (attempts >= maxAttempts) {
|
package/dist/plugin/accounts.js
CHANGED
|
@@ -28,7 +28,10 @@ export class AccountManager {
|
|
|
28
28
|
static async loadFromDisk(strategy) {
|
|
29
29
|
const s = await loadAccounts();
|
|
30
30
|
const u = await loadUsage();
|
|
31
|
-
const accounts = s.accounts.map((m) => ({
|
|
31
|
+
const accounts = s.accounts.map((m) => ({
|
|
32
|
+
...m,
|
|
33
|
+
region: m.region || KIRO_CONSTANTS.DEFAULT_REGION
|
|
34
|
+
}));
|
|
32
35
|
return new AccountManager(accounts, u.usage, strategy || 'sticky');
|
|
33
36
|
}
|
|
34
37
|
getAccountCount() {
|
|
@@ -140,7 +143,13 @@ export class AccountManager {
|
|
|
140
143
|
await saveUsage({ version: 1, usage: this.usage });
|
|
141
144
|
}
|
|
142
145
|
toAuthDetails(a) {
|
|
143
|
-
const p = {
|
|
146
|
+
const p = {
|
|
147
|
+
refreshToken: a.refreshToken,
|
|
148
|
+
profileArn: a.profileArn,
|
|
149
|
+
clientId: a.clientId,
|
|
150
|
+
clientSecret: a.clientSecret,
|
|
151
|
+
authMethod: a.authMethod
|
|
152
|
+
};
|
|
144
153
|
return {
|
|
145
154
|
refresh: encodeRefreshToken(p),
|
|
146
155
|
access: a.accessToken,
|
package/dist/plugin/auth-page.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
function escapeHtml(text) {
|
|
2
|
-
return text
|
|
2
|
+
return text
|
|
3
|
+
.replace(/&/g, '&')
|
|
4
|
+
.replace(/</g, '<')
|
|
5
|
+
.replace(/>/g, '>')
|
|
6
|
+
.replace(/"/g, '"')
|
|
7
|
+
.replace(/'/g, ''');
|
|
3
8
|
}
|
|
4
9
|
export function getIDCAuthHtml(verificationUrl, userCode, statusUrl) {
|
|
5
10
|
const escapedUrl = escapeHtml(verificationUrl);
|
|
@@ -95,7 +95,9 @@ function applyEnvOverrides(config) {
|
|
|
95
95
|
account_selection_strategy: env.KIRO_ACCOUNT_SELECTION_STRATEGY
|
|
96
96
|
? AccountSelectionStrategySchema.catch('lowest-usage').parse(env.KIRO_ACCOUNT_SELECTION_STRATEGY)
|
|
97
97
|
: config.account_selection_strategy,
|
|
98
|
-
default_region: env.KIRO_DEFAULT_REGION
|
|
98
|
+
default_region: env.KIRO_DEFAULT_REGION
|
|
99
|
+
? RegionSchema.catch('us-east-1').parse(env.KIRO_DEFAULT_REGION)
|
|
100
|
+
: config.default_region,
|
|
99
101
|
rate_limit_retry_delay_ms: parseNumberEnv(env.KIRO_RATE_LIMIT_RETRY_DELAY_MS, config.rate_limit_retry_delay_ms),
|
|
100
102
|
rate_limit_max_retries: parseNumberEnv(env.KIRO_RATE_LIMIT_MAX_RETRIES, config.rate_limit_max_retries),
|
|
101
103
|
usage_tracking_enabled: parseBooleanEnv(env.KIRO_USAGE_TRACKING_ENABLED, config.usage_tracking_enabled)
|
package/dist/plugin/logger.js
CHANGED
|
@@ -3,7 +3,9 @@ import { homedir } from 'node:os';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
const getLogDir = () => {
|
|
5
5
|
const platform = process.platform;
|
|
6
|
-
const base = platform === 'win32'
|
|
6
|
+
const base = platform === 'win32'
|
|
7
|
+
? join(process.env.APPDATA || join(homedir(), 'AppData', 'Roaming'), 'opencode')
|
|
8
|
+
: join(process.env.XDG_CONFIG_HOME || join(homedir(), '.config'), 'opencode');
|
|
7
9
|
return join(base, 'kiro-logs');
|
|
8
10
|
};
|
|
9
11
|
const writeToFile = (level, message, ...args) => {
|
|
@@ -18,20 +20,16 @@ const writeToFile = (level, message, ...args) => {
|
|
|
18
20
|
catch (e) { }
|
|
19
21
|
};
|
|
20
22
|
export function log(message, ...args) {
|
|
21
|
-
console.log(`[${new Date().toISOString()}] ${message}`, ...args);
|
|
22
23
|
writeToFile('INFO', message, ...args);
|
|
23
24
|
}
|
|
24
25
|
export function error(message, ...args) {
|
|
25
|
-
console.error(`[${new Date().toISOString()}] ERROR: ${message}`, ...args);
|
|
26
26
|
writeToFile('ERROR', message, ...args);
|
|
27
27
|
}
|
|
28
28
|
export function warn(message, ...args) {
|
|
29
|
-
console.warn(`[${new Date().toISOString()}] WARN: ${message}`, ...args);
|
|
30
29
|
writeToFile('WARN', message, ...args);
|
|
31
30
|
}
|
|
32
31
|
export function debug(message, ...args) {
|
|
33
32
|
if (process.env.DEBUG) {
|
|
34
|
-
console.debug(`[${new Date().toISOString()}] DEBUG: ${message}`, ...args);
|
|
35
33
|
writeToFile('DEBUG', message, ...args);
|
|
36
34
|
}
|
|
37
35
|
}
|
package/dist/plugin/request.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as crypto from 'crypto';
|
|
2
2
|
import * as os from 'os';
|
|
3
|
-
import { KIRO_CONSTANTS } from '../constants';
|
|
4
|
-
import { resolveKiroModel } from './models';
|
|
3
|
+
import { KIRO_CONSTANTS } from '../constants.js';
|
|
4
|
+
import { resolveKiroModel } from './models.js';
|
|
5
5
|
export function transformToCodeWhisperer(url, body, model, auth, think = false, budget = 20000) {
|
|
6
6
|
const req = typeof body === 'string' ? JSON.parse(body) : body;
|
|
7
|
-
const { messages, tools, system } = req;
|
|
7
|
+
const { messages, tools, system, conversationId } = req;
|
|
8
|
+
const convId = crypto.randomUUID();
|
|
8
9
|
if (!messages || messages.length === 0)
|
|
9
10
|
throw new Error('No messages');
|
|
10
11
|
const resolved = resolveKiroModel(model);
|
|
11
|
-
const convId = crypto.randomUUID();
|
|
12
12
|
let sys = system || '';
|
|
13
13
|
if (think) {
|
|
14
14
|
const pfx = `<thinking_mode>enabled</thinking_mode><max_thinking_length>${budget}</max_thinking_length>`;
|
|
@@ -20,17 +20,38 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
20
20
|
msgs.pop();
|
|
21
21
|
const cwTools = tools ? convertToolsToCodeWhisperer(tools) : [];
|
|
22
22
|
const history = [];
|
|
23
|
-
let
|
|
23
|
+
let firstUserIndex = -1;
|
|
24
|
+
for (let i = 0; i < msgs.length; i++) {
|
|
25
|
+
if (msgs[i].role === 'user') {
|
|
26
|
+
firstUserIndex = i;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
24
30
|
if (sys) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
if (firstUserIndex !== -1) {
|
|
32
|
+
const m = msgs[firstUserIndex];
|
|
33
|
+
const oldContent = getContentText(m);
|
|
34
|
+
if (Array.isArray(m.content)) {
|
|
35
|
+
m.content = [
|
|
36
|
+
{ type: 'text', text: `${sys}\n\n${oldContent}` },
|
|
37
|
+
...m.content.filter((p) => p.type !== 'text')
|
|
38
|
+
];
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
m.content = `${sys}\n\n${oldContent}`;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
history.push({
|
|
46
|
+
userInputMessage: {
|
|
47
|
+
content: sys,
|
|
48
|
+
modelId: resolved,
|
|
49
|
+
origin: KIRO_CONSTANTS.ORIGIN_AI_EDITOR
|
|
50
|
+
}
|
|
51
|
+
});
|
|
29
52
|
}
|
|
30
|
-
else
|
|
31
|
-
history.push({ userInputMessage: { content: sys, modelId: resolved, origin: KIRO_CONSTANTS.ORIGIN_AI_EDITOR } });
|
|
32
53
|
}
|
|
33
|
-
for (let i =
|
|
54
|
+
for (let i = 0; i < msgs.length - 1; i++) {
|
|
34
55
|
const m = msgs[i];
|
|
35
56
|
if (!m)
|
|
36
57
|
continue;
|
|
@@ -42,9 +63,16 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
42
63
|
if (p.type === 'text')
|
|
43
64
|
uim.content += p.text || '';
|
|
44
65
|
else if (p.type === 'tool_result')
|
|
45
|
-
trs.push({
|
|
66
|
+
trs.push({
|
|
67
|
+
content: [{ text: getContentText(p.content || p) }],
|
|
68
|
+
status: 'success',
|
|
69
|
+
toolUseId: p.tool_use_id
|
|
70
|
+
});
|
|
46
71
|
else if (p.type === 'image' && p.source)
|
|
47
|
-
imgs.push({
|
|
72
|
+
imgs.push({
|
|
73
|
+
format: p.source.media_type?.split('/')[1] || 'png',
|
|
74
|
+
source: { bytes: p.source.data }
|
|
75
|
+
});
|
|
48
76
|
}
|
|
49
77
|
}
|
|
50
78
|
else
|
|
@@ -53,11 +81,34 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
53
81
|
uim.images = imgs;
|
|
54
82
|
if (trs.length)
|
|
55
83
|
uim.userInputMessageContext = { toolResults: deduplicateToolResults(trs) };
|
|
56
|
-
const prev = history[history.length - 1];
|
|
57
|
-
if (prev && prev.userInputMessage)
|
|
58
|
-
history.push({ assistantResponseMessage: { content: 'Continue' } });
|
|
59
84
|
history.push({ userInputMessage: uim });
|
|
60
85
|
}
|
|
86
|
+
else if (m.role === 'tool') {
|
|
87
|
+
const trs = [];
|
|
88
|
+
if (m.tool_results) {
|
|
89
|
+
for (const tr of m.tool_results)
|
|
90
|
+
trs.push({
|
|
91
|
+
content: [{ text: getContentText(tr) }],
|
|
92
|
+
status: 'success',
|
|
93
|
+
toolUseId: tr.tool_call_id
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
trs.push({
|
|
98
|
+
content: [{ text: getContentText(m) }],
|
|
99
|
+
status: 'success',
|
|
100
|
+
toolUseId: m.tool_call_id
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
history.push({
|
|
104
|
+
userInputMessage: {
|
|
105
|
+
content: 'Tool results provided.',
|
|
106
|
+
modelId: resolved,
|
|
107
|
+
origin: KIRO_CONSTANTS.ORIGIN_AI_EDITOR,
|
|
108
|
+
userInputMessageContext: { toolResults: deduplicateToolResults(trs) }
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
61
112
|
else if (m.role === 'assistant') {
|
|
62
113
|
const arm = { content: '' };
|
|
63
114
|
const tus = [];
|
|
@@ -72,15 +123,26 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
72
123
|
tus.push({ input: p.input, name: p.name, toolUseId: p.id });
|
|
73
124
|
}
|
|
74
125
|
}
|
|
75
|
-
else
|
|
126
|
+
else {
|
|
76
127
|
arm.content = getContentText(m);
|
|
128
|
+
}
|
|
129
|
+
if (m.tool_calls && Array.isArray(m.tool_calls)) {
|
|
130
|
+
for (const tc of m.tool_calls) {
|
|
131
|
+
tus.push({
|
|
132
|
+
input: typeof tc.function?.arguments === 'string'
|
|
133
|
+
? JSON.parse(tc.function.arguments)
|
|
134
|
+
: tc.function?.arguments,
|
|
135
|
+
name: tc.function?.name,
|
|
136
|
+
toolUseId: tc.id
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
77
140
|
if (th)
|
|
78
|
-
arm.content = arm.content
|
|
141
|
+
arm.content = arm.content
|
|
142
|
+
? `<thinking>${th}</thinking>\n\n${arm.content}`
|
|
143
|
+
: `<thinking>${th}</thinking>`;
|
|
79
144
|
if (tus.length)
|
|
80
145
|
arm.toolUses = tus;
|
|
81
|
-
const prev = history[history.length - 1];
|
|
82
|
-
if (prev && prev.assistantResponseMessage)
|
|
83
|
-
history.push({ userInputMessage: { content: 'Continue', modelId: resolved, origin: KIRO_CONSTANTS.ORIGIN_AI_EDITOR } });
|
|
84
146
|
history.push({ assistantResponseMessage: arm });
|
|
85
147
|
}
|
|
86
148
|
}
|
|
@@ -107,8 +169,23 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
107
169
|
}
|
|
108
170
|
else
|
|
109
171
|
arm.content = getContentText(curMsg);
|
|
172
|
+
if (curMsg.tool_calls && Array.isArray(curMsg.tool_calls)) {
|
|
173
|
+
if (!arm.toolUses)
|
|
174
|
+
arm.toolUses = [];
|
|
175
|
+
for (const tc of curMsg.tool_calls) {
|
|
176
|
+
arm.toolUses.push({
|
|
177
|
+
input: typeof tc.function?.arguments === 'string'
|
|
178
|
+
? JSON.parse(tc.function.arguments)
|
|
179
|
+
: tc.function?.arguments,
|
|
180
|
+
name: tc.function?.name,
|
|
181
|
+
toolUseId: tc.id
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
110
185
|
if (th)
|
|
111
|
-
arm.content = arm.content
|
|
186
|
+
arm.content = arm.content
|
|
187
|
+
? `<thinking>${th}</thinking>\n\n${arm.content}`
|
|
188
|
+
: `<thinking>${th}</thinking>`;
|
|
112
189
|
history.push({ assistantResponseMessage: arm });
|
|
113
190
|
curContent = 'Continue';
|
|
114
191
|
}
|
|
@@ -116,14 +193,38 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
116
193
|
const prev = history[history.length - 1];
|
|
117
194
|
if (prev && !prev.assistantResponseMessage)
|
|
118
195
|
history.push({ assistantResponseMessage: { content: 'Continue' } });
|
|
119
|
-
if (
|
|
196
|
+
if (curMsg.role === 'tool') {
|
|
197
|
+
if (curMsg.tool_results) {
|
|
198
|
+
for (const tr of curMsg.tool_results)
|
|
199
|
+
curTrs.push({
|
|
200
|
+
content: [{ text: getContentText(tr) }],
|
|
201
|
+
status: 'success',
|
|
202
|
+
toolUseId: tr.tool_call_id
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
curTrs.push({
|
|
207
|
+
content: [{ text: getContentText(curMsg) }],
|
|
208
|
+
status: 'success',
|
|
209
|
+
toolUseId: curMsg.tool_call_id
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else if (Array.isArray(curMsg.content)) {
|
|
120
214
|
for (const p of curMsg.content) {
|
|
121
215
|
if (p.type === 'text')
|
|
122
216
|
curContent += p.text || '';
|
|
123
217
|
else if (p.type === 'tool_result')
|
|
124
|
-
curTrs.push({
|
|
218
|
+
curTrs.push({
|
|
219
|
+
content: [{ text: getContentText(p.content || p) }],
|
|
220
|
+
status: 'success',
|
|
221
|
+
toolUseId: p.tool_use_id
|
|
222
|
+
});
|
|
125
223
|
else if (p.type === 'image' && p.source)
|
|
126
|
-
curImgs.push({
|
|
224
|
+
curImgs.push({
|
|
225
|
+
format: p.source.media_type?.split('/')[1] || 'png',
|
|
226
|
+
source: { bytes: p.source.data }
|
|
227
|
+
});
|
|
127
228
|
}
|
|
128
229
|
}
|
|
129
230
|
else
|
|
@@ -135,10 +236,19 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
135
236
|
conversationState: {
|
|
136
237
|
chatTriggerType: KIRO_CONSTANTS.CHAT_TRIGGER_TYPE_MANUAL,
|
|
137
238
|
conversationId: convId,
|
|
138
|
-
|
|
139
|
-
|
|
239
|
+
currentMessage: {
|
|
240
|
+
userInputMessage: {
|
|
241
|
+
content: curContent,
|
|
242
|
+
modelId: resolved,
|
|
243
|
+
origin: KIRO_CONSTANTS.ORIGIN_AI_EDITOR
|
|
244
|
+
}
|
|
245
|
+
}
|
|
140
246
|
}
|
|
141
247
|
};
|
|
248
|
+
if (history.length > 0) {
|
|
249
|
+
;
|
|
250
|
+
request.conversationState.history = history;
|
|
251
|
+
}
|
|
142
252
|
const uim = request.conversationState.currentMessage.userInputMessage;
|
|
143
253
|
if (uim) {
|
|
144
254
|
if (curImgs.length)
|
|
@@ -196,6 +306,16 @@ export function mergeAdjacentMessages(msgs) {
|
|
|
196
306
|
last.content.push({ type: 'text', text: m.content });
|
|
197
307
|
else if (typeof last.content === 'string' && Array.isArray(m.content))
|
|
198
308
|
last.content = [{ type: 'text', text: last.content }, ...m.content];
|
|
309
|
+
if (m.tool_calls) {
|
|
310
|
+
if (!last.tool_calls)
|
|
311
|
+
last.tool_calls = [];
|
|
312
|
+
last.tool_calls.push(...m.tool_calls);
|
|
313
|
+
}
|
|
314
|
+
if (m.role === 'tool') {
|
|
315
|
+
if (!last.tool_results)
|
|
316
|
+
last.tool_results = [{ content: last.content, tool_call_id: last.tool_call_id }];
|
|
317
|
+
last.tool_results.push({ content: m.content, tool_call_id: m.tool_call_id });
|
|
318
|
+
}
|
|
199
319
|
}
|
|
200
320
|
else
|
|
201
321
|
merged.push({ ...m });
|
package/dist/plugin/response.js
CHANGED
|
@@ -76,7 +76,7 @@ function parseEventStreamChunk(rawText) {
|
|
|
76
76
|
};
|
|
77
77
|
});
|
|
78
78
|
if (contextUsagePercentage !== undefined) {
|
|
79
|
-
const totalTokens = Math.round((
|
|
79
|
+
const totalTokens = Math.round((172500 * contextUsagePercentage) / 100);
|
|
80
80
|
outputTokens = estimateTokens(content);
|
|
81
81
|
inputTokens = Math.max(0, totalTokens - outputTokens);
|
|
82
82
|
}
|
|
@@ -99,7 +99,14 @@ function parseAwsEventStreamBuffer(buffer) {
|
|
|
99
99
|
const inputStart = remaining.indexOf('{"input":', searchStart);
|
|
100
100
|
const stopStart = remaining.indexOf('{"stop":', searchStart);
|
|
101
101
|
const contextUsageStart = remaining.indexOf('{"contextUsagePercentage":', searchStart);
|
|
102
|
-
const candidates = [
|
|
102
|
+
const candidates = [
|
|
103
|
+
contentStart,
|
|
104
|
+
nameStart,
|
|
105
|
+
followupStart,
|
|
106
|
+
inputStart,
|
|
107
|
+
stopStart,
|
|
108
|
+
contextUsageStart
|
|
109
|
+
].filter((pos) => pos >= 0);
|
|
103
110
|
if (candidates.length === 0)
|
|
104
111
|
break;
|
|
105
112
|
const jsonStart = Math.min(...candidates);
|
package/dist/plugin/server.js
CHANGED
|
@@ -25,16 +25,29 @@ export function startIDCAuthServer(authData, port = 19847) {
|
|
|
25
25
|
client_id: authData.clientId,
|
|
26
26
|
client_secret: authData.clientSecret
|
|
27
27
|
});
|
|
28
|
-
const res = await fetch(`https://oidc.${authData.region}.amazonaws.com/token`, {
|
|
28
|
+
const res = await fetch(`https://oidc.${authData.region}.amazonaws.com/token`, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
31
|
+
body: body.toString()
|
|
32
|
+
});
|
|
29
33
|
const d = await res.json();
|
|
30
34
|
if (res.ok) {
|
|
31
35
|
const acc = d.access_token, ref = d.refresh_token, exp = Date.now() + d.expires_in * 1000;
|
|
32
|
-
const infoRes = await fetch('https://view.awsapps.com/api/user/info', {
|
|
36
|
+
const infoRes = await fetch('https://view.awsapps.com/api/user/info', {
|
|
37
|
+
headers: { Authorization: `Bearer ${acc}` }
|
|
38
|
+
});
|
|
33
39
|
const info = await infoRes.json();
|
|
34
40
|
const email = info.email || info.userName || 'builder-id@aws.amazon.com';
|
|
35
41
|
status.status = 'success';
|
|
36
42
|
if (resolver)
|
|
37
|
-
resolver({
|
|
43
|
+
resolver({
|
|
44
|
+
email,
|
|
45
|
+
accessToken: acc,
|
|
46
|
+
refreshToken: ref,
|
|
47
|
+
expiresAt: exp,
|
|
48
|
+
clientId: authData.clientId,
|
|
49
|
+
clientSecret: authData.clientSecret
|
|
50
|
+
});
|
|
38
51
|
setTimeout(cleanup, 2000);
|
|
39
52
|
}
|
|
40
53
|
else if (d.error === 'authorization_pending')
|
package/dist/plugin/streaming.js
CHANGED
|
@@ -224,7 +224,7 @@ export async function* transformKiroStream(response, model, conversationId) {
|
|
|
224
224
|
}
|
|
225
225
|
outputTokens = estimateTokens(totalContent);
|
|
226
226
|
if (contextUsagePercentage !== null && contextUsagePercentage > 0) {
|
|
227
|
-
const totalTokens = Math.round((
|
|
227
|
+
const totalTokens = Math.round((172500 * contextUsagePercentage) / 100);
|
|
228
228
|
inputTokens = Math.max(0, totalTokens - outputTokens);
|
|
229
229
|
}
|
|
230
230
|
yield convertToOpenAI({
|
|
@@ -322,7 +322,14 @@ function parseStreamBuffer(buffer) {
|
|
|
322
322
|
const inputStart = remaining.indexOf('{"input":', searchStart);
|
|
323
323
|
const stopStart = remaining.indexOf('{"stop":', searchStart);
|
|
324
324
|
const contextUsageStart = remaining.indexOf('{"contextUsagePercentage":', searchStart);
|
|
325
|
-
const candidates = [
|
|
325
|
+
const candidates = [
|
|
326
|
+
contentStart,
|
|
327
|
+
nameStart,
|
|
328
|
+
followupStart,
|
|
329
|
+
inputStart,
|
|
330
|
+
stopStart,
|
|
331
|
+
contextUsageStart
|
|
332
|
+
].filter((pos) => pos >= 0);
|
|
326
333
|
if (candidates.length === 0)
|
|
327
334
|
break;
|
|
328
335
|
const jsonStart = Math.min(...candidates);
|
package/dist/plugin/types.d.ts
CHANGED
|
@@ -113,7 +113,7 @@ export interface CodeWhispererRequest {
|
|
|
113
113
|
conversationState: {
|
|
114
114
|
chatTriggerType: string;
|
|
115
115
|
conversationId: string;
|
|
116
|
-
history
|
|
116
|
+
history?: CodeWhispererMessage[];
|
|
117
117
|
currentMessage: CodeWhispererMessage;
|
|
118
118
|
};
|
|
119
119
|
profileArn?: string;
|
package/dist/plugin/usage.js
CHANGED
|
@@ -3,7 +3,12 @@ export async function fetchUsageLimits(auth) {
|
|
|
3
3
|
try {
|
|
4
4
|
const res = await fetch(url, {
|
|
5
5
|
method: 'GET',
|
|
6
|
-
headers: {
|
|
6
|
+
headers: {
|
|
7
|
+
Authorization: `Bearer ${auth.access}`,
|
|
8
|
+
'Content-Type': 'application/json',
|
|
9
|
+
'x-amzn-kiro-agent-mode': 'vibe',
|
|
10
|
+
'amz-sdk-request': 'attempt=1; max=1'
|
|
11
|
+
}
|
|
7
12
|
});
|
|
8
13
|
if (!res.ok)
|
|
9
14
|
throw new Error(`Status: ${res.status}`);
|
|
@@ -26,7 +31,11 @@ export async function fetchUsageLimits(auth) {
|
|
|
26
31
|
}
|
|
27
32
|
}
|
|
28
33
|
export function updateAccountQuota(account, usage, accountManager) {
|
|
29
|
-
const meta = {
|
|
34
|
+
const meta = {
|
|
35
|
+
usedCount: usage.usedCount || 0,
|
|
36
|
+
limitCount: usage.limitCount || 0,
|
|
37
|
+
realEmail: usage.email
|
|
38
|
+
};
|
|
30
39
|
account.usedCount = meta.usedCount;
|
|
31
40
|
account.limitCount = meta.limitCount;
|
|
32
41
|
if (meta.realEmail)
|
package/dist/plugin.js
CHANGED
|
@@ -104,16 +104,31 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
|
|
|
104
104
|
object: 'chat.completion',
|
|
105
105
|
created: Math.floor(Date.now() / 1000),
|
|
106
106
|
model,
|
|
107
|
-
choices: [
|
|
108
|
-
|
|
107
|
+
choices: [
|
|
108
|
+
{
|
|
109
|
+
index: 0,
|
|
110
|
+
message: { role: 'assistant', content: p.content },
|
|
111
|
+
finish_reason: p.stopReason === 'tool_use' ? 'tool_calls' : 'stop'
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
usage: {
|
|
115
|
+
prompt_tokens: p.inputTokens || 0,
|
|
116
|
+
completion_tokens: p.outputTokens || 0,
|
|
117
|
+
total_tokens: (p.inputTokens || 0) + (p.outputTokens || 0)
|
|
118
|
+
}
|
|
109
119
|
};
|
|
110
120
|
if (p.toolCalls.length > 0)
|
|
111
121
|
oai.choices[0].message.tool_calls = p.toolCalls.map((tc) => ({
|
|
112
122
|
id: tc.toolUseId,
|
|
113
123
|
type: 'function',
|
|
114
|
-
function: {
|
|
124
|
+
function: {
|
|
125
|
+
name: tc.name,
|
|
126
|
+
arguments: typeof tc.input === 'string' ? tc.input : JSON.stringify(tc.input)
|
|
127
|
+
}
|
|
115
128
|
}));
|
|
116
|
-
return new Response(JSON.stringify(oai), {
|
|
129
|
+
return new Response(JSON.stringify(oai), {
|
|
130
|
+
headers: { 'Content-Type': 'application/json' }
|
|
131
|
+
});
|
|
117
132
|
}
|
|
118
133
|
if (res.status === 401 && retry < config.rate_limit_max_retries) {
|
|
119
134
|
logger.warn(`Unauthorized (401) on ${acc.email}, retrying...`);
|
|
@@ -188,7 +203,12 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
|
|
|
188
203
|
};
|
|
189
204
|
try {
|
|
190
205
|
const u = await fetchUsageLimits({
|
|
191
|
-
refresh: encodeRefreshToken({
|
|
206
|
+
refresh: encodeRefreshToken({
|
|
207
|
+
refreshToken: res.refreshToken,
|
|
208
|
+
clientId: res.clientId,
|
|
209
|
+
clientSecret: res.clientSecret,
|
|
210
|
+
authMethod: 'idc'
|
|
211
|
+
}),
|
|
192
212
|
access: res.accessToken,
|
|
193
213
|
expires: res.expiresAt,
|
|
194
214
|
authMethod: 'idc',
|
|
@@ -197,7 +217,11 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
|
|
|
197
217
|
clientSecret: res.clientSecret,
|
|
198
218
|
email: res.email
|
|
199
219
|
});
|
|
200
|
-
am.updateUsage(acc.id, {
|
|
220
|
+
am.updateUsage(acc.id, {
|
|
221
|
+
usedCount: u.usedCount,
|
|
222
|
+
limitCount: u.limitCount,
|
|
223
|
+
realEmail: u.email
|
|
224
|
+
});
|
|
201
225
|
}
|
|
202
226
|
catch (e) {
|
|
203
227
|
logger.warn(`Initial usage fetch failed: ${e.message}`);
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhafron/opencode-kiro-auth",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "OpenCode plugin for AWS Kiro (CodeWhisperer) providing access to Claude models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "tsc -p tsconfig.build.json",
|
|
10
|
-
"format": "prettier --write --no-config --no-semi --single-quote --trailing-comma none --print-width
|
|
10
|
+
"format": "prettier --write --no-config --no-semi --single-quote --trailing-comma none --print-width 100 'src/**/*.ts'",
|
|
11
11
|
"typecheck": "tsc --noEmit"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { KiroRegion } from '../plugin/types';
|
|
2
|
-
export interface KiroSocialAuthorization {
|
|
3
|
-
url: string;
|
|
4
|
-
verifier: string;
|
|
5
|
-
region: KiroRegion;
|
|
6
|
-
}
|
|
7
|
-
export interface KiroSocialTokenResult {
|
|
8
|
-
refreshToken: string;
|
|
9
|
-
accessToken: string;
|
|
10
|
-
expiresAt: number;
|
|
11
|
-
email: string;
|
|
12
|
-
profileArn: string;
|
|
13
|
-
region: KiroRegion;
|
|
14
|
-
authMethod: 'social';
|
|
15
|
-
}
|
|
16
|
-
export declare function authorizeKiroSocial(port: number, state: string, challenge: string, region?: KiroRegion): Promise<string>;
|
|
17
|
-
export declare function exchangeKiroSocial(code: string, verifier: string, region: KiroRegion, port: number): Promise<KiroSocialTokenResult>;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { KIRO_AUTH_SERVICE, KIRO_CONSTANTS } from '../constants';
|
|
2
|
-
export async function authorizeKiroSocial(port, state, challenge, region) {
|
|
3
|
-
const effectiveRegion = region || KIRO_CONSTANTS.DEFAULT_REGION;
|
|
4
|
-
const authServiceEndpoint = KIRO_AUTH_SERVICE.ENDPOINT.replace('{{region}}', effectiveRegion);
|
|
5
|
-
const redirectUri = `http://127.0.0.1:${port}/oauth/callback`;
|
|
6
|
-
const params = new URLSearchParams({
|
|
7
|
-
idp: 'Google',
|
|
8
|
-
redirect_uri: redirectUri,
|
|
9
|
-
code_challenge: challenge,
|
|
10
|
-
code_challenge_method: 'S256',
|
|
11
|
-
state: state,
|
|
12
|
-
prompt: 'select_account',
|
|
13
|
-
});
|
|
14
|
-
return `${authServiceEndpoint}/login?${params.toString()}`;
|
|
15
|
-
}
|
|
16
|
-
export async function exchangeKiroSocial(code, verifier, region, port) {
|
|
17
|
-
const authServiceEndpoint = KIRO_AUTH_SERVICE.ENDPOINT.replace('{{region}}', region);
|
|
18
|
-
const redirectUri = `http://127.0.0.1:${port}/oauth/callback`;
|
|
19
|
-
const tokenResponse = await fetch(`${authServiceEndpoint}/oauth/token`, {
|
|
20
|
-
method: 'POST',
|
|
21
|
-
headers: {
|
|
22
|
-
'Content-Type': 'application/json',
|
|
23
|
-
'User-Agent': KIRO_CONSTANTS.USER_AGENT,
|
|
24
|
-
},
|
|
25
|
-
body: JSON.stringify({
|
|
26
|
-
code,
|
|
27
|
-
code_verifier: verifier,
|
|
28
|
-
redirect_uri: redirectUri,
|
|
29
|
-
}),
|
|
30
|
-
});
|
|
31
|
-
if (!tokenResponse.ok) {
|
|
32
|
-
const errorText = await tokenResponse.text();
|
|
33
|
-
throw new Error(`Token exchange failed: ${tokenResponse.status} ${errorText}`);
|
|
34
|
-
}
|
|
35
|
-
const tokenData = await tokenResponse.json();
|
|
36
|
-
if (!tokenData.accessToken || !tokenData.refreshToken || !tokenData.profileArn) {
|
|
37
|
-
throw new Error('Invalid token response: missing required fields');
|
|
38
|
-
}
|
|
39
|
-
const expiresIn = tokenData.expiresIn || 3600;
|
|
40
|
-
const expiresAt = Date.now() + expiresIn * 1000;
|
|
41
|
-
const email = tokenData.email || 'unknown@kiro.dev';
|
|
42
|
-
return {
|
|
43
|
-
refreshToken: tokenData.refreshToken,
|
|
44
|
-
accessToken: tokenData.accessToken,
|
|
45
|
-
expiresAt,
|
|
46
|
-
email,
|
|
47
|
-
profileArn: tokenData.profileArn,
|
|
48
|
-
region,
|
|
49
|
-
authMethod: 'social',
|
|
50
|
-
};
|
|
51
|
-
}
|