@sunerpy/opencode-kiro-auth 0.1.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.
Files changed (113) hide show
  1. package/LICENSE +678 -0
  2. package/README.md +270 -0
  3. package/dist/constants.d.ts +28 -0
  4. package/dist/constants.js +108 -0
  5. package/dist/core/account/account-selector.d.ts +25 -0
  6. package/dist/core/account/account-selector.js +80 -0
  7. package/dist/core/account/usage-tracker.d.ts +20 -0
  8. package/dist/core/account/usage-tracker.js +56 -0
  9. package/dist/core/auth/auth-handler.d.ts +18 -0
  10. package/dist/core/auth/auth-handler.js +236 -0
  11. package/dist/core/auth/idc-auth-method.d.ts +9 -0
  12. package/dist/core/auth/idc-auth-method.js +169 -0
  13. package/dist/core/auth/token-refresher.d.ts +23 -0
  14. package/dist/core/auth/token-refresher.js +85 -0
  15. package/dist/core/index.d.ts +9 -0
  16. package/dist/core/index.js +9 -0
  17. package/dist/core/request/error-handler.d.ts +32 -0
  18. package/dist/core/request/error-handler.js +159 -0
  19. package/dist/core/request/request-handler.d.ts +35 -0
  20. package/dist/core/request/request-handler.js +296 -0
  21. package/dist/core/request/response-handler.d.ts +8 -0
  22. package/dist/core/request/response-handler.js +137 -0
  23. package/dist/core/request/retry-strategy.d.ts +18 -0
  24. package/dist/core/request/retry-strategy.js +28 -0
  25. package/dist/index.d.ts +94 -0
  26. package/dist/index.js +2 -0
  27. package/dist/infrastructure/database/account-cache.d.ts +14 -0
  28. package/dist/infrastructure/database/account-cache.js +44 -0
  29. package/dist/infrastructure/database/account-repository.d.ts +12 -0
  30. package/dist/infrastructure/database/account-repository.js +66 -0
  31. package/dist/infrastructure/index.d.ts +7 -0
  32. package/dist/infrastructure/index.js +7 -0
  33. package/dist/infrastructure/transformers/event-stream-parser.d.ts +7 -0
  34. package/dist/infrastructure/transformers/event-stream-parser.js +115 -0
  35. package/dist/infrastructure/transformers/history-builder.d.ts +16 -0
  36. package/dist/infrastructure/transformers/history-builder.js +226 -0
  37. package/dist/infrastructure/transformers/message-transformer.d.ts +5 -0
  38. package/dist/infrastructure/transformers/message-transformer.js +99 -0
  39. package/dist/infrastructure/transformers/tool-call-parser.d.ts +4 -0
  40. package/dist/infrastructure/transformers/tool-call-parser.js +45 -0
  41. package/dist/infrastructure/transformers/tool-transformer.d.ts +2 -0
  42. package/dist/infrastructure/transformers/tool-transformer.js +19 -0
  43. package/dist/kiro/auth.d.ts +4 -0
  44. package/dist/kiro/auth.js +25 -0
  45. package/dist/kiro/oauth-idc.d.ts +25 -0
  46. package/dist/kiro/oauth-idc.js +167 -0
  47. package/dist/plugin/accounts.d.ts +29 -0
  48. package/dist/plugin/accounts.js +266 -0
  49. package/dist/plugin/auth-bootstrap.d.ts +9 -0
  50. package/dist/plugin/auth-bootstrap.js +69 -0
  51. package/dist/plugin/auth-page.d.ts +4 -0
  52. package/dist/plugin/auth-page.js +721 -0
  53. package/dist/plugin/config/index.d.ts +3 -0
  54. package/dist/plugin/config/index.js +2 -0
  55. package/dist/plugin/config/loader.d.ts +6 -0
  56. package/dist/plugin/config/loader.js +129 -0
  57. package/dist/plugin/config/schema.d.ts +88 -0
  58. package/dist/plugin/config/schema.js +94 -0
  59. package/dist/plugin/effort.d.ts +46 -0
  60. package/dist/plugin/effort.js +113 -0
  61. package/dist/plugin/errors.d.ts +17 -0
  62. package/dist/plugin/errors.js +34 -0
  63. package/dist/plugin/health.d.ts +1 -0
  64. package/dist/plugin/health.js +13 -0
  65. package/dist/plugin/image-handler.d.ts +18 -0
  66. package/dist/plugin/image-handler.js +82 -0
  67. package/dist/plugin/logger.d.ts +8 -0
  68. package/dist/plugin/logger.js +84 -0
  69. package/dist/plugin/models.d.ts +2 -0
  70. package/dist/plugin/models.js +11 -0
  71. package/dist/plugin/request.d.ts +9 -0
  72. package/dist/plugin/request.js +287 -0
  73. package/dist/plugin/response.d.ts +3 -0
  74. package/dist/plugin/response.js +97 -0
  75. package/dist/plugin/sdk-client.d.ts +4 -0
  76. package/dist/plugin/sdk-client.js +55 -0
  77. package/dist/plugin/storage/locked-operations.d.ts +5 -0
  78. package/dist/plugin/storage/locked-operations.js +103 -0
  79. package/dist/plugin/storage/migrations.d.ts +4 -0
  80. package/dist/plugin/storage/migrations.js +155 -0
  81. package/dist/plugin/storage/sqlite.d.ts +18 -0
  82. package/dist/plugin/storage/sqlite.js +166 -0
  83. package/dist/plugin/streaming/index.d.ts +2 -0
  84. package/dist/plugin/streaming/index.js +2 -0
  85. package/dist/plugin/streaming/openai-converter.d.ts +2 -0
  86. package/dist/plugin/streaming/openai-converter.js +81 -0
  87. package/dist/plugin/streaming/sdk-stream-transformer.d.ts +1 -0
  88. package/dist/plugin/streaming/sdk-stream-transformer.js +274 -0
  89. package/dist/plugin/streaming/stream-parser.d.ts +5 -0
  90. package/dist/plugin/streaming/stream-parser.js +136 -0
  91. package/dist/plugin/streaming/stream-state.d.ts +5 -0
  92. package/dist/plugin/streaming/stream-state.js +59 -0
  93. package/dist/plugin/streaming/stream-transformer.d.ts +1 -0
  94. package/dist/plugin/streaming/stream-transformer.js +295 -0
  95. package/dist/plugin/streaming/types.d.ts +25 -0
  96. package/dist/plugin/streaming/types.js +2 -0
  97. package/dist/plugin/sync/kiro-cli-parser.d.ts +8 -0
  98. package/dist/plugin/sync/kiro-cli-parser.js +72 -0
  99. package/dist/plugin/sync/kiro-cli-profile.d.ts +1 -0
  100. package/dist/plugin/sync/kiro-cli-profile.js +30 -0
  101. package/dist/plugin/sync/kiro-cli.d.ts +2 -0
  102. package/dist/plugin/sync/kiro-cli.js +212 -0
  103. package/dist/plugin/sync/stale-accounts.d.ts +9 -0
  104. package/dist/plugin/sync/stale-accounts.js +31 -0
  105. package/dist/plugin/token.d.ts +2 -0
  106. package/dist/plugin/token.js +78 -0
  107. package/dist/plugin/types.d.ts +125 -0
  108. package/dist/plugin/types.js +0 -0
  109. package/dist/plugin/usage.d.ts +3 -0
  110. package/dist/plugin/usage.js +79 -0
  111. package/dist/plugin.d.ts +174 -0
  112. package/dist/plugin.js +170 -0
  113. package/package.json +74 -0
@@ -0,0 +1,721 @@
1
+ function escapeHtml(text) {
2
+ return text
3
+ .replace(/&/g, '&')
4
+ .replace(/</g, '&lt;')
5
+ .replace(/>/g, '&gt;')
6
+ .replace(/"/g, '&quot;')
7
+ .replace(/'/g, '&#039;');
8
+ }
9
+ export function getIDCAuthHtml(verificationUrl, userCode, statusUrl) {
10
+ const escapedUrl = escapeHtml(verificationUrl);
11
+ const escapedCode = escapeHtml(userCode);
12
+ const escapedStatusUrl = escapeHtml(statusUrl);
13
+ return `<!DOCTYPE html>
14
+ <html lang="en">
15
+ <head>
16
+ <meta charset="UTF-8">
17
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
18
+ <title>AWS Builder ID Authentication</title>
19
+ <style>
20
+ * {
21
+ margin: 0;
22
+ padding: 0;
23
+ box-sizing: border-box;
24
+ }
25
+ body {
26
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
27
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
28
+ min-height: 100vh;
29
+ display: flex;
30
+ align-items: center;
31
+ justify-content: center;
32
+ padding: 20px;
33
+ }
34
+ .container {
35
+ background: white;
36
+ border-radius: 16px;
37
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
38
+ max-width: 500px;
39
+ width: 100%;
40
+ padding: 48px 40px;
41
+ text-align: center;
42
+ animation: slideIn 0.4s ease-out;
43
+ }
44
+ @keyframes slideIn {
45
+ from {
46
+ opacity: 0;
47
+ transform: translateY(-20px);
48
+ }
49
+ to {
50
+ opacity: 1;
51
+ transform: translateY(0);
52
+ }
53
+ }
54
+ h1 {
55
+ color: #1a202c;
56
+ font-size: 28px;
57
+ font-weight: 700;
58
+ margin-bottom: 12px;
59
+ }
60
+ .subtitle {
61
+ color: #718096;
62
+ font-size: 16px;
63
+ margin-bottom: 32px;
64
+ line-height: 1.5;
65
+ }
66
+ .code-container {
67
+ background: #f7fafc;
68
+ border: 2px solid #e2e8f0;
69
+ border-radius: 12px;
70
+ padding: 24px;
71
+ margin-bottom: 24px;
72
+ position: relative;
73
+ }
74
+ .code-label {
75
+ color: #4a5568;
76
+ font-size: 14px;
77
+ font-weight: 600;
78
+ text-transform: uppercase;
79
+ letter-spacing: 0.5px;
80
+ margin-bottom: 12px;
81
+ }
82
+ .code {
83
+ font-family: 'Courier New', monospace;
84
+ font-size: 32px;
85
+ font-weight: 700;
86
+ color: #2d3748;
87
+ letter-spacing: 4px;
88
+ user-select: all;
89
+ cursor: pointer;
90
+ padding: 8px;
91
+ border-radius: 6px;
92
+ transition: background 0.2s;
93
+ }
94
+ .code:hover {
95
+ background: #edf2f7;
96
+ }
97
+ .copy-hint {
98
+ color: #a0aec0;
99
+ font-size: 12px;
100
+ margin-top: 8px;
101
+ }
102
+ .url-container {
103
+ margin-bottom: 32px;
104
+ }
105
+ .url-label {
106
+ color: #4a5568;
107
+ font-size: 14px;
108
+ font-weight: 600;
109
+ margin-bottom: 12px;
110
+ }
111
+ .url-link {
112
+ display: inline-block;
113
+ color: #4299e1;
114
+ text-decoration: none;
115
+ font-size: 16px;
116
+ padding: 12px 24px;
117
+ border: 2px solid #4299e1;
118
+ border-radius: 8px;
119
+ transition: all 0.2s;
120
+ font-weight: 600;
121
+ }
122
+ .url-link:hover {
123
+ background: #4299e1;
124
+ color: white;
125
+ transform: translateY(-2px);
126
+ box-shadow: 0 4px 12px rgba(66, 153, 225, 0.4);
127
+ }
128
+ .status {
129
+ display: flex;
130
+ align-items: center;
131
+ justify-content: center;
132
+ gap: 12px;
133
+ color: #718096;
134
+ font-size: 14px;
135
+ margin-top: 32px;
136
+ padding-top: 24px;
137
+ border-top: 1px solid #e2e8f0;
138
+ }
139
+ .spinner {
140
+ width: 20px;
141
+ height: 20px;
142
+ border: 3px solid #e2e8f0;
143
+ border-top-color: #4299e1;
144
+ border-radius: 50%;
145
+ animation: spin 0.8s linear infinite;
146
+ }
147
+ @keyframes spin {
148
+ to { transform: rotate(360deg); }
149
+ }
150
+ .instructions {
151
+ background: #edf2f7;
152
+ border-radius: 8px;
153
+ padding: 16px;
154
+ margin-bottom: 24px;
155
+ text-align: left;
156
+ }
157
+ .instructions ol {
158
+ margin-left: 20px;
159
+ color: #4a5568;
160
+ font-size: 14px;
161
+ line-height: 1.8;
162
+ }
163
+ .instructions li {
164
+ margin-bottom: 8px;
165
+ }
166
+ @media (max-width: 600px) {
167
+ .container {
168
+ padding: 32px 24px;
169
+ }
170
+ h1 {
171
+ font-size: 24px;
172
+ }
173
+ .code {
174
+ font-size: 24px;
175
+ letter-spacing: 2px;
176
+ }
177
+ }
178
+ </style>
179
+ </head>
180
+ <body>
181
+ <div class="container">
182
+ <h1>AWS Builder ID Authentication</h1>
183
+ <p class="subtitle">Complete the authentication in your browser</p>
184
+
185
+ <div class="instructions">
186
+ <ol>
187
+ <li>A browser window will open automatically</li>
188
+ <li>Enter the code shown below</li>
189
+ <li>Complete the authentication process</li>
190
+ </ol>
191
+ </div>
192
+
193
+ <div class="code-container">
194
+ <div class="code-label">Your Code</div>
195
+ <div class="code" onclick="copyCode()">${escapedCode}</div>
196
+ <div class="copy-hint">Click to copy</div>
197
+ </div>
198
+
199
+ <div class="url-container">
200
+ <div class="url-label">Verification URL</div>
201
+ <a href="${escapedUrl}" target="_blank" class="url-link">Open Browser</a>
202
+ </div>
203
+
204
+ <div class="status">
205
+ <div class="spinner"></div>
206
+ <span>Waiting for authentication...</span>
207
+ </div>
208
+ </div>
209
+
210
+ <script>
211
+ const statusUrl = '${escapedStatusUrl}';
212
+ const verificationUrl = '${escapedUrl}';
213
+
214
+ function copyCode() {
215
+ const code = '${escapedCode}';
216
+ navigator.clipboard.writeText(code).then(() => {
217
+ const codeEl = document.querySelector('.code');
218
+ const originalBg = codeEl.style.background;
219
+ codeEl.style.background = '#48bb78';
220
+ codeEl.style.color = 'white';
221
+ setTimeout(() => {
222
+ codeEl.style.background = originalBg;
223
+ codeEl.style.color = '#2d3748';
224
+ }, 300);
225
+ }).catch(() => {});
226
+ }
227
+
228
+ window.addEventListener('load', () => {
229
+ setTimeout(() => {
230
+ window.open(verificationUrl, '_blank');
231
+ }, 500);
232
+ });
233
+
234
+ async function checkStatus() {
235
+ try {
236
+ const response = await fetch(statusUrl);
237
+ const data = await response.json();
238
+
239
+ if (data.status === 'success') {
240
+ window.location.href = '/success';
241
+ } else if (data.status === 'failed' || data.status === 'timeout') {
242
+ window.location.href = '/error?message=' + encodeURIComponent(data.message || 'Authentication failed');
243
+ }
244
+ } catch (error) {
245
+ console.error('Status check failed:', error);
246
+ }
247
+ }
248
+
249
+ setInterval(checkStatus, 2000);
250
+ checkStatus();
251
+ </script>
252
+ </body>
253
+ </html>`;
254
+ }
255
+ export function getSuccessHtml() {
256
+ return `<!DOCTYPE html>
257
+ <html lang="en">
258
+ <head>
259
+ <meta charset="UTF-8">
260
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
261
+ <title>Authentication Successful</title>
262
+ <style>
263
+ * {
264
+ margin: 0;
265
+ padding: 0;
266
+ box-sizing: border-box;
267
+ }
268
+ body {
269
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
270
+ background: linear-gradient(135deg, #48bb78 0%, #38a169 100%);
271
+ min-height: 100vh;
272
+ display: flex;
273
+ align-items: center;
274
+ justify-content: center;
275
+ padding: 20px;
276
+ }
277
+ .container {
278
+ background: white;
279
+ border-radius: 16px;
280
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
281
+ max-width: 450px;
282
+ width: 100%;
283
+ padding: 48px 40px;
284
+ text-align: center;
285
+ animation: slideIn 0.4s ease-out;
286
+ }
287
+ @keyframes slideIn {
288
+ from {
289
+ opacity: 0;
290
+ transform: scale(0.9);
291
+ }
292
+ to {
293
+ opacity: 1;
294
+ transform: scale(1);
295
+ }
296
+ }
297
+ .checkmark {
298
+ width: 80px;
299
+ height: 80px;
300
+ margin: 0 auto 24px;
301
+ position: relative;
302
+ }
303
+ .checkmarkcle {
304
+ width: 80px;
305
+ height: 80px;
306
+ border-radius: 50%;
307
+ background: #48bb78;
308
+ animation: scaleIn 0.5s ease-out;
309
+ }
310
+ @keyframes scaleIn {
311
+ from {
312
+ transform: scale(0);
313
+ }
314
+ to {
315
+ transform: scale(1);
316
+ }
317
+ }
318
+ .checkmark-check {
319
+ position: absolute;
320
+ top: 50%;
321
+ left: 50%;
322
+ transform: translate(-50%, -50%);
323
+ width: 30px;
324
+ height: 50px;
325
+ border: solid white;
326
+ border-width: 0 6px 6px 0;
327
+ transform: translate(-50%, -60%) rotate(45deg);
328
+ animation: checkmark 0.5s 0.3s ease-out forwards;
329
+ opacity: 0;
330
+ }
331
+ @keyframes checkmark {
332
+ to {
333
+ opacity: 1;
334
+ transform: translate(-50%, -60%) rotate(45deg) scale(1);
335
+ }
336
+ }
337
+ h1 {
338
+ color: #1a202c;
339
+ font-size: 28px;
340
+ font-weight: 700;
341
+ margin-bottom: 12px;
342
+ }
343
+ .message {
344
+ color: #718096;
345
+ font-size: 16px;
346
+ line-height: 1.6;
347
+ margin-bottom: 24px;
348
+ }
349
+ .auto-close {
350
+ color: #a0aec0;
351
+ font-size: 14px;
352
+ padding-top: 24px;
353
+ border-top: 1px solid #e2e8f0;
354
+ }
355
+ @media (max-width: 600px) {
356
+ .container {
357
+ padding: 32px 24px;
358
+ }
359
+ h1 {
360
+ font-size: 24px;
361
+ }
362
+ }
363
+ </style>
364
+ </head>
365
+ <body>
366
+ <div class="container">
367
+ <div class="checkmark">
368
+ <div class="checkmark-circle"></div>
369
+ <div class="checkmark-check"></div>
370
+ </div>
371
+ <h1>Authentication Successful!</h1>
372
+ <p class="message">You have been successfully authenticated with AWS Builder ID. You can now close this window and return to your terminal.</p>
373
+ <div class="auto-close">This window will close automatically in <span id="countdown">3</span> seconds</div>
374
+ </div>
375
+
376
+ <script>
377
+ let seconds = 3;
378
+ const countdownEl = document.getElementById('countdown');
379
+
380
+ const interval = setInterval(() => {
381
+ seconds--;
382
+ if (countdownEl) {
383
+ countdownEl.textContent = seconds.toString();
384
+ }
385
+
386
+ if (seconds <= 0) {
387
+ clearInterval(interval);
388
+ try {
389
+ window.close();
390
+ } catch (e) {
391
+ console.log('Couluto-close window');
392
+ }
393
+ }
394
+ }, 1000);
395
+ </script>
396
+ </body>
397
+ </html>`;
398
+ }
399
+ export function getErrorHtml(message) {
400
+ const escapedMessage = escapeHtml(message);
401
+ return `<!DOCTYPE html>
402
+ <html lang="en">
403
+ <head>
404
+ <meta charset="UTF-8">
405
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
406
+ <title>Authentication Failed</title>
407
+ <style>
408
+ * {
409
+ margin: 0;
410
+ padding: 0;
411
+ box-sizing: border-box;
412
+ }
413
+ body {
414
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
415
+ background: linear-gradient(135deg, #fc8181 0%, #f56565 100%);
416
+ min-height: 100vh;
417
+ display: flex;
418
+ align-items: center;
419
+ justify-content: center;
420
+ padding: 20px;
421
+ }
422
+ .container {
423
+ background: white;
424
+ border-radius: 16px;
425
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
426
+ max-width: 450px;
427
+ width: 100%;
428
+ padding: 48px 40px;
429
+ text-align: center;
430
+ animation: slideIn 0.4s ease-out;
431
+ }
432
+ @keyframes slideIn {
433
+ from {
434
+ opacity: 0;
435
+ transform: scale(0.9);
436
+ }
437
+ to {
438
+ opacity: 1;
439
+ transform: scale(1);
440
+ }
441
+ }
442
+ .error-icon {
443
+ width: 80px;
444
+ height: 80px;
445
+ margin: 0 auto 24px;
446
+ position: relative;
447
+ }
448
+ .error-circle {
449
+ width: 80px;
450
+ height: 80px;
451
+ border-radius: 50%;
452
+ background: #fc8181;
453
+ animation: scaleIn 0.5s ease-out;
454
+ }
455
+ @keyframes scaleIn {
456
+ from {
457
+ transform: scale(0);
458
+ }
459
+ to {
460
+ transform: scale(1);
461
+ }
462
+ }
463
+ .error-x {
464
+ position: absolute;
465
+ top: 50%;
466
+ left: 50%;
467
+ transform: translate(-50%, -50%);
468
+ width: 40px;
469
+ height: 40px;
470
+ }
471
+ .error-x::before,
472
+ .error-x::after {
473
+ content: '';
474
+ position: absolute;
475
+ top: 50%;
476
+ left: 50%;
477
+ width: 40px;
478
+ height: 6px;
479
+ background: white;
480
+ border-radius: 3px;
481
+ animation: xmark 0.5s 0.3s ease-out forwards;
482
+ opacity: 0;
483
+ }
484
+ .error-x::before {
485
+ transform: translate(-50%, -50%) rotate(45deg);
486
+ }
487
+ .error-x::after {
488
+ transform: translate(-50%, -50%) rotate(-45deg);
489
+ }
490
+ @keyframes xmark {
491
+ to {
492
+ opacity: 1;
493
+ }
494
+ }
495
+ h1 {
496
+ color: #1a202c;
497
+ font-size: 28px;
498
+ font-weight: 700;
499
+ margin-bottom: 12px;
500
+ }
501
+ .message {
502
+ color: #718096;
503
+ font-size: 16px;
504
+ line-height: 1.6;
505
+ margin-bottom: 16px;
506
+ }
507
+ .error-details {
508
+ background: #fff5f5;
509
+ border: 1px solid #feb2b2;
510
+ border-radius: 8px;
511
+ padding: 16px;
512
+ margin-bottom: 24px;
513
+ color: #c53030;
514
+ font-size: 14px;
515
+ word-break: break-word;
516
+ }
517
+ .instruction {
518
+ color: #4a5568;
519
+ font-size: 15px;
520
+ margin-bottom: 24px;
521
+ }
522
+ .auto-close {
523
+ color: #a0aec0;
524
+ font-size: 14px;
525
+ padding-top: 24px;
526
+ border-top: 1px solid #e2e8f0;
527
+ }
528
+ @media (max-width: 600px) {
529
+ .container {
530
+ padding: 32px 24px;
531
+ }
532
+ h1 {
533
+ font-size: 24px;
534
+ }
535
+ }
536
+ </style>
537
+ </head>
538
+ <body>
539
+ <div class="container">
540
+ <div class="error-icon">
541
+ <div class="error-circle"></div>
542
+ <div class="error-x"></div>
543
+ </div>
544
+ <h1>Authentication Failed</h1>
545
+ <p class="message">We were unable to complete the authentication process.</p>
546
+ <div class="error-details">${escapedMessage}</div>
547
+ <p class="instruction">You can close this window and try again from your terminal.</p>
548
+ <div class="auto-close">This window will close automatically in <span id="countdown">5</span> seconds</div>
549
+ </div>
550
+
551
+ <script>
552
+ let seconds = 5;
553
+ const countdownEl = document.getElementById('countdown');
554
+
555
+ const interval = setInterval(() => {
556
+ seconds--;
557
+ if (countdownEl) {
558
+ countdownEl.textContent = seconds.toString();
559
+ }
560
+
561
+ if (seconds <= 0) {
562
+ clearInterval(interval);
563
+ try {
564
+ window.close();
565
+ } catch (e) {
566
+ console.log('Could not auto-close window');
567
+ }
568
+ }
569
+ }, 1000);
570
+ </script>
571
+ </body>
572
+ </html>`;
573
+ }
574
+ export function getStartUrlInputHtml(defaultStartUrl, submitUrl) {
575
+ const escapedDefault = escapeHtml(defaultStartUrl);
576
+ const escapedSubmit = escapeHtml(submitUrl);
577
+ return `<!DOCTYPE html>
578
+ <html lang="en">
579
+ <head>
580
+ <meta charset="UTF-8">
581
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
582
+ <title>AWS Authentication Setup</title>
583
+ <style>
584
+ * { margin: 0; padding: 0; box-sizing: border-box; }
585
+ body {
586
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
587
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
588
+ min-height: 100vh;
589
+ display: flex;
590
+ align-items: center;
591
+ justify-content: center;
592
+ padding: 20px;
593
+ }
594
+ .container {
595
+ background: white;
596
+ border-radius: 16px;
597
+ box-shadow: 0 20px 60px rgba(0,0,0,0.3);
598
+ max-width: 500px;
599
+ width: 100%;
600
+ padding: 48px 40px;
601
+ animation: slideIn 0.4s ease-out;
602
+ }
603
+ @keyframes slideIn {
604
+ from { opacity: 0; transform: translateY(-20px); }
605
+ to { opacity: 1; transform: translateY(0); }
606
+ }
607
+ h1 { color: #1a202c; font-size: 26px; font-weight: 700; margin-bottom: 10px; }
608
+ .subtitle { color: #718096; font-size: 15px; margin-bottom: 32px; line-height: 1.5; }
609
+ label { display: block; color: #4a5568; font-size: 14px; font-weight: 600; margin-bottom: 8px; }
610
+ input[type="url"], input[type="text"] {
611
+ width: 100%;
612
+ padding: 12px 16px;
613
+ border: 2px solid #e2e8f0;
614
+ border-radius: 8px;
615
+ font-size: 15px;
616
+ color: #2d3748;
617
+ outline: none;
618
+ transition: border-color 0.2s;
619
+ }
620
+ input:focus { border-color: #667eea; }
621
+ .hint { color: #a0aec0; font-size: 13px; margin-top: 8px; margin-bottom: 24px; }
622
+ .hint a { color: #667eea; text-decoration: none; }
623
+ button {
624
+ width: 100%;
625
+ padding: 14px;
626
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
627
+ color: white;
628
+ border: none;
629
+ border-radius: 8px;
630
+ font-size: 16px;
631
+ font-weight: 600;
632
+ cursor: pointer;
633
+ transition: opacity 0.2s, transform 0.1s;
634
+ }
635
+ button:hover { opacity: 0.9; transform: translateY(-1px); }
636
+ button:active { transform: translateY(0); }
637
+ button:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }
638
+ .error { color: #e53e3e; font-size: 13px; margin-top: 8px; display: none; }
639
+ .loading { display: none; text-align: center; color: #718096; margin-top: 16px; font-size: 14px; }
640
+ .spinner {
641
+ display: inline-block; width: 16px; height: 16px;
642
+ border: 2px solid #e2e8f0; border-top-color: #667eea;
643
+ border-radius: 50%; animation: spin 0.8s linear infinite;
644
+ vertical-align: middle; margin-right: 8px;
645
+ }
646
+ @keyframes spin { to { transform: rotate(360deg); } }
647
+ </style>
648
+ </head>
649
+ <body>
650
+ <div class="container">
651
+ <h1>AWS Authentication</h1>
652
+ <p class="subtitle">Enter your IAM Identity Center Start URL, or leave blank to use AWS Builder ID.</p>
653
+
654
+ <form id="form" onsubmit="handleSubmit(event)">
655
+ <label for="startUrl">Start URL</label>
656
+ <input
657
+ type="text"
658
+ id="startUrl"
659
+ name="startUrl"
660
+ placeholder="https://your-company.awsapps.com/start"
661
+ value="${escapedDefault}"
662
+ autocomplete="url"
663
+ spellcheck="false"
664
+ />
665
+ <div class="hint">Leave blank to sign in with <strong>AWS Builder ID</strong></div>
666
+ <div class="error" id="error"></div>
667
+ <button type="submit" id="btn">Continue</button>
668
+ </form>
669
+
670
+ <div class="loading" id="loading">
671
+ <span class="spinner"></span>Initializing authentication...
672
+ </div>
673
+ </div>
674
+
675
+ <script>
676
+ async function handleSubmit(e) {
677
+ e.preventDefault();
678
+ const input = document.getElementById('startUrl');
679
+ const errorEl = document.getElementById('error');
680
+ const btn = document.getElementById('btn');
681
+ const loading = document.getElementById('loading');
682
+ const val = input.value.trim();
683
+
684
+ if (val) {
685
+ try { new URL(val); } catch {
686
+ errorEl.textContent = 'Please enter a valid URL';
687
+ errorEl.style.display = 'block';
688
+ return;
689
+ }
690
+ }
691
+
692
+ errorEl.style.display = 'none';
693
+ btn.disabled = true;
694
+ loading.style.display = 'block';
695
+
696
+ try {
697
+ const res = await fetch('${escapedSubmit}', {
698
+ method: 'POST',
699
+ headers: { 'Content-Type': 'application/json' },
700
+ body: JSON.stringify({ startUrl: val || '' })
701
+ });
702
+ const data = await res.json();
703
+ if (data.error) {
704
+ errorEl.textContent = data.error;
705
+ errorEl.style.display = 'block';
706
+ btn.disabled = false;
707
+ loading.style.display = 'none';
708
+ } else {
709
+ window.location.href = '/auth?code=' + encodeURIComponent(data.userCode) + '&url=' + encodeURIComponent(data.verificationUriComplete);
710
+ }
711
+ } catch (err) {
712
+ errorEl.textContent = 'Failed to connect. Please try again.';
713
+ errorEl.style.display = 'block';
714
+ btn.disabled = false;
715
+ loading.style.display = 'none';
716
+ }
717
+ }
718
+ </script>
719
+ </body>
720
+ </html>`;
721
+ }
@@ -0,0 +1,3 @@
1
+ export { configExists, getDefaultLogsDir, getProjectConfigPath, getUserConfigPath, loadConfig } from './loader.js';
2
+ export { DEFAULT_CONFIG, KiroConfigSchema } from './schema.js';
3
+ export type { KiroConfig } from './schema.js';