feat(permissions): add workspace directory management tab

- Add Workspace tab to PermissionsDialog with full directory management UI
  - Directory list view: initial (non-removable) dirs shown inline,
    runtime-added dirs selectable; "Add directory…" always first
  - Add directory input view: filesystem autocomplete with ↑/↓ navigation
    and Tab-to-complete; path validation (existence, type, duplicate,
    subdirectory checks)
  - Remove directory confirmation view
  - Save directly to project settings (SettingScope.Workspace), no scope
    selection step
- Add onTab/onUp/onDown props to TextInput to intercept keys before buffer
- Add removeDirectory() and isInitialDirectory() to WorkspaceContext
- Add --add-dir CLI alias for --include-directories
- Add /add-dir slash command (alias for /directory add)
- Add permissions.additionalDirectories settings field
- Add i18n keys for all workspace directory UI strings (en/zh/de/ja/pt/ru)"
This commit is contained in:
LaZzyMan 2026-03-11 10:54:59 +08:00
parent 217d59c892
commit e793e82729
14 changed files with 780 additions and 13 deletions

View file

@ -21,6 +21,12 @@ export interface TextInputProps {
value: string;
onChange: (text: string) => void;
onSubmit?: () => void;
/** Called when Tab is pressed; if provided, prevents the default tab-insertion behaviour. */
onTab?: () => void;
/** Called when ↑ is pressed; if provided, prevents cursor-up in the buffer. */
onUp?: () => void;
/** Called when ↓ is pressed; if provided, prevents cursor-down in the buffer. */
onDown?: () => void;
placeholder?: string;
height?: number; // lines in viewport; >1 enables multiline
isActive?: boolean; // when false, ignore keypresses
@ -32,6 +38,9 @@ export function TextInput({
value,
onChange,
onSubmit,
onTab,
onUp,
onDown,
placeholder,
height = 1,
isActive = true,
@ -65,6 +74,22 @@ export function TextInput({
(key: Key) => {
if (!buffer || !isActive) return;
// Tab completion: delegate to caller instead of inserting a tab character
if (key.name === 'tab') {
onTab?.();
return;
}
// Arrow-key completion navigation: delegate to caller
if (key.name === 'up' && onUp) {
onUp();
return;
}
if (key.name === 'down' && onDown) {
onDown();
return;
}
// Submit on Enter
if (keyMatchers[Command.SUBMIT](key) || key.name === 'return') {
if (allowMultiline) {