@sunerpy/opencode-kiro-auth 0.3.0 → 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 +7 -0
- package/dist/core/auth/idc-auth-method.js +3 -0
- package/dist/plugin/accounts.js +5 -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
|
|
@@ -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) {
|
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)
|
|
@@ -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) {
|