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,19 +1,43 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect } from 'react';
|
|
4
|
+
import { useTranslations } from 'next-intl';
|
|
4
5
|
import { ArrowLeft, FolderOpen, X, Bot, Shield, Check } from 'lucide-react';
|
|
5
6
|
import { Button } from '@/components/ui/button';
|
|
6
7
|
import { Input } from '@/components/ui/input';
|
|
8
|
+
import { Checkbox } from '@/components/ui/checkbox';
|
|
7
9
|
import { useProjectStore } from '@/stores/project-store';
|
|
8
10
|
import { useSettingsUIStore } from '@/stores/settings-ui-store';
|
|
9
11
|
import { dispatchAgentProviderConfig } from '@/components/auth/agent-provider-dialog';
|
|
10
12
|
import { ApiAccessKeySetupForm } from '@/components/access-anywhere/api-access-key-setup-modal';
|
|
11
13
|
|
|
12
14
|
export function SettingsPage() {
|
|
15
|
+
const t = useTranslations('settings');
|
|
16
|
+
const tCommon = useTranslations('common');
|
|
13
17
|
const { currentProject, updateProject } = useProjectStore();
|
|
14
18
|
const { setOpen: setSettingsOpen } = useSettingsUIStore();
|
|
15
19
|
const [editingName, setEditingName] = useState('');
|
|
16
20
|
const [isEditing, setIsEditing] = useState(false);
|
|
21
|
+
const [autoCompactEnabled, setAutoCompactEnabled] = useState(false);
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
fetch('/api/settings?keys=auto_compact_enabled')
|
|
25
|
+
.then((res) => res.json())
|
|
26
|
+
.then((data) => {
|
|
27
|
+
if (data.auto_compact_enabled === 'true') {
|
|
28
|
+
setAutoCompactEnabled(true);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
const handleAutoCompactToggle = async (checked: boolean) => {
|
|
34
|
+
setAutoCompactEnabled(checked);
|
|
35
|
+
await fetch('/api/settings', {
|
|
36
|
+
method: 'POST',
|
|
37
|
+
headers: { 'Content-Type': 'application/json' },
|
|
38
|
+
body: JSON.stringify({ key: 'auto_compact_enabled', value: String(checked) }),
|
|
39
|
+
});
|
|
40
|
+
};
|
|
17
41
|
|
|
18
42
|
const [agentProviderConfigured, setAgentProviderConfigured] = useState(false);
|
|
19
43
|
const [apiAccessKeyConfigured, setApiAccessKeyConfigured] = useState(false);
|
|
@@ -71,7 +95,7 @@ export function SettingsPage() {
|
|
|
71
95
|
</Button>
|
|
72
96
|
<div className="flex items-center gap-3">
|
|
73
97
|
<FolderOpen className="w-6 h-6" />
|
|
74
|
-
<h1 className="text-2xl font-bold">
|
|
98
|
+
<h1 className="text-2xl font-bold">{t('title')}</h1>
|
|
75
99
|
</div>
|
|
76
100
|
</div>
|
|
77
101
|
<Button
|
|
@@ -89,7 +113,7 @@ export function SettingsPage() {
|
|
|
89
113
|
{/* Current Project Section */}
|
|
90
114
|
{currentProject && (
|
|
91
115
|
<div className="space-y-4">
|
|
92
|
-
<h2 className="text-lg font-semibold">
|
|
116
|
+
<h2 className="text-lg font-semibold">{t('currentProject')}</h2>
|
|
93
117
|
<div className="space-y-3 p-4 border rounded-lg bg-card">
|
|
94
118
|
<div className="flex items-center gap-3">
|
|
95
119
|
<FolderOpen className="h-5 w-5 text-muted-foreground" />
|
|
@@ -102,14 +126,14 @@ export function SettingsPage() {
|
|
|
102
126
|
autoFocus
|
|
103
127
|
/>
|
|
104
128
|
<Button size="sm" onClick={handleSaveName}>
|
|
105
|
-
|
|
129
|
+
{tCommon('save')}
|
|
106
130
|
</Button>
|
|
107
131
|
<Button
|
|
108
132
|
size="sm"
|
|
109
133
|
variant="ghost"
|
|
110
134
|
onClick={() => setIsEditing(false)}
|
|
111
135
|
>
|
|
112
|
-
|
|
136
|
+
{tCommon('cancel')}
|
|
113
137
|
</Button>
|
|
114
138
|
</div>
|
|
115
139
|
) : (
|
|
@@ -123,7 +147,7 @@ export function SettingsPage() {
|
|
|
123
147
|
setIsEditing(true);
|
|
124
148
|
}}
|
|
125
149
|
>
|
|
126
|
-
|
|
150
|
+
{tCommon('edit')}
|
|
127
151
|
</Button>
|
|
128
152
|
</div>
|
|
129
153
|
)}
|
|
@@ -135,21 +159,43 @@ export function SettingsPage() {
|
|
|
135
159
|
</div>
|
|
136
160
|
)}
|
|
137
161
|
|
|
162
|
+
{/* Context Management Section */}
|
|
163
|
+
<div className="space-y-4">
|
|
164
|
+
<h2 className="text-lg font-semibold">Context Management</h2>
|
|
165
|
+
<div className="space-y-3 p-4 border rounded-lg bg-card">
|
|
166
|
+
<div className="flex items-start gap-3">
|
|
167
|
+
<Checkbox
|
|
168
|
+
id="auto-compact"
|
|
169
|
+
checked={autoCompactEnabled}
|
|
170
|
+
onCheckedChange={(checked) => handleAutoCompactToggle(checked === true)}
|
|
171
|
+
/>
|
|
172
|
+
<div className="space-y-1">
|
|
173
|
+
<label htmlFor="auto-compact" className="font-medium leading-none cursor-pointer">
|
|
174
|
+
Auto-compact conversations
|
|
175
|
+
</label>
|
|
176
|
+
<p className="text-sm text-muted-foreground">
|
|
177
|
+
Automatically compact conversation context when it exceeds 75% of the context window
|
|
178
|
+
</p>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
138
184
|
{/* Agent Provider Section */}
|
|
139
185
|
<div className="space-y-4">
|
|
140
|
-
<h2 className="text-lg font-semibold">
|
|
186
|
+
<h2 className="text-lg font-semibold">{tCommon('agentProvider')}</h2>
|
|
141
187
|
<div className="p-4 border rounded-lg bg-card">
|
|
142
188
|
<div className="flex items-center justify-between">
|
|
143
189
|
<div className="flex items-center gap-3">
|
|
144
190
|
<Bot className="h-5 w-5 text-muted-foreground" />
|
|
145
191
|
<div>
|
|
146
|
-
<p className="font-medium">
|
|
192
|
+
<p className="font-medium">{t('claudeApiConfig')}</p>
|
|
147
193
|
<p className="text-sm text-muted-foreground">
|
|
148
194
|
{loadingStatus
|
|
149
|
-
? '
|
|
195
|
+
? tCommon('checking')
|
|
150
196
|
: agentProviderConfigured
|
|
151
|
-
? '
|
|
152
|
-
: '
|
|
197
|
+
? t('providerConfigured')
|
|
198
|
+
: t('noProviderConfigured')
|
|
153
199
|
}
|
|
154
200
|
</p>
|
|
155
201
|
</div>
|
|
@@ -158,7 +204,7 @@ export function SettingsPage() {
|
|
|
158
204
|
{!loadingStatus && agentProviderConfigured && (
|
|
159
205
|
<span className="inline-flex items-center gap-1 text-xs text-green-600 dark:text-green-400">
|
|
160
206
|
<Check className="h-3 w-3" />
|
|
161
|
-
|
|
207
|
+
{tCommon('configured')}
|
|
162
208
|
</span>
|
|
163
209
|
)}
|
|
164
210
|
<Button
|
|
@@ -166,7 +212,7 @@ export function SettingsPage() {
|
|
|
166
212
|
size="sm"
|
|
167
213
|
onClick={() => dispatchAgentProviderConfig()}
|
|
168
214
|
>
|
|
169
|
-
|
|
215
|
+
{t('configure')}
|
|
170
216
|
</Button>
|
|
171
217
|
</div>
|
|
172
218
|
</div>
|
|
@@ -175,19 +221,19 @@ export function SettingsPage() {
|
|
|
175
221
|
|
|
176
222
|
{/* API Access Key Section */}
|
|
177
223
|
<div className="space-y-4">
|
|
178
|
-
<h2 className="text-lg font-semibold">
|
|
224
|
+
<h2 className="text-lg font-semibold">{t('apiAccessKey')}</h2>
|
|
179
225
|
<div className="p-4 border rounded-lg bg-card space-y-4">
|
|
180
226
|
<div className="flex items-center justify-between">
|
|
181
227
|
<div className="flex items-center gap-3">
|
|
182
228
|
<Shield className="h-5 w-5 text-muted-foreground" />
|
|
183
229
|
<div>
|
|
184
|
-
<p className="font-medium">
|
|
230
|
+
<p className="font-medium">{t('remoteAccessAuth')}</p>
|
|
185
231
|
<p className="text-sm text-muted-foreground">
|
|
186
232
|
{loadingStatus
|
|
187
|
-
? '
|
|
233
|
+
? tCommon('checking')
|
|
188
234
|
: apiAccessKeyConfigured
|
|
189
|
-
? '
|
|
190
|
-
: '
|
|
235
|
+
? t('apiKeyConfigured')
|
|
236
|
+
: t('noApiKeyConfigured')
|
|
191
237
|
}
|
|
192
238
|
</p>
|
|
193
239
|
</div>
|
|
@@ -195,7 +241,7 @@ export function SettingsPage() {
|
|
|
195
241
|
{!loadingStatus && apiAccessKeyConfigured && (
|
|
196
242
|
<span className="inline-flex items-center gap-1 text-xs text-green-600 dark:text-green-400">
|
|
197
243
|
<Check className="h-3 w-3" />
|
|
198
|
-
|
|
244
|
+
{tCommon('configured')}
|
|
199
245
|
</span>
|
|
200
246
|
)}
|
|
201
247
|
</div>
|
|
@@ -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 { FolderOpen, AlertCircle, Plus, FolderOpen as FolderOpenIcon, Folder } from 'lucide-react';
|
|
5
6
|
import {
|
|
6
7
|
Dialog,
|
|
@@ -25,6 +26,8 @@ interface SetupDialogProps {
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
29
|
+
const t = useTranslations('settings');
|
|
30
|
+
const tCommon = useTranslations('common');
|
|
28
31
|
const { createProject, setCurrentProject } = useProjectStore();
|
|
29
32
|
const [mode, setMode] = useState<Mode>('open');
|
|
30
33
|
const [name, setName] = useState('');
|
|
@@ -68,7 +71,7 @@ export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
|
68
71
|
setError('');
|
|
69
72
|
|
|
70
73
|
if (!name.trim()) {
|
|
71
|
-
setError('
|
|
74
|
+
setError(t('projectNameRequired'));
|
|
72
75
|
return;
|
|
73
76
|
}
|
|
74
77
|
|
|
@@ -77,26 +80,26 @@ export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
|
77
80
|
// For create mode, build path from root + sanitized name
|
|
78
81
|
if (mode === 'create') {
|
|
79
82
|
if (!rootPath.trim()) {
|
|
80
|
-
setError('
|
|
83
|
+
setError(t('rootFolderRequired'));
|
|
81
84
|
return;
|
|
82
85
|
}
|
|
83
86
|
const sanitizedName = sanitizeDirName(name);
|
|
84
87
|
if (!sanitizedName) {
|
|
85
|
-
setError('
|
|
88
|
+
setError(t('projectNameAlphanumeric'));
|
|
86
89
|
return;
|
|
87
90
|
}
|
|
88
91
|
finalPath = `${rootPath.trim()}/${sanitizedName}`;
|
|
89
92
|
} else {
|
|
90
93
|
// Open mode - path is required
|
|
91
94
|
if (!path.trim()) {
|
|
92
|
-
setError('
|
|
95
|
+
setError(t('projectPathRequired'));
|
|
93
96
|
return;
|
|
94
97
|
}
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
// Validate path format
|
|
98
101
|
if (!finalPath.startsWith('/') && !finalPath.match(/^[A-Za-z]:\\/)) {
|
|
99
|
-
setError('
|
|
102
|
+
setError(t('enterAbsolutePath'));
|
|
100
103
|
return;
|
|
101
104
|
}
|
|
102
105
|
|
|
@@ -122,11 +125,11 @@ export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
|
122
125
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
123
126
|
<DialogContent className="sm:max-w-[500px]">
|
|
124
127
|
<DialogHeader>
|
|
125
|
-
<DialogTitle>
|
|
128
|
+
<DialogTitle>{t('setUpProject')}</DialogTitle>
|
|
126
129
|
<DialogDescription>
|
|
127
130
|
{mode === 'open'
|
|
128
|
-
? '
|
|
129
|
-
: '
|
|
131
|
+
? t('selectExistingDescription')
|
|
132
|
+
: t('configureNewDescription')}
|
|
130
133
|
</DialogDescription>
|
|
131
134
|
</DialogHeader>
|
|
132
135
|
|
|
@@ -137,14 +140,14 @@ export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
|
137
140
|
className="[&[data-state=active]]:![background-color:rgba(255,255,255,0.2)]"
|
|
138
141
|
>
|
|
139
142
|
<FolderOpenIcon className="h-4 w-4" />
|
|
140
|
-
|
|
143
|
+
{t('openExisting')}
|
|
141
144
|
</TabsTrigger>
|
|
142
145
|
<TabsTrigger
|
|
143
146
|
value="create"
|
|
144
147
|
className="[&[data-state=active]]:![background-color:rgba(255,255,255,0.2)]"
|
|
145
148
|
>
|
|
146
149
|
<Plus className="h-4 w-4" />
|
|
147
|
-
|
|
150
|
+
{t('createNew')}
|
|
148
151
|
</TabsTrigger>
|
|
149
152
|
</TabsList>
|
|
150
153
|
|
|
@@ -153,7 +156,7 @@ export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
|
153
156
|
{/* Project Path - auto-named from folder */}
|
|
154
157
|
<div className="space-y-2">
|
|
155
158
|
<label htmlFor="path-open" className="text-sm font-medium">
|
|
156
|
-
|
|
159
|
+
{t('projectFolder')}
|
|
157
160
|
</label>
|
|
158
161
|
<div className="flex gap-2">
|
|
159
162
|
<div
|
|
@@ -177,12 +180,12 @@ export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
|
177
180
|
onClick={() => (setBrowserMode('project'), setFolderBrowserOpen(true))}
|
|
178
181
|
disabled={loading}
|
|
179
182
|
>
|
|
180
|
-
|
|
183
|
+
{tCommon('browse')}
|
|
181
184
|
</Button>
|
|
182
185
|
</div>
|
|
183
186
|
{path && (
|
|
184
187
|
<p className="text-xs text-muted-foreground">
|
|
185
|
-
|
|
188
|
+
{t('projectName')}: <span className="font-medium">{name || t('autoDetected')}</span>
|
|
186
189
|
</p>
|
|
187
190
|
)}
|
|
188
191
|
</div>
|
|
@@ -203,10 +206,10 @@ export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
|
203
206
|
onClick={() => onOpenChange(false)}
|
|
204
207
|
disabled={loading}
|
|
205
208
|
>
|
|
206
|
-
|
|
209
|
+
{tCommon('cancel')}
|
|
207
210
|
</Button>
|
|
208
211
|
<Button type="submit" disabled={loading || !path}>
|
|
209
|
-
{loading ? '
|
|
212
|
+
{loading ? tCommon('opening') : t('openProject')}
|
|
210
213
|
</Button>
|
|
211
214
|
</div>
|
|
212
215
|
</form>
|
|
@@ -217,7 +220,7 @@ export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
|
217
220
|
{/* Project Name */}
|
|
218
221
|
<div className="space-y-2">
|
|
219
222
|
<label htmlFor="name" className="text-sm font-medium">
|
|
220
|
-
|
|
223
|
+
{t('projectName')}
|
|
221
224
|
</label>
|
|
222
225
|
<Input
|
|
223
226
|
id="name"
|
|
@@ -227,14 +230,14 @@ export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
|
227
230
|
disabled={loading}
|
|
228
231
|
/>
|
|
229
232
|
<p className="text-xs text-muted-foreground">
|
|
230
|
-
|
|
233
|
+
{t('folderNameHint')}
|
|
231
234
|
</p>
|
|
232
235
|
</div>
|
|
233
236
|
|
|
234
237
|
{/* Root Folder */}
|
|
235
238
|
<div className="space-y-2">
|
|
236
239
|
<label htmlFor="root-path" className="text-sm font-medium">
|
|
237
|
-
|
|
240
|
+
{t('rootFolder')}
|
|
238
241
|
</label>
|
|
239
242
|
<div className="flex gap-2">
|
|
240
243
|
<div
|
|
@@ -258,11 +261,11 @@ export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
|
258
261
|
onClick={() => (setBrowserMode('root'), setFolderBrowserOpen(true))}
|
|
259
262
|
disabled={loading}
|
|
260
263
|
>
|
|
261
|
-
|
|
264
|
+
{tCommon('browse')}
|
|
262
265
|
</Button>
|
|
263
266
|
</div>
|
|
264
267
|
<p className="text-xs text-muted-foreground">
|
|
265
|
-
|
|
268
|
+
{t('selectParentFolder')}
|
|
266
269
|
</p>
|
|
267
270
|
</div>
|
|
268
271
|
|
|
@@ -270,7 +273,7 @@ export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
|
270
273
|
{fullProjectPath && (
|
|
271
274
|
<div className="space-y-1">
|
|
272
275
|
<label className="text-sm font-medium">
|
|
273
|
-
|
|
276
|
+
{t('projectCreatedAt')}
|
|
274
277
|
</label>
|
|
275
278
|
<div className="p-3 bg-muted rounded-md text-sm font-mono break-all">
|
|
276
279
|
{fullProjectPath}
|
|
@@ -294,10 +297,10 @@ export function SetupDialog({ open, onOpenChange }: SetupDialogProps) {
|
|
|
294
297
|
onClick={() => onOpenChange(false)}
|
|
295
298
|
disabled={loading}
|
|
296
299
|
>
|
|
297
|
-
|
|
300
|
+
{tCommon('cancel')}
|
|
298
301
|
</Button>
|
|
299
302
|
<Button type="submit" disabled={loading || !name || !rootPath}>
|
|
300
|
-
{loading ? '
|
|
303
|
+
{loading ? tCommon('creating') : t('createProject')}
|
|
301
304
|
</Button>
|
|
302
305
|
</div>
|
|
303
306
|
</form>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect, useRef } from 'react';
|
|
4
|
+
import { useTranslations } from 'next-intl';
|
|
4
5
|
import {
|
|
5
6
|
Dialog,
|
|
6
7
|
DialogContent,
|
|
@@ -32,6 +33,8 @@ interface UnifiedSetupWizardProps {
|
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export function UnifiedSetupWizard({ open, onOpenChange, initialStatus }: UnifiedSetupWizardProps) {
|
|
36
|
+
const t = useTranslations('settings');
|
|
37
|
+
const tCommon = useTranslations('common');
|
|
35
38
|
const [expandedSection, setExpandedSection] = useState<SectionId | null>(null);
|
|
36
39
|
const [status, setStatus] = useState<SectionStatus>({
|
|
37
40
|
agentProvider: initialStatus?.agentProvider ?? false,
|
|
@@ -118,9 +121,9 @@ export function UnifiedSetupWizard({ open, onOpenChange, initialStatus }: Unifie
|
|
|
118
121
|
<Dialog open={open} onOpenChange={handleClose}>
|
|
119
122
|
<DialogContent className="sm:max-w-[600px] z-[9999] max-h-[80vh] p-0 flex flex-col overflow-hidden">
|
|
120
123
|
<DialogHeader className="p-6 pb-2 shrink-0">
|
|
121
|
-
<DialogTitle>
|
|
124
|
+
<DialogTitle>{t('setUpWorkspace')}</DialogTitle>
|
|
122
125
|
<DialogDescription>
|
|
123
|
-
|
|
126
|
+
{t('setUpWorkspaceDescription')}
|
|
124
127
|
</DialogDescription>
|
|
125
128
|
</DialogHeader>
|
|
126
129
|
|
|
@@ -139,9 +142,9 @@ export function UnifiedSetupWizard({ open, onOpenChange, initialStatus }: Unifie
|
|
|
139
142
|
{status.agentProvider ? <Check className="h-4 w-4" /> : <Bot className="h-4 w-4" />}
|
|
140
143
|
</div>
|
|
141
144
|
<div>
|
|
142
|
-
<span className="font-medium">
|
|
145
|
+
<span className="font-medium">{tCommon('agentProvider')}</span>
|
|
143
146
|
<p className="text-xs text-muted-foreground">
|
|
144
|
-
{status.agentProvider ? '
|
|
147
|
+
{status.agentProvider ? tCommon('configured') : t('configureAuthDescription')}
|
|
145
148
|
</p>
|
|
146
149
|
</div>
|
|
147
150
|
</div>
|
|
@@ -171,9 +174,9 @@ export function UnifiedSetupWizard({ open, onOpenChange, initialStatus }: Unifie
|
|
|
171
174
|
{status.apiAccessKey ? <Check className="h-4 w-4" /> : <Shield className="h-4 w-4" />}
|
|
172
175
|
</div>
|
|
173
176
|
<div>
|
|
174
|
-
<span className="font-medium">
|
|
177
|
+
<span className="font-medium">{t('apiAccessKey')}</span>
|
|
175
178
|
<p className="text-xs text-muted-foreground">
|
|
176
|
-
{status.apiAccessKey ? '
|
|
179
|
+
{status.apiAccessKey ? tCommon('configured') : t('setUpRemoteAccess')}
|
|
177
180
|
</p>
|
|
178
181
|
</div>
|
|
179
182
|
</div>
|
|
@@ -203,9 +206,9 @@ export function UnifiedSetupWizard({ open, onOpenChange, initialStatus }: Unifie
|
|
|
203
206
|
{status.remoteAccess ? <Check className="h-4 w-4" /> : <Globe className="h-4 w-4" />}
|
|
204
207
|
</div>
|
|
205
208
|
<div>
|
|
206
|
-
<span className="font-medium">
|
|
209
|
+
<span className="font-medium">{tCommon('accessAnywhere')}</span>
|
|
207
210
|
<p className="text-xs text-muted-foreground">
|
|
208
|
-
{status.remoteAccess ? '
|
|
211
|
+
{status.remoteAccess ? tCommon('configured') : t('setUpRemoteAccess')}
|
|
209
212
|
</p>
|
|
210
213
|
</div>
|
|
211
214
|
</div>
|
|
@@ -242,7 +245,7 @@ export function UnifiedSetupWizard({ open, onOpenChange, initialStatus }: Unifie
|
|
|
242
245
|
</Label>
|
|
243
246
|
</div>
|
|
244
247
|
<Button variant="outline" onClick={handleClose}>
|
|
245
|
-
|
|
248
|
+
{tCommon('close')}
|
|
246
249
|
</Button>
|
|
247
250
|
</div>
|
|
248
251
|
</DialogContent>
|
|
@@ -17,6 +17,7 @@ import { toast } from 'sonner';
|
|
|
17
17
|
import { useSidebarStore } from '@/stores/sidebar-store';
|
|
18
18
|
import { FileUploadDialog } from './file-upload-dialog';
|
|
19
19
|
import type { FileEntry } from '@/types';
|
|
20
|
+
import { useTranslations } from 'next-intl';
|
|
20
21
|
|
|
21
22
|
interface FileCreateButtonsProps {
|
|
22
23
|
/** Parent directory entry where files/folders will be created */
|
|
@@ -32,6 +33,9 @@ interface FileCreateButtonsProps {
|
|
|
32
33
|
* Displays at the bottom of file tree for quick creation at project root
|
|
33
34
|
*/
|
|
34
35
|
export function FileCreateButtons({ entry, rootPath, onRefresh }: FileCreateButtonsProps) {
|
|
36
|
+
const tSidebar = useTranslations('sidebar');
|
|
37
|
+
const tSettings = useTranslations('settings');
|
|
38
|
+
const tCommon = useTranslations('common');
|
|
35
39
|
const [createDialogOpen, setCreateDialogOpen] = useState(false);
|
|
36
40
|
const [uploadDialogOpen, setUploadDialogOpen] = useState(false);
|
|
37
41
|
const [createType, setCreateType] = useState<'file' | 'folder'>('file');
|
|
@@ -65,7 +69,7 @@ export function FileCreateButtons({ entry, rootPath, onRefresh }: FileCreateButt
|
|
|
65
69
|
const handleCreate = async () => {
|
|
66
70
|
const trimmedName = createName.trim();
|
|
67
71
|
if (!trimmedName) {
|
|
68
|
-
toast.error('
|
|
72
|
+
toast.error(tSidebar('nameCannotBeEmpty'));
|
|
69
73
|
return;
|
|
70
74
|
}
|
|
71
75
|
|
|
@@ -84,7 +88,7 @@ export function FileCreateButtons({ entry, rootPath, onRefresh }: FileCreateButt
|
|
|
84
88
|
|
|
85
89
|
if (!res.ok) {
|
|
86
90
|
const data = await res.json();
|
|
87
|
-
throw new Error(data.error || '
|
|
91
|
+
throw new Error(data.error || tSettings('createFailed'));
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
const data = await res.json();
|
|
@@ -103,7 +107,7 @@ export function FileCreateButtons({ entry, rootPath, onRefresh }: FileCreateButt
|
|
|
103
107
|
openTab(data.path);
|
|
104
108
|
}
|
|
105
109
|
} catch (err) {
|
|
106
|
-
toast.error(err instanceof Error ? err.message : '
|
|
110
|
+
toast.error(err instanceof Error ? err.message : tSettings('createFailed'));
|
|
107
111
|
} finally {
|
|
108
112
|
setIsCreating(false);
|
|
109
113
|
}
|
|
@@ -14,6 +14,7 @@ import { useContextMentionStore } from '@/stores/context-mention-store';
|
|
|
14
14
|
import { useProjectStore } from '@/stores/project-store';
|
|
15
15
|
import { useFileSync } from '@/hooks/use-file-sync';
|
|
16
16
|
import { waitForElement } from '@/lib/utils';
|
|
17
|
+
import { useTranslations } from 'next-intl';
|
|
17
18
|
|
|
18
19
|
interface FileContent {
|
|
19
20
|
content: string | null;
|
|
@@ -30,6 +31,9 @@ interface FileTabContentProps {
|
|
|
30
31
|
|
|
31
32
|
export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
32
33
|
const activeProject = useActiveProject();
|
|
34
|
+
const t = useTranslations('editor');
|
|
35
|
+
const tCommon = useTranslations('common');
|
|
36
|
+
const tSidebar = useTranslations('sidebar');
|
|
33
37
|
const { editorPosition, setEditorPosition, updateTabDirty, pendingEditorPosition, clearPendingEditorPosition } = useSidebarStore();
|
|
34
38
|
const { selectedTask, tasks, createTask, selectTask, setSelectedTask } = useTaskStore();
|
|
35
39
|
const { addFileMention, addLineMention } = useContextMentionStore();
|
|
@@ -439,7 +443,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
439
443
|
if (createNew || !targetTask) {
|
|
440
444
|
const projectId = selectedProjectIds[0];
|
|
441
445
|
if (!projectId) {
|
|
442
|
-
alert('
|
|
446
|
+
alert(tSidebar('selectProject'));
|
|
443
447
|
return;
|
|
444
448
|
}
|
|
445
449
|
|
|
@@ -470,7 +474,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
470
474
|
}
|
|
471
475
|
} catch (error) {
|
|
472
476
|
console.error('Failed to attach file:', error);
|
|
473
|
-
alert(error instanceof Error ? error.message : '
|
|
477
|
+
alert(error instanceof Error ? error.message : t('addFileToChat'));
|
|
474
478
|
}
|
|
475
479
|
};
|
|
476
480
|
|
|
@@ -498,7 +502,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
498
502
|
variant="ghost"
|
|
499
503
|
size="icon-sm"
|
|
500
504
|
onClick={() => setSearchVisible(!searchVisible)}
|
|
501
|
-
title=
|
|
505
|
+
title={t('searchPlaceholder') + ' (⌘F)'}
|
|
502
506
|
className={searchVisible ? 'bg-accent' : ''}
|
|
503
507
|
>
|
|
504
508
|
<Search className="size-4" />
|
|
@@ -512,7 +516,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
512
516
|
size="icon-sm"
|
|
513
517
|
onClick={handleUndo}
|
|
514
518
|
disabled={!canUndo}
|
|
515
|
-
title=
|
|
519
|
+
title={t('undo') + ' (⌘Z)'}
|
|
516
520
|
>
|
|
517
521
|
<Undo className="size-4" />
|
|
518
522
|
</Button>
|
|
@@ -521,7 +525,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
521
525
|
size="icon-sm"
|
|
522
526
|
onClick={handleRedo}
|
|
523
527
|
disabled={!canRedo}
|
|
524
|
-
title=
|
|
528
|
+
title={t('redo') + ' (⌘⇧Z)'}
|
|
525
529
|
>
|
|
526
530
|
<Redo className="size-4" />
|
|
527
531
|
</Button>
|
|
@@ -534,7 +538,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
534
538
|
size="sm"
|
|
535
539
|
onClick={handleSave}
|
|
536
540
|
disabled={!isDirty || saveStatus === 'saving'}
|
|
537
|
-
title=
|
|
541
|
+
title={tCommon('save') + ' (⌘S)'}
|
|
538
542
|
className="text-xs gap-1"
|
|
539
543
|
>
|
|
540
544
|
<Save className="size-3" />
|
|
@@ -547,7 +551,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
547
551
|
variant="ghost"
|
|
548
552
|
size="icon-sm"
|
|
549
553
|
onClick={toggleViewMode}
|
|
550
|
-
title={viewMode === 'preview' ? '
|
|
554
|
+
title={viewMode === 'preview' ? t('showSourceCode') : t('showPreview')}
|
|
551
555
|
className={viewMode === 'preview' ? 'bg-accent' : ''}
|
|
552
556
|
>
|
|
553
557
|
{viewMode === 'preview' ? <Code className="size-4" /> : <Eye className="size-4" />}
|
|
@@ -560,7 +564,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
560
564
|
<Button
|
|
561
565
|
variant="ghost"
|
|
562
566
|
size="icon-sm"
|
|
563
|
-
title={selection ?
|
|
567
|
+
title={selection ? t('addLinesToChat', { startLine: selection.startLine, endLine: selection.endLine }) : t('addFileToChat')}
|
|
564
568
|
className="relative"
|
|
565
569
|
>
|
|
566
570
|
<AtSign className="size-4" />
|
|
@@ -615,7 +619,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
615
619
|
<Button
|
|
616
620
|
variant="ghost"
|
|
617
621
|
size="icon-sm"
|
|
618
|
-
title=
|
|
622
|
+
title={t('export')}
|
|
619
623
|
>
|
|
620
624
|
<Download className="size-4" />
|
|
621
625
|
</Button>
|
|
@@ -642,7 +646,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
642
646
|
<div className="flex items-center gap-2 min-w-0 flex-1 justify-end">
|
|
643
647
|
{/* Sync indicator */}
|
|
644
648
|
{fileSync.isPolling && (
|
|
645
|
-
<span title=
|
|
649
|
+
<span title={t('checkingForChanges')}>
|
|
646
650
|
<RefreshCw className="size-3 animate-spin text-muted-foreground" />
|
|
647
651
|
</span>
|
|
648
652
|
)}
|
|
@@ -652,7 +656,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
652
656
|
size="sm"
|
|
653
657
|
onClick={() => setShowDiffResolver(true)}
|
|
654
658
|
className="text-xs gap-1 text-amber-600 dark:text-amber-400 hover:text-amber-600 dark:hover:text-amber-400"
|
|
655
|
-
title=
|
|
659
|
+
title={t('externalChangesDetected')}
|
|
656
660
|
>
|
|
657
661
|
<AlertCircle className="size-3" />
|
|
658
662
|
<span className="hidden sm:inline">Conflict</span>
|
|
@@ -687,7 +691,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
687
691
|
closeSearch();
|
|
688
692
|
}
|
|
689
693
|
}}
|
|
690
|
-
placeholder=
|
|
694
|
+
placeholder={t('searchPlaceholder')}
|
|
691
695
|
className="flex-1 min-w-0 bg-transparent border-0 outline-none text-sm placeholder:text-muted-foreground"
|
|
692
696
|
/>
|
|
693
697
|
{searchQuery && (
|
|
@@ -700,7 +704,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
700
704
|
size="icon-sm"
|
|
701
705
|
onClick={handlePrevMatch}
|
|
702
706
|
disabled={totalMatches === 0}
|
|
703
|
-
title=
|
|
707
|
+
title={t('previousMatch') + ' (⇧Enter)'}
|
|
704
708
|
className="shrink-0"
|
|
705
709
|
>
|
|
706
710
|
<span className="text-xs">↑</span>
|
|
@@ -710,7 +714,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
710
714
|
size="icon-sm"
|
|
711
715
|
onClick={handleNextMatch}
|
|
712
716
|
disabled={totalMatches === 0}
|
|
713
|
-
title=
|
|
717
|
+
title={t('nextMatch') + ' (Enter)'}
|
|
714
718
|
className="shrink-0"
|
|
715
719
|
>
|
|
716
720
|
<span className="text-xs">↓</span>
|
|
@@ -721,7 +725,7 @@ export function FileTabContent({ tabId, filePath }: FileTabContentProps) {
|
|
|
721
725
|
variant="ghost"
|
|
722
726
|
size="icon-sm"
|
|
723
727
|
onClick={closeSearch}
|
|
724
|
-
title=
|
|
728
|
+
title={tCommon('close') + ' (Esc)'}
|
|
725
729
|
className="shrink-0"
|
|
726
730
|
>
|
|
727
731
|
<X className="size-4" />
|