feat: workspace fence toggle (workspaceFence pref + one-click off in error surfaces)
- New persisted built-in pref workspaceFence (default true) under the files card's secondary settings modal; host reads it per request via the settings seam (fenceEnabledOf — absent/malformed stays ON). - ensureWorkspacePath/ensureWorkspaceWritePath gain a fence param: disarmed skips the containment assert but keeps realpath resolution; wired through fs.tree/fs.read/fs.write, the media + html routes, and the upload path (writeWorkspaceUpload fence input). - Editor load failures and file-tree level errors show the localized reason plus a one-click global off (FenceErrorNotice) that flips the pref, adopts it into the store, and auto-retries the failed operation (reloadSeq / retryDir) — the raw wire text is never shown. - GitView's two client-side pre-checks (hidden open action + no-op defense) respect the pref; store threaded through TreePanel/FileTree. - i18n: 4 new keys across all 21 dictionaries; tests: fence-off route coverage, prefs parsing, schema default, editor toggles list; docs: guide §8/§8.1 + plans/2026-08-29 design record.
This commit is contained in:
@@ -27,8 +27,9 @@ import { createElement } from 'react'
|
||||
import clsx from 'clsx'
|
||||
import { IconCheckOutline16, IconFolderOpen16, IconRefreshOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import type { Context } from '../context-types.ts'
|
||||
import { api, mediaUrl, type SessionScope } from './api.ts'
|
||||
import { api, isOutsideWorkspaceMessage, mediaUrl, type SessionScope } from './api.ts'
|
||||
import { BinaryDownload } from './binary-download.tsx'
|
||||
import { FenceErrorNotice } from './FenceErrorNotice.tsx'
|
||||
import { planFirstMatch, planFsReadOutcome, type EditorLoadAction } from './editor-load.ts'
|
||||
import { baseName } from './FileTree.tsx'
|
||||
import { createFrameBatcher } from './frame-batcher.ts'
|
||||
@@ -369,6 +370,7 @@ export function EditorHost(props: {
|
||||
<div className={css.editor}>
|
||||
<TreePanel
|
||||
full
|
||||
store={store}
|
||||
sessionId={scope.sessionId}
|
||||
cwd={folderRoot ?? scope.cwd}
|
||||
expanded={expanded}
|
||||
@@ -460,7 +462,9 @@ export function EditorHost(props: {
|
||||
<div className={css.editorMain}>
|
||||
{showEmpty && <div className={css.editorPlaceholder}>{t('editorEmptyHint')}</div>}
|
||||
{!showEmpty && load.status === 'loading' && <div className={css.editorPlaceholder}>{t('loading')}</div>}
|
||||
{!showEmpty && load.status === 'error' && <div className={css.editorError}>{load.message}</div>}
|
||||
{!showEmpty && load.status === 'error' && (isOutsideWorkspaceMessage(load.message)
|
||||
? <FenceErrorNotice store={store} onDisabled={() => { setReloadSeq(sequence => sequence + 1) }} />
|
||||
: <div className={css.editorError}>{load.message}</div>)}
|
||||
{!showEmpty && load.status === 'binary' && <BinaryDownload scope={scope} path={path} />}
|
||||
{!showEmpty && load.status === 'ready' && createElement(load.viewer.component, {
|
||||
ctx, store, scope, path, title,
|
||||
@@ -488,6 +492,7 @@ export function EditorHost(props: {
|
||||
onPointerCancel={onResizeEnd}
|
||||
/>
|
||||
<TreePanel
|
||||
store={store}
|
||||
sessionId={scope.sessionId}
|
||||
cwd={scope.cwd}
|
||||
expanded={expanded}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* The workspace-fence refusal surface. The raw wire text (`path "..." is
|
||||
* outside workspace`) is never shown as-is: the editor / file-tree error
|
||||
* slots render the localized reason plus a one-click global off — the click
|
||||
* flips the `workspaceFence` pref through the settings route, adopts the
|
||||
* returned document into the store (so every prefs reader — GitView's open
|
||||
* guard, the settings page — flips with it), and calls `onDisabled` so the
|
||||
* caller retries the failed operation immediately.
|
||||
*/
|
||||
import { useState } from 'react'
|
||||
import { Button } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import { api } from './api.ts'
|
||||
import { t } from './locales.ts'
|
||||
import { parsePrefs } from './prefs.ts'
|
||||
import css from './sidebar.module.css'
|
||||
import type { SidebarStore } from './state.ts'
|
||||
|
||||
export function FenceErrorNotice(props: { store: SidebarStore; onDisabled: () => void }) {
|
||||
const { store, onDisabled } = props
|
||||
const [busy, setBusy] = useState(false)
|
||||
const disable = (): void => {
|
||||
if (busy) return
|
||||
setBusy(true)
|
||||
api.settingsUpdate({ workspaceFence: false }).then((view) => {
|
||||
store.setPrefs(parsePrefs(view.value))
|
||||
onDisabled()
|
||||
}).catch((error: unknown) => {
|
||||
// The fence stays armed on failure (the notice remains, button
|
||||
// re-enabled); the console carries the cause.
|
||||
console.error('workspace fence disable failed', error)
|
||||
setBusy(false)
|
||||
})
|
||||
}
|
||||
return (
|
||||
<div className={css.fenceError}>
|
||||
<span>{t('fenceErrorReason')}</span>
|
||||
<Button variant="outline" disabled={busy} onClick={disable}>{t('fenceDisableAction')}</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+23
-2
@@ -29,11 +29,13 @@ import {
|
||||
} from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import { SiCursor, SiZedindustries } from 'react-icons/si'
|
||||
import { VscFile, VscFolder, VscFolderOpened, VscLinkExternal, VscPin, VscPinned } from 'react-icons/vsc'
|
||||
import { api, downloadUrl, type FsEntry } from './api.ts'
|
||||
import { api, downloadUrl, isOutsideWorkspaceMessage, type FsEntry } from './api.ts'
|
||||
import { FenceErrorNotice } from './FenceErrorNotice.tsx'
|
||||
import { IconUploadOutline16, IconVscode16 } from './icons.tsx'
|
||||
import type { OpenWithTarget } from './open-with.ts'
|
||||
import { relativeTo } from './paths.ts'
|
||||
import { t } from './locales.ts'
|
||||
import type { SidebarStore } from './state.ts'
|
||||
import { uploadItemsFromDrop, uploadItemsFromFiles, type UploadItem } from './upload.ts'
|
||||
import css from './sidebar.module.css'
|
||||
|
||||
@@ -105,6 +107,8 @@ const ChatDropIllustration = () => (
|
||||
export function FileTree(props: {
|
||||
sessionId: string
|
||||
cwd: string | undefined
|
||||
/** The sidebar store: the fence-refusal notice writes the `workspaceFence` pref through it. */
|
||||
store: SidebarStore
|
||||
expanded: string[]
|
||||
/** Files highlighted by a "Show in folder" reveal (absolute paths). */
|
||||
revealed: string[]
|
||||
@@ -136,7 +140,7 @@ export function FileTree(props: {
|
||||
/** True while an upload is in flight (drops are ignored). */
|
||||
busy: boolean
|
||||
}) {
|
||||
const { sessionId, cwd, expanded, revealed, onToggle, onOpenFile, onOpenFileNewTab, onOpenFileSide, openWithTargets, openWithPinned, openWithSsh, onOpenWith, onToggleOpenWithPin, onReferenceFile, refreshTick, onUploadRequest, busy } = props
|
||||
const { sessionId, cwd, store, expanded, revealed, onToggle, onOpenFile, onOpenFileNewTab, onOpenFileSide, openWithTargets, openWithPinned, openWithSsh, onOpenWith, onToggleOpenWithPin, onReferenceFile, refreshTick, onUploadRequest, busy } = props
|
||||
const [data, setData] = useState<Record<string, LevelData>>({})
|
||||
const dataRef = useRef(data)
|
||||
/** The row whose path was just copied ("copied" label replaces its button). */
|
||||
@@ -257,6 +261,13 @@ export function FileTree(props: {
|
||||
})
|
||||
}, [sessionId, cwd, storeLevel])
|
||||
|
||||
/** Drop one level from the cache and reload it (the fence notice's retry). */
|
||||
const retryDir = useCallback((dir: string) => {
|
||||
delete dataRef.current[dir]
|
||||
setData({ ...dataRef.current })
|
||||
loadDir(dir)
|
||||
}, [loadDir])
|
||||
|
||||
// The caller's refresh tick wipes the cache (declared BEFORE the load
|
||||
// effect so the reload below sees the empty cache).
|
||||
const lastTick = useRef(refreshTick)
|
||||
@@ -436,6 +447,16 @@ export function FileTree(props: {
|
||||
return <div className={css.explorerRow} style={{ paddingLeft: depth * 22 + 6 }}>{t('loading')}</div>
|
||||
}
|
||||
if (level.error !== undefined) {
|
||||
// The fence refusal becomes the friendly notice (reason + one-click
|
||||
// global off + immediate retry of this directory), never the raw
|
||||
// `path "..." is outside workspace` wire text.
|
||||
if (isOutsideWorkspaceMessage(level.error)) {
|
||||
return (
|
||||
<div style={{ paddingLeft: depth * 22 + 6 }}>
|
||||
<FenceErrorNotice store={store} onDisabled={() => { retryDir(dir) }} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className={clsx(css.explorerRow, css.explorerError)} style={{ paddingLeft: depth * 22 + 6 }}>
|
||||
{level.error}
|
||||
|
||||
+13
-8
@@ -19,7 +19,7 @@ import { api } from './api.ts'
|
||||
import { isWithinWorkspace, relativeTo } from './paths.ts'
|
||||
import { resolveSidebarPath } from './produced-files.ts'
|
||||
import { relativeTime, t } from './locales.ts'
|
||||
import type { SidebarTab } from './state.ts'
|
||||
import type { SidebarStore, SidebarTab } from './state.ts'
|
||||
import css from './sidebar.module.css'
|
||||
|
||||
/** The XY status letters a row badge shows (X = index, Y = worktree). */
|
||||
@@ -83,13 +83,15 @@ const LOG_BATCH = 20
|
||||
|
||||
export function GitView(props: {
|
||||
scope: SessionScope
|
||||
/** The sidebar store: reads the `workspaceFence` pref (see the open guard below). */
|
||||
store: SidebarStore
|
||||
onOpenFile: (path: string) => void
|
||||
/** Open a diff tab (the shell places it below the git pane on first use). */
|
||||
onOpenDiff: (tab: SidebarTab) => void
|
||||
/** Poll only while the tab is actually visible. */
|
||||
visible: boolean
|
||||
}) {
|
||||
const { scope, onOpenFile, onOpenDiff, visible } = props
|
||||
const { scope, store, onOpenFile, onOpenDiff, visible } = props
|
||||
const [status, setStatus] = useState<GitStatusResult | null>(null)
|
||||
const [worktrees, setWorktrees] = useState<GitWorktree[]>([])
|
||||
const [selectedWorktree, setSelectedWorktree] = useState<string | undefined>()
|
||||
@@ -572,10 +574,12 @@ export function GitView(props: {
|
||||
onClose={() => { setFileMenu(null) }}
|
||||
items={[
|
||||
// A linked worktree outside the session workspace cannot be
|
||||
// opened in the editor: the host's workspace fence rejects
|
||||
// every path under it. Hide the action for that checkout so
|
||||
// the menu does not offer a no-op that confuses the user.
|
||||
...(fileMenu !== null && isWithinWorkspace(scope.cwd ?? '', resolveSidebarPath(repoRoot ?? selectedWorktree ?? scope.cwd, fileMenu.entry.path))
|
||||
// opened in the editor while the host's workspace fence is
|
||||
// armed: it rejects every path under that checkout. Hide the
|
||||
// action for that checkout so the menu does not offer a no-op
|
||||
// that confuses the user; with the fence disarmed (the
|
||||
// `workspaceFence` pref) the open is allowed through.
|
||||
...(fileMenu !== null && (store.getPrefs().workspaceFence === false || isWithinWorkspace(scope.cwd ?? '', resolveSidebarPath(repoRoot ?? selectedWorktree ?? scope.cwd, fileMenu.entry.path)))
|
||||
? [{ id: 'open', label: t('openEditor'), icon: <IconCodeOutline16 size={14} /> }]
|
||||
: []),
|
||||
fileMenu?.staged === true
|
||||
@@ -597,8 +601,9 @@ export function GitView(props: {
|
||||
// Defense-in-depth: the menu hides this action when the
|
||||
// resolved path escapes the session workspace, but a
|
||||
// racing repo switch could still reach here with a path
|
||||
// the host would reject. No-op in that case.
|
||||
if (!isWithinWorkspace(scope.cwd ?? '', resolved)) return
|
||||
// the host would reject. No-op in that case — unless the
|
||||
// workspace fence is disarmed by pref.
|
||||
if (store.getPrefs().workspaceFence !== false && !isWithinWorkspace(scope.cwd ?? '', resolved)) return
|
||||
onOpenFile(resolved)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { useEffect, useRef, useState, type InputHTMLAttributes } from 'react'
|
||||
import clsx from 'clsx'
|
||||
import { IconFolderOpen16, IconRefreshOutline16 } from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import { api } from './api.ts'
|
||||
import type { SidebarStore } from './state.ts'
|
||||
import { FileTree } from './FileTree.tsx'
|
||||
import { IconUploadOutline16 } from './icons.tsx'
|
||||
import type { OpenWithTarget } from './open-with.ts'
|
||||
@@ -44,6 +45,8 @@ interface UploadSession {
|
||||
export function TreePanel(props: {
|
||||
sessionId: string
|
||||
cwd: string | undefined
|
||||
/** The sidebar store (passed through to the tree's fence-refusal notice). */
|
||||
store: SidebarStore
|
||||
expanded: string[]
|
||||
revealed: string[]
|
||||
onToggle: (path: string) => void
|
||||
@@ -64,7 +67,7 @@ export function TreePanel(props: {
|
||||
* at a fixed width. */
|
||||
full?: boolean
|
||||
}) {
|
||||
const { sessionId, cwd, expanded, revealed, onToggle, onOpenFile, onOpenFileNewTab, onOpenFileSide, openWithTargets, openWithPinned, openWithSsh, onOpenWith, onToggleOpenWithPin, onReferenceFile, full } = props
|
||||
const { sessionId, cwd, store, expanded, revealed, onToggle, onOpenFile, onOpenFileNewTab, onOpenFileSide, openWithTargets, openWithPinned, openWithSsh, onOpenWith, onToggleOpenWithPin, onReferenceFile, full } = props
|
||||
const [query, setQuery] = useState('')
|
||||
const [results, setResults] = useState<{ matches: string[]; truncated: boolean } | null>(null)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
@@ -221,6 +224,7 @@ export function TreePanel(props: {
|
||||
<FileTree
|
||||
sessionId={sessionId}
|
||||
cwd={cwd}
|
||||
store={store}
|
||||
expanded={expanded}
|
||||
revealed={revealed}
|
||||
onToggle={onToggle}
|
||||
|
||||
@@ -21,6 +21,22 @@ export class SidebarApiError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a wire failure is the workspace fence refusing a path outside the
|
||||
* session workspace (the host message reads `path "..." is outside
|
||||
* workspace`). The request-trust fence answers code `forbidden` with the
|
||||
* bare message 'forbidden', so the message fragment — not the code alone —
|
||||
* identifies this case.
|
||||
*/
|
||||
export function isOutsideWorkspaceError(error: unknown): boolean {
|
||||
return error instanceof SidebarApiError && isOutsideWorkspaceMessage(error.message)
|
||||
}
|
||||
|
||||
/** Message-level variant for surfaces that stored the raw text (file-tree level errors). */
|
||||
export function isOutsideWorkspaceMessage(message: string): boolean {
|
||||
return message.includes('outside workspace')
|
||||
}
|
||||
|
||||
/** Explorer row (host fs-tree shape). */
|
||||
export interface FsEntry {
|
||||
name: string
|
||||
|
||||
@@ -91,9 +91,11 @@ export function builtinTabs(ctx: Context, options: BuiltinTabOptions = {}): read
|
||||
dedupeKey: (tab) => tab.path,
|
||||
// Declarative settings: the file-open behavior picker (in-place switch
|
||||
// vs per-path windows) renders as an iconed select row under the
|
||||
// editor card's gear in the Side card settings page; the "open with"
|
||||
// configuration (SSH host + custom editors) is the custom panel BELOW
|
||||
// those rows — the settings seam renders rows first, custom panel after.
|
||||
// editor card's gear in the Side card settings page, followed by the
|
||||
// workspace fence switch (the host's containment guard over every
|
||||
// sidebar filesystem route); the "open with" configuration (SSH host +
|
||||
// custom editors) is the custom panel BELOW those rows — the settings
|
||||
// seam renders rows first, custom panel after.
|
||||
settings: {
|
||||
toggles: [{
|
||||
key: 'editorExplorer',
|
||||
@@ -114,6 +116,10 @@ export function builtinTabs(ctx: Context, options: BuiltinTabOptions = {}): read
|
||||
desc: () => t('editorExplorerSplitDesc'),
|
||||
},
|
||||
],
|
||||
}, {
|
||||
key: 'workspaceFence',
|
||||
title: () => t('settingsFenceTitle'),
|
||||
desc: () => t('settingsFenceDesc'),
|
||||
}],
|
||||
render: ({ pluginSettings, updatePluginSetting }) => (
|
||||
<OpenWithSettings pluginSettings={pluginSettings} updatePluginSetting={updatePluginSetting} />
|
||||
@@ -141,6 +147,7 @@ export function builtinTabs(ctx: Context, options: BuiltinTabOptions = {}): read
|
||||
component: ({ ctx, store, scope, visible, onOpenDiff }) => (
|
||||
<GitView
|
||||
scope={scope}
|
||||
store={store}
|
||||
visible={visible}
|
||||
onOpenFile={(path) => { openSidebarFile(ctx, store, scope.sessionId, path) }}
|
||||
onOpenDiff={onOpenDiff ?? (() => { /* no-op */ })}
|
||||
|
||||
@@ -228,6 +228,10 @@ export const ar: Record<string, string> = {
|
||||
settingsJobsDesc: 'توسيع البطاقة الجانبية وفتح صفحة المهام الخلفية عند ظهور مهمة خلفية جديدة للمحادثة الحالية (كل مهمة جديدة تُطلق ذلك)؛ أوقفها للفتح يدوياً',
|
||||
settingsToolsTitle: 'حقن أدوات الطرفية للنموذج',
|
||||
settingsToolsDesc: 'عند التفعيل، يمكن للنموذج إنشاء وتشغيل طرفيات الشريط الجانبي عبر أدوات terminal_* الثمانية (معطّل افتراضياً)',
|
||||
settingsFenceTitle: 'فحص مسارات مساحة العمل',
|
||||
settingsFenceDesc: 'عند التفعيل، تصل وظائف الملفات في الشريط الجانبي إلى مسارات داخل مساحة عمل الجلسة فقط (الافتراضي)؛ عند الإيقاف تصبح ملفات المضيف كلها متاحة — وتحصل سكربتات الصفحة على النفاذ نفسه طوال ذلك',
|
||||
fenceErrorReason: 'هذا المسار خارج مساحة عمل الجلسة وقد حجبه الفحص',
|
||||
fenceDisableAction: 'إيقاف فحص مساحة العمل',
|
||||
settingsBottomTerminalTitle: 'فتح طرفية تلقائياً عند أول توسيع للوحة السفلية',
|
||||
settingsBottomTerminalDesc: 'عند توسيع اللوحة السفلية لأول مرة في الجلسة، حاول فتح تبويب طرفية جديد هناك (حصة الطرفيات ما زالت تسري؛ مفعّل افتراضياً)',
|
||||
settingsFontFamilyTitle: 'عائلة خط الطرفية',
|
||||
|
||||
@@ -213,6 +213,10 @@ export const de: Record<string, string> = {
|
||||
settingsJobsDesc: 'Die Seitenkarte wird ausgeklappt und die Aufgaben-Seite geöffnet, sobald für die aktuelle Unterhaltung eine neue Hintergrundaufgabe erscheint (jede neue Aufgabe löst dies aus); ausschalten, um sie manuell zu öffnen',
|
||||
settingsToolsTitle: 'Terminal-Werkzeuge für das Modell bereitstellen',
|
||||
settingsToolsDesc: 'Wenn aktiviert, kann das Modell über die 8 terminal_*-Werkzeuge Terminale in der Seitenleiste erstellen und steuern (standardmäßig deaktiviert)',
|
||||
settingsFenceTitle: 'Workspace-Pfadkontrolle',
|
||||
settingsFenceDesc: 'Wenn aktiv, erreichen die Dateifunktionen der Seitenleiste nur Pfade innerhalb des Session-Workspaces (Standard); ausgeschaltet sind Dateien überall auf dem Host erreichbar — Skripte der Seite erhalten solange dieselbe Reichweite',
|
||||
fenceErrorReason: 'Dieser Pfad liegt außerhalb des Session-Workspaces und wurde von der Workspace-Kontrolle blockiert',
|
||||
fenceDisableAction: 'Workspace-Kontrolle ausschalten',
|
||||
settingsBottomTerminalTitle: 'Beim ersten Ausklappen des unteren Panels automatisch ein Terminal öffnen',
|
||||
settingsBottomTerminalDesc: 'Wird das untere Panel in einer Sitzung zum ersten Mal ausgeklappt, wird dort versucht, einen neuen Terminal-Tab zu öffnen (das Terminal-Kontingent gilt weiterhin; standardmäßig aktiviert)',
|
||||
settingsFontFamilyTitle: 'Terminal-Schriftart',
|
||||
|
||||
@@ -220,6 +220,10 @@ export const fr: Record<string, string> = {
|
||||
settingsJobsDesc: 'Lorsque la session actuelle produit une nouvelle tâche d’arrière-plan, déployer automatiquement la barre latérale et ouvrir la page des tâches (déclenché à chaque nouvelle tâche) ; une fois désactivé, l’ouverture est manuelle',
|
||||
settingsToolsTitle: 'Injecter des outils de terminal au modèle',
|
||||
settingsToolsDesc: 'Une fois activé, le modèle peut créer et piloter des terminaux de la barre latérale via les 8 outils terminal_* (désactivé par défaut)',
|
||||
settingsFenceTitle: 'Contrôle des chemins de l\'espace de travail',
|
||||
settingsFenceDesc: 'Activé, les fonctions fichiers de la barre latérale n\'atteignent que les chemins dans l\'espace de travail de la session (par défaut) ; désactivé, les fichiers de tout l\'hôte deviennent accessibles — les scripts de la page obtiennent la même portée pendant ce temps',
|
||||
fenceErrorReason: 'Ce chemin est hors de l\'espace de travail de la session et a été bloqué par le contrôle',
|
||||
fenceDisableAction: 'Désactiver le contrôle de l\'espace de travail',
|
||||
settingsBottomTerminalTitle: 'Ouvrir automatiquement un terminal au premier déploiement du panneau inférieur',
|
||||
settingsBottomTerminalDesc: 'Lors du premier déploiement du panneau inférieur dans une session, tenter d’y ouvrir automatiquement un nouvel onglet de terminal (la limite du nombre de terminaux s’applique toujours ; activé par défaut)',
|
||||
settingsFontFamilyTitle: 'Police du terminal',
|
||||
|
||||
@@ -227,6 +227,10 @@ export const hi: Record<string, string> = {
|
||||
settingsJobsDesc: 'वर्तमान वार्तालाप में नया बैकग्राउंड कार्य दिखने पर साइडबार विस्तृत करें और कार्य पृष्ठ खोलें (हर नया कार्य ट्रिगर करता है); बंद करने पर मैन्युअल रूप से खोलें',
|
||||
settingsToolsTitle: 'मॉडल के लिए टर्मिनल टूल इंजेक्ट करें',
|
||||
settingsToolsDesc: 'सक्षम होने पर, मॉडल 8 terminal_* टूल्स से साइडबार टर्मिनल बना और चला सकता है (डिफ़ॉल्ट रूप से बंद)',
|
||||
settingsFenceTitle: 'वर्कस्पेस पाथ जाँच',
|
||||
settingsFenceDesc: 'चालू होने पर साइडबार की फ़ाइल सुविधाएँ केवल सेशन वर्कस्पेस के भीतर के पाथ तक पहुँचती हैं (डिफ़ॉल्ट); बंद करने पर होस्ट की कोई भी फ़ाइल खोली जा सकती है — उस दौरान पेज के स्क्रिप्ट को भी वही पहुँच मिल जाती है',
|
||||
fenceErrorReason: 'यह पाथ सेशन वर्कस्पेस के बाहर है और जाँच द्वारा अवरुद्ध किया गया',
|
||||
fenceDisableAction: 'वर्कस्पेस जाँच बंद करें',
|
||||
settingsBottomTerminalTitle: 'निचला पैनल पहली बार खुलने पर स्वतः टर्मिनल खोलें',
|
||||
settingsBottomTerminalDesc: 'सत्र में निचला पैनल पहली बार विस्तृत होने पर वहाँ नया टर्मिनल टैब खोलने का प्रयास (टर्मिनल कोटा लागू; डिफ़ॉल्ट रूप से चालू)',
|
||||
settingsFontFamilyTitle: 'टर्मिनल फ़ॉन्ट परिवार',
|
||||
|
||||
@@ -225,6 +225,10 @@ export const id: Record<string, string> = {
|
||||
settingsJobsDesc: 'Bentangkan kartu samping dan buka halaman Jobs setiap kali tugas latar baru muncul untuk obrolan saat ini (setiap tugas baru memicu); matikan untuk membukanya secara manual',
|
||||
settingsToolsTitle: 'Suntik alat terminal untuk model',
|
||||
settingsToolsDesc: 'Saat diaktifkan, model dapat membuat dan mengendalikan terminal sidebar melalui 8 alat terminal_* (nonaktif secara default)',
|
||||
settingsFenceTitle: 'Pemeriksaan path workspace',
|
||||
settingsFenceDesc: 'Saat aktif, fitur berkas sidebar hanya menjangkau path di dalam workspace sesi (default); saat nonaktif, berkas di mana pun di host dapat diakses — skrip halaman memperoleh jangkauan yang sama selama itu',
|
||||
fenceErrorReason: 'Path ini berada di luar workspace sesi dan diblokir oleh pemeriksaan',
|
||||
fenceDisableAction: 'Matikan pemeriksaan workspace',
|
||||
settingsBottomTerminalTitle: 'Buka terminal otomatis saat panel bawah pertama kali dibentangkan',
|
||||
settingsBottomTerminalDesc: 'Saat panel bawah pertama kali dibentangkan dalam sesi, coba buka tab terminal baru di panel bawah (kuota terminal tetap berlaku; aktif secara default)',
|
||||
settingsFontFamilyTitle: 'Keluarga font terminal',
|
||||
|
||||
@@ -218,6 +218,10 @@ export const it: Record<string, string> = {
|
||||
settingsJobsDesc: 'Espande la barra laterale e apre la pagina Attività in background ogni volta che compare una nuova attività in background per la conversazione attuale (ogni nuova attività la attiva); disattivato va aperta manualmente',
|
||||
settingsToolsTitle: 'Inietta strumenti del terminale per il modello',
|
||||
settingsToolsDesc: 'Se attivato, il modello può creare e gestire terminali della barra laterale attraverso gli 8 strumenti terminal_* (disattivato per impostazione predefinita)',
|
||||
settingsFenceTitle: 'Controllo dei percorsi del workspace',
|
||||
settingsFenceDesc: 'Attivo, le funzioni file della barra laterale raggiungono solo i percorsi nel workspace di sessione (predefinito); disattivo, ogni file dell\'host è raggiungibile — gli script della pagina ottengono la stessa portata nel frattempo',
|
||||
fenceErrorReason: 'Questo percorso è fuori dal workspace di sessione ed è stato bloccato dal controllo',
|
||||
fenceDisableAction: 'Disattiva il controllo del workspace',
|
||||
settingsBottomTerminalTitle: 'Apri automaticamente un terminale alla prima espansione del pannello inferiore',
|
||||
settingsBottomTerminalDesc: 'Quando il pannello inferiore viene espanso per la prima volta in una sessione, prova ad aprire una nuova scheda terminale nel pannello inferiore (il limite di terminali si applica comunque; attivo per impostazione predefinita)',
|
||||
settingsFontFamilyTitle: 'Famiglia di caratteri del terminale',
|
||||
|
||||
@@ -227,6 +227,10 @@ export const ja: Record<string, string> = {
|
||||
settingsJobsDesc: '現在の会話で新しいバックグラウンドタスクが発生するたびにサイドバーを展開してタスクページを開く(新規タスクごとに発火)。オフ時は手動で開く必要あり',
|
||||
settingsToolsTitle: 'モデルにターミナルツールを注入',
|
||||
settingsToolsDesc: 'オンにすると、モデルが terminal_create 等 8 個のツールでサイドバーターミナルを作成・操作可能(デフォルトオフ)',
|
||||
settingsFenceTitle: 'ワークスペースパスガード',
|
||||
settingsFenceDesc: 'オンの場合、サイドバーのファイル機能はセッションワークスペース内のパスのみアクセス可能(デフォルト)。オフにするとホスト上の任意のファイルにアクセスできるが、オフの間はページ内スクリプトも同じ権限を得る',
|
||||
fenceErrorReason: 'このパスはセッションワークスペースの外にあり、ワークスペースガードによりブロックされました',
|
||||
fenceDisableAction: 'ワークスペースガードをオフにする',
|
||||
settingsBottomTerminalTitle: '下パネル初回展開時に自動でターミナルを開く',
|
||||
settingsBottomTerminalDesc: '会話ごとに下パネルを初めて展開した際、下パネルに新しいターミナルタブを自動で開く(ターミナル数上限は依然適用。デフォルトオン)',
|
||||
settingsFontFamilyTitle: 'ターミナルフォント',
|
||||
|
||||
@@ -219,6 +219,10 @@ export const ko: Record<string, string> = {
|
||||
settingsJobsDesc: '현재 대화에 새 백그라운드 작업이 생기면 사이드바를 자동으로 펼치고 백그라운드 작업 페이지를 엽니다(새 작업마다 트리거됨). 끄면 수동으로 열어야 합니다',
|
||||
settingsToolsTitle: '모델에 터미널 도구 주입',
|
||||
settingsToolsDesc: '켜면 모델이 terminal_create 등 8개 도구로 사이드바 터미널을 만들고 조작할 수 있습니다(기본 꺼짐)',
|
||||
settingsFenceTitle: '워크스페이스 경로 검사',
|
||||
settingsFenceDesc: '켜면 사이드바의 파일 기능이 세션 워크스페이스 내 경로만 접근합니다(기본값). 끄면 호스트의 모든 파일에 접근할 수 있으며, 꺼져 있는 동안 페이지 내 스크립트도 동일한 권한을 얻습니다',
|
||||
fenceErrorReason: '이 경로는 세션 워크스페이스 밖에 있어 검사에 의해 차단되었습니다',
|
||||
fenceDisableAction: '워크스페이스 검사 끄기',
|
||||
settingsBottomTerminalTitle: '하단 패널을 처음 펼칠 때 터미널 자동 열기',
|
||||
settingsBottomTerminalDesc: '세션에서 하단 패널을 처음 펼칠 때 하단 패널에 새 터미널 탭을 자동으로 열려고 시도합니다(터미널 개수 상한은 여전히 적용됩니다. 기본 켜짐)',
|
||||
settingsFontFamilyTitle: '터미널 글꼴',
|
||||
|
||||
@@ -225,6 +225,10 @@ export const nl: Record<string, string> = {
|
||||
settingsJobsDesc: 'De zijkaart uitklappen en de Jobs-pagina openen telkens een nieuwe achtergrondtaak verschijnt voor de huidige conversatie (elke nieuwe taak triggert); schakel uit om het handmatig te openen',
|
||||
settingsToolsTitle: 'Terminaltools voor het model injecteren',
|
||||
settingsToolsDesc: 'Indien ingeschakeld kan het model zijbalk-terminals aanmaken en besturen via de 8 terminal_*-tools (standaard uit)',
|
||||
settingsFenceTitle: 'Workspace-padcontrole',
|
||||
settingsFenceDesc: 'Aan: de bestandsfuncties van de zijbalk bereiken alleen paden binnen de sessie-workspace (standaard); uit: elk bestand op de host is bereikbaar — paginascripts krijgen dat bereik zolang het uit staat',
|
||||
fenceErrorReason: 'Dit pad ligt buiten de sessie-workspace en is geblokkeerd door de controle',
|
||||
fenceDisableAction: 'Workspace-controle uitzetten',
|
||||
settingsBottomTerminalTitle: 'Automatisch een terminal openen bij de eerste uitklap van het onderpaneel',
|
||||
settingsBottomTerminalDesc: 'Wanneer het onderpaneel voor het eerst in een sessie wordt uitgeklapt, wordt geprobeerd daar een nieuw terminaltabblad te openen (het terminalquotum blijft gelden; standaard aan)',
|
||||
settingsFontFamilyTitle: 'Terminallettertype-familie',
|
||||
|
||||
@@ -229,6 +229,10 @@ export const pl: Record<string, string> = {
|
||||
settingsJobsDesc: 'Gdy w bieżącej rozmowie pojawi się nowe zadanie w tle, rozwiń panel boczny i otwórz stronę zadań w tle (każde nowe zadanie wyzwala); wyłącz, aby otwierać ręcznie',
|
||||
settingsToolsTitle: 'Wstrzyknij narzędzia terminala dla modelu',
|
||||
settingsToolsDesc: 'Po włączeniu model może tworzyć i sterować terminalami panelu bocznego przez 8 narzędzi terminal_* (domyślnie wyłączone)',
|
||||
settingsFenceTitle: 'Kontrola ścieżek obszaru roboczego',
|
||||
settingsFenceDesc: 'Włączona: funkcje plików paska bocznego sięgają tylko ścieżek w obszarze roboczym sesji (domyślnie); wyłączona: dostępny jest dowolny plik hosta — skrypty strony zyskują ten sam zasięg przez ten czas',
|
||||
fenceErrorReason: 'Ta ścieżka jest poza obszarem roboczym sesji i została zablokowana przez kontrolę',
|
||||
fenceDisableAction: 'Wyłącz kontrolę obszaru roboczego',
|
||||
settingsBottomTerminalTitle: 'Automatycznie otwieraj terminal przy pierwszym rozwinięciu panelu dolnego',
|
||||
settingsBottomTerminalDesc: 'Gdy panel dolny jest rozwijany po raz pierwszy w sesji, spróbuj otworzyć nową kartę terminala tam (limit terminali nadal obowiązuje; domyślnie włączone)',
|
||||
settingsFontFamilyTitle: 'Krój czcionki terminala',
|
||||
|
||||
@@ -210,6 +210,10 @@ export const pt: Record<string, string> = {
|
||||
settingsJobsDesc: 'Expandir o cartão lateral e abrir a página de Tarefas sempre que uma nova tarefa em segundo plano aparecer para a conversa atual (cada nova tarefa dispara); desative para abrir manualmente',
|
||||
settingsToolsTitle: 'Injetar ferramentas de terminal para o modelo',
|
||||
settingsToolsDesc: 'Quando ativado, o modelo pode criar e operar terminais da barra lateral por meio das 8 ferramentas terminal_* (desativado por padrão)',
|
||||
settingsFenceTitle: 'Controle de caminhos do workspace',
|
||||
settingsFenceDesc: 'Ativado, os recursos de arquivos da barra lateral só alcançam caminhos dentro do workspace da sessão (padrão); desativado, arquivos de todo o host ficam acessíveis — scripts da página ganham o mesmo alcance enquanto isso',
|
||||
fenceErrorReason: 'Este caminho está fora do workspace da sessão e foi bloqueado pelo controle',
|
||||
fenceDisableAction: 'Desativar o controle do workspace',
|
||||
settingsBottomTerminalTitle: 'Abrir um terminal automaticamente na primeira expansão do painel inferior',
|
||||
settingsBottomTerminalDesc: 'Quando o painel inferior for expandido pela primeira vez em uma sessão, tente abrir uma nova aba de terminal lá (a cota de terminais ainda se aplica; ativado por padrão)',
|
||||
settingsFontFamilyTitle: 'Família de fonte do terminal',
|
||||
|
||||
@@ -224,6 +224,10 @@ export const ru: Record<string, string> = {
|
||||
settingsJobsDesc: 'При появлении новой фоновой задачи в текущей сессии боковая панель автоматически разворачивается и открывается страница «Фоновые задачи» (срабатывает на каждую новую задачу); при отключении нужно открывать вручную',
|
||||
settingsToolsTitle: 'Внедрить терминальные инструменты для модели',
|
||||
settingsToolsDesc: 'Если включено, модель может через 8 инструментов (terminal_create и др.) создавать терминалы боковой панели и управлять ими (по умолчанию выключено)',
|
||||
settingsFenceTitle: 'Контроль путей рабочей области',
|
||||
settingsFenceDesc: 'Включено — файловые функции боковой панели достигают только путей внутри рабочей области сессии (по умолчанию); выключено — доступны любые файлы хоста, а скрипты страницы получают тот же доступ всё это время',
|
||||
fenceErrorReason: 'Этот путь вне рабочей области сессии и заблокирован контролем',
|
||||
fenceDisableAction: 'Отключить контроль рабочей области',
|
||||
settingsBottomTerminalTitle: 'Автооткрытие терминала при первом разворачивании нижней панели',
|
||||
settingsBottomTerminalDesc: 'При первом разворачивании нижней панели в сессии попытаться автоматически открыть новую вкладку терминала в ней (лимит терминалов всё равно применяется; по умолчанию включено)',
|
||||
settingsFontFamilyTitle: 'Шрифт терминала',
|
||||
|
||||
@@ -210,6 +210,10 @@ export const sv: Record<string, string> = {
|
||||
settingsJobsDesc: 'Expandera sidokortet och öppna Jobbsidan när ett nytt bakgrundsjobb dyker upp för aktuell konversation (varje nytt jobb utlöser); stäng av för att öppna manuellt',
|
||||
settingsToolsTitle: 'Injicera terminalverktyg för modellen',
|
||||
settingsToolsDesc: 'När aktiverat kan modellen skapa och styra sidopanelsterminaler via de 8 terminal_*-verktygen (av som standard)',
|
||||
settingsFenceTitle: 'Kontroll av workspace-sökvägar',
|
||||
settingsFenceDesc: 'På: sidopanelens filfunktioner når bara sökvägar i sessionens workspace (standard); av: vilken fil som helst på värden kan nås — sidans skript får samma räckvidd så länge',
|
||||
fenceErrorReason: 'Denna sökväg ligger utanför sessionens workspace och blockerades av kontrollen',
|
||||
fenceDisableAction: 'Stäng av workspace-kontrollen',
|
||||
settingsBottomTerminalTitle: 'Öppna automatiskt en terminal vid bottenpanelens första expandering',
|
||||
settingsBottomTerminalDesc: 'När bottenpanelen expanderas för första gången i en session, försök öppna en ny terminalflik där (terminalgränsen gäller fortfarande; på som standard)',
|
||||
settingsFontFamilyTitle: 'Terminalens teckensnittsfamilj',
|
||||
|
||||
@@ -227,6 +227,10 @@ export const th: Record<string, string> = {
|
||||
settingsJobsDesc: 'ขยายการ์ดด้านข้างและเปิดหน้า Jobs เมื่อใดก็ตามที่มีงานเบื้องหลังใหม่ปรากฏสำหรับแชทปัจจุบัน (ทุกงานใหม่จะทริกเกอร์); ปิดเพื่อเปิดเอง',
|
||||
settingsToolsTitle: 'ฉีดเครื่องมือเทอร์มินัลสำหรับโมเดล',
|
||||
settingsToolsDesc: 'เมื่อเปิดใช้ โมเดลสามารถสร้างและควบคุมเทอร์มินัลแถบด้านข้างผ่านเครื่องมือ terminal_* 8 ตัว (ปิดเป็นค่าเริ่มต้น)',
|
||||
settingsFenceTitle: 'การตรวจสอบเส้นทางเวิร์กสเปซ',
|
||||
settingsFenceDesc: 'เมื่อเปิด ฟีเจอร์ไฟล์ของแถบข้างเข้าถึงได้เฉพาะเส้นทางในเวิร์กสเปซของเซสชัน (ค่าเริ่มต้น) เมื่อปิด จะเข้าถึงไฟล์ใดก็ได้บนโฮสต์ — สคริปต์ในหน้าก็ได้ขอบเขตเดียวกันตลอดช่วงนั้น',
|
||||
fenceErrorReason: 'เส้นทางนี้อยู่นอกเวิร์กสเปซของเซสชันและถูกบล็อกโดยการตรวจสอบ',
|
||||
fenceDisableAction: 'ปิดการตรวจสอบเวิร์กสเปซ',
|
||||
settingsBottomTerminalTitle: 'เปิดเทอร์มินัลอัตโนมัติเมื่อพาเนลล่างขยายครั้งแรก',
|
||||
settingsBottomTerminalDesc: 'เมื่อพาเนลล่างถูกขยายครั้งแรกในเซสชัน ลองเปิด tab เทอร์มินัลใหม่ที่นั่น (โควต้าเทอร์มินัลยังคงมีผล; เปิดเป็นค่าเริ่มต้น)',
|
||||
settingsFontFamilyTitle: 'ฟอนต์เทอร์มินัล',
|
||||
|
||||
@@ -227,6 +227,10 @@ export const tr: Record<string, string> = {
|
||||
settingsJobsDesc: 'Geçerli sohbet için yeni bir arka plan işi belirdiğinde yan kartı genişlet ve İşler sayfasını aç (her yeni iş tetikler); elle açmak için kapatın',
|
||||
settingsToolsTitle: 'Model için terminal araçları enjekte et',
|
||||
settingsToolsDesc: 'Etkinleştirildiğinde model, 8 terminal_* aracı üzerinden kenar çubuğu terminalleri oluşturup kullanabilir (varsayılan kapalı)',
|
||||
settingsFenceTitle: 'Çalışma alanı yol denetimi',
|
||||
settingsFenceDesc: 'Açıkken kenar çubuğunun dosya işlevleri yalnızca oturum çalışma alanındaki yollara erişir (varsayılan); kapatıldığında ana makinedeki her dosyaya erişilebilir — o süre boyunca sayfadaki betikler de aynı erişimi kazanır',
|
||||
fenceErrorReason: 'Bu yol oturum çalışma alanının dışında ve denetim tarafından engellendi',
|
||||
fenceDisableAction: 'Çalışma alanı denetimini kapat',
|
||||
settingsBottomTerminalTitle: 'Alt panelin ilk genişletilmesinde otomatik terminal aç',
|
||||
settingsBottomTerminalDesc: 'Bir oturumda alt panel ilk genişletildiğinde orada yeni bir terminal sekmesi açmayı dene (terminal kotası yine geçerli; varsayılan açık)',
|
||||
settingsFontFamilyTitle: 'Terminal yazı tipi ailesi',
|
||||
|
||||
@@ -227,6 +227,10 @@ export const vi: Record<string, string> = {
|
||||
settingsJobsDesc: 'Khi phiên hiện tại có tác vụ nền mới, tự động mở rộng thanh bên và mở trang Tác vụ nền (mỗi tác vụ mới đều kích hoạt); tắt thì phải mở thủ công',
|
||||
settingsToolsTitle: 'Tiêm công cụ terminal cho mô hình',
|
||||
settingsToolsDesc: 'Khi bật, mô hình có thể tạo và điều khiển terminal thanh bên qua 8 công cụ terminal_* (mặc định tắt)',
|
||||
settingsFenceTitle: 'Kiểm tra đường dẫn workspace',
|
||||
settingsFenceDesc: 'Khi bật, các tính năng tệp của thanh bên chỉ truy cập đường dẫn trong workspace của phiên (mặc định); khi tắt, mọi tệp trên máy chủ đều có thể truy cập — script trong trang cũng có quyền tương ứng trong thời gian đó',
|
||||
fenceErrorReason: 'Đường dẫn này nằm ngoài workspace của phiên và đã bị chặn bởi kiểm tra',
|
||||
fenceDisableAction: 'Tắt kiểm tra workspace',
|
||||
settingsBottomTerminalTitle: 'Tự động mở terminal khi panel dưới mở rộng lần đầu',
|
||||
settingsBottomTerminalDesc: 'Khi panel dưới được mở rộng lần đầu trong phiên, thử mở một tab terminal mới ở panel dưới (giới hạn terminal vẫn áp dụng; mặc định bật)',
|
||||
settingsFontFamilyTitle: 'Font terminal',
|
||||
|
||||
@@ -242,6 +242,10 @@ export const zhHK: Record<string, string> = {
|
||||
settingsJobsDesc: '目前工作階段出現新的背景任務時,自動展開側邊欄並開啟背景任務頁(每個新任務都會觸發);關閉後需手動開啟',
|
||||
settingsToolsTitle: '為模型注入終端工具',
|
||||
settingsToolsDesc: '開啟後,模型可透過 terminal_create 等 8 個工具建立並操作側邊欄終端(預設關閉)',
|
||||
settingsFenceTitle: '工作區路徑檢測',
|
||||
settingsFenceDesc: '開啟後,側欄的檔案功能僅能存取工作階段工作區內的路徑(預設);關閉後可存取主機上任意檔案——關閉期間頁面內指令碼也將獲得同等存取能力',
|
||||
fenceErrorReason: '此路徑在工作階段工作區之外,已被工作區檢測攔截',
|
||||
fenceDisableAction: '關閉工作區檢測',
|
||||
settingsBottomTerminalTitle: '底部面板首次展開自動開終端',
|
||||
settingsBottomTerminalDesc: '每次工作階段中第一次展開底部面板時,嘗試在底部面板自動開啟一個新終端標籤(終端數量上限仍會限制;預設開啟)',
|
||||
settingsFontFamilyTitle: '終端字體',
|
||||
|
||||
@@ -242,6 +242,10 @@ export const zhMO: Record<string, string> = {
|
||||
settingsJobsDesc: '目前工作階段出現新的背景任務時,自動展開側邊欄並開啟背景任務頁(每個新任務都會觸發);關閉後需手動開啟',
|
||||
settingsToolsTitle: '為模型注入終端工具',
|
||||
settingsToolsDesc: '開啟後,模型可透過 terminal_create 等 8 個工具建立並操作側邊欄終端(預設關閉)',
|
||||
settingsFenceTitle: '工作區路徑檢測',
|
||||
settingsFenceDesc: '開啟後,側欄的檔案功能僅能存取工作階段工作區內的路徑(預設);關閉後可存取主機上任意檔案——關閉期間頁面內指令碼也將獲得同等存取能力',
|
||||
fenceErrorReason: '此路徑在工作階段工作區之外,已被工作區檢測攔截',
|
||||
fenceDisableAction: '關閉工作區檢測',
|
||||
settingsBottomTerminalTitle: '底部面板首次展開自動開終端',
|
||||
settingsBottomTerminalDesc: '每次工作階段中第一次展開底部面板時,嘗試在底部面板自動開啟一個新終端標籤(終端數量上限仍會限制;預設開啟)',
|
||||
settingsFontFamilyTitle: '終端字體',
|
||||
|
||||
@@ -242,6 +242,10 @@ export const zhTW: Record<string, string> = {
|
||||
settingsJobsDesc: '目前工作階段出現新的背景任務時,自動展開側邊欄並開啟背景任務頁(每個新任務都會觸發);關閉後需手動開啟',
|
||||
settingsToolsTitle: '為模型注入終端工具',
|
||||
settingsToolsDesc: '開啟後,模型可透過 terminal_create 等 8 個工具建立並操作側邊欄終端(預設關閉)',
|
||||
settingsFenceTitle: '工作區路徑檢測',
|
||||
settingsFenceDesc: '開啟後,側欄的檔案功能僅能存取工作階段工作區內的路徑(預設);關閉後可存取主機上任意檔案——關閉期間頁面內指令碼也將獲得同等存取能力',
|
||||
fenceErrorReason: '此路徑在工作階段工作區之外,已被工作區檢測攔截',
|
||||
fenceDisableAction: '關閉工作區檢測',
|
||||
settingsBottomTerminalTitle: '底部面板首次展開自動開終端',
|
||||
settingsBottomTerminalDesc: '每次工作階段中第一次展開底部面板時,嘗試在底部面板自動開啟一個新終端標籤(終端數量上限仍會限制;預設開啟)',
|
||||
settingsFontFamilyTitle: '終端字體',
|
||||
|
||||
@@ -234,6 +234,10 @@ export const zh = {
|
||||
settingsJobsDesc: '当前会话出现新的后台任务时,自动展开侧边栏并打开后台任务页(每个新任务都会触发);关闭后需手动打开',
|
||||
settingsToolsTitle: '为模型注入终端工具',
|
||||
settingsToolsDesc: '开启后,模型可通过 terminal_create 等 8 个工具创建并操作侧边栏终端(默认关闭)',
|
||||
settingsFenceTitle: '工作区路径检测',
|
||||
settingsFenceDesc: '开启后,侧栏的文件功能仅能访问会话工作区内的路径(默认);关闭后可访问主机上任意文件——关闭期间页面内脚本也将获得同等访问能力',
|
||||
fenceErrorReason: '此路径在会话工作区之外,已被工作区检测拦截',
|
||||
fenceDisableAction: '关闭工作区检测',
|
||||
settingsBottomTerminalTitle: '底部面板首次展开自动开终端',
|
||||
settingsBottomTerminalDesc: '每次会话中第一次展开底部面板时,尝试在底部面板自动打开一个新终端标签(终端数量上限仍会限制;默认开启)',
|
||||
settingsFontFamilyTitle: '终端字体',
|
||||
@@ -590,6 +594,10 @@ export const en: Record<keyof typeof zh, string> = {
|
||||
settingsJobsDesc: 'Expand the side card and open the Jobs page whenever a new background job appears for the current conversation (every new job triggers); turn off to open it manually',
|
||||
settingsToolsTitle: 'Inject terminal tools for the model',
|
||||
settingsToolsDesc: 'When enabled, the model can create and drive sidebar terminals through the 8 terminal_* tools (off by default)',
|
||||
settingsFenceTitle: 'Workspace path fence',
|
||||
settingsFenceDesc: 'On, the sidebar\'s file features only reach paths inside the session workspace (default); off, any file on the host is reachable — page scripts gain the same reach while it is off',
|
||||
fenceErrorReason: 'This path is outside the session workspace and was blocked by the workspace fence',
|
||||
fenceDisableAction: 'Turn off the workspace fence',
|
||||
settingsBottomTerminalTitle: 'Auto-open a terminal on the bottom panel\'s first expansion',
|
||||
settingsBottomTerminalDesc: 'When the bottom panel is expanded for the first time in a session, try to open a fresh terminal tab there (the terminal quota still applies; on by default)',
|
||||
settingsFontFamilyTitle: 'Terminal font family',
|
||||
|
||||
@@ -82,6 +82,9 @@ export function parsePrefs(value: unknown): SidebarPrefs {
|
||||
editorExplorer: typeof record.editorExplorer === 'boolean'
|
||||
? record.editorExplorer
|
||||
: SIDEBAR_PREFS_DEFAULTS.editorExplorer,
|
||||
workspaceFence: typeof record.workspaceFence === 'boolean'
|
||||
? record.workspaceFence
|
||||
: SIDEBAR_PREFS_DEFAULTS.workspaceFence,
|
||||
// The title-bar scheme (auto | web | preset | custom). The schema
|
||||
// declares the field WITHOUT a default, so documents written by older
|
||||
// plugin versions resolve without it — migrate from the legacy fields:
|
||||
|
||||
@@ -1493,6 +1493,18 @@ body[data-dsh-sidebar-dragging] .bottomPanel {
|
||||
color: var(--dsw-alias-state-error-primary);
|
||||
}
|
||||
|
||||
/* The workspace-fence refusal row (FenceErrorNotice): reason text plus the
|
||||
* one-click global-off button share one baseline, wrapping when narrow. */
|
||||
.fenceError {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
font: var(--dsw-font-xxs-12);
|
||||
color: var(--dsw-alias-state-error-primary);
|
||||
}
|
||||
|
||||
.editorBanner {
|
||||
flex: none;
|
||||
padding: 4px 8px;
|
||||
|
||||
Reference in New Issue
Block a user