@kervnet/opencode-kiro-auth 1.5.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.
Files changed (106) hide show
  1. package/README.md +159 -0
  2. package/dist/constants.d.ts +24 -0
  3. package/dist/constants.js +55 -0
  4. package/dist/core/account/account-selector.d.ts +25 -0
  5. package/dist/core/account/account-selector.js +84 -0
  6. package/dist/core/account/usage-tracker.d.ts +17 -0
  7. package/dist/core/account/usage-tracker.js +39 -0
  8. package/dist/core/auth/auth-handler.d.ts +15 -0
  9. package/dist/core/auth/auth-handler.js +43 -0
  10. package/dist/core/auth/idc-auth-method.d.ts +17 -0
  11. package/dist/core/auth/idc-auth-method.js +200 -0
  12. package/dist/core/auth/token-refresher.d.ts +22 -0
  13. package/dist/core/auth/token-refresher.js +53 -0
  14. package/dist/core/index.d.ts +9 -0
  15. package/dist/core/index.js +9 -0
  16. package/dist/core/request/error-handler.d.ts +30 -0
  17. package/dist/core/request/error-handler.js +113 -0
  18. package/dist/core/request/request-handler.d.ts +27 -0
  19. package/dist/core/request/request-handler.js +199 -0
  20. package/dist/core/request/response-handler.d.ts +5 -0
  21. package/dist/core/request/response-handler.js +61 -0
  22. package/dist/core/request/retry-strategy.d.ts +18 -0
  23. package/dist/core/request/retry-strategy.js +28 -0
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.js +1 -0
  26. package/dist/infrastructure/database/account-cache.d.ts +14 -0
  27. package/dist/infrastructure/database/account-cache.js +44 -0
  28. package/dist/infrastructure/database/account-repository.d.ts +12 -0
  29. package/dist/infrastructure/database/account-repository.js +64 -0
  30. package/dist/infrastructure/index.d.ts +7 -0
  31. package/dist/infrastructure/index.js +7 -0
  32. package/dist/infrastructure/transformers/event-stream-parser.d.ts +7 -0
  33. package/dist/infrastructure/transformers/event-stream-parser.js +115 -0
  34. package/dist/infrastructure/transformers/history-builder.d.ts +5 -0
  35. package/dist/infrastructure/transformers/history-builder.js +171 -0
  36. package/dist/infrastructure/transformers/message-transformer.d.ts +6 -0
  37. package/dist/infrastructure/transformers/message-transformer.js +102 -0
  38. package/dist/infrastructure/transformers/tool-call-parser.d.ts +4 -0
  39. package/dist/infrastructure/transformers/tool-call-parser.js +45 -0
  40. package/dist/infrastructure/transformers/tool-transformer.d.ts +2 -0
  41. package/dist/infrastructure/transformers/tool-transformer.js +19 -0
  42. package/dist/kiro/auth.d.ts +4 -0
  43. package/dist/kiro/auth.js +25 -0
  44. package/dist/kiro/oauth-idc.d.ts +24 -0
  45. package/dist/kiro/oauth-idc.js +151 -0
  46. package/dist/plugin/accounts.d.ts +29 -0
  47. package/dist/plugin/accounts.js +235 -0
  48. package/dist/plugin/auth-page.d.ts +3 -0
  49. package/dist/plugin/auth-page.js +573 -0
  50. package/dist/plugin/cli.d.ts +8 -0
  51. package/dist/plugin/cli.js +103 -0
  52. package/dist/plugin/config/index.d.ts +3 -0
  53. package/dist/plugin/config/index.js +2 -0
  54. package/dist/plugin/config/loader.d.ts +6 -0
  55. package/dist/plugin/config/loader.js +129 -0
  56. package/dist/plugin/config/schema.d.ts +56 -0
  57. package/dist/plugin/config/schema.js +36 -0
  58. package/dist/plugin/errors.d.ts +17 -0
  59. package/dist/plugin/errors.js +34 -0
  60. package/dist/plugin/health.d.ts +1 -0
  61. package/dist/plugin/health.js +9 -0
  62. package/dist/plugin/image-handler.d.ts +14 -0
  63. package/dist/plugin/image-handler.js +64 -0
  64. package/dist/plugin/logger.d.ts +8 -0
  65. package/dist/plugin/logger.js +63 -0
  66. package/dist/plugin/models.d.ts +1 -0
  67. package/dist/plugin/models.js +8 -0
  68. package/dist/plugin/request.d.ts +2 -0
  69. package/dist/plugin/request.js +239 -0
  70. package/dist/plugin/response.d.ts +3 -0
  71. package/dist/plugin/response.js +95 -0
  72. package/dist/plugin/server.d.ts +24 -0
  73. package/dist/plugin/server.js +166 -0
  74. package/dist/plugin/storage/locked-operations.d.ts +5 -0
  75. package/dist/plugin/storage/locked-operations.js +91 -0
  76. package/dist/plugin/storage/migrations.d.ts +2 -0
  77. package/dist/plugin/storage/migrations.js +109 -0
  78. package/dist/plugin/storage/sqlite.d.ts +17 -0
  79. package/dist/plugin/storage/sqlite.js +134 -0
  80. package/dist/plugin/streaming/index.d.ts +2 -0
  81. package/dist/plugin/streaming/index.js +2 -0
  82. package/dist/plugin/streaming/openai-converter.d.ts +2 -0
  83. package/dist/plugin/streaming/openai-converter.js +68 -0
  84. package/dist/plugin/streaming/stream-parser.d.ts +5 -0
  85. package/dist/plugin/streaming/stream-parser.js +136 -0
  86. package/dist/plugin/streaming/stream-state.d.ts +5 -0
  87. package/dist/plugin/streaming/stream-state.js +59 -0
  88. package/dist/plugin/streaming/stream-transformer.d.ts +1 -0
  89. package/dist/plugin/streaming/stream-transformer.js +248 -0
  90. package/dist/plugin/streaming/types.d.ts +25 -0
  91. package/dist/plugin/streaming/types.js +2 -0
  92. package/dist/plugin/sync/aws-sso.d.ts +2 -0
  93. package/dist/plugin/sync/aws-sso.js +50 -0
  94. package/dist/plugin/sync/kiro-cli-parser.d.ts +8 -0
  95. package/dist/plugin/sync/kiro-cli-parser.js +72 -0
  96. package/dist/plugin/sync/kiro-cli.d.ts +2 -0
  97. package/dist/plugin/sync/kiro-cli.js +197 -0
  98. package/dist/plugin/token.d.ts +2 -0
  99. package/dist/plugin/token.js +79 -0
  100. package/dist/plugin/types.d.ts +109 -0
  101. package/dist/plugin/types.js +0 -0
  102. package/dist/plugin/usage.d.ts +3 -0
  103. package/dist/plugin/usage.js +45 -0
  104. package/dist/plugin.d.ts +32 -0
  105. package/dist/plugin.js +37 -0
  106. package/package.json +65 -0
package/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # OpenCode Kiro Auth Plugin
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@zhafron/opencode-kiro-auth)](https://www.npmjs.com/package/@zhafron/opencode-kiro-auth)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@zhafron/opencode-kiro-auth)](https://www.npmjs.com/package/@zhafron/opencode-kiro-auth)
5
+ [![license](https://img.shields.io/npm/l/@zhafron/opencode-kiro-auth)](https://www.npmjs.com/package/@zhafron/opencode-kiro-auth)
6
+
7
+ OpenCode plugin for AWS Kiro (CodeWhisperer) providing access to Claude Sonnet and Haiku models with substantial trial quotas.
8
+
9
+ ## Features
10
+
11
+ - **Multiple Auth Methods**: Supports AWS Builder ID (IDC), Kiro Desktop (CLI-based), and AWS SSO authentication.
12
+ - **Auto-Sync Kiro CLI**: Automatically imports and synchronizes active sessions from your local `kiro-cli` SQLite database.
13
+ - **Auto-Sync AWS SSO**: Automatically imports credentials from `~/.aws/sso/cache` for seamless integration with AWS profiles.
14
+ - **Gradual Context Truncation**: Intelligently prevents error 400 by reducing context size dynamically during retries.
15
+ - **Intelligent Account Rotation**: Prioritizes multi-account usage based on lowest available quota.
16
+ - **High-Performance Storage**: Efficient account and usage management using native Bun SQLite.
17
+ - **Native Thinking Mode**: Full support for Claude reasoning capabilities via virtual model mappings.
18
+ - **Automated Recovery**: Exponential backoff for rate limits and automated token refresh.
19
+
20
+ ## Installation
21
+
22
+ Add the plugin to your `opencode.json` or `opencode.jsonc`:
23
+
24
+ ```json
25
+ {
26
+ "plugin": ["@zhafron/opencode-kiro-auth"],
27
+ "provider": {
28
+ "kiro": {
29
+ "models": {
30
+ "claude-sonnet-4-5": {
31
+ "name": "Claude Sonnet 4.5",
32
+ "limit": { "context": 200000, "output": 64000 },
33
+ "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
34
+ },
35
+ "claude-sonnet-4-5-thinking": {
36
+ "name": "Claude Sonnet 4.5 Thinking",
37
+ "limit": { "context": 200000, "output": 64000 },
38
+ "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] },
39
+ "variants": {
40
+ "low": { "thinkingConfig": { "thinkingBudget": 8192 } },
41
+ "medium": { "thinkingConfig": { "thinkingBudget": 16384 } },
42
+ "max": { "thinkingConfig": { "thinkingBudget": 32768 } }
43
+ }
44
+ },
45
+ "claude-haiku-4-5": {
46
+ "name": "Claude Haiku 4.5",
47
+ "limit": { "context": 200000, "output": 64000 },
48
+ "modalities": { "input": ["text", "image"], "output": ["text"] }
49
+ },
50
+ "claude-opus-4-5": {
51
+ "name": "Claude Opus 4.5",
52
+ "limit": { "context": 200000, "output": 64000 },
53
+ "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] }
54
+ },
55
+ "claude-opus-4-5-thinking": {
56
+ "name": "Claude Opus 4.5 Thinking",
57
+ "limit": { "context": 200000, "output": 64000 },
58
+ "modalities": { "input": ["text", "image", "pdf"], "output": ["text"] },
59
+ "variants": {
60
+ "low": { "thinkingConfig": { "thinkingBudget": 8192 } },
61
+ "medium": { "thinkingConfig": { "thinkingBudget": 16384 } },
62
+ "max": { "thinkingConfig": { "thinkingBudget": 32768 } }
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ ## Setup
72
+
73
+ 1. **Authentication via Kiro CLI (Recommended)**:
74
+ - Perform login directly in your terminal using `kiro-cli login`.
75
+ - The plugin will automatically detect and import your session on startup.
76
+ - For AWS IAM Identity Center (SSO/IDC), the plugin imports both the token and device registration (OIDC client credentials) from the `kiro-cli` database.
77
+ 2. **Authentication via AWS SSO**:
78
+ - Ensure you have AWS SSO configured in `~/.aws/config` with active sessions.
79
+ - The plugin automatically imports credentials from `~/.aws/sso/cache` on startup.
80
+ - No additional configuration needed - just use your existing AWS SSO profiles.
81
+ 3. **Direct Authentication**:
82
+ - Run `opencode auth login`.
83
+ - Select `Other`, type `kiro`, and press enter.
84
+ - Follow the instructions for **AWS Builder ID (IDC)**.
85
+ 4. Configuration will be automatically managed at `~/.config/opencode/kiro.db`.
86
+
87
+ ## Troubleshooting
88
+
89
+ ### Error: No accounts
90
+
91
+ This happens when the plugin has no records in `~/.config/opencode/kiro.db`.
92
+
93
+ 1. Ensure `kiro-cli login` succeeds.
94
+ 2. Ensure `auto_sync_kiro_cli` is `true` in `~/.config/opencode/kiro.json`.
95
+ 3. Retry the request; the plugin will attempt a Kiro CLI sync when it detects zero accounts.
96
+
97
+ Note for IDC/SSO (ODIC): the plugin may temporarily create an account with a placeholder email if it cannot fetch the real email during sync (e.g. offline). It will replace it with the real email once usage/email lookup succeeds.
98
+
99
+ ## Configuration
100
+
101
+ The plugin supports extensive configuration options. Edit `~/.config/opencode/kiro.json`:
102
+
103
+ ```json
104
+ {
105
+ "auto_sync_kiro_cli": true,
106
+ "auto_sync_aws_sso": true,
107
+ "account_selection_strategy": "lowest-usage",
108
+ "default_region": "us-east-1",
109
+ "rate_limit_retry_delay_ms": 5000,
110
+ "rate_limit_max_retries": 3,
111
+ "max_request_iterations": 20,
112
+ "request_timeout_ms": 120000,
113
+ "token_expiry_buffer_ms": 120000,
114
+ "usage_sync_max_retries": 3,
115
+ "auth_server_port_start": 19847,
116
+ "auth_server_port_range": 10,
117
+ "usage_tracking_enabled": true,
118
+ "enable_log_api_request": false
119
+ }
120
+ ```
121
+
122
+ ### Configuration Options
123
+
124
+ - `auto_sync_kiro_cli`: Automatically sync sessions from Kiro CLI (default: `true`).
125
+ - `auto_sync_aws_sso`: Automatically sync credentials from AWS SSO cache (default: `true`).
126
+ - `account_selection_strategy`: Account rotation strategy (`sticky`, `round-robin`, `lowest-usage`).
127
+ - `default_region`: AWS region (`us-east-1`, `us-west-2`).
128
+ - `rate_limit_retry_delay_ms`: Delay between rate limit retries (1000-60000ms).
129
+ - `rate_limit_max_retries`: Maximum retry attempts for rate limits (0-10).
130
+ - `max_request_iterations`: Maximum loop iterations to prevent hangs (10-1000).
131
+ - `request_timeout_ms`: Request timeout in milliseconds (60000-600000ms).
132
+ - `token_expiry_buffer_ms`: Token refresh buffer time (30000-300000ms).
133
+ - `usage_sync_max_retries`: Retry attempts for usage sync (0-5).
134
+ - `auth_server_port_start`: Starting port for auth server (1024-65535).
135
+ - `auth_server_port_range`: Number of ports to try (1-100).
136
+ - `usage_tracking_enabled`: Enable usage tracking and toast notifications.
137
+ - `enable_log_api_request`: Enable detailed API request logging.
138
+
139
+ ## Storage
140
+
141
+ **Linux/macOS:**
142
+
143
+ - SQLite Database: `~/.config/opencode/kiro.db`
144
+ - Plugin Config: `~/.config/opencode/kiro.json`
145
+
146
+ **Windows:**
147
+
148
+ - SQLite Database: `%APPDATA%\opencode\kiro.db`
149
+ - Plugin Config: `%APPDATA%\opencode\kiro.json`
150
+
151
+ ## Acknowledgements
152
+
153
+ Special thanks to [AIClient-2-API](https://github.com/justlovemaki/AIClient-2-API) for providing the foundational Kiro authentication logic and request patterns.
154
+
155
+ ## Disclaimer
156
+
157
+ This plugin is provided strictly for learning and educational purposes. It is an independent implementation and is not affiliated with, endorsed by, or supported by Amazon Web Services (AWS) or Anthropic. Use of this plugin is at your own risk.
158
+
159
+ Feel free to open a PR to optimize this plugin further.
@@ -0,0 +1,24 @@
1
+ import type { KiroRegion } from './plugin/types';
2
+ export declare function isValidRegion(region: string): region is KiroRegion;
3
+ export declare function normalizeRegion(region: string | undefined): KiroRegion;
4
+ export declare function buildUrl(template: string, region: KiroRegion): string;
5
+ export declare const KIRO_CONSTANTS: {
6
+ REFRESH_URL: string;
7
+ REFRESH_IDC_URL: string;
8
+ BASE_URL: string;
9
+ USAGE_LIMITS_URL: string;
10
+ DEFAULT_REGION: KiroRegion;
11
+ AXIOS_TIMEOUT: number;
12
+ USER_AGENT: string;
13
+ KIRO_VERSION: string;
14
+ CHAT_TRIGGER_TYPE_MANUAL: string;
15
+ ORIGIN_AI_EDITOR: string;
16
+ };
17
+ export declare const MODEL_MAPPING: Record<string, string>;
18
+ export declare const SUPPORTED_MODELS: string[];
19
+ export declare const KIRO_AUTH_SERVICE: {
20
+ ENDPOINT: string;
21
+ SSO_OIDC_ENDPOINT: string;
22
+ BUILDER_ID_START_URL: string;
23
+ SCOPES: string[];
24
+ };
@@ -0,0 +1,55 @@
1
+ const VALID_REGIONS = ['us-east-1', 'us-west-2'];
2
+ export function isValidRegion(region) {
3
+ return VALID_REGIONS.includes(region);
4
+ }
5
+ export function normalizeRegion(region) {
6
+ if (!region || !isValidRegion(region)) {
7
+ return 'us-east-1';
8
+ }
9
+ return region;
10
+ }
11
+ export function buildUrl(template, region) {
12
+ const url = template.replace('{{region}}', region);
13
+ try {
14
+ new URL(url);
15
+ return url;
16
+ }
17
+ catch {
18
+ throw new Error(`Invalid URL generated: ${url}`);
19
+ }
20
+ }
21
+ export const KIRO_CONSTANTS = {
22
+ REFRESH_URL: 'https://prod.{{region}}.auth.desktop.kiro.dev/refreshToken',
23
+ REFRESH_IDC_URL: 'https://oidc.{{region}}.amazonaws.com/token',
24
+ BASE_URL: 'https://q.{{region}}.amazonaws.com/generateAssistantResponse',
25
+ USAGE_LIMITS_URL: 'https://q.{{region}}.amazonaws.com/getUsageLimits',
26
+ DEFAULT_REGION: 'us-east-1',
27
+ AXIOS_TIMEOUT: 120000,
28
+ USER_AGENT: 'KiroIDE',
29
+ KIRO_VERSION: '0.7.5',
30
+ CHAT_TRIGGER_TYPE_MANUAL: 'MANUAL',
31
+ ORIGIN_AI_EDITOR: 'AI_EDITOR'
32
+ };
33
+ export const MODEL_MAPPING = {
34
+ 'claude-haiku-4-5': 'claude-haiku-4.5',
35
+ 'claude-sonnet-4-5': 'CLAUDE_SONNET_4_5_20250929_V1_0',
36
+ 'claude-sonnet-4-5-thinking': 'CLAUDE_SONNET_4_5_20250929_V1_0',
37
+ 'claude-sonnet-4-5-20250929': 'CLAUDE_SONNET_4_5_20250929_V1_0',
38
+ 'claude-opus-4-5': 'CLAUDE_OPUS_4_5_20251101_V1_0',
39
+ 'claude-opus-4-5-thinking': 'CLAUDE_OPUS_4_5_20251101_V1_0',
40
+ 'claude-sonnet-4-20250514': 'CLAUDE_SONNET_4_20250514_V1_0',
41
+ 'claude-3-7-sonnet-20250219': 'CLAUDE_3_7_SONNET_20250219_V1_0'
42
+ };
43
+ export const SUPPORTED_MODELS = Object.keys(MODEL_MAPPING);
44
+ export const KIRO_AUTH_SERVICE = {
45
+ ENDPOINT: 'https://prod.{{region}}.auth.desktop.kiro.dev',
46
+ SSO_OIDC_ENDPOINT: 'https://oidc.{{region}}.amazonaws.com',
47
+ BUILDER_ID_START_URL: 'https://view.awsapps.com/start',
48
+ SCOPES: [
49
+ 'codewhisperer:completions',
50
+ 'codewhisperer:analysis',
51
+ 'codewhisperer:conversations',
52
+ 'codewhisperer:transformations',
53
+ 'codewhisperer:taskassist'
54
+ ]
55
+ };
@@ -0,0 +1,25 @@
1
+ import type { AccountRepository } from '../../infrastructure/database/account-repository';
2
+ import type { AccountManager } from '../../plugin/accounts';
3
+ import type { ManagedAccount } from '../../plugin/types';
4
+ type ToastFunction = (message: string, variant: 'info' | 'warning' | 'success' | 'error') => void;
5
+ interface AccountSelectorConfig {
6
+ auto_sync_kiro_cli: boolean;
7
+ account_selection_strategy: 'sticky' | 'round-robin' | 'lowest-usage';
8
+ }
9
+ export declare class AccountSelector {
10
+ private accountManager;
11
+ private config;
12
+ private syncFromKiroCli;
13
+ private repository;
14
+ private triedEmptySync;
15
+ private circuitBreakerTrips;
16
+ private lastCircuitBreakerReset;
17
+ constructor(accountManager: AccountManager, config: AccountSelectorConfig, syncFromKiroCli: () => Promise<void>, repository: AccountRepository);
18
+ selectHealthyAccount(showToast: ToastFunction): Promise<ManagedAccount | null>;
19
+ private handleEmptyAccounts;
20
+ private formatUsageMessage;
21
+ private checkCircuitBreaker;
22
+ private resetCircuitBreaker;
23
+ private sleep;
24
+ }
25
+ export {};
@@ -0,0 +1,84 @@
1
+ export class AccountSelector {
2
+ accountManager;
3
+ config;
4
+ syncFromKiroCli;
5
+ repository;
6
+ triedEmptySync = false;
7
+ circuitBreakerTrips = 0;
8
+ lastCircuitBreakerReset = Date.now();
9
+ constructor(accountManager, config, syncFromKiroCli, repository) {
10
+ this.accountManager = accountManager;
11
+ this.config = config;
12
+ this.syncFromKiroCli = syncFromKiroCli;
13
+ this.repository = repository;
14
+ }
15
+ async selectHealthyAccount(showToast) {
16
+ this.checkCircuitBreaker();
17
+ let count = this.accountManager.getAccountCount();
18
+ if (count === 0 && this.config.auto_sync_kiro_cli && !this.triedEmptySync) {
19
+ this.triedEmptySync = true;
20
+ await this.handleEmptyAccounts();
21
+ count = this.accountManager.getAccountCount();
22
+ }
23
+ if (count === 0) {
24
+ throw new Error('No accounts');
25
+ }
26
+ let acc = this.accountManager.getCurrentOrNext();
27
+ if (!acc) {
28
+ this.circuitBreakerTrips++;
29
+ const wait = this.accountManager.getMinWaitTime();
30
+ if (wait > 0 && wait < 30000) {
31
+ if (this.accountManager.shouldShowToast()) {
32
+ showToast(`All accounts rate-limited. Waiting ${Math.ceil(wait / 1000)}s...`, 'warning');
33
+ }
34
+ await this.sleep(wait);
35
+ return null;
36
+ }
37
+ throw new Error('All accounts are unhealthy or rate-limited');
38
+ }
39
+ this.resetCircuitBreaker();
40
+ if (this.accountManager.shouldShowToast()) {
41
+ showToast(`Using ${acc.email} (${this.accountManager.getAccounts().indexOf(acc) + 1}/${count})`, 'info');
42
+ }
43
+ if (this.accountManager.shouldShowUsageToast() &&
44
+ acc.usedCount !== undefined &&
45
+ acc.limitCount !== undefined) {
46
+ const p = acc.limitCount > 0 ? (acc.usedCount / acc.limitCount) * 100 : 0;
47
+ showToast(this.formatUsageMessage(acc.usedCount, acc.limitCount, acc.email), p >= 80 ? 'warning' : 'info');
48
+ }
49
+ return acc;
50
+ }
51
+ async handleEmptyAccounts() {
52
+ await this.syncFromKiroCli();
53
+ this.repository.invalidateCache();
54
+ const accounts = await this.repository.findAll();
55
+ for (const a of accounts) {
56
+ this.accountManager.addAccount(a);
57
+ }
58
+ }
59
+ formatUsageMessage(usedCount, limitCount, email) {
60
+ if (limitCount > 0) {
61
+ const percentage = Math.round((usedCount / limitCount) * 100);
62
+ return `Usage (${email}): ${usedCount}/${limitCount} (${percentage}%)`;
63
+ }
64
+ return `Usage (${email}): ${usedCount}`;
65
+ }
66
+ checkCircuitBreaker() {
67
+ if (Date.now() - this.lastCircuitBreakerReset > 60000) {
68
+ this.circuitBreakerTrips = 0;
69
+ this.lastCircuitBreakerReset = Date.now();
70
+ }
71
+ if (this.circuitBreakerTrips >= 10) {
72
+ throw new Error('Circuit breaker tripped: Too many consecutive failures selecting accounts');
73
+ }
74
+ }
75
+ resetCircuitBreaker() {
76
+ if (this.circuitBreakerTrips > 0) {
77
+ this.circuitBreakerTrips = 0;
78
+ this.lastCircuitBreakerReset = Date.now();
79
+ }
80
+ }
81
+ sleep(ms) {
82
+ return new Promise((r) => setTimeout(r, ms));
83
+ }
84
+ }
@@ -0,0 +1,17 @@
1
+ import type { AccountRepository } from '../../infrastructure/database/account-repository';
2
+ import type { AccountManager } from '../../plugin/accounts';
3
+ import type { KiroAuthDetails, ManagedAccount } from '../../plugin/types';
4
+ interface UsageTrackerConfig {
5
+ usage_tracking_enabled: boolean;
6
+ usage_sync_max_retries: number;
7
+ }
8
+ export declare class UsageTracker {
9
+ private config;
10
+ private accountManager;
11
+ private repository;
12
+ constructor(config: UsageTrackerConfig, accountManager: AccountManager, repository: AccountRepository);
13
+ syncUsage(account: ManagedAccount, auth: KiroAuthDetails): Promise<void>;
14
+ private syncWithRetry;
15
+ private sleep;
16
+ }
17
+ export {};
@@ -0,0 +1,39 @@
1
+ import { fetchUsageLimits, updateAccountQuota } from '../../plugin/usage';
2
+ export class UsageTracker {
3
+ config;
4
+ accountManager;
5
+ repository;
6
+ constructor(config, accountManager, repository) {
7
+ this.config = config;
8
+ this.accountManager = accountManager;
9
+ this.repository = repository;
10
+ }
11
+ async syncUsage(account, auth) {
12
+ if (!this.config.usage_tracking_enabled) {
13
+ return;
14
+ }
15
+ this.syncWithRetry(account, auth, 0).catch(() => { });
16
+ }
17
+ async syncWithRetry(account, auth, attempt) {
18
+ try {
19
+ const u = await fetchUsageLimits(auth);
20
+ updateAccountQuota(account, u, this.accountManager);
21
+ await this.repository.batchSave(this.accountManager.getAccounts());
22
+ }
23
+ catch (e) {
24
+ if (attempt < this.config.usage_sync_max_retries) {
25
+ await this.sleep(1000 * Math.pow(2, attempt));
26
+ return this.syncWithRetry(account, auth, attempt + 1);
27
+ }
28
+ if (e.message?.includes('403') ||
29
+ e.message?.includes('invalid') ||
30
+ e.message?.includes('bearer token')) {
31
+ this.accountManager.markUnhealthy(account, e.message);
32
+ this.repository.save(account).catch(() => { });
33
+ }
34
+ }
35
+ }
36
+ sleep(ms) {
37
+ return new Promise((r) => setTimeout(r, ms));
38
+ }
39
+ }
@@ -0,0 +1,15 @@
1
+ import type { AccountRepository } from '../../infrastructure/database/account-repository.js';
2
+ export declare class AuthHandler {
3
+ private config;
4
+ private repository;
5
+ private accountManager?;
6
+ constructor(config: any, repository: AccountRepository);
7
+ initialize(): Promise<void>;
8
+ setAccountManager(am: any): void;
9
+ getMethods(): Array<{
10
+ id: string;
11
+ label: string;
12
+ type: 'oauth';
13
+ authorize: (inputs?: any) => Promise<any>;
14
+ }>;
15
+ }
@@ -0,0 +1,43 @@
1
+ import { IdcAuthMethod } from './idc-auth-method.js';
2
+ export class AuthHandler {
3
+ config;
4
+ repository;
5
+ accountManager;
6
+ constructor(config, repository) {
7
+ this.config = config;
8
+ this.repository = repository;
9
+ }
10
+ async initialize() {
11
+ const { syncFromKiroCli } = await import('../../plugin/sync/kiro-cli.js');
12
+ const { syncFromAwsSso } = await import('../../plugin/sync/aws-sso.js');
13
+ if (this.config.auto_sync_kiro_cli) {
14
+ await syncFromKiroCli();
15
+ }
16
+ if (this.config.auto_sync_aws_sso !== false) {
17
+ const ssoAccounts = await syncFromAwsSso();
18
+ if (ssoAccounts.length > 0 && this.accountManager) {
19
+ for (const acc of ssoAccounts) {
20
+ this.accountManager.addAccount(acc);
21
+ }
22
+ await this.accountManager.saveToDisk();
23
+ }
24
+ }
25
+ }
26
+ setAccountManager(am) {
27
+ this.accountManager = am;
28
+ }
29
+ getMethods() {
30
+ if (!this.accountManager) {
31
+ return [];
32
+ }
33
+ const idcMethod = new IdcAuthMethod(this.config, this.repository);
34
+ return [
35
+ {
36
+ id: 'idc',
37
+ label: 'AWS Builder ID (IDC)',
38
+ type: 'oauth',
39
+ authorize: (inputs) => idcMethod.authorize(inputs)
40
+ }
41
+ ];
42
+ }
43
+ }
@@ -0,0 +1,17 @@
1
+ import type { AccountRepository } from '../../infrastructure/database/account-repository.js';
2
+ export declare class IdcAuthMethod {
3
+ private config;
4
+ private repository;
5
+ constructor(config: any, repository: AccountRepository);
6
+ authorize(inputs?: any): Promise<{
7
+ url: string;
8
+ instructions: string;
9
+ method: 'auto';
10
+ callback: () => Promise<{
11
+ type: 'success' | 'failed';
12
+ key?: string;
13
+ }>;
14
+ }>;
15
+ private handleMultipleLogin;
16
+ private handleSingleLogin;
17
+ }