dsh-coding-sidebar 1.0.8 → 1.0.9

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 (50) hide show
  1. package/lib/client-editor.js +223 -175
  2. package/lib/client-registry.js +763 -344
  3. package/lib/client-terminal.js +283 -179
  4. package/lib/client.js +760 -341
  5. package/lib/index.js +151 -2
  6. package/lib/types/client/DiffView.d.ts +33 -1
  7. package/lib/types/client/EditorHost.d.ts +3 -0
  8. package/lib/types/client/FileTree.d.ts +4 -0
  9. package/lib/types/client/TerminalWaitBanner.d.ts +6 -0
  10. package/lib/types/client/TreePanel.d.ts +3 -0
  11. package/lib/types/client/api.d.ts +26 -0
  12. package/lib/types/client/locales.d.ts +12 -0
  13. package/lib/types/client/state.d.ts +15 -0
  14. package/lib/types/fs-operations.d.ts +42 -0
  15. package/lib/types/git.d.ts +15 -0
  16. package/package.json +1 -1
  17. package/src/client/DiffTab.tsx +10 -1
  18. package/src/client/DiffView.tsx +174 -19
  19. package/src/client/EditorHost.tsx +8 -1
  20. package/src/client/FileTree.tsx +147 -4
  21. package/src/client/Sidebar.tsx +54 -3
  22. package/src/client/TerminalView.tsx +28 -0
  23. package/src/client/TerminalWaitBanner.tsx +32 -0
  24. package/src/client/TreePanel.tsx +6 -1
  25. package/src/client/api.ts +20 -0
  26. package/src/client/locales-ar.ts +12 -0
  27. package/src/client/locales-de.ts +12 -0
  28. package/src/client/locales-fr.ts +12 -0
  29. package/src/client/locales-hi.ts +12 -0
  30. package/src/client/locales-id.ts +12 -0
  31. package/src/client/locales-it.ts +12 -0
  32. package/src/client/locales-ja.ts +12 -0
  33. package/src/client/locales-ko.ts +12 -0
  34. package/src/client/locales-nl.ts +12 -0
  35. package/src/client/locales-pl.ts +12 -0
  36. package/src/client/locales-pt.ts +12 -0
  37. package/src/client/locales-ru.ts +12 -0
  38. package/src/client/locales-sv.ts +12 -0
  39. package/src/client/locales-th.ts +12 -0
  40. package/src/client/locales-tr.ts +12 -0
  41. package/src/client/locales-vi.ts +12 -0
  42. package/src/client/locales-zh-HK.ts +12 -0
  43. package/src/client/locales-zh-MO.ts +12 -0
  44. package/src/client/locales-zh-TW.ts +12 -0
  45. package/src/client/locales.ts +24 -0
  46. package/src/client/sidebar.module.css +68 -0
  47. package/src/client/state.ts +42 -3
  48. package/src/fs-operations.ts +126 -4
  49. package/src/git.ts +39 -2
  50. package/src/index.ts +43 -1
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The "Agent 正在等待 {needle}" wait banner: rendered at the top of an
3
+ * agent-owned terminal's view while the model blocks in terminal_wait_for.
4
+ * The skip button asks the host to abort every active wait on the terminal
5
+ * (`agent-pty.skip-wait`); the banner disappears when the host's next
6
+ * agent-terminals push drops the waiting field — no optimistic UI. Kept in
7
+ * its own module (no xterm imports) so jsdom tests can render it directly.
8
+ */
9
+ import { t } from './locales.ts'
10
+ import css from './sidebar.module.css'
11
+
12
+ /** Cap the needle shown inline; the full text rides the title tooltip. */
13
+ const NEEDLE_DISPLAY_CAP = 80
14
+
15
+ /** Truncate one needle for inline display (title attr carries the full text). */
16
+ export function truncateNeedle(needle: string): string {
17
+ return needle.length > NEEDLE_DISPLAY_CAP ? `${needle.slice(0, NEEDLE_DISPLAY_CAP - 1)}…` : needle
18
+ }
19
+
20
+ export function TerminalWaitBanner(props: { needle: string; onSkip: () => void }) {
21
+ const { needle, onSkip } = props
22
+ return (
23
+ <div className={css.terminalWaitBanner}>
24
+ <span className={css.terminalWaitNeedle} title={needle}>
25
+ {t('terminalWaitBanner', { needle: truncateNeedle(needle) })}
26
+ </span>
27
+ <button type="button" className={css.terminalRetry} onClick={onSkip}>
28
+ {t('terminalSkipWait')}
29
+ </button>
30
+ </div>
31
+ )
32
+ }
@@ -60,11 +60,14 @@ export function TreePanel(props: {
60
60
  onOpenWith?: (targetId: string, path: string) => void
61
61
  onToggleOpenWithPin?: (targetId: string) => void
62
62
  onReferenceFile: (path: string, isDir: boolean) => void
63
+ /** Tree-row mutations (passed through to the file tree; absent → hidden). */
64
+ onPathRenamed?: (oldPath: string, newPath: string) => void
65
+ onPathRemoved?: (path: string) => void
63
66
  /** Full-window presentation: the panel fills its host instead of docking
64
67
  * at a fixed width. */
65
68
  full?: boolean
66
69
  }) {
67
- const { sessionId, cwd, expanded, revealed, onToggle, onOpenFile, onOpenFileNewTab, onOpenFileSide, openWithTargets, openWithPinned, openWithSsh, onOpenWith, onToggleOpenWithPin, onReferenceFile, full } = props
70
+ const { sessionId, cwd, expanded, revealed, onToggle, onOpenFile, onOpenFileNewTab, onOpenFileSide, openWithTargets, openWithPinned, openWithSsh, onOpenWith, onToggleOpenWithPin, onReferenceFile, onPathRenamed, onPathRemoved, full } = props
68
71
  const [query, setQuery] = useState('')
69
72
  const [results, setResults] = useState<{ matches: string[]; truncated: boolean } | null>(null)
70
73
  const [error, setError] = useState<string | null>(null)
@@ -248,6 +251,8 @@ export function TreePanel(props: {
248
251
  onOpenWith={onOpenWith}
249
252
  onToggleOpenWithPin={onToggleOpenWithPin}
250
253
  onReferenceFile={onReferenceFile}
254
+ onPathRenamed={onPathRenamed}
255
+ onPathRemoved={onPathRemoved}
251
256
  refreshTick={refreshTick}
252
257
  onUploadRequest={startUpload}
253
258
  busy={busy}
package/src/client/api.ts CHANGED
@@ -212,6 +212,14 @@ export const api = {
212
212
  call<FsTextResult | FsBinaryResult>('fs.read', scopePayload(scope, { path }), signal),
213
213
  fsWrite: (scope: SessionScope, path: string, content: string) =>
214
214
  call<{ ok: true }>('fs.write', scopePayload(scope, { path, content })),
215
+ /** Rename one tree row within its directory (single-segment name; a
216
+ * destination-existence clash is a 409; symlink rows rename the link). */
217
+ fsRename: (scope: SessionScope, path: string, name: string) =>
218
+ call<{ path: string }>('fs.rename', scopePayload(scope, { path, name })),
219
+ /** Delete one tree row permanently (recursive for directories; a symlink
220
+ * row unlinks the link only). */
221
+ fsRemove: (scope: SessionScope, path: string) =>
222
+ call<{ path: string }>('fs.remove', scopePayload(scope, { path })),
215
223
  /** Upload one file's raw bytes into `dir` (keeps the folder tree via
216
224
  * `relativePath`); the host streams it under the session workspace. */
217
225
  uploadFile: (scope: SessionScope, dir: string, relativePath: string, body: Blob, signal?: AbortSignal) =>
@@ -241,6 +249,14 @@ export const api = {
241
249
  /** Full patch text of one commit (diff display for the history rows). */
242
250
  gitCommitDiff: (scope: SessionScope, hash: string, worktree?: string, signal?: AbortSignal) =>
243
251
  call<{ diff: string }>('git.commit-diff', gitPayload(scope, worktree, { hash }), signal),
252
+ /** Both sides' full file contents for a diff-fold expansion; a missing
253
+ * side is null (untracked / deleted) and the view degrades the fold. */
254
+ gitFoldContents: (scope: SessionScope, opts: { path: string; staged?: boolean; hash?: string }, worktree?: string, signal?: AbortSignal) =>
255
+ call<{ old: string | null; new: string | null }>('git.fold-contents', gitPayload(scope, worktree, {
256
+ path: opts.path,
257
+ ...(opts.staged !== undefined ? { staged: opts.staged } : {}),
258
+ ...(opts.hash !== undefined ? { hash: opts.hash } : {}),
259
+ }), signal),
244
260
  /** Discard the worktree changes of one file (the index is untouched). */
245
261
  gitDiscard: (scope: SessionScope, path: string, worktree?: string) =>
246
262
  call<{ ok: true }>('git.discard', gitPayload(scope, worktree, { path })),
@@ -258,6 +274,10 @@ export const api = {
258
274
  /** Release an agent terminal by uuid (tab closed while WS was down). */
259
275
  agentPtyClose: (uuid: string) =>
260
276
  call<{ ok: true }>('agent-pty.close', { uuid }),
277
+ /** Skip every active terminal_wait_for on one agent terminal (the wait
278
+ * banner's skip button). Idempotent: {skipped:0} when none is active. */
279
+ agentSkipWait: (uuid: string) =>
280
+ call<{ ok: true; skipped: number }>('agent-pty.skip-wait', { uuid }),
261
281
  /** Terminal dependency status (issue #140): after a WS close 1011 with
262
282
  * reason `pty-deps-missing` the view fetches the full repair details here
263
283
  * (the close reason itself is capped at 123 bytes). */
@@ -156,6 +156,18 @@ export const ar: Record<string, string> = {
156
156
  produced: 'النواتج',
157
157
  producedOpen: 'فتح في الشريط الجانبي',
158
158
  disconnected: 'انقطع اتصال الطرفية، جارٍ إعادة الاتصال…',
159
+ terminalWaitBanner: 'الوكيل ينتظر {needle}',
160
+ terminalSkipWait: 'تخطي الانتظار',
161
+ gitFoldExpand: 'إظهار {count} سطرًا من السياق',
162
+ gitFoldLoading: 'جارٍ التوسيع…',
163
+ gitFoldFailed: 'فشل التوسيع',
164
+ rename: 'إعادة تسمية',
165
+ renameInvalid: 'لا يمكن أن يكون الاسم فارغًا أو يحتوي على فواصل مسار.',
166
+ delete: 'حذف',
167
+ deleteTitle: 'حذف "{name}"؟',
168
+ deleteDescFile: 'سيتم حذف هذا الملف نهائيًا ولا يمكن التراجع.',
169
+ deleteDescDir: 'سيتم حذف هذا الدليل ومحتواه نهائيًا ولا يمكن التراجع.',
170
+ dismiss: 'إغلاق',
159
171
  exited: 'خرجت عملية الطرفية',
160
172
  noSession: 'اختر محادثة لاستخدام الشريط الجانبي',
161
173
  pluginNotLoaded: 'الإضافة غير محمّلة؛ التبويب غير متاح:',
@@ -141,6 +141,18 @@ export const de: Record<string, string> = {
141
141
  produced: 'Erstellt',
142
142
  producedOpen: 'In der Seitenleiste öffnen',
143
143
  disconnected: 'Terminalverbindung getrennt, Verbindung wird wiederhergestellt…',
144
+ terminalWaitBanner: 'Agent wartet auf {needle}',
145
+ terminalSkipWait: 'Warten abbrechen',
146
+ gitFoldExpand: '{count} Kontextzeilen einblenden',
147
+ gitFoldLoading: 'Wird eingeblendet…',
148
+ gitFoldFailed: 'Einblenden fehlgeschlagen',
149
+ rename: 'Umbenennen',
150
+ renameInvalid: 'Der Name darf nicht leer sein und keine Pfadtrenner enthalten.',
151
+ delete: 'Löschen',
152
+ deleteTitle: '„{name}“ löschen?',
153
+ deleteDescFile: 'Diese Datei wird endgültig gelöscht. Dies kann nicht rückgängig gemacht werden.',
154
+ deleteDescDir: 'Dieses Verzeichnis und sein gesamter Inhalt werden endgültig gelöscht. Dies kann nicht rückgängig gemacht werden.',
155
+ dismiss: 'Schließen',
144
156
  exited: 'Terminalprozess beendet',
145
157
  noSession: 'Wählen Sie eine Sitzung, um die Seitenleiste zu verwenden',
146
158
  pluginNotLoaded: 'Plugin nicht geladen; Tab vorübergehend nicht verfügbar:',
@@ -148,6 +148,18 @@ export const fr: Record<string, string> = {
148
148
  produced: 'Produits de cette exécution',
149
149
  producedOpen: 'Ouvrir dans la barre latérale',
150
150
  disconnected: 'Connexion du terminal perdue, reconnexion…',
151
+ terminalWaitBanner: 'L’agent attend {needle}',
152
+ terminalSkipWait: 'Ignorer l’attente',
153
+ gitFoldExpand: 'Afficher les {count} lignes de contexte',
154
+ gitFoldLoading: 'Déploiement…',
155
+ gitFoldFailed: 'Impossible de déployer',
156
+ rename: 'Renommer',
157
+ renameInvalid: 'Le nom ne peut pas être vide ni contenir de séparateur de chemin.',
158
+ delete: 'Supprimer',
159
+ deleteTitle: 'Supprimer « {name} » ?',
160
+ deleteDescFile: 'Ce fichier sera définitivement supprimé. Action irréversible.',
161
+ deleteDescDir: 'Ce répertoire et tout son contenu seront définitivement supprimés. Action irréversible.',
162
+ dismiss: 'Fermer',
151
163
  exited: 'Le processus du terminal s’est terminé',
152
164
  noSession: 'Sélectionnez une session pour utiliser la barre latérale',
153
165
  pluginNotLoaded: 'Plugin non chargé, onglet indisponible pour le moment :',
@@ -155,6 +155,18 @@ export const hi: Record<string, string> = {
155
155
  produced: 'उत्पादित',
156
156
  producedOpen: 'साइडबार में खोलें',
157
157
  disconnected: 'टर्मिनल डिस्कनेक्ट हो गया, पुनः कनेक्ट हो रहा…',
158
+ terminalWaitBanner: 'एजेंट {needle} की प्रतीक्षा कर रहा है',
159
+ terminalSkipWait: 'प्रतीक्षा छोड़ें',
160
+ gitFoldExpand: '{count} संदर्भ पंक्तियाँ दिखाएँ',
161
+ gitFoldLoading: 'खोल रहे हैं…',
162
+ gitFoldFailed: 'खोलने में विफल',
163
+ rename: 'नाम बदलें',
164
+ renameInvalid: 'नाम खाली नहीं हो सकता या पाथ सेपरेटर नहीं हो सकता।',
165
+ delete: 'हटाएँ',
166
+ deleteTitle: '"{name}" हटाएँ?',
167
+ deleteDescFile: 'यह फ़ाइल स्थायी रूप से हट जाएगी। इसे वापस नहीं किया जा सकता।',
168
+ deleteDescDir: 'यह निर्देशिका और उसकी सामग्री स्थायी रूप से हट जाएगी। इसे वापस नहीं किया जा सकता।',
169
+ dismiss: 'बंद करें',
158
170
  exited: 'टर्मिनल प्रक्रिया बाहर निकली',
159
171
  noSession: 'साइडबार उपयोग करने के लिए एक वार्तालाप चुनें',
160
172
  pluginNotLoaded: 'प्लगइन लोड नहीं; टैब अनुपलब्ध:',
@@ -153,6 +153,18 @@ export const id: Record<string, string> = {
153
153
  produced: 'Dihasilkan',
154
154
  producedOpen: 'Buka di sidebar',
155
155
  disconnected: 'Terminal terputus, menyambung ulang…',
156
+ terminalWaitBanner: 'Agen menunggu {needle}',
157
+ terminalSkipWait: 'Lewati penungguan',
158
+ gitFoldExpand: 'Tampilkan {count} baris konteks',
159
+ gitFoldLoading: 'Membentang…',
160
+ gitFoldFailed: 'Gagal membentang',
161
+ rename: 'Ganti nama',
162
+ renameInvalid: 'Nama tidak boleh kosong atau mengandung pemisah jalur.',
163
+ delete: 'Hapus',
164
+ deleteTitle: 'Hapus "{name}"?',
165
+ deleteDescFile: 'File ini dihapus permanen dan tidak dapat dibatalkan.',
166
+ deleteDescDir: 'Direktori ini dan seluruh isinya dihapus permanen dan tidak dapat dibatalkan.',
167
+ dismiss: 'Tutup',
156
168
  exited: 'Proses terminal keluar',
157
169
  noSession: 'Pilih obrolan untuk menggunakan sidebar',
158
170
  pluginNotLoaded: 'Plugin tidak dimuat; tab tidak tersedia untuk sementara:',
@@ -146,6 +146,18 @@ export const it: Record<string, string> = {
146
146
  produced: 'Prodotti',
147
147
  producedOpen: 'Apri nella barra laterale',
148
148
  disconnected: 'Terminale disconnesso, riconnessione…',
149
+ terminalWaitBanner: 'L’agente sta attendendo {needle}',
150
+ terminalSkipWait: 'Salta attesa',
151
+ gitFoldExpand: 'Mostra le {count} righe di contesto',
152
+ gitFoldLoading: 'Espansione…',
153
+ gitFoldFailed: 'Impossibile espandere',
154
+ rename: 'Rinomina',
155
+ renameInvalid: 'Il nome non può essere vuoto né contenere separatori di percorso.',
156
+ delete: 'Elimina',
157
+ deleteTitle: 'Eliminare "{name}"?',
158
+ deleteDescFile: 'Il file verrà eliminato definitivamente. Operazione irreversibile.',
159
+ deleteDescDir: 'La directory e tutto il suo contenuto verranno eliminati definitivamente. Operazione irreversibile.',
160
+ dismiss: 'Chiudi',
149
161
  exited: 'Il processo del terminale è terminato',
150
162
  noSession: 'Selezioni una conversazione per usare la barra laterale',
151
163
  pluginNotLoaded: 'Plugin non caricato; scheda non disponibile:',
@@ -155,6 +155,18 @@ export const ja: Record<string, string> = {
155
155
  produced: '今回の産物',
156
156
  producedOpen: 'サイドバーで開く',
157
157
  disconnected: 'ターミナル接続が切れました、再接続中…',
158
+ terminalWaitBanner: 'エージェントが {needle} を待機中',
159
+ terminalSkipWait: '待機をスキップ',
160
+ gitFoldExpand: 'コンテキスト {count} 行を表示',
161
+ gitFoldLoading: '展開中…',
162
+ gitFoldFailed: '展開できませんでした',
163
+ rename: '名前を変更',
164
+ renameInvalid: '名前は空にできないか、パス区切りを含めてはいけません。',
165
+ delete: '削除',
166
+ deleteTitle: '「{name}」を削除しますか?',
167
+ deleteDescFile: 'このファイルは完全に削除されます。元に戻せません。',
168
+ deleteDescDir: 'このディレクトリとその内容は完全に削除されます。元に戻せません。',
169
+ dismiss: '閉じる',
158
170
  exited: 'ターミナルプロセスが終了しました',
159
171
  noSession: 'サイドバーを使うには会話を選択してください',
160
172
  pluginNotLoaded: 'プラグイン未読み込み、タブは一時的に利用不可:',
@@ -147,6 +147,18 @@ export const ko: Record<string, string> = {
147
147
  produced: '이번 산출물',
148
148
  producedOpen: '사이드바에서 열기',
149
149
  disconnected: '터미널 연결이 끊겨 다시 연결하는 중…',
150
+ terminalWaitBanner: '에이전트가 {needle} 대기 중',
151
+ terminalSkipWait: '대기 건너뛰기',
152
+ gitFoldExpand: '컨텍스트 {count}줄 보기',
153
+ gitFoldLoading: '펼치는 중…',
154
+ gitFoldFailed: '펼치기 실패',
155
+ rename: '이름 바꾸기',
156
+ renameInvalid: '이름은 비어 있거나 경로 구분자를 포함할 수 없습니다.',
157
+ delete: '삭제',
158
+ deleteTitle: '"{name}"을(를) 삭제하시겠습니까?',
159
+ deleteDescFile: '이 파일은 영구 삭제되며 되돌릴 수 없습니다.',
160
+ deleteDescDir: '이 디렉터리와 그 내용이 영구 삭제되며 되돌릴 수 없습니다.',
161
+ dismiss: '닫기',
150
162
  exited: '터미널 프로세스가 종료되었습니다',
151
163
  noSession: '사이드바를 사용하려면 대화를 선택하세요',
152
164
  pluginNotLoaded: '플러그인이 로드되지 않아 탭을 지금 사용할 수 없습니다:',
@@ -153,6 +153,18 @@ export const nl: Record<string, string> = {
153
153
  produced: 'Geproduceerd',
154
154
  producedOpen: 'Openen in zijbalk',
155
155
  disconnected: 'Terminalverbinding verbroken, opnieuw verbinden…',
156
+ terminalWaitBanner: 'Agent wacht op {needle}',
157
+ terminalSkipWait: 'Wachttijd overslaan',
158
+ gitFoldExpand: 'Toon {count} contextregels',
159
+ gitFoldLoading: 'Uitvouwen…',
160
+ gitFoldFailed: 'Uitvouwen mislukt',
161
+ rename: 'Naam wijzigen',
162
+ renameInvalid: 'De naam mag niet leeg zijn of padscheiders bevatten.',
163
+ delete: 'Verwijderen',
164
+ deleteTitle: '"{name}" verwijderen?',
165
+ deleteDescFile: 'Dit verwijdert het bestand definitief. Dit kan niet ongedaan worden gemaakt.',
166
+ deleteDescDir: 'Dit verwijdert de map en de volledige inhoud definitief. Dit kan niet ongedaan worden gemaakt.',
167
+ dismiss: 'Sluiten',
156
168
  exited: 'Terminalproces beëindigd',
157
169
  noSession: 'Selecteer een conversatie om de zijbalk te gebruiken',
158
170
  pluginNotLoaded: 'Plugin niet geladen; tabblad niet beschikbaar:',
@@ -157,6 +157,18 @@ export const pl: Record<string, string> = {
157
157
  produced: 'Wyprodukowane',
158
158
  producedOpen: 'Otwórz w panelu bocznym',
159
159
  disconnected: 'Terminal odłączony, ponowne łączenie…',
160
+ terminalWaitBanner: 'Agent czeka na {needle}',
161
+ terminalSkipWait: 'Pomiń oczekiwanie',
162
+ gitFoldExpand: 'Pokaż {count} linii kontekstu',
163
+ gitFoldLoading: 'Rozwijanie…',
164
+ gitFoldFailed: 'Nie udało się rozwinąć',
165
+ rename: 'Zmień nazwę',
166
+ renameInvalid: 'Nazwa nie może być pusta ani zawierać separatorów ścieżki.',
167
+ delete: 'Usuń',
168
+ deleteTitle: 'Usunąć „{name}"?',
169
+ deleteDescFile: 'Ten plik zostanie trwale usunięty. Nie można tego cofnąć.',
170
+ deleteDescDir: 'Ten katalog i cała jego zawartość zostaną trwale usunięte. Nie można tego cofnąć.',
171
+ dismiss: 'Zamknij',
160
172
  exited: 'Proces terminala zakończony',
161
173
  noSession: 'Wybierz rozmowę, aby korzystać z panelu bocznego',
162
174
  pluginNotLoaded: 'Wtyczka niezaładowana; karta chwilowo niedostępna:',
@@ -138,6 +138,18 @@ export const pt: Record<string, string> = {
138
138
  produced: 'Produzidos',
139
139
  producedOpen: 'Abrir na barra lateral',
140
140
  disconnected: 'Terminal desconectado, reconectando…',
141
+ terminalWaitBanner: 'O agente está aguardando {needle}',
142
+ terminalSkipWait: 'Pular espera',
143
+ gitFoldExpand: 'Mostrar as {count} linhas de contexto',
144
+ gitFoldLoading: 'A expandir…',
145
+ gitFoldFailed: 'Falha ao expandir',
146
+ rename: 'Renomear',
147
+ renameInvalid: 'O nome não pode estar vazio nem conter separadores de caminho.',
148
+ delete: 'Eliminar',
149
+ deleteTitle: 'Eliminar "{name}"?',
150
+ deleteDescFile: 'Isto elimina definitivamente o ficheiro. Não pode ser anulado.',
151
+ deleteDescDir: 'Isto elimina definitivamente o diretório e todo o seu conteúdo. Não pode ser anulado.',
152
+ dismiss: 'Fechar',
141
153
  exited: 'O processo do terminal saiu',
142
154
  noSession: 'Selecione uma conversa para usar a barra lateral',
143
155
  pluginNotLoaded: 'Plugin não carregado; aba indisponível:',
@@ -151,6 +151,18 @@ export const ru: Record<string, string> = {
151
151
  produced: 'Результаты',
152
152
  producedOpen: 'Открыть в боковой панели',
153
153
  disconnected: 'Терминал отключён, переподключение…',
154
+ terminalWaitBanner: 'Агент ожидает {needle}',
155
+ terminalSkipWait: 'Пропустить ожидание',
156
+ gitFoldExpand: 'Показать {count} строк контекста',
157
+ gitFoldLoading: 'Развертывание…',
158
+ gitFoldFailed: 'Не удалось развернуть',
159
+ rename: 'Переименовать',
160
+ renameInvalid: 'Имя не может быть пустым или содержать разделители пути.',
161
+ delete: 'Удалить',
162
+ deleteTitle: 'Удалить «{name}»?',
163
+ deleteDescFile: 'Файл будет удалён безвозвратно. Действие необратимо.',
164
+ deleteDescDir: 'Каталог и всё его содержимое будут удалены безвозвратно. Действие необратимо.',
165
+ dismiss: 'Закрыть',
154
166
  exited: 'Процесс терминала завершился',
155
167
  noSession: 'Выберите сессию, чтобы использовать боковую панель',
156
168
  pluginNotLoaded: 'Плагин не загружен — вкладка недоступна:',
@@ -138,6 +138,18 @@ export const sv: Record<string, string> = {
138
138
  produced: 'Producerat',
139
139
  producedOpen: 'Öppna i sidopanelen',
140
140
  disconnected: 'Terminalen frånkopplad, ansluter igen…',
141
+ terminalWaitBanner: 'Agenten väntar på {needle}',
142
+ terminalSkipWait: 'Hoppa över väntan',
143
+ gitFoldExpand: 'Visa {count} sammanhangsrader',
144
+ gitFoldLoading: 'Expanderar…',
145
+ gitFoldFailed: 'Kunde inte expandera',
146
+ rename: 'Byt namn',
147
+ renameInvalid: 'Namnet får inte vara tomt eller innehålla sökvägsavgränsare.',
148
+ delete: 'Ta bort',
149
+ deleteTitle: 'Ta bort "{name}"?',
150
+ deleteDescFile: 'Filen tas bort permanent. Detta kan inte ångras.',
151
+ deleteDescDir: 'Katalogen och allt i den tas bort permanent. Detta kan inte ångras.',
152
+ dismiss: 'Stäng',
141
153
  exited: 'Terminalprocess avslutad',
142
154
  noSession: 'Välj en konversation för att använda sidopanelen',
143
155
  pluginNotLoaded: 'Plugin inte laddad; flik otillgänglig:',
@@ -155,6 +155,18 @@ export const th: Record<string, string> = {
155
155
  produced: 'ผลลัพธ์ที่สร้าง',
156
156
  producedOpen: 'เปิดในแถบด้านข้าง',
157
157
  disconnected: 'เทอร์มินัลถูกตัดการเชื่อมต่อ กำลังเชื่อมต่อใหม่…',
158
+ terminalWaitBanner: 'เอเจนต์กำลังรอ {needle}',
159
+ terminalSkipWait: 'ข้ามการรอ',
160
+ gitFoldExpand: 'แสดงบริบท {count} บรรทัด',
161
+ gitFoldLoading: 'กำลังขยาย…',
162
+ gitFoldFailed: 'ขยายไม่สำเร็จ',
163
+ rename: 'เปลี่ยนชื่อ',
164
+ renameInvalid: 'ชื่อต้องไม่ว่างและไม่มีอักขระคั่นพาธ',
165
+ delete: 'ลบ',
166
+ deleteTitle: 'ลบ "{name}"?',
167
+ deleteDescFile: 'ไฟล์นี้จะถูกลบอย่างถาวร ย้อนกลับไม่ได้',
168
+ deleteDescDir: 'ไดเรกทอรีนี้และเนื้อหาทั้งหมดจะถูกลบอย่างถาวร ย้อนกลับไม่ได้',
169
+ dismiss: 'ปิด',
158
170
  exited: 'กระบวนการเทอร์มินัลออกแล้ว',
159
171
  noSession: 'เลือกแชทเพื่อใช้แถบด้านข้าง',
160
172
  pluginNotLoaded: 'ปลั๊กอินไม่ได้โหลด; tab ไม่พร้อมใช้งาน:',
@@ -155,6 +155,18 @@ export const tr: Record<string, string> = {
155
155
  produced: 'Üretilenler',
156
156
  producedOpen: 'Kenar çubuğunda aç',
157
157
  disconnected: 'Terminal bağlantısı kesildi, yeniden bağlanılıyor…',
158
+ terminalWaitBanner: 'Ajan {needle} için bekliyor',
159
+ terminalSkipWait: 'Beklemeyi atla',
160
+ gitFoldExpand: '{count} bağlam satırını göster',
161
+ gitFoldLoading: 'Genişletiliyor…',
162
+ gitFoldFailed: 'Genişletilemedi',
163
+ rename: 'Yeniden adlandır',
164
+ renameInvalid: 'Ad boş olamaz veya yol ayracı içeremez.',
165
+ delete: 'Sil',
166
+ deleteTitle: '"{name}" silinsin mi?',
167
+ deleteDescFile: 'Bu dosya kalıcı olarak silinir. Bu işlem geri alınamaz.',
168
+ deleteDescDir: 'Bu dizin ve içeriği kalıcı olarak silinir. Bu işlem geri alınamaz.',
169
+ dismiss: 'Kapat',
158
170
  exited: 'Terminal süreci sonlandı',
159
171
  noSession: 'Kenar çubuğunu kullanmak için bir oturum seçin',
160
172
  pluginNotLoaded: 'Eklenti yüklenmedi; sekme kullanılamıyor:',
@@ -155,6 +155,18 @@ export const vi: Record<string, string> = {
155
155
  produced: 'Đã tạo',
156
156
  producedOpen: 'Mở trong thanh bên',
157
157
  disconnected: 'Terminal mất kết nối, đang kết nối lại…',
158
+ terminalWaitBanner: 'Agent đang chờ {needle}',
159
+ terminalSkipWait: 'Bỏ qua chờ',
160
+ gitFoldExpand: 'Hiện {count} dòng ngữ cảnh',
161
+ gitFoldLoading: 'Đang mở…',
162
+ gitFoldFailed: 'Không thể mở',
163
+ rename: 'Đổi tên',
164
+ renameInvalid: 'Tên không được trống hoặc chứa dấu phân cách đường dẫn.',
165
+ delete: 'Xóa',
166
+ deleteTitle: 'Xóa "{name}"?',
167
+ deleteDescFile: 'Thao tác này sẽ xóa vĩnh viễn tệp. Không thể hoàn tác.',
168
+ deleteDescDir: 'Thao tác này sẽ xóa vĩnh viễn thư mục và mọi thứ bên trong. Không thể hoàn tác.',
169
+ dismiss: 'Đóng',
158
170
  exited: 'Tiến trình terminal đã thoát',
159
171
  noSession: 'Chọn một phiên để dùng thanh bên',
160
172
  pluginNotLoaded: 'Plugin chưa tải, tab tạm không khả dụng:',
@@ -170,6 +170,18 @@ export const zhHK: Record<string, string> = {
170
170
  produced: '本次產出',
171
171
  producedOpen: '在側邊欄中開啟',
172
172
  disconnected: '終端連線斷開,重新連線中…',
173
+ terminalWaitBanner: 'Agent 正在等待 {needle}',
174
+ terminalSkipWait: '跳過等待',
175
+ gitFoldExpand: '展開 {count} 行上下文',
176
+ gitFoldLoading: '展開中…',
177
+ gitFoldFailed: '展開失敗',
178
+ rename: '重新命名',
179
+ renameInvalid: '名稱不能為空,且不能包含路徑分隔符。',
180
+ delete: '刪除',
181
+ deleteTitle: '刪除「{name}」?',
182
+ deleteDescFile: '將永久刪除該檔案,此操作無法復原。',
183
+ deleteDescDir: '將永久刪除該目錄及其全部內容,此操作無法復原。',
184
+ dismiss: '關閉',
173
185
  exited: '終端程序已退出',
174
186
  noSession: '選擇一個工作階段以使用側邊欄',
175
187
  pluginNotLoaded: '插件未載入,標籤暫不可用:',
@@ -170,6 +170,18 @@ export const zhMO: Record<string, string> = {
170
170
  produced: '本次產出',
171
171
  producedOpen: '在側邊欄中開啟',
172
172
  disconnected: '終端連線斷開,重新連線中…',
173
+ terminalWaitBanner: 'Agent 正在等待 {needle}',
174
+ terminalSkipWait: '跳過等待',
175
+ gitFoldExpand: '展開 {count} 行上下文',
176
+ gitFoldLoading: '展開中…',
177
+ gitFoldFailed: '展開失敗',
178
+ rename: '重新命名',
179
+ renameInvalid: '名稱不能為空,且不能包含路徑分隔符。',
180
+ delete: '刪除',
181
+ deleteTitle: '刪除「{name}」?',
182
+ deleteDescFile: '將永久刪除該檔案,此操作無法復原。',
183
+ deleteDescDir: '將永久刪除該目錄及其全部內容,此操作無法復原。',
184
+ dismiss: '關閉',
173
185
  exited: '終端程序已退出',
174
186
  noSession: '選擇一個工作階段以使用側邊欄',
175
187
  pluginNotLoaded: '插件未載入,標籤暫不可用:',
@@ -170,6 +170,18 @@ export const zhTW: Record<string, string> = {
170
170
  produced: '本次產出',
171
171
  producedOpen: '在側邊欄中開啟',
172
172
  disconnected: '終端連線斷開,重新連線中…',
173
+ terminalWaitBanner: 'Agent 正在等待 {needle}',
174
+ terminalSkipWait: '跳過等待',
175
+ gitFoldExpand: '展開 {count} 行上下文',
176
+ gitFoldLoading: '展開中…',
177
+ gitFoldFailed: '展開失敗',
178
+ rename: '重新命名',
179
+ renameInvalid: '名稱不能為空,且不能包含路徑分隔符。',
180
+ delete: '刪除',
181
+ deleteTitle: '刪除「{name}」?',
182
+ deleteDescFile: '將永久刪除該檔案,此操作無法復原。',
183
+ deleteDescDir: '將永久刪除該目錄及其全部內容,此操作無法復原。',
184
+ dismiss: '關閉',
173
185
  exited: '終端程序已退出',
174
186
  noSession: '選擇一個工作階段以使用側邊欄',
175
187
  pluginNotLoaded: '插件未載入,標籤暫不可用:',
@@ -160,6 +160,18 @@ export const zh = {
160
160
  producedOpen: '在侧边栏中打开',
161
161
  showInFolder: '在文件夹中显示',
162
162
  disconnected: '终端连接断开,重连中…',
163
+ terminalWaitBanner: 'Agent 正在等待 {needle}',
164
+ terminalSkipWait: '跳过等待',
165
+ gitFoldExpand: '展开 {count} 行上下文',
166
+ gitFoldLoading: '展开中…',
167
+ gitFoldFailed: '展开失败',
168
+ rename: '重命名',
169
+ renameInvalid: '名称不能为空,且不能包含路径分隔符。',
170
+ delete: '删除',
171
+ deleteTitle: '删除「{name}」?',
172
+ deleteDescFile: '将永久删除该文件,此操作不可撤销。',
173
+ deleteDescDir: '将永久删除该目录及其全部内容,此操作不可撤销。',
174
+ dismiss: '关闭',
163
175
  exited: '终端进程已退出',
164
176
  noSession: '选择一个会话以使用侧边栏',
165
177
  pluginNotLoaded: '插件未加载,标签页暂不可用:',
@@ -497,6 +509,18 @@ export const en: Record<keyof typeof zh, string> = {
497
509
  producedOpen: 'Open in sidebar',
498
510
  showInFolder: 'Show in folder',
499
511
  disconnected: 'Terminal disconnected, reconnecting…',
512
+ terminalWaitBanner: 'Agent is waiting for {needle}',
513
+ terminalSkipWait: 'Skip wait',
514
+ gitFoldExpand: 'Expand {count} context lines',
515
+ gitFoldLoading: 'Expanding…',
516
+ gitFoldFailed: 'Failed to expand',
517
+ rename: 'Rename',
518
+ renameInvalid: 'The name cannot be empty or contain path separators.',
519
+ delete: 'Delete',
520
+ deleteTitle: 'Delete "{name}"?',
521
+ deleteDescFile: 'This permanently deletes the file. This cannot be undone.',
522
+ deleteDescDir: 'This permanently deletes the directory and everything inside it. This cannot be undone.',
523
+ dismiss: 'Dismiss',
500
524
  exited: 'Terminal process exited',
501
525
  noSession: 'Select a conversation to use the sidebar',
502
526
  pluginNotLoaded: 'Plugin not loaded; tab unavailable:',
@@ -1651,6 +1651,74 @@ body[data-dsh-sidebar-dragging] .panel {
1651
1651
  color: var(--dsw-alias-label-primary);
1652
1652
  }
1653
1653
 
1654
+ /* A hunk-gap fold in a diff: the "expand hidden context" chip between two
1655
+ hunks (loading is inert, failure degrades to a static marker). */
1656
+ .gitFoldRow {
1657
+ display: block;
1658
+ width: 100%;
1659
+ box-sizing: border-box;
1660
+ padding: 2px 12px;
1661
+ border: none;
1662
+ background: var(--dsw-alias-bg-layer-1);
1663
+ color: var(--dsw-alias-label-tertiary);
1664
+ font: var(--dsw-font-xxxs-11);
1665
+ text-align: center;
1666
+ cursor: pointer;
1667
+ outline: none;
1668
+ }
1669
+
1670
+ .gitFoldRow:hover {
1671
+ background: var(--dsw-alias-interactive-bg-hover);
1672
+ color: var(--dsw-alias-label-secondary);
1673
+ }
1674
+
1675
+ .gitFoldRow:disabled {
1676
+ cursor: default;
1677
+ }
1678
+
1679
+ .gitFoldRowFailed {
1680
+ color: var(--dsw-alias-state-error-primary);
1681
+ opacity: 0.7;
1682
+ }
1683
+
1684
+ /* The tree row's inline rename editor: fills the row's name slot, keeps the
1685
+ row's metrics so the tree does not jump when editing starts. */
1686
+ .explorerRenameInput {
1687
+ flex: 1;
1688
+ min-width: 0;
1689
+ height: 20px;
1690
+ padding: 0 4px;
1691
+ border: 1px solid var(--dsw-alias-border-l2);
1692
+ border-radius: 4px;
1693
+ background: var(--dsw-alias-bg-layer-2);
1694
+ color: var(--dsw-alias-label-primary);
1695
+ font: var(--dsw-font-xxs-12);
1696
+ outline: none;
1697
+ }
1698
+
1699
+ /* The "Agent 正在等待 {needle}" wait banner: a warn-toned strip above the
1700
+ terminal surface while the model blocks in terminal_wait_for; the needle
1701
+ ellipsizes inline and the full text rides the title tooltip. */
1702
+ .terminalWaitBanner {
1703
+ flex: none;
1704
+ display: flex;
1705
+ align-items: center;
1706
+ gap: 8px;
1707
+ padding: 3px 10px;
1708
+ font: var(--dsw-font-xxxs-11);
1709
+ color: var(--dsw-alias-state-warn-label);
1710
+ background: var(--dsw-alias-state-warn-tertiary);
1711
+ }
1712
+
1713
+ .terminalWaitNeedle {
1714
+ flex: 1;
1715
+ min-width: 0;
1716
+ overflow: hidden;
1717
+ text-overflow: ellipsis;
1718
+ white-space: nowrap;
1719
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
1720
+ }
1721
+
1654
1722
  /* The node-pty dependency failure banner (issue #140): a taller warn block
1655
1723
  carrying the pasteable repair command (bash / cmd / PowerShell). */
1656
1724
  .terminalDepsBanner {