@sunerpy/opencode-kiro-auth 0.10.0 → 0.12.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 +8 -2
- package/dist/constants.js +4 -0
- package/dist/plugin/accounts.d.ts +6 -0
- package/dist/plugin/accounts.js +56 -6
- package/dist/plugin/config/schema.d.ts +14 -0
- package/dist/plugin/config/schema.js +12 -0
- package/dist/plugin/storage/locked-operations.d.ts +1 -0
- package/dist/plugin/storage/locked-operations.js +42 -1
- package/dist/plugin/storage/migrations.js +15 -5
- package/dist/plugin/storage/sqlite.d.ts +1 -0
- package/dist/plugin/storage/sqlite.js +10 -2
- package/dist/plugin.js +18 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
[](https://www.npmjs.com/package/@sunerpy/opencode-kiro-auth)
|
|
9
9
|
|
|
10
10
|
> OpenCode plugin that lets OpenCode use AWS Kiro (CodeWhisperer) as a model
|
|
11
|
-
> provider — Claude Sonnet, Opus, and Haiku, plus the
|
|
12
|
-
>
|
|
11
|
+
> provider — Claude Sonnet, Opus, and Haiku, plus the other models Kiro proxies
|
|
12
|
+
> (OpenAI GPT 5.6, DeepSeek, GLM, MiniMax, Qwen3) — with substantial trial
|
|
13
|
+
> quotas.
|
|
13
14
|
|
|
14
15
|
## Table of Contents
|
|
15
16
|
|
|
@@ -112,6 +113,11 @@ Paid-overage protection is on by default; see
|
|
|
112
113
|
[Overage protection](docs/CONFIGURATION.md#overage-protection) before disabling
|
|
113
114
|
`stop_on_overage`.
|
|
114
115
|
|
|
116
|
+
Running multiple OpenCode processes at once? `distribute_across_processes`
|
|
117
|
+
(default `true`) and `per_request_spread` (default `false`) control how load
|
|
118
|
+
spreads across accounts — see
|
|
119
|
+
[Account distribution across processes](docs/CONFIGURATION.md#account-distribution-across-processes).
|
|
120
|
+
|
|
115
121
|
## Multiple accounts & rotation
|
|
116
122
|
|
|
117
123
|
You can register more than one Kiro account and let the plugin spread
|
package/dist/constants.js
CHANGED
|
@@ -81,6 +81,10 @@ export const MODEL_MAPPING = {
|
|
|
81
81
|
'minimax-m2.5': 'minimax-m2.5',
|
|
82
82
|
'minimax-m2.1': 'minimax-m2.1',
|
|
83
83
|
'qwen3-coder-next': 'qwen3-coder-next',
|
|
84
|
+
// OpenAI GPT 5.6 — probe-confirmed (200, us-east-1); other naming guesses 400. No effort variant.
|
|
85
|
+
'gpt-5.6-sol': 'gpt-5.6-sol',
|
|
86
|
+
'gpt-5.6-terra': 'gpt-5.6-terra',
|
|
87
|
+
'gpt-5.6-luna': 'gpt-5.6-luna',
|
|
84
88
|
// Legacy / internal mappings kept for backwards compatibility
|
|
85
89
|
'claude-3-7-sonnet': 'CLAUDE_3_7_SONNET_20250219_V1_0',
|
|
86
90
|
'nova-swe': 'AGI_NOVA_SWE_V1_5',
|
|
@@ -8,6 +8,8 @@ export declare class AccountManager {
|
|
|
8
8
|
private lastUsageToastTime;
|
|
9
9
|
private rrCursor;
|
|
10
10
|
private stickyId?;
|
|
11
|
+
private startIndex;
|
|
12
|
+
private perRequestSpread;
|
|
11
13
|
private quotaAvoidanceEnabled;
|
|
12
14
|
private quotaReserveThreshold;
|
|
13
15
|
private stopOnOverage;
|
|
@@ -17,12 +19,16 @@ export declare class AccountManager {
|
|
|
17
19
|
quotaReserveThreshold?: number;
|
|
18
20
|
stopOnOverage?: boolean;
|
|
19
21
|
overageThreshold?: number;
|
|
22
|
+
startIndex?: number;
|
|
23
|
+
perRequestSpread?: boolean;
|
|
20
24
|
});
|
|
21
25
|
static loadFromDisk(strategy?: AccountSelectionStrategy, opts?: {
|
|
22
26
|
quotaAvoidanceEnabled?: boolean;
|
|
23
27
|
quotaReserveThreshold?: number;
|
|
24
28
|
stopOnOverage?: boolean;
|
|
25
29
|
overageThreshold?: number;
|
|
30
|
+
distributeAcrossProcesses?: boolean;
|
|
31
|
+
perRequestSpread?: boolean;
|
|
26
32
|
}): Promise<AccountManager>;
|
|
27
33
|
getAccountCount(): number;
|
|
28
34
|
getAccounts(): ManagedAccount[];
|
package/dist/plugin/accounts.js
CHANGED
|
@@ -15,8 +15,10 @@ export class AccountManager {
|
|
|
15
15
|
strategy;
|
|
16
16
|
lastToastTime = 0;
|
|
17
17
|
lastUsageToastTime = 0;
|
|
18
|
-
rrCursor
|
|
18
|
+
rrCursor;
|
|
19
19
|
stickyId;
|
|
20
|
+
startIndex;
|
|
21
|
+
perRequestSpread;
|
|
20
22
|
quotaAvoidanceEnabled;
|
|
21
23
|
quotaReserveThreshold;
|
|
22
24
|
stopOnOverage;
|
|
@@ -29,6 +31,9 @@ export class AccountManager {
|
|
|
29
31
|
this.quotaReserveThreshold = opts?.quotaReserveThreshold ?? 0.95;
|
|
30
32
|
this.stopOnOverage = opts?.stopOnOverage ?? true;
|
|
31
33
|
this.overageThreshold = opts?.overageThreshold ?? 0;
|
|
34
|
+
this.startIndex = opts?.startIndex ?? 0;
|
|
35
|
+
this.perRequestSpread = opts?.perRequestSpread ?? false;
|
|
36
|
+
this.rrCursor = this.startIndex;
|
|
32
37
|
}
|
|
33
38
|
static async loadFromDisk(strategy, opts) {
|
|
34
39
|
const rows = kiroDb.getAccounts();
|
|
@@ -56,7 +61,23 @@ export class AccountManager {
|
|
|
56
61
|
overageCount: r.overage_count || 0,
|
|
57
62
|
lastSync: r.last_sync
|
|
58
63
|
}));
|
|
59
|
-
|
|
64
|
+
let startIndex = 0;
|
|
65
|
+
if (opts?.distributeAcrossProcesses !== false) {
|
|
66
|
+
try {
|
|
67
|
+
startIndex = await kiroDb.nextAssignmentIndex();
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
logger.warn('assignment index failed, using 0', {
|
|
71
|
+
error: error instanceof Error ? error.message : String(error)
|
|
72
|
+
});
|
|
73
|
+
startIndex = 0;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return new AccountManager(accounts, strategy || 'sticky', {
|
|
77
|
+
...opts,
|
|
78
|
+
startIndex,
|
|
79
|
+
perRequestSpread: opts?.perRequestSpread
|
|
80
|
+
});
|
|
60
81
|
}
|
|
61
82
|
getAccountCount() {
|
|
62
83
|
return this.accounts.length;
|
|
@@ -140,10 +161,26 @@ export class AccountManager {
|
|
|
140
161
|
const nearFull = available.filter((a) => ratio(a) >= this.quotaReserveThreshold);
|
|
141
162
|
candidatePool = ample.length > 0 ? ample : nearFull;
|
|
142
163
|
}
|
|
164
|
+
const sorted = [...this.accounts].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
165
|
+
const N = sorted.length;
|
|
143
166
|
let selected;
|
|
144
167
|
if (candidatePool.length > 0) {
|
|
145
|
-
if (this.
|
|
146
|
-
selected = candidatePool.
|
|
168
|
+
if (this.perRequestSpread) {
|
|
169
|
+
selected = [...candidatePool].sort((a, b) => (a.usedCount || 0) - (b.usedCount || 0) || (a.lastUsed || 0) - (b.lastUsed || 0))[0];
|
|
170
|
+
}
|
|
171
|
+
else if (this.strategy === 'sticky') {
|
|
172
|
+
if (this.stickyId) {
|
|
173
|
+
selected = candidatePool.find((a) => a.id === this.stickyId);
|
|
174
|
+
}
|
|
175
|
+
if (!selected) {
|
|
176
|
+
for (let k = 0; k < N; k++) {
|
|
177
|
+
const candidate = sorted[(this.startIndex + k) % N];
|
|
178
|
+
if (candidate && candidatePool.some((account) => account.id === candidate.id)) {
|
|
179
|
+
selected = candidate;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
147
184
|
if (selected)
|
|
148
185
|
this.stickyId = selected.id;
|
|
149
186
|
}
|
|
@@ -151,8 +188,21 @@ export class AccountManager {
|
|
|
151
188
|
selected = candidatePool[this.rrCursor % candidatePool.length];
|
|
152
189
|
this.rrCursor++;
|
|
153
190
|
}
|
|
154
|
-
else
|
|
155
|
-
|
|
191
|
+
else {
|
|
192
|
+
const sortedIndexById = new Map(sorted.map((account, index) => [account.id, index]));
|
|
193
|
+
selected = [...candidatePool].sort((a, b) => {
|
|
194
|
+
const usageDifference = (a.usedCount || 0) - (b.usedCount || 0);
|
|
195
|
+
if (usageDifference !== 0)
|
|
196
|
+
return usageDifference;
|
|
197
|
+
const lastUsedDifference = (a.lastUsed || 0) - (b.lastUsed || 0);
|
|
198
|
+
if (lastUsedDifference !== 0)
|
|
199
|
+
return lastUsedDifference;
|
|
200
|
+
const aIndex = sortedIndexById.get(a.id) ?? 0;
|
|
201
|
+
const bIndex = sortedIndexById.get(b.id) ?? 0;
|
|
202
|
+
const aOffset = (((aIndex - this.startIndex) % N) + N) % N;
|
|
203
|
+
const bOffset = (((bIndex - this.startIndex) % N) + N) % N;
|
|
204
|
+
return aOffset - bOffset;
|
|
205
|
+
})[0];
|
|
156
206
|
}
|
|
157
207
|
}
|
|
158
208
|
if (!selected) {
|
|
@@ -19,6 +19,16 @@ export declare const KiroConfigSchema: z.ZodObject<{
|
|
|
19
19
|
idc_region: z.ZodOptional<z.ZodEnum<["us-east-1", "us-east-2", "us-west-1", "us-west-2", "af-south-1", "ap-east-1", "ap-south-2", "ap-southeast-3", "ap-southeast-5", "ap-southeast-4", "ap-south-1", "ap-southeast-6", "ap-northeast-3", "ap-northeast-2", "ap-southeast-1", "ap-southeast-2", "ap-east-2", "ap-southeast-7", "ap-northeast-1", "ca-central-1", "ca-west-1", "eu-central-1", "eu-west-1", "eu-west-2", "eu-south-1", "eu-west-3", "eu-south-2", "eu-north-1", "eu-central-2", "il-central-1", "mx-central-1", "me-south-1", "me-central-1", "sa-east-1"]>>;
|
|
20
20
|
idc_profile_arn: z.ZodOptional<z.ZodString>;
|
|
21
21
|
account_selection_strategy: z.ZodDefault<z.ZodEnum<["sticky", "round-robin", "lowest-usage"]>>;
|
|
22
|
+
/**
|
|
23
|
+
* Give each process a distinct start index so simultaneous starts spread
|
|
24
|
+
* across accounts.
|
|
25
|
+
*/
|
|
26
|
+
distribute_across_processes: z.ZodDefault<z.ZodBoolean>;
|
|
27
|
+
/**
|
|
28
|
+
* Re-pick the lowest-usage account for every request instead of pinning one.
|
|
29
|
+
* Overrides sticky selection.
|
|
30
|
+
*/
|
|
31
|
+
per_request_spread: z.ZodDefault<z.ZodBoolean>;
|
|
22
32
|
/**
|
|
23
33
|
* Softly avoid accounts whose usage ratio is at/above
|
|
24
34
|
* `quota_reserve_threshold` when other accounts still have room. When ALL
|
|
@@ -84,6 +94,8 @@ export declare const KiroConfigSchema: z.ZodObject<{
|
|
|
84
94
|
auto_effort_mapping: z.ZodDefault<z.ZodBoolean>;
|
|
85
95
|
}, "strip", z.ZodTypeAny, {
|
|
86
96
|
account_selection_strategy: "sticky" | "round-robin" | "lowest-usage";
|
|
97
|
+
distribute_across_processes: boolean;
|
|
98
|
+
per_request_spread: boolean;
|
|
87
99
|
quota_avoidance_enabled: boolean;
|
|
88
100
|
quota_reserve_threshold: number;
|
|
89
101
|
stop_on_overage: boolean;
|
|
@@ -115,6 +127,8 @@ export declare const KiroConfigSchema: z.ZodObject<{
|
|
|
115
127
|
idc_region?: "us-east-1" | "us-east-2" | "us-west-1" | "us-west-2" | "af-south-1" | "ap-east-1" | "ap-south-2" | "ap-southeast-3" | "ap-southeast-5" | "ap-southeast-4" | "ap-south-1" | "ap-southeast-6" | "ap-northeast-3" | "ap-northeast-2" | "ap-southeast-1" | "ap-southeast-2" | "ap-east-2" | "ap-southeast-7" | "ap-northeast-1" | "ca-central-1" | "ca-west-1" | "eu-central-1" | "eu-west-1" | "eu-west-2" | "eu-south-1" | "eu-west-3" | "eu-south-2" | "eu-north-1" | "eu-central-2" | "il-central-1" | "mx-central-1" | "me-south-1" | "me-central-1" | "sa-east-1" | undefined;
|
|
116
128
|
idc_profile_arn?: string | undefined;
|
|
117
129
|
account_selection_strategy?: "sticky" | "round-robin" | "lowest-usage" | undefined;
|
|
130
|
+
distribute_across_processes?: boolean | undefined;
|
|
131
|
+
per_request_spread?: boolean | undefined;
|
|
118
132
|
quota_avoidance_enabled?: boolean | undefined;
|
|
119
133
|
quota_reserve_threshold?: number | undefined;
|
|
120
134
|
stop_on_overage?: boolean | undefined;
|
|
@@ -51,6 +51,16 @@ export const KiroConfigSchema = z.object({
|
|
|
51
51
|
idc_region: RegionSchema.optional(),
|
|
52
52
|
idc_profile_arn: z.string().optional(),
|
|
53
53
|
account_selection_strategy: AccountSelectionStrategySchema.default('lowest-usage'),
|
|
54
|
+
/**
|
|
55
|
+
* Give each process a distinct start index so simultaneous starts spread
|
|
56
|
+
* across accounts.
|
|
57
|
+
*/
|
|
58
|
+
distribute_across_processes: z.boolean().default(true),
|
|
59
|
+
/**
|
|
60
|
+
* Re-pick the lowest-usage account for every request instead of pinning one.
|
|
61
|
+
* Overrides sticky selection.
|
|
62
|
+
*/
|
|
63
|
+
per_request_spread: z.boolean().default(false),
|
|
54
64
|
/**
|
|
55
65
|
* Softly avoid accounts whose usage ratio is at/above
|
|
56
66
|
* `quota_reserve_threshold` when other accounts still have room. When ALL
|
|
@@ -117,6 +127,8 @@ export const KiroConfigSchema = z.object({
|
|
|
117
127
|
});
|
|
118
128
|
export const DEFAULT_CONFIG = {
|
|
119
129
|
account_selection_strategy: 'lowest-usage',
|
|
130
|
+
distribute_across_processes: true,
|
|
131
|
+
per_request_spread: false,
|
|
120
132
|
quota_avoidance_enabled: true,
|
|
121
133
|
quota_reserve_threshold: 0.95,
|
|
122
134
|
stop_on_overage: true,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ManagedAccount } from '../types.js';
|
|
2
2
|
export { getKeepAliveLockPath, getRefreshLockPath } from '../paths.js';
|
|
3
3
|
type LockRelease = () => Promise<void>;
|
|
4
|
+
export declare function withDatabaseLockSync<T>(dbPath: string, fn: () => T): T;
|
|
4
5
|
export declare function withDatabaseLock<T>(dbPath: string, fn: () => Promise<T>): Promise<T>;
|
|
5
6
|
export declare function withRefreshLock<T>(accountId: string, fn: () => Promise<T>): Promise<T>;
|
|
6
7
|
export declare function tryAcquireKeepAliveLock(): Promise<LockRelease | null>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import { existsSync, promises as fs } from 'node:fs';
|
|
2
|
+
import { existsSync, promises as fs, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { dirname } from 'node:path';
|
|
4
4
|
import lockfile from 'proper-lockfile';
|
|
5
5
|
import { isPermanentError } from '../health.js';
|
|
@@ -30,6 +30,47 @@ const KEEP_ALIVE_LOCK_OPTIONS = {
|
|
|
30
30
|
retries: 0,
|
|
31
31
|
realpath: false
|
|
32
32
|
};
|
|
33
|
+
const SYNC_LOCK_OPTIONS = { stale: 10000, retries: 0, realpath: false };
|
|
34
|
+
const SYNC_LOCK_DEADLINE_MS = 10000;
|
|
35
|
+
function blockingBackoff(ms) {
|
|
36
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
37
|
+
}
|
|
38
|
+
function isLockContention(e) {
|
|
39
|
+
return typeof e === 'object' && e !== null && 'code' in e && e.code === 'ELOCKED';
|
|
40
|
+
}
|
|
41
|
+
export function withDatabaseLockSync(dbPath, fn) {
|
|
42
|
+
if (!existsSync(dbPath)) {
|
|
43
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
44
|
+
writeFileSync(dbPath, '');
|
|
45
|
+
}
|
|
46
|
+
// proper-lockfile's sync API rejects a retries object, so bounded lock-acquisition backoff is
|
|
47
|
+
// done here to serialize the synchronous constructor/init (schema + migrations) across processes.
|
|
48
|
+
const deadline = Date.now() + SYNC_LOCK_DEADLINE_MS;
|
|
49
|
+
let release = null;
|
|
50
|
+
let attempt = 0;
|
|
51
|
+
for (;;) {
|
|
52
|
+
try {
|
|
53
|
+
release = lockfile.lockSync(dbPath, SYNC_LOCK_OPTIONS);
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
if (!isLockContention(e) || Date.now() >= deadline)
|
|
58
|
+
throw e;
|
|
59
|
+
blockingBackoff(Math.min(100 * 2 ** attempt++, 500));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
return fn();
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
try {
|
|
67
|
+
release();
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
console.warn('Failed to release lock:', e);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
33
74
|
export async function withDatabaseLock(dbPath, fn) {
|
|
34
75
|
if (!existsSync(dbPath)) {
|
|
35
76
|
const dir = dbPath.substring(0, dbPath.lastIndexOf('/'));
|
|
@@ -7,15 +7,22 @@ export function runMigrations(db) {
|
|
|
7
7
|
migrateDropRefreshTokenUniqueIndex(db);
|
|
8
8
|
migrateRemovedAccountsTable(db);
|
|
9
9
|
migrateOverageColumn(db);
|
|
10
|
+
migratePluginMetaTable(db);
|
|
10
11
|
}
|
|
11
12
|
function migrateToUniqueRefreshToken(db) {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
.get();
|
|
15
|
-
if (hasIndex)
|
|
13
|
+
const indexProbe = db.prepare("SELECT name FROM sqlite_master WHERE type='index' AND name='idx_refresh_token_unique'");
|
|
14
|
+
if (indexProbe.get())
|
|
16
15
|
return;
|
|
17
|
-
|
|
16
|
+
// BEGIN IMMEDIATE (not deferred BEGIN): a deferred read-then-write txn raises unrecoverable
|
|
17
|
+
// SQLITE_BUSY_SNAPSHOT (busy_timeout cannot retry it) if another connection writes after the
|
|
18
|
+
// read snapshot. Taking the write lock at BEGIN makes concurrent processes serialize via
|
|
19
|
+
// busy_timeout instead of racing into a snapshot conflict.
|
|
20
|
+
db.exec('BEGIN IMMEDIATE');
|
|
18
21
|
try {
|
|
22
|
+
if (indexProbe.get()) {
|
|
23
|
+
db.exec('COMMIT');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
19
26
|
const duplicates = db
|
|
20
27
|
.prepare(`
|
|
21
28
|
SELECT refresh_token, COUNT(*) as count
|
|
@@ -167,3 +174,6 @@ function migrateOverageColumn(db) {
|
|
|
167
174
|
db.exec('ALTER TABLE accounts ADD COLUMN overage_count INTEGER DEFAULT 0');
|
|
168
175
|
}
|
|
169
176
|
}
|
|
177
|
+
function migratePluginMetaTable(db) {
|
|
178
|
+
db.exec('CREATE TABLE IF NOT EXISTS plugin_meta (key TEXT PRIMARY KEY, value INTEGER NOT NULL)');
|
|
179
|
+
}
|
|
@@ -18,6 +18,7 @@ export declare class KiroDatabase {
|
|
|
18
18
|
isAccountRemoved(id: string): Promise<boolean>;
|
|
19
19
|
clearRemovedAccount(id: string): Promise<void>;
|
|
20
20
|
listRemovedAccounts(): Promise<string[]>;
|
|
21
|
+
nextAssignmentIndex(): Promise<number>;
|
|
21
22
|
markAccountsUnhealthy(ids: string[], reason: string): Promise<void>;
|
|
22
23
|
private rowToAccount;
|
|
23
24
|
close(): void;
|
|
@@ -2,7 +2,7 @@ import Database from 'libsql';
|
|
|
2
2
|
import { existsSync, mkdirSync } from 'node:fs';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
import { deduplicateAccounts, mergeAccounts, withDatabaseLock } from './locked-operations.js';
|
|
5
|
+
import { deduplicateAccounts, mergeAccounts, withDatabaseLock, withDatabaseLockSync } from './locked-operations.js';
|
|
6
6
|
import { runMigrations } from './migrations.js';
|
|
7
7
|
function getBaseDir() {
|
|
8
8
|
const p = process.platform;
|
|
@@ -21,7 +21,7 @@ export class KiroDatabase {
|
|
|
21
21
|
mkdirSync(dir, { recursive: true });
|
|
22
22
|
this.db = new Database(path);
|
|
23
23
|
this.db.pragma('busy_timeout = 5000');
|
|
24
|
-
this.init();
|
|
24
|
+
withDatabaseLockSync(this.path, () => this.init());
|
|
25
25
|
}
|
|
26
26
|
init() {
|
|
27
27
|
this.db.pragma('journal_mode = WAL');
|
|
@@ -185,6 +185,14 @@ export class KiroDatabase {
|
|
|
185
185
|
async listRemovedAccounts() {
|
|
186
186
|
return this.db.prepare('SELECT id FROM removed_accounts').all().map((r) => r.id);
|
|
187
187
|
}
|
|
188
|
+
async nextAssignmentIndex() {
|
|
189
|
+
return withDatabaseLock(this.path, async () => {
|
|
190
|
+
const row = this.db
|
|
191
|
+
.prepare("INSERT INTO plugin_meta(key,value) VALUES('assignment_cursor',0) ON CONFLICT(key) DO UPDATE SET value=value+1 RETURNING value")
|
|
192
|
+
.get();
|
|
193
|
+
return row?.value ?? 0;
|
|
194
|
+
});
|
|
195
|
+
}
|
|
188
196
|
async markAccountsUnhealthy(ids, reason) {
|
|
189
197
|
if (ids.length === 0)
|
|
190
198
|
return;
|
package/dist/plugin.js
CHANGED
|
@@ -52,7 +52,9 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
|
|
|
52
52
|
quotaAvoidanceEnabled: config.quota_avoidance_enabled,
|
|
53
53
|
quotaReserveThreshold: config.quota_reserve_threshold,
|
|
54
54
|
stopOnOverage: config.stop_on_overage,
|
|
55
|
-
overageThreshold: config.overage_threshold
|
|
55
|
+
overageThreshold: config.overage_threshold,
|
|
56
|
+
distributeAcrossProcesses: config.distribute_across_processes,
|
|
57
|
+
perRequestSpread: config.per_request_spread
|
|
56
58
|
});
|
|
57
59
|
authHandler.setAccountManager(accountManager);
|
|
58
60
|
const requestHandler = new RequestHandler(accountManager, config, repository, client);
|
|
@@ -257,6 +259,21 @@ export const createKiroPlugin = (id) => async ({ client, directory }) => {
|
|
|
257
259
|
name: 'Qwen3 Coder Next (0.05x)',
|
|
258
260
|
limit: { context: 256000, output: 64000 },
|
|
259
261
|
modalities: { input: ['text'], output: ['text'] }
|
|
262
|
+
},
|
|
263
|
+
'gpt-5.6-sol': {
|
|
264
|
+
name: 'GPT 5.6 Sol (2.4x)',
|
|
265
|
+
limit: { context: 272000, output: 64000 },
|
|
266
|
+
modalities: { input: ['text'], output: ['text'] }
|
|
267
|
+
},
|
|
268
|
+
'gpt-5.6-terra': {
|
|
269
|
+
name: 'GPT 5.6 Terra (1.2x)',
|
|
270
|
+
limit: { context: 272000, output: 64000 },
|
|
271
|
+
modalities: { input: ['text'], output: ['text'] }
|
|
272
|
+
},
|
|
273
|
+
'gpt-5.6-luna': {
|
|
274
|
+
name: 'GPT 5.6 Luna',
|
|
275
|
+
limit: { context: 272000, output: 64000 },
|
|
276
|
+
modalities: { input: ['text'], output: ['text'] }
|
|
260
277
|
}
|
|
261
278
|
};
|
|
262
279
|
}
|