From 8b5102e55e1d73733f45bf3eaf6ce265e8ab1f4d Mon Sep 17 00:00:00 2001 From: Dmitry Lyalin Date: Tue, 10 Mar 2026 09:46:48 -0400 Subject: [PATCH] Rename directory command to workspace --- docs/cli/settings.md | 2 +- docs/reference/commands.md | 8 +++--- docs/tools/mcp-server.md | 4 +-- packages/cli/src/commands/mcp/add.test.ts | 26 +++++++++---------- packages/cli/src/commands/mcp/add.ts | 18 ++++++++----- packages/cli/src/commands/mcp/remove.test.ts | 6 ++--- packages/cli/src/commands/mcp/remove.ts | 11 ++++---- packages/cli/src/config/footerItems.ts | 4 +-- packages/cli/src/config/settingsSchema.ts | 4 +-- .../cli/src/services/BuiltinCommandLoader.ts | 4 +-- ...and.test.tsx => workspaceCommand.test.tsx} | 18 ++++++------- ...ectoryCommand.tsx => workspaceCommand.tsx} | 8 +++--- .../cli/src/ui/components/Footer.test.tsx | 6 ++--- .../ui/components/FooterConfigDialog.test.tsx | 11 +++----- .../__snapshots__/Footer.test.tsx.snap | 12 ++++----- ...ts-the-active-item-in-the-preview.snap.svg | 20 +++++++------- ...s-correctly-with-default-settings.snap.svg | 24 ++++++++--------- ...Show-footer-labels-is-toggled-off.snap.svg | 2 +- .../FooterConfigDialog.test.tsx.snap | 20 +++++++------- packages/cli/src/ui/constants/tips.ts | 6 ++--- schemas/settings.schema.json | 6 ++--- 21 files changed, 110 insertions(+), 110 deletions(-) rename packages/cli/src/ui/commands/{directoryCommand.test.tsx => workspaceCommand.test.tsx} (95%) rename packages/cli/src/ui/commands/{directoryCommand.tsx => workspaceCommand.tsx} (98%) diff --git a/docs/cli/settings.md b/docs/cli/settings.md index 5565a5e1f6..59f6521d9f 100644 --- a/docs/cli/settings.md +++ b/docs/cli/settings.md @@ -57,7 +57,7 @@ they appear in the UI. | Show Shortcuts Hint | `ui.showShortcutsHint` | Show the "? for shortcuts" hint above the input. | `true` | | Hide Banner | `ui.hideBanner` | Hide the application banner | `false` | | Hide Context Summary | `ui.hideContextSummary` | Hide the context summary (GEMINI.md, MCP servers) above the input. | `false` | -| Hide CWD | `ui.footer.hideCWD` | Hide the current working directory in the footer. | `false` | +| Hide Workspace Path | `ui.footer.hideCWD` | Hide the workspace path in the footer. | `false` | | Hide Sandbox Status | `ui.footer.hideSandboxStatus` | Hide the sandbox status indicator in the footer. | `false` | | Hide Model Info | `ui.footer.hideModelInfo` | Hide the model name and context usage in the footer. | `false` | | Hide Context Window Percentage | `ui.footer.hideContextPercentage` | Hides the context window usage percentage. | `true` | diff --git a/docs/reference/commands.md b/docs/reference/commands.md index c7c25cba1e..b666cd54fc 100644 --- a/docs/reference/commands.md +++ b/docs/reference/commands.md @@ -115,7 +115,7 @@ Slash commands provide meta-level control over the CLI itself. - On macOS, it requires `pbcopy`, and on Windows, it requires `clip`. These tools are typically pre-installed on their respective systems. -### `/directory` (or `/dir`) +### `/workspace` (or `/directory`, `/dir`) - **Description:** Manage workspace directories for multi-directory support. - **Sub-commands:** @@ -123,13 +123,13 @@ Slash commands provide meta-level control over the CLI itself. - **Description:** Add a directory to the workspace. The path can be absolute or relative to the current working directory. Moreover, the reference from home directory is supported as well. - - **Usage:** `/directory add ,` + - **Usage:** `/workspace add ,` - **Note:** Disabled in restrictive sandbox profiles. If you're using that, use `--include-directories` when starting the session instead. - **`show`**: - - **Description:** Display all directories added by `/directory add` and + - **Description:** Display all directories added by `/workspace add` and `--include-directories`. - - **Usage:** `/directory show` + - **Usage:** `/workspace show` ### `/docs` diff --git a/docs/tools/mcp-server.md b/docs/tools/mcp-server.md index bbb5c62aba..ee35fefd61 100644 --- a/docs/tools/mcp-server.md +++ b/docs/tools/mcp-server.md @@ -998,7 +998,7 @@ gemini mcp add [options] [args...] **Options (flags):** -- `-s, --scope`: Configuration scope (user or project). [default: "project"] +- `-s, --scope`: Configuration scope (user or workspace). [default: "workspace"] - `-t, --transport`: Transport type (stdio, sse, http). [default: "stdio"] - `-e, --env`: Set environment variables (e.g. -e KEY=value). - `-H, --header`: Set HTTP headers for SSE and HTTP transports (e.g. -H @@ -1109,7 +1109,7 @@ gemini mcp remove **Options (flags):** -- `-s, --scope`: Configuration scope (user or project). [default: "project"] +- `-s, --scope`: Configuration scope (user or workspace). [default: "workspace"] **Example:** diff --git a/packages/cli/src/commands/mcp/add.test.ts b/packages/cli/src/commands/mcp/add.test.ts index e6f955b680..3e679bc44f 100644 --- a/packages/cli/src/commands/mcp/add.test.ts +++ b/packages/cli/src/commands/mcp/add.test.ts @@ -71,7 +71,7 @@ describe('mcp add command', () => { }); }); - it('should add a stdio server to project settings', async () => { + it('should add a stdio server to workspace settings', async () => { await parser.parseAsync( 'add -e FOO=bar my-server /path/to/server arg1 arg2', ); @@ -121,7 +121,7 @@ describe('mcp add command', () => { }); }); - it('should add an http server to project settings', async () => { + it('should add an http server to workspace settings', async () => { await parser.parseAsync( 'add --transport http -H "Authorization: Bearer your-token" http-server https://example.com/mcp', ); @@ -219,12 +219,12 @@ describe('mcp add command', () => { }); }; - describe('when in a project directory', () => { + describe('when in a workspace directory', () => { beforeEach(() => { setupMocks('/path/to/project', '/path/to/project'); }); - it('should use project scope by default', async () => { + it('should use workspace scope by default', async () => { await parser.parseAsync(`add ${serverName} ${command}`); expect(mockSetValue).toHaveBeenCalledWith( SettingScope.Workspace, @@ -233,7 +233,7 @@ describe('mcp add command', () => { ); }); - it('should use project scope when --scope=project is used', async () => { + it('should support --scope=project as a compatibility alias', async () => { await parser.parseAsync(`add --scope project ${serverName} ${command}`); expect(mockSetValue).toHaveBeenCalledWith( SettingScope.Workspace, @@ -252,12 +252,12 @@ describe('mcp add command', () => { }); }); - describe('when in a subdirectory of a project', () => { + describe('when in a subdirectory of a workspace', () => { beforeEach(() => { setupMocks('/path/to/project/subdir', '/path/to/project'); }); - it('should use project scope by default', async () => { + it('should use workspace scope by default', async () => { await parser.parseAsync(`add ${serverName} ${command}`); expect(mockSetValue).toHaveBeenCalledWith( SettingScope.Workspace, @@ -290,7 +290,7 @@ describe('mcp add command', () => { expect(mockSetValue).not.toHaveBeenCalled(); }); - it('should show an error when --scope=project is used explicitly', async () => { + it('should show an error when --scope=project is used as a compatibility alias', async () => { const mockProcessExit = vi .spyOn(process, 'exit') .mockImplementation((() => { @@ -319,12 +319,12 @@ describe('mcp add command', () => { }); }); - describe('when in a subdirectory of home (not a project)', () => { + describe('when in a subdirectory of home (not a workspace)', () => { beforeEach(() => { setupMocks('/home/user/some/dir', '/home/user/some/dir'); }); - it('should use project scope by default', async () => { + it('should use workspace scope by default', async () => { await parser.parseAsync(`add ${serverName} ${command}`); expect(mockSetValue).toHaveBeenCalledWith( SettingScope.Workspace, @@ -347,12 +347,12 @@ describe('mcp add command', () => { }); }); - describe('when outside of home (not a project)', () => { + describe('when outside of home (not a workspace)', () => { beforeEach(() => { setupMocks('/tmp/foo', '/tmp/foo'); }); - it('should use project scope by default', async () => { + it('should use workspace scope by default', async () => { await parser.parseAsync(`add ${serverName} ${command}`); expect(mockSetValue).toHaveBeenCalledWith( SettingScope.Workspace, @@ -386,7 +386,7 @@ describe('mcp add command', () => { }); }); - it('should update the existing server in the project scope', async () => { + it('should update the existing server in the workspace scope', async () => { await parser.parseAsync( `add ${serverName} ${updatedCommand} ${updatedArgs.join(' ')}`, ); diff --git a/packages/cli/src/commands/mcp/add.ts b/packages/cli/src/commands/mcp/add.ts index 98e6a70879..8f87f2ef0f 100644 --- a/packages/cli/src/commands/mcp/add.ts +++ b/packages/cli/src/commands/mcp/add.ts @@ -38,10 +38,12 @@ async function addMcpServer( excludeTools, } = options; + const displayScope = scope === 'user' ? 'user' : 'workspace'; + const settings = loadSettings(process.cwd()); const inHome = settings.workspace.path === settings.user.path; - if (scope === 'project' && inHome) { + if (displayScope === 'workspace' && inHome) { debugLogger.error( 'Error: Please use --scope user to edit settings in the home directory.', ); @@ -120,7 +122,7 @@ async function addMcpServer( const isExistingServer = !!mcpServers[name]; if (isExistingServer) { debugLogger.log( - `MCP server "${name}" is already configured within ${scope} settings.`, + `MCP server "${name}" is already configured within ${displayScope} settings.`, ); } @@ -129,10 +131,12 @@ async function addMcpServer( settings.setValue(settingsScope, 'mcpServers', mcpServers); if (isExistingServer) { - debugLogger.log(`MCP server "${name}" updated in ${scope} settings.`); + debugLogger.log( + `MCP server "${name}" updated in ${displayScope} settings.`, + ); } else { debugLogger.log( - `MCP server "${name}" added to ${scope} settings. (${transport})`, + `MCP server "${name}" added to ${displayScope} settings. (${transport})`, ); } } @@ -159,10 +163,10 @@ export const addCommand: CommandModule = { }) .option('scope', { alias: 's', - describe: 'Configuration scope (user or project)', + describe: 'Configuration scope (user or workspace)', type: 'string', - default: 'project', - choices: ['user', 'project'], + default: 'workspace', + choices: ['user', 'workspace', 'project'], }) .option('transport', { alias: ['t', 'type'], diff --git a/packages/cli/src/commands/mcp/remove.test.ts b/packages/cli/src/commands/mcp/remove.test.ts index ef8f35f096..3fcaf8e0b6 100644 --- a/packages/cli/src/commands/mcp/remove.test.ts +++ b/packages/cli/src/commands/mcp/remove.test.ts @@ -81,7 +81,7 @@ describe('mcp remove command', () => { parser = yargsInstance; }); - it('should remove a server from project settings', async () => { + it('should remove a server from workspace settings', async () => { await parser.parseAsync('remove test-server'); expect(mockSetValue).toHaveBeenCalledWith( @@ -99,7 +99,7 @@ describe('mcp remove command', () => { expect(mockSetValue).not.toHaveBeenCalled(); expect(debugLogSpy).toHaveBeenCalledWith( - 'Server "non-existent-server" not found in project settings.', + 'Server "non-existent-server" not found in workspace settings.', ); debugLogSpy.mockRestore(); }); @@ -159,7 +159,7 @@ describe('mcp remove command', () => { expect(updatedContent).not.toContain('"server-to-remove"'); expect(debugLogSpy).toHaveBeenCalledWith( - 'Server "server-to-remove" removed from project settings.', + 'Server "server-to-remove" removed from workspace settings.', ); debugLogSpy.mockRestore(); diff --git a/packages/cli/src/commands/mcp/remove.ts b/packages/cli/src/commands/mcp/remove.ts index 8c5bd1efab..a5b1cf805b 100644 --- a/packages/cli/src/commands/mcp/remove.ts +++ b/packages/cli/src/commands/mcp/remove.ts @@ -17,6 +17,7 @@ async function removeMcpServer( }, ) { const { scope } = options; + const displayScope = scope === 'user' ? 'user' : 'workspace'; const settingsScope = scope === 'user' ? SettingScope.User : SettingScope.Workspace; const settings = loadSettings(); @@ -25,7 +26,7 @@ async function removeMcpServer( const mcpServers = existingSettings.mcpServers || {}; if (!mcpServers[name]) { - debugLogger.log(`Server "${name}" not found in ${scope} settings.`); + debugLogger.log(`Server "${name}" not found in ${displayScope} settings.`); return; } @@ -33,7 +34,7 @@ async function removeMcpServer( settings.setValue(settingsScope, 'mcpServers', mcpServers); - debugLogger.log(`Server "${name}" removed from ${scope} settings.`); + debugLogger.log(`Server "${name}" removed from ${displayScope} settings.`); } export const removeCommand: CommandModule = { @@ -49,10 +50,10 @@ export const removeCommand: CommandModule = { }) .option('scope', { alias: 's', - describe: 'Configuration scope (user or project)', + describe: 'Configuration scope (user or workspace)', type: 'string', - default: 'project', - choices: ['user', 'project'], + default: 'workspace', + choices: ['user', 'workspace', 'project'], }), handler: async (argv) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion diff --git a/packages/cli/src/config/footerItems.ts b/packages/cli/src/config/footerItems.ts index 8410d0b5ec..38697f791b 100644 --- a/packages/cli/src/config/footerItems.ts +++ b/packages/cli/src/config/footerItems.ts @@ -9,8 +9,8 @@ import type { MergedSettings } from './settings.js'; export const ALL_ITEMS = [ { id: 'workspace', - header: 'workspace (/directory)', - description: 'Current working directory', + header: 'workspace', + description: 'Current workspace path', }, { id: 'git-branch', diff --git a/packages/cli/src/config/settingsSchema.ts b/packages/cli/src/config/settingsSchema.ts index bd1f9d82a4..bd78b6b35e 100644 --- a/packages/cli/src/config/settingsSchema.ts +++ b/packages/cli/src/config/settingsSchema.ts @@ -588,11 +588,11 @@ const SETTINGS_SCHEMA = { }, hideCWD: { type: 'boolean', - label: 'Hide CWD', + label: 'Hide Workspace Path', category: 'UI', requiresRestart: false, default: false, - description: 'Hide the current working directory in the footer.', + description: 'Hide the workspace path in the footer.', showInDialog: true, }, hideSandboxStatus: { diff --git a/packages/cli/src/services/BuiltinCommandLoader.ts b/packages/cli/src/services/BuiltinCommandLoader.ts index 66806f5ef1..eb848e7b19 100644 --- a/packages/cli/src/services/BuiltinCommandLoader.ts +++ b/packages/cli/src/services/BuiltinCommandLoader.ts @@ -29,7 +29,7 @@ import { compressCommand } from '../ui/commands/compressCommand.js'; import { copyCommand } from '../ui/commands/copyCommand.js'; import { corgiCommand } from '../ui/commands/corgiCommand.js'; import { docsCommand } from '../ui/commands/docsCommand.js'; -import { directoryCommand } from '../ui/commands/directoryCommand.js'; +import { workspaceCommand } from '../ui/commands/workspaceCommand.js'; import { editorCommand } from '../ui/commands/editorCommand.js'; import { extensionsCommand } from '../ui/commands/extensionsCommand.js'; import { footerCommand } from '../ui/commands/footerCommand.js'; @@ -131,7 +131,7 @@ export class BuiltinCommandLoader implements ICommandLoader { copyCommand, corgiCommand, docsCommand, - directoryCommand, + workspaceCommand, editorCommand, ...(this.config?.getExtensionsEnabled() === false ? [ diff --git a/packages/cli/src/ui/commands/directoryCommand.test.tsx b/packages/cli/src/ui/commands/workspaceCommand.test.tsx similarity index 95% rename from packages/cli/src/ui/commands/directoryCommand.test.tsx rename to packages/cli/src/ui/commands/workspaceCommand.test.tsx index d9c534a89e..de9c420143 100644 --- a/packages/cli/src/ui/commands/directoryCommand.test.tsx +++ b/packages/cli/src/ui/commands/workspaceCommand.test.tsx @@ -6,7 +6,7 @@ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest'; import type { Mock } from 'vitest'; -import { directoryCommand } from './directoryCommand.js'; +import { workspaceCommand } from './workspaceCommand.js'; import { expandHomeDir, getDirectorySuggestions, @@ -38,14 +38,14 @@ vi.mock('../utils/directoryUtils.js', async (importOriginal) => { }; }); -describe('directoryCommand', () => { +describe('workspaceCommand', () => { let mockContext: CommandContext; let mockConfig: Config; let mockWorkspaceContext: WorkspaceContext; - const addCommand = directoryCommand.subCommands?.find( + const addCommand = workspaceCommand.subCommands?.find( (c) => c.name === 'add', ); - const showCommand = directoryCommand.subCommands?.find( + const showCommand = workspaceCommand.subCommands?.find( (c) => c.name === 'show', ); @@ -126,7 +126,7 @@ describe('directoryCommand', () => { type: 'message', messageType: 'error', content: - 'The /directory add command is not supported in restrictive sandbox profiles. Please use --include-directories when starting the session instead.', + 'The /workspace add command is not supported in restrictive sandbox profiles. Please use --include-directories when starting the session instead.', }); }); @@ -343,7 +343,6 @@ describe('directoryCommand', () => { beforeEach(() => { vi.spyOn(trustedFolders, 'isFolderTrustEnabled').mockReturnValue(true); - // isWorkspaceTrusted is no longer checked, so we don't need to mock it returning true mockIsPathTrusted = vi.fn(); const mockLoadedFolders = { isPathTrusted: mockIsPathTrusted, @@ -375,7 +374,7 @@ describe('directoryCommand', () => { it('should return a custom dialog for an explicitly untrusted directory (upgrade flow)', async () => { if (!addCommand?.action) throw new Error('No action'); - mockIsPathTrusted.mockReturnValue(false); // DO_NOT_TRUST + mockIsPathTrusted.mockReturnValue(false); const newPath = path.resolve('/home/user/untrusted-project'); const result = await addCommand.action(mockContext, newPath); @@ -384,7 +383,7 @@ describe('directoryCommand', () => { expect.objectContaining({ type: 'custom_dialog', component: expect.objectContaining({ - type: expect.any(Function), // React component for MultiFolderTrustDialog + type: expect.any(Function), }), }), ); @@ -407,7 +406,7 @@ describe('directoryCommand', () => { expect.objectContaining({ type: 'custom_dialog', component: expect.objectContaining({ - type: expect.any(Function), // React component for MultiFolderTrustDialog + type: expect.any(Function), }), }), ); @@ -421,7 +420,6 @@ describe('directoryCommand', () => { it('should prompt for directory even if workspace is untrusted', async () => { if (!addCommand?.action) throw new Error('No action'); - // Even if workspace is untrusted, we should still check directory trust vi.spyOn(trustedFolders, 'isWorkspaceTrusted').mockReturnValue({ isTrusted: false, source: 'file', diff --git a/packages/cli/src/ui/commands/directoryCommand.tsx b/packages/cli/src/ui/commands/workspaceCommand.tsx similarity index 98% rename from packages/cli/src/ui/commands/directoryCommand.tsx rename to packages/cli/src/ui/commands/workspaceCommand.tsx index 08a65ca78a..7f3ff4b33e 100644 --- a/packages/cli/src/ui/commands/directoryCommand.tsx +++ b/packages/cli/src/ui/commands/workspaceCommand.tsx @@ -77,9 +77,9 @@ async function finishAddingDirectories( } } -export const directoryCommand: SlashCommand = { - name: 'directory', - altNames: ['dir'], +export const workspaceCommand: SlashCommand = { + name: 'workspace', + altNames: ['directory', 'dir'], description: 'Manage workspace directories', kind: CommandKind.BUILT_IN, subCommands: [ @@ -156,7 +156,7 @@ export const directoryCommand: SlashCommand = { type: 'message' as const, messageType: 'error' as const, content: - 'The /directory add command is not supported in restrictive sandbox profiles. Please use --include-directories when starting the session instead.', + 'The /workspace add command is not supported in restrictive sandbox profiles. Please use --include-directories when starting the session instead.', }; } diff --git a/packages/cli/src/ui/components/Footer.test.tsx b/packages/cli/src/ui/components/Footer.test.tsx index 21aa6ee5c0..7424d95e9a 100644 --- a/packages/cli/src/ui/components/Footer.test.tsx +++ b/packages/cli/src/ui/components/Footer.test.tsx @@ -755,7 +755,7 @@ describe('