@sunerpy/opencode-kiro-auth 0.2.2 → 0.4.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 +13 -0
- package/dist/core/auth/idc-auth-method.js +3 -0
- package/dist/core/request/request-handler.js +22 -0
- package/dist/plugin/accounts.js +5 -0
- package/dist/plugin/config/schema.d.ts +9 -0
- package/dist/plugin/config/schema.js +8 -0
- package/dist/plugin/storage/migrations.js +6 -0
- package/dist/plugin/storage/sqlite.d.ts +4 -0
- package/dist/plugin/storage/sqlite.js +18 -0
- package/dist/plugin/sync/kiro-cli.js +10 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -136,6 +136,13 @@ avoid a hot loop.
|
|
|
136
136
|
choose "Remove a Kiro account (N stored)", then pick the account from the
|
|
137
137
|
dropdown (or cancel).
|
|
138
138
|
|
|
139
|
+
> **Note:** removal is persistent. Once you remove an account it stays
|
|
140
|
+
> removed across restarts and Kiro CLI auto-sync — it won't come back on its
|
|
141
|
+
> own. To re-add it, just log in with that account again via
|
|
142
|
+
> `opencode auth login`. See
|
|
143
|
+
> [Removing accounts & the removal tombstone](docs/CONFIGURATION.md#removing-accounts--the-removal-tombstone)
|
|
144
|
+
> for how this works.
|
|
145
|
+
|
|
139
146
|
Full config key reference: [docs/CONFIGURATION.md](docs/CONFIGURATION.md).
|
|
140
147
|
|
|
141
148
|
## Usage display
|
|
@@ -179,6 +186,12 @@ Thinking budgets map to Kiro's native `effort` field automatically:
|
|
|
179
186
|
|
|
180
187
|
Details and the full JSON example: [docs/MODELS.md](docs/MODELS.md).
|
|
181
188
|
|
|
189
|
+
> **Note:** OpenCode's per-agent thinking level (`--variant` / an agent's
|
|
190
|
+
> `variant` in `oh-my-openagent.json`) isn't honored per agent by this
|
|
191
|
+
> plugin — OpenCode consumes it upstream. Use the global `effort` key in
|
|
192
|
+
> `kiro.json` instead. See
|
|
193
|
+
> [Reasoning effort](docs/CONFIGURATION.md#reasoning-effort) for details.
|
|
194
|
+
|
|
182
195
|
## Troubleshooting
|
|
183
196
|
|
|
184
197
|
Common issues — 403/AccessDeniedException with IAM Identity Center, "No
|
|
@@ -3,6 +3,7 @@ import { extractRegionFromArn, normalizeRegion } from '../../constants.js';
|
|
|
3
3
|
import { authorizeKiroIDC, pollKiroIDCToken } from '../../kiro/oauth-idc.js';
|
|
4
4
|
import { createDeterministicAccountId } from '../../plugin/accounts.js';
|
|
5
5
|
import * as logger from '../../plugin/logger.js';
|
|
6
|
+
import { kiroDb } from '../../plugin/storage/sqlite.js';
|
|
6
7
|
import { makePlaceholderEmail } from '../../plugin/sync/kiro-cli-parser.js';
|
|
7
8
|
import { readActiveProfileArnFromKiroCli } from '../../plugin/sync/kiro-cli-profile.js';
|
|
8
9
|
import { fetchUsageLimits } from '../../plugin/usage.js';
|
|
@@ -156,6 +157,8 @@ export class IdcAuthMethod {
|
|
|
156
157
|
};
|
|
157
158
|
await this.repository.save(acc);
|
|
158
159
|
this.accountManager?.addAccount?.(acc);
|
|
160
|
+
// clear tombstone ONLY on deliberate user login; never in auto-sync (would revive removed accounts)
|
|
161
|
+
await kiroDb.clearRemovedAccount(id);
|
|
159
162
|
return { type: 'success', key: token.accessToken };
|
|
160
163
|
}
|
|
161
164
|
catch (e) {
|
|
@@ -106,6 +106,28 @@ export class RequestHandler {
|
|
|
106
106
|
continue;
|
|
107
107
|
}
|
|
108
108
|
const sdkPrep = this.prepareSdkRequest(init?.body, model, auth, think, budget, showToast);
|
|
109
|
+
if (this.config.enable_log_effort_debug) {
|
|
110
|
+
try {
|
|
111
|
+
logger.log('[effort-debug] request effort resolution', {
|
|
112
|
+
model,
|
|
113
|
+
effectiveModel: sdkPrep.effectiveModel,
|
|
114
|
+
think,
|
|
115
|
+
budget,
|
|
116
|
+
resolvedEffort: sdkPrep.effort ?? 'undefined (not effort-capable or not thinking)',
|
|
117
|
+
inboundBodyKeys: Object.keys(body),
|
|
118
|
+
messagesCount: body.messages?.length,
|
|
119
|
+
reasoningSubtree: {
|
|
120
|
+
reasoningEffort: body.reasoningEffort,
|
|
121
|
+
reasoning_effort: body.reasoning_effort,
|
|
122
|
+
reasoning: body.reasoning,
|
|
123
|
+
providerOptions: body.providerOptions,
|
|
124
|
+
thinkingConfig: body.thinkingConfig,
|
|
125
|
+
providerOptionsThinkingConfig: body.providerOptions?.thinkingConfig
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch (e) { }
|
|
130
|
+
}
|
|
109
131
|
const apiTimestamp = this.config.enable_log_api_request ? logger.getTimestamp() : null;
|
|
110
132
|
if (apiTimestamp) {
|
|
111
133
|
this.logSdkRequest(sdkPrep, acc, apiTimestamp);
|
package/dist/plugin/accounts.js
CHANGED
|
@@ -160,6 +160,11 @@ export class AccountManager {
|
|
|
160
160
|
email: a.email,
|
|
161
161
|
error: e instanceof Error ? e.message : String(e)
|
|
162
162
|
}));
|
|
163
|
+
kiroDb.addRemovedAccount(a.id).catch((e) => logger.warn('DB write failed', {
|
|
164
|
+
method: 'removeAccount:tombstone',
|
|
165
|
+
email: a.email,
|
|
166
|
+
error: e instanceof Error ? e.message : String(e)
|
|
167
|
+
}));
|
|
163
168
|
if (this.accounts.length === 0)
|
|
164
169
|
this.cursor = 0;
|
|
165
170
|
else if (this.cursor >= this.accounts.length)
|
|
@@ -31,6 +31,13 @@ export declare const KiroConfigSchema: z.ZodObject<{
|
|
|
31
31
|
usage_tracking_enabled: z.ZodDefault<z.ZodBoolean>;
|
|
32
32
|
auto_sync_kiro_cli: z.ZodDefault<z.ZodBoolean>;
|
|
33
33
|
enable_log_api_request: z.ZodDefault<z.ZodBoolean>;
|
|
34
|
+
/**
|
|
35
|
+
* Enable config-gated debug logging that records the inbound
|
|
36
|
+
* OpenAI-compatible request body shape (top-level keys, reasoning-related
|
|
37
|
+
* fields only — no message content) and the resolved Kiro effort for each
|
|
38
|
+
* request. Independent from `enable_log_api_request`; off by default.
|
|
39
|
+
*/
|
|
40
|
+
enable_log_effort_debug: z.ZodDefault<z.ZodBoolean>;
|
|
34
41
|
/**
|
|
35
42
|
* Default effort level for thinking models. Controls reasoning depth.
|
|
36
43
|
* When set, this overrides the automatic budget-based mapping.
|
|
@@ -57,6 +64,7 @@ export declare const KiroConfigSchema: z.ZodObject<{
|
|
|
57
64
|
usage_tracking_enabled: boolean;
|
|
58
65
|
auto_sync_kiro_cli: boolean;
|
|
59
66
|
enable_log_api_request: boolean;
|
|
67
|
+
enable_log_effort_debug: boolean;
|
|
60
68
|
auto_effort_mapping: boolean;
|
|
61
69
|
$schema?: string | undefined;
|
|
62
70
|
idc_start_url?: string | undefined;
|
|
@@ -81,6 +89,7 @@ export declare const KiroConfigSchema: z.ZodObject<{
|
|
|
81
89
|
usage_tracking_enabled?: boolean | undefined;
|
|
82
90
|
auto_sync_kiro_cli?: boolean | undefined;
|
|
83
91
|
enable_log_api_request?: boolean | undefined;
|
|
92
|
+
enable_log_effort_debug?: boolean | undefined;
|
|
84
93
|
effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
|
|
85
94
|
auto_effort_mapping?: boolean | undefined;
|
|
86
95
|
}>;
|
|
@@ -63,6 +63,13 @@ export const KiroConfigSchema = z.object({
|
|
|
63
63
|
usage_tracking_enabled: z.boolean().default(true),
|
|
64
64
|
auto_sync_kiro_cli: z.boolean().default(true),
|
|
65
65
|
enable_log_api_request: z.boolean().default(false),
|
|
66
|
+
/**
|
|
67
|
+
* Enable config-gated debug logging that records the inbound
|
|
68
|
+
* OpenAI-compatible request body shape (top-level keys, reasoning-related
|
|
69
|
+
* fields only — no message content) and the resolved Kiro effort for each
|
|
70
|
+
* request. Independent from `enable_log_api_request`; off by default.
|
|
71
|
+
*/
|
|
72
|
+
enable_log_effort_debug: z.boolean().default(false),
|
|
66
73
|
/**
|
|
67
74
|
* Default effort level for thinking models. Controls reasoning depth.
|
|
68
75
|
* When set, this overrides the automatic budget-based mapping.
|
|
@@ -90,5 +97,6 @@ export const DEFAULT_CONFIG = {
|
|
|
90
97
|
usage_tracking_enabled: true,
|
|
91
98
|
auto_sync_kiro_cli: true,
|
|
92
99
|
enable_log_api_request: false,
|
|
100
|
+
enable_log_effort_debug: false,
|
|
93
101
|
auto_effort_mapping: true
|
|
94
102
|
};
|
|
@@ -5,6 +5,7 @@ export function runMigrations(db) {
|
|
|
5
5
|
migrateStartUrlColumn(db);
|
|
6
6
|
migrateOidcRegionColumn(db);
|
|
7
7
|
migrateDropRefreshTokenUniqueIndex(db);
|
|
8
|
+
migrateRemovedAccountsTable(db);
|
|
8
9
|
}
|
|
9
10
|
function migrateToUniqueRefreshToken(db) {
|
|
10
11
|
const hasIndex = db
|
|
@@ -153,3 +154,8 @@ function migrateDropRefreshTokenUniqueIndex(db) {
|
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
}
|
|
157
|
+
function migrateRemovedAccountsTable(db) {
|
|
158
|
+
// Tombstone table: records account ids the user explicitly removed via the auth menu,
|
|
159
|
+
// so kiro-cli auto-sync does not silently re-import them. Cleared only on deliberate login.
|
|
160
|
+
db.exec('CREATE TABLE IF NOT EXISTS removed_accounts (id TEXT PRIMARY KEY, removed_at INTEGER NOT NULL)');
|
|
161
|
+
}
|
|
@@ -10,6 +10,10 @@ export declare class KiroDatabase {
|
|
|
10
10
|
upsertAccount(acc: ManagedAccount): Promise<void>;
|
|
11
11
|
batchUpsertAccounts(accounts: ManagedAccount[]): Promise<void>;
|
|
12
12
|
deleteAccount(id: string): Promise<void>;
|
|
13
|
+
addRemovedAccount(id: string): Promise<void>;
|
|
14
|
+
isAccountRemoved(id: string): Promise<boolean>;
|
|
15
|
+
clearRemovedAccount(id: string): Promise<void>;
|
|
16
|
+
listRemovedAccounts(): Promise<string[]>;
|
|
13
17
|
markAccountsUnhealthy(ids: string[], reason: string): Promise<void>;
|
|
14
18
|
private rowToAccount;
|
|
15
19
|
close(): void;
|
|
@@ -103,6 +103,24 @@ export class KiroDatabase {
|
|
|
103
103
|
this.db.prepare('DELETE FROM accounts WHERE id = ?').run(id);
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
|
+
async addRemovedAccount(id) {
|
|
107
|
+
await withDatabaseLock(this.path, async () => {
|
|
108
|
+
this.db
|
|
109
|
+
.prepare('INSERT OR REPLACE INTO removed_accounts (id, removed_at) VALUES (?, ?)')
|
|
110
|
+
.run(id, Date.now());
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async isAccountRemoved(id) {
|
|
114
|
+
return !!this.db.prepare('SELECT id FROM removed_accounts WHERE id = ?').get(id);
|
|
115
|
+
}
|
|
116
|
+
async clearRemovedAccount(id) {
|
|
117
|
+
await withDatabaseLock(this.path, async () => {
|
|
118
|
+
this.db.prepare('DELETE FROM removed_accounts WHERE id = ?').run(id);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
async listRemovedAccounts() {
|
|
122
|
+
return this.db.prepare('SELECT id FROM removed_accounts').all().map((r) => r.id);
|
|
123
|
+
}
|
|
106
124
|
async markAccountsUnhealthy(ids, reason) {
|
|
107
125
|
if (ids.length === 0)
|
|
108
126
|
return;
|
|
@@ -33,6 +33,7 @@ export async function syncFromKiroCli() {
|
|
|
33
33
|
const deviceReg = safeJsonParse(deviceRegRow?.value);
|
|
34
34
|
const regCreds = deviceReg ? findClientCredsRecursive(deviceReg) : {};
|
|
35
35
|
const syncedAccounts = [];
|
|
36
|
+
let skippedRemoved = 0;
|
|
36
37
|
for (const row of rows) {
|
|
37
38
|
if (row.key.includes(':token')) {
|
|
38
39
|
const data = safeJsonParse(row.value);
|
|
@@ -122,7 +123,10 @@ export async function syncFromKiroCli() {
|
|
|
122
123
|
const placeholderId = createDeterministicAccountId(placeholderEmail, authMethod, clientId, profileArn);
|
|
123
124
|
if (placeholderId !== id) {
|
|
124
125
|
const placeholderRow = all.find((a) => a.id === placeholderId);
|
|
125
|
-
if (placeholderRow) {
|
|
126
|
+
if (placeholderRow && (await kiroDb.isAccountRemoved(placeholderId))) {
|
|
127
|
+
skippedRemoved++;
|
|
128
|
+
}
|
|
129
|
+
else if (placeholderRow) {
|
|
126
130
|
await kiroDb.upsertAccount({
|
|
127
131
|
id: placeholderId,
|
|
128
132
|
email: placeholderRow.email,
|
|
@@ -147,6 +151,10 @@ export async function syncFromKiroCli() {
|
|
|
147
151
|
}
|
|
148
152
|
}
|
|
149
153
|
}
|
|
154
|
+
if (await kiroDb.isAccountRemoved(id)) {
|
|
155
|
+
skippedRemoved++;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
150
158
|
await kiroDb.upsertAccount({
|
|
151
159
|
id,
|
|
152
160
|
email: resolvedEmail,
|
|
@@ -181,6 +189,7 @@ export async function syncFromKiroCli() {
|
|
|
181
189
|
await kiroDb.markAccountsUnhealthy(staleIds, STALE_CLI_ACCOUNT_REASON);
|
|
182
190
|
logger.warn('Kiro CLI sync: deactivated stale cached accounts', { count: staleIds.length });
|
|
183
191
|
}
|
|
192
|
+
logger.log('Kiro CLI sync: done', { synced: syncedAccounts.length, skippedRemoved });
|
|
184
193
|
cliDb.close();
|
|
185
194
|
}
|
|
186
195
|
catch (e) {
|