claude-ws 0.3.97 → 0.3.99
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/locales/de.json +374 -12
- package/locales/en.json +374 -12
- package/locales/es.json +398 -11
- package/locales/fr.json +398 -11
- package/locales/ja.json +398 -11
- package/locales/ko.json +398 -11
- package/locales/vi.json +374 -12
- package/locales/zh.json +398 -11
- package/package.json +1 -1
- package/server.ts +283 -6
- package/src/app/[locale]/not-found.tsx +6 -3
- package/src/app/[locale]/page.tsx +14 -4
- package/src/app/api/attempts/[id]/workflow/route.ts +76 -0
- package/src/app/api/questions/answer/route.ts +58 -0
- package/src/app/api/questions/route.ts +68 -0
- package/src/app/api/tasks/[id]/compact/route.ts +62 -0
- package/src/components/access-anywhere/api-access-key-setup-modal.tsx +2 -2
- package/src/components/access-anywhere/tunnel-settings-dialog.tsx +6 -6
- package/src/components/access-anywhere/wizard-step-ctunnel.tsx +8 -8
- package/src/components/agent-factory/dependency-tree.tsx +5 -3
- package/src/components/agent-factory/discovery-dialog.tsx +26 -22
- package/src/components/agent-factory/plugin-detail-dialog.tsx +41 -38
- package/src/components/agent-factory/plugin-form-dialog.tsx +23 -20
- package/src/components/agent-factory/plugin-list.tsx +20 -17
- package/src/components/agent-factory/upload-dialog.tsx +17 -14
- package/src/components/auth/agent-provider-dialog.tsx +67 -65
- package/src/components/auth/api-key-dialog.tsx +14 -11
- package/src/components/auth/auth-error-message.tsx +6 -3
- package/src/components/editor/code-editor-with-inline-edit.tsx +4 -2
- package/src/components/editor/file-diff-resolver-modal.tsx +31 -26
- package/src/components/editor/inline-edit-dialog.tsx +9 -6
- package/src/components/editor/selection-mention-popup.tsx +3 -1
- package/src/components/header/project-selector.tsx +7 -4
- package/src/components/header.tsx +70 -4
- package/src/components/kanban/column.tsx +11 -0
- package/src/components/kanban/task-card.tsx +70 -4
- package/src/components/project-settings/component-selector.tsx +3 -1
- package/src/components/project-settings/plugin-upload-dialog.tsx +7 -5
- package/src/components/project-settings/project-settings-dialog.tsx +5 -3
- package/src/components/questions/questions-panel.tsx +136 -0
- package/src/components/settings/folder-browser-dialog.tsx +29 -25
- package/src/components/settings/settings-page.tsx +64 -18
- package/src/components/settings/setup-dialog.tsx +26 -23
- package/src/components/setup/unified-setup-wizard.tsx +12 -9
- package/src/components/sidebar/file-browser/file-create-buttons.tsx +7 -3
- package/src/components/sidebar/file-browser/file-tab-content.tsx +19 -15
- package/src/components/sidebar/file-browser/file-tabs-panel.tsx +7 -4
- package/src/components/sidebar/file-browser/file-tree.tsx +3 -1
- package/src/components/sidebar/git-changes/branch-checkout-modal.tsx +6 -4
- package/src/components/sidebar/git-changes/commit-details-modal.tsx +5 -3
- package/src/components/sidebar/git-changes/diff-tabs-panel.tsx +3 -1
- package/src/components/sidebar/git-changes/git-file-item.tsx +8 -6
- package/src/components/sidebar/git-changes/git-graph.tsx +8 -5
- package/src/components/sidebar/git-changes/git-panel.tsx +28 -27
- package/src/components/sidebar/git-changes/git-section.tsx +5 -3
- package/src/components/sidebar/shells/shell-panel.tsx +3 -1
- package/src/components/task/attachment-bar.tsx +4 -1
- package/src/components/task/attempt-item.tsx +7 -5
- package/src/components/task/conversation-view.tsx +21 -13
- package/src/components/task/floating-chat-window.tsx +14 -5
- package/src/components/task/interactive-command/checkpoint-list.tsx +5 -3
- package/src/components/task/interactive-command/confirm-dialog.tsx +9 -4
- package/src/components/task/interactive-command/interactive-command-overlay.tsx +23 -9
- package/src/components/task/interactive-command/question-prompt.tsx +12 -8
- package/src/components/task/pending-question-indicator.tsx +5 -3
- package/src/components/task/prompt-input.tsx +1 -1
- package/src/components/task/shell-log-view.tsx +3 -1
- package/src/components/task/status-line.tsx +84 -23
- package/src/components/task/task-detail-panel.tsx +27 -27
- package/src/components/task/task-shell-indicator.tsx +10 -6
- package/src/components/terminal/terminal-context-menu.tsx +6 -4
- package/src/components/terminal/terminal-instance.tsx +11 -3
- package/src/components/terminal/terminal-panel.tsx +6 -3
- package/src/components/terminal/terminal-shortcut-bar.tsx +3 -1
- package/src/components/terminal/terminal-tab-bar.tsx +5 -3
- package/src/components/workflow/workflow-panel.tsx +181 -0
- package/src/hooks/use-attempt-stream.ts +96 -3
- package/src/lib/agent-manager.ts +89 -3
- package/src/lib/db/index.ts +18 -0
- package/src/lib/db/schema.ts +29 -0
- package/src/lib/process-manager.ts +28 -7
- package/src/lib/session-manager.ts +60 -0
- package/src/lib/usage-tracker.ts +19 -19
- package/src/lib/workflow-tracker.ts +118 -20
- package/src/stores/questions-store.ts +76 -0
- package/src/stores/workflow-store.ts +71 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState, useRef } from 'react';
|
|
4
|
+
import { useTranslations } from 'next-intl';
|
|
4
5
|
import {
|
|
5
6
|
Dialog,
|
|
6
7
|
DialogContent,
|
|
@@ -26,6 +27,8 @@ interface UploadDialogProps {
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export function UploadDialog({ open, onOpenChange, onUploadSuccess }: UploadDialogProps) {
|
|
30
|
+
const t = useTranslations('agentFactory');
|
|
31
|
+
const tCommon = useTranslations('common');
|
|
29
32
|
const [step, setStep] = useState<'upload' | 'preview' | 'importing'>('upload');
|
|
30
33
|
const [uploading, setUploading] = useState(false);
|
|
31
34
|
const [error, setError] = useState<string | null>(null);
|
|
@@ -72,7 +75,7 @@ export function UploadDialog({ open, onOpenChange, onUploadSuccess }: UploadDial
|
|
|
72
75
|
const isValidExtension = validExtensions.some(ext => fileName.endsWith(ext));
|
|
73
76
|
|
|
74
77
|
if (!isValidExtension) {
|
|
75
|
-
setError('
|
|
78
|
+
setError(t('invalidFileType'));
|
|
76
79
|
return;
|
|
77
80
|
}
|
|
78
81
|
|
|
@@ -209,7 +212,7 @@ export function UploadDialog({ open, onOpenChange, onUploadSuccess }: UploadDial
|
|
|
209
212
|
const isValidExtension = validExtensions.some(ext => fileName.endsWith(ext));
|
|
210
213
|
|
|
211
214
|
if (!isValidExtension) {
|
|
212
|
-
setError('
|
|
215
|
+
setError(t('invalidFileType'));
|
|
213
216
|
return;
|
|
214
217
|
}
|
|
215
218
|
|
|
@@ -296,12 +299,12 @@ export function UploadDialog({ open, onOpenChange, onUploadSuccess }: UploadDial
|
|
|
296
299
|
<DialogHeader>
|
|
297
300
|
<DialogTitle className="flex items-center gap-2">
|
|
298
301
|
<FileArchive className="w-5 h-5" />
|
|
299
|
-
{step === 'preview' ? '
|
|
302
|
+
{step === 'preview' ? t('confirmImport') : t('importFromArchive')}
|
|
300
303
|
</DialogTitle>
|
|
301
304
|
<DialogDescription>
|
|
302
305
|
{step === 'preview'
|
|
303
306
|
? `Review ${previewItems.length} plugin(s) found in ${uploadedFileName}`
|
|
304
|
-
: '
|
|
307
|
+
: t('supportedFormats')
|
|
305
308
|
}
|
|
306
309
|
</DialogDescription>
|
|
307
310
|
</DialogHeader>
|
|
@@ -330,15 +333,15 @@ export function UploadDialog({ open, onOpenChange, onUploadSuccess }: UploadDial
|
|
|
330
333
|
{uploading ? (
|
|
331
334
|
<div className="flex flex-col items-center gap-3">
|
|
332
335
|
<Loader2 className="w-12 h-12 animate-spin text-muted-foreground" />
|
|
333
|
-
<p className="text-muted-foreground">
|
|
336
|
+
<p className="text-muted-foreground">{t('analyzingArchive')}</p>
|
|
334
337
|
</div>
|
|
335
338
|
) : (
|
|
336
339
|
<div className="flex flex-col items-center gap-3">
|
|
337
340
|
<Upload className="w-12 h-12 text-muted-foreground" />
|
|
338
341
|
<div>
|
|
339
|
-
<p className="font-medium">
|
|
342
|
+
<p className="font-medium">{t('clickToUploadOrDrag')}</p>
|
|
340
343
|
<p className="text-sm text-muted-foreground mt-1">
|
|
341
|
-
|
|
344
|
+
{t('supportedFormats')}
|
|
342
345
|
</p>
|
|
343
346
|
</div>
|
|
344
347
|
</div>
|
|
@@ -355,7 +358,7 @@ export function UploadDialog({ open, onOpenChange, onUploadSuccess }: UploadDial
|
|
|
355
358
|
|
|
356
359
|
{/* Info */}
|
|
357
360
|
<div className="text-sm text-muted-foreground bg-muted/50 p-3 rounded-lg">
|
|
358
|
-
<p className="font-medium mb-2">
|
|
361
|
+
<p className="font-medium mb-2">{t('automaticOrganization')}</p>
|
|
359
362
|
<p className="text-xs mb-2">
|
|
360
363
|
Files will be automatically organized into the correct folders:
|
|
361
364
|
</p>
|
|
@@ -376,7 +379,7 @@ export function UploadDialog({ open, onOpenChange, onUploadSuccess }: UploadDial
|
|
|
376
379
|
{/* Preview List */}
|
|
377
380
|
<div className="border rounded-lg overflow-hidden">
|
|
378
381
|
<div className="bg-muted/50 px-3 py-2 text-sm font-medium border-b">
|
|
379
|
-
|
|
382
|
+
{t('itemsToImport')} ({previewItems.length})
|
|
380
383
|
</div>
|
|
381
384
|
<div className="max-h-[300px] overflow-y-auto">
|
|
382
385
|
{previewItems.map((item, index) => (
|
|
@@ -406,7 +409,7 @@ export function UploadDialog({ open, onOpenChange, onUploadSuccess }: UploadDial
|
|
|
406
409
|
<div className="flex items-start gap-2 p-3 bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-200 rounded-lg text-sm">
|
|
407
410
|
<Check className="w-4 h-4 mt-0.5 flex-shrink-0" />
|
|
408
411
|
<span>
|
|
409
|
-
|
|
412
|
+
{t('archiveAnalyzed')}
|
|
410
413
|
</span>
|
|
411
414
|
</div>
|
|
412
415
|
</>
|
|
@@ -415,7 +418,7 @@ export function UploadDialog({ open, onOpenChange, onUploadSuccess }: UploadDial
|
|
|
415
418
|
{step === 'importing' && (
|
|
416
419
|
<div className="flex flex-col items-center gap-4 py-8">
|
|
417
420
|
<Loader2 className="w-12 h-12 animate-spin text-muted-foreground" />
|
|
418
|
-
<p className="text-muted-foreground">
|
|
421
|
+
<p className="text-muted-foreground">{t('importingPlugins')}</p>
|
|
419
422
|
</div>
|
|
420
423
|
)}
|
|
421
424
|
</div>
|
|
@@ -425,7 +428,7 @@ export function UploadDialog({ open, onOpenChange, onUploadSuccess }: UploadDial
|
|
|
425
428
|
<>
|
|
426
429
|
<Button variant="outline" onClick={handleCancel} disabled={uploading}>
|
|
427
430
|
<X className="w-4 h-4 mr-1" />
|
|
428
|
-
|
|
431
|
+
{tCommon('cancel')}
|
|
429
432
|
</Button>
|
|
430
433
|
<Button
|
|
431
434
|
variant="outline"
|
|
@@ -434,7 +437,7 @@ export function UploadDialog({ open, onOpenChange, onUploadSuccess }: UploadDial
|
|
|
434
437
|
title="Import to ~/.claude (globally available)"
|
|
435
438
|
>
|
|
436
439
|
<Globe className="w-4 h-4 mr-1" />
|
|
437
|
-
|
|
440
|
+
{t('importGlobally')}
|
|
438
441
|
</Button>
|
|
439
442
|
<Button onClick={() => handleConfirmImport(false)} disabled={uploading}>
|
|
440
443
|
<Check className="w-4 h-4 mr-1" />
|
|
@@ -443,7 +446,7 @@ export function UploadDialog({ open, onOpenChange, onUploadSuccess }: UploadDial
|
|
|
443
446
|
</>
|
|
444
447
|
) : (
|
|
445
448
|
<Button variant="outline" onClick={() => onOpenChange(false)} disabled={uploading}>
|
|
446
|
-
|
|
449
|
+
{tCommon('cancel')}
|
|
447
450
|
</Button>
|
|
448
451
|
)}
|
|
449
452
|
</div>
|
|
@@ -71,6 +71,7 @@ interface AgentProviderSetupFormProps {
|
|
|
71
71
|
|
|
72
72
|
export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormProps) {
|
|
73
73
|
const t = useTranslations('agentProvider');
|
|
74
|
+
const tCommon = useTranslations('common');
|
|
74
75
|
const [selectedOption, setSelectedOption] = useState<ProviderOption | null>(null);
|
|
75
76
|
const [config, setConfig] = useState<ProviderConfig>({
|
|
76
77
|
ANTHROPIC_AUTH_TOKEN: '',
|
|
@@ -165,7 +166,7 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
165
166
|
|
|
166
167
|
const handleOAuthLogin = () => {
|
|
167
168
|
window.open('https://claude.ai/login', '_blank');
|
|
168
|
-
setError('
|
|
169
|
+
setError(t('afterLoginHint'));
|
|
169
170
|
};
|
|
170
171
|
|
|
171
172
|
const handleConsoleSetup = () => {
|
|
@@ -313,21 +314,21 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
313
314
|
</div>
|
|
314
315
|
<div className="flex-1">
|
|
315
316
|
<div className="flex items-center gap-2">
|
|
316
|
-
<span className="font-medium">
|
|
317
|
+
<span className="font-medium">{t('loginWithClaude')}</span>
|
|
317
318
|
{providers.oauth.configured && (
|
|
318
319
|
<span className="inline-flex items-center gap-1 text-xs text-green-600 dark:text-green-400">
|
|
319
320
|
<Check className="h-3 w-3" />
|
|
320
|
-
|
|
321
|
+
{tCommon('configured')}
|
|
321
322
|
</span>
|
|
322
323
|
)}
|
|
323
324
|
{providers.oauth.isDefault && (
|
|
324
325
|
<span className="text-xs bg-primary/10 text-primary px-1.5 py-0.5 rounded">
|
|
325
|
-
|
|
326
|
+
{tCommon('default')}
|
|
326
327
|
</span>
|
|
327
328
|
)}
|
|
328
329
|
</div>
|
|
329
330
|
<div className="text-sm text-muted-foreground mt-1">
|
|
330
|
-
|
|
331
|
+
{t('forClaudeSubscribers')}
|
|
331
332
|
</div>
|
|
332
333
|
</div>
|
|
333
334
|
</div>
|
|
@@ -349,21 +350,21 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
349
350
|
</div>
|
|
350
351
|
<div className="flex-1">
|
|
351
352
|
<div className="flex items-center gap-2">
|
|
352
|
-
<span className="font-medium">
|
|
353
|
+
<span className="font-medium">{t('anthropicConsole')}</span>
|
|
353
354
|
{providers.console.configured && (
|
|
354
355
|
<span className="inline-flex items-center gap-1 text-xs text-green-600 dark:text-green-400">
|
|
355
356
|
<Check className="h-3 w-3" />
|
|
356
|
-
|
|
357
|
+
{tCommon('configured')}
|
|
357
358
|
</span>
|
|
358
359
|
)}
|
|
359
360
|
{providers.console.isDefault && (
|
|
360
361
|
<span className="text-xs bg-primary/10 text-primary px-1.5 py-0.5 rounded">
|
|
361
|
-
|
|
362
|
+
{tCommon('default')}
|
|
362
363
|
</span>
|
|
363
364
|
)}
|
|
364
365
|
</div>
|
|
365
366
|
<div className="text-sm text-muted-foreground mt-1">
|
|
366
|
-
|
|
367
|
+
{t('payAsYouGo')}
|
|
367
368
|
</div>
|
|
368
369
|
</div>
|
|
369
370
|
</div>
|
|
@@ -385,21 +386,21 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
385
386
|
</div>
|
|
386
387
|
<div className="flex-1">
|
|
387
388
|
<div className="flex items-center gap-2">
|
|
388
|
-
<span className="font-medium">
|
|
389
|
+
<span className="font-medium">{t('claudeCodeSettings')}</span>
|
|
389
390
|
{providers.settings.configured && (
|
|
390
391
|
<span className="inline-flex items-center gap-1 text-xs text-green-600 dark:text-green-400">
|
|
391
392
|
<Check className="h-3 w-3" />
|
|
392
|
-
|
|
393
|
+
{tCommon('configured')}
|
|
393
394
|
</span>
|
|
394
395
|
)}
|
|
395
396
|
{providers.settings.isDefault && (
|
|
396
397
|
<span className="text-xs bg-primary/10 text-primary px-1.5 py-0.5 rounded">
|
|
397
|
-
|
|
398
|
+
{tCommon('default')}
|
|
398
399
|
</span>
|
|
399
400
|
)}
|
|
400
401
|
</div>
|
|
401
402
|
<div className="text-sm text-muted-foreground mt-1">
|
|
402
|
-
|
|
403
|
+
{t('useSettingsJson')}
|
|
403
404
|
</div>
|
|
404
405
|
</div>
|
|
405
406
|
</div>
|
|
@@ -421,21 +422,21 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
421
422
|
</div>
|
|
422
423
|
<div className="flex-1">
|
|
423
424
|
<div className="flex items-center gap-2">
|
|
424
|
-
<span className="font-medium">
|
|
425
|
+
<span className="font-medium">{t('customApiKey')}</span>
|
|
425
426
|
{providers.custom.configured && (
|
|
426
427
|
<span className="inline-flex items-center gap-1 text-xs text-green-600 dark:text-green-400">
|
|
427
428
|
<Check className="h-3 w-3" />
|
|
428
|
-
|
|
429
|
+
{tCommon('configured')}
|
|
429
430
|
</span>
|
|
430
431
|
)}
|
|
431
432
|
{providers.custom.isDefault && (
|
|
432
433
|
<span className="text-xs bg-primary/10 text-primary px-1.5 py-0.5 rounded">
|
|
433
|
-
|
|
434
|
+
{tCommon('default')}
|
|
434
435
|
</span>
|
|
435
436
|
)}
|
|
436
437
|
</div>
|
|
437
438
|
<div className="text-sm text-muted-foreground mt-1">
|
|
438
|
-
|
|
439
|
+
{t('useOwnApiKey')}
|
|
439
440
|
</div>
|
|
440
441
|
</div>
|
|
441
442
|
</div>
|
|
@@ -503,14 +504,14 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
503
504
|
// OAuth instructions view
|
|
504
505
|
<div className="space-y-4 py-4">
|
|
505
506
|
<div className="p-4 rounded-lg bg-muted/50">
|
|
506
|
-
<h4 className="font-medium mb-2">
|
|
507
|
+
<h4 className="font-medium mb-2">{t('howToLoginOAuth')}</h4>
|
|
507
508
|
<ol className="text-sm text-muted-foreground space-y-2 list-decimal list-inside">
|
|
508
|
-
<li>
|
|
509
|
-
<li>
|
|
510
|
-
<li>
|
|
511
|
-
<li>
|
|
512
|
-
<li>
|
|
513
|
-
<li>
|
|
509
|
+
<li>{t('ensureSubscription')}</li>
|
|
510
|
+
<li>{t('openTerminal')}</li>
|
|
511
|
+
<li>{t('runClaudeLogin')} <code className="px-1.5 py-0.5 rounded bg-muted font-mono text-xs">claude /login</code></li>
|
|
512
|
+
<li>{t('chooseOAuthOption')}</li>
|
|
513
|
+
<li>{t('followAuthFlow')}</li>
|
|
514
|
+
<li>{t('restartAfterLogin')}</li>
|
|
514
515
|
</ol>
|
|
515
516
|
</div>
|
|
516
517
|
{error && (
|
|
@@ -522,10 +523,10 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
522
523
|
|
|
523
524
|
<div className="flex gap-2">
|
|
524
525
|
<Button variant="ghost" onClick={handleBack} className="flex-1">
|
|
525
|
-
|
|
526
|
+
{tCommon('back')}
|
|
526
527
|
</Button>
|
|
527
528
|
<Button onClick={handleReload} className="flex-1">
|
|
528
|
-
|
|
529
|
+
{t('loggedInReload')}
|
|
529
530
|
</Button>
|
|
530
531
|
</div>
|
|
531
532
|
</div>
|
|
@@ -533,22 +534,22 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
533
534
|
// Console setup view
|
|
534
535
|
<div className="space-y-4 py-4">
|
|
535
536
|
<div className="p-4 rounded-lg bg-muted/50">
|
|
536
|
-
<h4 className="font-medium mb-2">
|
|
537
|
+
<h4 className="font-medium mb-2">{t('howToUseConsole')}</h4>
|
|
537
538
|
<ol className="text-sm text-muted-foreground space-y-2 list-decimal list-inside">
|
|
538
|
-
<li>
|
|
539
|
-
<li>
|
|
540
|
-
<li>
|
|
541
|
-
<li>
|
|
542
|
-
<li>
|
|
543
|
-
<li>
|
|
539
|
+
<li>{t('ensureSubscription')}</li>
|
|
540
|
+
<li>{t('openTerminal')}</li>
|
|
541
|
+
<li>{t('runClaudeLogin')} <code className="px-1.5 py-0.5 rounded bg-muted font-mono text-xs">claude /login</code></li>
|
|
542
|
+
<li>{t('chooseConsoleOption')}</li>
|
|
543
|
+
<li>{t('followAuthFlow')}</li>
|
|
544
|
+
<li>{t('restartAfterLogin')}</li>
|
|
544
545
|
</ol>
|
|
545
546
|
</div>
|
|
546
547
|
<div className="flex gap-2">
|
|
547
548
|
<Button variant="ghost" onClick={handleBack} className="flex-1">
|
|
548
|
-
|
|
549
|
+
{tCommon('back')}
|
|
549
550
|
</Button>
|
|
550
551
|
<Button onClick={handleReload} className="flex-1">
|
|
551
|
-
|
|
552
|
+
{t('loggedInReload')}
|
|
552
553
|
</Button>
|
|
553
554
|
</div>
|
|
554
555
|
</div>
|
|
@@ -556,18 +557,18 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
556
557
|
// Settings.json info view
|
|
557
558
|
<div className="space-y-4 py-4">
|
|
558
559
|
<div className="p-4 rounded-lg bg-muted/50">
|
|
559
|
-
<h4 className="font-medium mb-2">
|
|
560
|
+
<h4 className="font-medium mb-2">{t('usingClaudeCodeSettings')}</h4>
|
|
560
561
|
<div className="text-sm text-muted-foreground space-y-2">
|
|
561
562
|
<p>
|
|
562
|
-
|
|
563
|
+
{t('settingsFileDescription')}
|
|
563
564
|
</p>
|
|
564
565
|
<ul className="list-disc list-inside pl-2 space-y-1 text-xs">
|
|
565
|
-
<li><strong>
|
|
566
|
-
<li><strong>
|
|
566
|
+
<li><strong>{t('linuxMacOs')}</strong> <code className="px-1 rounded bg-muted font-mono">~/.claude/settings.json</code></li>
|
|
567
|
+
<li><strong>{t('windows')}</strong> <code className="px-1 rounded bg-muted font-mono">%USERPROFILE%\.claude\settings.json</code></li>
|
|
567
568
|
</ul>
|
|
568
|
-
<p className="mt-2">
|
|
569
|
+
<p className="mt-2">{t('envVarsDescription')}</p>
|
|
569
570
|
<ul className="list-disc list-inside pl-2 space-y-1 text-xs">
|
|
570
|
-
<li><code className="px-1 rounded bg-muted font-mono">ANTHROPIC_AUTH_TOKEN</code> <span className="text-destructive"
|
|
571
|
+
<li><code className="px-1 rounded bg-muted font-mono">ANTHROPIC_AUTH_TOKEN</code> <span className="text-destructive">{t('required')}</span></li>
|
|
571
572
|
<li><code className="px-1 rounded bg-muted font-mono">ANTHROPIC_MODEL</code></li>
|
|
572
573
|
<li><code className="px-1 rounded bg-muted font-mono">ANTHROPIC_BASE_URL</code></li>
|
|
573
574
|
<li><code className="px-1 rounded bg-muted font-mono">ANTHROPIC_DEFAULT_HAIKU_MODEL</code></li>
|
|
@@ -577,21 +578,21 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
577
578
|
</ul>
|
|
578
579
|
{providers.settings.configured ? (
|
|
579
580
|
<p className="text-green-600 dark:text-green-400 mt-2">
|
|
580
|
-
✓
|
|
581
|
+
✓ {t('settingsConfigured')}
|
|
581
582
|
</p>
|
|
582
583
|
) : (
|
|
583
584
|
<p className="text-amber-600 dark:text-amber-400 mt-2">
|
|
584
|
-
|
|
585
|
+
{t('settingsNotConfigured')}
|
|
585
586
|
</p>
|
|
586
587
|
)}
|
|
587
588
|
</div>
|
|
588
589
|
</div>
|
|
589
590
|
<div className="flex gap-2">
|
|
590
591
|
<Button variant="ghost" onClick={handleBack} className="flex-1">
|
|
591
|
-
|
|
592
|
+
{tCommon('back')}
|
|
592
593
|
</Button>
|
|
593
594
|
<Button onClick={handleReload} className="flex-1">
|
|
594
|
-
|
|
595
|
+
{t('reloadToApply')}
|
|
595
596
|
</Button>
|
|
596
597
|
</div>
|
|
597
598
|
</div>
|
|
@@ -601,7 +602,7 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
601
602
|
{/* API Key - Required */}
|
|
602
603
|
<div className="space-y-2">
|
|
603
604
|
<Label htmlFor="api-key" className="text-sm font-medium">
|
|
604
|
-
|
|
605
|
+
{t('customApiKey')} {!hasExistingKey && <span className="text-destructive">*</span>}
|
|
605
606
|
</Label>
|
|
606
607
|
<div className="relative">
|
|
607
608
|
<Key className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
|
@@ -610,7 +611,7 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
610
611
|
type="password"
|
|
611
612
|
value={config.ANTHROPIC_AUTH_TOKEN}
|
|
612
613
|
onChange={(e) => handleConfigChange('ANTHROPIC_AUTH_TOKEN', e.target.value)}
|
|
613
|
-
placeholder={hasExistingKey ?
|
|
614
|
+
placeholder={hasExistingKey ? t('leaveEmptyToKeep') : "Enter API key..."}
|
|
614
615
|
className="pl-8"
|
|
615
616
|
disabled={loading}
|
|
616
617
|
autoFocus
|
|
@@ -618,7 +619,7 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
618
619
|
</div>
|
|
619
620
|
{hasExistingKey && (
|
|
620
621
|
<p className="text-xs text-muted-foreground">
|
|
621
|
-
|
|
622
|
+
{t('existingKeyHint')}
|
|
622
623
|
</p>
|
|
623
624
|
)}
|
|
624
625
|
</div>
|
|
@@ -633,13 +634,13 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
633
634
|
disabled={loading}
|
|
634
635
|
>
|
|
635
636
|
<RotateCcw className="h-4 w-4 mr-2" />
|
|
636
|
-
|
|
637
|
+
{t('fillDefaultValues')}
|
|
637
638
|
</Button>
|
|
638
639
|
|
|
639
640
|
{/* Base URL */}
|
|
640
641
|
<div className="space-y-2">
|
|
641
642
|
<Label htmlFor="base-url" className="text-sm font-medium">
|
|
642
|
-
|
|
643
|
+
{t('baseUrl')}
|
|
643
644
|
</Label>
|
|
644
645
|
<Input
|
|
645
646
|
id="base-url"
|
|
@@ -654,7 +655,7 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
654
655
|
{/* Model */}
|
|
655
656
|
<div className="space-y-2">
|
|
656
657
|
<Label htmlFor="model" className="text-sm font-medium">
|
|
657
|
-
|
|
658
|
+
{t('defaultModel')}
|
|
658
659
|
</Label>
|
|
659
660
|
<Input
|
|
660
661
|
id="model"
|
|
@@ -670,7 +671,7 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
670
671
|
<div className="grid grid-cols-3 gap-2">
|
|
671
672
|
<div className="space-y-1">
|
|
672
673
|
<Label htmlFor="haiku-model" className="text-xs font-medium">
|
|
673
|
-
|
|
674
|
+
{t('haikuModel')}
|
|
674
675
|
</Label>
|
|
675
676
|
<Input
|
|
676
677
|
id="haiku-model"
|
|
@@ -684,7 +685,7 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
684
685
|
</div>
|
|
685
686
|
<div className="space-y-1">
|
|
686
687
|
<Label htmlFor="sonnet-model" className="text-xs font-medium">
|
|
687
|
-
|
|
688
|
+
{t('sonnetModel')}
|
|
688
689
|
</Label>
|
|
689
690
|
<Input
|
|
690
691
|
id="sonnet-model"
|
|
@@ -698,7 +699,7 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
698
699
|
</div>
|
|
699
700
|
<div className="space-y-1">
|
|
700
701
|
<Label htmlFor="opus-model" className="text-xs font-medium">
|
|
701
|
-
|
|
702
|
+
{t('opusModel')}
|
|
702
703
|
</Label>
|
|
703
704
|
<Input
|
|
704
705
|
id="opus-model"
|
|
@@ -715,7 +716,7 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
715
716
|
{/* Timeout */}
|
|
716
717
|
<div className="space-y-2">
|
|
717
718
|
<Label htmlFor="timeout" className="text-sm font-medium">
|
|
718
|
-
|
|
719
|
+
{t('apiTimeout')}
|
|
719
720
|
</Label>
|
|
720
721
|
<Input
|
|
721
722
|
id="timeout"
|
|
@@ -728,7 +729,7 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
728
729
|
</div>
|
|
729
730
|
|
|
730
731
|
<p className="text-xs text-muted-foreground">
|
|
731
|
-
|
|
732
|
+
{t('configSavedToEnv')}
|
|
732
733
|
</p>
|
|
733
734
|
|
|
734
735
|
{error && (
|
|
@@ -740,7 +741,7 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
740
741
|
|
|
741
742
|
<div className="flex gap-2">
|
|
742
743
|
<Button variant="ghost" onClick={handleBack} disabled={loading}>
|
|
743
|
-
|
|
744
|
+
{tCommon('back')}
|
|
744
745
|
</Button>
|
|
745
746
|
{hasExistingKey && !showDismissConfirm && (
|
|
746
747
|
<Button
|
|
@@ -748,19 +749,19 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
748
749
|
onClick={() => setShowDismissConfirm(true)}
|
|
749
750
|
disabled={loading}
|
|
750
751
|
>
|
|
751
|
-
|
|
752
|
+
{t('dismissProvider')}
|
|
752
753
|
</Button>
|
|
753
754
|
)}
|
|
754
755
|
{showDismissConfirm && (
|
|
755
756
|
<div className="flex items-center gap-2">
|
|
756
|
-
<span className="text-sm text-destructive">
|
|
757
|
+
<span className="text-sm text-destructive">{t('areYouSure')}</span>
|
|
757
758
|
<Button
|
|
758
759
|
variant="outline"
|
|
759
760
|
size="sm"
|
|
760
761
|
onClick={() => setShowDismissConfirm(false)}
|
|
761
762
|
disabled={loading}
|
|
762
763
|
>
|
|
763
|
-
|
|
764
|
+
{tCommon('no')}
|
|
764
765
|
</Button>
|
|
765
766
|
<Button
|
|
766
767
|
variant="destructive"
|
|
@@ -768,7 +769,7 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
768
769
|
onClick={handleDismissMethod}
|
|
769
770
|
disabled={loading}
|
|
770
771
|
>
|
|
771
|
-
|
|
772
|
+
{t('yesDismiss')}
|
|
772
773
|
</Button>
|
|
773
774
|
</div>
|
|
774
775
|
)}
|
|
@@ -781,10 +782,10 @@ export function AgentProviderSetupForm({ onComplete }: AgentProviderSetupFormPro
|
|
|
781
782
|
{loading ? (
|
|
782
783
|
<>
|
|
783
784
|
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
|
784
|
-
|
|
785
|
+
{tCommon('saving')}
|
|
785
786
|
</>
|
|
786
787
|
) : (
|
|
787
|
-
'
|
|
788
|
+
t('saveConfiguration')
|
|
788
789
|
)}
|
|
789
790
|
</Button>
|
|
790
791
|
)}
|
|
@@ -801,13 +802,14 @@ interface AgentProviderDialogProps {
|
|
|
801
802
|
}
|
|
802
803
|
|
|
803
804
|
export function AgentProviderDialog({ open, onOpenChange }: AgentProviderDialogProps) {
|
|
805
|
+
const t = useTranslations('agentProvider');
|
|
804
806
|
return (
|
|
805
807
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
806
808
|
<DialogContent className="sm:max-w-[500px] z-[9999] max-h-[90vh] overflow-y-auto !grid !grid-rows-[auto_1fr]">
|
|
807
809
|
<DialogHeader>
|
|
808
|
-
<DialogTitle>
|
|
810
|
+
<DialogTitle>{t('configureTitle')}</DialogTitle>
|
|
809
811
|
<DialogDescription>
|
|
810
|
-
|
|
812
|
+
{t('configureDescription')}
|
|
811
813
|
</DialogDescription>
|
|
812
814
|
</DialogHeader>
|
|
813
815
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect } from 'react';
|
|
4
|
+
import { useTranslations } from 'next-intl';
|
|
4
5
|
import { Key, AlertCircle, Check } from 'lucide-react';
|
|
5
6
|
import {
|
|
6
7
|
Dialog,
|
|
@@ -95,6 +96,8 @@ async function verifyApiKey(apiKey: string): Promise<boolean> {
|
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
export function ApiKeyDialog({ open, onOpenChange, onSuccess }: ApiKeyDialogProps) {
|
|
99
|
+
const t = useTranslations('auth');
|
|
100
|
+
const tCommon = useTranslations('common');
|
|
98
101
|
const [apiKey, setApiKey] = useState('');
|
|
99
102
|
const [loading, setLoading] = useState(false);
|
|
100
103
|
const [error, setError] = useState('');
|
|
@@ -112,7 +115,7 @@ export function ApiKeyDialog({ open, onOpenChange, onSuccess }: ApiKeyDialogProp
|
|
|
112
115
|
setError('');
|
|
113
116
|
|
|
114
117
|
if (!apiKey.trim()) {
|
|
115
|
-
setError('
|
|
118
|
+
setError(t('apiKeyIsRequired'));
|
|
116
119
|
return;
|
|
117
120
|
}
|
|
118
121
|
|
|
@@ -125,10 +128,10 @@ export function ApiKeyDialog({ open, onOpenChange, onSuccess }: ApiKeyDialogProp
|
|
|
125
128
|
onOpenChange(false);
|
|
126
129
|
onSuccess();
|
|
127
130
|
} else {
|
|
128
|
-
setError('
|
|
131
|
+
setError(t('invalidApiKey'));
|
|
129
132
|
}
|
|
130
133
|
} catch {
|
|
131
|
-
setError('
|
|
134
|
+
setError(t('failedToVerifyApiKey'));
|
|
132
135
|
} finally {
|
|
133
136
|
setLoading(false);
|
|
134
137
|
}
|
|
@@ -138,9 +141,9 @@ export function ApiKeyDialog({ open, onOpenChange, onSuccess }: ApiKeyDialogProp
|
|
|
138
141
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
139
142
|
<DialogContent className="sm:max-w-[450px] z-[9999]">
|
|
140
143
|
<DialogHeader>
|
|
141
|
-
<DialogTitle>
|
|
144
|
+
<DialogTitle>{t('apiKeyRequired')}</DialogTitle>
|
|
142
145
|
<DialogDescription>
|
|
143
|
-
|
|
146
|
+
{t('serverRequiresApiKey')}
|
|
144
147
|
</DialogDescription>
|
|
145
148
|
</DialogHeader>
|
|
146
149
|
|
|
@@ -148,7 +151,7 @@ export function ApiKeyDialog({ open, onOpenChange, onSuccess }: ApiKeyDialogProp
|
|
|
148
151
|
{/* API Key Input */}
|
|
149
152
|
<div className="space-y-2">
|
|
150
153
|
<label htmlFor="api-key" className="text-sm font-medium">
|
|
151
|
-
|
|
154
|
+
{t('apiKey')}
|
|
152
155
|
</label>
|
|
153
156
|
<div className="relative">
|
|
154
157
|
<Key className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
|
@@ -157,14 +160,14 @@ export function ApiKeyDialog({ open, onOpenChange, onSuccess }: ApiKeyDialogProp
|
|
|
157
160
|
type="password"
|
|
158
161
|
value={apiKey}
|
|
159
162
|
onChange={(e) => setApiKey(e.target.value)}
|
|
160
|
-
placeholder=
|
|
163
|
+
placeholder={t('enterYourApiKey')}
|
|
161
164
|
className="pl-8"
|
|
162
165
|
disabled={loading}
|
|
163
166
|
autoFocus
|
|
164
167
|
/>
|
|
165
168
|
</div>
|
|
166
169
|
<p className="text-xs text-muted-foreground">
|
|
167
|
-
|
|
170
|
+
{t('apiKeyStoredLocally')}
|
|
168
171
|
</p>
|
|
169
172
|
</div>
|
|
170
173
|
|
|
@@ -180,7 +183,7 @@ export function ApiKeyDialog({ open, onOpenChange, onSuccess }: ApiKeyDialogProp
|
|
|
180
183
|
{!error && apiKey && (
|
|
181
184
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
182
185
|
<Check className="h-4 w-4 text-muted-foreground" />
|
|
183
|
-
|
|
186
|
+
{t('pressEnterOrSubmit')}
|
|
184
187
|
</div>
|
|
185
188
|
)}
|
|
186
189
|
|
|
@@ -192,10 +195,10 @@ export function ApiKeyDialog({ open, onOpenChange, onSuccess }: ApiKeyDialogProp
|
|
|
192
195
|
onClick={() => onOpenChange(false)}
|
|
193
196
|
disabled={loading}
|
|
194
197
|
>
|
|
195
|
-
|
|
198
|
+
{tCommon('cancel')}
|
|
196
199
|
</Button>
|
|
197
200
|
<Button type="submit" disabled={loading || !apiKey}>
|
|
198
|
-
{loading ? '
|
|
201
|
+
{loading ? tCommon('verifying') : tCommon('submit')}
|
|
199
202
|
</Button>
|
|
200
203
|
</div>
|
|
201
204
|
</form>
|