@google/gemini-cli 0.25.0-nightly.20260112.15891721a → 0.25.0-preview.0
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/dist/package.json +2 -2
- package/dist/src/commands/extensions/examples/mcp-server/example.d.ts +6 -0
- package/dist/src/commands/extensions/examples/mcp-server/example.js +22 -36
- package/dist/src/commands/extensions/examples/mcp-server/example.js.map +1 -0
- package/dist/src/commands/extensions/examples/mcp-server/example.test.d.ts +6 -0
- package/dist/src/commands/extensions/examples/mcp-server/example.test.js +111 -0
- package/dist/src/commands/extensions/examples/mcp-server/example.test.js.map +1 -0
- package/dist/src/commands/extensions/examples/mcp-server/example.test.ts +135 -0
- package/dist/src/commands/extensions/examples/mcp-server/example.ts +60 -0
- package/dist/src/commands/extensions/examples/mcp-server/gemini-extension.json +1 -1
- package/dist/src/commands/extensions/examples/mcp-server/package.json +7 -0
- package/dist/src/commands/extensions/examples/mcp-server/tsconfig.json +13 -0
- package/dist/src/commands/extensions/utils.d.ts +1 -1
- package/dist/src/commands/skills/disable.js +1 -1
- package/dist/src/commands/skills/disable.js.map +1 -1
- package/dist/src/commands/skills/disable.test.js +1 -1
- package/dist/src/commands/skills/disable.test.js.map +1 -1
- package/dist/src/commands/skills/install.d.ts +14 -0
- package/dist/src/commands/skills/install.js +61 -0
- package/dist/src/commands/skills/install.js.map +1 -0
- package/dist/src/commands/skills/install.test.d.ts +6 -0
- package/dist/src/commands/skills/install.test.js +57 -0
- package/dist/src/commands/skills/install.test.js.map +1 -0
- package/dist/src/commands/skills/list.js +1 -1
- package/dist/src/commands/skills/list.js.map +1 -1
- package/dist/src/commands/skills/list.test.js +1 -1
- package/dist/src/commands/skills/list.test.js.map +1 -1
- package/dist/src/commands/skills/uninstall.d.ts +13 -0
- package/dist/src/commands/skills/uninstall.js +56 -0
- package/dist/src/commands/skills/uninstall.js.map +1 -0
- package/dist/src/commands/skills/uninstall.test.d.ts +6 -0
- package/dist/src/commands/skills/uninstall.test.js +61 -0
- package/dist/src/commands/skills/uninstall.test.js.map +1 -0
- package/dist/src/commands/skills.js +4 -0
- package/dist/src/commands/skills.js.map +1 -1
- package/dist/src/config/config.js +5 -0
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/extension-manager-agents.test.d.ts +6 -0
- package/dist/src/config/extension-manager-agents.test.js +115 -0
- package/dist/src/config/extension-manager-agents.test.js.map +1 -0
- package/dist/src/config/extension-manager-scope.test.js +11 -0
- package/dist/src/config/extension-manager-scope.test.js.map +1 -1
- package/dist/src/config/extension-manager-skills.test.js +4 -0
- package/dist/src/config/extension-manager-skills.test.js.map +1 -1
- package/dist/src/config/extension-manager.js +7 -1
- package/dist/src/config/extension-manager.js.map +1 -1
- package/dist/src/config/extension.test.js +10 -1
- package/dist/src/config/extension.test.js.map +1 -1
- package/dist/src/config/keyBindings.d.ts +14 -2
- package/dist/src/config/keyBindings.js +85 -10
- package/dist/src/config/keyBindings.js.map +1 -1
- package/dist/src/config/settings.js +8 -9
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +66 -2
- package/dist/src/config/settingsSchema.js +99 -2
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/gemini.js +12 -6
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/services/BuiltinCommandLoader.js +18 -1
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
- package/dist/src/test-utils/render.js +1 -0
- package/dist/src/test-utils/render.js.map +1 -1
- package/dist/src/ui/AppContainer.js +103 -40
- package/dist/src/ui/AppContainer.js.map +1 -1
- package/dist/src/ui/AppContainer.test.js +214 -41
- package/dist/src/ui/AppContainer.test.js.map +1 -1
- package/dist/src/ui/auth/AuthDialog.d.ts +4 -1
- package/dist/src/ui/auth/AuthDialog.js +8 -2
- package/dist/src/ui/auth/AuthDialog.js.map +1 -1
- package/dist/src/ui/auth/AuthDialog.test.js +17 -0
- package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
- package/dist/src/ui/auth/LoginWithGoogleRestartDialog.d.ts +10 -0
- package/dist/src/ui/auth/LoginWithGoogleRestartDialog.js +27 -0
- package/dist/src/ui/auth/LoginWithGoogleRestartDialog.js.map +1 -0
- package/dist/src/ui/auth/LoginWithGoogleRestartDialog.test.d.ts +6 -0
- package/dist/src/ui/auth/LoginWithGoogleRestartDialog.test.js +68 -0
- package/dist/src/ui/auth/LoginWithGoogleRestartDialog.test.js.map +1 -0
- package/dist/src/ui/commands/aboutCommand.js +1 -1
- package/dist/src/ui/commands/aboutCommand.js.map +1 -1
- package/dist/src/ui/commands/aboutCommand.test.js +4 -4
- package/dist/src/ui/commands/aboutCommand.test.js.map +1 -1
- package/dist/src/ui/commands/agentsCommand.js +5 -1
- package/dist/src/ui/commands/agentsCommand.js.map +1 -1
- package/dist/src/ui/commands/agentsCommand.test.js +1 -1
- package/dist/src/ui/commands/agentsCommand.test.js.map +1 -1
- package/dist/src/ui/commands/chatCommand.js +1 -1
- package/dist/src/ui/commands/chatCommand.js.map +1 -1
- package/dist/src/ui/commands/chatCommand.test.js +1 -1
- package/dist/src/ui/commands/chatCommand.test.js.map +1 -1
- package/dist/src/ui/commands/directoryCommand.js +9 -9
- package/dist/src/ui/commands/directoryCommand.js.map +1 -1
- package/dist/src/ui/commands/directoryCommand.test.js +9 -9
- package/dist/src/ui/commands/directoryCommand.test.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.js +36 -36
- package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.test.js +36 -36
- package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -1
- package/dist/src/ui/commands/helpCommand.js +1 -1
- package/dist/src/ui/commands/helpCommand.js.map +1 -1
- package/dist/src/ui/commands/helpCommand.test.js +1 -1
- package/dist/src/ui/commands/helpCommand.test.js.map +1 -1
- package/dist/src/ui/commands/hooksCommand.js +1 -1
- package/dist/src/ui/commands/hooksCommand.js.map +1 -1
- package/dist/src/ui/commands/hooksCommand.test.js +4 -4
- package/dist/src/ui/commands/hooksCommand.test.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.js +6 -6
- package/dist/src/ui/commands/mcpCommand.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.test.js +3 -3
- package/dist/src/ui/commands/mcpCommand.test.js.map +1 -1
- package/dist/src/ui/commands/memoryCommand.js +18 -43
- package/dist/src/ui/commands/memoryCommand.js.map +1 -1
- package/dist/src/ui/commands/memoryCommand.test.js +85 -15
- package/dist/src/ui/commands/memoryCommand.test.js.map +1 -1
- package/dist/src/ui/commands/skillsCommand.js +23 -8
- package/dist/src/ui/commands/skillsCommand.js.map +1 -1
- package/dist/src/ui/commands/skillsCommand.test.js +33 -12
- package/dist/src/ui/commands/skillsCommand.test.js.map +1 -1
- package/dist/src/ui/commands/statsCommand.js +4 -4
- package/dist/src/ui/commands/statsCommand.js.map +1 -1
- package/dist/src/ui/commands/statsCommand.test.js +4 -4
- package/dist/src/ui/commands/statsCommand.test.js.map +1 -1
- package/dist/src/ui/commands/toolsCommand.js +2 -2
- package/dist/src/ui/commands/toolsCommand.js.map +1 -1
- package/dist/src/ui/commands/toolsCommand.test.js +2 -2
- package/dist/src/ui/commands/toolsCommand.test.js.map +1 -1
- package/dist/src/ui/components/DialogManager.js +1 -1
- package/dist/src/ui/components/DialogManager.js.map +1 -1
- package/dist/src/ui/components/Help.js +1 -1
- package/dist/src/ui/components/Help.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.js +18 -7
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.test.js +64 -1
- package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
- package/dist/src/ui/components/MainContent.js +6 -9
- package/dist/src/ui/components/MainContent.js.map +1 -1
- package/dist/src/ui/components/MainContent.test.js +19 -9
- package/dist/src/ui/components/MainContent.test.js.map +1 -1
- package/dist/src/ui/components/ModelDialog.js +1 -1
- package/dist/src/ui/components/ModelDialog.js.map +1 -1
- package/dist/src/ui/components/MultiFolderTrustDialog.d.ts +2 -2
- package/dist/src/ui/components/MultiFolderTrustDialog.js +1 -1
- package/dist/src/ui/components/MultiFolderTrustDialog.js.map +1 -1
- package/dist/src/ui/components/MultiFolderTrustDialog.test.js +2 -2
- package/dist/src/ui/components/MultiFolderTrustDialog.test.js.map +1 -1
- package/dist/src/ui/components/SettingsDialog.test.js +5 -2
- package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
- package/dist/src/ui/components/StickyHeader.d.ts +2 -0
- package/dist/src/ui/components/StickyHeader.js +1 -1
- package/dist/src/ui/components/StickyHeader.js.map +1 -1
- package/dist/src/ui/components/messages/DiffRenderer.js +5 -13
- package/dist/src/ui/components/messages/DiffRenderer.js.map +1 -1
- package/dist/src/ui/components/messages/DiffRenderer.test.js +26 -17
- package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
- package/dist/src/ui/components/messages/ShellToolMessage.js +8 -5
- package/dist/src/ui/components/messages/ShellToolMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +1 -5
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolMessage.js +6 -2
- package/dist/src/ui/components/messages/ToolMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolResultDisplay.js +22 -16
- package/dist/src/ui/components/messages/ToolResultDisplay.js.map +1 -1
- package/dist/src/ui/components/messages/ToolResultDisplay.test.js +36 -18
- package/dist/src/ui/components/messages/ToolResultDisplay.test.js.map +1 -1
- package/dist/src/ui/components/messages/ToolStickyHeaderRegression.test.d.ts +6 -0
- package/dist/src/ui/components/messages/ToolStickyHeaderRegression.test.js +134 -0
- package/dist/src/ui/components/messages/ToolStickyHeaderRegression.test.js.map +1 -0
- package/dist/src/ui/components/shared/MaxSizedBox.d.ts +2 -38
- package/dist/src/ui/components/shared/MaxSizedBox.js +34 -419
- package/dist/src/ui/components/shared/MaxSizedBox.js.map +1 -1
- package/dist/src/ui/components/shared/MaxSizedBox.test.js +48 -133
- package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -1
- package/dist/src/ui/components/shared/text-buffer.d.ts +4 -4
- package/dist/src/ui/components/shared/text-buffer.js +35 -38
- package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
- package/dist/src/ui/components/views/AgentsStatus.js +3 -3
- package/dist/src/ui/components/views/AgentsStatus.js.map +1 -1
- package/dist/src/ui/constants/tips.js +1 -1
- package/dist/src/ui/constants/tips.js.map +1 -1
- package/dist/src/ui/constants.d.ts +1 -0
- package/dist/src/ui/constants.js +1 -0
- package/dist/src/ui/constants.js.map +1 -1
- package/dist/src/ui/contexts/KeypressContext.js +28 -0
- package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
- package/dist/src/ui/contexts/KeypressContext.test.js +31 -1
- package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
- package/dist/src/ui/contexts/UIActionsContext.d.ts +3 -0
- package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.d.ts +2 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.js +5 -4
- package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +1 -1
- package/dist/src/ui/hooks/useCommandCompletion.d.ts +1 -0
- package/dist/src/ui/hooks/useCommandCompletion.js +1 -0
- package/dist/src/ui/hooks/useCommandCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useCommandCompletion.test.js +7 -2
- package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.test.js +11 -2
- package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.d.ts +2 -1
- package/dist/src/ui/hooks/useGeminiStream.js +34 -14
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.test.js +87 -10
- package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
- package/dist/src/ui/hooks/useHistoryManager.d.ts +1 -1
- package/dist/src/ui/hooks/useHistoryManager.js +1 -1
- package/dist/src/ui/hooks/useHistoryManager.js.map +1 -1
- package/dist/src/ui/hooks/useHistoryManager.test.js +16 -0
- package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -1
- package/dist/src/ui/hooks/useIncludeDirsTrust.js +2 -2
- package/dist/src/ui/hooks/useIncludeDirsTrust.js.map +1 -1
- package/dist/src/ui/hooks/useIncludeDirsTrust.test.js +2 -2
- package/dist/src/ui/hooks/useIncludeDirsTrust.test.js.map +1 -1
- package/dist/src/ui/hooks/useLoadingIndicator.d.ts +2 -1
- package/dist/src/ui/hooks/useLoadingIndicator.js +7 -3
- package/dist/src/ui/hooks/useLoadingIndicator.js.map +1 -1
- package/dist/src/ui/hooks/useLoadingIndicator.test.js +14 -4
- package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
- package/dist/src/ui/hooks/usePhraseCycler.d.ts +1 -1
- package/dist/src/ui/hooks/usePhraseCycler.js +2 -2
- package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
- package/dist/src/ui/keyMatchers.test.js +79 -53
- package/dist/src/ui/keyMatchers.test.js.map +1 -1
- package/dist/src/ui/types.d.ts +2 -1
- package/dist/src/ui/types.js +2 -0
- package/dist/src/ui/types.js.map +1 -1
- package/dist/src/ui/utils/CodeColorizer.js +2 -2
- package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
- package/dist/src/ui/utils/commandUtils.js +1 -3
- package/dist/src/ui/utils/commandUtils.js.map +1 -1
- package/dist/src/ui/utils/commandUtils.test.js +15 -2
- package/dist/src/ui/utils/commandUtils.test.js.map +1 -1
- package/dist/src/utils/sessionCleanup.js +12 -0
- package/dist/src/utils/sessionCleanup.js.map +1 -1
- package/dist/src/utils/skillUtils.d.ts +13 -0
- package/dist/src/utils/skillUtils.js +93 -0
- package/dist/src/utils/skillUtils.js.map +1 -1
- package/dist/src/utils/skillUtils.test.d.ts +6 -0
- package/dist/src/utils/skillUtils.test.js +57 -0
- package/dist/src/utils/skillUtils.test.js.map +1 -0
- package/dist/src/utils/windowTitle.d.ts +13 -4
- package/dist/src/utils/windowTitle.js +65 -7
- package/dist/src/utils/windowTitle.js.map +1 -1
- package/dist/src/utils/windowTitle.test.js +183 -40
- package/dist/src/utils/windowTitle.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/dist/google-gemini-cli-0.25.0-nightly.20260107.59a18e710.tgz +0 -0
- package/dist/src/commands/extensions/examples/hooks/gemini-extension.json +0 -4
- package/dist/src/commands/extensions/examples/hooks/hooks/hooks.json +0 -14
- package/dist/src/commands/extensions/examples/hooks/scripts/on-start.js +0 -8
- package/dist/src/commands/extensions/examples/mcp-server/README.md +0 -35
- package/dist/src/commands/extensions/examples/skills/gemini-extension.json +0 -4
- package/dist/src/commands/extensions/examples/skills/skills/greeter/SKILL.md +0 -7
|
@@ -174,16 +174,10 @@ describe('AppContainer State Management', () => {
|
|
|
174
174
|
const mockedUseHookDisplayState = useHookDisplayState;
|
|
175
175
|
beforeEach(() => {
|
|
176
176
|
vi.clearAllMocks();
|
|
177
|
+
mockIdeClient.getInstance.mockReturnValue(new Promise(() => { }));
|
|
177
178
|
// Initialize mock stdout for terminal title tests
|
|
178
179
|
mocks.mockStdout.write.mockClear();
|
|
179
|
-
// Mock computeWindowTitle function to centralize title logic testing
|
|
180
|
-
vi.mock('../utils/windowTitle.js', async () => ({
|
|
181
|
-
computeWindowTitle: vi.fn((folderName) =>
|
|
182
|
-
// Default behavior: return "Gemini - {folderName}" unless CLI_TITLE is set
|
|
183
|
-
process.env['CLI_TITLE'] || `Gemini - ${folderName}`),
|
|
184
|
-
}));
|
|
185
180
|
capturedUIState = null;
|
|
186
|
-
capturedUIActions = null;
|
|
187
181
|
// **Provide a default return value for EVERY mocked hook.**
|
|
188
182
|
mockedUseQuotaAndFallback.mockReturnValue({
|
|
189
183
|
proQuotaRequest: null,
|
|
@@ -324,6 +318,7 @@ describe('AppContainer State Management', () => {
|
|
|
324
318
|
});
|
|
325
319
|
afterEach(() => {
|
|
326
320
|
cleanup();
|
|
321
|
+
vi.restoreAllMocks();
|
|
327
322
|
});
|
|
328
323
|
describe('Basic Rendering', () => {
|
|
329
324
|
it('renders without crashing with minimal props', async () => {
|
|
@@ -839,7 +834,7 @@ describe('AppContainer State Management', () => {
|
|
|
839
834
|
const { stdout } = useStdout();
|
|
840
835
|
expect(stdout).toBe(mocks.mockStdout);
|
|
841
836
|
});
|
|
842
|
-
it('should
|
|
837
|
+
it('should update terminal title with Working… when showStatusInTitle is false', () => {
|
|
843
838
|
// Arrange: Set up mock settings with showStatusInTitle disabled
|
|
844
839
|
const mockSettingsWithShowStatusFalse = {
|
|
845
840
|
...mockSettings,
|
|
@@ -852,13 +847,55 @@ describe('AppContainer State Management', () => {
|
|
|
852
847
|
},
|
|
853
848
|
},
|
|
854
849
|
};
|
|
850
|
+
// Mock the streaming state as Active
|
|
851
|
+
mockedUseGeminiStream.mockReturnValue({
|
|
852
|
+
streamingState: 'responding',
|
|
853
|
+
submitQuery: vi.fn(),
|
|
854
|
+
initError: null,
|
|
855
|
+
pendingHistoryItems: [],
|
|
856
|
+
thought: { subject: 'Some thought' },
|
|
857
|
+
cancelOngoingRequest: vi.fn(),
|
|
858
|
+
});
|
|
855
859
|
// Act: Render the container
|
|
856
860
|
const { unmount } = renderAppContainer({
|
|
857
861
|
settings: mockSettingsWithShowStatusFalse,
|
|
858
862
|
});
|
|
859
|
-
// Assert: Check that
|
|
860
|
-
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]
|
|
861
|
-
expect(titleWrites).toHaveLength(
|
|
863
|
+
// Assert: Check that title was updated with "Working…"
|
|
864
|
+
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
865
|
+
expect(titleWrites).toHaveLength(1);
|
|
866
|
+
expect(titleWrites[0][0]).toBe(`\x1b]0;${'✦ Working… (workspace)'.padEnd(80, ' ')}\x07`);
|
|
867
|
+
unmount();
|
|
868
|
+
});
|
|
869
|
+
it('should use legacy terminal title when dynamicWindowTitle is false', () => {
|
|
870
|
+
// Arrange: Set up mock settings with dynamicWindowTitle disabled
|
|
871
|
+
const mockSettingsWithDynamicTitleFalse = {
|
|
872
|
+
...mockSettings,
|
|
873
|
+
merged: {
|
|
874
|
+
...mockSettings.merged,
|
|
875
|
+
ui: {
|
|
876
|
+
...mockSettings.merged.ui,
|
|
877
|
+
dynamicWindowTitle: false,
|
|
878
|
+
hideWindowTitle: false,
|
|
879
|
+
},
|
|
880
|
+
},
|
|
881
|
+
};
|
|
882
|
+
// Mock the streaming state
|
|
883
|
+
mockedUseGeminiStream.mockReturnValue({
|
|
884
|
+
streamingState: 'responding',
|
|
885
|
+
submitQuery: vi.fn(),
|
|
886
|
+
initError: null,
|
|
887
|
+
pendingHistoryItems: [],
|
|
888
|
+
thought: { subject: 'Some thought' },
|
|
889
|
+
cancelOngoingRequest: vi.fn(),
|
|
890
|
+
});
|
|
891
|
+
// Act: Render the container
|
|
892
|
+
const { unmount } = renderAppContainer({
|
|
893
|
+
settings: mockSettingsWithDynamicTitleFalse,
|
|
894
|
+
});
|
|
895
|
+
// Assert: Check that legacy title was used
|
|
896
|
+
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
897
|
+
expect(titleWrites).toHaveLength(1);
|
|
898
|
+
expect(titleWrites[0][0]).toBe(`\x1b]0;${'Gemini CLI (workspace)'.padEnd(80, ' ')}\x07`);
|
|
862
899
|
unmount();
|
|
863
900
|
});
|
|
864
901
|
it('should not update terminal title when hideWindowTitle is true', () => {
|
|
@@ -879,7 +916,7 @@ describe('AppContainer State Management', () => {
|
|
|
879
916
|
settings: mockSettingsWithHideTitleTrue,
|
|
880
917
|
});
|
|
881
918
|
// Assert: Check that no title-related writes occurred
|
|
882
|
-
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]
|
|
919
|
+
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
883
920
|
expect(titleWrites).toHaveLength(0);
|
|
884
921
|
unmount();
|
|
885
922
|
});
|
|
@@ -910,10 +947,10 @@ describe('AppContainer State Management', () => {
|
|
|
910
947
|
const { unmount } = renderAppContainer({
|
|
911
948
|
settings: mockSettingsWithTitleEnabled,
|
|
912
949
|
});
|
|
913
|
-
// Assert: Check that title was updated with thought subject
|
|
914
|
-
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]
|
|
950
|
+
// Assert: Check that title was updated with thought subject and suffix
|
|
951
|
+
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
915
952
|
expect(titleWrites).toHaveLength(1);
|
|
916
|
-
expect(titleWrites[0][0]).toBe(`\x1b]
|
|
953
|
+
expect(titleWrites[0][0]).toBe(`\x1b]0;${`✦ ${thoughtSubject} (workspace)`.padEnd(80, ' ')}\x07`);
|
|
917
954
|
unmount();
|
|
918
955
|
});
|
|
919
956
|
it('should update terminal title with default text when in Idle state and no thought subject', () => {
|
|
@@ -943,12 +980,12 @@ describe('AppContainer State Management', () => {
|
|
|
943
980
|
settings: mockSettingsWithTitleEnabled,
|
|
944
981
|
});
|
|
945
982
|
// Assert: Check that title was updated with default Idle text
|
|
946
|
-
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]
|
|
983
|
+
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
947
984
|
expect(titleWrites).toHaveLength(1);
|
|
948
|
-
expect(titleWrites[0][0]).toBe(`\x1b]
|
|
985
|
+
expect(titleWrites[0][0]).toBe(`\x1b]0;${'◇ Ready (workspace)'.padEnd(80, ' ')}\x07`);
|
|
949
986
|
unmount();
|
|
950
987
|
});
|
|
951
|
-
it('should update terminal title when in WaitingForConfirmation state with thought subject', () => {
|
|
988
|
+
it('should update terminal title when in WaitingForConfirmation state with thought subject', async () => {
|
|
952
989
|
// Arrange: Set up mock settings with showStatusInTitle enabled
|
|
953
990
|
const mockSettingsWithTitleEnabled = {
|
|
954
991
|
...mockSettings,
|
|
@@ -964,7 +1001,7 @@ describe('AppContainer State Management', () => {
|
|
|
964
1001
|
// Mock the streaming state and thought
|
|
965
1002
|
const thoughtSubject = 'Confirm tool execution';
|
|
966
1003
|
mockedUseGeminiStream.mockReturnValue({
|
|
967
|
-
streamingState: '
|
|
1004
|
+
streamingState: 'waiting_for_confirmation',
|
|
968
1005
|
submitQuery: vi.fn(),
|
|
969
1006
|
initError: null,
|
|
970
1007
|
pendingHistoryItems: [],
|
|
@@ -972,15 +1009,146 @@ describe('AppContainer State Management', () => {
|
|
|
972
1009
|
cancelOngoingRequest: vi.fn(),
|
|
973
1010
|
});
|
|
974
1011
|
// Act: Render the container
|
|
975
|
-
|
|
976
|
-
|
|
1012
|
+
let unmount;
|
|
1013
|
+
await act(async () => {
|
|
1014
|
+
const result = renderAppContainer({
|
|
1015
|
+
settings: mockSettingsWithTitleEnabled,
|
|
1016
|
+
});
|
|
1017
|
+
unmount = result.unmount;
|
|
977
1018
|
});
|
|
978
1019
|
// Assert: Check that title was updated with confirmation text
|
|
979
|
-
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]
|
|
1020
|
+
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
980
1021
|
expect(titleWrites).toHaveLength(1);
|
|
981
|
-
expect(titleWrites[0][0]).toBe(`\x1b]
|
|
1022
|
+
expect(titleWrites[0][0]).toBe(`\x1b]0;${'✋ Action Required (workspace)'.padEnd(80, ' ')}\x07`);
|
|
982
1023
|
unmount();
|
|
983
1024
|
});
|
|
1025
|
+
describe('Shell Focus Action Required', () => {
|
|
1026
|
+
beforeEach(() => {
|
|
1027
|
+
vi.useFakeTimers();
|
|
1028
|
+
});
|
|
1029
|
+
afterEach(() => {
|
|
1030
|
+
vi.useRealTimers();
|
|
1031
|
+
});
|
|
1032
|
+
it('should show Action Required in title after a delay when shell is awaiting focus', async () => {
|
|
1033
|
+
const startTime = 1000000;
|
|
1034
|
+
vi.setSystemTime(startTime);
|
|
1035
|
+
// Arrange: Set up mock settings with showStatusInTitle enabled
|
|
1036
|
+
const mockSettingsWithTitleEnabled = {
|
|
1037
|
+
...mockSettings,
|
|
1038
|
+
merged: {
|
|
1039
|
+
...mockSettings.merged,
|
|
1040
|
+
ui: {
|
|
1041
|
+
...mockSettings.merged.ui,
|
|
1042
|
+
showStatusInTitle: true,
|
|
1043
|
+
hideWindowTitle: false,
|
|
1044
|
+
},
|
|
1045
|
+
},
|
|
1046
|
+
};
|
|
1047
|
+
// Mock an active shell pty but not focused
|
|
1048
|
+
mockedUseGeminiStream.mockReturnValue({
|
|
1049
|
+
streamingState: 'responding',
|
|
1050
|
+
submitQuery: vi.fn(),
|
|
1051
|
+
initError: null,
|
|
1052
|
+
pendingHistoryItems: [],
|
|
1053
|
+
thought: { subject: 'Executing shell command' },
|
|
1054
|
+
cancelOngoingRequest: vi.fn(),
|
|
1055
|
+
activePtyId: 'pty-1',
|
|
1056
|
+
lastOutputTime: 0,
|
|
1057
|
+
});
|
|
1058
|
+
vi.spyOn(mockConfig, 'isInteractive').mockReturnValue(true);
|
|
1059
|
+
vi.spyOn(mockConfig, 'isInteractiveShellEnabled').mockReturnValue(true);
|
|
1060
|
+
// Act: Render the container (embeddedShellFocused is false by default in state)
|
|
1061
|
+
const { unmount } = renderAppContainer({
|
|
1062
|
+
settings: mockSettingsWithTitleEnabled,
|
|
1063
|
+
});
|
|
1064
|
+
// Initially it should show the working status
|
|
1065
|
+
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
1066
|
+
expect(titleWrites[titleWrites.length - 1][0]).toContain('✦ Executing shell command');
|
|
1067
|
+
// Fast-forward time by 40 seconds
|
|
1068
|
+
await act(async () => {
|
|
1069
|
+
await vi.advanceTimersByTimeAsync(40000);
|
|
1070
|
+
});
|
|
1071
|
+
// Now it should show Action Required
|
|
1072
|
+
const titleWritesDelayed = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
1073
|
+
const lastTitle = titleWritesDelayed[titleWritesDelayed.length - 1][0];
|
|
1074
|
+
expect(lastTitle).toContain('✋ Action Required');
|
|
1075
|
+
unmount();
|
|
1076
|
+
});
|
|
1077
|
+
it('should NOT show Action Required in title if shell is streaming output', async () => {
|
|
1078
|
+
const startTime = 1000000;
|
|
1079
|
+
vi.setSystemTime(startTime);
|
|
1080
|
+
// Arrange: Set up mock settings with showStatusInTitle enabled
|
|
1081
|
+
const mockSettingsWithTitleEnabled = {
|
|
1082
|
+
...mockSettings,
|
|
1083
|
+
merged: {
|
|
1084
|
+
...mockSettings.merged,
|
|
1085
|
+
ui: {
|
|
1086
|
+
...mockSettings.merged.ui,
|
|
1087
|
+
showStatusInTitle: true,
|
|
1088
|
+
hideWindowTitle: false,
|
|
1089
|
+
},
|
|
1090
|
+
},
|
|
1091
|
+
};
|
|
1092
|
+
// Mock an active shell pty but not focused
|
|
1093
|
+
let lastOutputTime = 1000;
|
|
1094
|
+
mockedUseGeminiStream.mockImplementation(() => ({
|
|
1095
|
+
streamingState: 'responding',
|
|
1096
|
+
submitQuery: vi.fn(),
|
|
1097
|
+
initError: null,
|
|
1098
|
+
pendingHistoryItems: [],
|
|
1099
|
+
thought: { subject: 'Executing shell command' },
|
|
1100
|
+
cancelOngoingRequest: vi.fn(),
|
|
1101
|
+
activePtyId: 'pty-1',
|
|
1102
|
+
lastOutputTime,
|
|
1103
|
+
}));
|
|
1104
|
+
vi.spyOn(mockConfig, 'isInteractive').mockReturnValue(true);
|
|
1105
|
+
vi.spyOn(mockConfig, 'isInteractiveShellEnabled').mockReturnValue(true);
|
|
1106
|
+
// Act: Render the container
|
|
1107
|
+
const { unmount, rerender } = renderAppContainer({
|
|
1108
|
+
settings: mockSettingsWithTitleEnabled,
|
|
1109
|
+
});
|
|
1110
|
+
// Fast-forward time by 20 seconds
|
|
1111
|
+
await act(async () => {
|
|
1112
|
+
await vi.advanceTimersByTimeAsync(20000);
|
|
1113
|
+
});
|
|
1114
|
+
// Update lastOutputTime to simulate new output
|
|
1115
|
+
lastOutputTime = 21000;
|
|
1116
|
+
mockedUseGeminiStream.mockImplementation(() => ({
|
|
1117
|
+
streamingState: 'responding',
|
|
1118
|
+
submitQuery: vi.fn(),
|
|
1119
|
+
initError: null,
|
|
1120
|
+
pendingHistoryItems: [],
|
|
1121
|
+
thought: { subject: 'Executing shell command' },
|
|
1122
|
+
cancelOngoingRequest: vi.fn(),
|
|
1123
|
+
activePtyId: 'pty-1',
|
|
1124
|
+
lastOutputTime,
|
|
1125
|
+
}));
|
|
1126
|
+
// Rerender to propagate the new lastOutputTime
|
|
1127
|
+
await act(async () => {
|
|
1128
|
+
rerender(getAppContainer({ settings: mockSettingsWithTitleEnabled }));
|
|
1129
|
+
});
|
|
1130
|
+
// Fast-forward time by another 20 seconds
|
|
1131
|
+
// Total time elapsed: 40s.
|
|
1132
|
+
// Time since last output: 20s.
|
|
1133
|
+
// It should NOT show Action Required yet.
|
|
1134
|
+
await act(async () => {
|
|
1135
|
+
await vi.advanceTimersByTimeAsync(20000);
|
|
1136
|
+
});
|
|
1137
|
+
const titleWritesAfterOutput = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
1138
|
+
const lastTitle = titleWritesAfterOutput[titleWritesAfterOutput.length - 1][0];
|
|
1139
|
+
expect(lastTitle).not.toContain('✋ Action Required');
|
|
1140
|
+
expect(lastTitle).toContain('✦ Executing shell command');
|
|
1141
|
+
// Fast-forward another 40 seconds (Total 60s since last output)
|
|
1142
|
+
await act(async () => {
|
|
1143
|
+
await vi.advanceTimersByTimeAsync(40000);
|
|
1144
|
+
});
|
|
1145
|
+
// Now it SHOULD show Action Required
|
|
1146
|
+
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
1147
|
+
const lastTitleFinal = titleWrites[titleWrites.length - 1][0];
|
|
1148
|
+
expect(lastTitleFinal).toContain('✋ Action Required');
|
|
1149
|
+
unmount();
|
|
1150
|
+
});
|
|
1151
|
+
});
|
|
984
1152
|
it('should pad title to exactly 80 characters', () => {
|
|
985
1153
|
// Arrange: Set up mock settings with showStatusInTitle enabled
|
|
986
1154
|
const mockSettingsWithTitleEnabled = {
|
|
@@ -1009,14 +1177,12 @@ describe('AppContainer State Management', () => {
|
|
|
1009
1177
|
settings: mockSettingsWithTitleEnabled,
|
|
1010
1178
|
});
|
|
1011
1179
|
// Assert: Check that title is padded to exactly 80 characters
|
|
1012
|
-
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]
|
|
1180
|
+
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
1013
1181
|
expect(titleWrites).toHaveLength(1);
|
|
1014
1182
|
const calledWith = titleWrites[0][0];
|
|
1015
|
-
const expectedTitle = shortTitle
|
|
1016
|
-
|
|
1017
|
-
expect(calledWith).
|
|
1018
|
-
expect(calledWith).toContain('\x07');
|
|
1019
|
-
expect(calledWith).toBe('\x1b]2;' + expectedTitle + '\x07');
|
|
1183
|
+
const expectedTitle = `✦ ${shortTitle} (workspace)`.padEnd(80, ' ');
|
|
1184
|
+
const expectedEscapeSequence = `\x1b]0;${expectedTitle}\x07`;
|
|
1185
|
+
expect(calledWith).toBe(expectedEscapeSequence);
|
|
1020
1186
|
unmount();
|
|
1021
1187
|
});
|
|
1022
1188
|
it('should use correct ANSI escape code format', () => {
|
|
@@ -1047,30 +1213,30 @@ describe('AppContainer State Management', () => {
|
|
|
1047
1213
|
settings: mockSettingsWithTitleEnabled,
|
|
1048
1214
|
});
|
|
1049
1215
|
// Assert: Check that the correct ANSI escape sequence is used
|
|
1050
|
-
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]
|
|
1216
|
+
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
1051
1217
|
expect(titleWrites).toHaveLength(1);
|
|
1052
|
-
const expectedEscapeSequence = `\x1b]
|
|
1218
|
+
const expectedEscapeSequence = `\x1b]0;${`✦ ${title} (workspace)`.padEnd(80, ' ')}\x07`;
|
|
1053
1219
|
expect(titleWrites[0][0]).toBe(expectedEscapeSequence);
|
|
1054
1220
|
unmount();
|
|
1055
1221
|
});
|
|
1056
1222
|
it('should use CLI_TITLE environment variable when set', () => {
|
|
1057
|
-
// Arrange: Set up mock settings with showStatusInTitle
|
|
1058
|
-
const
|
|
1223
|
+
// Arrange: Set up mock settings with showStatusInTitle disabled (so it shows suffix)
|
|
1224
|
+
const mockSettingsWithTitleDisabled = {
|
|
1059
1225
|
...mockSettings,
|
|
1060
1226
|
merged: {
|
|
1061
1227
|
...mockSettings.merged,
|
|
1062
1228
|
ui: {
|
|
1063
1229
|
...mockSettings.merged.ui,
|
|
1064
|
-
showStatusInTitle:
|
|
1230
|
+
showStatusInTitle: false,
|
|
1065
1231
|
hideWindowTitle: false,
|
|
1066
1232
|
},
|
|
1067
1233
|
},
|
|
1068
1234
|
};
|
|
1069
1235
|
// Mock CLI_TITLE environment variable
|
|
1070
1236
|
vi.stubEnv('CLI_TITLE', 'Custom Gemini Title');
|
|
1071
|
-
// Mock the streaming state
|
|
1237
|
+
// Mock the streaming state
|
|
1072
1238
|
mockedUseGeminiStream.mockReturnValue({
|
|
1073
|
-
streamingState: '
|
|
1239
|
+
streamingState: 'responding',
|
|
1074
1240
|
submitQuery: vi.fn(),
|
|
1075
1241
|
initError: null,
|
|
1076
1242
|
pendingHistoryItems: [],
|
|
@@ -1079,12 +1245,12 @@ describe('AppContainer State Management', () => {
|
|
|
1079
1245
|
});
|
|
1080
1246
|
// Act: Render the container
|
|
1081
1247
|
const { unmount } = renderAppContainer({
|
|
1082
|
-
settings:
|
|
1248
|
+
settings: mockSettingsWithTitleDisabled,
|
|
1083
1249
|
});
|
|
1084
1250
|
// Assert: Check that title was updated with CLI_TITLE value
|
|
1085
|
-
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]
|
|
1251
|
+
const titleWrites = mocks.mockStdout.write.mock.calls.filter((call) => call[0].includes('\x1b]0;'));
|
|
1086
1252
|
expect(titleWrites).toHaveLength(1);
|
|
1087
|
-
expect(titleWrites[0][0]).toBe(`\x1b]
|
|
1253
|
+
expect(titleWrites[0][0]).toBe(`\x1b]0;${'✦ Working… (Custom Gemini Title)'.padEnd(80, ' ')}\x07`);
|
|
1088
1254
|
unmount();
|
|
1089
1255
|
});
|
|
1090
1256
|
});
|
|
@@ -1094,6 +1260,7 @@ describe('AppContainer State Management', () => {
|
|
|
1094
1260
|
});
|
|
1095
1261
|
afterEach(() => {
|
|
1096
1262
|
vi.useRealTimers();
|
|
1263
|
+
vi.restoreAllMocks();
|
|
1097
1264
|
});
|
|
1098
1265
|
it('should set and clear the queue error message after a timeout', async () => {
|
|
1099
1266
|
const { rerender, unmount } = renderAppContainer();
|
|
@@ -1237,6 +1404,7 @@ describe('AppContainer State Management', () => {
|
|
|
1237
1404
|
});
|
|
1238
1405
|
afterEach(() => {
|
|
1239
1406
|
vi.useRealTimers();
|
|
1407
|
+
vi.restoreAllMocks();
|
|
1240
1408
|
});
|
|
1241
1409
|
describe('CTRL+C', () => {
|
|
1242
1410
|
it('should cancel ongoing request on first press', async () => {
|
|
@@ -1337,6 +1505,7 @@ describe('AppContainer State Management', () => {
|
|
|
1337
1505
|
});
|
|
1338
1506
|
afterEach(() => {
|
|
1339
1507
|
vi.useRealTimers();
|
|
1508
|
+
vi.restoreAllMocks();
|
|
1340
1509
|
});
|
|
1341
1510
|
describe.each([
|
|
1342
1511
|
{
|
|
@@ -1547,7 +1716,9 @@ describe('AppContainer State Management', () => {
|
|
|
1547
1716
|
handler({ model: 'new-model' });
|
|
1548
1717
|
});
|
|
1549
1718
|
// Assert: Verify model is updated
|
|
1550
|
-
|
|
1719
|
+
await waitFor(() => {
|
|
1720
|
+
expect(capturedUIState.currentModel).toBe('new-model');
|
|
1721
|
+
});
|
|
1551
1722
|
unmount();
|
|
1552
1723
|
});
|
|
1553
1724
|
it('provides activeHooks from useHookDisplayState', async () => {
|
|
@@ -1652,7 +1823,9 @@ describe('AppContainer State Management', () => {
|
|
|
1652
1823
|
await act(async () => {
|
|
1653
1824
|
onCancelSubmit(true);
|
|
1654
1825
|
});
|
|
1655
|
-
|
|
1826
|
+
await waitFor(() => {
|
|
1827
|
+
expect(mockSetText).toHaveBeenCalledWith('previous message');
|
|
1828
|
+
});
|
|
1656
1829
|
unmount();
|
|
1657
1830
|
});
|
|
1658
1831
|
it('input history is independent from conversation history (survives /clear)', async () => {
|