@zhafron/opencode-kiro-auth 1.2.8 → 1.3.1
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 +31 -45
- package/dist/index.d.ts +1 -1
- package/dist/kiro/auth.js +15 -6
- package/dist/plugin/accounts.d.ts +2 -1
- package/dist/plugin/accounts.js +65 -31
- package/dist/plugin/cli.js +1 -1
- package/dist/plugin/config/index.d.ts +2 -2
- package/dist/plugin/config/index.js +2 -2
- package/dist/plugin/config/loader.js +3 -3
- package/dist/plugin/config/schema.d.ts +3 -0
- package/dist/plugin/config/schema.js +2 -0
- package/dist/plugin/request.d.ts +1 -1
- package/dist/plugin/request.js +10 -8
- package/dist/plugin/response.d.ts +1 -1
- package/dist/plugin/server.js +1 -1
- package/dist/plugin/storage/migration.d.ts +1 -0
- package/dist/plugin/storage/migration.js +53 -0
- package/dist/plugin/storage/sqlite.d.ts +14 -0
- package/dist/plugin/storage/sqlite.js +94 -0
- package/dist/plugin/sync/kiro-cli.d.ts +2 -0
- package/dist/plugin/sync/kiro-cli.js +96 -0
- package/dist/plugin/token.js +29 -17
- package/dist/plugin/types.d.ts +1 -27
- package/dist/plugin/usage.d.ts +1 -1
- package/dist/plugin.js +174 -243
- package/package.json +3 -2
- package/dist/plugin/storage.d.ts +0 -7
- package/dist/plugin/storage.js +0 -124
package/README.md
CHANGED
|
@@ -7,14 +7,13 @@ OpenCode plugin for AWS Kiro (CodeWhisperer) providing access to Claude Sonnet a
|
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
-
- AWS Builder ID (IDC)
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
- Usage tracking with automatic retry on sync failures.
|
|
10
|
+
- **Multiple Auth Methods**: Supports AWS Builder ID (IDC) and Kiro Desktop (CLI-based) authentication.
|
|
11
|
+
- **Auto-Sync Kiro CLI**: Automatically imports and synchronizes active sessions from your local `kiro-cli` SQLite database.
|
|
12
|
+
- **Gradual Context Truncation**: Intelligently prevents error 400 by reducing context size dynamically during retries.
|
|
13
|
+
- **Intelligent Account Rotation**: Prioritizes multi-account usage based on lowest available quota.
|
|
14
|
+
- **High-Performance Storage**: Efficient account and usage management using native Bun SQLite.
|
|
15
|
+
- **Native Thinking Mode**: Full support for Claude reasoning capabilities via virtual model mappings.
|
|
16
|
+
- **Automated Recovery**: Exponential backoff for rate limits and automated token refresh.
|
|
18
17
|
|
|
19
18
|
## Installation
|
|
20
19
|
|
|
@@ -54,10 +53,14 @@ Add the plugin to your `opencode.json` or `opencode.jsonc`:
|
|
|
54
53
|
|
|
55
54
|
## Setup
|
|
56
55
|
|
|
57
|
-
1.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
1. **Authentication via Kiro CLI (Recommended)**:
|
|
57
|
+
- Perform login directly in your terminal using `kiro-cli login`.
|
|
58
|
+
- The plugin will automatically detect and import your session on startup.
|
|
59
|
+
2. **Direct Authentication**:
|
|
60
|
+
- Run `opencode auth login`.
|
|
61
|
+
- Select `Other`, type `kiro`, and press enter.
|
|
62
|
+
- Follow the instructions for **AWS Builder ID (IDC)**.
|
|
63
|
+
3. Configuration will be automatically managed at `~/.config/opencode/kiro.db`.
|
|
61
64
|
|
|
62
65
|
## Configuration
|
|
63
66
|
|
|
@@ -65,6 +68,7 @@ The plugin supports extensive configuration options. Edit `~/.config/opencode/ki
|
|
|
65
68
|
|
|
66
69
|
```json
|
|
67
70
|
{
|
|
71
|
+
"auto_sync_kiro_cli": true,
|
|
68
72
|
"account_selection_strategy": "lowest-usage",
|
|
69
73
|
"default_region": "us-east-1",
|
|
70
74
|
"rate_limit_retry_delay_ms": 5000,
|
|
@@ -82,46 +86,28 @@ The plugin supports extensive configuration options. Edit `~/.config/opencode/ki
|
|
|
82
86
|
|
|
83
87
|
### Configuration Options
|
|
84
88
|
|
|
85
|
-
- `
|
|
86
|
-
- `
|
|
87
|
-
- `
|
|
88
|
-
- `
|
|
89
|
-
- `
|
|
90
|
-
- `
|
|
91
|
-
- `
|
|
92
|
-
- `
|
|
93
|
-
- `
|
|
94
|
-
- `
|
|
95
|
-
- `
|
|
96
|
-
- `
|
|
97
|
-
|
|
98
|
-
### Environment Variables
|
|
99
|
-
|
|
100
|
-
All configuration options can be overridden via environment variables:
|
|
101
|
-
|
|
102
|
-
- `KIRO_ACCOUNT_SELECTION_STRATEGY`
|
|
103
|
-
- `KIRO_DEFAULT_REGION`
|
|
104
|
-
- `KIRO_RATE_LIMIT_RETRY_DELAY_MS`
|
|
105
|
-
- `KIRO_RATE_LIMIT_MAX_RETRIES`
|
|
106
|
-
- `KIRO_MAX_REQUEST_ITERATIONS`
|
|
107
|
-
- `KIRO_REQUEST_TIMEOUT_MS`
|
|
108
|
-
- `KIRO_TOKEN_EXPIRY_BUFFER_MS`
|
|
109
|
-
- `KIRO_USAGE_SYNC_MAX_RETRIES`
|
|
110
|
-
- `KIRO_AUTH_SERVER_PORT_START`
|
|
111
|
-
- `KIRO_AUTH_SERVER_PORT_RANGE`
|
|
112
|
-
- `KIRO_USAGE_TRACKING_ENABLED`
|
|
113
|
-
- `KIRO_ENABLE_LOG_API_REQUEST`
|
|
89
|
+
- `auto_sync_kiro_cli`: Automatically sync sessions from Kiro CLI (default: `true`).
|
|
90
|
+
- `account_selection_strategy`: Account rotation strategy (`sticky`, `round-robin`, `lowest-usage`).
|
|
91
|
+
- `default_region`: AWS region (`us-east-1`, `us-west-2`).
|
|
92
|
+
- `rate_limit_retry_delay_ms`: Delay between rate limit retries (1000-60000ms).
|
|
93
|
+
- `rate_limit_max_retries`: Maximum retry attempts for rate limits (0-10).
|
|
94
|
+
- `max_request_iterations`: Maximum loop iterations to prevent hangs (10-1000).
|
|
95
|
+
- `request_timeout_ms`: Request timeout in milliseconds (60000-600000ms).
|
|
96
|
+
- `token_expiry_buffer_ms`: Token refresh buffer time (30000-300000ms).
|
|
97
|
+
- `usage_sync_max_retries`: Retry attempts for usage sync (0-5).
|
|
98
|
+
- `auth_server_port_start`: Starting port for auth server (1024-65535).
|
|
99
|
+
- `auth_server_port_range`: Number of ports to try (1-100).
|
|
100
|
+
- `usage_tracking_enabled`: Enable usage tracking and toast notifications.
|
|
101
|
+
- `enable_log_api_request`: Enable detailed API request logging.
|
|
114
102
|
|
|
115
103
|
## Storage
|
|
116
104
|
|
|
117
105
|
**Linux/macOS:**
|
|
118
|
-
-
|
|
119
|
-
- Usage Tracking: `~/.config/opencode/kiro-usage.json`
|
|
106
|
+
- SQLite Database: `~/.config/opencode/kiro.db`
|
|
120
107
|
- Plugin Config: `~/.config/opencode/kiro.json`
|
|
121
108
|
|
|
122
109
|
**Windows:**
|
|
123
|
-
-
|
|
124
|
-
- Usage Tracking: `%APPDATA%\opencode\kiro-usage.json`
|
|
110
|
+
- SQLite Database: `%APPDATA%\opencode\kiro.db`
|
|
125
111
|
- Plugin Config: `%APPDATA%\opencode\kiro.json`
|
|
126
112
|
|
|
127
113
|
## Acknowledgements
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { KiroOAuthPlugin } from './plugin.js';
|
|
2
2
|
export type { KiroConfig } from './plugin/config/index.js';
|
|
3
|
-
export type {
|
|
3
|
+
export type { KiroAuthMethod, KiroRegion, ManagedAccount } from './plugin/types.js';
|
package/dist/kiro/auth.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
export function decodeRefreshToken(refresh) {
|
|
2
2
|
const parts = refresh.split('|');
|
|
3
3
|
if (parts.length < 2)
|
|
4
|
-
return { refreshToken: parts[0], authMethod: '
|
|
4
|
+
return { refreshToken: parts[0], authMethod: 'desktop' };
|
|
5
5
|
const refreshToken = parts[0];
|
|
6
6
|
const authMethod = parts[parts.length - 1];
|
|
7
7
|
if (authMethod === 'idc')
|
|
8
8
|
return { refreshToken, clientId: parts[1], clientSecret: parts[2], authMethod: 'idc' };
|
|
9
|
-
|
|
9
|
+
if (authMethod === 'desktop')
|
|
10
|
+
return { refreshToken, authMethod: 'desktop' };
|
|
11
|
+
return { refreshToken, authMethod: 'desktop' };
|
|
10
12
|
}
|
|
11
13
|
export function accessTokenExpired(auth, bufferMs = 120000) {
|
|
12
14
|
if (!auth.access || !auth.expires)
|
|
@@ -14,10 +16,17 @@ export function accessTokenExpired(auth, bufferMs = 120000) {
|
|
|
14
16
|
return Date.now() >= auth.expires - bufferMs;
|
|
15
17
|
}
|
|
16
18
|
export function validateAuthDetails(auth) {
|
|
17
|
-
|
|
19
|
+
if (!auth.refresh)
|
|
20
|
+
return false;
|
|
21
|
+
if (auth.authMethod === 'idc')
|
|
22
|
+
return !!auth.clientId && !!auth.clientSecret;
|
|
23
|
+
return true;
|
|
18
24
|
}
|
|
19
25
|
export function encodeRefreshToken(parts) {
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
if (parts.authMethod === 'idc') {
|
|
27
|
+
if (!parts.clientId || !parts.clientSecret)
|
|
28
|
+
throw new Error('Missing credentials');
|
|
29
|
+
return `${parts.refreshToken}|${parts.clientId}|${parts.clientSecret}|idc`;
|
|
30
|
+
}
|
|
31
|
+
return `${parts.refreshToken}|desktop`;
|
|
23
32
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AccountSelectionStrategy, KiroAuthDetails, ManagedAccount, UsageMetadata } from './types';
|
|
2
2
|
export declare function generateAccountId(): string;
|
|
3
|
+
export declare function createDeterministicAccountId(email: string, method: string, clientId?: string, profileArn?: string): string;
|
|
3
4
|
export declare class AccountManager {
|
|
4
5
|
private accounts;
|
|
5
6
|
private usage;
|
package/dist/plugin/accounts.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { randomBytes } from 'node:crypto';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { decodeRefreshToken, encodeRefreshToken } from '../kiro/auth';
|
|
3
|
+
import { kiroDb } from './storage/sqlite';
|
|
4
|
+
import { writeToKiroCli } from './sync/kiro-cli';
|
|
5
5
|
export function generateAccountId() {
|
|
6
6
|
return randomBytes(16).toString('hex');
|
|
7
7
|
}
|
|
8
|
+
export function createDeterministicAccountId(email, method, clientId, profileArn) {
|
|
9
|
+
return createHash('sha256')
|
|
10
|
+
.update(`${email}:${method}:${clientId || ''}:${profileArn || ''}`)
|
|
11
|
+
.digest('hex');
|
|
12
|
+
}
|
|
8
13
|
export class AccountManager {
|
|
9
14
|
accounts;
|
|
10
15
|
usage;
|
|
@@ -27,13 +32,27 @@ export class AccountManager {
|
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
static async loadFromDisk(strategy) {
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const accounts =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
const rows = kiroDb.getAccounts();
|
|
36
|
+
const usage = kiroDb.getUsage();
|
|
37
|
+
const accounts = rows.map((r) => ({
|
|
38
|
+
id: r.id,
|
|
39
|
+
email: r.email,
|
|
40
|
+
realEmail: r.real_email,
|
|
41
|
+
authMethod: r.auth_method,
|
|
42
|
+
region: r.region,
|
|
43
|
+
clientId: r.client_id,
|
|
44
|
+
clientSecret: r.client_secret,
|
|
45
|
+
profileArn: r.profile_arn,
|
|
46
|
+
refreshToken: r.refresh_token,
|
|
47
|
+
accessToken: r.access_token,
|
|
48
|
+
expiresAt: r.expires_at,
|
|
49
|
+
rateLimitResetTime: r.rate_limit_reset,
|
|
50
|
+
isHealthy: r.is_healthy === 1,
|
|
51
|
+
unhealthyReason: r.unhealthy_reason,
|
|
52
|
+
recoveryTime: r.recovery_time,
|
|
53
|
+
lastUsed: r.last_used
|
|
35
54
|
}));
|
|
36
|
-
return new AccountManager(accounts,
|
|
55
|
+
return new AccountManager(accounts, usage, strategy || 'sticky');
|
|
37
56
|
}
|
|
38
57
|
getAccountCount() {
|
|
39
58
|
return this.accounts.length;
|
|
@@ -72,18 +91,29 @@ export class AccountManager {
|
|
|
72
91
|
}
|
|
73
92
|
return !(a.rateLimitResetTime && now < a.rateLimitResetTime);
|
|
74
93
|
});
|
|
75
|
-
if (available.length === 0)
|
|
76
|
-
return null;
|
|
77
94
|
let selected;
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
95
|
+
if (available.length > 0) {
|
|
96
|
+
if (this.strategy === 'sticky') {
|
|
97
|
+
selected = available.find((_, i) => i === this.cursor) || available[0];
|
|
98
|
+
}
|
|
99
|
+
else if (this.strategy === 'round-robin') {
|
|
100
|
+
selected = available[this.cursor % available.length];
|
|
101
|
+
this.cursor = (this.cursor + 1) % available.length;
|
|
102
|
+
}
|
|
103
|
+
else if (this.strategy === 'lowest-usage') {
|
|
104
|
+
selected = [...available].sort((a, b) => (a.usedCount || 0) - (b.usedCount || 0) || (a.lastUsed || 0) - (b.lastUsed || 0))[0];
|
|
105
|
+
}
|
|
84
106
|
}
|
|
85
|
-
|
|
86
|
-
|
|
107
|
+
if (!selected) {
|
|
108
|
+
const fallback = this.accounts
|
|
109
|
+
.filter((a) => !a.isHealthy)
|
|
110
|
+
.sort((a, b) => (a.usedCount || 0) - (b.usedCount || 0) || (a.lastUsed || 0) - (b.lastUsed || 0))[0];
|
|
111
|
+
if (fallback) {
|
|
112
|
+
fallback.isHealthy = true;
|
|
113
|
+
delete fallback.unhealthyReason;
|
|
114
|
+
delete fallback.recoveryTime;
|
|
115
|
+
selected = fallback;
|
|
116
|
+
}
|
|
87
117
|
}
|
|
88
118
|
if (selected) {
|
|
89
119
|
selected.lastUsed = now;
|
|
@@ -102,6 +132,7 @@ export class AccountManager {
|
|
|
102
132
|
a.realEmail = meta.realEmail;
|
|
103
133
|
}
|
|
104
134
|
this.usage[id] = { ...meta, lastSync: Date.now() };
|
|
135
|
+
kiroDb.upsertUsage(id, this.usage[id]);
|
|
105
136
|
}
|
|
106
137
|
addAccount(a) {
|
|
107
138
|
const i = this.accounts.findIndex((x) => x.id === a.id);
|
|
@@ -109,6 +140,7 @@ export class AccountManager {
|
|
|
109
140
|
this.accounts.push(a);
|
|
110
141
|
else
|
|
111
142
|
this.accounts[i] = a;
|
|
143
|
+
kiroDb.upsertAccount(a);
|
|
112
144
|
}
|
|
113
145
|
removeAccount(a) {
|
|
114
146
|
const removedIndex = this.accounts.findIndex((x) => x.id === a.id);
|
|
@@ -116,15 +148,13 @@ export class AccountManager {
|
|
|
116
148
|
return;
|
|
117
149
|
this.accounts = this.accounts.filter((x) => x.id !== a.id);
|
|
118
150
|
delete this.usage[a.id];
|
|
119
|
-
|
|
151
|
+
kiroDb.deleteAccount(a.id);
|
|
152
|
+
if (this.accounts.length === 0)
|
|
120
153
|
this.cursor = 0;
|
|
121
|
-
|
|
122
|
-
else if (this.cursor >= this.accounts.length) {
|
|
154
|
+
else if (this.cursor >= this.accounts.length)
|
|
123
155
|
this.cursor = this.accounts.length - 1;
|
|
124
|
-
|
|
125
|
-
else if (removedIndex <= this.cursor && this.cursor > 0) {
|
|
156
|
+
else if (removedIndex <= this.cursor && this.cursor > 0)
|
|
126
157
|
this.cursor--;
|
|
127
|
-
}
|
|
128
158
|
}
|
|
129
159
|
updateFromAuth(a, auth) {
|
|
130
160
|
const acc = this.accounts.find((x) => x.id === a.id);
|
|
@@ -140,25 +170,29 @@ export class AccountManager {
|
|
|
140
170
|
acc.profileArn = p.profileArn;
|
|
141
171
|
if (p.clientId)
|
|
142
172
|
acc.clientId = p.clientId;
|
|
173
|
+
kiroDb.upsertAccount(acc);
|
|
174
|
+
writeToKiroCli(acc).catch(() => { });
|
|
143
175
|
}
|
|
144
176
|
}
|
|
145
177
|
markRateLimited(a, ms) {
|
|
146
178
|
const acc = this.accounts.find((x) => x.id === a.id);
|
|
147
|
-
if (acc)
|
|
179
|
+
if (acc) {
|
|
148
180
|
acc.rateLimitResetTime = Date.now() + ms;
|
|
181
|
+
kiroDb.upsertAccount(acc);
|
|
182
|
+
}
|
|
149
183
|
}
|
|
150
184
|
markUnhealthy(a, reason, recovery) {
|
|
151
185
|
const acc = this.accounts.find((x) => x.id === a.id);
|
|
152
186
|
if (acc) {
|
|
153
187
|
acc.isHealthy = false;
|
|
154
188
|
acc.unhealthyReason = reason;
|
|
155
|
-
acc.recoveryTime = recovery;
|
|
189
|
+
acc.recoveryTime = recovery || Date.now() + 3600000;
|
|
190
|
+
kiroDb.upsertAccount(acc);
|
|
156
191
|
}
|
|
157
192
|
}
|
|
158
193
|
async saveToDisk() {
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
await saveUsage({ version: 1, usage: this.usage });
|
|
194
|
+
for (const a of this.accounts)
|
|
195
|
+
kiroDb.upsertAccount(a);
|
|
162
196
|
}
|
|
163
197
|
toAuthDetails(a) {
|
|
164
198
|
const p = {
|
package/dist/plugin/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createInterface } from 'node:readline/promises';
|
|
2
1
|
import { stdin as input, stdout as output } from 'node:process';
|
|
2
|
+
import { createInterface } from 'node:readline/promises';
|
|
3
3
|
export async function promptAddAnotherAccount(currentCount) {
|
|
4
4
|
const rl = createInterface({ input, output });
|
|
5
5
|
try {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { configExists, getDefaultLogsDir, getProjectConfigPath, getUserConfigPath, loadConfig } from './loader';
|
|
2
|
+
export { DEFAULT_CONFIG, KiroConfigSchema } from './schema';
|
|
2
3
|
export type { KiroConfig } from './schema';
|
|
3
|
-
export { loadConfig, getUserConfigPath, getProjectConfigPath, getDefaultLogsDir, configExists } from './loader';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
1
|
+
export { configExists, getDefaultLogsDir, getProjectConfigPath, getUserConfigPath, loadConfig } from './loader';
|
|
2
|
+
export { DEFAULT_CONFIG, KiroConfigSchema } from './schema';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync
|
|
2
|
-
import { join, dirname } from 'node:path';
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
2
|
import { homedir } from 'node:os';
|
|
4
|
-
import {
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
5
4
|
import * as logger from '../logger';
|
|
5
|
+
import { AccountSelectionStrategySchema, DEFAULT_CONFIG, KiroConfigSchema, RegionSchema } from './schema';
|
|
6
6
|
function getConfigDir() {
|
|
7
7
|
const platform = process.platform;
|
|
8
8
|
if (platform === 'win32') {
|
|
@@ -16,6 +16,7 @@ export declare const KiroConfigSchema: z.ZodObject<{
|
|
|
16
16
|
auth_server_port_start: z.ZodDefault<z.ZodNumber>;
|
|
17
17
|
auth_server_port_range: z.ZodDefault<z.ZodNumber>;
|
|
18
18
|
usage_tracking_enabled: z.ZodDefault<z.ZodBoolean>;
|
|
19
|
+
auto_sync_kiro_cli: z.ZodDefault<z.ZodBoolean>;
|
|
19
20
|
enable_log_api_request: z.ZodDefault<z.ZodBoolean>;
|
|
20
21
|
}, "strip", z.ZodTypeAny, {
|
|
21
22
|
account_selection_strategy: "sticky" | "round-robin" | "lowest-usage";
|
|
@@ -29,6 +30,7 @@ export declare const KiroConfigSchema: z.ZodObject<{
|
|
|
29
30
|
auth_server_port_start: number;
|
|
30
31
|
auth_server_port_range: number;
|
|
31
32
|
usage_tracking_enabled: boolean;
|
|
33
|
+
auto_sync_kiro_cli: boolean;
|
|
32
34
|
enable_log_api_request: boolean;
|
|
33
35
|
$schema?: string | undefined;
|
|
34
36
|
}, {
|
|
@@ -44,6 +46,7 @@ export declare const KiroConfigSchema: z.ZodObject<{
|
|
|
44
46
|
auth_server_port_start?: number | undefined;
|
|
45
47
|
auth_server_port_range?: number | undefined;
|
|
46
48
|
usage_tracking_enabled?: boolean | undefined;
|
|
49
|
+
auto_sync_kiro_cli?: boolean | undefined;
|
|
47
50
|
enable_log_api_request?: boolean | undefined;
|
|
48
51
|
}>;
|
|
49
52
|
export type KiroConfig = z.infer<typeof KiroConfigSchema>;
|
|
@@ -14,6 +14,7 @@ export const KiroConfigSchema = z.object({
|
|
|
14
14
|
auth_server_port_start: z.number().min(1024).max(65535).default(19847),
|
|
15
15
|
auth_server_port_range: z.number().min(1).max(100).default(10),
|
|
16
16
|
usage_tracking_enabled: z.boolean().default(true),
|
|
17
|
+
auto_sync_kiro_cli: z.boolean().default(true),
|
|
17
18
|
enable_log_api_request: z.boolean().default(false)
|
|
18
19
|
});
|
|
19
20
|
export const DEFAULT_CONFIG = {
|
|
@@ -28,5 +29,6 @@ export const DEFAULT_CONFIG = {
|
|
|
28
29
|
auth_server_port_start: 19847,
|
|
29
30
|
auth_server_port_range: 10,
|
|
30
31
|
usage_tracking_enabled: true,
|
|
32
|
+
auto_sync_kiro_cli: true,
|
|
31
33
|
enable_log_api_request: false
|
|
32
34
|
};
|
package/dist/plugin/request.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { KiroAuthDetails, PreparedRequest } from './types';
|
|
2
|
-
export declare function transformToCodeWhisperer(url: string, body: any, model: string, auth: KiroAuthDetails, think?: boolean, budget?: number): PreparedRequest;
|
|
2
|
+
export declare function transformToCodeWhisperer(url: string, body: any, model: string, auth: KiroAuthDetails, think?: boolean, budget?: number, reductionFactor?: number): PreparedRequest;
|
|
3
3
|
export declare function mergeAdjacentMessages(msgs: any[]): any[];
|
|
4
4
|
export declare function convertToolsToCodeWhisperer(tools: any[]): any[];
|
package/dist/plugin/request.js
CHANGED
|
@@ -46,7 +46,7 @@ function findOriginalToolCall(msgs, toolUseId) {
|
|
|
46
46
|
}
|
|
47
47
|
return null;
|
|
48
48
|
}
|
|
49
|
-
export function transformToCodeWhisperer(url, body, model, auth, think = false, budget = 20000) {
|
|
49
|
+
export function transformToCodeWhisperer(url, body, model, auth, think = false, budget = 20000, reductionFactor = 1.0) {
|
|
50
50
|
const req = typeof body === 'string' ? JSON.parse(body) : body;
|
|
51
51
|
const { messages, tools, system } = req;
|
|
52
52
|
const convId = crypto.randomUUID();
|
|
@@ -94,6 +94,7 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
94
94
|
});
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
|
+
const toolResultLimit = Math.floor(250000 * reductionFactor);
|
|
97
98
|
for (let i = 0; i < msgs.length - 1; i++) {
|
|
98
99
|
const m = msgs[i];
|
|
99
100
|
if (!m)
|
|
@@ -107,7 +108,7 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
107
108
|
uim.content += p.text || '';
|
|
108
109
|
else if (p.type === 'tool_result')
|
|
109
110
|
trs.push({
|
|
110
|
-
content: [{ text: truncate(getContentText(p.content || p),
|
|
111
|
+
content: [{ text: truncate(getContentText(p.content || p), toolResultLimit) }],
|
|
111
112
|
status: 'success',
|
|
112
113
|
toolUseId: p.tool_use_id
|
|
113
114
|
});
|
|
@@ -134,14 +135,14 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
134
135
|
if (m.tool_results) {
|
|
135
136
|
for (const tr of m.tool_results)
|
|
136
137
|
trs.push({
|
|
137
|
-
content: [{ text: truncate(getContentText(tr),
|
|
138
|
+
content: [{ text: truncate(getContentText(tr), toolResultLimit) }],
|
|
138
139
|
status: 'success',
|
|
139
140
|
toolUseId: tr.tool_call_id
|
|
140
141
|
});
|
|
141
142
|
}
|
|
142
143
|
else {
|
|
143
144
|
trs.push({
|
|
144
|
-
content: [{ text: truncate(getContentText(m),
|
|
145
|
+
content: [{ text: truncate(getContentText(m), toolResultLimit) }],
|
|
145
146
|
status: 'success',
|
|
146
147
|
toolUseId: m.tool_call_id
|
|
147
148
|
});
|
|
@@ -196,7 +197,8 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
196
197
|
}
|
|
197
198
|
history = sanitizeHistory(history);
|
|
198
199
|
let historySize = JSON.stringify(history).length;
|
|
199
|
-
|
|
200
|
+
const historyLimit = Math.floor(850000 * reductionFactor);
|
|
201
|
+
while (historySize > historyLimit && history.length > 2) {
|
|
200
202
|
history.shift();
|
|
201
203
|
while (history.length > 0) {
|
|
202
204
|
const first = history[0];
|
|
@@ -258,14 +260,14 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
258
260
|
if (curMsg.tool_results) {
|
|
259
261
|
for (const tr of curMsg.tool_results)
|
|
260
262
|
curTrs.push({
|
|
261
|
-
content: [{ text: truncate(getContentText(tr),
|
|
263
|
+
content: [{ text: truncate(getContentText(tr), toolResultLimit) }],
|
|
262
264
|
status: 'success',
|
|
263
265
|
toolUseId: tr.tool_call_id
|
|
264
266
|
});
|
|
265
267
|
}
|
|
266
268
|
else {
|
|
267
269
|
curTrs.push({
|
|
268
|
-
content: [{ text: truncate(getContentText(curMsg),
|
|
270
|
+
content: [{ text: truncate(getContentText(curMsg), toolResultLimit) }],
|
|
269
271
|
status: 'success',
|
|
270
272
|
toolUseId: curMsg.tool_call_id
|
|
271
273
|
});
|
|
@@ -277,7 +279,7 @@ export function transformToCodeWhisperer(url, body, model, auth, think = false,
|
|
|
277
279
|
curContent += p.text || '';
|
|
278
280
|
else if (p.type === 'tool_result')
|
|
279
281
|
curTrs.push({
|
|
280
|
-
content: [{ text: truncate(getContentText(p.content || p),
|
|
282
|
+
content: [{ text: truncate(getContentText(p.content || p), toolResultLimit) }],
|
|
281
283
|
status: 'success',
|
|
282
284
|
toolUseId: p.tool_use_id
|
|
283
285
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ParsedResponse, ToolCall } from './types';
|
|
2
2
|
export declare function parseEventStream(rawResponse: string): ParsedResponse;
|
|
3
3
|
export declare function parseEventLine(line: string): any | null;
|
|
4
4
|
export declare function parseBracketToolCalls(text: string): ToolCall[];
|
package/dist/plugin/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createServer } from 'node:http';
|
|
2
|
-
import { getIDCAuthHtml, getSuccessHtml
|
|
2
|
+
import { getErrorHtml, getIDCAuthHtml, getSuccessHtml } from './auth-page';
|
|
3
3
|
import * as logger from './logger';
|
|
4
4
|
async function tryPort(port) {
|
|
5
5
|
return new Promise((resolve) => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function migrateJsonToSqlite(): Promise<void>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import * as logger from '../logger';
|
|
5
|
+
import { kiroDb } from './sqlite';
|
|
6
|
+
function getBaseDir() {
|
|
7
|
+
const platform = process.platform;
|
|
8
|
+
if (platform === 'win32') {
|
|
9
|
+
return join(process.env.APPDATA || join(homedir(), 'AppData', 'Roaming'), 'opencode');
|
|
10
|
+
}
|
|
11
|
+
return join(process.env.XDG_CONFIG_HOME || join(homedir(), '.config'), 'opencode');
|
|
12
|
+
}
|
|
13
|
+
export async function migrateJsonToSqlite() {
|
|
14
|
+
const base = getBaseDir();
|
|
15
|
+
const accPath = join(base, 'kiro-accounts.json');
|
|
16
|
+
const usePath = join(base, 'kiro-usage.json');
|
|
17
|
+
try {
|
|
18
|
+
const accExists = await fs
|
|
19
|
+
.access(accPath)
|
|
20
|
+
.then(() => true)
|
|
21
|
+
.catch(() => false);
|
|
22
|
+
if (accExists) {
|
|
23
|
+
const data = JSON.parse(await fs.readFile(accPath, 'utf-8'));
|
|
24
|
+
if (data.accounts && Array.isArray(data.accounts)) {
|
|
25
|
+
for (const acc of data.accounts) {
|
|
26
|
+
kiroDb.upsertAccount({
|
|
27
|
+
...acc,
|
|
28
|
+
rateLimitResetTime: acc.rateLimitResetTime || 0,
|
|
29
|
+
isHealthy: acc.isHealthy !== false,
|
|
30
|
+
lastUsed: acc.lastUsed || 0
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
await fs.rename(accPath, accPath + '.bak');
|
|
35
|
+
}
|
|
36
|
+
const useExists = await fs
|
|
37
|
+
.access(usePath)
|
|
38
|
+
.then(() => true)
|
|
39
|
+
.catch(() => false);
|
|
40
|
+
if (useExists) {
|
|
41
|
+
const data = JSON.parse(await fs.readFile(usePath, 'utf-8'));
|
|
42
|
+
if (data.usage && typeof data.usage === 'object') {
|
|
43
|
+
for (const [id, meta] of Object.entries(data.usage)) {
|
|
44
|
+
kiroDb.upsertUsage(id, meta);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
await fs.rename(usePath, usePath + '.bak');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
logger.error('Migration failed', e);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { UsageMetadata } from '../types';
|
|
2
|
+
export declare const DB_PATH: string;
|
|
3
|
+
export declare class KiroDatabase {
|
|
4
|
+
private db;
|
|
5
|
+
constructor(path?: string);
|
|
6
|
+
private init;
|
|
7
|
+
getAccounts(): any[];
|
|
8
|
+
upsertAccount(acc: any): void;
|
|
9
|
+
deleteAccount(id: string): void;
|
|
10
|
+
getUsage(): Record<string, UsageMetadata>;
|
|
11
|
+
upsertUsage(id: string, meta: UsageMetadata): void;
|
|
12
|
+
close(): void;
|
|
13
|
+
}
|
|
14
|
+
export declare const kiroDb: KiroDatabase;
|