dsh-coding-sidebar 1.0.8 → 1.0.10
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/README.md +2 -2
- package/lib/client-editor.js +257 -178
- package/lib/client-registry.js +959 -345
- package/lib/client-terminal.js +307 -172
- package/lib/client.js +952 -338
- package/lib/index.js +214 -2
- package/lib/types/changes-ops.d.ts +31 -0
- package/lib/types/client/DiffView.d.ts +33 -1
- package/lib/types/client/EditorHost.d.ts +3 -0
- package/lib/types/client/FileTree.d.ts +4 -0
- package/lib/types/client/SessionLens.d.ts +4 -0
- package/lib/types/client/TerminalWaitBanner.d.ts +6 -0
- package/lib/types/client/TreePanel.d.ts +3 -0
- package/lib/types/client/api.d.ts +36 -0
- package/lib/types/client/locales.d.ts +20 -0
- package/lib/types/client/redact.d.ts +14 -0
- package/lib/types/client/state.d.ts +15 -0
- package/lib/types/fs-operations.d.ts +42 -0
- package/lib/types/git.d.ts +15 -0
- package/package.json +1 -1
- package/src/changes-ops.ts +78 -0
- package/src/client/DiffTab.tsx +10 -1
- package/src/client/DiffView.tsx +174 -19
- package/src/client/EditorHost.tsx +8 -1
- package/src/client/FileTree.tsx +147 -4
- package/src/client/GitView.tsx +37 -0
- package/src/client/SessionLens.tsx +95 -0
- package/src/client/Sidebar.tsx +54 -3
- package/src/client/TerminalView.tsx +28 -0
- package/src/client/TerminalWaitBanner.tsx +32 -0
- package/src/client/TreePanel.tsx +6 -1
- package/src/client/api.ts +24 -0
- package/src/client/locales-ar.ts +20 -0
- package/src/client/locales-de.ts +20 -0
- package/src/client/locales-fr.ts +20 -0
- package/src/client/locales-hi.ts +20 -0
- package/src/client/locales-id.ts +20 -0
- package/src/client/locales-it.ts +20 -0
- package/src/client/locales-ja.ts +20 -0
- package/src/client/locales-ko.ts +20 -0
- package/src/client/locales-nl.ts +20 -0
- package/src/client/locales-pl.ts +20 -0
- package/src/client/locales-pt.ts +20 -0
- package/src/client/locales-ru.ts +20 -0
- package/src/client/locales-sv.ts +20 -0
- package/src/client/locales-th.ts +20 -0
- package/src/client/locales-tr.ts +20 -0
- package/src/client/locales-vi.ts +20 -0
- package/src/client/locales-zh-HK.ts +20 -0
- package/src/client/locales-zh-MO.ts +20 -0
- package/src/client/locales-zh-TW.ts +20 -0
- package/src/client/locales.ts +40 -0
- package/src/client/redact.ts +39 -0
- package/src/client/sidebar.module.css +183 -0
- package/src/client/state.ts +42 -3
- package/src/fs-operations.ts +126 -4
- package/src/git.ts +39 -2
- package/src/index.ts +56 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The session lens: file operations the model performed in this session,
|
|
3
|
+
* parsed from the session's own event log (`changes.ops`). Clicking a row
|
|
4
|
+
* expands a best-effort text preview of the file (read through `fs.read`,
|
|
5
|
+
* passed through the secret-redaction layer). Kept a leaf component — the
|
|
6
|
+
* GitView hosts it as the "session changes" lens of the unified tab.
|
|
7
|
+
*/
|
|
8
|
+
import { useCallback, useEffect, useState } from 'react'
|
|
9
|
+
import { IconRefreshOutline16 } from '@deepseek-ai/dsh-client-ui-primitives'
|
|
10
|
+
import { api, type SessionScope } from './api.ts'
|
|
11
|
+
import { redactSecrets } from './redact.ts'
|
|
12
|
+
import { t } from './locales.ts'
|
|
13
|
+
import css from './sidebar.module.css'
|
|
14
|
+
|
|
15
|
+
/** One deduplicated file operation row (the host's `changes.ops` payload). */
|
|
16
|
+
interface SessionFileOp {
|
|
17
|
+
path: string
|
|
18
|
+
tool: string
|
|
19
|
+
time: number
|
|
20
|
+
count: number
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Preview cap: a long file shows its head only (the sidebar is not an editor). */
|
|
24
|
+
const PREVIEW_CHARS = 20_000
|
|
25
|
+
|
|
26
|
+
export function SessionLens(props: { scope: SessionScope }) {
|
|
27
|
+
const { scope } = props
|
|
28
|
+
const [ops, setOps] = useState<SessionFileOp[] | null>(null)
|
|
29
|
+
const [error, setError] = useState<string | null>(null)
|
|
30
|
+
const [openPath, setOpenPath] = useState<string | null>(null)
|
|
31
|
+
const [preview, setPreview] = useState<string | null>(null)
|
|
32
|
+
const [previewLoading, setPreviewLoading] = useState(false)
|
|
33
|
+
|
|
34
|
+
const load = useCallback(async (): Promise<void> => {
|
|
35
|
+
setError(null)
|
|
36
|
+
try {
|
|
37
|
+
const result = await api.changesOps(scope)
|
|
38
|
+
setOps(result.ops)
|
|
39
|
+
} catch (reason) {
|
|
40
|
+
setError(reason instanceof Error ? reason.message : String(reason))
|
|
41
|
+
}
|
|
42
|
+
}, [scope])
|
|
43
|
+
|
|
44
|
+
useEffect(() => { void load() }, [load])
|
|
45
|
+
|
|
46
|
+
/** Toggle one row's preview: fetch + redact on first open, cached after. */
|
|
47
|
+
const togglePreview = (path: string): void => {
|
|
48
|
+
if (openPath === path) {
|
|
49
|
+
setOpenPath(null)
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
setOpenPath(path)
|
|
53
|
+
setPreview(null)
|
|
54
|
+
setPreviewLoading(true)
|
|
55
|
+
api.fsRead(scope, path).then((result) => {
|
|
56
|
+
const text = result.kind === 'text' ? redactSecrets(result.content) : t('changesBinary')
|
|
57
|
+
setPreview(text.slice(0, PREVIEW_CHARS))
|
|
58
|
+
}).catch((reason: unknown) => {
|
|
59
|
+
setPreview(t('changesPreviewError', { message: reason instanceof Error ? reason.message : String(reason) }))
|
|
60
|
+
}).finally(() => { setPreviewLoading(false) })
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className={css.sessionLens}>
|
|
65
|
+
<div className={css.sessionLensBar}>
|
|
66
|
+
<span className={css.sessionLensCount}>{ops === null ? t('loading') : t('changesCount', { count: ops.length })}</span>
|
|
67
|
+
<button type="button" className={css.iconButton} aria-label={t('refresh')} title={t('refresh')} onClick={() => { void load() }}>
|
|
68
|
+
<IconRefreshOutline16 size={14} />
|
|
69
|
+
</button>
|
|
70
|
+
</div>
|
|
71
|
+
{error !== null && <div className={css.sessionLensEmpty}>{error}</div>}
|
|
72
|
+
{error === null && ops !== null && ops.length === 0 && (
|
|
73
|
+
<div className={css.sessionLensEmpty}>{t('changesEmpty')}</div>
|
|
74
|
+
)}
|
|
75
|
+
{ops !== null && ops.map(op => (
|
|
76
|
+
<div key={op.path} className={css.sessionLensItem}>
|
|
77
|
+
<button
|
|
78
|
+
type="button"
|
|
79
|
+
className={css.sessionLensRow}
|
|
80
|
+
aria-expanded={openPath === op.path}
|
|
81
|
+
onClick={() => { togglePreview(op.path) }}
|
|
82
|
+
>
|
|
83
|
+
<span className={css.sessionLensPath} title={op.path}>{op.path}</span>
|
|
84
|
+
<span className={css.sessionLensMeta}>{op.tool}{op.count > 1 ? ` ×${op.count}` : ''}</span>
|
|
85
|
+
</button>
|
|
86
|
+
{openPath === op.path && (
|
|
87
|
+
<div className={css.sessionLensPreview}>
|
|
88
|
+
{previewLoading ? t('loading') : preview ?? ''}
|
|
89
|
+
</div>
|
|
90
|
+
)}
|
|
91
|
+
</div>
|
|
92
|
+
))}
|
|
93
|
+
</div>
|
|
94
|
+
)
|
|
95
|
+
}
|
package/src/client/Sidebar.tsx
CHANGED
|
@@ -28,11 +28,13 @@ import type { Context, SidebarSessionList } from '../context-types.ts'
|
|
|
28
28
|
import { appendToDraft, insertFileReference } from './conversation-draft.ts'
|
|
29
29
|
import {
|
|
30
30
|
PANEL_MIN, activateTab, agentUuidOf, closeFloatByTab, closeTab, dockFloat, firstLeaf, floatTab,
|
|
31
|
-
isAgentTabId, leafWithTab,
|
|
31
|
+
isAgentTabId, leafWithTab, allLeaves,
|
|
32
32
|
moveFloat, moveTab, moveTabToEdge, openDiffTab, raiseFloat, reconcileAgentTerminals,
|
|
33
33
|
resizeFloat, resizeSplitIn, setTabPin, setWidth, toggleExpanded, togglePanel,
|
|
34
34
|
type DropZone, type SidebarState, type SidebarStore, type SidebarTab,
|
|
35
35
|
} from './state.ts'
|
|
36
|
+
import { baseName } from './FileTree.tsx'
|
|
37
|
+
import { isWithinWorkspace } from './paths.ts'
|
|
36
38
|
import { collectPinnedTabs, createPinnedVirtualTab, getPinnedHomeScope, injectPinnedIntoTree, isPinnedVirtualId, isPinnedVirtualTab, parsePinnedVirtualId, type PinnedTabEntry } from './pinned.ts'
|
|
37
39
|
import { IconPinOutline16 } from './icons.tsx'
|
|
38
40
|
import { IconPanelRightOutline16 } from './icons.tsx'
|
|
@@ -126,11 +128,14 @@ interface TabContentProps extends TabContentMemoKey {
|
|
|
126
128
|
onSubagentJump: (childSessionId: string) => void
|
|
127
129
|
/** Open a diff tab from the git panel (placement handled by the store). */
|
|
128
130
|
onOpenDiff: (tab: SidebarTab) => void
|
|
131
|
+
/** Tree-row mutations (threaded to the file tree; see Sidebar's handlers). */
|
|
132
|
+
onPathRenamed?: (oldPath: string, newPath: string) => void
|
|
133
|
+
onPathRemoved?: (path: string) => void
|
|
129
134
|
}
|
|
130
135
|
|
|
131
136
|
/** Render the content of one tab (dispatched by type). */
|
|
132
137
|
const TabContent = memo(function TabContent(props: TabContentProps) {
|
|
133
|
-
const { tab, effectiveTabId, sessionId, cwd, expanded, revealed, onToggleDir, onReferenceFile, ctx, store, visible, onSubagentJump, onOpenDiff } = props
|
|
138
|
+
const { tab, effectiveTabId, sessionId, cwd, expanded, revealed, onToggleDir, onReferenceFile, ctx, store, visible, onSubagentJump, onOpenDiff, onPathRenamed, onPathRemoved } = props
|
|
134
139
|
const scope = { sessionId, cwd }
|
|
135
140
|
const descriptor = ctx.get('betterSidebar')?.getTab(tab.type)
|
|
136
141
|
if (descriptor === undefined) {
|
|
@@ -394,7 +399,7 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) {
|
|
|
394
399
|
socket.onmessage = (event) => {
|
|
395
400
|
if (typeof event.data !== 'string') return
|
|
396
401
|
try {
|
|
397
|
-
const list = JSON.parse(event.data) as Array<{ uuid: string; title: string; command: string; exited: boolean }>
|
|
402
|
+
const list = JSON.parse(event.data) as Array<{ uuid: string; title: string; command: string; exited: boolean; waiting?: { needle: string; since: number } | null }>
|
|
398
403
|
if (!Array.isArray(list)) return
|
|
399
404
|
store.reduce(s => ctx.get('betterSidebar')?.isTabEnabled('terminal') === false
|
|
400
405
|
? s
|
|
@@ -1160,6 +1165,41 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) {
|
|
|
1160
1165
|
}
|
|
1161
1166
|
}, [ctx, sessionId, cwd])
|
|
1162
1167
|
|
|
1168
|
+
/** Tree-row rename reconciliation: retarget every open tab whose path was
|
|
1169
|
+
* the renamed file (the editor content survives and later saves land on
|
|
1170
|
+
* the new path; the title follows the new base name). */
|
|
1171
|
+
const onPathRenamed = useCallback((oldPath: string, newPath: string): void => {
|
|
1172
|
+
const service = ctx.get('betterSidebar')
|
|
1173
|
+
if (service === undefined) return
|
|
1174
|
+
const snapshot = store.getSnapshot().state
|
|
1175
|
+
if (snapshot === undefined) return
|
|
1176
|
+
for (const leaf of allLeaves(snapshot.splits)) {
|
|
1177
|
+
for (const tab of leaf.tabs) {
|
|
1178
|
+
if (tab.path === oldPath) service.updateTab(tab.id, { path: newPath, title: baseName(newPath) })
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
for (const float of snapshot.floats) {
|
|
1182
|
+
if (float.tab.path === oldPath) service.updateTab(float.tab.id, { path: newPath, title: baseName(newPath) })
|
|
1183
|
+
}
|
|
1184
|
+
}, [ctx, store])
|
|
1185
|
+
|
|
1186
|
+
/** Tree-row delete reconciliation: close every open tab at or under the
|
|
1187
|
+
* removed path (a stale tab's next save would fail against a missing
|
|
1188
|
+
* path). Floating tabs are as open as docked ones. */
|
|
1189
|
+
const onPathRemoved = useCallback((target: string): void => {
|
|
1190
|
+
const service = ctx.get('betterSidebar')
|
|
1191
|
+
if (service === undefined) return
|
|
1192
|
+
const snapshot = store.getSnapshot().state
|
|
1193
|
+
if (snapshot === undefined) return
|
|
1194
|
+
const tabs: SidebarTab[] = []
|
|
1195
|
+
for (const leaf of allLeaves(snapshot.splits)) tabs.push(...leaf.tabs)
|
|
1196
|
+
for (const float of snapshot.floats) tabs.push(float.tab)
|
|
1197
|
+
for (const tab of tabs) {
|
|
1198
|
+
const path = tab.path
|
|
1199
|
+
if (path !== undefined && (path === target || isWithinWorkspace(target, path))) service.closeTab(tab.id)
|
|
1200
|
+
}
|
|
1201
|
+
}, [ctx, store])
|
|
1202
|
+
|
|
1163
1203
|
if (state === undefined || sessionId === undefined) {
|
|
1164
1204
|
// Keep the unavailable controls focusable: touch users have no hover, so
|
|
1165
1205
|
// focus is the only way the existing Tooltip can explain what is missing.
|
|
@@ -1205,6 +1245,15 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) {
|
|
|
1205
1245
|
* strip must never break because a plugin's badge computation failed.
|
|
1206
1246
|
*/
|
|
1207
1247
|
const tabBadgeOf = (tab: SidebarTab): ReactNode => {
|
|
1248
|
+
// Agent-terminal wait indicator (sidebar-internal, deliberately NOT a
|
|
1249
|
+
// TabDescriptor.badge — that API is type-keyed and shared with external
|
|
1250
|
+
// plugins, and cannot address one tab): the agent-terminals push mirrors
|
|
1251
|
+
// the model's live terminal_wait_for into state.agentWaits; an agent tab
|
|
1252
|
+
// whose uuid is waiting shows the hourglass pill.
|
|
1253
|
+
if (isAgentTabId(tab.id)) {
|
|
1254
|
+
const wait = state.agentWaits?.[agentUuidOf(tab.id)]
|
|
1255
|
+
if (wait !== undefined) return <span className={css.tabBadge}>{'⏳'}</span>
|
|
1256
|
+
}
|
|
1208
1257
|
const descriptor = ctx.get('betterSidebar')?.getTab(tab.type)
|
|
1209
1258
|
if (descriptor?.badge === undefined) return null
|
|
1210
1259
|
let value: string | number | null | undefined
|
|
@@ -1250,6 +1299,8 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) {
|
|
|
1250
1299
|
revealed={state.revealed ?? []}
|
|
1251
1300
|
onToggleDir={(path) => { store.reduce(s => toggleExpanded(s, path)) }}
|
|
1252
1301
|
onReferenceFile={referenceInChat}
|
|
1302
|
+
onPathRenamed={onPathRenamed}
|
|
1303
|
+
onPathRemoved={onPathRemoved}
|
|
1253
1304
|
ctx={ctx}
|
|
1254
1305
|
store={store}
|
|
1255
1306
|
visible={placement === 'float' ? true : state.panelOpen && active}
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
shouldActivateTerminalLink,
|
|
48
48
|
openTerminalUrl,
|
|
49
49
|
} from './terminal-links.ts'
|
|
50
|
+
import { TerminalWaitBanner } from './TerminalWaitBanner.tsx'
|
|
50
51
|
import css from './sidebar.module.css'
|
|
51
52
|
|
|
52
53
|
/** How many consecutive unreasoned failures before showing the error banner. */
|
|
@@ -122,6 +123,27 @@ export function TerminalView(props: { scope: SessionScope; tabId: string; store:
|
|
|
122
123
|
const [fatal, setFatal] = useState<string | null>(null)
|
|
123
124
|
const [depsFatal, setDepsFatal] = useState<TerminalDepsInfo | null>(null)
|
|
124
125
|
const [lastUrl, setLastUrl] = useState<string | null>(null)
|
|
126
|
+
// Agent terminals only: the model's active terminal_wait_for (mirrored
|
|
127
|
+
// from the host's agent-terminals push into the store) drives the wait
|
|
128
|
+
// banner. Read + subscribe like the font prefs above; the banner vanishes
|
|
129
|
+
// when the host's push drops the waiting field (skip / exit / abort all
|
|
130
|
+
// converge through the same push). getSnapshot() is {sessionId, state?,
|
|
131
|
+
// prefs} — the state may be briefly undefined around session switches.
|
|
132
|
+
const agentUuid = isAgentTabId(tabId) ? agentUuidOf(tabId) : null
|
|
133
|
+
const [waiting, setWaiting] = useState<{ needle: string; since: number } | undefined>(undefined)
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
if (agentUuid === null) return
|
|
136
|
+
const read = (): void => {
|
|
137
|
+
const next = store.getSnapshot().state?.agentWaits?.[agentUuid]
|
|
138
|
+
setWaiting(prev => {
|
|
139
|
+
const nextValue = next === undefined ? undefined : { needle: next.needle, since: next.since }
|
|
140
|
+
if (prev?.needle === nextValue?.needle && prev?.since === nextValue?.since) return prev
|
|
141
|
+
return nextValue
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
read()
|
|
145
|
+
return store.subscribe(read)
|
|
146
|
+
}, [agentUuid, store])
|
|
125
147
|
const connectRef = useRef<(() => void) | null>(null)
|
|
126
148
|
|
|
127
149
|
useEffect(() => {
|
|
@@ -374,6 +396,12 @@ export function TerminalView(props: { scope: SessionScope; tabId: string; store:
|
|
|
374
396
|
|
|
375
397
|
return (
|
|
376
398
|
<div className={css.terminalWrap}>
|
|
399
|
+
{agentUuid !== null && waiting !== undefined && (
|
|
400
|
+
<TerminalWaitBanner
|
|
401
|
+
needle={waiting.needle}
|
|
402
|
+
onSkip={() => { void api.agentSkipWait(agentUuid).catch(() => { /* 跳过失败时 banner 留存,可重试 */ }) }}
|
|
403
|
+
/>
|
|
404
|
+
)}
|
|
377
405
|
{depsFatal !== null && (
|
|
378
406
|
<TerminalDepsBanner deps={depsFatal} onRetry={() => { setDepsFatal(null); connectRef.current?.() }} />
|
|
379
407
|
)}
|
|
@@ -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
|
+
}
|
package/src/client/TreePanel.tsx
CHANGED
|
@@ -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,14 @@ 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 }),
|
|
281
|
+
/** The session lens: file operations the model performed in one session
|
|
282
|
+
* (parsed from the session's own event log; newest first). */
|
|
283
|
+
changesOps: (scope: SessionScope, signal?: AbortSignal) =>
|
|
284
|
+
call<{ ops: Array<{ path: string; tool: string; time: number; count: number }> }>('changes.ops', scopePayload(scope, {}), signal),
|
|
261
285
|
/** Terminal dependency status (issue #140): after a WS close 1011 with
|
|
262
286
|
* reason `pty-deps-missing` the view fetches the full repair details here
|
|
263
287
|
* (the close reason itself is capped at 123 bytes). */
|
package/src/client/locales-ar.ts
CHANGED
|
@@ -156,6 +156,26 @@ 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: 'إغلاق',
|
|
171
|
+
changesSessionGit: 'تغييرات Git',
|
|
172
|
+
changesSessionLens: 'تغييرات الجلسة',
|
|
173
|
+
changesEmpty: 'لا عمليات ملفات في هذه الجلسة',
|
|
174
|
+
changesCount: '{count} عملية ملف',
|
|
175
|
+
changesRedacted: '[مُنقَّح]',
|
|
176
|
+
changesBinary: 'ملف ثنائي — لا معاينة',
|
|
177
|
+
changesPreviewError: 'فشل قراءة المعاينة: {message}',
|
|
178
|
+
changesLens: 'عرض',
|
|
159
179
|
exited: 'خرجت عملية الطرفية',
|
|
160
180
|
noSession: 'اختر محادثة لاستخدام الشريط الجانبي',
|
|
161
181
|
pluginNotLoaded: 'الإضافة غير محمّلة؛ التبويب غير متاح:',
|
package/src/client/locales-de.ts
CHANGED
|
@@ -141,6 +141,26 @@ 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',
|
|
156
|
+
changesSessionGit: 'Git-Änderungen',
|
|
157
|
+
changesSessionLens: 'Sitzungsänderungen',
|
|
158
|
+
changesEmpty: 'Keine Dateioperationen in dieser Sitzung',
|
|
159
|
+
changesCount: '{count} Dateioperationen',
|
|
160
|
+
changesRedacted: '[GESCHWÄRZT]',
|
|
161
|
+
changesBinary: 'Binärdatei – keine Vorschau',
|
|
162
|
+
changesPreviewError: 'Vorschau konnte nicht gelesen werden: {message}',
|
|
163
|
+
changesLens: 'Ansicht',
|
|
144
164
|
exited: 'Terminalprozess beendet',
|
|
145
165
|
noSession: 'Wählen Sie eine Sitzung, um die Seitenleiste zu verwenden',
|
|
146
166
|
pluginNotLoaded: 'Plugin nicht geladen; Tab vorübergehend nicht verfügbar:',
|
package/src/client/locales-fr.ts
CHANGED
|
@@ -148,6 +148,26 @@ 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',
|
|
163
|
+
changesSessionGit: 'Modifications Git',
|
|
164
|
+
changesSessionLens: 'Modifications de session',
|
|
165
|
+
changesEmpty: 'Aucune opération de fichier dans cette session',
|
|
166
|
+
changesCount: '{count} opérations de fichier',
|
|
167
|
+
changesRedacted: '[MASQUÉ]',
|
|
168
|
+
changesBinary: 'Fichier binaire — pas d’aperçu',
|
|
169
|
+
changesPreviewError: 'Échec de lecture de l’aperçu : {message}',
|
|
170
|
+
changesLens: 'Vue',
|
|
151
171
|
exited: 'Le processus du terminal s’est terminé',
|
|
152
172
|
noSession: 'Sélectionnez une session pour utiliser la barre latérale',
|
|
153
173
|
pluginNotLoaded: 'Plugin non chargé, onglet indisponible pour le moment :',
|
package/src/client/locales-hi.ts
CHANGED
|
@@ -155,6 +155,26 @@ 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: 'बंद करें',
|
|
170
|
+
changesSessionGit: 'Git बदलाव',
|
|
171
|
+
changesSessionLens: 'सेशन बदलाव',
|
|
172
|
+
changesEmpty: 'इस सेशन में कोई फ़ाइल ऑपरेशन नहीं',
|
|
173
|
+
changesCount: '{count} फ़ाइल ऑपरेशन',
|
|
174
|
+
changesRedacted: '[मास्क किया गया]',
|
|
175
|
+
changesBinary: 'बाइनरी फ़ाइल — कोई पूर्वावलोकन नहीं',
|
|
176
|
+
changesPreviewError: 'पूर्वावलोकन पढ़ने में विफल: {message}',
|
|
177
|
+
changesLens: 'दृश्य',
|
|
158
178
|
exited: 'टर्मिनल प्रक्रिया बाहर निकली',
|
|
159
179
|
noSession: 'साइडबार उपयोग करने के लिए एक वार्तालाप चुनें',
|
|
160
180
|
pluginNotLoaded: 'प्लगइन लोड नहीं; टैब अनुपलब्ध:',
|
package/src/client/locales-id.ts
CHANGED
|
@@ -153,6 +153,26 @@ 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',
|
|
168
|
+
changesSessionGit: 'Perubahan Git',
|
|
169
|
+
changesSessionLens: 'Perubahan sesi',
|
|
170
|
+
changesEmpty: 'Tidak ada operasi file di sesi ini',
|
|
171
|
+
changesCount: '{count} operasi file',
|
|
172
|
+
changesRedacted: '[DISENSOR]',
|
|
173
|
+
changesBinary: 'File biner — tanpa pratinjau',
|
|
174
|
+
changesPreviewError: 'Gagal membaca pratinjau: {message}',
|
|
175
|
+
changesLens: 'Tampilan',
|
|
156
176
|
exited: 'Proses terminal keluar',
|
|
157
177
|
noSession: 'Pilih obrolan untuk menggunakan sidebar',
|
|
158
178
|
pluginNotLoaded: 'Plugin tidak dimuat; tab tidak tersedia untuk sementara:',
|
package/src/client/locales-it.ts
CHANGED
|
@@ -146,6 +146,26 @@ 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',
|
|
161
|
+
changesSessionGit: 'Modifiche Git',
|
|
162
|
+
changesSessionLens: 'Modifiche di sessione',
|
|
163
|
+
changesEmpty: 'Nessuna operazione su file in questa sessione',
|
|
164
|
+
changesCount: '{count} operazioni su file',
|
|
165
|
+
changesRedacted: '[OSCURATO]',
|
|
166
|
+
changesBinary: 'File binario — nessuna anteprima',
|
|
167
|
+
changesPreviewError: 'Lettura anteprima non riuscita: {message}',
|
|
168
|
+
changesLens: 'Vista',
|
|
149
169
|
exited: 'Il processo del terminale è terminato',
|
|
150
170
|
noSession: 'Selezioni una conversazione per usare la barra laterale',
|
|
151
171
|
pluginNotLoaded: 'Plugin non caricato; scheda non disponibile:',
|
package/src/client/locales-ja.ts
CHANGED
|
@@ -155,6 +155,26 @@ 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: '閉じる',
|
|
170
|
+
changesSessionGit: 'Git 変更',
|
|
171
|
+
changesSessionLens: 'セッション変更',
|
|
172
|
+
changesEmpty: 'このセッションにはファイル操作がありません',
|
|
173
|
+
changesCount: '{count} 件のファイル操作',
|
|
174
|
+
changesRedacted: '[マスク済み]',
|
|
175
|
+
changesBinary: 'バイナリファイルのためプレビューできません',
|
|
176
|
+
changesPreviewError: 'プレビューの読み取りに失敗: {message}',
|
|
177
|
+
changesLens: 'ビュー',
|
|
158
178
|
exited: 'ターミナルプロセスが終了しました',
|
|
159
179
|
noSession: 'サイドバーを使うには会話を選択してください',
|
|
160
180
|
pluginNotLoaded: 'プラグイン未読み込み、タブは一時的に利用不可:',
|
package/src/client/locales-ko.ts
CHANGED
|
@@ -147,6 +147,26 @@ 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: '닫기',
|
|
162
|
+
changesSessionGit: 'Git 변경',
|
|
163
|
+
changesSessionLens: '세션 변경',
|
|
164
|
+
changesEmpty: '이 세션에는 파일 작업이 없습니다',
|
|
165
|
+
changesCount: '파일 작업 {count}건',
|
|
166
|
+
changesRedacted: '[마스킹됨]',
|
|
167
|
+
changesBinary: '바이너리 파일 — 미리보기 없음',
|
|
168
|
+
changesPreviewError: '미리보기 읽기 실패: {message}',
|
|
169
|
+
changesLens: '보기',
|
|
150
170
|
exited: '터미널 프로세스가 종료되었습니다',
|
|
151
171
|
noSession: '사이드바를 사용하려면 대화를 선택하세요',
|
|
152
172
|
pluginNotLoaded: '플러그인이 로드되지 않아 탭을 지금 사용할 수 없습니다:',
|
package/src/client/locales-nl.ts
CHANGED
|
@@ -153,6 +153,26 @@ 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',
|
|
168
|
+
changesSessionGit: 'Git-wijzigingen',
|
|
169
|
+
changesSessionLens: 'Sessiewijzigingen',
|
|
170
|
+
changesEmpty: 'Geen bestandsbewerkingen in deze sessie',
|
|
171
|
+
changesCount: '{count} bestandsbewerkingen',
|
|
172
|
+
changesRedacted: '[GEREDICEERD]',
|
|
173
|
+
changesBinary: 'Binair bestand — geen voorbeeldweergave',
|
|
174
|
+
changesPreviewError: 'Voorbeeldweergave lezen mislukt: {message}',
|
|
175
|
+
changesLens: 'Weergave',
|
|
156
176
|
exited: 'Terminalproces beëindigd',
|
|
157
177
|
noSession: 'Selecteer een conversatie om de zijbalk te gebruiken',
|
|
158
178
|
pluginNotLoaded: 'Plugin niet geladen; tabblad niet beschikbaar:',
|
package/src/client/locales-pl.ts
CHANGED
|
@@ -157,6 +157,26 @@ 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',
|
|
172
|
+
changesSessionGit: 'Zmiany Git',
|
|
173
|
+
changesSessionLens: 'Zmiany sesji',
|
|
174
|
+
changesEmpty: 'Brak operacji na plikach w tej sesji',
|
|
175
|
+
changesCount: 'Operacji na plikach: {count}',
|
|
176
|
+
changesRedacted: '[ZREDAKOWANO]',
|
|
177
|
+
changesBinary: 'Plik binarny — brak podglądu',
|
|
178
|
+
changesPreviewError: 'Nie udało się odczytać podglądu: {message}',
|
|
179
|
+
changesLens: 'Widok',
|
|
160
180
|
exited: 'Proces terminala zakończony',
|
|
161
181
|
noSession: 'Wybierz rozmowę, aby korzystać z panelu bocznego',
|
|
162
182
|
pluginNotLoaded: 'Wtyczka niezaładowana; karta chwilowo niedostępna:',
|