Full Code of MayDay-wpf/snow-cli for AI

main 1c0e794663ef cached
606 files
4.4 MB
1.2M tokens
3382 symbols
1 requests
Download .txt
Showing preview only (4,963K chars total). Download the full file or copy to clipboard to get everything.
Repository: MayDay-wpf/snow-cli
Branch: main
Commit: 1c0e794663ef
Files: 606
Total size: 4.4 MB

Directory structure:
gitextract_06hmzq__/

├── .editorconfig
├── .gitattributes
├── .github/
│   └── workflows/
│       ├── build_jetbrains.yml
│       ├── build_vsix.yml
│       └── publish.yml
├── .gitignore
├── .npmrc
├── .npmrc.ci
├── .prettierignore
├── .vscode/
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── JetBrains/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   ├── gradle/
│   │   └── wrapper/
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── gradle.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── settings.gradle.kts
│   └── src/
│       └── main/
│           ├── kotlin/
│           │   ├── com/
│           │   │   └── snow/
│           │   │       └── plugin/
│           │   │           ├── SnowCodeNavigator.kt
│           │   │           ├── SnowEditorContextTracker.kt
│           │   │           ├── SnowMessageHandler.kt
│           │   │           ├── SnowPluginLifecycle.kt
│           │   │           ├── SnowProjectActivity.kt
│           │   │           ├── SnowWebSocketManager.kt
│           │   │           ├── actions/
│           │   │           │   ├── GenerateCommitMessageAction.kt
│           │   │           │   ├── OpenSnowTerminalAction.kt
│           │   │           │   ├── SendToSnowCLIAction.kt
│           │   │           │   └── TestNotificationAction.kt
│           │   │           ├── commit/
│           │   │           │   └── SnowCommitMessageGenerationService.kt
│           │   │           ├── toolwindow/
│           │   │           │   └── SnowToolWindowFactory.kt
│           │   │           └── util/
│           │   │               └── TerminalCompat.kt
│           │   └── icons/
│           │       └── SnowPluginIcons.kt
│           └── resources/
│               └── META-INF/
│                   └── plugin.xml
├── LICENSE
├── README.md
├── README_zh.md
├── VSIX/
│   ├── .vscodeignore
│   ├── LICENSE
│   ├── README.md
│   ├── package.json
│   ├── res/
│   │   ├── sidebarTerminal.css
│   │   └── sidebarTerminal.js
│   ├── src/
│   │   ├── aceHandlers.ts
│   │   ├── commitMessageGenerator.ts
│   │   ├── diffHandlers.ts
│   │   ├── extension.ts
│   │   ├── gitBlameProvider.ts
│   │   ├── ptyManager.ts
│   │   ├── sidebarTerminalProvider.ts
│   │   ├── sidebarTerminalSession.ts
│   │   ├── startupCommandManager.ts
│   │   ├── terminalPathFormatter.ts
│   │   ├── terminalProxy.ts
│   │   └── webSocketServer.ts
│   ├── tsconfig.json
│   └── webpack.config.js
├── build-ncc.mjs
├── build-shim.js
├── build.mjs
├── docs/
│   ├── role/
│   │   ├── en/
│   │   │   └── 01.Snow CLI Plan Every Step.md
│   │   └── zh/
│   │       └── 01.Snow CLI 一步一规划.md
│   └── usage/
│       ├── en/
│       │   ├── 0.Catalogue.md
│       │   ├── 01.Installation Guide.md
│       │   ├── 02.First Time Configuration.md
│       │   ├── 03.Proxy and Browser Settings.md
│       │   ├── 04.Codebase Setup.md
│       │   ├── 05.Sub-Agent Configuration.md
│       │   ├── 06.Sensitive Commands Configuration.md
│       │   ├── 07.Hooks Configuration.md
│       │   ├── 08.Theme Settings.md
│       │   ├── 09.Command Panel Guide.md
│       │   ├── 10.Command Injection Mode.md
│       │   ├── 11.Vulnerability Hunting Mode.md
│       │   ├── 12.Headless Mode.md
│       │   ├── 13.Keyboard Shortcuts Guide.md
│       │   ├── 14.MCP Configuration.md
│       │   ├── 15.Async Task Management.md
│       │   ├── 16.Third-Party Relay Configuration.md
│       │   ├── 17.LSP Configuration.md
│       │   ├── 18.Skills Command Detailed Guide.md
│       │   ├── 19.Startup Parameters Guide.md
│       │   ├── 20.SSE Service Mode.md
│       │   ├── 21.Custom StatusLine Guide.md
│       │   ├── 22.Team Mode Guide.md
│       │   └── 23.Custom Search Engine Guide.md
│       └── zh/
│           ├── 0.目录.md
│           ├── 01.安装指南.md
│           ├── 02.首次配置.md
│           ├── 03.代理和浏览器设置.md
│           ├── 04.代码库设置.md
│           ├── 05.子代理设置.md
│           ├── 06.敏感命令配置.md
│           ├── 07.Hooks配置.md
│           ├── 08.主题设置.md
│           ├── 09.指令面板说明.md
│           ├── 10.命令注入模式.md
│           ├── 11.漏洞猎人模式.md
│           ├── 12.无头模式.md
│           ├── 13.快捷键指南.md
│           ├── 14.MCP配置.md
│           ├── 15.异步任务管理.md
│           ├── 16.第三方中转配置.md
│           ├── 17.LSP配置.md
│           ├── 18.Skills指令详细说明.md
│           ├── 19.启动参数说明.md
│           ├── 20.SSE服务模式.md
│           ├── 21.自定义StatusLine指南.md
│           ├── 22.Team模式指南.md
│           └── 23.自定义搜索引擎指南.md
├── package.json
├── scripts/
│   ├── clean-build.cjs
│   └── postinstall.cjs
├── source/
│   ├── agents/
│   │   ├── bashOutputSummaryAgent.ts
│   │   ├── codebaseIndexAgent.ts
│   │   ├── codebaseReviewAgent.ts
│   │   ├── compactAgent.ts
│   │   ├── reviewAgent.ts
│   │   └── summaryAgent.ts
│   ├── api/
│   │   ├── anthropic.ts
│   │   ├── chat.ts
│   │   ├── embedding.ts
│   │   ├── gemini.ts
│   │   ├── models.ts
│   │   ├── rerank.ts
│   │   ├── responses.ts
│   │   ├── sse-server.ts
│   │   └── types.ts
│   ├── app.tsx
│   ├── cli.tsx
│   ├── hooks/
│   │   ├── conversation/
│   │   │   ├── chatLogic/
│   │   │   │   ├── types.ts
│   │   │   │   ├── useChatHandlers.ts
│   │   │   │   ├── useMessageProcessing.ts
│   │   │   │   ├── useRemoteEvents.ts
│   │   │   │   └── useRollback.ts
│   │   │   ├── core/
│   │   │   │   ├── autoCompressHandler.ts
│   │   │   │   ├── conversationSetup.ts
│   │   │   │   ├── conversationTypes.ts
│   │   │   │   ├── editorContextBuilder.ts
│   │   │   │   ├── encoderManager.ts
│   │   │   │   ├── onStopHookHandler.ts
│   │   │   │   ├── pendingMessagesHandler.ts
│   │   │   │   ├── sessionInitializer.ts
│   │   │   │   ├── streamFactory.ts
│   │   │   │   ├── streamProcessor.ts
│   │   │   │   ├── subAgentMessageHandler.ts
│   │   │   │   ├── toolCallProcessor.ts
│   │   │   │   ├── toolCallRoundHandler.ts
│   │   │   │   ├── toolConfirmationFlow.ts
│   │   │   │   ├── toolRejectionHandler.ts
│   │   │   │   └── toolResultDisplay.ts
│   │   │   ├── useChatLogic.ts
│   │   │   ├── useCommandHandler.ts
│   │   │   ├── useConversation.ts
│   │   │   ├── useStreamingState.ts
│   │   │   ├── useToolConfirmation.ts
│   │   │   └── utils/
│   │   │       ├── messageCleanup.ts
│   │   │       └── thinkingExtractor.ts
│   │   ├── execution/
│   │   │   ├── useBackgroundProcesses.ts
│   │   │   ├── useSchedulerExecutionState.ts
│   │   │   └── useTerminalExecutionState.ts
│   │   ├── input/
│   │   │   ├── keyboard/
│   │   │   │   ├── context.ts
│   │   │   │   ├── handlers/
│   │   │   │   │   ├── arrowKeys.ts
│   │   │   │   │   ├── clipboard.ts
│   │   │   │   │   ├── deleteAndBackspace.ts
│   │   │   │   │   ├── editing.ts
│   │   │   │   │   ├── escape.ts
│   │   │   │   │   ├── focusFilter.ts
│   │   │   │   │   ├── modeToggle.ts
│   │   │   │   │   ├── newline.ts
│   │   │   │   │   ├── pickers/
│   │   │   │   │   │   ├── agentPicker.ts
│   │   │   │   │   │   ├── argsPicker.ts
│   │   │   │   │   │   ├── commandPanel.ts
│   │   │   │   │   │   ├── filePicker.ts
│   │   │   │   │   │   ├── gitLinePicker.ts
│   │   │   │   │   │   ├── historyMenu.ts
│   │   │   │   │   │   ├── profilePicker.ts
│   │   │   │   │   │   ├── runningAgentsPicker.ts
│   │   │   │   │   │   ├── skillsPicker.ts
│   │   │   │   │   │   └── todoPicker.ts
│   │   │   │   │   ├── profileShortcut.ts
│   │   │   │   │   ├── regularInput.ts
│   │   │   │   │   ├── submit.ts
│   │   │   │   │   └── tabArgsPicker.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── utils/
│   │   │   │       └── wordBoundary.ts
│   │   │   ├── useBashMode.ts
│   │   │   ├── useClipboard.ts
│   │   │   ├── useHistoryNavigation.ts
│   │   │   ├── useInputBuffer.ts
│   │   │   └── useKeyboardInput.ts
│   │   ├── integration/
│   │   │   ├── useGlobalExit.ts
│   │   │   ├── useGlobalNavigation.ts
│   │   │   └── useVSCodeState.ts
│   │   ├── picker/
│   │   │   ├── useAgentPicker.ts
│   │   │   ├── useFilePicker.ts
│   │   │   ├── useGitLinePicker.ts
│   │   │   ├── useProfilePicker.ts
│   │   │   ├── useRunningAgentsPicker.ts
│   │   │   ├── useSkillsPicker.ts
│   │   │   └── useTodoPicker.ts
│   │   ├── session/
│   │   │   ├── useSessionManagement.ts
│   │   │   ├── useSessionSave.ts
│   │   │   └── useSnapshotState.ts
│   │   └── ui/
│   │       ├── useCommandPanel.ts
│   │       ├── useCursorHide.ts
│   │       ├── usePanelState.ts
│   │       ├── useTerminalFocus.ts
│   │       ├── useTerminalSize.ts
│   │       └── useTerminalTitle.ts
│   ├── i18n/
│   │   ├── I18nContext.tsx
│   │   ├── index.ts
│   │   ├── lang/
│   │   │   ├── en.ts
│   │   │   ├── zh-TW.ts
│   │   │   └── zh.ts
│   │   ├── translations.ts
│   │   └── types.ts
│   ├── mcp/
│   │   ├── aceCodeSearch.ts
│   │   ├── askUserQuestion.ts
│   │   ├── bash.ts
│   │   ├── codebaseSearch.ts
│   │   ├── engines/
│   │   │   └── websearch/
│   │   │       ├── bing.engine.ts
│   │   │       ├── duckduckgo.engine.ts
│   │   │       ├── index.ts
│   │   │       └── types.ts
│   │   ├── filesystem.ts
│   │   ├── ideDiagnostics.ts
│   │   ├── lsp/
│   │   │   ├── HybridCodeSearchService.ts
│   │   │   ├── LSPClient.ts
│   │   │   ├── LSPManager.ts
│   │   │   └── LSPServerRegistry.ts
│   │   ├── notebook.ts
│   │   ├── scheduler.ts
│   │   ├── skills.ts
│   │   ├── subagent.ts
│   │   ├── team.ts
│   │   ├── todo.ts
│   │   ├── types/
│   │   │   ├── aceCodeSearch.types.ts
│   │   │   ├── bash.types.ts
│   │   │   ├── filesystem.types.ts
│   │   │   ├── todo.types.ts
│   │   │   └── websearch.types.ts
│   │   ├── utils/
│   │   │   ├── aceCodeSearch/
│   │   │   │   ├── constants.utils.ts
│   │   │   │   ├── filesystem.utils.ts
│   │   │   │   ├── language.utils.ts
│   │   │   │   ├── search.utils.ts
│   │   │   │   └── symbol.utils.ts
│   │   │   ├── bash/
│   │   │   │   └── security.utils.ts
│   │   │   ├── filesystem/
│   │   │   │   ├── backup.utils.ts
│   │   │   │   ├── batch-operations.utils.ts
│   │   │   │   ├── code-analysis.utils.ts
│   │   │   │   ├── diagnostics.utils.ts
│   │   │   │   ├── edit-tools.utils.ts
│   │   │   │   ├── encoding.utils.ts
│   │   │   │   ├── hashline.utils.ts
│   │   │   │   ├── match-finder.utils.ts
│   │   │   │   ├── message-format.utils.ts
│   │   │   │   ├── office-parser.utils.ts
│   │   │   │   ├── path-fixer.utils.ts
│   │   │   │   ├── read-tools.utils.ts
│   │   │   │   └── similarity.utils.ts
│   │   │   ├── todo/
│   │   │   │   └── date.utils.ts
│   │   │   └── websearch/
│   │   │       ├── browser.utils.ts
│   │   │       └── text.utils.ts
│   │   └── websearch.ts
│   ├── prompt/
│   │   ├── planModeSystemPrompt.ts
│   │   ├── shared/
│   │   │   └── promptHelpers.ts
│   │   ├── systemPrompt.ts
│   │   ├── teamModeSystemPrompt.ts
│   │   └── vulnerabilityHuntingModeSystemPrompt.ts
│   ├── test/
│   │   ├── logger-test.ts
│   │   ├── rg-spawn-repro/
│   │   │   ├── rg-spawn-repro-fixed.mjs
│   │   │   └── rg-spawn-repro.mjs
│   │   └── sse-client/
│   │       ├── app.js
│   │       ├── dialogs.js
│   │       ├── index.html
│   │       ├── json-viewer.js
│   │       └── style.css
│   ├── types/
│   │   └── index.ts
│   ├── ui/
│   │   ├── components/
│   │   │   ├── bash/
│   │   │   │   ├── BackgroundProcessPanel.tsx
│   │   │   │   ├── BashCommandConfirmation.tsx
│   │   │   │   └── CustomCommandExecutionDisplay.tsx
│   │   │   ├── chat/
│   │   │   │   ├── ChatFooter.tsx
│   │   │   │   ├── ChatInput.tsx
│   │   │   │   ├── CodebaseSearchStatus.tsx
│   │   │   │   ├── LoadingIndicator.tsx
│   │   │   │   ├── MessageList.tsx
│   │   │   │   ├── MessageRenderer.tsx
│   │   │   │   ├── PendingMessages.tsx
│   │   │   │   ├── PendingToolCalls.tsx
│   │   │   │   └── UserMessagePreview.tsx
│   │   │   ├── common/
│   │   │   │   ├── MarkdownRenderer.tsx
│   │   │   │   ├── Menu.tsx
│   │   │   │   ├── PickerList.tsx
│   │   │   │   ├── ScrollableSelectInput.tsx
│   │   │   │   ├── ShimmerText.tsx
│   │   │   │   ├── StatusLine.tsx
│   │   │   │   ├── UpdateNotice.tsx
│   │   │   │   └── statusline/
│   │   │   │       ├── builtinIds.ts
│   │   │   │       ├── gitBranch.ts
│   │   │   │       ├── types.ts
│   │   │   │       └── useStatusLineHooks.ts
│   │   │   ├── compression/
│   │   │   │   └── CompressionStatus.tsx
│   │   │   ├── panels/
│   │   │   │   ├── AgentPickerPanel.tsx
│   │   │   │   ├── BranchPanel.tsx
│   │   │   │   ├── BtwPanel.tsx
│   │   │   │   ├── CommandArgsPanel.tsx
│   │   │   │   ├── CommandPanel.tsx
│   │   │   │   ├── ConnectionPanel.tsx
│   │   │   │   ├── CustomCommandConfigPanel.tsx
│   │   │   │   ├── DiffReviewPanel.tsx
│   │   │   │   ├── GitLinePickerPanel.tsx
│   │   │   │   ├── HelpPanel.tsx
│   │   │   │   ├── IdeSelectPanel.tsx
│   │   │   │   ├── MCPInfoPanel.tsx
│   │   │   │   ├── ModelsPanel.tsx
│   │   │   │   ├── NewPromptPanel.tsx
│   │   │   │   ├── PanelsManager.tsx
│   │   │   │   ├── PermissionsPanel.tsx
│   │   │   │   ├── ProfileEditPanel.tsx
│   │   │   │   ├── ProfilePanel.tsx
│   │   │   │   ├── ReviewCommitPanel.tsx
│   │   │   │   ├── RoleCreationPanel.tsx
│   │   │   │   ├── RoleDeletionPanel.tsx
│   │   │   │   ├── RoleListPanel.tsx
│   │   │   │   ├── RoleSubagentCreationPanel.tsx
│   │   │   │   ├── RoleSubagentDeletionPanel.tsx
│   │   │   │   ├── RoleSubagentListPanel.tsx
│   │   │   │   ├── RollbackMenuPanel.tsx
│   │   │   │   ├── RunningAgentsPanel.tsx
│   │   │   │   ├── SessionListPanel.tsx
│   │   │   │   ├── SkillsCreationPanel.tsx
│   │   │   │   ├── SkillsListPanel.tsx
│   │   │   │   ├── SkillsPickerPanel.tsx
│   │   │   │   ├── SubAgentDepthPanel.tsx
│   │   │   │   ├── TodoListPanel.tsx
│   │   │   │   ├── TodoPickerPanel.tsx
│   │   │   │   ├── UsagePanel.tsx
│   │   │   │   └── WorkingDirectoryPanel.tsx
│   │   │   ├── pixel-editor/
│   │   │   │   ├── PixelEditor.tsx
│   │   │   │   ├── index.ts
│   │   │   │   └── types.ts
│   │   │   ├── scheduler/
│   │   │   │   └── SchedulerCountdown.tsx
│   │   │   ├── special/
│   │   │   │   ├── AskUserQuestion.tsx
│   │   │   │   ├── ChatHeader.tsx
│   │   │   │   ├── HookErrorDisplay.tsx
│   │   │   │   └── TodoTree.tsx
│   │   │   ├── sse/
│   │   │   │   └── SSEServerStatus.tsx
│   │   │   └── tools/
│   │   │       ├── DiffViewer.tsx
│   │   │       ├── FileList.tsx
│   │   │       ├── FileRollbackConfirmation.tsx
│   │   │       ├── ToolConfirmation.tsx
│   │   │       └── ToolResultPreview.tsx
│   │   ├── contexts/
│   │   │   └── ThemeContext.tsx
│   │   ├── pages/
│   │   │   ├── ChatScreen.tsx
│   │   │   ├── CodeBaseConfigScreen.tsx
│   │   │   ├── ConfigScreen.tsx
│   │   │   ├── CustomHeadersScreen.tsx
│   │   │   ├── CustomThemeScreen.tsx
│   │   │   ├── ExitScreen.tsx
│   │   │   ├── HeadlessModeScreen.tsx
│   │   │   ├── HelpScreen.tsx
│   │   │   ├── HooksConfigScreen.tsx
│   │   │   ├── LanguageSettingsScreen.tsx
│   │   │   ├── MCPConfigScreen.tsx
│   │   │   ├── PixelEditorScreen.tsx
│   │   │   ├── ProxyConfigScreen.tsx
│   │   │   ├── SensitiveCommandConfigScreen.tsx
│   │   │   ├── SubAgentConfigScreen.tsx
│   │   │   ├── SubAgentListScreen.tsx
│   │   │   ├── SystemPromptConfigScreen.tsx
│   │   │   ├── TaskManagerScreen.tsx
│   │   │   ├── ThemeSettingsScreen.tsx
│   │   │   ├── WelcomeScreen.tsx
│   │   │   ├── chatScreen/
│   │   │   │   ├── ChatScreenConversationView.tsx
│   │   │   │   ├── ChatScreenPanels.tsx
│   │   │   │   ├── types.ts
│   │   │   │   ├── useBackgroundProcessSelection.ts
│   │   │   │   ├── useChatScreenCommands.ts
│   │   │   │   ├── useChatScreenInputHandler.ts
│   │   │   │   ├── useChatScreenLocalState.ts
│   │   │   │   ├── useChatScreenModes.ts
│   │   │   │   ├── useChatScreenSessionLifecycle.ts
│   │   │   │   └── useCodebaseIndexing.ts
│   │   │   └── configScreen/
│   │   │       ├── ConfigFieldRenderer.tsx
│   │   │       ├── ConfigSelectPanel.tsx
│   │   │       ├── ConfigSubViews.tsx
│   │   │       ├── types.ts
│   │   │       ├── useConfigInput.ts
│   │   │       └── useConfigState.ts
│   │   └── themes/
│   │       └── index.ts
│   ├── utils/
│   │   ├── acp/
│   │   │   └── acpManager.ts
│   │   ├── codebase/
│   │   │   ├── codebaseDatabase.ts
│   │   │   ├── codebaseSearchEvents.ts
│   │   │   ├── conversationContext.ts
│   │   │   ├── gitignoreValidator.ts
│   │   │   ├── hashBasedSnapshot.ts
│   │   │   └── reindexCodebase.ts
│   │   ├── commands/
│   │   │   ├── addDir.ts
│   │   │   ├── agent.ts
│   │   │   ├── autoformat.ts
│   │   │   ├── backend.ts
│   │   │   ├── branch.ts
│   │   │   ├── btw.ts
│   │   │   ├── btwStream.ts
│   │   │   ├── clear.ts
│   │   │   ├── codebase.ts
│   │   │   ├── compact.ts
│   │   │   ├── connect.ts
│   │   │   ├── copyLast.ts
│   │   │   ├── custom.ts
│   │   │   ├── deepresearch.ts
│   │   │   ├── diff.ts
│   │   │   ├── export.ts
│   │   │   ├── gitline.ts
│   │   │   ├── help.ts
│   │   │   ├── home.ts
│   │   │   ├── hybridCompress.ts
│   │   │   ├── ide.ts
│   │   │   ├── init.ts
│   │   │   ├── loop.ts
│   │   │   ├── mcp.ts
│   │   │   ├── models.ts
│   │   │   ├── newPrompt.ts
│   │   │   ├── permissions.ts
│   │   │   ├── pixel.ts
│   │   │   ├── plan.ts
│   │   │   ├── profiles.ts
│   │   │   ├── quit.ts
│   │   │   ├── reindex.ts
│   │   │   ├── resume.ts
│   │   │   ├── review.ts
│   │   │   ├── role.ts
│   │   │   ├── roleSubagent.ts
│   │   │   ├── simple.ts
│   │   │   ├── skills.ts
│   │   │   ├── skillsPicker.ts
│   │   │   ├── subagentDepth.ts
│   │   │   ├── team.ts
│   │   │   ├── todoPicker.ts
│   │   │   ├── todolist.ts
│   │   │   ├── toolsearch.ts
│   │   │   ├── usage.ts
│   │   │   ├── vulnerability-hunting.ts
│   │   │   ├── worktree.ts
│   │   │   └── yolo.ts
│   │   ├── config/
│   │   │   ├── apiConfig.ts
│   │   │   ├── codebaseConfig.ts
│   │   │   ├── configEvents.ts
│   │   │   ├── configManager.ts
│   │   │   ├── disabledBuiltInTools.ts
│   │   │   ├── disabledMCPTools.ts
│   │   │   ├── disabledSkills.ts
│   │   │   ├── hooksConfig.ts
│   │   │   ├── languageConfig.ts
│   │   │   ├── permissionsConfig.ts
│   │   │   ├── projectSettings.ts
│   │   │   ├── proxyConfig.ts
│   │   │   ├── subAgentConfig.ts
│   │   │   ├── themeConfig.ts
│   │   │   ├── toolDisplayConfig.ts
│   │   │   └── workingDirConfig.ts
│   │   ├── connection/
│   │   │   ├── ConnectionManager.ts
│   │   │   ├── configStore.ts
│   │   │   ├── contextManager.ts
│   │   │   ├── instanceLock.ts
│   │   │   ├── interactionManager.ts
│   │   │   ├── projectData.ts
│   │   │   ├── stateManager.ts
│   │   │   └── types.ts
│   │   ├── core/
│   │   │   ├── autoCompress.ts
│   │   │   ├── clipboard.ts
│   │   │   ├── compressionCoordinator.ts
│   │   │   ├── contextCompressor.ts
│   │   │   ├── devMode.ts
│   │   │   ├── fileUtils.ts
│   │   │   ├── globalCleanup.ts
│   │   │   ├── logger.ts
│   │   │   ├── notebookManager.ts
│   │   │   ├── processManager.ts
│   │   │   ├── proxyUtils.ts
│   │   │   ├── resourceMonitor.ts
│   │   │   ├── retryUtils.ts
│   │   │   ├── runUpdate.ts
│   │   │   ├── streamGuards.ts
│   │   │   ├── subAgentContextCompressor.ts
│   │   │   ├── textUtils.ts
│   │   │   ├── todoPreprocessor.ts
│   │   │   ├── todoScanner.ts
│   │   │   ├── usageLogger.ts
│   │   │   └── version.ts
│   │   ├── events/
│   │   │   └── todoEvents.ts
│   │   ├── execution/
│   │   │   ├── commandExecutor.ts
│   │   │   ├── hookResultInterpreter.ts
│   │   │   ├── hookStrategies.ts
│   │   │   ├── mcpToolsManager.ts
│   │   │   ├── runningSubAgentTracker.ts
│   │   │   ├── sensitiveCommandManager.ts
│   │   │   ├── subAgentBuiltinTools.ts
│   │   │   ├── subAgentExecutor.ts
│   │   │   ├── subAgentResolver.ts
│   │   │   ├── subAgentStreamProcessor.ts
│   │   │   ├── subAgentToolApproval.ts
│   │   │   ├── subAgentToolInterceptor.ts
│   │   │   ├── subAgentTypes.ts
│   │   │   ├── subagents/
│   │   │   │   ├── analyzeAgent.ts
│   │   │   │   ├── debugAgent.ts
│   │   │   │   ├── exploreAgent.ts
│   │   │   │   ├── generalAgent.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── planAgent.ts
│   │   │   │   ├── qaAgent.ts
│   │   │   │   └── types.ts
│   │   │   ├── teamExecutor.ts
│   │   │   ├── teamTracker.ts
│   │   │   ├── terminal.ts
│   │   │   ├── tokenLimiter.ts
│   │   │   ├── toolExecutor.ts
│   │   │   ├── toolSearchService.ts
│   │   │   ├── unifiedHooksExecutor.ts
│   │   │   └── yoloPermissionChecker.ts
│   │   ├── index.ts
│   │   ├── latex/
│   │   │   └── unicodeMath.ts
│   │   ├── session/
│   │   │   ├── chatExporter.ts
│   │   │   ├── checkpointManager.ts
│   │   │   ├── commandUsageManager.ts
│   │   │   ├── historyManager.ts
│   │   │   ├── projectUtils.ts
│   │   │   ├── sessionConverter.ts
│   │   │   └── sessionManager.ts
│   │   ├── sse/
│   │   │   ├── daemonLogger.ts
│   │   │   ├── sseDaemon.ts
│   │   │   └── sseManager.ts
│   │   ├── ssh/
│   │   │   └── sshClient.ts
│   │   ├── task/
│   │   │   ├── loopManager.ts
│   │   │   ├── taskExecutor.ts
│   │   │   └── taskManager.ts
│   │   ├── team/
│   │   │   ├── teamConfig.ts
│   │   │   ├── teamSnapshot.ts
│   │   │   ├── teamTaskList.ts
│   │   │   └── teamWorktree.ts
│   │   └── ui/
│   │       ├── escapeHandler.ts
│   │       ├── externalEditor.ts
│   │       ├── fileDialog.ts
│   │       ├── messageFormatter.ts
│   │       ├── pickerState.ts
│   │       ├── skillMask.ts
│   │       ├── textBuffer.ts
│   │       ├── updateNotice.ts
│   │       ├── userInteractionError.ts
│   │       └── vscodeConnection.ts
│   └── vendor/
│       └── ink/
│           ├── license
│           ├── package.json
│           └── src/
│               ├── colorize.ts
│               ├── components/
│               │   ├── App.tsx
│               │   ├── AppContext.ts
│               │   ├── Box.tsx
│               │   ├── CursorContext.ts
│               │   ├── ErrorOverview.tsx
│               │   ├── FocusContext.ts
│               │   ├── Newline.tsx
│               │   ├── Spacer.tsx
│               │   ├── Static.tsx
│               │   ├── StderrContext.ts
│               │   ├── StdinContext.ts
│               │   ├── StdoutContext.ts
│               │   ├── Text.tsx
│               │   └── Transform.tsx
│               ├── cursor-helpers.ts
│               ├── devtools-window-polyfill.ts
│               ├── devtools.ts
│               ├── dom.ts
│               ├── get-max-width.ts
│               ├── global.d.ts
│               ├── hooks/
│               │   ├── use-app.ts
│               │   ├── use-cursor.ts
│               │   ├── use-focus-manager.ts
│               │   ├── use-focus.ts
│               │   ├── use-input.ts
│               │   ├── use-stderr.ts
│               │   ├── use-stdin.ts
│               │   └── use-stdout.ts
│               ├── index.ts
│               ├── ink.tsx
│               ├── instances.ts
│               ├── line-width-cache.ts
│               ├── log-update.ts
│               ├── measure-element.ts
│               ├── measure-text.ts
│               ├── output.ts
│               ├── parse-keypress.ts
│               ├── reconciler.ts
│               ├── render-border.ts
│               ├── render-node-to-output.ts
│               ├── render.ts
│               ├── renderer.ts
│               ├── squash-text-nodes.ts
│               ├── styles.ts
│               ├── vendor-types.d.ts
│               ├── wrap-text.ts
│               ├── yoga-compat.ts
│               └── yoga-ts/
│                   ├── enums.ts
│                   └── index.ts
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.yml]
indent_style = space
indent_size = 2


================================================
FILE: .gitattributes
================================================
* text=auto eol=lf


================================================
FILE: .github/workflows/build_jetbrains.yml
================================================
name: Build JetBrains Plugin

on:
  push:
    paths:
      - '.github/workflows/build_jetbrains.yml'
      - 'JetBrains/**'
      - '!JetBrains/**.md'
      - '!JetBrains/.gitignore'
    branches:
      - '*'
    tags:
      - 'v*'
  workflow_dispatch:
    inputs:
      version:
        description: 'Version to publish (e.g., 1.0.0)'
        required: true
        type: string

permissions:
  contents: write
  packages: write

jobs:
  publish:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: JetBrains
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Setup Java
        uses: actions/setup-java@v5
        with:
          distribution: zulu
          java-version: 21

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v5
        with:
          cache-read-only: false
          gradle-version: wrapper

      - name: Update version (manual trigger)
        if: github.event_name == 'workflow_dispatch'
        run: |
          VERSION="${{ github.event.inputs.version }}"
          echo "Updating version to ${VERSION}"
          sed -i "s/^version = .*/version = \"${VERSION}\"/" build.gradle.kts
          sed -i "s/^pluginVersion = .*/pluginVersion = ${VERSION}/" gradle.properties

      - name: Get version
        run: |
          echo "PLUGIN_VERSION=$(grep '^version =' build.gradle.kts | cut -d'"' -f2)" >> $GITHUB_ENV

      - name: Build and Publish Plugin
        # env:
        # PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
        # CERTIFICATE_CHAIN: ${{ secrets.CERTIFICATE_CHAIN }}
        # PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
        # PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }}
        run: |
          ./gradlew buildPlugin
          ./gradlew verifyPlugin
          # ./gradlew publishPlugin

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: jetbrains
          files: JetBrains/build/distributions/snow-cli-jetbrains-${{ env.PLUGIN_VERSION }}.zip
          name: Release JetBrains plugin
          body: |
            ## 🚀 Snow CLI JetBrains plugin 
            Latest release version: `v${{ env.PLUGIN_VERSION }}`

            ### What's New

            - Add AI-generated git commit message feature

            ### Usage

            JetBrains IDE plugin for integrating with Snow AI CLI. Provides intelligent code navigation and search powered by AI, with support for IntelliJ IDEA, PyCharm, WebStorm, and other JetBrains IDEs.

            ### Features

            - **WebSocket Integration**: Real-time bi-directional communication with Snow CLI
            - **Editor Context Tracking**: Automatically sends active file, cursor position, and selected text to Snow CLI
            - **Code Diagnostics**: Retrieves and shares code diagnostics with the AI
            - **Go to Definition**: Navigate to symbol definitions via Snow CLI
            - **Find References**: Find all references to symbols across the project
            - **Document Symbols**: Extract and share document structure with the AI
            - **Auto-Reconnection**: Robust reconnection with exponential backoff strategy
            - **Terminal Integration**: Quick access to Snow CLI from the toolbar
          draft: false
          prerelease: false


================================================
FILE: .github/workflows/build_vsix.yml
================================================
name: Build VSIX Package

on:
  push:
    paths:
      - '.github/workflows/build_vsix.yml'
      - 'VSIX/**'
      - 'VSIX/**.vsix'
      - '!VSIX/**.md'
      - '!VSIX/LICENSE'
      - '!VSIX/.vscodeignore'
    branches:
      - '*'
    tags:
      - 'v*'
  workflow_dispatch:
    inputs:
      version:
        description: 'Version to publish (e.g., 1.0.0)'
        required: true
        type: string

permissions:
  contents: write
  packages: write

jobs:
  publish:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: VSIX
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: '20'
          registry-url: 'https://registry.npmjs.org/'

      - name: Update version (manual trigger)
        if: github.event_name == 'workflow_dispatch'
        run: npm version ${{ github.event.inputs.version }} --no-git-tag-version

      - name: Get package version
        run: |
          echo "PACKAGE_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV

      - name: Install dependencies
        run: npm install

      - name: Build project
        run: npx -y @vscode/vsce package

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: vsix-v${{ env.PACKAGE_VERSION }}
          files: VSIX/snow-cli-${{ env.PACKAGE_VERSION }}.vsix
          name: VSCode Extension v${{ env.PACKAGE_VERSION }}
          body: |
            ## 🚀 Snow CLI VSCode Extension v${{ env.PACKAGE_VERSION }}

            ### What's New

            - Fix the problem of not being able to trigger the system ringtone and add relevant settings

            ### Installation

            1. Download the `.vsix` file from this release
            2. Open VSCode
            3. Go to Extensions view (Ctrl+Shift+X)
            4. Click the "..." menu → "Install from VSIX..."
            5. Select the downloaded file

            ### Requirements

            Install Snow CLI globally:

            ```bash
            npm install -g snow-ai
            ```

            ### Usage

            1. Open any file in VSCode
            2. Click the **Snow icon** button in the editor toolbar (top right)
            3. A terminal opens with Snow CLI running
            4. The extension automatically connects via WebSocket

            ### Features

            - Integrated terminal with Snow CLI
            - WebSocket-based communication
            - ACE Code Search integration
            - Sidebar and split terminal modes
          draft: false
          prerelease: false
          fail_on_unmatched_files: true
          make_latest: true


================================================
FILE: .github/workflows/publish.yml
================================================
name: Publish to NPM

on:
  push:
    tags:
      - 'v*'
  workflow_dispatch:
    inputs:
      version:
        description: 'Version to publish (e.g., 1.0.0)'
        required: true
        type: string

permissions:
  contents: write
  packages: write

jobs:
  publish:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: '22'
          registry-url: 'https://registry.npmjs.org/'

      - name: Use CI npm config
        run: cp .npmrc.ci .npmrc

      - name: Install dependencies
        run: npm install

      - name: Build project
        run: npm run build

      - name: Publish to NPM
        run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: Create GitHub Release
        if: github.event_name == 'push'
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ github.ref_name }}
          name: Release ${{ github.ref_name }}
          body: |
            ## Snow CLI ${{ github.ref_name }}

            ### What's New

            - Add the /simple command to quickly switch to the simple theme
            - Add search engine plugins to support more custom search engines
            
            ### Installation
            ```bash
            npm install -g snow-ai
            ```

            ### Usage
            ```bash
            snow
            ```
            ### Update
            ```bash
            snow --update
            ```
          draft: false
          prerelease: false


================================================
FILE: .gitignore
================================================
node_modules
dist
bundle
out
.snow
AGENTS.md
pr.md
CHANGELOG.md
CONTEXT.md
ROLE*.md
.venv
.idea


================================================
FILE: .npmrc
================================================
# 保持对等依赖兼容性
legacy-peer-deps=true

# 安装速度优化配置
# 使用 npm 镜像源(中国大陆用户)
registry=https://registry.npmmirror.com

# 并行安装配置
fetch-retries=3
fetch-retry-mintimeout=10000
fetch-retry-maxtimeout=60000

# 网络超时设置(使用 fetch-timeout 替代已废弃的 network-timeout)
fetch-timeout=300000

# 缓存配置优化
prefer-offline=true
audit=false
fund=false

# 并行下载数(提升安装速度)
maxsockets=10


================================================
FILE: .npmrc.ci
================================================
# CI 环境专用配置
# 必须使用官方 npm registry 才能发布

# 保持对等依赖兼容性
legacy-peer-deps=true

# 使用官方 npm registry
registry=https://registry.npmjs.org

# 并行安装配置
fetch-retries=3
fetch-retry-mintimeout=10000
fetch-retry-maxtimeout=60000

# 网络超时设置
fetch-timeout=300000

# 缓存配置优化
prefer-offline=false
audit=false
fund=false

# 并行下载数
maxsockets=10


================================================
FILE: .prettierignore
================================================
dist


================================================
FILE: .vscode/launch.json
================================================
{
	"version": "0.2.0",
	"configurations": [
		{
			"name": "Debug CLI (ts-node)",
			"type": "node",
			"request": "launch",
			"runtimeExecutable": "node",
			"runtimeArgs": ["--loader", "ts-node/esm"],
			"args": ["${workspaceFolder}/source/cli.tsx"],
			"cwd": "${workspaceFolder}",
			"console": "integratedTerminal",
			"internalConsoleOptions": "neverOpen",
			"skipFiles": ["<node_internals>/**"],
			"env": {
				"TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json"
			}
		},
		{
			"name": "Debug CLI (built)",
			"type": "node",
			"request": "launch",
			"program": "${workspaceFolder}/bundle/cli.mjs",
			"cwd": "${workspaceFolder}",
			"console": "integratedTerminal",
			"internalConsoleOptions": "neverOpen",
			"preLaunchTask": "npm: build",
			"skipFiles": ["<node_internals>/**"]
		},
		{
			"name": "Debug Current File (ts-node)",
			"type": "node",
			"request": "launch",
			"runtimeArgs": ["--loader", "ts-node/esm"],
			"args": ["${relativeFile}"],
			"cwd": "${workspaceFolder}",
			"console": "integratedTerminal",
			"internalConsoleOptions": "neverOpen",
			"skipFiles": ["<node_internals>/**"],
			"env": {
				"TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json"
			}
		}
	]
}


================================================
FILE: .vscode/settings.json
================================================
{}

================================================
FILE: .vscode/tasks.json
================================================
{
	"version": "2.0.0",
	"tasks": [
		{
			"label": "npm: build",
			"type": "npm",
			"script": "build",
			"group": "build",
			"problemMatcher": ["$tsc"],
			"detail": "Build the project"
		},
		{
			"label": "npm: dev",
			"type": "npm",
			"script": "dev",
			"group": "build",
			"isBackground": true,
			"problemMatcher": ["$tsc-watch"],
			"detail": "Watch TypeScript files for changes"
		},
		{
			"label": "TypeScript: Watch",
			"type": "shell",
			"command": "npx tsc --watch",
			"group": "build",
			"isBackground": true,
			"problemMatcher": ["$tsc-watch"]
		}
	]
}


================================================
FILE: JetBrains/.gitignore
================================================
# Gradle
.gradle/
build/
!gradle/
!gradle/wrapper/
!gradle/wrapper/gradle-wrapper.jar
!gradle/wrapper/gradle-wrapper.properties

# IntelliJ IDEA
.idea/
*.iml
*.iws
*.ipr
out/

# Build output
dist/

# OS
.DS_Store
Thumbs.db

# Logs
*.log

# Plugin build artifacts
*.zip


================================================
FILE: JetBrains/README.md
================================================
# Snow CLI JetBrains Plugin

JetBrains IDE plugin for integrating with Snow AI CLI. Provides intelligent code navigation and search powered by AI, with support for IntelliJ IDEA, PyCharm, WebStorm, and other JetBrains IDEs.

## Features

- **WebSocket Integration**: Real-time bi-directional communication with Snow CLI
- **Editor Context Tracking**: Automatically sends active file, cursor position, and selected text to Snow CLI
- **Code Diagnostics**: Retrieves and shares code diagnostics with the AI
- **Go to Definition**: Navigate to symbol definitions via Snow CLI
- **Find References**: Find all references to symbols across the project
- **Document Symbols**: Extract and share document structure with the AI
- **Auto-Reconnection**: Robust reconnection with exponential backoff strategy
- **Terminal Integration**: Quick access to Snow CLI from the toolbar

## Recommended Terminal for Windows Users

For the best experience on Windows, we recommend:

- **PowerShell 7+**: Modern cross-platform PowerShell with enhanced features and compatibility
  - GitHub: https://github.com/PowerShell/PowerShell
- **Windows Terminal**: Modern terminal application with tabs, panes, and GPU-accelerated rendering
  - GitHub: https://github.com/microsoft/terminal

**Installation**:

```bash
# Install via winget (built-in on Windows 10/11)
winget install Microsoft.PowerShell
winget install Microsoft.WindowsTerminal

# Or install from Microsoft Store
```


================================================
FILE: JetBrains/build.gradle.kts
================================================
plugins {
    id("java")
    id("org.jetbrains.kotlin.jvm") version "1.9.21"
    id("org.jetbrains.intellij") version "1.16.1"
}

group = "com.snow"
version = "0.4.21"

repositories {
    mavenCentral()
}

// Configure Gradle IntelliJ Plugin
intellij {
    version.set("2024.1")
    type.set("IC") // Target IDE Platform (IC = IntelliJ IDEA Community)

    plugins.set(listOf("org.jetbrains.plugins.terminal"))
}

tasks {
    // Set the JVM compatibility versions
    withType<JavaCompile> {
        sourceCompatibility = "17"
        targetCompatibility = "17"
    }

    withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
        kotlinOptions.jvmTarget = "17"
    }

    patchPluginXml {
        sinceBuild.set("241")
        untilBuild.set("261.*")
    }

    signPlugin {
        certificateChain.set(System.getenv("CERTIFICATE_CHAIN"))
        privateKey.set(System.getenv("PRIVATE_KEY"))
        password.set(System.getenv("PRIVATE_KEY_PASSWORD"))
    }

    publishPlugin {
        token.set(System.getenv("PUBLISH_TOKEN"))
    }

    // Skip instrumentCode task to avoid JDK path issues
    instrumentCode {
        enabled = false
    }

    // Skip buildSearchableOptions to avoid coroutines-javaagent issues
    buildSearchableOptions {
        enabled = false
    }
}

dependencies {
    implementation("org.java-websocket:Java-WebSocket:1.5.4")
    implementation("org.json:json:20231013")
}


================================================
FILE: JetBrains/gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
networkTimeout=60000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists


================================================
FILE: JetBrains/gradle.properties
================================================
# IntelliJ Platform Artifacts Repositories -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html

pluginGroup = com.snow
pluginName = Snow CLI
pluginRepositoryUrl = https://github.com/yourusername/snow-cli

# SemVer format -> https://semver.org
pluginVersion = 0.4.5

# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
pluginSinceBuild = 241
pluginUntilBuild = 253.*

# IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension
platformType = IC
platformVersion = 2024.1

# Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html
# Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22
platformPlugins =

# Gradle Releases -> https://github.com/gradle/gradle/releases
gradleVersion = 8.4

# Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib
kotlin.stdlib.default.dependency = false

# Enable Gradle Configuration Cache -> https://docs.gradle.org/current/userguide/configuration_cache.html
org.gradle.configuration-cache = true

# Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html
org.gradle.caching = true

# Enable Gradle Kotlin DSL Lazy Property Assignment -> https://docs.gradle.org/current/userguide/kotlin_dsl.html#kotdsl:assignment
systemProp.org.gradle.unsafe.kotlin.assignment = true


================================================
FILE: JetBrains/gradlew
================================================
#!/bin/sh

#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

##############################################################################
#
#   Gradle start up script for POSIX generated by Gradle.
#
#   Important for running:
#
#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
#       noncompliant, but you have some other compliant shell such as ksh or
#       bash, then to run this script, type that shell name before the whole
#       command line, like:
#
#           ksh Gradle
#
#       Busybox and similar reduced shells will NOT work, because this script
#       requires all of these POSIX shell features:
#         * functions;
#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
#         * compound commands having a testable exit status, especially «case»;
#         * various built-in commands including «command», «set», and «ulimit».
#
#   Important for patching:
#
#   (2) This script targets any POSIX shell, so it avoids extensions provided
#       by Bash, Ksh, etc; in particular arrays are avoided.
#
#       The "traditional" practice of packing multiple parameters into a
#       space-separated string is a well documented source of bugs and security
#       problems, so this is (mostly) avoided, by progressively accumulating
#       options in "$@", and eventually passing that to Java.
#
#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
#       see the in-line comments for details.
#
#       There are tweaks for specific operating systems such as AIX, CygWin,
#       Darwin, MinGW, and NonStop.
#
#   (3) This script is generated from the Groovy template
#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
#       within the Gradle project.
#
#       You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################

# Attempt to set APP_HOME

# Resolve links: $0 may be a link
app_path=$0

# Need this for daisy-chained symlinks.
while
    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
    [ -h "$app_path" ]
do
    ls=$( ls -ld "$app_path" )
    link=${ls#*' -> '}
    case $link in             #(
      /*)   app_path=$link ;; #(
      *)    app_path=$APP_HOME$link ;;
    esac
done

# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

warn () {
    echo "$*"
} >&2

die () {
    echo
    echo "$*"
    echo
    exit 1
} >&2

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in                #(
  CYGWIN* )         cygwin=true  ;; #(
  Darwin* )         darwin=true  ;; #(
  MSYS* | MINGW* )  msys=true    ;; #(
  NONSTOP* )        nonstop=true ;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar


# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD=$JAVA_HOME/jre/sh/java
    else
        JAVACMD=$JAVA_HOME/bin/java
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD=java
    if ! command -v java >/dev/null 2>&1
    then
        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
fi

# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
    case $MAX_FD in #(
      max*)
        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
        # shellcheck disable=SC3045
        MAX_FD=$( ulimit -H -n ) ||
            warn "Could not query maximum file descriptor limit"
    esac
    case $MAX_FD in  #(
      '' | soft) :;; #(
      *)
        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
        # shellcheck disable=SC3045
        ulimit -n "$MAX_FD" ||
            warn "Could not set maximum file descriptor limit to $MAX_FD"
    esac
fi

# Collect all arguments for the java command, stacking in reverse order:
#   * args from the command line
#   * the main class name
#   * -classpath
#   * -D...appname settings
#   * --module-path (only if needed)
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.

# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )

    JAVACMD=$( cygpath --unix "$JAVACMD" )

    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    for arg do
        if
            case $arg in                                #(
              -*)   false ;;                            # don't mess with options #(
              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
                    [ -e "$t" ] ;;                      #(
              *)    false ;;
            esac
        then
            arg=$( cygpath --path --ignore --mixed "$arg" )
        fi
        # Roll the args list around exactly as many times as the number of
        # args, so each arg winds up back in the position where it started, but
        # possibly modified.
        #
        # NB: a `for` loop captures its iteration list before it begins, so
        # changing the positional parameters here affects neither the number of
        # iterations, nor the values presented in `arg`.
        shift                   # remove old arg
        set -- "$@" "$arg"      # push replacement arg
    done
fi


# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Collect all arguments for the java command:
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
#     and any embedded shellness will be escaped.
#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
#     treated as '${Hostname}' itself on the command line.

set -- \
        "-Dorg.gradle.appname=$APP_BASE_NAME" \
        -classpath "$CLASSPATH" \
        org.gradle.wrapper.GradleWrapperMain \
        "$@"

# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
    die "xargs is not available"
fi

# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
#   set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#

eval "set -- $(
        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
        xargs -n1 |
        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
        tr '\n' ' '
    )" '"$@"'

exec "$JAVACMD" "$@"


================================================
FILE: JetBrains/gradlew.bat
================================================
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem      https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem

@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto execute

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar


@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*

:end
@rem End local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" endlocal

:omega
@exit /b %ERRORLEVEL%

:fail
@exit /b 1


================================================
FILE: JetBrains/settings.gradle.kts
================================================
rootProject.name = "snow-cli-jetbrains"


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/SnowCodeNavigator.kt
================================================
package com.snow.plugin

import com.intellij.openapi.editor.LogicalPosition
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiManager
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNamedElement
import com.intellij.psi.PsiFile
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorFactory

/**
 * Handles code navigation features (go to definition, find references, get symbols)
 */
class SnowCodeNavigator(private val project: Project) {

    /**
     * Go to definition at specified location
     */
    fun goToDefinition(filePath: String, line: Int, column: Int): List<Map<String, Any?>> {
        val file = VirtualFileManager.getInstance().findFileByUrl("file://$filePath") ?: return emptyList()
        val psiFile = PsiManager.getInstance(project).findFile(file) ?: return emptyList()
        val document = PsiDocumentManager.getInstance(project).getDocument(psiFile) ?: return emptyList()

        if (line >= document.lineCount) return emptyList()

        val offset = document.getLineStartOffset(line) + column
        val element = psiFile.findElementAt(offset) ?: return emptyList()

        // Navigate to declaration
        val references = element.references
        val definitions = mutableListOf<Map<String, Any?>>()

        for (reference in references) {
            val resolved = reference.resolve() ?: continue
            val containingFile = resolved.containingFile?.virtualFile ?: continue
            val doc = PsiDocumentManager.getInstance(project).getDocument(resolved.containingFile) ?: continue
            val textRange = resolved.textRange

            definitions.add(
                mapOf(
                    "filePath" to containingFile.path,
                    "line" to doc.getLineNumber(textRange.startOffset),
                    "column" to textRange.startOffset - doc.getLineStartOffset(doc.getLineNumber(textRange.startOffset)),
                    "endLine" to doc.getLineNumber(textRange.endOffset),
                    "endColumn" to textRange.endOffset - doc.getLineStartOffset(doc.getLineNumber(textRange.endOffset))
                )
            )
        }

        return definitions
    }

    /**
     * Find all references to element at specified location
     */
    fun findReferences(filePath: String, line: Int, column: Int): List<Map<String, Any?>> {
        val file = VirtualFileManager.getInstance().findFileByUrl("file://$filePath") ?: return emptyList()
        val psiFile = PsiManager.getInstance(project).findFile(file) ?: return emptyList()
        val document = PsiDocumentManager.getInstance(project).getDocument(psiFile) ?: return emptyList()

        if (line >= document.lineCount) return emptyList()

        val offset = document.getLineStartOffset(line) + column
        val element = psiFile.findElementAt(offset) ?: return emptyList()

        // Find the parent named element
        val namedElement = PsiTreeUtil.getParentOfType(element, PsiNamedElement::class.java) ?: return emptyList()

        // Search for references
        val references = ReferencesSearch.search(namedElement, namedElement.useScope).findAll()
        val results = mutableListOf<Map<String, Any?>>()

        for (reference in references) {
            val refElement = reference.element
            val refFile = refElement.containingFile?.virtualFile ?: continue
            val refDoc = PsiDocumentManager.getInstance(project).getDocument(refElement.containingFile) ?: continue
            val textRange = refElement.textRange

            results.add(
                mapOf(
                    "filePath" to refFile.path,
                    "line" to refDoc.getLineNumber(textRange.startOffset),
                    "column" to textRange.startOffset - refDoc.getLineStartOffset(refDoc.getLineNumber(textRange.startOffset)),
                    "endLine" to refDoc.getLineNumber(textRange.endOffset),
                    "endColumn" to textRange.endOffset - refDoc.getLineStartOffset(refDoc.getLineNumber(textRange.endOffset))
                )
            )
        }

        return results
    }

    /**
     * Get all symbols in the file
     */
    fun getSymbols(filePath: String): List<Map<String, Any?>> {
        val file = VirtualFileManager.getInstance().findFileByUrl("file://$filePath") ?: return emptyList()
        val psiFile = PsiManager.getInstance(project).findFile(file) ?: return emptyList()
        val document = PsiDocumentManager.getInstance(project).getDocument(psiFile) ?: return emptyList()

        val symbols = mutableListOf<Map<String, Any?>>()

        // Recursively collect named elements
        fun collectSymbols(element: PsiElement) {
            if (element is PsiNamedElement && element.name != null) {
                val textRange = element.textRange
                val startLine = document.getLineNumber(textRange.startOffset)
                val endLine = document.getLineNumber(textRange.endOffset)

                symbols.add(
                    mapOf(
                        "name" to element.name,
                        "kind" to getSymbolKind(element),
                        "line" to startLine,
                        "column" to textRange.startOffset - document.getLineStartOffset(startLine),
                        "endLine" to endLine,
                        "endColumn" to textRange.endOffset - document.getLineStartOffset(endLine),
                        "detail" to (element.text.take(50) + if (element.text.length > 50) "..." else "")
                    )
                )
            }

            for (child in element.children) {
                collectSymbols(child)
            }
        }

        collectSymbols(psiFile)
        return symbols
    }

    /**
     * Get symbol kind from PSI element type
     */
    private fun getSymbolKind(element: PsiElement): String {
        val className = element.javaClass.simpleName
        return when {
            className.contains("Class") -> "Class"
            className.contains("Method") || className.contains("Function") -> "Method"
            className.contains("Field") || className.contains("Property") -> "Field"
            className.contains("Variable") -> "Variable"
            className.contains("Interface") -> "Interface"
            className.contains("Enum") -> "Enum"
            className.contains("Constant") -> "Constant"
            className.contains("Constructor") -> "Constructor"
            className.contains("Module") || className.contains("Package") -> "Module"
            else -> "Unknown"
        }
    }
}


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/SnowEditorContextTracker.kt
================================================
package com.snow.plugin

import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.event.CaretEvent
import com.intellij.openapi.editor.event.CaretListener
import com.intellij.openapi.editor.event.SelectionEvent
import com.intellij.openapi.editor.event.SelectionListener
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
import com.intellij.openapi.fileEditor.FileEditorManagerListener
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile

/**
 * Tracks editor context and sends updates to Snow CLI
 */
class SnowEditorContextTracker(private val project: Project) {
    private val logger = Logger.getInstance(SnowEditorContextTracker::class.java)
    private val wsManager = SnowWebSocketManager.instance
    private var currentEditor: Editor? = null

    init {
        setupListeners()
    }

    /**
     * Normalize path for cross-platform compatibility
     * - Converts Windows backslashes to forward slashes
     * - Converts drive letters to lowercase for consistent comparison
     */
    private fun normalizePath(path: String?): String? {
        if (path == null) return null
        var normalized = path.replace('\\', '/')
        // Convert Windows drive letter to lowercase (C: -> c:)
        if (normalized.matches(Regex("^[A-Z]:.*"))) {
            normalized = normalized[0].lowercaseChar() + normalized.substring(1)
        }
        return normalized
    }

    /**
     * Setup editor listeners
     */
    private fun setupListeners() {
        // Listen to file editor changes
        val connection = project.messageBus.connect()
        connection.subscribe(
            FileEditorManagerListener.FILE_EDITOR_MANAGER,
            object : FileEditorManagerListener {
                override fun selectionChanged(event: FileEditorManagerEvent) {
                    val editor = FileEditorManager.getInstance(project).selectedTextEditor
                    setupEditorListeners(editor)
                    sendEditorContext()
                }

                override fun fileOpened(source: FileEditorManager, file: VirtualFile) {
                    sendEditorContext()
                }
            }
        )
    }

    /**
     * Setup listeners for a specific editor
     */
    private fun setupEditorListeners(editor: Editor?) {
        // Remove old listeners by tracking current editor
        if (editor == currentEditor) {
            return
        }

        currentEditor = editor

        if (editor == null) {
            return
        }

        // Add caret listener for cursor position changes
        editor.caretModel.addCaretListener(object : CaretListener {
            override fun caretPositionChanged(event: CaretEvent) {
                sendEditorContext()
            }
        })

        // Add selection listener
        editor.selectionModel.addSelectionListener(object : SelectionListener {
            override fun selectionChanged(event: SelectionEvent) {
                sendEditorContext()
            }
        })
    }

    /**
     * Send current editor context to Snow CLI
     */
    fun sendEditorContext() {
        ApplicationManager.getApplication().runReadAction {
            try {
                val editor = FileEditorManager.getInstance(project).selectedTextEditor
                val context = buildContext(editor)

                wsManager.sendMessage(context)
            } catch (e: Exception) {
                logger.warn("Failed to send editor context", e)
            }
        }
    }

    /**
     * Build context map from current editor state
     */
    private fun buildContext(editor: Editor?): Map<String, Any?> {
        val context = mutableMapOf<String, Any?>(
            "type" to "context"
        )

        // Get workspace folder (always include) - normalize path for Windows compatibility
        project.basePath?.let { context["workspaceFolder"] = normalizePath(it) }

        // Get active file (try to get even if editor is null) - normalize path for Windows compatibility
        val virtualFile = FileEditorManager.getInstance(project).selectedFiles.firstOrNull()
        virtualFile?.path?.let {
            context["activeFile"] = normalizePath(it)
        }

        // If no editor, still return context with file info
        if (editor == null) {
            return context
        }

        // Get cursor position
        val caretModel = editor.caretModel
        val position = mapOf(
            "line" to caretModel.logicalPosition.line,
            "character" to caretModel.logicalPosition.column
        )
        context["cursorPosition"] = position

        // Get selected text
        val selectionModel = editor.selectionModel
        if (selectionModel.hasSelection()) {
            val selectedText = selectionModel.selectedText
            context["selectedText"] = selectedText
        }

        return context
    }

    /**
     * Get current virtual file
     */
    fun getCurrentFile(): VirtualFile? {
        return FileEditorManager.getInstance(project).selectedFiles.firstOrNull()
    }

    /**
     * Get current editor
     */
    fun getCurrentEditor(): Editor? {
        return FileEditorManager.getInstance(project).selectedTextEditor
    }
}


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/SnowMessageHandler.kt
================================================
package com.snow.plugin

import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.impl.HighlightInfoType
import com.intellij.diff.DiffContentFactory
import com.intellij.diff.DiffManager
import com.intellij.diff.chains.SimpleDiffRequestChain
import com.intellij.diff.requests.SimpleDiffRequest
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.notification.NotificationGroupManager
import com.intellij.notification.NotificationType
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Document
import com.intellij.openapi.fileTypes.FileTypeManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.wm.ToolWindowManager
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import org.json.JSONObject
import org.json.JSONArray
import java.io.File

/**
 * Handles incoming messages from Snow CLI
 */
class SnowMessageHandler(private val project: Project) {
    private val logger = Logger.getInstance(SnowMessageHandler::class.java)
    private val wsManager = SnowWebSocketManager.instance
    private val codeNavigator = SnowCodeNavigator(project)

    init {
        wsManager.setMessageHandler { message -> handleMessage(message) }
    }

    /**
     * Handle incoming WebSocket message
     */
    private fun handleMessage(message: String) {
        try {
            val json = JSONObject(message)
            val type = json.optString("type")

            when (type) {
                "getDiagnostics" -> handleGetDiagnostics(json)
                "aceGoToDefinition" -> handleGoToDefinition(json)
                "aceFindReferences" -> handleFindReferences(json)
                "aceGetSymbols" -> handleGetSymbols(json)
                "showDiff" -> handleShowDiff(json)
                "showDiffReview" -> handleShowDiffReview(json)
                "showGitDiff" -> handleShowGitDiff(json)
                "closeDiff" -> handleCloseDiff()
                else -> logger.info("Unknown message type: $type")
            }
        } catch (e: Exception) {
            logger.warn("Failed to handle message", e)
        }
    }

    /**
     * Handle getDiagnostics request
     */
    private fun handleGetDiagnostics(json: JSONObject) {
        val filePath = json.optString("filePath")
        val requestId = json.optString("requestId")

        ApplicationManager.getApplication().runReadAction {
            try {
                val file = VirtualFileManager.getInstance().findFileByUrl("file://$filePath")
                val diagnostics = if (file != null) {
                    getDiagnostics(file)
                } else {
                    emptyList()
                }

                val response = mapOf(
                    "type" to "diagnostics",
                    "requestId" to requestId,
                    "diagnostics" to diagnostics
                )
                wsManager.sendMessage(response)
            } catch (e: Exception) {
                logger.warn("Failed to get diagnostics", e)
                sendEmptyResponse("diagnostics", requestId)
            }
        }
    }

    /**
     * Get diagnostics for a file
     */
    private fun getDiagnostics(file: VirtualFile): List<Map<String, Any?>> {
        val psiFile = PsiManager.getInstance(project).findFile(file) ?: return emptyList()
        val document = PsiDocumentManager.getInstance(project).getDocument(psiFile) ?: return emptyList()

        return try {
            val highlightInfos = mutableListOf<Map<String, Any?>>()

            // Wrap in read action to ensure thread safety
            ApplicationManager.getApplication().runReadAction {
                try {
                    // Use DocumentMarkupModel to get all highlight infos safely
                    val markupModel = com.intellij.openapi.editor.impl.DocumentMarkupModel.forDocument(document, project, true)
                    if (markupModel != null) {
                        // Process all highlighters
                        markupModel.allHighlighters.forEach { highlighter ->
                            try {
                                // Get HighlightInfo from the highlighter's error stripe tooltip
                                val errorStripeTooltip = highlighter.errorStripeTooltip

                                // Try to extract info from different tooltip types
                                if (errorStripeTooltip is HighlightInfo) {
                                    val info = errorStripeTooltip
                                    val severity = info.severity

                                    // Skip if severity is too low (e.g., just syntax highlighting)
                                    if (severity.myVal <= HighlightSeverity.INFORMATION.myVal) {
                                        return@forEach
                                    }

                                    val startOffset = info.startOffset
                                    val line = document.getLineNumber(startOffset)
                                    val lineStartOffset = document.getLineStartOffset(line)
                                    val character = startOffset - lineStartOffset

                                    highlightInfos.add(mapOf(
                                        "message" to (info.description ?: "Unknown issue"),
                                        "severity" to when {
                                            severity == HighlightSeverity.ERROR -> "error"
                                            severity == HighlightSeverity.WARNING -> "warning"
                                            severity == HighlightSeverity.WEAK_WARNING -> "info"
                                            else -> "hint"
                                        },
                                        "line" to line,
                                        "character" to character,
                                        "source" to "IntelliJ",
                                        "code" to (info.inspectionToolId ?: "")
                                    ))
                                }
                            } catch (e: Exception) {
                                // Silently skip this highlighter if we can't process it
                                logger.debug("Failed to process highlighter", e)
                            }
                        }
                    }
                } catch (e: Exception) {
                    logger.warn("Failed to extract diagnostics from markup model", e)
                }
            }

            highlightInfos
        } catch (e: Exception) {
            logger.warn("Failed to get diagnostics", e)
            emptyList()
        }
    }

    /**
     * Handle aceGoToDefinition request
     */
    private fun handleGoToDefinition(json: JSONObject) {
        val filePath = json.optString("filePath")
        val line = json.optInt("line")
        val column = json.optInt("column")
        val requestId = json.optString("requestId")

        ApplicationManager.getApplication().runReadAction {
            try {
                val definitions = codeNavigator.goToDefinition(filePath, line, column)
                val response = mapOf(
                    "type" to "aceGoToDefinitionResult",
                    "requestId" to requestId,
                    "definitions" to definitions
                )
                wsManager.sendMessage(response)
            } catch (e: Exception) {
                logger.warn("Failed to go to definition", e)
                sendEmptyResponse("aceGoToDefinitionResult", requestId, "definitions")
            }
        }
    }

    /**
     * Handle aceFindReferences request
     */
    private fun handleFindReferences(json: JSONObject) {
        val filePath = json.optString("filePath")
        val line = json.optInt("line")
        val column = json.optInt("column")
        val requestId = json.optString("requestId")

        ApplicationManager.getApplication().runReadAction {
            try {
                val references = codeNavigator.findReferences(filePath, line, column)
                val response = mapOf(
                    "type" to "aceFindReferencesResult",
                    "requestId" to requestId,
                    "references" to references
                )
                wsManager.sendMessage(response)
            } catch (e: Exception) {
                logger.warn("Failed to find references", e)
                sendEmptyResponse("aceFindReferencesResult", requestId, "references")
            }
        }
    }

    /**
     * Handle aceGetSymbols request
     */
    private fun handleGetSymbols(json: JSONObject) {
        val filePath = json.optString("filePath")
        val requestId = json.optString("requestId")

        ApplicationManager.getApplication().runReadAction {
            try {
                val symbols = codeNavigator.getSymbols(filePath)
                val response = mapOf(
                    "type" to "aceGetSymbolsResult",
                    "requestId" to requestId,
                    "symbols" to symbols
                )
                wsManager.sendMessage(response)
            } catch (e: Exception) {
                logger.warn("Failed to get symbols", e)
                sendEmptyResponse("aceGetSymbolsResult", requestId, "symbols")
            }
        }
    }

    @Volatile
    private var trackedDiffFiles = mutableListOf<VirtualFile>()

    private fun closeTrackedDiffs() {
        if (project.isDisposed) return
        val fem = FileEditorManager.getInstance(project)
        val toClose = trackedDiffFiles.toList()
        trackedDiffFiles.clear()
        for (file in toClose) {
            if (file.isValid) {
                fem.closeFile(file)
            }
        }
    }

    private fun showDiffInEditor(title: String, leftText: String, rightText: String, leftLabel: String, rightLabel: String, fileName: String) {
        if (project.isDisposed) return

        val fem = FileEditorManager.getInstance(project)
        val beforeFiles = fem.openFiles.toSet()

        closeTrackedDiffs()

        val fileType = FileTypeManager.getInstance().getFileTypeByFileName(fileName)
        val contentFactory = DiffContentFactory.getInstance()
        val left = contentFactory.create(leftText, fileType)
        val right = contentFactory.create(rightText, fileType)
        val request = SimpleDiffRequest(title, left, right, leftLabel, rightLabel)
        DiffManager.getInstance().showDiff(project, request)

        val afterFiles = fem.openFiles.toSet()
        val newFiles = afterFiles - beforeFiles
        trackedDiffFiles.addAll(newFiles)

        restoreTerminalFocus()
    }

    private fun handleCloseDiff() {
        ApplicationManager.getApplication().invokeLater({
            closeTrackedDiffs()
        }, ModalityState.defaultModalityState())
    }

    private fun restoreTerminalFocus() {
        ApplicationManager.getApplication().invokeLater {
            if (project.isDisposed) return@invokeLater
            ToolWindowManager.getInstance(project).getToolWindow("Terminal")?.activate(null, false, false)
        }
    }

    private fun notifyError(message: String) {
        try {
            NotificationGroupManager.getInstance()
                .getNotificationGroup("Snow CLI")
                .createNotification(message, NotificationType.ERROR)
                .notify(project)
        } catch (e: Exception) {
            logger.warn("Failed to show notification: $message", e)
        }
    }

    private fun handleShowDiff(json: JSONObject) {
        val filePath = json.optString("filePath", "")
        val originalContent = json.optString("originalContent", "")
        val newContent = json.optString("newContent", "")
        val label = json.optString("label", "Diff")

        if (filePath.isEmpty()) {
            logger.warn("showDiff: filePath is empty")
            return
        }

        val fileName = File(filePath).name

        ApplicationManager.getApplication().invokeLater({
            try {
                showDiffInEditor("$label: $fileName", originalContent, newContent, "Original", "Current", fileName)
            } catch (e: Exception) {
                logger.error("Failed to show diff for $filePath", e)
                notifyError("Snow CLI: Failed to show diff - ${e.message}")
            }
        }, ModalityState.defaultModalityState())
    }

    private fun handleShowDiffReview(json: JSONObject) {
        val filesArray = json.optJSONArray("files")
        if (filesArray == null || filesArray.length() == 0) {
            logger.warn("showDiffReview: no files")
            return
        }

        data class DiffItem(val title: String, val left: String, val right: String, val fileName: String)

        val items = mutableListOf<DiffItem>()
        for (i in 0 until filesArray.length()) {
            try {
                val fileObj = filesArray.getJSONObject(i)
                val filePath = fileObj.optString("filePath", "")
                val originalContent = fileObj.optString("originalContent", "")
                val newContent = fileObj.optString("newContent", "")
                val fileName = File(filePath).name
                items.add(DiffItem("Diff Review: $fileName", originalContent, newContent, fileName))
            } catch (e: Exception) {
                logger.warn("showDiffReview: failed to parse file $i", e)
            }
        }

        if (items.isEmpty()) return

        ApplicationManager.getApplication().invokeLater({
            try {
                if (project.isDisposed) return@invokeLater

                val fem = FileEditorManager.getInstance(project)
                val beforeFiles = fem.openFiles.toSet()

                closeTrackedDiffs()

                if (items.size == 1) {
                    val item = items[0]
                    val fileType = FileTypeManager.getInstance().getFileTypeByFileName(item.fileName)
                    val contentFactory = DiffContentFactory.getInstance()
                    val left = contentFactory.create(item.left, fileType)
                    val right = contentFactory.create(item.right, fileType)
                    val request = SimpleDiffRequest(item.title, left, right, "Original", "Current")
                    DiffManager.getInstance().showDiff(project, request)
                } else {
                    val contentFactory = DiffContentFactory.getInstance()
                    val requests = items.map { item ->
                        val fileType = FileTypeManager.getInstance().getFileTypeByFileName(item.fileName)
                        val left = contentFactory.create(item.left, fileType)
                        val right = contentFactory.create(item.right, fileType)
                        SimpleDiffRequest(item.title, left, right, "Original", "Current")
                    }
                    val chain = SimpleDiffRequestChain(requests)
                    DiffManager.getInstance().showDiff(project, chain, com.intellij.diff.DiffDialogHints.DEFAULT)
                }

                val afterFiles = fem.openFiles.toSet()
                trackedDiffFiles.addAll(afterFiles - beforeFiles)
                restoreTerminalFocus()
            } catch (e: Exception) {
                logger.error("Failed to show diff review", e)
                notifyError("Snow CLI: Failed to show diff review - ${e.message}")
            }
        }, ModalityState.defaultModalityState())
    }

    private fun handleShowGitDiff(json: JSONObject) {
        val filePath = json.optString("filePath", "")
        if (filePath.isEmpty()) return

        ApplicationManager.getApplication().executeOnPooledThread {
            try {
                val file = File(filePath)
                val repoRoot = project.basePath ?: return@executeOnPooledThread
                val relPath = File(repoRoot).toPath().relativize(file.toPath()).toString().replace('\\', '/')

                val currentContent = if (file.exists()) file.readText() else ""

                var originalContent = ""
                try {
                    val process = ProcessBuilder("git", "show", "HEAD:$relPath")
                        .directory(File(repoRoot))
                        .redirectErrorStream(false)
                        .start()
                    originalContent = process.inputStream.bufferedReader().readText()
                    process.waitFor()
                } catch (_: Exception) {
                    // New/untracked file
                }

                val fileName = file.name

                ApplicationManager.getApplication().invokeLater({
                    try {
                        showDiffInEditor("Git Diff: $fileName", originalContent, currentContent, "HEAD", "Working Tree", fileName)
                    } catch (e: Exception) {
                        logger.error("Failed to show git diff for $filePath", e)
                        notifyError("Snow CLI: Failed to show git diff - ${e.message}")
                    }
                }, ModalityState.defaultModalityState())
            } catch (e: Exception) {
                logger.error("Failed to show git diff for $filePath", e)
            }
        }
    }

    /**
     * Send empty response on error
     */
    private fun sendEmptyResponse(type: String, requestId: String, arrayField: String = "diagnostics") {
        val response = mapOf(
            "type" to type,
            "requestId" to requestId,
            arrayField to emptyList<Any>()
        )
        wsManager.sendMessage(response)
    }
}


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/SnowPluginLifecycle.kt
================================================
package com.snow.plugin

import com.intellij.ide.AppLifecycleListener
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.project.ProjectManagerListener

/**
 * Plugin lifecycle listener
 */
class SnowPluginLifecycle : AppLifecycleListener {
    private val wsManager = SnowWebSocketManager.instance

    override fun appFrameCreated(commandLineArgs: MutableList<String>) {
        wsManager.connect()

        ApplicationManager.getApplication().messageBus.connect()
            .subscribe(ProjectManager.TOPIC, object : ProjectManagerListener {
                override fun projectClosed(project: Project) {
                    cleanupProject(project)
                }
            })

        for (project in ProjectManager.getInstance().openProjects) {
            setupProject(project)
        }
    }

    override fun appWillBeClosed(isRestart: Boolean) {
        wsManager.disconnect()
    }

    companion object {
        private val trackers = mutableMapOf<Project, SnowEditorContextTracker>()
        private val handlers = mutableMapOf<Project, SnowMessageHandler>()

        fun setupProject(project: Project) {
            SnowWebSocketManager.instance.updatePortInfoForProject(project)

            if (!trackers.containsKey(project)) {
                val tracker = SnowEditorContextTracker(project)
                val handler = SnowMessageHandler(project)
                trackers[project] = tracker
                handlers[project] = handler

                ApplicationManager.getApplication().executeOnPooledThread {
                    tracker.sendEditorContext()

                    for (i in 1..3) {
                        Thread.sleep(1000)
                        tracker.sendEditorContext()
                    }
                }
            }
        }

        fun cleanupProject(project: Project) {
            SnowWebSocketManager.instance.cleanupPortInfoForProject(project)
            trackers.remove(project)
            handlers.remove(project)
        }
    }
}


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/SnowProjectActivity.kt
================================================
package com.snow.plugin

import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.DefaultActionGroup
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.ProjectActivity

class SnowProjectActivity : ProjectActivity {
    override suspend fun execute(project: Project) {
        SnowPluginLifecycle.setupProject(project)
        ApplicationManager.getApplication().invokeLater {
            registerProjectViewAction()
        }
    }

    companion object {
        @Volatile
        private var registered = false

        private fun registerProjectViewAction() {
            if (registered) return
            val actionManager = ActionManager.getInstance()
            val sendAction = actionManager.getAction("snow.SendToSnowCLI") ?: return
            val group = actionManager.getAction("ProjectViewPopupMenu") as? DefaultActionGroup ?: return
            group.addSeparator()
            group.add(sendAction)
            registered = true
        }
    }
}


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/SnowWebSocketManager.kt
================================================
package com.snow.plugin

import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger
import org.java_websocket.WebSocket
import org.java_websocket.handshake.ClientHandshake
import org.java_websocket.server.WebSocketServer
import java.net.InetSocketAddress
import java.net.ServerSocket
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicReference

/**
 * Manages WebSocket server for Snow CLI connections
 */
class SnowWebSocketManager private constructor() {
    private val logger = Logger.getInstance(SnowWebSocketManager::class.java)
    private val server = AtomicReference<WebSocketServerImpl?>(null)
    private val messageHandler = AtomicReference<((String) -> Unit)?>(null)
    private val clients = ConcurrentHashMap.newKeySet<WebSocket>()

    // Cache for last valid editor context
    @Volatile
    private var lastValidContext: Map<String, Any?>? = null

    companion object {
        // Use different port range from VSCode (9527-9537) to avoid conflicts
        private const val BASE_PORT = 9538
        private const val MAX_PORT = 9548

        val instance: SnowWebSocketManager by lazy { SnowWebSocketManager() }

        /**
         * Normalize path for cross-platform compatibility
         * - Converts Windows backslashes to forward slashes
         * - Converts drive letters to lowercase for consistent comparison
         */
        private fun normalizePath(path: String?): String? {
            if (path == null) return null
            var normalized = path.replace('\\', '/')
            // Convert Windows drive letter to lowercase (C: -> c:)
            if (normalized.matches(Regex("^[A-Z]:.*"))) {
                normalized = normalized[0].lowercaseChar() + normalized.substring(1)
            }
            return normalized
        }
    }

    @Volatile
    private var actualPort = BASE_PORT

    /**
     * Start WebSocket server
     */
    fun connect() {
        if (server.get() != null) {
            return
        }

        ApplicationManager.getApplication().executeOnPooledThread {
            tryStartServer(BASE_PORT)
        }
    }

    /**
     * Try to start server on a specific port, with fallback to next port
     */
    private fun tryStartServer(port: Int) {
        if (port > MAX_PORT) {
            logger.error("Failed to start WebSocket server: all ports $BASE_PORT-$MAX_PORT are in use")
            return
        }

        // Synchronously probe whether the port is actually free before handing it
        // to Java-WebSocket. Java-WebSocket's start() is asynchronous: when another
        // process (e.g. another JetBrains IDE) already holds the port, the bind
        // failure surfaces only inside the server thread via onError, AFTER we have
        // already cached actualPort and registered the project under the wrong port
        // in snow-cli-ports.json. That mismatch is what causes the CLI to attach
        // to the WRONG IDE when two JetBrains IDEs are open simultaneously
        // (showing one IDE's active file with another IDE's working directory).
        if (!isPortAvailable(port)) {
            tryStartServer(port + 1)
            return
        }

        try {
            val wsServer = WebSocketServerImpl(InetSocketAddress(port))
            server.set(wsServer)

            try {
                wsServer.start()
                actualPort = port

                // Server is ready — register all currently open projects
                for (openProject in com.intellij.openapi.project.ProjectManager.getInstance().openProjects) {
                    if (!openProject.isDefault) {
                        writePortInfo(port, openProject)
                    }
                }
            } catch (e: Exception) {
                if (e.message?.contains("Address already in use") == true) {
                    server.set(null)
                    tryStartServer(port + 1)
                } else {
                    logger.error("Failed to start WebSocket server on port $port", e)
                    server.set(null)
                }
            }
        } catch (e: Exception) {
            logger.error("Failed to create WebSocket server on port $port", e)
            tryStartServer(port + 1)
        }
    }

    /**
     * Test whether a TCP port can be bound on localhost. Used to avoid the
     * Java-WebSocket async-bind race: if another IDE already owns the port,
     * binding here fails immediately and we move on to the next port.
     *
     * Note: there is an inherent (microscopic) TOCTOU window between the probe
     * and the actual WebSocketServer bind. The async catch path above still
     * handles that fallback for completeness.
     */
    private fun isPortAvailable(port: Int): Boolean {
        return try {
            ServerSocket().use { socket ->
                socket.reuseAddress = false
                socket.bind(InetSocketAddress("0.0.0.0", port))
            }
            true
        } catch (e: Exception) {
            false
        }
    }

    /**
     * Write port information to temp file for a specific project.
     * Skips writing if the workspace path is empty to avoid
     * an entry that matches every cwd.
     */
    private fun writePortInfo(port: Int, project: com.intellij.openapi.project.Project? = null) {
        try {
            val tmpDir = System.getProperty("java.io.tmpdir")
            val portInfoFile = java.io.File(tmpDir, "snow-cli-ports.json")

            val portInfo = if (portInfoFile.exists()) {
                org.json.JSONObject(portInfoFile.readText())
            } else {
                org.json.JSONObject()
            }

            val resolvedProject = project
                ?: com.intellij.openapi.project.ProjectManager.getInstance().openProjects
                    .firstOrNull { !it.isDefault }
            val workspaceFolder = normalizePath(resolvedProject?.basePath)

            if (workspaceFolder.isNullOrEmpty()) return

            // Remove stale empty-key entry if present
            if (portInfo.has("")) {
                portInfo.remove("")
            }

            val entry = org.json.JSONObject()
            entry.put("port", port)
            entry.put("ide", "JetBrains")
            portInfo.put(workspaceFolder, entry)
            portInfoFile.writeText(portInfo.toString(2))
        } catch (e: Exception) {
            logger.warn("Failed to write port info", e)
        }
    }

    /**
     * Register a project's workspace in the port info file.
     * Called when a project finishes initialisation.
     */
    fun updatePortInfoForProject(project: com.intellij.openapi.project.Project) {
        if (server.get() == null) return
        writePortInfo(actualPort, project)
    }

    /**
     * Stop WebSocket server
     */
    fun disconnect() {
        server.getAndSet(null)?.let { wsServer ->
            try {
                wsServer.stop()
                clients.clear()

                // Clean up port info file
                cleanupPortInfo()
            } catch (e: Exception) {
                logger.error("Error stopping WebSocket server", e)
            }
        }
    }

    /**
     * Clean up port information from temp file
     */
    private fun cleanupPortInfo(project: com.intellij.openapi.project.Project? = null) {
        try {
            val tmpDir = System.getProperty("java.io.tmpdir")
            val portInfoFile = java.io.File(tmpDir, "snow-cli-ports.json")

            if (portInfoFile.exists()) {
                val portInfo = org.json.JSONObject(portInfoFile.readText())

                val resolvedProject = project
                    ?: com.intellij.openapi.project.ProjectManager.getInstance().openProjects
                        .firstOrNull { !it.isDefault }
                val workspaceFolder = normalizePath(resolvedProject?.basePath)

                // Remove the workspace entry
                if (!workspaceFolder.isNullOrEmpty()) {
                    portInfo.remove(workspaceFolder)
                }
                // Always remove stale empty-key entry
                if (portInfo.has("")) {
                    portInfo.remove("")
                }

                if (portInfo.length() == 0) {
                    portInfoFile.delete()
                } else {
                    portInfoFile.writeText(portInfo.toString(2))
                }
            }
        } catch (e: Exception) {
            logger.warn("Failed to clean up port info", e)
        }
    }

    /**
     * Remove a project's workspace from the port info file.
     * Called when a project is closed.
     */
    fun cleanupPortInfoForProject(project: com.intellij.openapi.project.Project) {
        cleanupPortInfo(project)
    }

    /**
     * Send message through WebSocket to all connected clients
     */
    fun sendMessage(data: Map<String, Any?>) {
        if (clients.isEmpty()) {
            return
        }

        try {
            val json = buildJsonString(data)

            // Cache context messages
            if (data["type"] == "context") {
                lastValidContext = data
            }

            // Broadcast to all connected clients
            for (client in clients) {
                if (client.isOpen) {
                    client.send(json)
                }
            }
        } catch (e: Exception) {
            logger.warn("Failed to send message", e)
        }
    }

    /**
     * Set message handler
     */
    fun setMessageHandler(handler: (String) -> Unit) {
        messageHandler.set(handler)
    }

    /**
     * Send editor context for a specific project
     */
    private fun sendEditorContextForProject(project: com.intellij.openapi.project.Project) {
        ApplicationManager.getApplication().runReadAction {
            try {
                val editor = com.intellij.openapi.fileEditor.FileEditorManager.getInstance(project).selectedTextEditor
                val virtualFile = com.intellij.openapi.fileEditor.FileEditorManager.getInstance(project).selectedFiles.firstOrNull()

                val context = mutableMapOf<String, Any?>(
                    "type" to "context"
                )

                // Add workspace folder - normalize path for Windows compatibility
                project.basePath?.let { context["workspaceFolder"] = normalizePath(it) }

                // Add active file - normalize path for Windows compatibility
                virtualFile?.path?.let { context["activeFile"] = normalizePath(it) }

                // Add cursor position if editor available
                if (editor != null) {
                    val caretModel = editor.caretModel
                    val position = mapOf(
                        "line" to caretModel.logicalPosition.line,
                        "character" to caretModel.logicalPosition.column
                    )
                    context["cursorPosition"] = position

                    // Add selected text
                    val selectionModel = editor.selectionModel
                    if (selectionModel.hasSelection()) {
                        context["selectedText"] = selectionModel.selectedText
                    }
                }

                sendMessage(context)
            } catch (e: Exception) {
                logger.warn("Failed to build editor context for project ${project.name}", e)
            }
        }
    }

    /**
     * Inner WebSocket server implementation
     */
    private inner class WebSocketServerImpl(address: InetSocketAddress) : WebSocketServer(address) {
        init {
            connectionLostTimeout = 0
        }

        override fun onOpen(conn: WebSocket, handshake: ClientHandshake?) {
            clients.add(conn)

            // Always send current context on new connection
            // This ensures CLI always receives the latest editor state
            ApplicationManager.getApplication().invokeLater {
                val projects = com.intellij.openapi.project.ProjectManager.getInstance().openProjects
                for (project in projects) {
                    try {
                        sendEditorContextForProject(project)
                    } catch (e: Exception) {
                        logger.warn("Failed to send context for project ${project.name}", e)
                    }
                }
            }

            // Also send cached context immediately if available (fast path)
            lastValidContext?.let { context ->
                try {
                    val json = buildJsonString(context)
                    conn.send(json)
                } catch (e: Exception) {
                    logger.warn("Failed to send cached context", e)
                }
            }
        }

        override fun onClose(conn: WebSocket, code: Int, reason: String?, remote: Boolean) {
            clients.remove(conn)
        }

        override fun onMessage(conn: WebSocket, message: String) {
            messageHandler.get()?.invoke(message)
        }

        override fun onError(conn: WebSocket?, ex: Exception) {
            logger.warn("WebSocket error", ex)
            conn?.let { clients.remove(it) }
        }

        override fun onStart() {
            // WebSocket server started
        }
    }

    /**
     * Simple JSON string builder (avoiding external dependencies)
     */
    private fun buildJsonString(data: Map<String, Any?>): String {
        val entries = data.entries.joinToString(",") { (key, value) ->
            val valueStr = when (value) {
                null -> "null"
                is String -> "\"${escapeJson(value)}\""
                is Number -> value.toString()
                is Boolean -> value.toString()
                is Map<*, *> -> buildJsonString(value as Map<String, Any?>)
                is List<*> -> buildJsonArray(value)
                else -> "\"${escapeJson(value.toString())}\""
            }
            "\"$key\":$valueStr"
        }
        return "{$entries}"
    }

    private fun buildJsonArray(list: List<*>): String {
        val items = list.joinToString(",") { item ->
            when (item) {
                null -> "null"
                is String -> "\"${escapeJson(item)}\""
                is Number -> item.toString()
                is Boolean -> item.toString()
                is Map<*, *> -> buildJsonString(item as Map<String, Any?>)
                is List<*> -> buildJsonArray(item)
                else -> "\"${escapeJson(item.toString())}\""
            }
        }
        return "[$items]"
    }

    private fun escapeJson(str: String): String {
        return str
            .replace("\\", "\\\\")
            .replace("\"", "\\\"")
            .replace("\n", "\\n")
            .replace("\r", "\\r")
            .replace("\t", "\\t")
    }
}


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/actions/GenerateCommitMessageAction.kt
================================================
package com.snow.plugin.actions

import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.components.service
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.vcs.VcsDataKeys
import com.snow.plugin.commit.SnowCommitMessageGenerationService
import icons.SnowPluginIcons
import java.awt.event.InputEvent

class GenerateCommitMessageAction : DumbAwareAction() {

    override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT

    override fun actionPerformed(e: AnActionEvent) {
        val project = e.project ?: return
        val commitMessageControl = e.getData(VcsDataKeys.COMMIT_MESSAGE_CONTROL)
        val commitWorkflowUi = e.getData(VcsDataKeys.COMMIT_WORKFLOW_UI)
        val service = project.service<SnowCommitMessageGenerationService>()

        if (service.isGenerating()) {
            service.generate(commitMessageControl, commitWorkflowUi?.commitMessageUi)
            return
        }

        val shouldAskForRequirements = hasRequirementsModifier(e)
        val additionalRequirements = if (shouldAskForRequirements) {
            val input = Messages.showInputDialog(
                project,
                "Add optional requirements for the generated commit message.",
                "Snow CLI: Commit Message Requirements",
                Messages.getQuestionIcon(),
            ) ?: return
            input.trim().ifEmpty { null }
        } else {
            null
        }

        service.generate(
            commitMessageControl,
            commitWorkflowUi?.commitMessageUi,
            additionalRequirements,
        )
    }

    override fun update(e: AnActionEvent) {
        val project = e.project
        val hasCommitMessageTarget = e.getData(VcsDataKeys.COMMIT_MESSAGE_CONTROL) != null ||
            e.getData(VcsDataKeys.COMMIT_WORKFLOW_UI) != null
        val isGenerating = project?.service<SnowCommitMessageGenerationService>()?.isGenerating() == true

        e.presentation.icon = if (isGenerating) {
            SnowPluginIcons.SnowStopToolbarAction
        } else {
            SnowPluginIcons.SnowToolbarAction
        }

        e.presentation.isEnabledAndVisible = project != null && hasCommitMessageTarget
        e.presentation.text = if (isGenerating) {
            "Cancel Commit Message Generation"
        } else {
            "Generate Commit Message"
        }
        e.presentation.description = if (isGenerating) {
            "Cancel Snow CLI commit message generation"
        } else {
            "Generate a commit message with Snow CLI AI. Alt/Option-click to add requirements."
        }
    }

    private fun hasRequirementsModifier(e: AnActionEvent): Boolean {
        return (e.inputEvent?.modifiersEx ?: 0) and InputEvent.ALT_DOWN_MASK != 0
    }
}


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/actions/OpenSnowTerminalAction.kt
================================================
package com.snow.plugin.actions

import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.application.ApplicationManager
import com.snow.plugin.SnowWebSocketManager
import com.snow.plugin.util.TerminalCompat

class OpenSnowTerminalAction : AnAction() {
    override fun actionPerformed(e: AnActionEvent) {
        val project = e.project ?: return

        ApplicationManager.getApplication().invokeLater {
            try {
                TerminalCompat.openTerminalWithCommand(project, project.basePath, "Snow CLI", "snow")
            } catch (_: Exception) {
            }
        }

        val wsManager = SnowWebSocketManager.instance
        ApplicationManager.getApplication().executeOnPooledThread {
            Thread.sleep(500)
            wsManager.connect()
        }
    }

    override fun update(e: AnActionEvent) {
        e.presentation.isEnabled = e.project != null
    }
}


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/actions/SendToSnowCLIAction.kt
================================================
package com.snow.plugin.actions

import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.DumbAwareAction
import com.snow.plugin.SnowWebSocketManager
import com.snow.plugin.util.TerminalCompat

class SendToSnowCLIAction : DumbAwareAction() {

    override fun getActionUpdateThread() = ActionUpdateThread.BGT

    override fun actionPerformed(e: AnActionEvent) {
        val project = e.project ?: return
        val files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY)
            ?: e.getData(CommonDataKeys.VIRTUAL_FILE)?.let { arrayOf(it) }
            ?: return
        if (files.isEmpty()) return

        val formattedPaths = files.joinToString(" ") { "\"${it.path}\"" }

        ApplicationManager.getApplication().invokeLater {
            val sent = TerminalCompat.sendTextToNamedTerminal(project, "Snow CLI", formattedPaths)
            if (!sent) {
                TerminalCompat.openTerminalWithCommand(project, project.basePath, "Snow CLI", "snow")
                ApplicationManager.getApplication().executeOnPooledThread {
                    Thread.sleep(3000)
                    ApplicationManager.getApplication().invokeLater {
                        TerminalCompat.sendTextToNamedTerminal(project, "Snow CLI", formattedPaths)
                    }
                }
                val wsManager = SnowWebSocketManager.instance
                ApplicationManager.getApplication().executeOnPooledThread {
                    Thread.sleep(500)
                    wsManager.connect()
                }
            }
        }
    }

    override fun update(e: AnActionEvent) {
        e.presentation.isVisible = true
        e.presentation.isEnabled = e.project != null
    }
}


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/actions/TestNotificationAction.kt
================================================
package com.snow.plugin.actions

import com.intellij.notification.Notification
import com.intellij.notification.NotificationType
import com.intellij.notification.Notifications
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent

/**
 * Simple test action to verify notifications work
 */
class TestNotificationAction : AnAction("Test Notification") {

    override fun actionPerformed(e: AnActionEvent) {
        val project = e.project ?: return

        val notification = Notification(
            "Snow CLI",
            "Test",
            "This is notification 1",
            NotificationType.INFORMATION
        )
        Notifications.Bus.notify(notification, project)

        val notification2 = Notification(
            "Snow CLI",
            "Test",
            "This is notification 2",
            NotificationType.WARNING
        )
        Notifications.Bus.notify(notification2, project)

        val notification3 = Notification(
            "Snow CLI",
            "Test",
            "This is notification 3",
            NotificationType.ERROR
        )
        Notifications.Bus.notify(notification3, project)
    }
}


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/commit/SnowCommitMessageGenerationService.kt
================================================
package com.snow.plugin.commit

import com.intellij.notification.NotificationGroupManager
import com.intellij.notification.NotificationType
import com.intellij.ide.ActivityTracker
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.Service
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.Project
import com.intellij.openapi.vcs.CommitMessageI
import com.intellij.vcs.commit.CommitMessageUi
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
import java.time.Duration
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.math.min

private const val MAX_DIFF_CHARS = 120_000
private const val API_MAX_RETRIES = 5
private const val API_RETRY_BASE_DELAY_MS = 1_000L
private val RESTRICTED_HEADERS = setOf(
    "connection",
    "content-length",
    "date",
    "expect",
    "from",
    "host",
    "upgrade",
    "via",
    "warning",
)

@Service(Service.Level.PROJECT)
class SnowCommitMessageGenerationService(private val project: Project) {
    private val logger = Logger.getInstance(SnowCommitMessageGenerationService::class.java)
    private val generating = AtomicBoolean(false)
    private val httpClient = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(30))
        .build()

    @Volatile
    private var activeIndicator: ProgressIndicator? = null

    fun isGenerating(): Boolean = generating.get()

    fun generate(
        commitMessageControl: CommitMessageI?,
        commitMessageUi: CommitMessageUi?,
        additionalRequirements: String? = null,
    ) {
        if (!generating.compareAndSet(false, true)) {
            activeIndicator?.cancel()
            return
        }
        updateActions()

        ProgressManager.getInstance().run(object : Task.Backgroundable(project, "Snow CLI: Generating commit message", true) {
            private var generatedMessage: String? = null

            override fun run(indicator: ProgressIndicator) {
                activeIndicator = indicator
                ApplicationManager.getApplication().invokeLater {
                    commitMessageUi?.startLoading()
                }

                val payload = collectDiffPayload(indicator)
                if (payload.diff.isBlank()) {
                    notify("Snow CLI: No staged or working tree changes found.", NotificationType.INFORMATION)
                    return
                }

                generatedMessage = normalizeCommitMessage(requestCommitMessage(payload, indicator, additionalRequirements))
            }

            override fun onSuccess() {
                val message = generatedMessage ?: return
                if (commitMessageControl != null) {
                    commitMessageControl.setCommitMessage(message)
                } else {
                    commitMessageUi?.setText(message)
                }
                commitMessageUi?.focus()
            }

            override fun onCancel() {
                notify("Snow CLI: Commit message generation stopped.", NotificationType.INFORMATION)
            }

            override fun onThrowable(error: Throwable) {
                if (error is ProcessCanceledException) {
                    return
                }
                logger.warn("Failed to generate commit message", error)
                notify(
                    "Snow CLI: Failed to generate commit message. ${error.message ?: error.javaClass.simpleName}",
                    NotificationType.ERROR,
                )
            }

            override fun onFinished() {
                commitMessageUi?.stopLoading()
                activeIndicator = null
                generating.set(false)
                updateActions()
            }
        })
    }

    private fun updateActions() {
        ApplicationManager.getApplication().invokeLater {
            ActivityTracker.getInstance().inc()
        }
    }

    private fun collectDiffPayload(indicator: ProgressIndicator): DiffPayload {
        val repositoryRoot = findGitRoot(indicator)
        val stagedDiff = execGit(listOf("diff", "--cached", "--no-ext-diff"), repositoryRoot, indicator)
        val hasStagedChanges = stagedDiff.trim().isNotEmpty()
        val fullDiff = if (hasStagedChanges) {
            stagedDiff
        } else {
            execGit(listOf("diff", "--no-ext-diff"), repositoryRoot, indicator)
        }
        val truncated = fullDiff.length > MAX_DIFF_CHARS

        return DiffPayload(
            diff = if (truncated) fullDiff.take(MAX_DIFF_CHARS) else fullDiff,
            source = if (hasStagedChanges) DiffSource.STAGED else DiffSource.WORKING_TREE,
            truncated = truncated,
        )
    }

    private fun findGitRoot(indicator: ProgressIndicator): String {
        val projectRoot = project.basePath ?: throw IllegalStateException("Project path is not available.")
        return try {
            execGit(listOf("rev-parse", "--show-toplevel"), projectRoot, indicator).trim().ifEmpty { projectRoot }
        } catch (_: Exception) {
            projectRoot
        }
    }

    private fun execGit(args: List<String>, cwd: String, indicator: ProgressIndicator): String {
        indicator.checkCanceled()
        val process = ProcessBuilder(listOf("git") + args)
            .directory(File(cwd))
            .redirectErrorStream(true)
            .start()

        val output = StringBuilder()
        val readerThread = Thread {
            process.inputStream.bufferedReader().use { reader ->
                output.append(reader.readText())
            }
        }.apply {
            name = "Snow Git Output Reader"
            isDaemon = true
            start()
        }

        try {
            while (!process.waitFor(100, TimeUnit.MILLISECONDS)) {
                indicator.checkCanceled()
            }
            readerThread.join(1_000)
        } catch (error: ProcessCanceledException) {
            process.destroyForcibly()
            throw error
        }

        val text = output.toString()
        if (process.exitValue() != 0) {
            throw IllegalStateException(text.trim().ifEmpty { "git ${args.joinToString(" ")} failed." })
        }
        return text
    }

    private fun requestCommitMessage(
        payload: DiffPayload,
        indicator: ProgressIndicator,
        additionalRequirements: String?,
    ): String {
        val config = loadActiveSnowConfig()
        val model = config.basicModel.trim()
        if (model.isEmpty()) {
            throw IllegalStateException("Basic model is not configured.")
        }

        val prompt = buildPrompt(payload, additionalRequirements)
        return withApiRetry(indicator) {
            when (config.requestMethod.ifBlank { "chat" }) {
                "responses" -> requestResponsesCommitMessage(config, model, prompt, indicator)
                "gemini" -> requestGeminiCommitMessage(config, model, prompt, indicator)
                "anthropic" -> requestAnthropicCommitMessage(config, model, prompt, indicator)
                else -> requestChatCommitMessage(config, model, prompt, indicator)
            }
        }
    }

    private fun requestChatCommitMessage(
        config: SnowApiConfig,
        model: String,
        prompt: CommitPrompt,
        indicator: ProgressIndicator,
    ): String {
        val url = "${requireBaseUrl(config)}/chat/completions"
        val body = JSONObject()
            .put("model", model)
            .put(
                "messages",
                JSONArray()
                    .put(JSONObject().put("role", "system").put("content", prompt.system))
                    .put(JSONObject().put("role", "user").put("content", prompt.user)),
            )
            .put("stream", false)
            .put("temperature", 0.2)

        val data = postJson(url, config, null, body, indicator, "OpenAI Chat API")
        return data.optJSONArray("choices")
            ?.optJSONObject(0)
            ?.optJSONObject("message")
            ?.optString("content")
            .orEmpty()
    }

    private fun requestResponsesCommitMessage(
        config: SnowApiConfig,
        model: String,
        prompt: CommitPrompt,
        indicator: ProgressIndicator,
    ): String {
        val url = "${requireBaseUrl(config)}/responses"
        val body = JSONObject()
            .put("model", model)
            .put("instructions", prompt.system)
            .put("input", prompt.user)
            .put("store", false)

        val data = postJson(url, config, null, body, indicator, "OpenAI Responses API")
        return extractResponsesText(data)
    }

    private fun requestGeminiCommitMessage(
        config: SnowApiConfig,
        model: String,
        prompt: CommitPrompt,
        indicator: ProgressIndicator,
    ): String {
        val baseUrl = if (config.baseUrl.isNotBlank() && config.baseUrl != "https://api.openai.com/v1") {
            trimTrailingSlash(config.baseUrl)
        } else {
            "https://generativelanguage.googleapis.com/v1beta"
        }
        val modelName = if (model.startsWith("models/")) model else "models/$model"
        val body = JSONObject()
            .put(
                "contents",
                JSONArray().put(
                    JSONObject()
                        .put("role", "user")
                        .put("parts", JSONArray().put(JSONObject().put("text", "${prompt.system}\n\n${prompt.user}"))),
                ),
            )
            .put(
                "generationConfig",
                JSONObject()
                    .put("temperature", 0.2),
            )

        val data = postJson("$baseUrl/$modelName:generateContent", config, "gemini", body, indicator, "Gemini API")
        return data.optJSONArray("candidates")
            ?.optJSONObject(0)
            ?.optJSONObject("content")
            ?.optJSONArray("parts")
            ?.joinTextParts()
            .orEmpty()
    }

    private fun requestAnthropicCommitMessage(
        config: SnowApiConfig,
        model: String,
        prompt: CommitPrompt,
        indicator: ProgressIndicator,
    ): String {
        val baseUrl = if (config.baseUrl.isNotBlank() && config.baseUrl != "https://api.openai.com/v1") {
            trimTrailingSlash(config.baseUrl)
        } else {
            "https://api.anthropic.com/v1"
        }
        val body = JSONObject()
            .put("model", model)
            .put("max_tokens", 4_096)
            .put("temperature", 0.2)
            .put("system", prompt.system)
            .put("messages", JSONArray().put(JSONObject().put("role", "user").put("content", prompt.user)))

        val data = postJson("$baseUrl/messages", config, "anthropic", body, indicator, "Anthropic API")
        return data.optJSONArray("content")?.joinTextParts().orEmpty()
    }

    private fun postJson(
        url: String,
        config: SnowApiConfig,
        provider: String?,
        body: JSONObject,
        indicator: ProgressIndicator,
        apiName: String,
    ): JSONObject {
        indicator.checkCanceled()
        val requestBuilder = HttpRequest.newBuilder(URI.create(url))
            .timeout(Duration.ofSeconds(config.streamIdleTimeoutSec?.coerceAtLeast(1) ?: 120))
            .POST(HttpRequest.BodyPublishers.ofString(body.toString()))

        buildHeaders(config, provider).forEach { (key, value) ->
            if (isRestrictedHeader(key)) {
                logger.warn("Skip restricted header: $key")
                return@forEach
            }
            requestBuilder.header(key, value)
        }

        val response = httpClient.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString())
        indicator.checkCanceled()

        if (response.statusCode() !in 200..299) {
            throw ApiRequestException(
                "$apiName error: ${response.statusCode()} - ${response.body()}",
                response.statusCode(),
                response.body(),
            )
        }

        return JSONObject(response.body())
    }

    private fun buildHeaders(config: SnowApiConfig, provider: String?): Map<String, String> {
        val headers = linkedMapOf<String, String>()
        headers["Content-Type"] = "application/json"
        headers.putAll(loadCustomHeaders(config))

        if (config.apiKey.isNotBlank()) {
            headers["Authorization"] = "Bearer ${config.apiKey}"
        }
        if (provider == "gemini" && config.apiKey.isNotBlank()) {
            headers["x-goog-api-key"] = config.apiKey
        }
        if (provider == "anthropic") {
            if (config.apiKey.isNotBlank()) {
                headers["x-api-key"] = config.apiKey
            }
            if (headers.keys.none { it.equals("anthropic-version", ignoreCase = true) }) {
                headers["anthropic-version"] = "2023-06-01"
            }
        }
        return headers
    }

    private fun isRestrictedHeader(name: String): Boolean {
        val lower = name.lowercase()
        return lower in RESTRICTED_HEADERS
    }


    private fun loadActiveSnowConfig(): SnowApiConfig {
        val configDir = File(System.getProperty("user.home"), ".snow")
        val activeProfile = getActiveProfileName(configDir)
        val profilePath = File(File(configDir, "profiles"), "$activeProfile.json")
        val appConfig = readJsonFile(profilePath) ?: readJsonFile(File(configDir, "config.json"))
        val snowConfig = appConfig?.optJSONObject("snowcfg")
            ?: throw IllegalStateException("Snow configuration not found.")

        return SnowApiConfig(
            baseUrl = snowConfig.optString("baseUrl", "").trim(),
            apiKey = snowConfig.optString("apiKey", ""),
            requestMethod = snowConfig.optString("requestMethod", "chat"),
            basicModel = snowConfig.optString("basicModel", "").trim(),
            streamIdleTimeoutSec = if (snowConfig.has("streamIdleTimeoutSec")) snowConfig.optLong("streamIdleTimeoutSec") else null,
            customHeadersSchemeId = if (snowConfig.has("customHeadersSchemeId") && !snowConfig.isNull("customHeadersSchemeId")) {
                snowConfig.optString("customHeadersSchemeId")
            } else {
                null
            },
        )
    }

    private fun getActiveProfileName(configDir: File): String {
        val activeProfile = readJsonFile(File(configDir, "active-profile.json"))?.optString("activeProfile", "")
        if (!activeProfile.isNullOrBlank()) {
            return activeProfile
        }

        val legacyActiveProfile = File(configDir, "active-profile.txt")
        if (legacyActiveProfile.exists()) {
            return legacyActiveProfile.readText().trim().ifEmpty { "default" }
        }

        return "default"
    }

    private fun readJsonFile(file: File): JSONObject? {
        if (!file.exists()) {
            return null
        }
        return try {
            JSONObject(file.readText())
        } catch (_: Exception) {
            null
        }
    }

    private fun loadCustomHeaders(config: SnowApiConfig): Map<String, String> {
        val customHeadersConfig = readJsonFile(File(File(System.getProperty("user.home"), ".snow"), "custom-headers.json"))
            ?: return emptyMap()
        val schemeId = config.customHeadersSchemeId ?: customHeadersConfig.optString("active", "")
        if (schemeId.isBlank()) {
            return emptyMap()
        }

        val schemes = customHeadersConfig.optJSONArray("schemes") ?: return emptyMap()
        for (index in 0 until schemes.length()) {
            val scheme = schemes.optJSONObject(index) ?: continue
            if (scheme.optString("id", "") != schemeId) {
                continue
            }
            val headersObject = scheme.optJSONObject("headers") ?: return emptyMap()
            val headers = linkedMapOf<String, String>()
            val keys = headersObject.keys()
            while (keys.hasNext()) {
                val key = keys.next()
                headers[key] = headersObject.optString(key, "")
            }
            return headers
        }

        return emptyMap()
    }

    private fun buildPrompt(payload: DiffPayload, additionalRequirements: String?): CommitPrompt {
        val sourceLabel = if (payload.source == DiffSource.STAGED) "staged" else "working tree"
        val truncatedNotice = if (payload.truncated) "\n\nNote: The diff was truncated because it is large." else ""
        val requirementNotice = additionalRequirements?.trim()
            ?.takeIf { it.isNotEmpty() }
            ?.let { "\n\nAdditional requirements from the user:\n$it" }
            .orEmpty()

        return CommitPrompt(
            system = listOf(
                "You generate clear Git commit messages.",
                "Return only the final commit message, with no markdown, no quotes, and no explanation.",
                "Use an appropriate level of detail for the changes; include a body when it helps explain important context.",
                "Prefer Conventional Commit style when it fits, for example: feat: add login validation.",
            ).joinToString(" "),
            user = "Generate one commit message for the $sourceLabel changes below.$truncatedNotice$requirementNotice\n\n${payload.diff}",
        )
    }

    private fun normalizeCommitMessage(message: String): String {
        val normalized = message
            .trim()
            .replace(Regex("^```(?:[\\w-]+)?\\s*"), "")
            .replace(Regex("```$"), "")
            .trim()
            .replace(Regex("^[\\\"']|[\\\"']$"), "")
            .replace(Regex("^commit message:\\s*", RegexOption.IGNORE_CASE), "")
            .trim()

        if (normalized.isEmpty()) {
            throw IllegalStateException("The model returned an empty commit message.")
        }
        return normalized
    }

    private fun extractResponsesText(data: JSONObject): String {
        val outputText = data.optString("output_text", "")
        if (outputText.isNotEmpty()) {
            return outputText
        }

        val output = data.optJSONArray("output") ?: return ""
        val result = StringBuilder()
        for (index in 0 until output.length()) {
            val item = output.optJSONObject(index) ?: continue
            val content = item.optJSONArray("content") ?: continue
            result.append(content.joinTextParts())
        }
        return result.toString()
    }

    private fun JSONArray.joinTextParts(): String {
        val result = StringBuilder()
        for (index in 0 until length()) {
            val part = optJSONObject(index) ?: continue
            if (part.has("text")) {
                result.append(part.optString("text", ""))
            }
        }
        return result.toString()
    }

    private fun <T> withApiRetry(indicator: ProgressIndicator, request: () -> T): T {
        var lastError: Throwable? = null
        for (attempt in 0..API_MAX_RETRIES) {
            indicator.checkCanceled()
            try {
                return request()
            } catch (error: ProcessCanceledException) {
                throw error
            } catch (error: Throwable) {
                lastError = error
                if (!isRetriableApiError(error) || attempt >= API_MAX_RETRIES) {
                    throw error
                }
                delay(API_RETRY_BASE_DELAY_MS * (1L shl attempt), indicator)
            }
        }
        throw lastError ?: IllegalStateException("Commit message request failed.")
    }

    private fun isRetriableApiError(error: Throwable): Boolean {
        if (error is ApiRequestException) {
            return error.status == 429 || error.status >= 500
        }

        val message = error.message?.lowercase().orEmpty()
        return listOf(
            "network",
            "econnrefused",
            "econnreset",
            "etimedout",
            "timeout",
            "rate limit",
            "too many requests",
            "service unavailable",
            "temporarily unavailable",
            "bad gateway",
            "gateway timeout",
            "internal server error",
        ).any { message.contains(it) }
    }

    private fun delay(ms: Long, indicator: ProgressIndicator) {
        var remaining = ms
        while (remaining > 0) {
            indicator.checkCanceled()
            val step = min(remaining, 100L)
            Thread.sleep(step)
            remaining -= step
        }
    }

    private fun requireBaseUrl(config: SnowApiConfig): String {
        if (config.baseUrl.isBlank()) {
            throw IllegalStateException("Base URL is not configured.")
        }
        return trimTrailingSlash(config.baseUrl)
    }

    private fun trimTrailingSlash(value: String): String = value.replace(Regex("/+$"), "")

    private fun notify(message: String, type: NotificationType) {
        ApplicationManager.getApplication().invokeLater {
            NotificationGroupManager.getInstance()
                .getNotificationGroup("Snow CLI")
                .createNotification(message, type)
                .notify(project)
        }
    }
}

private data class DiffPayload(
    val diff: String,
    val source: DiffSource,
    val truncated: Boolean,
)

private enum class DiffSource {
    STAGED,
    WORKING_TREE,
}

private data class CommitPrompt(
    val system: String,
    val user: String,
)

private data class SnowApiConfig(
    val baseUrl: String,
    val apiKey: String,
    val requestMethod: String,
    val basicModel: String,
    val streamIdleTimeoutSec: Long?,
    val customHeadersSchemeId: String?,
)

private class ApiRequestException(
    message: String,
    val status: Int,
    val responseText: String,
) : RuntimeException(message)


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/toolwindow/SnowToolWindowFactory.kt
================================================
package com.snow.plugin.toolwindow

import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.ToolWindow
import com.intellij.openapi.wm.ToolWindowFactory
import com.intellij.openapi.wm.ex.ToolWindowManagerListener
import com.intellij.ui.components.JBLabel
import com.intellij.ui.content.ContentFactory
import com.snow.plugin.SnowWebSocketManager
import com.snow.plugin.util.TerminalCompat
import java.awt.BorderLayout
import javax.swing.JPanel

class SnowToolWindowFactory : ToolWindowFactory, DumbAware {
    companion object {
        private val isLaunching = mutableMapOf<String, Boolean>()
    }
    
    override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
        val contentPanel = JPanel(BorderLayout())
        val label = JBLabel("Snow CLI will launch when you open this window", javax.swing.SwingConstants.CENTER)
        contentPanel.add(label, BorderLayout.CENTER)
        
        val contentFactory = ContentFactory.getInstance()
        val content = contentFactory.createContent(contentPanel, "", false)
        toolWindow.contentManager.addContent(content)
        
        val projectKey = project.basePath ?: project.name
        val connection = project.messageBus.connect()
        
        connection.subscribe(ToolWindowManagerListener.TOPIC, object : ToolWindowManagerListener {
            override fun stateChanged(toolWindowManager: com.intellij.openapi.wm.ToolWindowManager) {
                if (toolWindow.isVisible) {
                    synchronized(isLaunching) {
                        if (isLaunching[projectKey] != true) {
                            isLaunching[projectKey] = true
                            launchSnowCLI(project, toolWindow, projectKey)
                        }
                    }
                }
            }
        })
    }
    
    private fun launchSnowCLI(project: Project, toolWindow: ToolWindow, projectKey: String) {
        ApplicationManager.getApplication().invokeLater {
            try {
                TerminalCompat.openTerminalWithCommand(project, project.basePath, "Snow CLI", "snow")

                ApplicationManager.getApplication().invokeLater {
                    toolWindow.hide(null)
                    synchronized(isLaunching) {
                        isLaunching[projectKey] = false
                    }
                }
            } catch (_: Exception) {
                synchronized(isLaunching) {
                    isLaunching[projectKey] = false
                }
            }
        }
        
        val wsManager = SnowWebSocketManager.instance
        ApplicationManager.getApplication().executeOnPooledThread {
            Thread.sleep(500)
            wsManager.connect()
        }
    }
}


================================================
FILE: JetBrains/src/main/kotlin/com/snow/plugin/util/TerminalCompat.kt
================================================
package com.snow.plugin.util

import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.ToolWindowManager

/**
 * Compatibility layer for terminal API across IntelliJ versions.
 * Uses Reworked Terminal API (2025.3+) when available, falls back to classic API via reflection.
 */
object TerminalCompat {

    @Volatile
    private var lastTerminalRef: Any? = null

    fun openTerminalWithCommand(project: Project, workingDirectory: String?, tabName: String, command: String) {
        if (!tryReworkedApi(project, workingDirectory, tabName, command)) {
            fallbackClassicApi(project, workingDirectory, tabName, command)
        }
    }

    /**
     * Send text to an existing Snow CLI terminal (without pressing Enter).
     * Uses saved terminal reference first, falls back to component tree search.
     */
    fun sendTextToNamedTerminal(project: Project, tabName: String, text: String): Boolean {
        // Strategy 1: use the saved reference from openTerminalWithCommand
        lastTerminalRef?.let { ref ->
            if (trySendTextViaRef(ref, text)) {
                activateTerminalTab(project, tabName)
                return true
            }
        }

        // Strategy 2: search component tree in the matching terminal tab
        val toolWindow = ToolWindowManager.getInstance(project).getToolWindow("Terminal")
            ?: return false
        val content = toolWindow.contentManager.contents.firstOrNull {
            it.displayName == tabName || it.displayName.contains("Snow", ignoreCase = true)
        } ?: return false

        toolWindow.contentManager.setSelectedContent(content)
        toolWindow.activate(null, false, false)
        return sendTextToComponentTree(content.component, text)
    }

    private fun trySendTextViaRef(ref: Any, text: String): Boolean {
        // Reworked API: TerminalView.sendText(String)
        try {
            ref.javaClass.getMethod("sendText", String::class.java).invoke(ref, text)
            return true
        } catch (_: Exception) {}

        // Classic API: widget.getTtyConnector().write(String)
        try {
            val connector = ref.javaClass.getMethod("getTtyConnector").invoke(ref)
            if (connector != null) {
                connector.javaClass.getMethod("write", String::class.java).invoke(connector, text)
                return true
            }
        } catch (_: Exception) {}

        return false
    }

    private fun activateTerminalTab(project: Project, tabName: String) {
        val toolWindow = ToolWindowManager.getInstance(project).getToolWindow("Terminal") ?: return
        val content = toolWindow.contentManager.contents.firstOrNull {
            it.displayName == tabName || it.displayName.contains("Snow", ignoreCase = true)
        }
        if (content != null) {
            toolWindow.contentManager.setSelectedContent(content)
        }
        toolWindow.activate(null, false, false)
    }

    private fun sendTextToComponentTree(root: java.awt.Component, text: String): Boolean {
        if (trySendTextViaComponent(root, text)) return true
        if (root is java.awt.Container) {
            for (i in 0 until root.componentCount) {
                if (sendTextToComponentTree(root.getComponent(i), text)) return true
            }
        }
        return false
    }

    private fun trySendTextViaComponent(component: Any, text: String): Boolean {
        val className = component.javaClass.name
        if (className.startsWith("javax.swing.") || className.startsWith("java.awt.")) return false

        try {
            val connector = component.javaClass.getMethod("getTtyConnector").invoke(component)
            if (connector != null) {
                connector.javaClass.getMethod("write", String::class.java).invoke(connector, text)
                return true
            }
        } catch (_: Exception) {}

        try {
            component.javaClass.getMethod("sendText", String::class.java).invoke(component, text)
            return true
        } catch (_: Exception) {}

        return false
    }

    private fun tryReworkedApi(
        project: Project, workingDirectory: String?, tabName: String, command: String
    ): Boolean {
        return try {
            val mgrClass = Class.forName(
                "com.intellij.terminal.frontend.toolwindow.TerminalToolWindowTabsManager"
            )
            val mgr = mgrClass.getMethod("getInstance", Project::class.java).invoke(null, project)

            val bClass = Class.forName(
                "com.intellij.terminal.frontend.toolwindow.TerminalToolWindowTabBuilder"
            )
            var b: Any = mgrClass.getMethod("createTabBuilder").invoke(mgr)!!
            b = bClass.getMethod("workingDirectory", String::class.java).invoke(b, workingDirectory)!!
            b = bClass.getMethod("tabName", String::class.java).invoke(b, tabName)!!
            b = bClass.getMethod("requestFocus", java.lang.Boolean.TYPE).invoke(b, true)!!
            b = bClass.getMethod("deferSessionStartUntilUiShown", java.lang.Boolean.TYPE).invoke(b, true)!!
            val tab = bClass.getMethod("createTab").invoke(b)!!

            val tClass = Class.forName("com.intellij.terminal.frontend.toolwindow.TerminalToolWindowTab")
            val view = tClass.getMethod("getView").invoke(tab)!!
            val vClass = Class.forName("com.intellij.terminal.frontend.view.TerminalView")

            lastTerminalRef = view

            scheduleCommand {
                vClass.getMethod("sendText", String::class.java).invoke(view, "$command\n")
            }
            true
        } catch (_: Exception) {
            false
        }
    }

    private fun fallbackClassicApi(
        project: Project, workingDirectory: String?, tabName: String, command: String
    ) {
        try {
            val mgrClass = Class.forName("org.jetbrains.plugins.terminal.TerminalToolWindowManager")
            val mgr = mgrClass.getMethod("getInstance", Project::class.java).invoke(null, project)
            val widget = mgrClass.getMethod(
                "createShellWidget",
                String::class.java, String::class.java,
                java.lang.Boolean.TYPE, java.lang.Boolean.TYPE
            ).invoke(mgr, workingDirectory, tabName, true, true)!!

            lastTerminalRef = widget

            scheduleCommand {
                widget.javaClass.getMethod("sendCommandToExecute", String::class.java)
                    .invoke(widget, command)
            }
        } catch (_: Exception) {
        }
    }

    private fun scheduleCommand(action: () -> Unit) {
        ApplicationManager.getApplication().executeOnPooledThread {
            try {
                Thread.sleep(1000)
                ApplicationManager.getApplication().invokeLater {
                    try {
                        action()
                    } catch (_: Exception) {
                    }
                }
            } catch (_: Exception) {
            }
        }
    }
}


================================================
FILE: JetBrains/src/main/kotlin/icons/SnowPluginIcons.kt
================================================
package icons

import com.intellij.icons.AllIcons
import com.intellij.openapi.util.IconLoader
import java.awt.Component
import java.awt.Graphics
import java.awt.Graphics2D
import java.awt.RenderingHints
import javax.swing.Icon
import kotlin.math.min

/**
 * Icon loader for Snow CLI plugin
 * Must be in 'icons' package and class name must end with 'Icons'
 */
object SnowPluginIcons {
    @JvmField
    val SnowAction: Icon = IconLoader.getIcon("/icons/snow.png", SnowPluginIcons::class.java)

    @JvmField
    val SnowToolbarAction: Icon = BoundedSquareIcon(SnowAction, 16)

    @JvmField
    val SnowStopToolbarAction: Icon = BoundedSquareIcon(AllIcons.Actions.Suspend, 16)
}

private class BoundedSquareIcon(
    private val source: Icon,
    private val size: Int,
) : Icon {
    override fun getIconWidth(): Int = size

    override fun getIconHeight(): Int = size

    override fun paintIcon(component: Component?, graphics: Graphics, x: Int, y: Int) {
        if (source.iconWidth <= 0 || source.iconHeight <= 0) {
            source.paintIcon(component, graphics, x, y)
            return
        }

        val graphics2d = graphics.create() as Graphics2D
        try {
            graphics2d.setRenderingHint(
                RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BICUBIC,
            )
            graphics2d.setRenderingHint(
                RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY,
            )

            val scale = min(
                size.toDouble() / source.iconWidth.toDouble(),
                size.toDouble() / source.iconHeight.toDouble(),
            )
            val scaledWidth = source.iconWidth * scale
            val scaledHeight = source.iconHeight * scale
            graphics2d.translate(
                x + (size - scaledWidth) / 2.0,
                y + (size - scaledHeight) / 2.0,
            )
            graphics2d.scale(scale, scale)
            source.paintIcon(component, graphics2d, 0, 0)
        } finally {
            graphics2d.dispose()
        }
    }
}


================================================
FILE: JetBrains/src/main/resources/META-INF/plugin.xml
================================================
<!-- Plugin Configuration File. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html -->
<idea-plugin>
    <!-- Unique identifier of the plugin. It should be FQN. It cannot be changed between the plugin versions. -->
    <id>com.snow.plugin</id>

    <!-- Public plugin name should be written in Title Case.
         Guidelines: https://plugins.jetbrains.com/docs/marketplace/plugin-overview-page.html#plugin-name -->
    <name>Snow CLI</name>

    <!-- A displayed Vendor name or Organization ID displayed on the Plugins Page. -->
    <vendor email="maymay5jace@gmail.com" url="https://github.com/MayDay-wpf/snow-cli/tree/main/JetBrains">Snow AI</vendor>

    <!-- Description of the plugin displayed on the Plugin Page and IDE Plugin Manager.
         Simple HTML elements (text formatting, paragraphs, and lists) can be added inside of <![CDATA[ ]]> tag.
         Guidelines: https://plugins.jetbrains.com/docs/marketplace/plugin-overview-page.html#plugin-description -->
    <description><![CDATA[
    Snow AI CLI integration for JetBrains IDEs. Provides intelligent code navigation and search powered by AI.<br>
    <br>
    Features:<br>
    <ul>
      <li>WebSocket-based integration with Snow CLI</li>
      <li>Real-time editor context sharing</li>
      <li>Code diagnostics integration</li>
      <li>Go to definition support</li>
      <li>Find references support</li>
      <li>Document symbols extraction</li>
      <li>Automatic reconnection with exponential backoff</li>
    </ul>
  ]]></description>

    <!-- Product and plugin compatibility requirements.
         Read more: https://plugins.jetbrains.com/docs/intellij/plugin-compatibility.html -->
    <depends>com.intellij.modules.platform</depends>
    <depends>org.jetbrains.plugins.terminal</depends>

    <!-- Extension points defined by the plugin.
         Read more: https://plugins.jetbrains.com/docs/intellij/plugin-extension-points.html -->
    <extensions defaultExtensionNs="com.intellij">
        <notificationGroup id="Snow CLI" displayType="BALLOON"/>
        <toolWindow id="Snow CLI" 
                    secondary="false" 
                    anchor="right" 
                    icon="SnowPluginIcons.SnowAction"
                    factoryClass="com.snow.plugin.toolwindow.SnowToolWindowFactory"/>
        <postStartupActivity implementation="com.snow.plugin.SnowProjectActivity"/>
    </extensions>

    <actions>
        <!-- Add your actions here -->
        <action id="snow.OpenTerminal"
                class="com.snow.plugin.actions.OpenSnowTerminalAction"
                text="Snow CLI"
                description="Open Snow CLI in integrated terminal"
                icon="SnowPluginIcons.SnowAction">
            <add-to-group group-id="ToolsMenu" anchor="last"/>
            <keyboard-shortcut first-keystroke="control alt S" keymap="$default"/>
        </action>

        <action id="snow.GenerateCommitMessage"
                class="com.snow.plugin.actions.GenerateCommitMessageAction"
                text="Generate Commit Message"
                description="Generate a commit message with Snow CLI AI">
            <add-to-group group-id="Vcs.MessageActionGroup" anchor="first"/>
        </action>

        <action id="snow.SendToSnowCLI"
                class="com.snow.plugin.actions.SendToSnowCLIAction"
                text="Send to Snow CLI"
                description="Send file path to Snow CLI terminal input">
            <add-to-group group-id="EditorPopupMenu" anchor="last"/>
            <add-to-group group-id="EditorTabPopupMenu" anchor="last"/>
        </action>
    </actions>

    <applicationListeners>
        <listener class="com.snow.plugin.SnowPluginLifecycle"
                  topic="com.intellij.ide.AppLifecycleListener"/>
    </applicationListeners>
</idea-plugin>


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.


================================================
FILE: README.md
================================================
<div align="center">

<img src="docs/images/logo.png" alt="Snow AI CLI Logo" width="200"/>

# snow-ai

[![npm version](https://img.shields.io/npm/v/snow-ai.svg)](https://www.npmjs.com/package/snow-ai)
[![npm downloads](https://img.shields.io/npm/dm/snow-ai.svg)](https://www.npmjs.com/package/snow-ai)
[![license](https://img.shields.io/npm/l/snow-ai.svg)](https://github.com/MayDay-wpf/snow-cli/blob/main/LICENSE)
[![node](https://img.shields.io/node/v/snow-ai.svg)](https://nodejs.org/)

<a href="https://www.producthunt.com/products/snow-cli/launches/snow-cli?embed=true&amp;utm_source=badge-featured&amp;utm_medium=badge&amp;utm_campaign=badge-snow-cli" target="_blank" rel="noopener noreferrer"><img alt="Snow CLI - Agentic coding in your terminal | Product Hunt" width="250" height="54" src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=1084735&amp;theme=light&amp;t=1776848197707"></a>

**English** | [中文](README_zh.md)

**QQ Group**: 910298558

**Telegram**: [https://t.me/snow_cli](https://t.me/snow_cli)

**AI Community**: [https://linux.do](https://linux.do)

_Agentic coding in your terminal_

</div>

## Thanks Developer

<a href="https://github.com/MayDay-wpf/snow-cli/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=MayDay-wpf/snow-cli" />
</a>

![alt text](docs/images/image.png)

![alt text](docs/images/image2.png)

<h3>Recommend using fonts: <a href="https://github.com/SpaceTimee/Fusion-JetBrainsMapleMono">JetBrains Maple Mono NF</a> </3>

<h3>Recommended Terminal Combination for Windows Users</h3>

- **PowerShell 7+**: Modern cross-platform PowerShell, offering stronger features and better compatibility
  - GitHub: https://github.com/PowerShell/PowerShell
- **Windows Terminal**: Modern terminal application, supporting multi-tab, split-screen, and GPU accelerated rendering
  - GitHub: https://github.com/microsoft/terminal

**Installation**:

```bash
# Install using winget (built-in for Windows 10/11)
winget install Microsoft.PowerShell
winget install Microsoft.WindowsTerminal

# Or install using the Microsoft Store
```


## Documentation

- [Installation Guide](docs/usage/en/01.Installation%20Guide.md) - System requirements, installation (update, uninstall) steps, IDE extension installation
- [First Time Configuration](docs/usage/en/02.First%20Time%20Configuration.md) - API configuration, model selection, basic settings
- [Startup Parameters Guide](docs/usage/en/19.Startup%20Parameters%20Guide.md) - Command-line parameters explained, quick start modes, headless mode, async tasks, developer mode

### Advanced Configuration

- [Proxy and Browser Settings](docs/usage/en/03.Proxy%20and%20Browser%20Settings.md) - Network proxy configuration, browser usage settings
- [Codebase Setup](docs/usage/en/04.Codebase%20Setup.md) - Codebase integration, search configuration
- [Sub-Agent Configuration](docs/usage/en/05.Sub-Agent%20Configuration.md) - Sub-agent management, custom sub-agent configuration
- [Sensitive Commands Configuration](docs/usage/en/06.Sensitive%20Commands%20Configuration.md) - Sensitive command protection, custom command rules
- [Hooks Configuration](docs/usage/en/07.Hooks%20Configuration.md) - Workflow automation, hook types explanation, practical configuration examples
- [Theme Settings](docs/usage/en/08.Theme%20Settings.md) - Interface theme configuration, custom color schemes, simplified mode
- [Third-Party Relay Configuration](docs/usage/en/16.Third-Party%20Relay%20Configuration.md) - Claude Code relay, Codex relay, custom headers configuration

### Feature Guide

- [Command Panel Guide](docs/usage/en/09.Command%20Panel%20Guide.md) - Detailed description of all available commands, usage tips, shortcut key reference
- [Command Injection Mode](docs/usage/en/10.Command%20Injection%20Mode.md) - Execute commands directly in messages, syntax explanation, security mechanisms, use cases
- [Vulnerability Hunting Mode](docs/usage/en/11.Vulnerability%20Hunting%20Mode.md) - Professional security analysis, vulnerability detection, verification scripts, detailed reports
- [Headless Mode](docs/usage/en/12.Headless%20Mode.md) - Command line quick conversations, session management, script integration, third-party tool integration
- [Keyboard Shortcuts Guide](docs/usage/en/13.Keyboard%20Shortcuts%20Guide.md) - All keyboard shortcuts, editing operations, navigation control, rollback functionality
- [MCP Configuration](docs/usage/en/14.MCP%20Configuration.md) - MCP service management, configure external services, enable/disable services, troubleshooting
- [Async Task Management](docs/usage/en/15.Async%20Task%20Management.md) - Background task creation, task management interface, sensitive command approval, task to session conversion
- [Skills Command Detailed Guide](docs/usage/en/18.Skills%20Command%20Detailed%20Guide.md) - Skill creation, usage methods, Claude Code Skills compatibility, tool restrictions
- [LSP Configuration and Usage](docs/usage/en/17.LSP%20Configuration.md) - LSP config file, language server installation, ACE tool usage (definition/outline)
- [SSE Service Mode](docs/usage/en/20.SSE%20Service%20Mode.md) - SSE server startup, API endpoints explanation, tool confirmation flow, permission configuration, YOLO mode, client integration examples
- [Custom StatusLine Guide](docs/usage/en/21.Custom%20StatusLine%20Guide.md) - User-level StatusLine plugins, hook structure, override behavior, bilingual examples
- [Team Mode Guide](docs/usage/en/22.Team%20Mode%20Guide.md) - Multi-agent collaboration, parallel task execution, team management
- [Custom Search Engine Guide](docs/usage/en/23.Custom%20Search%20Engine%20Guide.md) - User-level search engine plugins, engine contract, enable flag, minimal template

### Recommended ROLE.md

- [Recommended ROLE.md](docs/role/en/01.Snow%20CLI%20Plan%20Every%20Step.md) - Recommended behavior guidelines, work mode, and quality standards for the Snow CLI terminal programming assistant
  - Bilingual documentation: English (primary) / [Chinese](docs/role/zh/01.Snow%20CLI%20一步一规划.md)
  - Maintenance rule: Keep Chinese and English structures aligned; tool names remain unchanged

---

## Development Guide

### Prerequisites

- **Node.js >= 18.x** (Requires ES2020 features support)
- npm >= 8.3.0

Check your Node.js version:

```bash
node --version
```

If your version is below 18.x, please upgrade first:

```bash
# Using nvm (recommended)
nvm install 18
nvm use 18

# Or download from official website
# https://nodejs.org/
```

### Build from Source

```bash
git clone https://github.com/MayDay-wpf/snow-cli.git
cd snow-cli
npm install
npm run link   # builds and globally links snow
# to remove the link later: npm run unlink
```

### IDE Extension Development

#### VSCode Extension

- Extension source located in `VSIX/` directory
- Download release: [mufasa.snow-cli](https://marketplace.visualstudio.com/items?itemName=mufasa.snow-cli)

#### JetBrains Plugin

- Plugin source located in `Jetbrains/` directory
- Download release: [JetBrains plugin](https://plugins.jetbrains.com/plugin/28715-snow-cli/edit)

### Project Structure

```
source/                     # Source code
├── agents/                 # AI agents implementation
├── api/                    # LLM API adapters
├── hooks/                  # React hooks for conversation
├── i18n/                   # Internationalization
├── mcp/                    # Model Context Protocol
├── prompt/                 # System prompt templates
├── types/                  # TypeScript type definitions
├── ui/                     # UI components (Ink)
└── utils/                  # Utility functions

bundle/                     # Build output (single-file executable)
dist/                       # TypeScript compilation output
docs/                       # Documentation
JetBrains/                  # JetBrains plugin source
scripts/                    # Build and utility scripts
VSIX/                       # VSCode extension source
```

### User Configuration Directory

After running snow, `.snow/` directory is created in your home folder:

```
~/.snow/                    # User configuration directory
├── log/                    # Runtime logs (local, can be deleted)
├── profiles/               # Configuration profiles
├── sessions/               # Conversation history
├── tasks/                  # Async tasks
├── hooks/                  # Workflow hooks
├── config.json             # API configuration
├── mcp-config.json         # MCP configuration
└── ...                     # Other config files
```

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=MayDay-wpf/snow-cli&type=Date)](https://star-history.com/#MayDay-wpf/snow-cli&Date)


================================================
FILE: README_zh.md
================================================
<div align="center">

<img src="docs/images/logo.png" alt="Snow AI CLI Logo" width="200"/>

# snow-ai

[![npm version](https://img.shields.io/npm/v/snow-ai.svg)](https://www.npmjs.com/package/snow-ai)
[![npm downloads](https://img.shields.io/npm/dm/snow-ai.svg)](https://www.npmjs.com/package/snow-ai)
[![license](https://img.shields.io/npm/l/snow-ai.svg)](https://github.com/MayDay-wpf/snow-cli/blob/main/LICENSE)
[![node](https://img.shields.io/node/v/snow-ai.svg)](https://nodejs.org/)

<a href="https://www.producthunt.com/products/snow-cli/launches/snow-cli?embed=true&amp;utm_source=badge-featured&amp;utm_medium=badge&amp;utm_campaign=badge-snow-cli" target="_blank" rel="noopener noreferrer"><img alt="Snow CLI - Agentic coding in your terminal | Product Hunt" width="250" height="54" src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=1084735&amp;theme=light&amp;t=1776848197707"></a>

[English](README.md) | **中文**

**QQ 群**: 910298558

**Telegram**: [https://t.me/snow_cli](https://t.me/snow_cli)

**AI 社区**: [https://linux.do](https://linux.do)

_在终端中进行 Agentic 编程_

</div>

## 感谢开发者

<a href="https://github.com/MayDay-wpf/snow-cli/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=MayDay-wpf/snow-cli" />
</a>

![alt text](docs/images/image_zh.png)

![alt text](docs/images/image_zh2.png)

<h3>推荐使用字体:<a href="https://github.com/SpaceTimee/Fusion-JetBrainsMapleMono">JetBrains Maple Mono NF</a> </3>

<h3>Windows 用户推荐终端组合</h3>

- **PowerShell 7+**: 现代化的跨平台 PowerShell,提供更强的功能和更好的兼容性
  - GitHub: https://github.com/PowerShell/PowerShell
- **Windows Terminal**: 现代化的终端应用程序,支持多标签、分屏、GPU 加速渲染
  - GitHub: https://github.com/microsoft/terminal

**安装方式**:

```bash
# 使用 winget 安装 (Windows 10/11 自带)
winget install Microsoft.PowerShell
winget install Microsoft.WindowsTerminal

# 或使用 Microsoft Store 安装
```
## 文档目录

- [安装指南](docs/usage/zh/01.安装指南.md) - 系统要求、安装(更新、卸载)步骤、IDE 扩展安装
- [首次配置](docs/usage/zh/02.首次配置.md) - API 配置、模型选择、基础设置
- [启动参数说明](docs/usage/zh/19.启动参数说明.md) - 命令行参数详解、快速启动模式、无头模式、异步任务、开发者模式

### 高级配置

- [代理和浏览器设置](docs/usage/zh/03.代理和浏览器设置.md) - 网络代理配置、浏览器使用设置
- [代码库设置](docs/usage/zh/04.代码库设置.md) - 代码库集成、搜索配置
- [子代理设置](docs/usage/zh/05.子代理设置.md) - 子代理管理、自定义子代理配置
- [敏感命令配置](docs/usage/zh/06.敏感命令配置.md) - 敏感命令保护、自定义命令规则
- [Hooks 配置](docs/usage/zh/07.Hooks配置.md) - 工作流程自动化、Hook 类型说明、实用配置示例
- [主题设置](docs/usage/zh/08.主题设置.md) - 界面主题配置、自定义配色、简洁模式
- [第三方中转配置](docs/usage/zh/16.第三方中转配置.md) - Claude Code 中转、Codex 中转、自定义请求头配置

### 功能指南

- [指令面板说明](docs/usage/zh/09.指令面板说明.md) - 所有可用指令的详细说明、使用技巧、快捷键参考
- [命令注入模式](docs/usage/zh/10.命令注入模式.md) - 消息中直接执行命令、语法说明、安全机制、使用场景
- [漏洞猎人模式](docs/usage/zh/11.漏洞猎人模式.md) - 专业安全分析、漏洞检测、验证脚本、详细报告
- [无头模式](docs/usage/zh/12.无头模式.md) - 命令行快速对话、会话管理、脚本集成、第三方工具集成
- [快捷键指南](docs/usage/zh/13.快捷键指南.md) - 所有快捷键说明、编辑操作、导航控制、回滚功能
- [MCP 配置](docs/usage/zh/14.MCP配置.md) - MCP 服务管理、配置外部服务、启用/禁用服务、故障排除
- [异步任务管理](docs/usage/zh/15.异步任务管理.md) - 后台任务创建、任务管理界面、敏感命令审批、任务转会话
- [Skills 指令详细说明](docs/usage/zh/18.Skills指令详细说明.md) - 技能创建、使用方法、Claude Code Skills 兼容性、工具限制
- [LSP 配置与用法](docs/usage/zh/17.LSP配置.md) - LSP 配置文件、语言服务器安装、ACE 工具用法(跳转/大纲)
- [SSE 服务模式](docs/usage/zh/20.SSE服务模式.md) - SSE 服务器启动、API 端点说明、工具确认流程、权限配置、YOLO 模式、客户端集成示例
- [自定义 StatusLine 指南](docs/usage/zh/21.自定义StatusLine指南.md) - 用户级状态栏插件、hook 结构、覆盖机制、中英文示例
- [Team 模式指南](docs/usage/zh/22.Team模式指南.md) - 多智能体协作、并行任务执行、团队管理
- [自定义搜索引擎指南](docs/usage/zh/23.自定义搜索引擎指南.md) - 用户级搜索引擎插件、引擎合约、enable 开关、最小模板示例

### 推荐使用的 ROLE.md

- [推荐使用的 ROLE.md](docs/role/zh/01.Snow%20CLI%20一步一规划.md) - Snow CLI 终端编程助手推荐使用的行为准则、工作模式与质量标准
  - 双语文档:中文(主版本)/[英文](docs/role/en/01.Snow%20CLI%20Plan%20Every%20Step.md)
  - 维护规则:保持中英文结构对齐,工具名称保持不变

---

## 开发指南

### 环境要求

- **Node.js >= 18.x** (需要 ES2020 特性支持)
- npm >= 8.3.0

检查你的 Node.js 版本:

```bash
node --version
```

如果版本低于 18.x,请先升级:

```bash
# 使用 nvm (推荐)
nvm install 18
nvm use 18

# 或从官网下载
# https://nodejs.org/
```

### 源码构建

```bash
git clone https://github.com/MayDay-wpf/snow-cli.git
cd snow-cli
npm install
npm run link   # 构建并全局链接 snow
# 之后删除链接: npm run unlink
```

### IDE 扩展开发

#### VSCode 扩展

- 扩展源码位于 `VSIX/` 目录
- 下载发布版: [mufasa.snow-cli](https://marketplace.visualstudio.com/items?itemName=mufasa.snow-cli)

#### JetBrains 插件

- 插件源码位于 `Jetbrains/` 目录
- 下载发布版: [JetBrains 插件](https://plugins.jetbrains.com/plugin/28715-snow-cli/edit)

### 项目结构

```
source/                     # 源代码
├── agents/                 # AI 代理实现
├── api/                    # LLM API 适配器
├── hooks/                  # 对话 React Hooks
├── i18n/                   # 国际化
├── mcp/                    # Model Context Protocol
├── prompt/                 # 系统提示词模板
├── types/                  # TypeScript 类型定义
├── ui/                     # UI 组件 (Ink)
└── utils/                  # 工具函数

bundle/                     # 构建输出(单文件可执行)
dist/                       # TypeScript 编译输出
docs/                       # 文档
JetBrains/                  # JetBrains 插件源码
scripts/                    # 构建和工具脚本
VSIX/                       # VSCode 扩展源码
```

### 用户配置目录

运行 snow 后,会在主目录创建 `.snow/` 文件夹:

```
~/.snow/                    # 用户配置目录
├── log/                    # 运行日志(本地,可删除)
├── profiles/               # 配置文件
├── sessions/               # 对话记录
├── tasks/                  # 异步任务
├── hooks/                  # 工作流钩子
├── config.json             # API 配置
├── mcp-config.json         # MCP 配置
└── ...                     # 其他配置文件
```

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=MayDay-wpf/snow-cli&type=Date)](https://star-history.com/#MayDay-wpf/snow-cli&Date)


================================================
FILE: VSIX/.vscodeignore
================================================
.vscode/**
.vscode-test/**
.tmp-vsix-check/**
src/**
out/**
node_modules/**
!node_modules/node-pty/**
!node_modules/node-pty/build/Release/*.node
!node_modules/node-pty/build/Release/*.dll
!node_modules/@xterm/**
!node_modules/@xterm/xterm/**
!node_modules/@xterm/xterm/css/**
!node_modules/@xterm/xterm/css/xterm.css
!node_modules/@xterm/xterm/lib/**
!node_modules/@xterm/xterm/lib/xterm.js
!node_modules/@xterm/addon-fit/**
!node_modules/@xterm/addon-fit/lib/**
!node_modules/@xterm/addon-fit/lib/addon-fit.js
!node_modules/ws/**
!node_modules/ws/lib/**
**/*.ts
!**/*.d.ts
**/*.map
**/tsconfig.json
**/.eslintrc.json
**/webpack.config.js
**/*.md
!README.md
**/test/**
**/tests/**
**/.git/**
.gitignore
.yarnrc
vsc-extension-quickstart.md

================================================
FILE: VSIX/LICENSE
================================================
MIT License

Copyright (c) 2025 Snow CLI

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: VSIX/README.md
================================================
# Snow CLI Extension with ACE Code Search

This extension provides seamless integration between VSCode and Snow AI CLI, featuring the powerful **ACE (Agentic Computer Environment) Code Search** system for intelligent code navigation.

## Features

### 🎯 Quick Access

- **One-click Terminal** - Button in editor toolbar to instantly launch Snow CLI
- **Auto-connection** - Automatic WebSocket connection to Snow CLI server
- **Real-time Sync** - Live editor context synchronization

### 🔍 ACE Code Search Integration

- **Go to Definition** - Leverage VSCode's language servers for precise symbol navigation
- **Find References** - Discover all symbol usages across your codebase
- **Document Symbols** - Get complete file outline with all functions, classes, and variables
- **Real-time Diagnostics** - Instant error and warning detection

### 🚀 Performance

- **Exponential Backoff** - Smart reconnection strategy
- **Context Caching** - Maintains state even when editor loses focus
- **Low Latency** - WebSocket communication for instant updates

## Requirements

Install Snow CLI globally:

```bash
npm install -g snow-ai
```

## Usage

### Basic Usage

1. Open any file in VSCode
2. Click the **Snow icon** button in the editor toolbar (top right)
3. A terminal opens with Snow CLI running
4. The extension automatically connects via WebSocket

#### Interface Preview

**English Interface:**

![English Interface](https://raw.githubusercontent.com/MayDay-wpf/snow-cli/main/VSIX/en.png)

**Chinese Interface:**

![Chinese Interface](https://raw.githubusercontent.com/MayDay-wpf/snow-cli/main/VSIX/zh.png)

### ACE Code Search Features

The extension enhances Snow CLI with VSCode's built-in language intelligence:

- **Symbol Navigation** - AI can request Go to Definition for any symbol
- **Reference Finding** - AI can find all references to functions/classes
- **Code Outline** - AI can get complete file structure
- **Error Detection** - AI receives real-time diagnostics

These features work automatically when Snow CLI uses ACE Code Search tools.

## Supported Languages

ACE Code Search supports:

- TypeScript/JavaScript
- Python
- Go
- Rust
- Java
- C#
- And more via VSCode language servers

## Extension Settings

This extension works out of the box with no configuration required.

Optional: Configure Snow CLI settings in `~/.snow/config.json`

## Architecture

```text
VSCode Extension (Port 9527)
    ↕ WebSocket
Snow CLI
    ↕ MCP Tools
ACE Code Search Engine
    ↕ Language Parsers
Your Codebase
```

## Known Issues

None currently. Please report issues on GitHub.

## Release Notes

### 0.3.0 - ACE Code Search Integration

**Major Update:**

- ✨ Added ACE Code Search integration
- 🎯 Go to Definition support via VSCode language servers
- 🔍 Find References across entire workspace
- 📋 Document symbol extraction
- 🔗 WebSocket message handlers for ACE features
- 📊 Enhanced diagnostic support

### 0.2.6

- Add automatic WebSocket reconnection with exponential backoff
- Improve connection stability
- Enhanced context caching for better reliability

---

## Learn More

- [Snow CLI GitHub](https://github.com/yourusername/snow-cli)
- [ACE Code Search Documentation](https://github.com/yourusername/snow-cli/blob/main/docs/ACE_CODE_SEARCH.md)

**Enjoy intelligent coding with Snow CLI + ACE Code Search!** 🚀


================================================
FILE: VSIX/package.json
================================================
{
	"name": "snow-cli",
	"displayName": "Snow CLI",
	"description": "Snow AI CLI with ACE Code Search - Intelligent code navigation and search powered by AI",
	"version": "0.4.23",
	"publisher": "mufasa",
	"repository": {
		"type": "git",
		"url": "https://github.com/MayDay-wpf/snow-cli"
	},
	"engines": {
		"vscode": "^1.106.0"
	},
	"categories": [
		"Other"
	],
	"activationEvents": [
		"onStartupFinished"
	],
	"main": "./dist/extension.js",
	"contributes": {
		"configuration": {
			"title": "Snow CLI",
			"properties": {
				"snow-cli.terminalMode": {
					"type": "string",
					"default": "sidebar",
					"enum": [
						"sidebar",
						"split"
					],
					"enumDescriptions": [
						"Embedded terminal in the sidebar (xterm.js + node-pty)",
						"Split editor right and open a terminal in the editor area"
					],
					"description": "Choose the terminal display mode. 'sidebar' embeds a terminal in the sidebar panel; 'split' opens a terminal in a right-side editor split."
				},
				"snow-cli.startupCommand": {
					"type": "string",
					"default": "snow",
					"description": "The command or comma-separated commands to run when terminals start. New terminals are assigned commands in round-robin order, and each terminal keeps its assigned command across restarts."
				},
				"snow-cli.terminal.shellType": {
					"type": "string",
					"default": "auto",
					"description": "Shell for the sidebar terminal. Use 'auto' to follow VS Code's default terminal profile, or enter a shell executable path (e.g. 'C:\\Program Files\\Git\\bin\\bash.exe', 'pwsh.exe', 'cmd.exe', '/usr/bin/zsh'). Falls back to PowerShell (Windows) or $SHELL (macOS/Linux) if the path is not found."
				},
				"snow-cli.terminal.proxyUrl": {
					"type": "string",
					"default": "",
					"description": "Optional proxy URL injected into Snow CLI terminals as HTTP_PROXY/HTTPS_PROXY. Leave empty to fall back to VS Code's http.proxy setting."
				},
				"snow-cli.terminal.fontFamily": {
					"type": "string",
					"default": "",
					"description": "Font family for the sidebar terminal. Leave empty to use the default monospace font."
				},
				"snow-cli.terminal.fontSize": {
					"type": "number",
					"default": 14,
					"minimum": 8,
					"maximum": 32,
					"description": "Font size (px) for the sidebar terminal."
				},
				"snow-cli.terminal.fontWeight": {
					"type": "string",
					"default": "normal",
					"enum": [
						"normal",
						"bold",
						"100",
						"200",
						"300",
						"400",
						"500",
						"600",
						"700",
						"800",
						"900"
					],
					"description": "Font weight for the sidebar terminal."
				},
				"snow-cli.terminal.lineHeight": {
					"type": "number",
					"default": 1,
					"minimum": 0.8,
					"maximum": 2,
					"description": "Line height for the sidebar terminal."
				},
				"snow-cli.gitBlame.enabled": {
					"type": "boolean",
					"default": false,
					"description": "Enable Git Blame annotations. Shows commit info (author, time, message) on the current line, similar to GitLens."
				},
				"snow-cli.bell.enabled": {
					"type": "boolean",
					"default": true,
					"description": "Enable terminal bell (BEL / \\x07) notifications. When disabled, both audio and visual feedback are suppressed."
				},
				"snow-cli.bell.volume": {
					"type": "number",
					"default": 0.5,
					"minimum": 0,
					"maximum": 1,
					"description": "Terminal bell volume (0.0 - 1.0). Set to 0 to mute audio while still allowing visual flash."
				},
				"snow-cli.bell.sound": {
					"type": "string",
					"default": "beep",
					"enum": [
						"beep",
						"ding",
						"chime",
						"pluck",
						"blip",
						"none"
					],
					"enumDescriptions": [
						"Short 800Hz sine beep (default classic terminal bell)",
						"Bright triangle-wave ding",
						"Two-tone descending chime",
						"Soft sawtooth pluck",
						"Quick high-frequency blip",
						"No sound (visual flash only)"
					],
					"description": "Bell sound style. Use 'none' to disable audio while keeping visual flash enabled."
				},
				"snow-cli.bell.visualFlash": {
					"type": "boolean",
					"default": true,
					"description": "Show a brief visual flash overlay on the terminal panel when the bell rings."
				}
			}
		},
		"viewsContainers": {
			"secondarySidebar": [
				{
					"id": "snow-cli-sidebar",
					"title": "Snow CLI",
					"icon": "snow.png"
				}
			]
		},
		"views": {
			"snow-cli-sidebar": [
				{
					"type": "webview",
					"id": "snowCliTerminal",
					"name": "Terminal",
					"icon": "snow.png",
					"when": "snow-cli.sidebarMode"
				}
			]
		},
		"commands": [
			{
				"command": "snow-cli.openTerminal",
				"title": "Open Snow CLI",
				"icon": {
					"light": "./snow.png",
					"dark": "./snow.png"
				}
			},
			{
				"command": "snow-cli.restartSidebarTerminal",
				"title": "Restart Terminal",
				"icon": "$(debug-rerun)"
			},
			{
				"command": "snow-cli.newSidebarTerminalTab",
				"title": "New Terminal Tab",
				"icon": "$(add)"
			},
			{
				"command": "snow-cli.addFolderPath",
				"title": "Add Folder Path",
				"icon": "$(file-symlink-directory)"
			},
			{
				"command": "snow-cli.addFilePath",
				"title": "Add File Path",
				"icon": "$(file-symlink-file)"
			},
			{
				"command": "snow-cli.openSnowSettings",
				"title": "Snow CLI Settings",
				"icon": "$(settings-gear)"
			},
			{
				"command": "snow-cli.focusSidebar",
				"title": "Focus Snow CLI Sidebar"
			},
			{
				"command": "snow-cli.sendFilePaths",
				"title": "Send to Snow CLI",
				"icon": "$(file-symlink-file)"
			},
			{
				"command": "snow-cli.sendSelectionLocation",
				"title": "Send to Snow CLI",
				"icon": "$(file-symlink-file)"
			},
			{
				"command": "snow-cli.toggleGitBlame",
				"title": "Snow CLI: Toggle Git Blame",
				"icon": "$(git-commit)"
			},
			{
				"command": "snow-cli.toggleFileAnnotations",
				"title": "Snow CLI: Toggle File Annotations",
				"icon": "$(list-flat)"
			},
			{
				"command": "snow-cli.generateCommitMessage",
				"title": "Snow CLI: Generate Commit Message",
				"icon": {
					"light": "./snow.png",
					"dark": "./snow.png"
				}
			},
			{
				"command": "snow-cli.generateCommitMessageWithRequirements",
				"title": "Snow CLI: Generate Commit Message with Requirements",
				"icon": "$(comment)"
			},
			{
				"command": "snow-cli.cancelCommitMessageGeneration",
				"title": "Snow CLI: Stop Generating Commit Message",
				"icon": "$(debug-stop)"
			}
		],
		"submenus": [
			{
				"id": "snow-cli.insertPathActions",
				"label": "Insert Path",
				"icon": "$(attach)"
			}
		],
		"keybindings": [
			{
				"command": "snow-cli.focusSidebar",
				"key": "ctrl+alt+s",
				"mac": "cmd+alt+s"
			}
		],
		"menus": {
			"scm/title": [
				{
					"command": "snow-cli.generateCommitMessage",
					"alt": "snow-cli.generateCommitMessageWithRequirements",
					"when": "!snow-cli.commitMessageGenerating",
					"group": "navigation@1"
				},
				{
					"command": "snow-cli.generateCommitMessageWithRequirements",
					"when": "!snow-cli.commitMessageGenerating",
					"group": "snow@1"
				},
				{
					"command": "snow-cli.cancelCommitMessageGeneration",
					"when": "snow-cli.commitMessageGenerating",
					"group": "navigation@1"
				}
			],
			"editor/title": [
				{
					"command": "snow-cli.openTerminal",
					"group": "navigation"
				}
			],
			"view/title": [
				{
					"command": "snow-cli.restartSidebarTerminal",
					"when": "view == snowCliTerminal && snow-cli.sidebarMode",
					"group": "navigation@1"
				},
				{
					"command": "snow-cli.newSidebarTerminalTab",
					"when": "view == snowCliTerminal && snow-cli.sidebarMode",
					"group": "navigation@2"
				},
				{
					"command": "snow-cli.openSnowSettings",
					"when": "view == snowCliTerminal && snow-cli.sidebarMode",
					"group": "navigation@3"
				},
				{
					"submenu": "snow-cli.insertPathActions",
					"when": "view == snowCliTerminal && snow-cli.sidebarMode",
					"group": "navigation@4"
				}
			],
			"snow-cli.insertPathActions": [
				{
					"command": "snow-cli.addFolderPath",
					"group": "navigation@1"
				},
				{
					"command": "snow-cli.addFilePath",
					"group": "navigation@2"
				}
			],
			"explorer/context": [
				{
					"command": "snow-cli.sendFilePaths",
					"group": "snow@1"
				}
			],
			"editor/title/context": [
				{
					"command": "snow-cli.sendFilePaths",
					"when": "resourceScheme == file || resourceScheme == vscode-remote",
					"group": "snow@1"
				}
			],
			"editor/context": [
				{
					"command": "snow-cli.sendSelectionLocation",
					"when": "editorHasSelection && (resourceScheme == file || resourceScheme == vscode-remote)",
					"group": "snow@1"
				}
			]
		}
	},
	"scripts": {
		"vscode:prepublish": "npm run package",
		"compile": "webpack",
		"watch": "webpack --watch",
		"package": "webpack --mode production --devtool hidden-source-map",
		"rebuild": "npm rebuild node-pty",
		"lint": "eslint src --ext ts",
		"pretest": "npm run compile && npm run lint",
		"test": "node ./out/test/runTest.js"
	},
	"dependencies": {
		"@xterm/addon-fit": "^0.11.0",
		"@xterm/addon-search": "^0.16.0",
		"@xterm/addon-unicode11": "^0.9.0",
		"@xterm/addon-web-links": "^0.12.0",
		"@xterm/addon-webgl": "^0.19.0",
		"@xterm/xterm": "^6.0.0",
		"node-pty": "1.2.0-beta.10",
		"ws": "^8.14.2"
	},
	"devDependencies": {
		"@types/node": "20.x",
		"@types/vscode": "^1.75.0",
		"@types/ws": "^8.5.8",
		"@vscode/vsce": "^2.22.0",
		"ts-loader": "^9.5.0",
		"typescript": "^5.3.0",
		"webpack": "^5.90.0",
		"webpack-cli": "^5.1.0"
	},
	"icon": "snow.png"
}


================================================
FILE: VSIX/res/sidebarTerminal.css
================================================
:root {
	--terminal-bg: #181818;
	--terminal-drag-outline: #007acc;
	--terminal-error: #f14c4c;
	--terminal-border: var(--vscode-panel-border, rgba(255, 255, 255, 0.12));
	--terminal-toolbar-bg: var(--vscode-sideBar-background, #181818);
	--terminal-button-bg: var(
		--vscode-button-secondaryBackground,
		rgba(255, 255, 255, 0.08)
	);
	--terminal-button-fg: var(--vscode-button-secondaryForeground, #cccccc);
	--terminal-button-hover-bg: var(
		--vscode-button-secondaryHoverBackground,
		rgba(255, 255, 255, 0.14)
	);
	--terminal-button-border: var(--vscode-contrastBorder, transparent);
	--terminal-tab-height: 26px;
}

* {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}

html,
body {
	height: 100%;
	width: 100%;
}

body {
	overflow: hidden;
	background-color: var(--terminal-bg);
}

#terminal-root {
	height: 100%;
	width: 100%;
	display: flex;
	flex-direction: column;
	min-height: 0;
}

#terminal-tab-strip {
	display: flex;
	gap: 0;
	padding: 0;
	border-bottom: 1px solid var(--terminal-border);
	background-color: var(
		--vscode-editorGroupHeader-tabsBackground,
		var(--terminal-toolbar-bg)
	);
	flex: 0 0 auto;
	overflow-x: auto;
	scrollbar-width: none;
}

#terminal-tab-strip:empty {
	display: none;
}

.terminal-tab-item {
	display: inline-flex;
	align-items: stretch;
	flex: 0 0 auto;
	min-height: var(--terminal-tab-height);
	white-space: nowrap;
	background-color: var(--vscode-tab-inactiveBackground, transparent);
	color: var(--vscode-tab-inactiveForeground, var(--terminal-button-fg));
	border-right: 1px solid var(--terminal-border);
}

.terminal-tab-item:hover:not(.is-active):not(.is-restarting) {
	background-color: var(
		--vscode-tab-hoverBackground,
		var(--terminal-button-hover-bg)
	);
}

.terminal-tab-item.is-active,
.terminal-tab-item.is-restarting {
	background-color: var(--vscode-tab-activeBackground, var(--terminal-bg));
	color: var(--vscode-tab-activeForeground, var(--terminal-button-fg));
}

.terminal-tab {
	appearance: none;
	border: none;
	background: transparent;
	color: inherit;
	font: inherit;
	font-size: 12px;
	line-height: 1.2;
	padding: 0 6px 0 8px;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	min-height: var(--terminal-tab-height);
	white-space: nowrap;
}

.terminal-tab-label {
	overflow: hidden;
	text-overflow: ellipsis;
}

.terminal-tab-close {
	appearance: none;
	border: none;
	background: transparent;
	color: inherit;
	font: inherit;
	font-size: 13px;
	line-height: 1;
	padding: 0;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 18px;
	min-width: 18px;
	min-height: var(--terminal-tab-height);
	flex: 0 0 18px;
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
}

.terminal-tab-item.is-active .terminal-tab-close,
.terminal-tab-item.is-restarting .terminal-tab-close {
	opacity: 1;
	visibility: visible;
}

.terminal-tab-item.is-active .terminal-tab-close {
	pointer-events: auto;
}

.terminal-tab-item.is-restarting .terminal-tab-close {
	pointer-events: none;
	cursor: default;
}

.terminal-tab-close:hover {
	background-color: var(--terminal-button-hover-bg);
}

.terminal-tab:focus-visible,
.terminal-tab-close:focus-visible {
	outline: 1px solid var(--vscode-focusBorder, #007acc);
	outline-offset: -1px;
}

.terminal-tab-spinner {
	width: 10px;
	height: 10px;
	border: 1.5px solid currentColor;
	border-right-color: transparent;
	border-radius: 50%;
	animation: terminal-tab-spinner-spin 0.8s linear infinite;
}

@keyframes terminal-tab-spinner-spin {
	to {
		transform: rotate(360deg);
	}
}

#terminal-toolbar {
	display: flex;
	gap: 6px;
	padding: 4px 6px;
	border-bottom: 1px solid var(--terminal-border);
	background-color: var(--terminal-toolbar-bg);
	flex: 0 0 auto;
}

#terminal-toolbar button {
	appearance: none;
	border: 1px solid var(--terminal-button-border);
	border-radius: 4px;
	background-color: var(--terminal-button-bg);
	color: var(--terminal-button-fg);
	font: inherit;
	font-size: 13px;
	line-height: 1.4;
	padding: 2px 8px;
	cursor: pointer;
}

#terminal-toolbar button:hover {
	background-color: var(--terminal-button-hover-bg);
}

#terminal-toolbar button:focus-visible {
	outline: 1px solid var(--vscode-focusBorder, #007acc);
	outline-offset: 1px;
}

#terminal-container {
	position: relative;
	flex: 1 1 auto;
	min-height: 0;
}

#terminal-container,
.xterm {
	height: 100%;
	width: 100%;
}

#terminal-container.drag-over {
	outline: 2px dashed var(--terminal-drag-outline);
	outline-offset: -2px;
}

#terminal-container::after {
	content: '';
	position: absolute;
	inset: 0;
	z-index: 5;
	pointer-events: none;
	background: rgba(255, 255, 255, 0);
	border: 0 solid rgba(255, 255, 255, 0);
	box-sizing: border-box;
	opacity: 0;
}

#terminal-container.bell-flash::after {
	animation: terminal-bell-flash 320ms ease-out;
}

@keyframes terminal-bell-flash {
	0% {
		opacity: 1;
		background: rgba(255, 255, 255, 0.18);
		border: 3px solid rgba(255, 255, 255, 0.85);
	}
	60% {
		opacity: 0.6;
		background: rgba(255, 255, 255, 0.05);
		border: 3px solid rgba(255, 255, 255, 0.4);
	}
	100% {
		opacity: 0;
		background: rgba(255, 255, 255, 0);
		border: 3px solid rgba(255, 255, 255, 0);
	}
}

#terminal-container.terminal-error {
	color: var(--terminal-error);
	padding: 20px;
	font-family: monospace;
	font-size: 12px;
	white-space: pre-wrap;
}

.terminal-freeze-overlay {
	position: absolute;
	inset: 0;
	z-index: 2;
	overflow: hidden;
	pointer-events: none;
	background-color: var(--terminal-bg);
}

.terminal-freeze-overlay > .xterm {
	height: 100%;
	width: 100%;
}

.terminal-freeze-overlay .xterm-helpers,
.terminal-freeze-overlay .xterm-accessibility,
.terminal-freeze-overlay .xterm-cursor-layer {
	visibility: hidden !important;
}

.xterm .xterm-viewport,
.xterm .xterm-scrollable-element {
	background-color: var(--terminal-bg) !important;
}

.xterm .xterm-scrollable-element {
	height: 100%;
}

.xterm .xterm-scrollable-element > .scrollbar.vertical {
	box-sizing: border-box;
	border-left: 1px solid var(--terminal-border);
}

.xterm .xterm-scrollable-element > .scrollbar.horizontal {
	box-sizing: border-box;
	border-top: 1px solid var(--terminal-border);
}


================================================
FILE: VSIX/res/sidebarTerminal.js
================================================
(function () {
	const vscode = acquireVsCodeApi();

	const normalizeLogMessage = value => {
		if (typeof value === 'string') {
			const trimmed = value.trim();
			if (trimmed) {
				return trimmed;
			}
		}
		try {
			return String(value);
		} catch {
			return 'Unknown frontend log message';
		}
	};

	const stringifyLogDetails = value => {
		if (typeof value === 'undefined' || value === null) {
			return undefined;
		}
		if (typeof value === 'string') {
			const trimmed = value.trim();
			return trimmed || undefined;
		}
		if (value instanceof Error) {
			return value.stack || value.message;
		}
		try {
			return JSON.stringify(
				value,
				(_key, entry) => {
					if (entry instanceof Error) {
						return {
							name: entry.name,
							message: entry.message,
							stack: entry.stack,
						};
					}
					return typeof entry === 'bigint' ? entry.toString() : entry;
				},
				2,
			);
		} catch {
			try {
				return String(value);
			} catch {
				return 'Unserializable log details';
			}
		}
	};

	const bridgeFrontendLog = (level, message, details) => {
		const normalizedMessage = normalizeLogMessage(message);
		const normalizedDetails = stringifyLogDetails(details);
		const consoleMethod =
			level === 'error'
				? 'error'
				: level === 'warn'
				? 'warn'
				: level === 'debug'
				? 'debug'
				: 'info';
		const logToConsole =
			typeof console[consoleMethod] === 'function'
				? console[consoleMethod].bind(console)
				: console.log.bind(console);
		const consolePrefix = `[Snow CLI][SidebarTerminal][${level.toUpperCase()}] ${normalizedMessage}`;

		if (typeof normalizedDetails === 'string') {
			logToConsole(consolePrefix, normalizedDetails);
		} else {
			logToConsole(consolePrefix);
		}

		try {
			vscode.postMessage({
				type: 'frontendLog',
				level,
				message: normalizedMessage,
				details: normalizedDetails,
			});
		} catch {
			// Ignore logging bridge failures.
		}
	};

	const logInfo = (message, details) => {
		bridgeFrontendLog('info', message, details);
	};

	const logWarn = (message, details) => {
		bridgeFrontendLog('warn', message, details);
	};

	const logError = (message, details) => {
		bridgeFrontendLog('error', message, details);
	};

	const tabStrip = document.getElementById('terminal-tab-strip');
	if (!(tabStrip instanceof HTMLElement)) {
		logError('Terminal tab strip element was not found.');
		return;
	}

	const container = document.getElementById('terminal-container');
	if (!(container instanceof HTMLElement)) {
		logError('Terminal container element was not found.');
		return;
	}

	const showError = msg => {
		for (const overlay of container.querySelectorAll(
			'.terminal-freeze-overlay',
		)) {
			overlay.remove();
		}
		container.classList.add('terminal-error');
		container.textContent = `Terminal Error:\n${msg}`;
		logError('Terminal UI error displayed.', msg);
	};

	const getOptionalButton = buttonId => {
		const button = document.getElementById(buttonId);
		if (button instanceof HTMLButtonElement) {
			return button;
		}
		if (button !== null) {
			logWarn(
				'Renderer test control element is not a button.',
				`id=${buttonId}`,
			);
		}
		return undefined;
	};

	const renderStallTestButton = getOptionalButton('terminal-test-render-stall');
	const contextLossTestButton = getOptionalButton('terminal-test-context-loss');

	const getGlobalConstructor = (globalName, memberName) => {
		const globalValue = globalThis[globalName];
		if (typeof memberName !== 'string') {
			return typeof globalValue === 'function' ? globalValue : undefined;
		}
		const constructorValue = globalValue && globalValue[memberName];
		return typeof constructorValue === 'function'
			? constructorValue
			: undefined;
	};

	const TerminalCtor = getGlobalConstructor('Terminal');
	const FitAddonCtor = getGlobalConstructor('FitAddon', 'FitAddon');
	const WebLinksAddonCtor = getGlobalConstructor(
		'WebLinksAddon',
		'WebLinksAddon',
	);
	const Unicode11AddonCtor = getGlobalConstructor(
		'Unicode11Addon',
		'Unicode11Addon',
	);
	const WebglAddonCtor = getGlobalConstructor('WebglAddon', 'WebglAddon');

	const requiredAddons = [
		['Terminal', typeof TerminalCtor],
		['FitAddon', typeof FitAddonCtor],
		['WebLinksAddon', typeof WebLinksAddonCtor],
	];
	for (const [name, type] of requiredAddons) {
		if (type === 'undefined') {
			const errorMessage = `${name} failed to load.${
				name === 'Terminal' ? ' Check CSP or resource paths.' : ''
			}`;
			showError(errorMessage);
			return;
		}
	}

	const createCleanupRegistry = () => {
		const handlers = [];
		let cleaned = false;

		const registerCleanup = cleanup => {
			handlers.push(cleanup);
		};

		const runCleanups = () => {
			if (cleaned) {
				return;
			}
			cleaned = true;
			for (let i = handlers.length - 1; i >= 0; i -= 1) {
				try {
					handlers[i]();
				} catch {
					// Ignore cleanup failures.
				}
			}
			handlers.length = 0;
		};

		const addManagedListener = (target, type, listener, options) => {
			target.addEventListener(type, listener, options);
			registerCleanup(() => {
				target.removeEventListener(type, listener, options);
			});
		};

		const registerDisposable = disposable => {
			if (!disposable || typeof disposable.dispose !== 'function') {
				return;
			}
			registerCleanup(() => {
				try {
					disposable.dispose();
				} catch {
					// Ignore disposal failures.
				}
			});
		};

		return {
			registerCleanup,
			runCleanups,
			addManagedListener,
			registerDisposable,
		};
	};

	const applyTermOption = (options, key, value) => {
		if (typeof value === 'string' && value) {
			options[key] = value;
		} else if (typeof value === 'number' && Number.isFinite(value)) {
			options[key] = value;
		}
	};

	const createTimerRegistry = () => {
		const timers = new Map();

		const clearTimer = key => {
			const timer = timers.get(key);
			if (typeof timer === 'undefined' || timer === null) {
				return;
			}
			clearTimeout(timer);
			timers.set(key, null);
		};

		const scheduleTimer = (key, callback, delayMs) => {
			clearTimer(key);
			const timer = setTimeout(() => {
				timers.set(key, null);
				callback();
			}, delayMs);
			timers.set(key, timer);
			return timer;
		};

		const clearAllTimers = () => {
			for (const key of Array.from(timers.keys())) {
				clearTimer(key);
			}
		};

		return {
			clearTimer,
			scheduleTimer,
			clearAllTimers,
		};
	};

	const createFocusRecoveryController = ({term, cooldownMs, delaysMs}) => {
		let focusRecoveryTimers = [];
		let focusRecoveryCooldownUntil = 0;

		const clearFocusRecoveryTimers = () => {
			if (focusRecoveryTimers.length === 0) {
				return;
			}
			for (const timer of focusRecoveryTimers) {
				clearTimeout(timer);
			}
			focusRecoveryTimers = [];
		};

		const scheduleFocusRecovery = () => {
			if (document.hidden) {
				return;
			}
			const now = Date.now();
			if (now < focusRecoveryCooldownUntil) {
				return;
			}
			focusRecoveryCooldownUntil = now + cooldownMs;
			clearFocusRecoveryTimers();
			for (const delay of delaysMs) {
				const timer = setTimeout(() => {
					focusRecoveryTimers = focusRecoveryTimers.filter(
						entry => entry !== timer,
					);
					term.focus();
				}, delay);
				focusRecoveryTimers.push(timer);
			}
		};

		return {
			clearFocusRecoveryTimers,
			scheduleFocusRecovery,
		};
	};

	const createLayoutController = ({
		term,
		container,
		fitAddon,
		setRendererHealthSuspended,
		suspendAfterLayoutMs,
		scheduleTimer,
		resizeDebounceTimerKey,
	}) => {
		const RESIZE_FILL_TOLERANCE_PX = 2;
		let lastReportedCols = 0;
		let lastReportedRows = 0;

		const reportSize = () => {
			const cols = term.cols;
			const rows = term.rows;
			if (
				cols > 0 &&
				rows > 0 &&
				(cols !== lastReportedCols || rows !== lastReportedRows)
			) {
				lastReportedCols = cols;
				lastReportedRows = rows;
				vscode.postMessage({
					type: 'resize',
					cols,
					rows,
				});
			}
		};

		const getMeasuredRowHeight = () => {
			const screenCanvas = container.querySelector('.xterm-screen canvas');
			if (screenCanvas instanceof HTMLCanvasElement && term.rows > 0) {
				const measured =
					screenCanvas.getBoundingClientRect().height / term.rows;
				if (measured > 0) {
					return measured;
				}
			}

			const fontSize =
				typeof term.options.fontSize === 'number' ? term.options.fontSize : 14;
			const lineHeight =
				typeof term.options.lineHeight === 'number'
					? term.options.lineHeight
					: 1;
			const estimated = fontSize * lineHeight;
			return estimated > 0 ? estimated : 0;
		};

		const resizeToContainer = () => {
			const proposed = fitAddon.proposeDimensions();
			if (!proposed) {
				return false;
			}

			let {cols, rows} = proposed;
			if (cols <= 0 || rows <= 0) {
				return false;
			}

			const rowHeight = getMeasuredRowHeight();
			if (rowHeight > 0) {
				const availableHeight = container.getBoundingClientRect().height;
				const remainingHeight = availableHeight - rows * rowHeight;
				if (remainingHeight >= rowHeight - RESIZE_FILL_TOLERANCE_PX) {
					rows += 1;
				}
			}

			if (cols !== term.cols || rows !== term.rows) {
				term.resize(cols, rows);
			}
			return true;
		};

		const fitTerminal = () => {
			setRendererHealthSuspended(suspendAfterLayoutMs);
			try {
				const resized = resizeToContainer();
				if (!resized) {
					fitAddon.fit();
				}
				reportSize();
			} catch {
				// Ignore fit errors caused by transient hidden/invalid layout states.
			}
		};

		const scheduleFit = () => {
			scheduleTimer(
				resizeDebounceTimerKey,
				() => {
					fitTerminal();
				},
				50,
			);
		};

		return {
			fitTerminal,
			scheduleFit,
		};
	};

	const createWindowMessageRouter = ({messageHandlers}) => {
		return event => {
			const message = event.data;
			if (!message || typeof message.type !== 'string') {
				return;
			}

			const handler = messageHandlers[message.type];
			if (typeof handler !== 'function') {
				logWarn('Unhandled extension message type.', `type=${message.type}`);
				return;
			}

			try {
				handler(message);
			} catch (error) {
				logError(`Failed to handle extension message: ${message.type}`, error);
			}
		};
	};

	const createClipboardAndContextController = ({term, sendInput}) => {
		const isMacPlatform = /mac/i.test(navigator.userAgent);

		const shouldUseCtrlSelectionCopy = event => {
			if (
				isMacPlatform ||
				event.type !== 'keydown' ||
				!event.ctrlKey ||
				event.shiftKey ||
				event.altKey ||
				event.metaKey ||
				event.key.toLowerCase() !== 'c'
			) {
				return false;
			}
			return term.hasSelection() && Boolean(term.getSelection());
		};

		const allowTerminalKeyEvent = event => {
			if (
				!isMacPlatform &&
				event.type === 'keydown' &&
				event.ctrlKey &&
				!event.shiftKey &&
				!event.altKey &&
				!event.metaKey &&
				event.key.toLowerCase() === 'v'
			) {
				return false;
			}
			if (shouldUseCtrlSelectionCopy(event)) {
				const selection = term.getSelection();
				if (selection) {
					navigator.clipboard.writeText(selection).catch(() => {
						// Ignore clipboard write failures.
					});
				}
				return false;
			}
			return true;
		};

		const handleContextMenu = event => {
			event.preventDefault();
			const selection = term.getSelection();
			if (selection) {
				navigator.clipboard.writeText(selection).catch(() => {
					// Ignore clipboard write failures.
				});
				term.clearSelection();
				return;
			}

			navigator.clipboard
				.readText()
				.then(text => {
					sendInput(text);
				})
				.catch(() => {
					// Ignore clipboard read failures.
				});
		};

		return {
			allowTerminalKeyEvent,
			handleContextMenu,
		};
	};

	const createWindowLifecycleController = ({
		scheduleFocusRecovery,
		setRendererHealthSuspended,
		suspendAfterLayoutMs,
		getActiveRendererMode,
		getLastWebglFailureReason,
		scheduleWebglRecoveryAttempt,
		webglRecoveryRecheckMs,
	}) => {
		const handleContainerMouseDown = () => {
			scheduleFocusRecovery();
		};

		const handleVisibilityChange = () => {
			if (document.hidden) {
				return;
			}
			setRendererHealthSuspended(suspendAfterLayoutMs);
			scheduleFocusRecovery();
			const lastFailureReason = getLastWebglFailureReason();
			if (getActiveRendererMode() !== 'webgl' && lastFailureReason) {
				scheduleWebglRecoveryAttempt(lastFailureReason, webglRecoveryRecheckMs);
			}
		};

		const handleWindowFocus = () => {
			setRendererHealthSuspended(suspendAfterLayoutMs);
			scheduleFocusRecovery();
		};

		return {
			handleContainerMouseDown,
			handleVisibilityChange,
			handleWindowFocus,
		};
	};

	try {
		const {
			registerCleanup,
			runCleanups,
			addManagedListener,
			registerDisposable,
		} = createCleanupRegistry();
		logInfo('Initializing sidebar terminal frontend.');

		let currentTabId;
		let tabStates = [];

		const normalizeTabState = value => {
			if (!value || typeof value !== 'object') {
				return undefined;
			}
			const id = typeof value.id === 'string' ? value.id : '';
			const title = typeof value.title === 'string' ? value.title : '';
			if (!id || !title) {
				return undefined;
			}
			return {
				id,
				title,
				isActive: Boolean(value.isActive),
				isRunning: Boolean(value.isRunning),
				isRestarting: Boolean(value.isRestarting),
				exitCode:
					typeof value.exitCode === 'number' && Number.isFinite(value.exitCode)
						? value.exitCode
						: undefined,
			};
		};

		const revealTabItem = item => {
			if (!(item instanceof HTMLElement)) {
				return;
			}
			window.requestAnimationFrame(() => {
				const visibleLeft = tabStrip.scrollLeft;
				const visibleRight = visibleLeft + tabStrip.clientWidth;
				const itemLeft = item.offsetLeft;
				const itemRight = itemLeft + item.offsetWidth;
				if (itemLeft < visibleLeft) {
					tabStrip.scrollLeft = itemLeft;
					return;
				}
				if (itemRight > visibleRight) {
					tabStrip.scrollLeft = Math.max(0, itemRight - tabStrip.clientWidth);
				}
			});
		};

		const renderTabs = () => {
			tabStrip.replaceChildren();
			if (tabStates.length === 0) {
				return;
			}
			let activeItem;
			for (const tab of tabStates) {
				const item = document.createElement('div');
				item.className = 'terminal-tab-item';
				item.dataset.tabId = tab.id;
				if (tab.isActive) {
					item.classList.add('is-active');
					activeItem = item;
				}
				if (tab.isRestarting) {
					item.classList.add('is-restarting');
				}

				const button = document.createElement('button');
				button.type = 'button';
				button.className = 'terminal-tab';
				button.setAttribute('role', 'tab');
				button.setAttribute('aria-selected', tab.isActive ? 'true' : 'false');
				button.setAttribute('aria-controls', 'terminal-container');
				button.title = tab.title;

				const label = document.createElement('span');
				label.className = 'terminal-tab-label';
				label.textContent = tab.title;
				button.appendChild(label);

				button.addEventListener('click', () => {
					if (tab.id === currentTabId) {
						return;
					}
					vscode.postMessage({type: 'switchTab', tabId: tab.id});
				});

				const closeButton = document.createElement('button');
				closeButton.type = 'button';
				closeButton.className = 'terminal-tab-close';
				if (tab.isRestarting) {
					const spinner = document.createElement('span');
					spinner.className = 'terminal-tab-spinner';
					closeButton.setAttribute('aria-label', `${tab.title} is restarting`);
					closeButton.title = `${tab.title} is restarting`;
					closeButton.disabled = true;
					closeButton.appendChild(spinner);
				} else {
					closeButton.setAttribute('aria-label', `Close ${tab.title}`);
					closeButton.title = `Close ${tab.title}`;
					closeButton.textContent = '×';
					closeButton.addEventListener('click', event => {
						event.preventDefault();
						event.stopPropagation();
						vscode.postMessage({type: 'closeTab', tabId: tab.id});
					});
				}

				item.appendChild(button);
				item.appendChild(closeButton);
				tabStrip.appendChild(item);
			}
			if (activeItem) {
				revealTabItem(activeItem);
			}
		};

		const applyTabs = nextTabs => {
			const normalizedTabs = Array.isArray(nextTabs)
				? nextTabs.map(normalizeTabState).filter(Boolean)
				: [];
			if (normalizedTabs.length === 0) {
				tabStates = [];
				currentTabId = undefined;
				renderTabs();
				return;
			}
			const activeTab =
				normalizedTabs.find(tab => tab.isActive) || normalizedTabs[0];
			currentTabId = activeTab.id;
			tabStates = normalizedTabs.map(tab => ({
				...tab,
				isActive: tab.id === activeTab.id,
			}));
			renderTabs();
		};

		const sendInput = text => {
			if (typeof text !== 'string' || text.length === 0) {
				return;
			}
			vscode.postMessage({type: 'input', data: text});
		};

		const createBellPlayer = () => {
			const config = {
				enabled: true,
				volume: 0.5,
				sound: 'beep',
				visualFlash: true,
			};
			let audioCtx = null;
			let lastBellAt = 0;
			let visualFlashClearTimer = null;
			const MIN_BELL_INTERVAL_MS = 80;
			const VISUAL_FLASH_DURATION_MS = 320;

			const ensureAudioCtx = () => {
				if (audioCtx) {
					return audioCtx;
				}
				const Ctor =
					typeof window.AudioContext === 'function'
						? window.AudioContext
						: typeof window.webkitAudioContext === 'function'
						? window.webkitAudioContext
						: undefined;
				if (!Ctor) {
					return null;
				}
				try {
					audioCtx = new Ctor();
				} catch (error) {
					logWarn(
						'Failed to initialize AudioContext for terminal bell.',
						error,
					);
					audioCtx = null;
				}
				return audioCtx;
			};

			const unlockAudio = () => {
				const ctx = ensureAudioCtx();
				if (!ctx || ctx.state !== 'suspended') {
					return;
				}
				ctx.resume().catch(() => {
					// AudioContext will be retried on the next user gesture.
				});
			};

			const updateConfig = next => {
				if (!next || typeof next !== 'object') {
					return;
				}
				if (typeof next.enabled === 'boolean') {
					config.enabled = next.enabled;
				}
				if (typeof next.volume === 'number' && Number.isFinite(next.volume)) {
					config.volume = Math.min(1, Math.max(0, next.volume));
				}
				if (typeof next.sound === 'string') {
					config.sound = next.sound;
				}
				if (typeof next.visualFlash === 'boolean') {
					config.visualFlash = next.visualFlash;
				}
			};

			const flashBellOverlay = () => {
				if (!config.visualFlash) {
					return;
				}
				container.classList.remove('bell-flash');
				// Force reflow so the animation restarts on rapid consecutive bells.
				void container.offsetWidth;
				container.classList.add('bell-flash');
				if (visualFlashClearTimer) {
					clearTimeout(visualFlashClearTimer);
				}
				visualFlashClearTimer = setTimeout(() => {
					container.classList.remove('bell-flash');
					visualFlashClearTimer = null;
				}, VISUAL_FLASH_DURATION_MS);
			};

			const scheduleBellTone = (ctx, gainNode, spec) => {
				const oscillator = ctx.createOscillator();
				oscillator.type = spec.type || 'sine';
				oscillator.frequency.setValueAtTime(spec.frequency, spec.startTime);
				if (typeof spec.endFrequency === 'number') {
					oscillator.frequency.exponentialRampToValueAtTime(
						spec.endFrequency,
						spec.startTime + spec.duration,
					);
				}
				oscillator.connect(gainNode);
				oscillator.start(spec.startTime);
				oscillator.stop(spec.startTime + spec.duration + 0.02);
			};

			const renderSound = ctx => {
				const masterGain = ctx.createGain();
				masterGain.gain.value = config.volume;
				masterGain.connect(ctx.destination);

				const now = ctx.currentTime;
				const peak = 0.6; // pre-volume peak; final amplitude = peak * config.volume
				const tones = [];

				switch (config.sound) {
					case 'ding': {
						const envGain = ctx.createGain();
						envGain.gain.setValueAtTime(0.0001, now);
						envGain.gain.exponentialRampToValueAtTime(peak, now + 0.005);
						envGain.gain.exponentialRampToValueAtTime(0.0001, now + 0.32);
						envGain.connect(masterGain);
						tones.push({
							type: 'triangle',
							frequency: 1320,
							startTime: now,
							duration: 0.32,
							gain: envGain,
						});
						tones.push({
							type: 'triangle',
							frequency: 1980,
							startTime: now,
							duration: 0.28,
							gain: envGain,
						});
						break;
					}
					case 'chime': {
						const env1 = ctx.createGain();
						env1.gain.setValueAtTime(0.0001, now);
						env1.gain.exponentialRampToValueAtTime(peak, now + 0.01);
						env1.gain.exponentialRampToValueAtTime(0.0001, now + 0.2);
						env1.connect(masterGain);
						tones.push({
							type: 'sine',
							frequency: 1046.5,
							startTime: now,
							duration: 0.2,
							gain: env1,
						});

						const env2 = ctx.createGain();
						env2.gain.setValueAtTime(0.0001, now + 0.16);
						env2.gain.exponentialRampToValueAtTime(peak, now + 0.17);
						env2.gain.exponentialRampToValueAtTime(0.0001, now + 0.42);
						env2.connect(masterGain);
						tones.push({
							type: 'sine',
							frequency: 783.99,
							startTime: now + 0.16,
							duration: 0.26,
							gain: env2,
						});
						break;
					}
					case 'pluck': {
						const envGain = ctx.createGain();
						envGain.gain.setValueAtTime(0.0001, now);
						envGain.gain.exponentialRampToValueAtTime(peak * 0.85, now + 0.005);
						envGain.gain.exponentialRampToValueAtTime(0.0001, now + 0.18);
						envGain.connect(masterGain);
						tones.push({
							type: 'sawtooth',
							frequency: 660,
							endFrequency: 330,
							startTime: now,
							duration: 0.18,
							gain: envGain,
						});
						break;
					}
					case 'blip': {
						const envGain = ctx.createGain();
						envGain.gain.setValueAtTime(0.0001, now);
						envGain.gain.exponentialRampToValueAtTime(peak, now + 0.004);
						envGain.gain.exponentialRampToValueAtTime(0.0001, now + 0.08);
						envGain.connect(masterGain);
						tones.push({
							type: 'square',
							frequency: 1760,
							startTime: now,
							duration: 0.08,
							gain: envGain,
						});
						break;
					}
					case 'beep':
					default: {
						const envGain = ctx.createGain();
						envGain.gain.setValueAtTime(0.0001, now);
						envGain.gain.exponentialRampToValueAtTime(peak, now + 0.01);
						envGain.gain.exponentialRampToValueAtTime(0.0001, now + 0.13);
						envGain.connect(masterGain);
						tones.push({
							type: 'sine',
							frequency: 800,
							startTime: now,
							duration: 0.13,
							gain: envGain,
						});
						break;
					}
				}

				for (const tone of tones) {
					scheduleBellTone(ctx, tone.gain, tone);
				}
			};

			const playBell = () => {
				if (!config.enabled) {
					return;
				}
				const now = Date.now();
				if (now - lastBellAt < MIN_BELL_INTERVAL_MS) {
					return;
				}
				lastBellAt = now;
				flashBellOverlay();
				if (config.sound === 'none' || config.volume <= 0) {
					return;
				}
				const ctx = ensureAudioCtx();
				if (!ctx) {
					return;
				}
				if (ctx.state === 'suspended') {
					ctx.resume().catch(() => {
						// User has not yet interacted with the webview; visual flash is the only feedback this time.
					});
					return;
				}
				try {
					renderSound(ctx);
				} catch (error) {
					logWarn('Failed to play terminal bell.', error);
				}
			};

			const dispose = () => {
				if (visualFlashClearTimer) {
					clearTimeout(visualFlashClearTimer);
					visualFlashClearTimer = null;
				}
			};

			return {playBell, unlockAudio, updateConfig, dispose};
		};

		const {
			playBell: playTerminalBell,
			unlockAudio: unlockTerminalAudio,
			updateConfig: updateBellConfig,
			dispose: disposeBellPlayer,
		} = createBellPlayer();
		registerCleanup(disposeBellPlayer);

		const term = new TerminalCtor({
			cursorBlink: true,
			fontFamily: 'monospace',
			fontSize: 14,
			altClickMovesCursor: true,
			drawBoldTextInBrightColors: true,
			minimumContrastRatio: 4.5,
			tabStopWidth: 8,
			macOptionIsMeta: false,
			rightClickSelectsWord: false,
			fastScrollModifier: 'alt',
			fastScrollSensitivity: 5,
			scrollSensitivity: 1,
			scrollback: 1000,
			scrollOnUserInput: true,
			wordSeparator: " ()[]{}',\\\"`─''|",
			allowTransparency: false,
			rescaleOverlappingGlyphs: true,
			allowProposedApi: true,
			cursorStyle: 'block',
			cursorInactiveStyle: 'outline',
			cursorWidth: 1,
			convertEol: false,
			disableStdin: false,
			screenReaderMode: false,
			windowOptions: {
				restoreWin: false,
				minimizeWin: false,
				setWinPosition: false,
				setWinSizePixels: false,
				raiseWin: false,
				lowerWin: false,
				refreshWin: false,
				setWinSizeChars: false,
				maximizeWin: false,
				fullscreenWin: false,
			},
			theme: {
				background: '#181818',
				foreground: '#d4d4d4',
				cursor: '#aeafad',
				cursorAccent: '#000000',
				selectionBackground: '#264f78',
				black: '#000000',
				red: '#cd3131',
				green: '#0dbc79',
				yellow: '#e5e510',
				blue: '#2472c8',
				magenta: '#bc3fbc',
				cyan: '#11a8cd',
				white: '#e5e5e5',
				brightBlack: '#666666',
				brightRed: '#f14c4c',
				brightGreen: '#23d18b',
				brightYellow: '#f5f543',
				brightBlue: '#3b8eea',
				brightMagenta: '#d670d6',
				brightCyan: '#29b8db',
				brightWhite: '#e5e5e5',
			},
		});

		const fitAddon = new FitAddonCtor();
		const webLinksAddon = new WebLinksAddonCtor();
		term.loadAddon(fitAddon);
		term.loadAddon(webLinksAddon);

		if (typeof Unicode11AddonCtor === 'function') {
			try {
				const unicode11Addon = new Unicode11AddonCtor();
				term.loadAddon(unicode11Addon);
				try {
					term.unicode.activeVersion = '11';
					logInfo('Unicode version 11 activated.');
				} catch (error) {
					logWarn('Failed to activate Unicode version 11.', error);
				}
			} catch (error) {
				logWarn('Unicode11Addon failed to load.', error);
			}
		}

		term.open(container);
		const TIMER_KEYS = {
			resizeDebounce: 'resizeDebounce',
			webglRecovery: 'webglRecovery',
			silentWebglRecovery: 'silentWebglRecovery',
			rendererFreezeRelease: 'rendererFreezeRelease',
			webglStability: 'webglStability',
		};
		const FOCUS_RECOVERY_DELAYS_MS = [0, 80, 240];
		const FOCUS_RECOVERY_COOLDOWN_MS = 400;

		const RENDER_STALL_TIMEOUT_MS = 10000;
		const RENDER_STALL_CHECK_INTERVAL_MS = 2000;
		const RENDER_STALL_WRITE_ACTIVITY_GRACE_MS = 1000;
		const RENDERER_HEALTH_SUSPEND_AFTER_LAYOUT_MS = 2500;
		const RENDERER_HEALTH_SUSPEND_AFTER_WEBGL_ENABLE_MS = 4000;
		const WEBGL_RECOVERY_RECHECK_MS = 2000;
		const WEBGL_RECOVERY_SUSPEND_DEFER_MIN_MS = 250;
		const WEBGL_RECOVERY_DELAY_STEPS_MS = [1000, 5000, 15000];
		const WEBGL_STABILITY_RESET_MS = 30000;
		const SILENT_WEBGL_RECOVERY_DELAY_MS = 180;
		const RENDERER_FREEZE_RELEASE_FALLBACK_MS = 120;

		const {clearTimer, scheduleTimer, clearAllTimers} = createTimerRegistry();
		const {clearFocusRecoveryTimers, scheduleFocusRecovery} =
			createFocusRecoveryController({
				term,
				cooldownMs: FOCUS_RECOVERY_COOLDOWN_MS,
				delaysMs: FOCUS_RECOVERY_DELAYS_MS,
			});

		let webglAddon = null;
		let activeRendererMode = 'fallback';
		let lastOutputAt = 0;
		let lastRenderAt = Date.now();
		let lastWriteParsedAt = 0;
		let lastWriteCallbackAt = 0;
		let bytesPendingRender = 0;
		let pendingVisualUpdate = false;
		let pendingRenderSince = 0;
		let rendererStallReportedAt = 0;
		let rendererHealthSuspendedUntil =
			Date.now() + RENDERER_HEALTH_SUSPEND_AFTER_LAYOUT_MS;
		let webglFailureCount = 0;
		let lastWebglFailureReason = undefined;
		let lastWebglEscalationRequestedAt = 0;
		let rendererRecoveryCycleId = 0;
		let currentRecoveryCycleId = 0;
		let currentRecoveryAttemptId = 0;
		let rendererStallWriteGracePendingSince = 0;
		let rendererStallWriteGraceUntil = 0;
		let rendererFreezeOverlay = null;
		let rendererFreezeReleasePending = false;
		let rendererFallbackPending = false;

		const clearWebglRecoveryTimer = () => {
			clearTimer(TIMER_KEYS.webglRecovery);
		};

		const clearWebglStabilityTimer = () => {
			clearTimer(TIMER_KEYS.webglStability);
		};

		const isContainerVisible = () => {
			if (document.hidden) {
				return false;
			}
			const rect = container.getBoundingClientRect();
			return rect.width > 0 && rect.height > 0;
		};

		const setRendererHealthSuspended = durationMs => {
			if (typeof durationMs !== 'number' || durationMs <= 0) {
				return;
			}
			const suspendedUntil = Date.now() + durationMs;
			if (suspendedUntil > rendererHealthSuspendedUntil) {
				rendererHealthSuspendedUntil = suspendedUntil;
			}
		};

		const getRendererHealthSuspendedRemainingMs = now =>
			Math.max(0, rendererHealthSuspendedUntil - now);

		const clearRendererStallWriteGrace = () => {
			rendererStallWriteGracePendingSince = 0;
			rendererStallWriteGraceUntil = 0;
		};

		const getWebglRecoveryDelayMs = delayMs => {
			const nextDelayMs = Math.max(0, Math.floor(delayMs));
			const suspendedRemainingMs = getRendererHealthSuspendedRemainingMs(
				Date.now(),
			);
			if (suspendedRemainingMs <= 0) {
				return nextDelayMs;
			}
			return Math.max(
				nextDelayMs,
				WEBGL_RECOVERY_SUSPEND_DEFER_MIN_MS,
				suspendedRemainingMs,
			);
		};

		const postRendererHealth = (stage, reason, extraStats) => {
			const now = Date.now();
			try {
				vscode.postMessage({
					type: 'rendererHealth',
					stage,
					reason,
					stats: {
						activeRendererMode,
						pendingVisualUpdate,
						pendingDurationMs:
							pendingVisualUpdate && pendingRenderSince > 0
								? now - pendingRenderSince
								: 0,
						sinceLastRenderMs:
							lastRenderAt > 0 ? now - lastRenderAt : undefined,
						sinceLastOutputMs:
							lastOutputAt > 0 ? now - lastOutputAt : undefined,
						sinceLastWriteParsedMs:
							lastWriteParsedAt > 0 ? now - lastWriteParsedAt : undefined,
						sinceLastWriteCallbackMs:
							lastWriteCallbackAt > 0 ? now - lastWriteCallbackAt : undefined,
						bytesPendingRender,
						webglFailureCount,
						rendererRecoveryCycleId: currentRecoveryCycleId || undefined,
						rendererRecoveryAttemptId: currentRecoveryAttemptId || undefined,
						rendererHealthSuspendedForMs:
							getRendererHealthSuspendedRemainingMs(now),
						lastWebglFailureReason,
						...(extraStats || {}),
					},
				});
			} catch {
				// Ignore renderer health bridge failures.
			}
		};

		const {fitTerminal, scheduleFit} = createLayoutController({
			term,
			container,
			fitAddon,
			setRendererHealthSuspended,
			suspendAfterLayoutMs: RENDERER_HEALTH_SUSPEND_AFTER_LAYOUT_MS,
			scheduleTimer,
			resizeDebounceTimerKey: TIMER_KEYS.resizeDebounce,
		});

		const copyFreezeCanvasBitmap = (sourceCanvas, targetCanvas) => {
			try {
				targetCanvas.width = sourceCanvas.width;
				targetCanvas.height = sourceCanvas.height;
				targetCanvas.style.width = sourceCanvas.style.width;
				targetCanvas.style.height = sourceCanvas.style.height;
				const context = targetCanvas.getContext('2d');
				if (!context) {
					return;
				}
				context.clearRect(0, 0, targetCanvas.width, targetCanvas.height);
				context.drawImage(sourceCanvas, 0, 0);
			} catch {
				// Ignore canvas snapshot failures.
			}
		};

		const createRendererFreezeOverlay = () => {
			if (rendererFreezeOverlay) {
				return true;
			}
			const terminalElement = container.querySelector('.xterm');
			if (!(terminalElement instanceof HTMLElement)) {
				return false;
			}
			const terminalClone = terminalElement.cloneNode(true);
			if (!(terminalClone instanceof HTMLElement)) {
				return false;
			}
			const sourceCanvases = terminalElement.querySelectorAll('canvas');
			const targetCanvases = terminalClone.querySelectorAll('canvas');
			for (let index = 0; index < targetCanvases.length; index += 1) {
				const sourceCanvas = sourceCanvases[index];
				const targetCanvas = targetCanvases[index];
				if (
					sour
Download .txt
gitextract_06hmzq__/

├── .editorconfig
├── .gitattributes
├── .github/
│   └── workflows/
│       ├── build_jetbrains.yml
│       ├── build_vsix.yml
│       └── publish.yml
├── .gitignore
├── .npmrc
├── .npmrc.ci
├── .prettierignore
├── .vscode/
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── JetBrains/
│   ├── .gitignore
│   ├── README.md
│   ├── build.gradle.kts
│   ├── gradle/
│   │   └── wrapper/
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── gradle.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── settings.gradle.kts
│   └── src/
│       └── main/
│           ├── kotlin/
│           │   ├── com/
│           │   │   └── snow/
│           │   │       └── plugin/
│           │   │           ├── SnowCodeNavigator.kt
│           │   │           ├── SnowEditorContextTracker.kt
│           │   │           ├── SnowMessageHandler.kt
│           │   │           ├── SnowPluginLifecycle.kt
│           │   │           ├── SnowProjectActivity.kt
│           │   │           ├── SnowWebSocketManager.kt
│           │   │           ├── actions/
│           │   │           │   ├── GenerateCommitMessageAction.kt
│           │   │           │   ├── OpenSnowTerminalAction.kt
│           │   │           │   ├── SendToSnowCLIAction.kt
│           │   │           │   └── TestNotificationAction.kt
│           │   │           ├── commit/
│           │   │           │   └── SnowCommitMessageGenerationService.kt
│           │   │           ├── toolwindow/
│           │   │           │   └── SnowToolWindowFactory.kt
│           │   │           └── util/
│           │   │               └── TerminalCompat.kt
│           │   └── icons/
│           │       └── SnowPluginIcons.kt
│           └── resources/
│               └── META-INF/
│                   └── plugin.xml
├── LICENSE
├── README.md
├── README_zh.md
├── VSIX/
│   ├── .vscodeignore
│   ├── LICENSE
│   ├── README.md
│   ├── package.json
│   ├── res/
│   │   ├── sidebarTerminal.css
│   │   └── sidebarTerminal.js
│   ├── src/
│   │   ├── aceHandlers.ts
│   │   ├── commitMessageGenerator.ts
│   │   ├── diffHandlers.ts
│   │   ├── extension.ts
│   │   ├── gitBlameProvider.ts
│   │   ├── ptyManager.ts
│   │   ├── sidebarTerminalProvider.ts
│   │   ├── sidebarTerminalSession.ts
│   │   ├── startupCommandManager.ts
│   │   ├── terminalPathFormatter.ts
│   │   ├── terminalProxy.ts
│   │   └── webSocketServer.ts
│   ├── tsconfig.json
│   └── webpack.config.js
├── build-ncc.mjs
├── build-shim.js
├── build.mjs
├── docs/
│   ├── role/
│   │   ├── en/
│   │   │   └── 01.Snow CLI Plan Every Step.md
│   │   └── zh/
│   │       └── 01.Snow CLI 一步一规划.md
│   └── usage/
│       ├── en/
│       │   ├── 0.Catalogue.md
│       │   ├── 01.Installation Guide.md
│       │   ├── 02.First Time Configuration.md
│       │   ├── 03.Proxy and Browser Settings.md
│       │   ├── 04.Codebase Setup.md
│       │   ├── 05.Sub-Agent Configuration.md
│       │   ├── 06.Sensitive Commands Configuration.md
│       │   ├── 07.Hooks Configuration.md
│       │   ├── 08.Theme Settings.md
│       │   ├── 09.Command Panel Guide.md
│       │   ├── 10.Command Injection Mode.md
│       │   ├── 11.Vulnerability Hunting Mode.md
│       │   ├── 12.Headless Mode.md
│       │   ├── 13.Keyboard Shortcuts Guide.md
│       │   ├── 14.MCP Configuration.md
│       │   ├── 15.Async Task Management.md
│       │   ├── 16.Third-Party Relay Configuration.md
│       │   ├── 17.LSP Configuration.md
│       │   ├── 18.Skills Command Detailed Guide.md
│       │   ├── 19.Startup Parameters Guide.md
│       │   ├── 20.SSE Service Mode.md
│       │   ├── 21.Custom StatusLine Guide.md
│       │   ├── 22.Team Mode Guide.md
│       │   └── 23.Custom Search Engine Guide.md
│       └── zh/
│           ├── 0.目录.md
│           ├── 01.安装指南.md
│           ├── 02.首次配置.md
│           ├── 03.代理和浏览器设置.md
│           ├── 04.代码库设置.md
│           ├── 05.子代理设置.md
│           ├── 06.敏感命令配置.md
│           ├── 07.Hooks配置.md
│           ├── 08.主题设置.md
│           ├── 09.指令面板说明.md
│           ├── 10.命令注入模式.md
│           ├── 11.漏洞猎人模式.md
│           ├── 12.无头模式.md
│           ├── 13.快捷键指南.md
│           ├── 14.MCP配置.md
│           ├── 15.异步任务管理.md
│           ├── 16.第三方中转配置.md
│           ├── 17.LSP配置.md
│           ├── 18.Skills指令详细说明.md
│           ├── 19.启动参数说明.md
│           ├── 20.SSE服务模式.md
│           ├── 21.自定义StatusLine指南.md
│           ├── 22.Team模式指南.md
│           └── 23.自定义搜索引擎指南.md
├── package.json
├── scripts/
│   ├── clean-build.cjs
│   └── postinstall.cjs
├── source/
│   ├── agents/
│   │   ├── bashOutputSummaryAgent.ts
│   │   ├── codebaseIndexAgent.ts
│   │   ├── codebaseReviewAgent.ts
│   │   ├── compactAgent.ts
│   │   ├── reviewAgent.ts
│   │   └── summaryAgent.ts
│   ├── api/
│   │   ├── anthropic.ts
│   │   ├── chat.ts
│   │   ├── embedding.ts
│   │   ├── gemini.ts
│   │   ├── models.ts
│   │   ├── rerank.ts
│   │   ├── responses.ts
│   │   ├── sse-server.ts
│   │   └── types.ts
│   ├── app.tsx
│   ├── cli.tsx
│   ├── hooks/
│   │   ├── conversation/
│   │   │   ├── chatLogic/
│   │   │   │   ├── types.ts
│   │   │   │   ├── useChatHandlers.ts
│   │   │   │   ├── useMessageProcessing.ts
│   │   │   │   ├── useRemoteEvents.ts
│   │   │   │   └── useRollback.ts
│   │   │   ├── core/
│   │   │   │   ├── autoCompressHandler.ts
│   │   │   │   ├── conversationSetup.ts
│   │   │   │   ├── conversationTypes.ts
│   │   │   │   ├── editorContextBuilder.ts
│   │   │   │   ├── encoderManager.ts
│   │   │   │   ├── onStopHookHandler.ts
│   │   │   │   ├── pendingMessagesHandler.ts
│   │   │   │   ├── sessionInitializer.ts
│   │   │   │   ├── streamFactory.ts
│   │   │   │   ├── streamProcessor.ts
│   │   │   │   ├── subAgentMessageHandler.ts
│   │   │   │   ├── toolCallProcessor.ts
│   │   │   │   ├── toolCallRoundHandler.ts
│   │   │   │   ├── toolConfirmationFlow.ts
│   │   │   │   ├── toolRejectionHandler.ts
│   │   │   │   └── toolResultDisplay.ts
│   │   │   ├── useChatLogic.ts
│   │   │   ├── useCommandHandler.ts
│   │   │   ├── useConversation.ts
│   │   │   ├── useStreamingState.ts
│   │   │   ├── useToolConfirmation.ts
│   │   │   └── utils/
│   │   │       ├── messageCleanup.ts
│   │   │       └── thinkingExtractor.ts
│   │   ├── execution/
│   │   │   ├── useBackgroundProcesses.ts
│   │   │   ├── useSchedulerExecutionState.ts
│   │   │   └── useTerminalExecutionState.ts
│   │   ├── input/
│   │   │   ├── keyboard/
│   │   │   │   ├── context.ts
│   │   │   │   ├── handlers/
│   │   │   │   │   ├── arrowKeys.ts
│   │   │   │   │   ├── clipboard.ts
│   │   │   │   │   ├── deleteAndBackspace.ts
│   │   │   │   │   ├── editing.ts
│   │   │   │   │   ├── escape.ts
│   │   │   │   │   ├── focusFilter.ts
│   │   │   │   │   ├── modeToggle.ts
│   │   │   │   │   ├── newline.ts
│   │   │   │   │   ├── pickers/
│   │   │   │   │   │   ├── agentPicker.ts
│   │   │   │   │   │   ├── argsPicker.ts
│   │   │   │   │   │   ├── commandPanel.ts
│   │   │   │   │   │   ├── filePicker.ts
│   │   │   │   │   │   ├── gitLinePicker.ts
│   │   │   │   │   │   ├── historyMenu.ts
│   │   │   │   │   │   ├── profilePicker.ts
│   │   │   │   │   │   ├── runningAgentsPicker.ts
│   │   │   │   │   │   ├── skillsPicker.ts
│   │   │   │   │   │   └── todoPicker.ts
│   │   │   │   │   ├── profileShortcut.ts
│   │   │   │   │   ├── regularInput.ts
│   │   │   │   │   ├── submit.ts
│   │   │   │   │   └── tabArgsPicker.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── utils/
│   │   │   │       └── wordBoundary.ts
│   │   │   ├── useBashMode.ts
│   │   │   ├── useClipboard.ts
│   │   │   ├── useHistoryNavigation.ts
│   │   │   ├── useInputBuffer.ts
│   │   │   └── useKeyboardInput.ts
│   │   ├── integration/
│   │   │   ├── useGlobalExit.ts
│   │   │   ├── useGlobalNavigation.ts
│   │   │   └── useVSCodeState.ts
│   │   ├── picker/
│   │   │   ├── useAgentPicker.ts
│   │   │   ├── useFilePicker.ts
│   │   │   ├── useGitLinePicker.ts
│   │   │   ├── useProfilePicker.ts
│   │   │   ├── useRunningAgentsPicker.ts
│   │   │   ├── useSkillsPicker.ts
│   │   │   └── useTodoPicker.ts
│   │   ├── session/
│   │   │   ├── useSessionManagement.ts
│   │   │   ├── useSessionSave.ts
│   │   │   └── useSnapshotState.ts
│   │   └── ui/
│   │       ├── useCommandPanel.ts
│   │       ├── useCursorHide.ts
│   │       ├── usePanelState.ts
│   │       ├── useTerminalFocus.ts
│   │       ├── useTerminalSize.ts
│   │       └── useTerminalTitle.ts
│   ├── i18n/
│   │   ├── I18nContext.tsx
│   │   ├── index.ts
│   │   ├── lang/
│   │   │   ├── en.ts
│   │   │   ├── zh-TW.ts
│   │   │   └── zh.ts
│   │   ├── translations.ts
│   │   └── types.ts
│   ├── mcp/
│   │   ├── aceCodeSearch.ts
│   │   ├── askUserQuestion.ts
│   │   ├── bash.ts
│   │   ├── codebaseSearch.ts
│   │   ├── engines/
│   │   │   └── websearch/
│   │   │       ├── bing.engine.ts
│   │   │       ├── duckduckgo.engine.ts
│   │   │       ├── index.ts
│   │   │       └── types.ts
│   │   ├── filesystem.ts
│   │   ├── ideDiagnostics.ts
│   │   ├── lsp/
│   │   │   ├── HybridCodeSearchService.ts
│   │   │   ├── LSPClient.ts
│   │   │   ├── LSPManager.ts
│   │   │   └── LSPServerRegistry.ts
│   │   ├── notebook.ts
│   │   ├── scheduler.ts
│   │   ├── skills.ts
│   │   ├── subagent.ts
│   │   ├── team.ts
│   │   ├── todo.ts
│   │   ├── types/
│   │   │   ├── aceCodeSearch.types.ts
│   │   │   ├── bash.types.ts
│   │   │   ├── filesystem.types.ts
│   │   │   ├── todo.types.ts
│   │   │   └── websearch.types.ts
│   │   ├── utils/
│   │   │   ├── aceCodeSearch/
│   │   │   │   ├── constants.utils.ts
│   │   │   │   ├── filesystem.utils.ts
│   │   │   │   ├── language.utils.ts
│   │   │   │   ├── search.utils.ts
│   │   │   │   └── symbol.utils.ts
│   │   │   ├── bash/
│   │   │   │   └── security.utils.ts
│   │   │   ├── filesystem/
│   │   │   │   ├── backup.utils.ts
│   │   │   │   ├── batch-operations.utils.ts
│   │   │   │   ├── code-analysis.utils.ts
│   │   │   │   ├── diagnostics.utils.ts
│   │   │   │   ├── edit-tools.utils.ts
│   │   │   │   ├── encoding.utils.ts
│   │   │   │   ├── hashline.utils.ts
│   │   │   │   ├── match-finder.utils.ts
│   │   │   │   ├── message-format.utils.ts
│   │   │   │   ├── office-parser.utils.ts
│   │   │   │   ├── path-fixer.utils.ts
│   │   │   │   ├── read-tools.utils.ts
│   │   │   │   └── similarity.utils.ts
│   │   │   ├── todo/
│   │   │   │   └── date.utils.ts
│   │   │   └── websearch/
│   │   │       ├── browser.utils.ts
│   │   │       └── text.utils.ts
│   │   └── websearch.ts
│   ├── prompt/
│   │   ├── planModeSystemPrompt.ts
│   │   ├── shared/
│   │   │   └── promptHelpers.ts
│   │   ├── systemPrompt.ts
│   │   ├── teamModeSystemPrompt.ts
│   │   └── vulnerabilityHuntingModeSystemPrompt.ts
│   ├── test/
│   │   ├── logger-test.ts
│   │   ├── rg-spawn-repro/
│   │   │   ├── rg-spawn-repro-fixed.mjs
│   │   │   └── rg-spawn-repro.mjs
│   │   └── sse-client/
│   │       ├── app.js
│   │       ├── dialogs.js
│   │       ├── index.html
│   │       ├── json-viewer.js
│   │       └── style.css
│   ├── types/
│   │   └── index.ts
│   ├── ui/
│   │   ├── components/
│   │   │   ├── bash/
│   │   │   │   ├── BackgroundProcessPanel.tsx
│   │   │   │   ├── BashCommandConfirmation.tsx
│   │   │   │   └── CustomCommandExecutionDisplay.tsx
│   │   │   ├── chat/
│   │   │   │   ├── ChatFooter.tsx
│   │   │   │   ├── ChatInput.tsx
│   │   │   │   ├── CodebaseSearchStatus.tsx
│   │   │   │   ├── LoadingIndicator.tsx
│   │   │   │   ├── MessageList.tsx
│   │   │   │   ├── MessageRenderer.tsx
│   │   │   │   ├── PendingMessages.tsx
│   │   │   │   ├── PendingToolCalls.tsx
│   │   │   │   └── UserMessagePreview.tsx
│   │   │   ├── common/
│   │   │   │   ├── MarkdownRenderer.tsx
│   │   │   │   ├── Menu.tsx
│   │   │   │   ├── PickerList.tsx
│   │   │   │   ├── ScrollableSelectInput.tsx
│   │   │   │   ├── ShimmerText.tsx
│   │   │   │   ├── StatusLine.tsx
│   │   │   │   ├── UpdateNotice.tsx
│   │   │   │   └── statusline/
│   │   │   │       ├── builtinIds.ts
│   │   │   │       ├── gitBranch.ts
│   │   │   │       ├── types.ts
│   │   │   │       └── useStatusLineHooks.ts
│   │   │   ├── compression/
│   │   │   │   └── CompressionStatus.tsx
│   │   │   ├── panels/
│   │   │   │   ├── AgentPickerPanel.tsx
│   │   │   │   ├── BranchPanel.tsx
│   │   │   │   ├── BtwPanel.tsx
│   │   │   │   ├── CommandArgsPanel.tsx
│   │   │   │   ├── CommandPanel.tsx
│   │   │   │   ├── ConnectionPanel.tsx
│   │   │   │   ├── CustomCommandConfigPanel.tsx
│   │   │   │   ├── DiffReviewPanel.tsx
│   │   │   │   ├── GitLinePickerPanel.tsx
│   │   │   │   ├── HelpPanel.tsx
│   │   │   │   ├── IdeSelectPanel.tsx
│   │   │   │   ├── MCPInfoPanel.tsx
│   │   │   │   ├── ModelsPanel.tsx
│   │   │   │   ├── NewPromptPanel.tsx
│   │   │   │   ├── PanelsManager.tsx
│   │   │   │   ├── PermissionsPanel.tsx
│   │   │   │   ├── ProfileEditPanel.tsx
│   │   │   │   ├── ProfilePanel.tsx
│   │   │   │   ├── ReviewCommitPanel.tsx
│   │   │   │   ├── RoleCreationPanel.tsx
│   │   │   │   ├── RoleDeletionPanel.tsx
│   │   │   │   ├── RoleListPanel.tsx
│   │   │   │   ├── RoleSubagentCreationPanel.tsx
│   │   │   │   ├── RoleSubagentDeletionPanel.tsx
│   │   │   │   ├── RoleSubagentListPanel.tsx
│   │   │   │   ├── RollbackMenuPanel.tsx
│   │   │   │   ├── RunningAgentsPanel.tsx
│   │   │   │   ├── SessionListPanel.tsx
│   │   │   │   ├── SkillsCreationPanel.tsx
│   │   │   │   ├── SkillsListPanel.tsx
│   │   │   │   ├── SkillsPickerPanel.tsx
│   │   │   │   ├── SubAgentDepthPanel.tsx
│   │   │   │   ├── TodoListPanel.tsx
│   │   │   │   ├── TodoPickerPanel.tsx
│   │   │   │   ├── UsagePanel.tsx
│   │   │   │   └── WorkingDirectoryPanel.tsx
│   │   │   ├── pixel-editor/
│   │   │   │   ├── PixelEditor.tsx
│   │   │   │   ├── index.ts
│   │   │   │   └── types.ts
│   │   │   ├── scheduler/
│   │   │   │   └── SchedulerCountdown.tsx
│   │   │   ├── special/
│   │   │   │   ├── AskUserQuestion.tsx
│   │   │   │   ├── ChatHeader.tsx
│   │   │   │   ├── HookErrorDisplay.tsx
│   │   │   │   └── TodoTree.tsx
│   │   │   ├── sse/
│   │   │   │   └── SSEServerStatus.tsx
│   │   │   └── tools/
│   │   │       ├── DiffViewer.tsx
│   │   │       ├── FileList.tsx
│   │   │       ├── FileRollbackConfirmation.tsx
│   │   │       ├── ToolConfirmation.tsx
│   │   │       └── ToolResultPreview.tsx
│   │   ├── contexts/
│   │   │   └── ThemeContext.tsx
│   │   ├── pages/
│   │   │   ├── ChatScreen.tsx
│   │   │   ├── CodeBaseConfigScreen.tsx
│   │   │   ├── ConfigScreen.tsx
│   │   │   ├── CustomHeadersScreen.tsx
│   │   │   ├── CustomThemeScreen.tsx
│   │   │   ├── ExitScreen.tsx
│   │   │   ├── HeadlessModeScreen.tsx
│   │   │   ├── HelpScreen.tsx
│   │   │   ├── HooksConfigScreen.tsx
│   │   │   ├── LanguageSettingsScreen.tsx
│   │   │   ├── MCPConfigScreen.tsx
│   │   │   ├── PixelEditorScreen.tsx
│   │   │   ├── ProxyConfigScreen.tsx
│   │   │   ├── SensitiveCommandConfigScreen.tsx
│   │   │   ├── SubAgentConfigScreen.tsx
│   │   │   ├── SubAgentListScreen.tsx
│   │   │   ├── SystemPromptConfigScreen.tsx
│   │   │   ├── TaskManagerScreen.tsx
│   │   │   ├── ThemeSettingsScreen.tsx
│   │   │   ├── WelcomeScreen.tsx
│   │   │   ├── chatScreen/
│   │   │   │   ├── ChatScreenConversationView.tsx
│   │   │   │   ├── ChatScreenPanels.tsx
│   │   │   │   ├── types.ts
│   │   │   │   ├── useBackgroundProcessSelection.ts
│   │   │   │   ├── useChatScreenCommands.ts
│   │   │   │   ├── useChatScreenInputHandler.ts
│   │   │   │   ├── useChatScreenLocalState.ts
│   │   │   │   ├── useChatScreenModes.ts
│   │   │   │   ├── useChatScreenSessionLifecycle.ts
│   │   │   │   └── useCodebaseIndexing.ts
│   │   │   └── configScreen/
│   │   │       ├── ConfigFieldRenderer.tsx
│   │   │       ├── ConfigSelectPanel.tsx
│   │   │       ├── ConfigSubViews.tsx
│   │   │       ├── types.ts
│   │   │       ├── useConfigInput.ts
│   │   │       └── useConfigState.ts
│   │   └── themes/
│   │       └── index.ts
│   ├── utils/
│   │   ├── acp/
│   │   │   └── acpManager.ts
│   │   ├── codebase/
│   │   │   ├── codebaseDatabase.ts
│   │   │   ├── codebaseSearchEvents.ts
│   │   │   ├── conversationContext.ts
│   │   │   ├── gitignoreValidator.ts
│   │   │   ├── hashBasedSnapshot.ts
│   │   │   └── reindexCodebase.ts
│   │   ├── commands/
│   │   │   ├── addDir.ts
│   │   │   ├── agent.ts
│   │   │   ├── autoformat.ts
│   │   │   ├── backend.ts
│   │   │   ├── branch.ts
│   │   │   ├── btw.ts
│   │   │   ├── btwStream.ts
│   │   │   ├── clear.ts
│   │   │   ├── codebase.ts
│   │   │   ├── compact.ts
│   │   │   ├── connect.ts
│   │   │   ├── copyLast.ts
│   │   │   ├── custom.ts
│   │   │   ├── deepresearch.ts
│   │   │   ├── diff.ts
│   │   │   ├── export.ts
│   │   │   ├── gitline.ts
│   │   │   ├── help.ts
│   │   │   ├── home.ts
│   │   │   ├── hybridCompress.ts
│   │   │   ├── ide.ts
│   │   │   ├── init.ts
│   │   │   ├── loop.ts
│   │   │   ├── mcp.ts
│   │   │   ├── models.ts
│   │   │   ├── newPrompt.ts
│   │   │   ├── permissions.ts
│   │   │   ├── pixel.ts
│   │   │   ├── plan.ts
│   │   │   ├── profiles.ts
│   │   │   ├── quit.ts
│   │   │   ├── reindex.ts
│   │   │   ├── resume.ts
│   │   │   ├── review.ts
│   │   │   ├── role.ts
│   │   │   ├── roleSubagent.ts
│   │   │   ├── simple.ts
│   │   │   ├── skills.ts
│   │   │   ├── skillsPicker.ts
│   │   │   ├── subagentDepth.ts
│   │   │   ├── team.ts
│   │   │   ├── todoPicker.ts
│   │   │   ├── todolist.ts
│   │   │   ├── toolsearch.ts
│   │   │   ├── usage.ts
│   │   │   ├── vulnerability-hunting.ts
│   │   │   ├── worktree.ts
│   │   │   └── yolo.ts
│   │   ├── config/
│   │   │   ├── apiConfig.ts
│   │   │   ├── codebaseConfig.ts
│   │   │   ├── configEvents.ts
│   │   │   ├── configManager.ts
│   │   │   ├── disabledBuiltInTools.ts
│   │   │   ├── disabledMCPTools.ts
│   │   │   ├── disabledSkills.ts
│   │   │   ├── hooksConfig.ts
│   │   │   ├── languageConfig.ts
│   │   │   ├── permissionsConfig.ts
│   │   │   ├── projectSettings.ts
│   │   │   ├── proxyConfig.ts
│   │   │   ├── subAgentConfig.ts
│   │   │   ├── themeConfig.ts
│   │   │   ├── toolDisplayConfig.ts
│   │   │   └── workingDirConfig.ts
│   │   ├── connection/
│   │   │   ├── ConnectionManager.ts
│   │   │   ├── configStore.ts
│   │   │   ├── contextManager.ts
│   │   │   ├── instanceLock.ts
│   │   │   ├── interactionManager.ts
│   │   │   ├── projectData.ts
│   │   │   ├── stateManager.ts
│   │   │   └── types.ts
│   │   ├── core/
│   │   │   ├── autoCompress.ts
│   │   │   ├── clipboard.ts
│   │   │   ├── compressionCoordinator.ts
│   │   │   ├── contextCompressor.ts
│   │   │   ├── devMode.ts
│   │   │   ├── fileUtils.ts
│   │   │   ├── globalCleanup.ts
│   │   │   ├── logger.ts
│   │   │   ├── notebookManager.ts
│   │   │   ├── processManager.ts
│   │   │   ├── proxyUtils.ts
│   │   │   ├── resourceMonitor.ts
│   │   │   ├── retryUtils.ts
│   │   │   ├── runUpdate.ts
│   │   │   ├── streamGuards.ts
│   │   │   ├── subAgentContextCompressor.ts
│   │   │   ├── textUtils.ts
│   │   │   ├── todoPreprocessor.ts
│   │   │   ├── todoScanner.ts
│   │   │   ├── usageLogger.ts
│   │   │   └── version.ts
│   │   ├── events/
│   │   │   └── todoEvents.ts
│   │   ├── execution/
│   │   │   ├── commandExecutor.ts
│   │   │   ├── hookResultInterpreter.ts
│   │   │   ├── hookStrategies.ts
│   │   │   ├── mcpToolsManager.ts
│   │   │   ├── runningSubAgentTracker.ts
│   │   │   ├── sensitiveCommandManager.ts
│   │   │   ├── subAgentBuiltinTools.ts
│   │   │   ├── subAgentExecutor.ts
│   │   │   ├── subAgentResolver.ts
│   │   │   ├── subAgentStreamProcessor.ts
│   │   │   ├── subAgentToolApproval.ts
│   │   │   ├── subAgentToolInterceptor.ts
│   │   │   ├── subAgentTypes.ts
│   │   │   ├── subagents/
│   │   │   │   ├── analyzeAgent.ts
│   │   │   │   ├── debugAgent.ts
│   │   │   │   ├── exploreAgent.ts
│   │   │   │   ├── generalAgent.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── planAgent.ts
│   │   │   │   ├── qaAgent.ts
│   │   │   │   └── types.ts
│   │   │   ├── teamExecutor.ts
│   │   │   ├── teamTracker.ts
│   │   │   ├── terminal.ts
│   │   │   ├── tokenLimiter.ts
│   │   │   ├── toolExecutor.ts
│   │   │   ├── toolSearchService.ts
│   │   │   ├── unifiedHooksExecutor.ts
│   │   │   └── yoloPermissionChecker.ts
│   │   ├── index.ts
│   │   ├── latex/
│   │   │   └── unicodeMath.ts
│   │   ├── session/
│   │   │   ├── chatExporter.ts
│   │   │   ├── checkpointManager.ts
│   │   │   ├── commandUsageManager.ts
│   │   │   ├── historyManager.ts
│   │   │   ├── projectUtils.ts
│   │   │   ├── sessionConverter.ts
│   │   │   └── sessionManager.ts
│   │   ├── sse/
│   │   │   ├── daemonLogger.ts
│   │   │   ├── sseDaemon.ts
│   │   │   └── sseManager.ts
│   │   ├── ssh/
│   │   │   └── sshClient.ts
│   │   ├── task/
│   │   │   ├── loopManager.ts
│   │   │   ├── taskExecutor.ts
│   │   │   └── taskManager.ts
│   │   ├── team/
│   │   │   ├── teamConfig.ts
│   │   │   ├── teamSnapshot.ts
│   │   │   ├── teamTaskList.ts
│   │   │   └── teamWorktree.ts
│   │   └── ui/
│   │       ├── escapeHandler.ts
│   │       ├── externalEditor.ts
│   │       ├── fileDialog.ts
│   │       ├── messageFormatter.ts
│   │       ├── pickerState.ts
│   │       ├── skillMask.ts
│   │       ├── textBuffer.ts
│   │       ├── updateNotice.ts
│   │       ├── userInteractionError.ts
│   │       └── vscodeConnection.ts
│   └── vendor/
│       └── ink/
│           ├── license
│           ├── package.json
│           └── src/
│               ├── colorize.ts
│               ├── components/
│               │   ├── App.tsx
│               │   ├── AppContext.ts
│               │   ├── Box.tsx
│               │   ├── CursorContext.ts
│               │   ├── ErrorOverview.tsx
│               │   ├── FocusContext.ts
│               │   ├── Newline.tsx
│               │   ├── Spacer.tsx
│               │   ├── Static.tsx
│               │   ├── StderrContext.ts
│               │   ├── StdinContext.ts
│               │   ├── StdoutContext.ts
│               │   ├── Text.tsx
│               │   └── Transform.tsx
│               ├── cursor-helpers.ts
│               ├── devtools-window-polyfill.ts
│               ├── devtools.ts
│               ├── dom.ts
│               ├── get-max-width.ts
│               ├── global.d.ts
│               ├── hooks/
│               │   ├── use-app.ts
│               │   ├── use-cursor.ts
│               │   ├── use-focus-manager.ts
│               │   ├── use-focus.ts
│               │   ├── use-input.ts
│               │   ├── use-stderr.ts
│               │   ├── use-stdin.ts
│               │   └── use-stdout.ts
│               ├── index.ts
│               ├── ink.tsx
│               ├── instances.ts
│               ├── line-width-cache.ts
│               ├── log-update.ts
│               ├── measure-element.ts
│               ├── measure-text.ts
│               ├── output.ts
│               ├── parse-keypress.ts
│               ├── reconciler.ts
│               ├── render-border.ts
│               ├── render-node-to-output.ts
│               ├── render.ts
│               ├── renderer.ts
│               ├── squash-text-nodes.ts
│               ├── styles.ts
│               ├── vendor-types.d.ts
│               ├── wrap-text.ts
│               ├── yoga-compat.ts
│               └── yoga-ts/
│                   ├── enums.ts
│                   └── index.ts
└── tsconfig.json
Download .txt
Showing preview only (293K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (3382 symbols across 437 files)

FILE: VSIX/src/aceHandlers.ts
  type BroadcastFunction (line 8) | type BroadcastFunction = (message: string) => void;
  function handleGoToDefinition (line 13) | async function handleGoToDefinition(
  function handleFindReferences (line 62) | async function handleFindReferences(
  function handleGetSymbols (line 111) | async function handleGetSymbols(
  function handleGetDiagnostics (line 168) | function handleGetDiagnostics(

FILE: VSIX/src/commitMessageGenerator.ts
  constant GENERATING_CONTEXT_KEY (line 7) | const GENERATING_CONTEXT_KEY = 'snow-cli.commitMessageGenerating';
  constant CONFIG_DIR (line 8) | const CONFIG_DIR = join(homedir(), '.snow');
  constant ACTIVE_PROFILE_FILE (line 9) | const ACTIVE_PROFILE_FILE = join(CONFIG_DIR, 'active-profile.json');
  constant LEGACY_ACTIVE_PROFILE_FILE (line 10) | const LEGACY_ACTIVE_PROFILE_FILE = join(CONFIG_DIR, 'active-profile.txt');
  constant PROFILES_DIR (line 11) | const PROFILES_DIR = join(CONFIG_DIR, 'profiles');
  constant LEGACY_CONFIG_FILE (line 12) | const LEGACY_CONFIG_FILE = join(CONFIG_DIR, 'config.json');
  constant CUSTOM_HEADERS_FILE (line 13) | const CUSTOM_HEADERS_FILE = join(CONFIG_DIR, 'custom-headers.json');
  constant MAX_DIFF_CHARS (line 14) | const MAX_DIFF_CHARS = 120_000;
  constant API_MAX_RETRIES (line 15) | const API_MAX_RETRIES = 5;
  constant API_RETRY_BASE_DELAY_MS (line 16) | const API_RETRY_BASE_DELAY_MS = 1000;
  type GenerateCommitMessageOptions (line 20) | interface GenerateCommitMessageOptions {
  type RequestMethod (line 24) | type RequestMethod = 'chat' | 'responses' | 'gemini' | 'anthropic';
  type SnowApiConfig (line 26) | interface SnowApiConfig {
  type SnowAppConfig (line 37) | interface SnowAppConfig {
  type GitExtension (line 41) | interface GitExtension {
  type GitAPI (line 45) | interface GitAPI {
  type GitRepository (line 49) | interface GitRepository {
  type DiffPayload (line 56) | interface DiffPayload {
  type CustomHeadersConfig (line 62) | interface CustomHeadersConfig {
  function registerCommitMessageCommands (line 70) | function registerCommitMessageCommands(
  function generateCommitMessageWithRequirements (line 94) | async function generateCommitMessageWithRequirements(): Promise<void> {
  function generateCommitMessage (line 116) | async function generateCommitMessage(
  function cancelCommitMessageGeneration (line 189) | function cancelCommitMessageGeneration(): void {
  function getTargetRepository (line 193) | async function getTargetRepository(): Promise<GitRepository | undefined> {
  function collectDiffPayload (line 223) | async function collectDiffPayload(
  function execGit (line 248) | function execGit(
  function requestCommitMessage (line 289) | async function requestCommitMessage(
  function loadActiveSnowConfig (line 319) | function loadActiveSnowConfig(): SnowApiConfig {
  function getActiveProfileName (line 334) | function getActiveProfileName(): string {
  function readJsonFile (line 350) | function readJsonFile<T>(filePath: string): T | undefined {
  function buildPrompt (line 362) | function buildPrompt(
  function requestChatCommitMessage (line 385) | async function requestChatCommitMessage(
  function requestResponsesCommitMessage (line 410) | async function requestResponsesCommitMessage(
  function requestGeminiCommitMessage (line 432) | async function requestGeminiCommitMessage(
  function requestAnthropicCommitMessage (line 468) | async function requestAnthropicCommitMessage(
  function buildHeaders (line 500) | function buildHeaders(
  function loadCustomHeaders (line 524) | function loadCustomHeaders(config: SnowApiConfig): Record<string, string> {
  function readResponseJson (line 542) | async function readResponseJson(
  class ApiRequestError (line 559) | class ApiRequestError extends Error {
    method constructor (line 560) | constructor(
  function withApiRetry (line 571) | async function withApiRetry<T>(
  function isRetriableApiError (line 602) | function isRetriableApiError(error: unknown): boolean {
  function delay (line 628) | function delay(ms: number, signal: AbortSignal): Promise<void> {
  function extractResponsesText (line 654) | function extractResponsesText(data: any): string {
  function normalizeCommitMessage (line 667) | function normalizeCommitMessage(message: string): string {
  function trimTrailingSlash (line 684) | function trimTrailingSlash(value: string): string {
  function createAbortError (line 688) | function createAbortError(): Error {
  function isAbortError (line 694) | function isAbortError(error: unknown): boolean {

FILE: VSIX/src/diffHandlers.ts
  function ensureContentProvidersRegistered (line 23) | function ensureContentProvidersRegistered(): void {
  function disposeContentProviders (line 45) | function disposeContentProviders(): void {
  function showGitDiff (line 61) | async function showGitDiff(filePath: string): Promise<void> {
  function registerDiffCommands (line 132) | function registerDiffCommands(

FILE: VSIX/src/extension.ts
  function getConfig (line 26) | function getConfig<T>(key: string, fallback: T): T {
  function refreshStartupCommandManager (line 30) | function refreshStartupCommandManager(): void {
  function applySidebarContext (line 36) | function applySidebarContext(): void {
  function getWorkspaceFolderForActiveEditor (line 45) | function getWorkspaceFolderForActiveEditor(): string | undefined {
  function getSplitTerminalShellFamily (line 55) | function getSplitTerminalShellFamily(): ShellFamily {
  function getExistingSplitSnowTerminal (line 59) | function getExistingSplitSnowTerminal(): vscode.Terminal | undefined {
  function openSplitTerminal (line 71) | async function openSplitTerminal(): Promise<vscode.Terminal> {
  function ensureSplitSnowTerminal (line 99) | async function ensureSplitSnowTerminal(): Promise<vscode.Terminal> {
  function sendFilePathsToSplitTerminal (line 108) | async function sendFilePathsToSplitTerminal(paths: string[]): Promise<vo...
  function sendFilePathsToConfiguredTerminal (line 123) | async function sendFilePathsToConfiguredTerminal(
  function pickPaths (line 139) | async function pickPaths(mode: 'file' | 'folder'): Promise<string[]> {
  function formatSelectionLocation (line 150) | function formatSelectionLocation(
  function checkExtensionVersionChange (line 176) | function checkExtensionVersionChange(context: vscode.ExtensionContext): ...
  function activate (line 205) | function activate(context: vscode.ExtensionContext) {
  function deactivate (line 405) | function deactivate() {

FILE: VSIX/src/gitBlameProvider.ts
  type CommitMeta (line 5) | interface CommitMeta {
  type LineBlame (line 12) | interface LineBlame {
  type BlameCache (line 17) | interface BlameCache {
  constant UNCOMMITTED_HASH (line 22) | const UNCOMMITTED_HASH = '0000000000000000000000000000000000000000';
  constant HASH_LINE_RE (line 23) | const HASH_LINE_RE = /^([0-9a-f]{40}) (\d+) (\d+)/;
  constant MAX_CACHE_FILES (line 24) | const MAX_CACHE_FILES = 10;
  constant MAX_BUFFER (line 25) | const MAX_BUFFER = 10 * 1024 * 1024;
  function createDecorationTypes (line 35) | function createDecorationTypes(): void {
  function formatRelativeTime (line 53) | function formatRelativeTime(timestamp: number): string {
  function formatBlameAnnotation (line 63) | function formatBlameAnnotation(blame: LineBlame): string {
  function formatFileAnnotation (line 71) | function formatFileAnnotation(blame: LineBlame, maxAuthorLen: number): s...
  function getRepoRoot (line 78) | function getRepoRoot(filePath: string): string | undefined {
  function cancelPendingBlame (line 84) | function cancelPendingBlame(): void {
  function runGitBlame (line 91) | function runGitBlame(filePath: string): Promise<(LineBlame | undefined)[...
  function parsePorcelainBlame (line 118) | function parsePorcelainBlame(output: string): (LineBlame | undefined)[] {
  function evictOldestCache (line 157) | function evictOldestCache(): void {
  function getBlameData (line 163) | async function getBlameData(document: vscode.TextDocument): Promise<(Lin...
  function updateCurrentLineBlame (line 183) | async function updateCurrentLineBlame(editor: vscode.TextEditor): Promis...
  function showFileAnnotations (line 207) | async function showFileAnnotations(editor: vscode.TextEditor): Promise<v...
  function clearFileAnnotations (line 232) | function clearFileAnnotations(editor: vscode.TextEditor): void {
  function clearAllDecorations (line 236) | function clearAllDecorations(): void {
  function onConfigChanged (line 243) | function onConfigChanged(): void {
  function registerGitBlame (line 261) | function registerGitBlame(context: vscode.ExtensionContext): void {

FILE: VSIX/src/ptyManager.ts
  function loadPty (line 7) | function loadPty(): any {
  type PtyManagerEvents (line 11) | interface PtyManagerEvents {
  type ShellFamily (line 16) | type ShellFamily = 'powershell' | 'cmd' | 'posix';
  type ResolvedShell (line 18) | type ResolvedShell = {
  function detectShellFamily (line 24) | function detectShellFamily(shellPath: string): ShellFamily {
  function defaultArgsForFamily (line 35) | function defaultArgsForFamily(family: ShellFamily): string[] {
  function detectPowerShellPath (line 46) | function detectPowerShellPath(): string {
  function windowsFallback (line 57) | function windowsFallback(): ResolvedShell {
  function posixFallback (line 62) | function posixFallback(): ResolvedShell {
  function resolveAutoFromVSCode (line 67) | function resolveAutoFromVSCode(): ResolvedShell | undefined {
  function resolveShellProfile (line 107) | function resolveShellProfile(input?: string): ResolvedShell {
  class PtyManager (line 124) | class PtyManager {
    method setResolvedShell (line 130) | public setResolvedShell(shell: ResolvedShell): void {
    method getShellFamily (line 134) | public getShellFamily(): ShellFamily {
    method start (line 138) | public start(
    method write (line 222) | public write(data: string): void {
    method resize (line 226) | public resize(cols: number, rows: number): void {
    method kill (line 234) | public kill(): void {
    method isRunning (line 245) | public isRunning(): boolean {
    method normalizeDimension (line 249) | private normalizeDimension(value: number | undefined, fallback: number...
    method fixSpawnHelperPermissions (line 257) | private fixSpawnHelperPermissions(): void {

FILE: VSIX/src/sidebarTerminalProvider.ts
  type LaunchPolicy (line 10) | type LaunchPolicy = 'ensure' | 'restart';
  type Trigger (line 11) | type Trigger =
  type LifecycleAction (line 19) | type LifecycleAction = {
  type LifecycleActionTemplate (line 27) | type LifecycleActionTemplate = Omit<LifecycleAction, 'trigger'>;
  type EnsureOptions (line 28) | type EnsureOptions = {focus?: boolean};
  type RestartOptions (line 29) | type RestartOptions = {
  type ReloadFrontendOptions (line 33) | type ReloadFrontendOptions = {focusAfterReady?: boolean};
  type OutputLogLevel (line 35) | type OutputLogLevel = 'debug' | 'info' | 'warn' | 'error';
  type LogScope (line 36) | type LogScope = 'SidebarTerminal' | 'Frontend';
  type FrontendLogMessage (line 37) | type FrontendLogMessage = {
  type TerminalConfig (line 44) | type TerminalConfig = {
  type NormalizedFontConfig (line 52) | type NormalizedFontConfig = Omit<TerminalConfig, 'shellProfile'>;
  type RendererHealthStage (line 54) | type RendererHealthStage =
  type RendererHealthStats (line 60) | type RendererHealthStats = {
  type RendererHealthStatField (line 73) | type RendererHealthStatField = {
  constant RENDERER_HEALTH_STAT_FIELDS (line 79) | const RENDERER_HEALTH_STAT_FIELDS: readonly RendererHealthStatField[] = [
  type BellSound (line 116) | type BellSound = 'beep' | 'ding' | 'chime' | 'pluck' | 'blip' | 'none';
  type BellConfig (line 118) | type BellConfig = {
  type ExtensionToWebviewMessage (line 125) | type ExtensionToWebviewMessage =
  type WebviewToExtensionMessage (line 142) | type WebviewToExtensionMessage =
  constant RESOURCE_ROOT_SEGMENTS (line 157) | const RESOURCE_ROOT_SEGMENTS: readonly (readonly string[])[] = [
  constant XTERM_SCRIPT_SEGMENTS (line 162) | const XTERM_SCRIPT_SEGMENTS: readonly (readonly string[])[] = [
  constant XTERM_CSS_SEGMENTS (line 170) | const XTERM_CSS_SEGMENTS = [
  constant SIDEBAR_STYLE_SEGMENTS (line 177) | const SIDEBAR_STYLE_SEGMENTS = ['res', 'sidebarTerminal.css'] as const;
  constant SIDEBAR_SCRIPT_SEGMENTS (line 178) | const SIDEBAR_SCRIPT_SEGMENTS = ['res', 'sidebarTerminal.js'] as const;
  constant OUTPUT_BUFFER_MAX_BYTES (line 180) | const OUTPUT_BUFFER_MAX_BYTES = 2 * 1024 * 1024;
  constant OUTPUT_TRUNCATION_NOTICE (line 181) | const OUTPUT_TRUNCATION_NOTICE =
  constant FOCUS_RETRY_DELAYS_MS (line 183) | const FOCUS_RETRY_DELAYS_MS = [0, 80, 240] as const;
  constant FONT_SIZE_MIN (line 185) | const FONT_SIZE_MIN = 8;
  constant FONT_SIZE_MAX (line 186) | const FONT_SIZE_MAX = 32;
  constant LINE_HEIGHT_MIN (line 187) | const LINE_HEIGHT_MIN = 0.8;
  constant LINE_HEIGHT_MAX (line 188) | const LINE_HEIGHT_MAX = 2.0;
  constant OUTPUT_CHANNEL_NAME (line 190) | const OUTPUT_CHANNEL_NAME = 'Snow CLI';
  constant SIDEBAR_LOG_SCOPE (line 191) | const SIDEBAR_LOG_SCOPE: LogScope = 'SidebarTerminal';
  constant FRONTEND_LOG_SCOPE (line 192) | const FRONTEND_LOG_SCOPE: LogScope = 'Frontend';
  constant INVALID_MESSAGE_LOG_THROTTLE_MS (line 193) | const INVALID_MESSAGE_LOG_THROTTLE_MS = 5000;
  constant RESTART_SETTLE_DELAY_MS (line 194) | const RESTART_SETTLE_DELAY_MS = 150;
  constant RESTART_FRONTEND_FALLBACK_MS (line 195) | const RESTART_FRONTEND_FALLBACK_MS = 3000;
  constant MANUAL_RESTART_DEBOUNCE_MS (line 196) | const MANUAL_RESTART_DEBOUNCE_MS = 1500;
  constant MAX_SIDEBAR_TERMINAL_TABS (line 197) | const MAX_SIDEBAR_TERMINAL_TABS = 5;
  constant SHOW_RENDERER_TEST_CONTROLS (line 199) | const SHOW_RENDERER_TEST_CONTROLS = false;
  constant DEFAULT_ACTION (line 201) | const DEFAULT_ACTION: LifecycleActionTemplate = {
  constant TRIGGER_ACTIONS (line 209) | const TRIGGER_ACTIONS: Record<Trigger, LifecycleActionTemplate> = {
  function isRecord (line 245) | function isRecord(value: unknown): value is Record<string, unknown> {
  function clampNumber (line 249) | function clampNumber(value: number, min: number, max: number): number {
  function asOptionalNonEmptyString (line 253) | function asOptionalNonEmptyString(value: unknown): string | undefined {
  function normalizeFrontendLogLevel (line 261) | function normalizeFrontendLogLevel(value: unknown): OutputLogLevel {
  function summarizeForLog (line 273) | function summarizeForLog(value: string, maxLength = 160): string {
  function describeWebviewMessage (line 280) | function describeWebviewMessage(rawMessage: unknown): string {
  function formatUnknownError (line 303) | function formatUnknownError(error: unknown): string {
  function asOptionalFiniteNumber (line 310) | function asOptionalFiniteNumber(value: unknown): number | undefined {
  function normalizeRendererHealthStage (line 316) | function normalizeRendererHealthStage(
  function parseRendererHealthStatValue (line 330) | function parseRendererHealthStatValue(
  function parseRendererHealthStats (line 339) | function parseRendererHealthStats(
  function parseWebviewMessage (line 358) | function parseWebviewMessage(
  function mergeActions (line 442) | function mergeActions(
  class PendingLifecycleQueue (line 468) | class PendingLifecycleQueue {
    method queue (line 471) | public queue(action: LifecycleAction): void {
    method mergeWithPending (line 477) | public mergeWithPending(current: LifecycleAction): LifecycleAction {
    method take (line 486) | public take(): LifecycleAction | undefined {
    method clear (line 492) | public clear(): void {
  class SidebarTerminalProvider (line 497) | class SidebarTerminalProvider implements vscode.WebviewViewProvider {
    method constructor (line 524) | constructor(private readonly extensionUri: vscode.Uri) {
    method writeOutputLog (line 531) | private writeOutputLog(
    method logSidebar (line 552) | private logSidebar(
    method logSidebarInfo (line 560) | private logSidebarInfo(message: string, details?: string): void {
    method logSidebarWarn (line 564) | private logSidebarWarn(message: string, details?: string): void {
    method logSidebarError (line 568) | private logSidebarError(message: string, details?: string): void {
    method logInvalidWebviewMessage (line 572) | private logInvalidWebviewMessage(rawMessage: unknown): void {
    method getTerminalConfig (line 587) | private getTerminalConfig(): TerminalConfig {
    method normalizeFontConfig (line 598) | private normalizeFontConfig(config: TerminalConfig): NormalizedFontCon...
    method applyShellProfile (line 611) | private applyShellProfile(): void {
    method sendFontConfig (line 619) | private sendFontConfig(): void {
    method getBellConfig (line 624) | private getBellConfig(): BellConfig {
    method sendBellConfig (line 646) | public sendBellConfig(): void {
    method updateRendererRecoveryState (line 650) | private updateRendererRecoveryState(
    method getWorkspaceFolderForActiveEditor (line 680) | private getWorkspaceFolderForActiveEditor(): string | undefined {
    method createTab (line 690) | public createTab(options?: EnsureOptions): void {
    method closeActiveTab (line 718) | public closeActiveTab(options?: EnsureOptions): void {
    method createSession (line 726) | private createSession(): SidebarTerminalSession {
    method getSessionById (line 743) | private getSessionById(
    method getOrderedSessions (line 752) | private getOrderedSessions(): SidebarTerminalSession[] {
    method getActiveSession (line 761) | private getActiveSession(): SidebarTerminalSession | undefined {
    method ensureActiveSessionExists (line 765) | private ensureActiveSessionExists(): SidebarTerminalSession {
    method resizeAllRunningSessions (line 773) | private resizeAllRunningSessions(cols: number, rows: number): void {
    method syncTabsToWebview (line 781) | private syncTabsToWebview(): void {
    method syncActiveSessionToWebview (line 794) | private syncActiveSessionToWebview(options?: {
    method switchActiveSession (line 816) | private switchActiveSession(
    method closeSession (line 836) | private closeSession(
    method ensureTerminal (line 901) | public ensureTerminal(options?: EnsureOptions): void {
    method restartTerminal (line 906) | public restartTerminal(options?: RestartOptions): void {
    method onViewReady (line 947) | public onViewReady(): void {
    method onViewRecreate (line 964) | public onViewRecreate(): void {
    method resolveWebviewView (line 969) | public resolveWebviewView(
    method configureWebview (line 991) | private configureWebview(webviewView: vscode.WebviewView): void {
    method registerWebviewEventHandlers (line 1005) | private registerWebviewEventHandlers(webviewView: vscode.WebviewView):...
    method teardownRuntimeState (line 1021) | private teardownRuntimeState(): void {
    method handleViewDisposed (line 1032) | private handleViewDisposed(): void {
    method isWebviewOperational (line 1053) | private isWebviewOperational(): boolean {
    method handleMessage (line 1057) | private handleMessage(rawMessage: unknown): void {
    method handleRendererHealthMessage (line 1127) | private handleRendererHealthMessage(
    method writeInputToTerminal (line 1225) | private writeInputToTerminal(data: string): void {
    method startTerminal (line 1231) | private startTerminal(sessionId?: string): void {
    method handleTerminalData (line 1280) | private handleTerminalData(sessionId: string, data: string): void {
    method handleTerminalExit (line 1292) | private handleTerminalExit(
    method scheduleEnsureRunning (line 1329) | private scheduleEnsureRunning(): void {
    method clearEnsureRunningTimer (line 1341) | private clearEnsureRunningTimer(): void {
    method clearRestartCompletionTimer (line 1345) | private clearRestartCompletionTimer(): void {
    method clearTimer (line 1349) | private clearTimer(timer: NodeJS.Timeout | undefined): undefined {
    method scheduleRestartCompletion (line 1356) | private scheduleRestartCompletion(delayMs: number): void {
    method clearRestartingSessionState (line 1364) | private clearRestartingSessionState(): void {
    method finishRestart (line 1378) | private finishRestart(drainPending = true): void {
    method ensureTerminalRunning (line 1394) | private ensureTerminalRunning(sessionId?: string): void {
    method runLifecycleAction (line 1404) | private runLifecycleAction(trigger: Trigger, options?: EnsureOptions):...
    method applyLifecycleAction (line 1414) | private applyLifecycleAction(action: LifecycleAction): void {
    method executeLifecycleAction (line 1431) | private executeLifecycleAction(action: LifecycleAction): void {
    method executeRestart (line 1443) | private executeRestart(action: LifecycleAction): void {
    method reloadWebviewFrontend (line 1482) | private reloadWebviewFrontend(options?: ReloadFrontendOptions): void {
    method clearFocusRetryTimers (line 1502) | private clearFocusRetryTimers(): void {
    method requestWebviewFocus (line 1512) | private requestWebviewFocus(): void {
    method postWebviewMessage (line 1529) | private postWebviewMessage(message: ExtensionToWebviewMessage): void {
    method getExtensionResourceUri (line 1536) | private getExtensionResourceUri(segments: readonly string[]): vscode.U...
    method getWebviewResourceUri (line 1540) | private getWebviewResourceUri(
    method getHtmlForWebview (line 1547) | private getHtmlForWebview(
    method handleDropPaths (line 1605) | private handleDropPaths(uris: string[]): void {
    method sendFilePaths (line 1627) | public sendFilePaths(paths: string[]): void {
    method dispose (line 1646) | public dispose(): void {

FILE: VSIX/src/sidebarTerminalSession.ts
  type SidebarTerminalSize (line 3) | type SidebarTerminalSize = {cols: number; rows: number};
  type SidebarTerminalTabState (line 5) | type SidebarTerminalTabState = {
  type SidebarTerminalSessionOptions (line 14) | type SidebarTerminalSessionOptions = {
  type SidebarTerminalSessionStartHandlers (line 21) | type SidebarTerminalSessionStartHandlers = {
  type StartupCommandProvider (line 30) | type StartupCommandProvider = () => string | undefined;
  class SidebarTerminalSession (line 32) | class SidebarTerminalSession {
    method constructor (line 48) | constructor(options: SidebarTerminalSessionOptions) {
    method setResolvedShell (line 55) | public setResolvedShell(shell: ResolvedShell): void {
    method getShellFamily (line 59) | public getShellFamily(): ShellFamily {
    method start (line 63) | public start(
    method write (line 100) | public write(data: string): void {
    method resize (line 104) | public resize(cols: number, rows: number): void {
    method kill (line 108) | public kill(): void {
    method isRunning (line 112) | public isRunning(): boolean {
    method isRestarting (line 116) | public isRestarting(): boolean {
    method setRestarting (line 120) | public setRestarting(restarting: boolean): void {
    method suppressCurrentExitBanner (line 127) | public suppressCurrentExitBanner(): void {
    method clearTranscript (line 133) | public clearTranscript(): void {
    method appendOutput (line 140) | public appendOutput(data: string): void {
    method appendExitBanner (line 156) | public appendExitBanner(code: number): void {
    method getTranscript (line 161) | public getTranscript(): string {
    method toTabState (line 168) | public toTabState(isActive: boolean): SidebarTerminalTabState {

FILE: VSIX/src/startupCommandManager.ts
  constant DEFAULT_STARTUP_COMMAND (line 1) | const DEFAULT_STARTUP_COMMAND = 'snow';
  function normalizeStartupCommand (line 3) | function normalizeStartupCommand(command: string): string | undefined {
  function parseStartupCommands (line 8) | function parseStartupCommands(rawConfig: string | undefined): string[] {
  class StartupCommandManager (line 19) | class StartupCommandManager {
    method setStartupCommandConfig (line 23) | public setStartupCommandConfig(rawConfig: string | undefined): void {
    method getNextStartupCommand (line 28) | public getNextStartupCommand(): string | undefined {

FILE: VSIX/src/terminalPathFormatter.ts
  type TerminalPathFormatOptions (line 3) | type TerminalPathFormatOptions = {
  function quoteForPowerShell (line 8) | function quoteForPowerShell(path: string): string {
  function quoteForCmd (line 12) | function quoteForCmd(path: string): string {
  function quoteForBash (line 16) | function quoteForBash(path: string): string {
  function formatTerminalPathPayload (line 20) | function formatTerminalPathPayload(

FILE: VSIX/src/terminalProxy.ts
  type TerminalProxyEnv (line 3) | type TerminalProxyEnv = Record<string, string>;
  function asOptionalNonEmptyString (line 5) | function asOptionalNonEmptyString(value: string | undefined): string | u...
  function getConfiguredSnowTerminalProxyUrl (line 10) | function getConfiguredSnowTerminalProxyUrl(): string | undefined {
  function getVsCodeHttpProxyUrl (line 18) | function getVsCodeHttpProxyUrl(): string | undefined {
  function hasExplicitSnowTerminalProxyUrl (line 23) | function hasExplicitSnowTerminalProxyUrl(): boolean {
  function getSnowTerminalProxyUrl (line 27) | function getSnowTerminalProxyUrl(): string | undefined {
  function getSnowTerminalProxyEnv (line 31) | function getSnowTerminalProxyEnv(): TerminalProxyEnv | undefined {

FILE: VSIX/src/webSocketServer.ts
  constant BASE_PORT (line 19) | const BASE_PORT = 9527;
  constant MAX_PORT (line 20) | const MAX_PORT = 9537;
  function normalizePath (line 34) | function normalizePath(filePath: string | undefined): string | undefined {
  function getWorkspaceFolderKeys (line 50) | function getWorkspaceFolderKeys(): string[] {
  function getWorkspaceFolderForEditor (line 68) | function getWorkspaceFolderForEditor(
  function broadcast (line 81) | function broadcast(message: string): void {
  function isTrackableEditor (line 89) | function isTrackableEditor(
  function getTrackableVisibleEditors (line 95) | function getTrackableVisibleEditors(): vscode.TextEditor[] {
  function getFallbackEditor (line 99) | function getFallbackEditor(
  function sendEditorContext (line 117) | function sendEditorContext(): void {
  function handleMessage (line 168) | function handleMessage(message: string): void {
  function startWebSocketServer (line 233) | function startWebSocketServer(): void {
  function stopWebSocketServer (line 324) | function stopWebSocketServer(): void {
  function getActualPort (line 363) | function getActualPort(): number {
  function getClientCount (line 370) | function getClientCount(): number {

FILE: build.mjs
  method setup (line 9) | setup(build) {

FILE: scripts/postinstall.cjs
  function detectRegion (line 22) | function detectRegion() {
  function getCurrentRegistry (line 48) | function getCurrentRegistry() {
  function checkNodeVersion (line 60) | function checkNodeVersion() {
  function tryInstallSharp (line 85) | function tryInstallSharp() {
  function main (line 111) | async function main() {

FILE: source/agents/bashOutputSummaryAgent.ts
  class BashOutputSummaryAgent (line 14) | class BashOutputSummaryAgent {
    method initialize (line 19) | private async initialize(): Promise<boolean> {
    method clearCache (line 36) | clearCache(): void {
    method isAvailable (line 42) | async isAvailable(): Promise<boolean> {
    method callModel (line 49) | private async callModel(
    method summarizeCommandResult (line 124) | async summarizeCommandResult(

FILE: source/agents/codebaseIndexAgent.ts
  type ProgressCallback (line 22) | type ProgressCallback = (progress: {
  class CodebaseIndexAgent (line 35) | class CodebaseIndexAgent {
    method constructor (line 102) | constructor(projectRoot: string) {
    method start (line 118) | async start(progressCallback?: ProgressCallback): Promise<void> {
    method stop (line 282) | async stop(): Promise<void> {
    method isIndexing (line 302) | isIndexing(): boolean {
    method getProgress (line 309) | async getProgress() {
    method clear (line 321) | clear(): void {
    method close (line 328) | close(): void {
    method isWatcherEnabled (line 336) | async isWatcherEnabled(): Promise<boolean> {
    method startWatching (line 348) | startWatching(progressCallback?: ProgressCallback): void {
    method stopWatching (line 449) | stopWatching(): void {
    method waitForWatcherClose (line 472) | async waitForWatcherClose(): Promise<void> {
    method debounceFileChange (line 482) | private debounceFileChange(filePath: string, relativePath: string): vo...
    method handleFileChange (line 501) | private async handleFileChange(
    method loadGitignore (line 533) | private loadGitignore(): void {
    method addDefaultIgnorePatterns (line 544) | private addDefaultIgnorePatterns(): void {
    method scanFiles (line 568) | public async scanFiles(): Promise<string[]> {
    method countFiles (line 623) | public async countFiles(): Promise<number> {
    method processFiles (line 631) | private async processFiles(files: string[]): Promise<void> {
    method processFile (line 657) | private async processFile(filePath: string): Promise<void> {
    method splitIntoChunks (line 824) | private splitIntoChunks(content: string, filePath: string): CodeChunk[] {
    method splitDocumentIntoChunks (line 881) | private splitDocumentIntoChunks(
    method extractDetailedError (line 971) | private extractDetailedError(error: unknown): string {
    method notifyProgress (line 994) | private notifyProgress(progress: {

FILE: source/agents/codebaseReviewAgent.ts
  class CodebaseReviewAgent (line 16) | class CodebaseReviewAgent {
    method initialize (line 66) | private async initialize(): Promise<boolean> {
    method clearCache (line 96) | clearCache(): void {
    method isAvailable (line 105) | async isAvailable(): Promise<boolean> {
    method callModel (line 116) | private async callModel(
    method tryParseJSON (line 236) | private tryParseJSON(response: string): any | null {
    method reviewWithRetry (line 267) | private async reviewWithRetry(
    method sleep (line 428) | private sleep(ms: number): Promise<void> {
    method reviewResults (line 441) | async reviewResults(

FILE: source/agents/compactAgent.ts
  class CompactAgent (line 29) | class CompactAgent {
    method initialize (line 38) | private async initialize(): Promise<boolean> {
    method clearCache (line 61) | clearCache(): void {
    method isAvailable (line 70) | async isAvailable(): Promise<boolean> {
    method callCompactModel (line 85) | private async callCompactModel(
    method extractWebPageContent (line 279) | async extractWebPageContent(

FILE: source/agents/reviewAgent.ts
  class ReviewAgent (line 15) | class ReviewAgent {
    method initialize (line 24) | private async initialize(): Promise<boolean> {
    method clearCache (line 46) | clearCache(): void {
    method isAvailable (line 55) | async isAvailable(): Promise<boolean> {
    method findGitRoot (line 67) | private findGitRoot(startDir: string): string | null {
    method checkGitRepository (line 86) | checkGitRepository(): {isGitRepo: boolean; gitRoot?: string; error?: s...
    method getWorkingTreeStatus (line 126) | getWorkingTreeStatus(gitRoot: string): {
    method getStagedDiff (line 188) | getStagedDiff(gitRoot: string): string {
    method getUnstagedDiff (line 216) | getUnstagedDiff(gitRoot: string): string {
    method getGitDiff (line 244) | getGitDiff(gitRoot: string): string {
    method runGit (line 283) | private runGit(
    method assertSafeCommitSha (line 300) | private assertSafeCommitSha(sha: string): void {
    method normalizeNonNegativeInt (line 306) | private normalizeNonNegativeInt(value: number, name: string): number {
    method listCommitsPaginated (line 313) | listCommitsPaginated(
    method getCommitPatch (line 373) | getCommitPatch(gitRoot: string, sha: string): string {
    method generateReviewPrompt (line 400) | private generateReviewPrompt(gitDiff: string): string {
    method callAdvancedModel (line 429) | private async *callAdvancedModel(
    method reviewChanges (line 508) | async *reviewChanges(

FILE: source/agents/summaryAgent.ts
  class SummaryAgent (line 22) | class SummaryAgent {
    method initialize (line 31) | private async initialize(): Promise<boolean> {
    method clearCache (line 61) | clearCache(): void {
    method isAvailable (line 70) | async isAvailable(): Promise<boolean> {
    method callModel (line 84) | private async callModel(
    method generateSummary (line 184) | async generateSummary(
    method applyTerminalTitle (line 202) | private applyTerminalTitle(title: string | undefined): void {
    method generateSummaryInternal (line 218) | private async generateSummaryInternal(
    method generateFallbackSummary (line 310) | private generateFallbackSummary(
    method truncateString (line 332) | private truncateString(str: string, maxLength: number): string {

FILE: source/api/anthropic.ts
  type AnthropicOptions (line 24) | interface AnthropicOptions {
  type AnthropicStreamChunk (line 43) | interface AnthropicStreamChunk {
  type AnthropicTool (line 70) | interface AnthropicTool {
  type AnthropicMessageParam (line 77) | interface AnthropicMessageParam {
  function toAnthropicImageSource (line 102) | function toAnthropicImageSource(image: {
  function resetAnthropicClient (line 140) | function resetAnthropicClient(): void {
  function getPersistentUserId (line 153) | function getPersistentUserId(): string {
  function convertToolsToAnthropic (line 174) | function convertToolsToAnthropic(
  function convertToAnthropicMessages (line 211) | function convertToAnthropicMessages(

FILE: source/api/chat.ts
  type ChatCompletionOptions (line 34) | interface ChatCompletionOptions {
  type ChatCompletionChunk (line 58) | interface ChatCompletionChunk {
  type ChatCompletionMessageParam (line 82) | interface ChatCompletionMessageParam {
  function convertToOpenAIMessages (line 105) | function convertToOpenAIMessages(
  function resetApiClient (line 293) | function resetApiClient(): void {
  type StreamChunk (line 297) | interface StreamChunk {
  function validateChatOptions (line 752) | function validateChatOptions(options: ChatCompletionOptions): string[] {

FILE: source/api/embedding.ts
  type EmbeddingOptions (line 6) | interface EmbeddingOptions {
  type EmbeddingResponse (line 15) | interface EmbeddingResponse {
  type OllamaEmbeddingsMode (line 29) | type OllamaEmbeddingsMode = 'openai' | 'ollama';
  type OllamaEmbeddingResponse (line 31) | interface OllamaEmbeddingResponse {
  type GeminiEmbeddingResponse (line 39) | interface GeminiEmbeddingResponse {
  function isOpenAIEmbeddingsResponse (line 48) | function isOpenAIEmbeddingsResponse(data: any): data is EmbeddingResponse {
  function isOllamaEmbedResponse (line 63) | function isOllamaEmbedResponse(data: any): data is OllamaEmbeddingRespon...
  function isGeminiEmbedResponse (line 71) | function isGeminiEmbedResponse(data: any): data is GeminiEmbeddingRespon...
  function resolveOllamaEmbeddingsEndpoint (line 78) | function resolveOllamaEmbeddingsEndpoint(baseUrl: string): {
  function resolveOpenAICompatibleEmbeddingsEndpoint (line 113) | function resolveOpenAICompatibleEmbeddingsEndpoint(baseUrl: string): str...
  function warnOnDimensionMismatch (line 133) | function warnOnDimensionMismatch(params: {
  function normalizeOllamaResponse (line 162) | function normalizeOllamaResponse(params: {
  function normalizeGeminiResponse (line 224) | function normalizeGeminiResponse(params: {
  function createEmbeddings (line 304) | async function createEmbeddings(
  function createEmbedding (line 444) | async function createEmbedding(

FILE: source/api/gemini.ts
  type GeminiOptions (line 20) | interface GeminiOptions {
  type GeminiStreamChunk (line 37) | interface GeminiStreamChunk {
  function resetGeminiClient (line 75) | function resetGeminiClient(): void {
  function toGeminiImagePart (line 86) | function toGeminiImagePart(image: {
  function convertToolsToGemini (line 130) | function convertToolsToGemini(tools?: ChatCompletionTool[]): any[] | und...
  function convertToGeminiMessages (line 163) | function convertToGeminiMessages(

FILE: source/api/models.ts
  type Model (line 9) | interface Model {
  type ModelsResponse (line 16) | interface ModelsResponse {
  type GeminiModel (line 22) | interface GeminiModel {
  type GeminiModelsResponse (line 29) | interface GeminiModelsResponse {
  type AnthropicModel (line 34) | interface AnthropicModel {
  function fetchOpenAIModels (line 44) | async function fetchOpenAIModels(
  function fetchGeminiModels (line 79) | async function fetchGeminiModels(
  function fetchAnthropicModels (line 115) | async function fetchAnthropicModels(
  function fetchAvailableModels (line 175) | async function fetchAvailableModels(
  function filterModels (line 252) | function filterModels(models: Model[], searchTerm: string): Model[] {

FILE: source/api/rerank.ts
  type RerankOptions (line 6) | interface RerankOptions {
  type RerankResult (line 16) | interface RerankResult {
  type RerankResponse (line 21) | interface RerankResponse {
  constant MAX_RETRIES (line 27) | const MAX_RETRIES = 3;
  constant RETRY_BASE_DELAY_MS (line 28) | const RETRY_BASE_DELAY_MS = 500;
  constant CONTEXT_RESERVE_RATIO (line 29) | const CONTEXT_RESERVE_RATIO = 0.95;
  constant SINGLE_DOC_MAX_RATIO (line 30) | const SINGLE_DOC_MAX_RATIO = 0.3;
  function countTokens (line 35) | async function countTokens(text: string): Promise<number> {
  function truncateText (line 57) | async function truncateText(
  type FitResult (line 86) | interface FitResult {
  function fitDocumentsToContext (line 103) | async function fitDocumentsToContext(
  function resolveRerankEndpoint (line 168) | function resolveRerankEndpoint(baseUrl: string): string {
  function normalizeRerankResponse (line 187) | function normalizeRerankResponse(data: any): RerankResponse {
  function callRerankAPI (line 209) | async function callRerankAPI(options: {
  function rerankDocuments (line 264) | async function rerankDocuments(

FILE: source/api/responses.ts
  type ResponseOptions (line 24) | interface ResponseOptions {
  function ensureStrictSchema (line 56) | function ensureStrictSchema(
  function convertToolsForResponses (line 112) | function convertToolsForResponses(tools?: ChatCompletionTool[]):
  type ResponseStreamChunk (line 134) | interface ResponseStreamChunk {
  function getResponsesReasoningConfig (line 155) | function getResponsesReasoningConfig(): {
  function getResponsesVerbosityConfig (line 172) | function getResponsesVerbosityConfig(): 'low' | 'medium' | 'high' {
  function resetApiClient (line 177) | function resetApiClient(): void {
  function toResponseImageUrl (line 181) | function toResponseImageUrl(image: {data: string; mimeType?: string}): s...
  function convertToResponseInput (line 194) | function convertToResponseInput(

FILE: source/api/sse-server.ts
  type SSEEventType (line 7) | type SSEEventType =
  type SSEEvent (line 24) | interface SSEEvent {
  type ClientMessage (line 34) | interface ClientMessage {
  class SSEConnection (line 63) | class SSEConnection {
    method constructor (line 67) | constructor(response: ServerResponse, connectionId: string) {
    method sendEvent (line 90) | sendEvent(event: SSEEvent): void {
    method close (line 98) | close(): void {
    method getId (line 102) | getId(): string {
  class SSEServer (line 110) | class SSEServer {
    method constructor (line 125) | constructor(port: number = 3000) {
    method setLogCallback (line 132) | setLogCallback(
    method log (line 141) | private log(
    method setMessageHandler (line 155) | setMessageHandler(
    method start (line 168) | start(): Promise<void> {
    method stop (line 190) | stop(): Promise<void> {
    method bindSessionToConnection (line 213) | bindSessionToConnection(sessionId: string, connectionId: string): void {
    method sendToSession (line 221) | sendToSession(sessionId: string, event: SSEEvent): void {
    method sendToConnection (line 234) | sendToConnection(connectionId: string, event: SSEEvent): void {
    method readJsonBody (line 244) | private async readJsonBody<T = any>(req: IncomingMessage): Promise<T> {
    method getActiveConnectionId (line 263) | private getActiveConnectionId(preferred?: string): string | undefined {
    method handleRequest (line 276) | private handleRequest(req: IncomingMessage, res: ServerResponse): void {
    method handleSessionCreate (line 363) | private handleSessionCreate(req: IncomingMessage, res: ServerResponse)...
    method handleSessionLoad (line 397) | private handleSessionLoad(req: IncomingMessage, res: ServerResponse): ...
    method handleSessionRollbackPoints (line 443) | private handleSessionRollbackPoints(
    method handleSessionList (line 569) | private handleSessionList(
    method handleSessionDelete (line 627) | private handleSessionDelete(
    method handleContextCompress (line 669) | private handleContextCompress(
    method handleSSEConnection (line 789) | private handleSSEConnection(req: IncomingMessage, res: ServerResponse)...
    method handleMessage (line 809) | private handleMessage(req: IncomingMessage, res: ServerResponse): void {
    method broadcast (line 881) | broadcast(event: SSEEvent): void {
    method getConnectionCount (line 890) | getConnectionCount(): number {

FILE: source/api/types.ts
  type ImageContent (line 5) | interface ImageContent {
  type ToolCall (line 11) | interface ToolCall {
  type ChatMessage (line 20) | interface ChatMessage {
  type ChatCompletionTool (line 57) | interface ChatCompletionTool {
  type UsageInfo (line 66) | interface UsageInfo {

FILE: source/app.tsx
  type Props (line 34) | type Props = {
  function ShowTaskListWrapper (line 47) | function ShowTaskListWrapper() {
  function AppContent (line 126) | function AppContent({
  function App (line 325) | function App({

FILE: source/cli.tsx
  constant MIN_NODE_VERSION (line 10) | const MIN_NODE_VERSION = 16;
  function sanitizeNodeOptions (line 33) | function sanitizeNodeOptions() {
  function isStreamDestroyedError (line 110) | function isStreamDestroyedError(err: unknown): boolean {
  constant VERSION (line 177) | const VERSION = packageJson.version;
  function loadDependencies (line 180) | async function loadDependencies() {
  function checkForUpdates (line 227) | async function checkForUpdates(currentVersion: string): Promise<void> {

FILE: source/hooks/conversation/chatLogic/types.ts
  type UseChatLogicProps (line 5) | interface UseChatLogicProps {

FILE: source/hooks/conversation/chatLogic/useChatHandlers.ts
  type UseChatHandlersDeps (line 13) | interface UseChatHandlersDeps {
  function useChatHandlers (line 22) | function useChatHandlers(

FILE: source/hooks/conversation/chatLogic/useMessageProcessing.ts
  type MessageTarget (line 21) | interface MessageTarget {
  function parseMessageTargets (line 33) | function parseMessageTargets(message: string): {
  function useMessageProcessing (line 71) | function useMessageProcessing(props: UseChatLogicProps) {

FILE: source/hooks/conversation/chatLogic/useRemoteEvents.ts
  type UseRemoteEventsHandlers (line 8) | interface UseRemoteEventsHandlers {
  function useRemoteEvents (line 29) | function useRemoteEvents(

FILE: source/hooks/conversation/chatLogic/useRollback.ts
  function resolveSnapshotIndex (line 43) | function resolveSnapshotIndex(
  function useRollback (line 76) | function useRollback(props: UseChatLogicProps) {

FILE: source/hooks/conversation/core/autoCompressHandler.ts
  type AutoCompressOptions (line 14) | type AutoCompressOptions = {
  type AutoCompressResult (line 30) | type AutoCompressResult = {
  function handleAutoCompression (line 42) | async function handleAutoCompression(

FILE: source/hooks/conversation/core/conversationSetup.ts
  type PreparedConversationSetup (line 14) | type PreparedConversationSetup = {
  function prepareConversationSetup (line 21) | async function prepareConversationSetup(
  function appendUserMessageAndSyncContext (line 62) | async function appendUserMessageAndSyncContext(options: {

FILE: source/hooks/conversation/core/conversationTypes.ts
  type UserQuestionResult (line 6) | type UserQuestionResult = {
  type ConversationUsage (line 11) | type ConversationUsage = {
  type ConversationHandlerOptions (line 20) | type ConversationHandlerOptions = {
  type TokenEncoder (line 83) | type TokenEncoder = {
  type StreamRoundResult (line 87) | type StreamRoundResult = {
  type ToolCallRoundResult (line 99) | type ToolCallRoundResult =

FILE: source/hooks/conversation/core/editorContextBuilder.ts
  type EditorContext (line 4) | interface EditorContext {
  function buildEditorContextContent (line 21) | function buildEditorContextContent(

FILE: source/hooks/conversation/core/encoderManager.ts
  class EncoderManager (line 7) | class EncoderManager {
    method constructor (line 11) | constructor() {
    method encode (line 24) | encode(text: string): number[] {
    method free (line 34) | free(): void {
    method isFreed (line 49) | isFreed(): boolean {

FILE: source/hooks/conversation/core/onStopHookHandler.ts
  type OnStopHookOptions (line 6) | type OnStopHookOptions = {
  type OnStopHookResult (line 12) | type OnStopHookResult = {
  function handleOnStopHooks (line 19) | async function handleOnStopHooks(

FILE: source/hooks/conversation/core/pendingMessagesHandler.ts
  type PendingMessagesOptions (line 5) | type PendingMessagesOptions = {
  type PendingMessagesResult (line 17) | type PendingMessagesResult = {
  type BasicConversationMessage (line 25) | type BasicConversationMessage = {
  function isPendingSendTimingReady (line 35) | function isPendingSendTimingReady(
  function waitForPendingSendSignal (line 67) | async function waitForPendingSendSignal(options?: {
  function handlePendingMessages (line 116) | async function handlePendingMessages(

FILE: source/hooks/conversation/core/sessionInitializer.ts
  function initializeConversationSession (line 15) | async function initializeConversationSession(

FILE: source/hooks/conversation/core/streamFactory.ts
  type StreamFactoryOptions (line 10) | type StreamFactoryOptions = {
  function createStreamGenerator (line 25) | function createStreamGenerator(options: StreamFactoryOptions) {

FILE: source/hooks/conversation/core/streamProcessor.ts
  constant TOKEN_UPDATE_INTERVAL (line 13) | const TOKEN_UPDATE_INTERVAL = 100;
  constant STREAM_FLUSH_INTERVAL (line 14) | const STREAM_FLUSH_INTERVAL = 80;
  constant THINKING_TAG_PATTERN (line 15) | const THINKING_TAG_PATTERN = /\s*<\/?think(?:ing)?>\s*/gi;
  constant LIST_ITEM_PATTERN (line 16) | const LIST_ITEM_PATTERN = /^\s*\d+[.)]\s|^\s*[-*+]\s/;
  constant LIST_CONTINUATION_PATTERN (line 17) | const LIST_CONTINUATION_PATTERN = /^\s{2,}/;
  function cleanThinkingContent (line 19) | function cleanThinkingContent(content: string): string {
  function isTableRow (line 23) | function isTableRow(line: string): boolean {
  function isListItemLine (line 28) | function isListItemLine(line: string): boolean {
  function processStreamRound (line 32) | async function processStreamRound(ctx: {

FILE: source/hooks/conversation/core/subAgentMessageHandler.ts
  type TeammateCtxUsage (line 11) | interface TeammateCtxUsage {
  type TeammateStreamInfo (line 17) | interface TeammateStreamInfo {
  type SubAgentStreamInfo (line 25) | interface SubAgentStreamInfo {
  function notifyTeammateStreamListeners (line 44) | function notifyTeammateStreamListeners(): void {
  function notifySubAgentStreamListeners (line 50) | function notifySubAgentStreamListeners(): void {
  function rebuildTeammateSnapshot (line 56) | function rebuildTeammateSnapshot(): void {
  function rebuildSubAgentSnapshot (line 66) | function rebuildSubAgentSnapshot(): void {
  function setTeammateStreamEntry (line 76) | function setTeammateStreamEntry(agentId: string, agentName: string, toke...
  function removeTeammateStreamEntry (line 83) | function removeTeammateStreamEntry(agentId: string): void {
  function setSubAgentStreamEntry (line 89) | function setSubAgentStreamEntry(
  function removeSubAgentStreamEntry (line 115) | function removeSubAgentStreamEntry(agentId: string): void {
  function subscribeTeammateStream (line 121) | function subscribeTeammateStream(listener: () => void): () => void {
  function getTeammateStreamSnapshot (line 126) | function getTeammateStreamSnapshot(): TeammateStreamInfo[] {
  function subscribeSubAgentStream (line 130) | function subscribeSubAgentStream(listener: () => void): () => void {
  function getSubAgentStreamSnapshot (line 137) | function getSubAgentStreamSnapshot(): SubAgentStreamInfo[] {
  function clearAllTeammateStreamEntries (line 141) | function clearAllTeammateStreamEntries(): void {
  function clearAllSubAgentStreamEntries (line 148) | function clearAllSubAgentStreamEntries(): void {
  type CtxUsage (line 157) | type CtxUsage = {percentage: number; inputTokens: number; maxTokens: num...
  type StreamState (line 159) | type StreamState = {
  function formatTokenCount (line 179) | function formatTokenCount(tokens: number | undefined): string {
  function extractRejectionReason (line 187) | function extractRejectionReason(content: string): string | undefined {
  class SubAgentUIHandler (line 199) | class SubAgentUIHandler {
    method constructor (line 211) | constructor(
    method handleMessage (line 222) | handleMessage(prev: Message[], subAgentMessage: SubAgentMessage): Mess...
    method createInitialStreamState (line 265) | private createInitialStreamState(): StreamState {
    method getStreamState (line 284) | private getStreamState(agentId: string): StreamState {
    method clearStreamState (line 291) | private clearStreamState(agentId: string): void {
    method updateGlobalTokenCount (line 298) | private updateGlobalTokenCount(): void {
    method setAgentReasoning (line 320) | private setAgentReasoning(agentId: string, isReasoning: boolean): void {
    method addTokens (line 353) | private addTokens(agentId: string, text: string): void {
    method shouldFlush (line 363) | private shouldFlush(state: StreamState, now: number): boolean {
    method flushTokenCount (line 367) | private flushTokenCount(agentId: string, now: number): void {
    method emitStreamLine (line 373) | private emitStreamLine(
    method emitAgentTitle (line 421) | private emitAgentTitle(lines: Message[], subAgentMessage: SubAgentMess...
    method flushNextQueuedAgent (line 440) | private flushNextQueuedAgent(): Message[] {
    method cleanThinkingContent (line 473) | private cleanThinkingContent(content: string): string {
    method flushThinkingBuffer (line 477) | private flushThinkingBuffer(
    method isTableRow (line 494) | private isTableRow(line: string): boolean {
    method isListItemLine (line 503) | private isListItemLine(line: string): boolean {
    method processContentLine (line 507) | private processContentLine(
    method flushRemainingContentBuffers (line 605) | private flushRemainingContentBuffers(
    method persistCompletedResponse (line 651) | private persistCompletedResponse(
    method resetRoundState (line 684) | private resetRoundState(state: StreamState): void {
    method handleReasoningStarted (line 702) | private handleReasoningStarted(
    method handleReasoningDelta (line 713) | private handleReasoningDelta(
    method handleToolCallDelta (line 749) | private handleToolCallDelta(
    method handleContextUsage (line 768) | private handleContextUsage(
    method handleContextCompressing (line 822) | private handleContextCompressing(
    method handleContextCompressRetrying (line 842) | private handleContextCompressRetrying(
    method handleContextCompressed (line 863) | private handleContextCompressed(
    method handleInterAgentSent (line 889) | private handleInterAgentSent(
    method handleAgentSpawned (line 917) | private handleAgentSpawned(
    method handleSpawnedAgentCompleted (line 952) | private handleSpawnedAgentCompleted(
    method handleToolCalls (line 975) | private handleToolCalls(
    method handleToolResult (line 1124) | private handleToolResult(
    method handleTimeConsumingToolResult (line 1210) | private handleTimeConsumingToolResult(
    method handleContent (line 1332) | private handleContent(
    method handleDone (line 1375) | private handleDone(

FILE: source/hooks/conversation/core/toolCallProcessor.ts
  type ProcessToolCallsOptions (line 8) | type ProcessToolCallsOptions = {
  function processToolCallsAfterStream (line 23) | async function processToolCallsAfterStream(

FILE: source/hooks/conversation/core/toolCallRoundHandler.ts
  function handleToolCallRound (line 26) | async function handleToolCallRound(ctx: {

FILE: source/hooks/conversation/core/toolConfirmationFlow.ts
  type ToolConfirmationFlowOptions (line 8) | type ToolConfirmationFlowOptions = {
  type ToolConfirmationFlowResult (line 28) | type ToolConfirmationFlowResult =
  function notifyAndRequestConfirmation (line 32) | async function notifyAndRequestConfirmation(
  function isRejection (line 78) | function isRejection(confirmation: ConfirmationResult): boolean {
  function resolveToolConfirmations (line 90) | async function resolveToolConfirmations(

FILE: source/hooks/conversation/core/toolRejectionHandler.ts
  type ToolRejectionResult (line 6) | type ToolRejectionResult = {
  type ToolRejectionHandlerOptions (line 12) | type ToolRejectionHandlerOptions = {
  function handleToolRejection (line 25) | async function handleToolRejection(

FILE: source/hooks/conversation/core/toolResultDisplay.ts
  function buildToolResultMessages (line 9) | function buildToolResultMessages(
  function extractEditDiffData (line 73) | function extractEditDiffData(

FILE: source/hooks/conversation/useChatLogic.ts
  function useChatLogic (line 18) | function useChatLogic(props: UseChatLogicProps) {
  type UseChatLogicReturn (line 326) | type UseChatLogicReturn = ReturnType<typeof useChatLogic>;

FILE: source/hooks/conversation/useCommandHandler.ts
  function getExportMessages (line 27) | function getExportMessages() {
  function executeContextCompression (line 38) | async function executeContextCompression(
  type CommandHandlerOptions (line 384) | type CommandHandlerOptions = {
  function useCommandHandler (line 471) | function useCommandHandler(options: CommandHandlerOptions) {

FILE: source/hooks/conversation/useConversation.ts
  function handleConversationWithTools (line 28) | async function handleConversationWithTools(
  function mergeUsage (line 230) | function mergeUsage(

FILE: source/hooks/conversation/useStreamingState.ts
  type RetryStatus (line 4) | type RetryStatus = {
  type CodebaseSearchStatus (line 12) | type CodebaseSearchStatus = {
  type StreamStatus (line 23) | type StreamStatus = 'idle' | 'streaming' | 'stopping';
  function useStreamingState (line 25) | function useStreamingState() {

FILE: source/hooks/conversation/useToolConfirmation.ts
  type PendingConfirmation (line 12) | type PendingConfirmation = {
  function useToolConfirmation (line 23) | function useToolConfirmation(workingDirectory: string) {

FILE: source/hooks/conversation/utils/messageCleanup.ts
  function cleanOrphanedToolCalls (line 15) | function cleanOrphanedToolCalls(messages: ChatMessage[]): void {

FILE: source/hooks/conversation/utils/thinkingExtractor.ts
  type ReasoningData (line 4) | interface ReasoningData {
  type ThinkingData (line 13) | interface ThinkingData {
  function cleanThinkingContent (line 27) | function cleanThinkingContent(content: string): string {
  function extractThinkingContent (line 47) | function extractThinkingContent(

FILE: source/hooks/execution/useBackgroundProcesses.ts
  type BackgroundProcess (line 4) | interface BackgroundProcess {
  function useBackgroundProcesses (line 24) | function useBackgroundProcesses() {
  function addBackgroundProcess (line 156) | function addBackgroundProcess(command: string, pid: number): string {
  function updateBackgroundProcessStatus (line 176) | function updateBackgroundProcessStatus(
  function showBackgroundPanel (line 200) | function showBackgroundPanel() {

FILE: source/hooks/execution/useSchedulerExecutionState.ts
  type SchedulerExecutionState (line 3) | interface SchedulerExecutionState {
  function useSchedulerExecutionState (line 28) | function useSchedulerExecutionState() {
  function setSchedulerExecutionState (line 101) | function setSchedulerExecutionState(state: SchedulerExecutionState) {
  function startSchedulerTask (line 110) | function startSchedulerTask(description: string, duration: number) {
  function updateSchedulerRemainingTime (line 128) | function updateSchedulerRemainingTime(seconds: number) {
  function completeSchedulerTask (line 140) | function completeSchedulerTask() {
  function resetSchedulerState (line 156) | function resetSchedulerState() {
  function getSchedulerState (line 173) | function getSchedulerState(): SchedulerExecutionState | null {

FILE: source/hooks/execution/useTerminalExecutionState.ts
  type TerminalExecutionState (line 3) | interface TerminalExecutionState {
  function useTerminalExecutionState (line 23) | function useTerminalExecutionState() {
  function setTerminalExecutionState (line 85) | function setTerminalExecutionState(state: TerminalExecutionState) {
  constant OUTPUT_BATCH_SIZE (line 94) | const OUTPUT_BATCH_SIZE = 10;
  constant OUTPUT_FLUSH_DELAY (line 95) | const OUTPUT_FLUSH_DELAY = 50;
  function flushOutputBuffer (line 101) | function flushOutputBuffer() {
  function appendTerminalOutput (line 123) | function appendTerminalOutput(line: string) {
  function setTerminalNeedsInput (line 147) | function setTerminalNeedsInput(needsInput: boolean, prompt?: string) {
  function registerInputCallback (line 164) | function registerInputCallback(
  function sendTerminalInput (line 174) | function sendTerminalInput(input: string) {

FILE: source/hooks/input/keyboard/context.ts
  function createHelpers (line 11) | function createHelpers(
  function createContext (line 68) | function createContext(

FILE: source/hooks/input/keyboard/handlers/arrowKeys.ts
  function arrowKeysHandler (line 3) | function arrowKeysHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/clipboard.ts
  function clipboardHandler (line 3) | function clipboardHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/deleteAndBackspace.ts
  function deleteAndBackspaceHandler (line 3) | function deleteAndBackspaceHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/editing.ts
  function editingHandler (line 5) | function editingHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/escape.ts
  function escapeHandler (line 4) | function escapeHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/focusFilter.ts
  function focusFilterHandler (line 3) | function focusFilterHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/modeToggle.ts
  function cycleModes (line 3) | function cycleModes(ctx: HandlerContext): void {
  function modeToggleHandler (line 44) | function modeToggleHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/newline.ts
  function newlineHandler (line 3) | function newlineHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/pickers/agentPicker.ts
  function agentPickerHandler (line 3) | function agentPickerHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/pickers/argsPicker.ts
  function argsPickerHandler (line 4) | function argsPickerHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/pickers/commandPanel.ts
  function commandPanelHandler (line 6) | function commandPanelHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/pickers/filePicker.ts
  function filePickerHandler (line 3) | function filePickerHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/pickers/gitLinePicker.ts
  function gitLinePickerHandler (line 3) | function gitLinePickerHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/pickers/historyMenu.ts
  function historyMenuHandler (line 3) | function historyMenuHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/pickers/profilePicker.ts
  function profilePickerHandler (line 3) | function profilePickerHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/pickers/runningAgentsPicker.ts
  function runningAgentsPickerHandler (line 3) | function runningAgentsPickerHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/pickers/skillsPicker.ts
  function skillsPickerHandler (line 3) | function skillsPickerHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/pickers/todoPicker.ts
  function todoPickerHandler (line 3) | function todoPickerHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/profileShortcut.ts
  function profileShortcutHandler (line 3) | function profileShortcutHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/regularInput.ts
  function regularInputHandler (line 3) | function regularInputHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/submit.ts
  function submitHandler (line 5) | function submitHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/handlers/tabArgsPicker.ts
  function tabArgsPickerHandler (line 4) | function tabArgsPickerHandler(ctx: HandlerContext): boolean {

FILE: source/hooks/input/keyboard/types.ts
  type KeyboardInputOptions (line 6) | type KeyboardInputOptions = {
  type HandlerRefs (line 196) | type HandlerRefs = {
  type HandlerHelpers (line 208) | type HandlerHelpers = {
  type HandlerContext (line 218) | type HandlerContext = {

FILE: source/hooks/input/keyboard/utils/wordBoundary.ts
  function findWordBoundary (line 2) | function findWordBoundary(

FILE: source/hooks/input/useBashMode.ts
  type BashCommand (line 5) | interface BashCommand {
  type CommandExecutionResult (line 13) | interface CommandExecutionResult {
  type BashModeState (line 22) | interface BashModeState {
  function useBashMode (line 30) | function useBashMode() {

FILE: source/hooks/input/useClipboard.ts
  function useClipboard (line 7) | function useClipboard(

FILE: source/hooks/input/useHistoryNavigation.ts
  type ChatMessage (line 9) | type ChatMessage = {
  function useHistoryNavigation (line 17) | function useHistoryNavigation(

FILE: source/hooks/input/useInputBuffer.ts
  function useInputBuffer (line 4) | function useInputBuffer(viewport: Viewport) {

FILE: source/hooks/input/useKeyboardInput.ts
  function useKeyboardInput (line 30) | function useKeyboardInput(options: KeyboardInputOptions) {

FILE: source/hooks/integration/useGlobalExit.ts
  type ExitNotification (line 6) | interface ExitNotification {
  function useGlobalExit (line 11) | function useGlobalExit(

FILE: source/hooks/integration/useGlobalNavigation.ts
  constant NAVIGATION_EVENT (line 8) | const NAVIGATION_EVENT = 'navigate';
  type NavigationEvent (line 10) | interface NavigationEvent {
  function navigateTo (line 24) | function navigateTo(destination: NavigationEvent['destination']) {
  function onNavigate (line 29) | function onNavigate(handler: (event: NavigationEvent) => void) {

FILE: source/hooks/integration/useVSCodeState.ts
  type VSCodeConnectionStatus (line 7) | type VSCodeConnectionStatus =
  function useVSCodeState (line 13) | function useVSCodeState() {

FILE: source/hooks/picker/useAgentPicker.ts
  function useAgentPicker (line 8) | function useAgentPicker(buffer: TextBuffer, triggerUpdate: () => void) {

FILE: source/hooks/picker/useFilePicker.ts
  type FilePickerState (line 5) | type FilePickerState = {
  type FilePickerAction (line 14) | type FilePickerAction =
  function filePickerReducer (line 26) | function filePickerReducer(
  function useFilePicker (line 71) | function useFilePicker(buffer: TextBuffer, triggerUpdate: () => void) {

FILE: source/hooks/picker/useGitLinePicker.ts
  type GitLineCommit (line 5) | type GitLineCommit = {
  constant PAGE_SIZE (line 14) | const PAGE_SIZE = 30;
  constant STAGED_ENTRY_SHA (line 15) | const STAGED_ENTRY_SHA = 'staged';
  function createStagedEntry (line 17) | function createStagedEntry(fileCount: number): GitLineCommit {
  function buildInjectedGitLineText (line 28) | function buildInjectedGitLineText(
  function useGitLinePicker (line 68) | function useGitLinePicker(

FILE: source/hooks/picker/useProfilePicker.ts
  function useProfilePicker (line 5) | function useProfilePicker() {

FILE: source/hooks/picker/useRunningAgentsPicker.ts
  type PickerAgent (line 19) | interface PickerAgent {
  function buildVisualTag (line 36) | function buildVisualTag(agent: PickerAgent): string {
  function findDoubleGreaterTrigger (line 63) | function findDoubleGreaterTrigger(beforeCursor: string): number {
  function useRunningAgentsPicker (line 101) | function useRunningAgentsPicker(

FILE: source/hooks/picker/useSkillsPicker.ts
  type SkillsPickerFocus (line 5) | type SkillsPickerFocus = 'search' | 'append';
  function buildInjectedSkillText (line 7) | function buildInjectedSkillText(skill: Skill, appendText: string): string {
  function useSkillsPicker (line 24) | function useSkillsPicker(buffer: TextBuffer, triggerUpdate: () => void) {

FILE: source/hooks/picker/useTodoPicker.ts
  function useTodoPicker (line 5) | function useTodoPicker(

FILE: source/hooks/session/useSessionManagement.ts
  function useSessionManagement (line 9) | function useSessionManagement(

FILE: source/hooks/session/useSessionSave.ts
  function useSessionSave (line 8) | function useSessionSave() {

FILE: source/hooks/session/useSnapshotState.ts
  function useSnapshotState (line 5) | function useSnapshotState(messagesLength: number) {

FILE: source/hooks/ui/useCommandPanel.ts
  type CommandPanelCommand (line 21) | type CommandPanelCommand = {
  constant COMMAND_ARGS_HINTS (line 30) | const COMMAND_ARGS_HINTS: Record<string, string> = {
  constant COMMAND_ARGS_OPTIONS (line 51) | const COMMAND_ARGS_OPTIONS: Record<string, string[]> = {
  function useCommandPanel (line 63) | function useCommandPanel(buffer: TextBuffer, isProcessing = false) {

FILE: source/hooks/ui/useCursorHide.ts
  function useCursorHide (line 19) | function useCursorHide(): void {

FILE: source/hooks/ui/usePanelState.ts
  type PanelState (line 9) | type PanelState = {
  type PanelActions (line 43) | type PanelActions = {
  function usePanelState (line 93) | function usePanelState(): PanelState & PanelActions {

FILE: source/hooks/ui/useTerminalFocus.ts
  function useTerminalFocus (line 31) | function useTerminalFocus(): {

FILE: source/hooks/ui/useTerminalSize.ts
  type SizeListener (line 5) | type SizeListener = (size: {columns: number; rows: number}) => void;
  function handleResize (line 14) | function handleResize() {
  function subscribe (line 22) | function subscribe(listener: SizeListener): () => void {
  function useTerminalSize (line 43) | function useTerminalSize(): {columns: number; rows: number} {

FILE: source/hooks/ui/useTerminalTitle.ts
  function useTerminalTitle (line 26) | function useTerminalTitle(title: string): void {

FILE: source/i18n/I18nContext.tsx
  type I18nContextType (line 9) | type I18nContextType = {
  type Props (line 17) | type Props = {
  function I18nProvider (line 22) | function I18nProvider({children, defaultLanguage}: Props) {
  function useI18n (line 43) | function useI18n(): I18nContextType {

FILE: source/i18n/types.ts
  type TranslationKeys (line 3) | type TranslationKeys = {
  type Translations (line 1760) | type Translations = {

FILE: source/mcp/aceCodeSearch.ts
  class ACECodeSearchService (line 65) | class ACECodeSearchService {
    method constructor (line 100) | constructor(
    method withIndexBuildLock (line 121) | private async withIndexBuildLock<T>(fn: () => Promise<T>): Promise<T> {
    method markIndexTruncated (line 130) | private markIndexTruncated(message: string): void {
    method ensureNotDisposed (line 138) | private ensureNotDisposed(): void {
    method scheduleIdleCleanup (line 144) | private scheduleIdleCleanup(): void {
    method markActivity (line 166) | private markActivity(): void {
    method removeFromContentCache (line 172) | private removeFromContentCache(filePath: string): void {
    method clearContentCache (line 180) | private clearContentCache(): void {
    method trimContentCacheByBytes (line 185) | private trimContentCacheByBytes(): void {
    method checkMemoryPressure (line 209) | private checkMemoryPressure(): void {
    method getMemoryStats (line 239) | getMemoryStats(): {
    method trimFileStatCache (line 264) | private trimFileStatCache(): void {
    method clearCaches (line 281) | private clearCaches(options?: {
    method dispose (line 307) | dispose(): void {
    method isSSHPath (line 322) | private isSSHPath(filePath: string): boolean {
    method getSSHConfigForPath (line 331) | private async getSSHConfigForPath(sshUrl: string): Promise<SSHConfig |...
    method readRemoteFile (line 363) | private async readRemoteFile(sshUrl: string): Promise<string> {
    method loadExclusionPatterns (line 391) | private async loadExclusionPatterns(): Promise<void> {
    method isCommandAvailableCached (line 400) | private async isCommandAvailableCached(command: string): Promise<boole...
    method isGitRepository (line 413) | private async isGitRepository(
    method buildIndex (line 439) | private async buildIndex(forceRefresh: boolean = false): Promise<void> {
    method buildFzfIndex (line 604) | private buildFzfIndex(): void {
    method searchSymbols (line 632) | async searchSymbols(
    method searchSymbolsManual (line 728) | private async searchSymbolsManual(
    method findReferences (line 816) | async findReferences(
    method findDefinition (line 962) | async findDefinition(
    method gitGrepSearch (line 1005) | private async gitGrepSearch(
    method systemGrepSearch (line 1111) | private async systemGrepSearch(
    method globPatternToRegex (line 1235) | private globPatternToRegex(globPattern: string): RegExp {
    method jsTextSearch (line 1266) | private async jsTextSearch(
    method searchInLargeFile (line 1455) | private async searchInLargeFile(
    method textSearch (line 1542) | async textSearch(
    method executeTextSearch (line 1584) | private async executeTextSearch(
    method sortResultsByRecency (line 1667) | private async sortResultsByRecency(
    method estimateFileOutlinePayloadChars (line 1746) | private estimateFileOutlinePayloadChars(symbols: CodeSymbol[]): number {
    method constrainFileOutlinePayload (line 1750) | private constrainFileOutlinePayload(
    method getFileOutline (line 1784) | async getFileOutline(
    method semanticSearch (line 1870) | async semanticSearch(

FILE: source/mcp/askUserQuestion.ts
  type AskUserQuestionArgs (line 3) | interface AskUserQuestionArgs {
  type AskUserQuestionResult (line 8) | interface AskUserQuestionResult {

FILE: source/mcp/bash.ts
  function markCommandAsBackgrounded (line 34) | function markCommandAsBackgrounded() {
  function resetBackgroundFlag (line 41) | function resetBackgroundFlag() {
  class TerminalCommandService (line 49) | class TerminalCommandService {
    method constructor (line 53) | constructor(
    method maybeSummarizeCommandResult (line 61) | private async maybeSummarizeCommandResult(
    method isSSHPath (line 99) | private isSSHPath(dirPath: string): boolean {
    method getSSHConfigForPath (line 106) | private async getSSHConfigForPath(sshUrl: string): Promise<SSHConfig |...
    method executeRemoteCommand (line 136) | private async executeRemoteCommand(
    method selectAvailableWindowsShell (line 194) | private selectAvailableWindowsShell(
    method executeCommand (line 251) | async executeCommand(
    method getWorkingDirectory (line 757) | getWorkingDirectory(): string {
    method setWorkingDirectory (line 766) | setWorkingDirectory(newPath: string): void {

FILE: source/mcp/codebaseSearch.ts
  class CodebaseSearchService (line 16) | class CodebaseSearchService {
    method isCodebaseIndexAvailable (line 20) | private async isCodebaseIndexAvailable(): Promise<{
    method cosineSimilarity (line 72) | private cosineSimilarity(a: number[], b: number[]): number {
    method search (line 97) | async search(

FILE: source/mcp/engines/websearch/bing.engine.ts
  class BingEngine (line 31) | class BingEngine implements SearchEngine {
    method search (line 35) | async search(

FILE: source/mcp/engines/websearch/duckduckgo.engine.ts
  class DuckDuckGoEngine (line 14) | class DuckDuckGoEngine implements SearchEngine {
    method search (line 18) | async search(

FILE: source/mcp/engines/websearch/index.ts
  constant DEFAULT_SEARCH_ENGINE (line 32) | const DEFAULT_SEARCH_ENGINE: SearchEngineId = 'duckduckgo';
  constant SUPPORTED_SEARCH_ENGINE_EXTENSIONS (line 34) | const SUPPORTED_SEARCH_ENGINE_EXTENSIONS = new Set(['.js', '.mjs', '.cjs...
  constant BUILT_IN_ENGINES (line 36) | const BUILT_IN_ENGINES: SearchEngine[] = [
  constant ENGINES (line 47) | const ENGINES: Map<string, SearchEngine> = new Map(
  type SearchEngineModule (line 54) | type SearchEngineModule = {
  function isSearchEngine (line 60) | function isSearchEngine(candidate: unknown): candidate is SearchEngine {
  function isEngineEnabled (line 76) | function isEngineEnabled(engine: SearchEngine): boolean {
  function collectFromModule (line 80) | function collectFromModule(mod: SearchEngineModule): SearchEngine[] {
  function loadExternalEngines (line 92) | async function loadExternalEngines(): Promise<void> {
  function ensureSearchEnginesLoaded (line 149) | function ensureSearchEnginesLoaded(): Promise<void> {
  function getSearchEngine (line 166) | function getSearchEngine(id?: string | null): SearchEngine {
  function listSearchEngines (line 174) | function listSearchEngines(): SearchEngine[] {
  function listSearchEnginesAsync (line 182) | async function listSearchEnginesAsync(): Promise<SearchEngine[]> {

FILE: source/mcp/engines/websearch/types.ts
  type SearchEngineId (line 25) | type SearchEngineId = string;
  type SearchEngine (line 30) | interface SearchEngine {

FILE: source/mcp/filesystem.ts
  class FilesystemMCPService (line 56) | class FilesystemMCPService {
    method constructor (line 80) | constructor(basePath: string = process.cwd()) {
    method isSSHPath (line 89) | private isSSHPath(filePath: string): boolean {
    method getSSHConfigForPath (line 98) | private async getSSHConfigForPath(sshUrl: string): Promise<SSHConfig |...
    method readRemoteFile (line 130) | private async readRemoteFile(sshUrl: string): Promise<string> {
    method writeRemoteFile (line 160) | private async writeRemoteFile(
    method isImageFile (line 192) | private isImageFile(filePath: string): boolean {
    method isOfficeFile (line 202) | private isOfficeFile(filePath: string): boolean {
    method getImageMimeType (line 212) | private getImageMimeType(filePath: string): string | undefined {
    method readImageAsBase64 (line 223) | private async readImageAsBase64(
    method extractRelevantSymbols (line 284) | private extractRelevantSymbols(
    method getNotebookEntries (line 372) | private getNotebookEntries(filePath: string): string {
    method getFileContent (line 412) | async getFileContent(
    method createFile (line 498) | async createFile(
    method listFiles (line 571) | private async listFiles(dirPath: string = '.'): Promise<string[]> {
    method exists (line 601) | async exists(filePath: string): Promise<boolean> {
    method getFileInfo (line 617) | async getFileInfo(filePath: string): Promise<{
    method editFileBySearch (line 649) | async editFileBySearch(
    method editFileBySearchSingle (line 704) | private async editFileBySearchSingle(
    method editFile (line 742) | async editFile(
    method editFileSingle (line 775) | private async editFileSingle(
    method resolvePath (line 804) | private resolvePath(filePath: string, contextPath?: string): string {
    method validatePath (line 830) | private async validatePath(fullPath: string): Promise<void> {

FILE: source/mcp/ideDiagnostics.ts
  class IdeDiagnosticsMCPService (line 8) | class IdeDiagnosticsMCPService {
    method getDiagnostics (line 14) | async getDiagnostics(filePath: string): Promise<Diagnostic[]> {
    method formatDiagnostics (line 36) | formatDiagnostics(diagnostics: Diagnostic[], filePath: string): string {

FILE: source/mcp/lsp/HybridCodeSearchService.ts
  class HybridCodeSearchService (line 7) | class HybridCodeSearchService {
    method constructor (line 13) | constructor(basePath: string = process.cwd()) {
    method findDefinition (line 18) | async findDefinition(
    method findDefinitionWithLSP (line 43) | private async findDefinitionWithLSP(
    method findReferences (line 146) | async findReferences(
    method getFileOutline (line 153) | async getFileOutline(
    method convertLSPSymbolsToCodeSymbols (line 202) | private convertLSPSymbolsToCodeSymbols(
    method uriToPath (line 249) | private uriToPath(uri: string): string {
    method detectLanguage (line 257) | private detectLanguage(filePath: string): string {
    method textSearch (line 274) | async textSearch(
    method semanticSearch (line 283) | async semanticSearch(
    method dispose (line 299) | async dispose(): Promise<void> {

FILE: source/mcp/lsp/LSPClient.ts
  type LSPClientConfig (line 29) | interface LSPClientConfig extends LSPServerConfig {
  class LSPClient (line 34) | class LSPClient {
    method canSendMessages (line 47) | private canSendMessages(): boolean {
    method markTransportClosed (line 60) | private markTransportClosed(): void {
    method constructor (line 80) | constructor(private config: LSPClientConfig) {}
    method findCsharpSolutionFile (line 82) | private async findCsharpSolutionFile(
    method start (line 110) | async start(): Promise<void> {
    method shutdown (line 290) | async shutdown(): Promise<void> {
    method cleanup (line 330) | private async cleanup(): Promise<void> {
    method openDocument (line 357) | async openDocument(uri: string, text: string): Promise<void> {
    method closeDocument (line 389) | async closeDocument(uri: string): Promise<void> {
    method gotoDefinition (line 412) | async gotoDefinition(uri: string, position: Position): Promise<Locatio...
    method findReferences (line 449) | async findReferences(
    method hover (line 481) | async hover(uri: string, position: Position): Promise<Hover | null> {
    method completion (line 508) | async completion(uri: string, position: Position): Promise<CompletionI...
    method documentSymbol (line 538) | async documentSymbol(
    method pathToUri (line 565) | private pathToUri(filePath: string): string {
    method getCapabilities (line 572) | getCapabilities(): ServerCapabilities | undefined {
    method isReady (line 576) | isReady(): boolean {

FILE: source/mcp/lsp/LSPManager.ts
  class LSPManager (line 7) | class LSPManager {
    method constructor (line 11) | constructor(private basePath: string) {}
    method getClient (line 13) | async getClient(language: string): Promise<LSPClient | null> {
    method findDefinition (line 53) | async findDefinition(
    method findReferences (line 101) | async findReferences(
    method getDocumentSymbols (line 150) | async getDocumentSymbols(filePath: string) {
    method getHoverInfo (line 193) | async getHoverInfo(filePath: string, line: number, column: number) {
    method getDocumentContent (line 237) | private async getDocumentContent(filePath: string): Promise<string | n...
    method pathToUri (line 253) | private pathToUri(filePath: string): string {
    method dispose (line 259) | async dispose(): Promise<void> {
    method clearDocumentCache (line 268) | clearDocumentCache(): void {

FILE: source/mcp/lsp/LSPServerRegistry.ts
  type LSPServerConfig (line 9) | interface LSPServerConfig {
  type LSPConfigFile (line 17) | interface LSPConfigFile {
  constant CONFIG_DIR (line 22) | const CONFIG_DIR = join(homedir(), '.snow');
  constant LSP_CONFIG_FILE (line 23) | const LSP_CONFIG_FILE = join(CONFIG_DIR, 'lsp-config.json');
  constant DEFAULT_LSP_SERVERS (line 25) | const DEFAULT_LSP_SERVERS: Record<string, LSPServerConfig> = {
  constant LSP_SERVERS (line 70) | const LSP_SERVERS = DEFAULT_LSP_SERVERS;
  function ensureConfigDirectory (line 72) | function ensureConfigDirectory(): void {
  function isRecord (line 78) | function isRecord(value: unknown): value is Record<string, unknown> {
  function toStringArray (line 82) | function toStringArray(value: unknown): string[] | undefined {
  function parseServerConfig (line 90) | function parseServerConfig(value: unknown): LSPServerConfig | null {
  function parseServersConfig (line 128) | function parseServersConfig(
  function parseLspConfigFile (line 148) | function parseLspConfigFile(
  function getDefaultConfigFile (line 163) | function getDefaultConfigFile(): LSPConfigFile {
  function loadServersFromDisk (line 170) | function loadServersFromDisk(): Record<string, LSPServerConfig> {
  class LSPServerRegistry (line 199) | class LSPServerRegistry {
    method getServers (line 203) | private static getServers(): Record<string, LSPServerConfig> {
    method getServerForFile (line 211) | static getServerForFile(filePath: string): {
    method getConfig (line 226) | static getConfig(language: string): LSPServerConfig | null {
    method getInstallCommand (line 230) | static getInstallCommand(language: string): string | null {
    method isServerInstalled (line 234) | static async isServerInstalled(language: string): Promise<boolean> {
    method clearCache (line 261) | static clearCache(): void {

FILE: source/mcp/notebook.ts
  function executeNotebookTool (line 115) | async function executeNotebookTool(

FILE: source/mcp/scheduler.ts
  type SchedulerTaskArgs (line 3) | interface SchedulerTaskArgs {
  type SchedulerTaskResult (line 14) | interface SchedulerTaskResult {

FILE: source/mcp/skills.ts
  type SkillMetadata (line 8) | interface SkillMetadata {
  type Skill (line 14) | interface Skill {
  function readSkillFile (line 27) | async function readSkillFile(skillPath: string): Promise<{
  function normalizeSkillId (line 89) | function normalizeSkillId(skillId: string): string {
  function loadSkillsFromDirectory (line 93) | async function loadSkillsFromDirectory(
  function loadAvailableSkills (line 176) | async function loadAvailableSkills(
  function generateSkillToolDescription (line 197) | function generateSkillToolDescription(skills: Map<string, Skill>): string {
  function listAvailableSkills (line 241) | async function listAvailableSkills(
  function getMCPTools (line 249) | async function getMCPTools(projectRoot?: string) {
  function generateSkillTree (line 289) | async function generateSkillTree(skillPath: string): Promise<string> {
  function executeSkillTool (line 349) | async function executeSkillTool(

FILE: source/mcp/subagent.ts
  type SubAgentToolExecutionOptions (line 7) | interface SubAgentToolExecutionOptions {
  class SubAgentService (line 33) | class SubAgentService {
    method execute (line 37) | async execute(options: SubAgentToolExecutionOptions): Promise<any> {
    method getTools (line 96) | getTools(): Array<{
  function getMCPTools (line 244) | function getMCPTools(): Array<{

FILE: source/mcp/team.ts
  type TeamToolExecutionOptions (line 42) | interface TeamToolExecutionOptions {
  class TeamService (line 61) | class TeamService {
    method getOwnTeam (line 62) | private getOwnTeam(): import('../utils/team/teamConfig.js').TeamConfig...
    method aiResolveConflicts (line 75) | private async aiResolveConflicts(
    method execute (line 187) | async execute(options: TeamToolExecutionOptions): Promise<any> {
    method spawnTeammate (line 226) | private async spawnTeammate(options: TeamToolExecutionOptions): Promis...
    method messageTeammate (line 299) | private messageTeammate(args: Record<string, any>): any {
    method broadcastToTeam (line 333) | private broadcastToTeam(args: Record<string, any>): any {
    method shutdownTeammate (line 346) | private shutdownTeammate(args: Record<string, any>): any {
    method waitForTeammates (line 377) | private async waitForTeammates(
    method createTask (line 460) | private createTask(args: Record<string, any>): any {
    method updateTask (line 488) | private updateTask(args: Record<string, any>): any {
    method listTasks (line 513) | private listTasks(): any {
    method listTeammates (line 533) | private listTeammates(): any {
    method mergeTeammateWork (line 549) | private async mergeTeammateWork(args: Record<string, any>): Promise<an...
    method mergeAllTeammateWork (line 635) | private async mergeAllTeammateWork(args: Record<string, any>): Promise...
    method resolveMergeConflicts (line 776) | private resolveMergeConflicts(): any {
    method abortMerge (line 800) | private abortMerge(): any {
    method cleanupTeam (line 815) | private async cleanupTeam(): Promise<any> {
    method approvePlan (line 871) | private approvePlan(args: Record<string, any>): any {
    method getTools (line 902) | getTools(): Array<{
  function getTeamMCPTools (line 1084) | function getTeamMCPTools(): Array<{

FILE: source/mcp/todo.ts
  class TodoService (line 19) | class TodoService {
    method constructor (line 23) | constructor(baseDir: string, getCurrentSessionId: GetCurrentSessionId) {
    method initialize (line 30) | async initialize(): Promise<void> {
    method getTodoPath (line 34) | private getTodoPath(sessionId: string, date?: Date): string {
    method ensureTodoDir (line 41) | private async ensureTodoDir(date?: Date): Promise<void> {
    method saveTodoList (line 58) | async saveTodoList(
    method getTodoList (line 97) | async getTodoList(sessionId: string): Promise<TodoList | null> {
    method findTodoInDateFolders (line 118) | private async findTodoInDateFolders(
    method updateTodoItem (line 150) | async updateTodoItem(
    method updateTodoItems (line 178) | async updateTodoItems(
    method addTodoItem (line 211) | async addTodoItem(
    method deleteTodoItem (line 248) | async deleteTodoItem(
    method deleteTodoItems (line 266) | async deleteTodoItems(
    method createEmptyTodo (line 285) | async createEmptyTodo(sessionId: string): Promise<TodoList> {
    method copyTodoList (line 295) | async copyTodoList(
    method deleteTodoList (line 323) | async deleteTodoList(sessionId: string): Promise<boolean> {
    method getTools (line 363) | getTools(): Tool[] {
    method executeTool (line 448) | async executeTool(

FILE: source/mcp/types/aceCodeSearch.types.ts
  type SymbolType (line 8) | type SymbolType =
  type CodeSymbol (line 23) | interface CodeSymbol {
  type ReferenceType (line 40) | type ReferenceType = 'definition' | 'usage' | 'import' | 'type';
  type CodeReference (line 45) | interface CodeReference {
  type SemanticSearchResult (line 57) | interface SemanticSearchResult {
  type ASTNode (line 68) | interface ASTNode {
  type TextSearchResult (line 81) | interface TextSearchResult {
  type LanguageConfig (line 91) | interface LanguageConfig {
  type IndexStats (line 106) | interface IndexStats {

FILE: source/mcp/types/bash.types.ts
  type CommandExecutionResult (line 8) | interface CommandExecutionResult {

FILE: source/mcp/types/filesystem.types.ts
  type MCPContentType (line 10) | type MCPContentType = 'text' | 'image' | 'document';
  type TextContent (line 15) | interface TextContent {
  type ImageContent (line 23) | interface ImageContent {
  type DocumentContent (line 32) | interface DocumentContent {
  type MultimodalContent (line 47) | type MultimodalContent = Array<
  constant IMAGE_MIME_TYPES (line 54) | const IMAGE_MIME_TYPES: Record<string, string> = {
  constant OFFICE_FILE_TYPES (line 67) | const OFFICE_FILE_TYPES: Record<
  type StructureAnalysis (line 83) | interface StructureAnalysis {
  type FileReadConfig (line 104) | interface FileReadConfig {
  type SingleFileReadResult (line 113) | interface SingleFileReadResult {
  type MultipleFilesReadResult (line 127) | interface MultipleFilesReadResult {
  type EditBySearchConfig (line 145) | interface EditBySearchConfig {
  type HashlineOperationType (line 155) | type HashlineOperationType = 'replace' | 'insert_after' | 'delete';
  type HashlineOperation (line 161) | interface HashlineOperation {
  type EditByHashlineConfig (line 174) | interface EditByHashlineConfig {
  type EditByHashlineSingleResult (line 182) | interface EditByHashlineSingleResult extends SingleFileEditResult {
  type SingleFileEditResult (line 190) | interface SingleFileEditResult {
  type EditBySearchSingleResult (line 205) | interface EditBySearchSingleResult extends SingleFileEditResult {
  type BatchResultItem (line 213) | interface BatchResultItem {
  type EditBySearchBatchResultItem (line 222) | type EditBySearchBatchResultItem = BatchResultItem &
  type EditByHashlineBatchResultItem (line 228) | type EditByHashlineBatchResultItem = BatchResultItem &
  type BatchOperationResult (line 234) | interface BatchOperationResult<T extends BatchResultItem> {
  type EditByHashlineResult (line 245) | type EditByHashlineResult =
  type EditBySearchResult (line 252) | type EditBySearchResult =

FILE: source/mcp/types/todo.types.ts
  type TodoItem (line 8) | interface TodoItem {
  type TodoList (line 20) | interface TodoList {
  type GetCurrentSessionId (line 30) | type GetCurrentSessionId = () => string | null;

FILE: source/mcp/types/websearch.types.ts
  type SearchResult (line 8) | interface SearchResult {
  type SearchResponse (line 18) | interface SearchResponse {
  type WebPageContent (line 27) | interface WebPageContent {

FILE: source/mcp/utils/aceCodeSearch/constants.utils.ts
  constant INDEX_CACHE_DURATION (line 8) | const INDEX_CACHE_DURATION = 60000;
  constant BATCH_SIZE (line 13) | const BATCH_SIZE = 10;
  constant BINARY_EXTENSIONS (line 19) | const BINARY_EXTENSIONS = new Set([
  constant GREP_EXCLUDE_DIRS (line 56) | const GREP_EXCLUDE_DIRS = [
  constant RECENT_FILE_THRESHOLD (line 71) | const RECENT_FILE_THRESHOLD = 24 * 60 * 60 * 1000;
  constant MAX_FILE_CACHE_SIZE (line 76) | const MAX_FILE_CACHE_SIZE = 50;
  constant MAX_FILE_STAT_CACHE_SIZE (line 82) | const MAX_FILE_STAT_CACHE_SIZE = 500;
  constant ACE_IDLE_CLEANUP_MS (line 88) | const ACE_IDLE_CLEANUP_MS = 2 * 60 * 1000;
  constant MAX_INDEXED_FILES (line 94) | const MAX_INDEXED_FILES = 2000;
  constant MAX_SYMBOLS_PER_FILE (line 100) | const MAX_SYMBOLS_PER_FILE = 100;
  constant MAX_FZF_SYMBOL_NAMES (line 106) | const MAX_FZF_SYMBOL_NAMES = 30000;
  constant MAX_FILE_OUTLINE_SYMBOLS (line 112) | const MAX_FILE_OUTLINE_SYMBOLS = 200;
  constant MAX_FILE_OUTLINE_PAYLOAD_CHARS (line 118) | const MAX_FILE_OUTLINE_PAYLOAD_CHARS = 120_000;
  constant LARGE_FILE_THRESHOLD (line 125) | const LARGE_FILE_THRESHOLD = 1024 * 1024;
  constant FILE_READ_CHUNK_SIZE (line 131) | const FILE_READ_CHUNK_SIZE = 512 * 1024;
  constant TEXT_SEARCH_TIMEOUT_MS (line 137) | const TEXT_SEARCH_TIMEOUT_MS = 30000;
  constant MAX_CONCURRENT_FILE_READS (line 143) | const MAX_CONCURRENT_FILE_READS = 20;
  constant MAX_REGEX_COMPLEXITY_SCORE (line 149) | const MAX_REGEX_COMPLEXITY_SCORE = 100;
  constant MAX_CONTENT_CACHE_BYTES (line 155) | const MAX_CONTENT_CACHE_BYTES = 50 * 1024 * 1024;
  constant MEMORY_PRESSURE_THRESHOLD_BYTES (line 161) | const MEMORY_PRESSURE_THRESHOLD_BYTES = 512 * 1024 * 1024;
  constant MEMORY_CHECK_INTERVAL_MS (line 167) | const MEMORY_CHECK_INTERVAL_MS = 10_000;

FILE: source/mcp/utils/aceCodeSearch/filesystem.utils.ts
  constant DEFAULT_EXCLUDES (line 11) | const DEFAULT_EXCLUDES = [
  function shouldExcludeDirectory (line 35) | function shouldExcludeDirectory(
  function shouldExcludeFile (line 91) | function shouldExcludeFile(
  function loadExclusionPatterns (line 165) | async function loadExclusionPatterns(
  type ContentCacheCallbacks (line 213) | interface ContentCacheCallbacks {
  function readFileWithCache (line 226) | async function readFileWithCache(
  function isGitRepository (line 265) | async function isGitRepository(

FILE: source/mcp/utils/aceCodeSearch/language.utils.ts
  constant LANGUAGE_CONFIG (line 10) | const LANGUAGE_CONFIG: Record<string, LanguageConfig> = {
  function detectLanguage (line 462) | function detectLanguage(filePath: string): string | null {

FILE: source/mcp/utils/aceCodeSearch/search.utils.ts
  function isCommandAvailable (line 15) | function isCommandAvailable(command: string): Promise<boolean> {
  function parseGrepOutput (line 47) | function parseGrepOutput(
  function globToRegex (line 94) | function globToRegex(glob: string): RegExp {
  function calculateFuzzyScore (line 120) | function calculateFuzzyScore(symbolName: string, query: string): number {
  function expandGlobBraces (line 159) | function expandGlobBraces(glob: string): string[] {
  function globPatternToRegex (line 184) | function globPatternToRegex(globPattern: string): RegExp {
  function calculateRegexComplexity (line 213) | function calculateRegexComplexity(pattern: string): number {
  function isSafeRegexPattern (line 258) | function isSafeRegexPattern(
  function processWithConcurrency (line 288) | async function processWithConcurrency<T, R>(
  function createTimeoutPromise (line 319) | function createTimeoutPromise(
  function sortResultsByRecency (line 336) | async function sortResultsByRecency(

FILE: source/mcp/utils/aceCodeSearch/symbol.utils.ts
  function getContext (line 16) | function getContext(
  type ParseFileSymbolsOptions (line 30) | interface ParseFileSymbolsOptions {
  function parseFileSymbols (line 43) | async function parseFileSymbols(

FILE: source/mcp/utils/bash/security.utils.ts
  constant DANGEROUS_PATTERNS (line 8) | const DANGEROUS_PATTERNS = [
  function isDangerousCommand (line 20) | function isDangerousCommand(command: string): boolean {
  function isSelfDestructiveCommand (line 31) | function isSelfDestructiveCommand(command: string): {
  function truncateOutput (line 102) | function truncateOutput(output: string, maxLength: number): string {

FILE: source/mcp/utils/filesystem/backup.utils.ts
  type BackupFileParams (line 1) | type BackupFileParams = {
  function backupFileBeforeMutation (line 12) | async function backupFileBeforeMutation(

FILE: source/mcp/utils/filesystem/batch-operations.utils.ts
  function parseFilePathParameter (line 15) | function parseFilePathParameter<T extends {path: string}>(
  function extractFilePath (line 27) | function extractFilePath<T extends {path: string}>(
  function parseEditBySearchParams (line 36) | function parseEditBySearchParams(
  function executeBatchOperation (line 72) | async function executeBatchOperation<

FILE: source/mcp/utils/filesystem/code-analysis.utils.ts
  function analyzeCodeStructure (line 11) | function analyzeCodeStructure(
  function findSmartContextBoundaries (line 156) | function findSmartContextBoundaries(

FILE: source/mcp/utils/filesystem/diagnostics.utils.ts
  function sleep (line 6) | function sleep(ms: number): Promise<void> {
  function getDiagnosticFingerprint (line 10) | function getDiagnosticFingerprint(diagnostics: Diagnostic[]): string {
  function getFreshDiagnostics (line 28) | async function getFreshDiagnostics(filePath: string): Promise<Diagnostic...

FILE: source/mcp/utils/filesystem/edit-tools.utils.ts
  type EditToolContext (line 41) | type EditToolContext = {
  function executeEditBySearchSingle (line 51) | async function executeEditBySearchSingle(
  function executeHashlineEditSingle (line 356) | async function executeHashlineEditSingle(

FILE: source/mcp/utils/filesystem/encoding.utils.ts
  constant MAX_READABLE_FILE_BYTES (line 8) | const MAX_READABLE_FILE_BYTES = 256 * 1024 * 1024;
  constant ENCODING_SAMPLE_BYTES (line 11) | const ENCODING_SAMPLE_BYTES = 64 * 1024;
  function isUtf8Buffer (line 13) | function isUtf8Buffer(buffer: Buffer): boolean {
  function readFileWithEncoding (line 40) | async function readFileWithEncoding(filePath: string): Promise<string> {
  function readFileLinesStreaming (line 116) | async function readFileLinesStreaming(
  function writeFileWithEncoding (line 198) | async function writeFileWithEncoding(

FILE: source/mcp/utils/filesystem/hashline.utils.ts
  function lineHash (line 15) | function lineHash(content: string): string {
  function formatLineWithHash (line 32) | function formatLineWithHash(lineNum: number, content: string): string {
  function formatLineWithHashDisplay (line 43) | function formatLineWithHashDisplay(
  type ParsedAnchor (line 53) | interface ParsedAnchor {
  function parseAnchor (line 62) | function parseAnchor(anchor: string): ParsedAnchor | null {
  function validateAnchor (line 75) | function validateAnchor(
  function buildHashMap (line 100) | function buildHashMap(lines: string[]): string[] {

FILE: source/mcp/utils/filesystem/match-finder.utils.ts
  type MatchCandidate (line 5) | interface MatchCandidate {
  function findClosestMatches (line 19) | async function findClosestMatches(
  function generateDiffMessage (line 100) | function generateDiffMessage(

FILE: source/mcp/utils/filesystem/message-format.utils.ts
  type DiagnosticsSummaryOptions (line 4) | type DiagnosticsSummaryOptions = {
  function appendDiagnosticsSummary (line 13) | function appendDiagnosticsSummary(
  function getStructureWarnings (line 57) | function getStructureWarnings(structureAnalysis: StructureAnalysis): str...
  function appendStructureWarnings (line 115) | function appendStructureWarnings(

FILE: source/mcp/utils/filesystem/office-parser.utils.ts
  function parseWordDocument (line 18) | async function parseWordDocument(
  function parsePDFDocument (line 44) | async function parsePDFDocument(
  function parseExcelDocument (line 80) | async function parseExcelDocument(
  function parsePowerPointDocument (line 121) | async function parsePowerPointDocument(
  function getOfficeFileType (line 150) | function getOfficeFileType(
  function readOfficeDocument (line 162) | async function readOfficeDocument(

FILE: source/mcp/utils/filesystem/path-fixer.utils.ts
  function tryFixPath (line 10) | async function tryFixPath(

FILE: source/mcp/utils/filesystem/read-tools.utils.ts
  type GetFileContentContext (line 17) | type GetFileContentContext = {
  function executeGetFileContentCore (line 43) | async function executeGetFileContentCore(

FILE: source/mcp/utils/filesystem/similarity.utils.ts
  function calculateSimilarity (line 10) | function calculateSimilarity(
  function levenshteinDistance (line 51) | function levenshteinDistance(
  function levenshteinDistanceAsync (line 105) | async function levenshteinDistanceAsync(
  function calculateSimilarityAsync (line 165) | async function calculateSimilarityAsync(
  function normalizeForDisplay (line 204) | function normalizeForDisplay(line: string): string {

FILE: source/mcp/utils/todo/date.utils.ts
  function formatDateForFolder (line 10) | function formatDateForFolder(date: Date): string {

FILE: source/mcp/utils/websearch/browser.utils.ts
  function isWSL (line 14) | function isWSL(): boolean {
  function findWindowsBrowserInWSL (line 35) | function findWindowsBrowserInWSL(): string | null {
  function launchWindowsBrowserFromWSL (line 61) | async function launchWindowsBrowserFromWSL(
  function getRunningBrowserWSEndpoint (line 122) | async function getRunningBrowserWSEndpoint(
  function findBrowserExecutable (line 167) | function findBrowserExecutable(): string | null {

FILE: source/mcp/utils/websearch/text.utils.ts
  function cleanText (line 12) | function cleanText(text: string): string {
  function formatSearchResults (line 29) | function formatSearchResults(searchResponse: SearchResponse): string {

FILE: source/mcp/websearch.ts
  class WebSearchService (line 34) | class WebSearchService {
    method constructor (line 41) | constructor(maxResults: number = 10) {
    method launchBrowser (line 59) | private async launchBrowser(): Promise<Browser> {
    method launchBrowserWSL (line 79) | private async launchBrowserWSL(
    method launchBrowserDirect (line 133) | private async launchBrowserDirect(
    method closeBrowser (line 190) | async closeBrowser(): Promise<void> {
    method search (line 216) | async search(query: string, maxResults?: number): Promise<SearchRespon...
    method fetchPage (line 273) | async fetchPage(

FILE: source/prompt/planModeSystemPrompt.ts
  constant PLAN_MODE_SYSTEM_PROMPT (line 17) | const PLAN_MODE_SYSTEM_PROMPT = `You are Snow AI CLI - Plan Mode, a task...
  function getAnalysisToolsSection (line 216) | function getAnalysisToolsSection(hasCodebase: boolean): string {
  function getAvailableToolsSection (line 236) | function getAvailableToolsSection(hasCodebase: boolean): string {
  constant TOOL_DISCOVERY_SECTIONS (line 259) | const TOOL_DISCOVERY_SECTIONS = {
  function getPlanModeSystemPrompt (line 290) | function getPlanModeSystemPrompt(toolSearchDisabled = false): string {

FILE: source/prompt/shared/promptHelpers.ts
  function getSystemPromptWithRole (line 17) | function getSystemPromptWithRole(
  function detectWindowsPowerShell (line 99) | function detectWindowsPowerShell(): 'pwsh' | 'powershell' | null {
  function getSystemEnvironmentInfo (line 124) | function getSystemEnvironmentInfo(
  function isCodebaseEnabled (line 189) | function isCodebaseEnabled(): boolean {
  function getCurrentTimeInfo (line 201) | function getCurrentTimeInfo(): {date: string} {
  function appendSystemContext (line 212) | function appendSystemContext(
  function getOverrideRoleContent (line 230) | function getOverrideRoleContent(): string | null {
  function getToolDiscoverySection (line 305) | function getToolDiscoverySection(

FILE: source/prompt/systemPrompt.ts
  function getPlatformCommandsSection (line 20) | function getPlatformCommandsSection(): string {
  constant SYSTEM_PROMPT_TEMPLATE (line 82) | const SYSTEM_PROMPT_TEMPLATE = `You are Snow AI CLI, an intelligent comm...
  function getWorkflowSection (line 298) | function getWorkflowSection(hasCodebase: boolean): string {
  function getCodeSearchSection (line 335) | function getCodeSearchSection(hasCodebase: boolean): string {
  constant TOOL_DISCOVERY_SECTIONS (line 360) | const TOOL_DISCOVERY_SECTIONS = {
  function getSystemPrompt (line 409) | function getSystemPrompt(toolSearchDisabled = false): string {
  function getSystemPromptForMode (line 465) | function getSystemPromptForMode(

FILE: source/prompt/teamModeSystemPrompt.ts
  constant TEAM_MODE_SYSTEM_PROMPT (line 16) | const TEAM_MODE_SYSTEM_PROMPT = `You are Snow AI CLI, operating in **Age...
  function getCodeSearchSection (line 161) | function getCodeSearchSection(hasCodebase: boolean): string {
  constant TOOL_DISCOVERY_SECTIONS (line 178) | const TOOL_DISCOVERY_SECTIONS = {
  function getTeamModeSystemPrompt (line 185) | function getTeamModeSystemPrompt(toolSearchDisabled = false): string {

FILE: source/prompt/vulnerabilityHuntingModeSystemPrompt.ts
  constant VULNERABILITY_HUNTING_MODE_SYSTEM_PROMPT (line 16) | const VULNERABILITY_HUNTING_MODE_SYSTEM_PROMPT = `You are Snow AI CLI - ...
  function getAnalysisToolsSection (line 537) | function getAnalysisToolsSection(hasCodebase: boolean): string {
  function getAvailableToolsSection (line 555) | function getAvailableToolsSection(hasCodebase: boolean): string {
  constant TOOL_DISCOVERY_SECTIONS (line 584) | const TOOL_DISCOVERY_SECTIONS = {
  function getVulnerabilityHuntingModeSystemPrompt (line 604) | function getVulnerabilityHuntingModeSystemPrompt(

FILE: source/test/rg-spawn-repro/rg-spawn-repro-fixed.mjs
  function parseArgs (line 11) | function parseArgs(argv) {
  function buildRipgrepArgs (line 50) | function buildRipgrepArgs(pattern, fileGlob) {
  function main (line 77) | async function main() {

FILE: source/test/rg-spawn-repro/rg-spawn-repro.mjs
  function parseArgs (line 11) | function parseArgs(argv) {
  function buildRipgrepArgs (line 50) | function buildRipgrepArgs(pattern, fileGlob) {
  function main (line 76) | async function main() {

FILE: source/test/sse-client/app.js
  function byId (line 32) | function byId(id) {
  function escapeHtml (line 37) | function escapeHtml(str) {
  function formatTime (line 47) | function formatTime(ts) {
  function summarizeText (line 57) | function summarizeText(text) {
  function normalizeChatMessageContent (line 64) | function normalizeChatMessageContent(msg) {
  function setSessionControlsEnabled (line 87) | function setSessionControlsEnabled(enabled) {
  function renderSessionList (line 100) | function renderSessionList() {
  function selectSession (line 153) | function selectSession(sessionId) {
  function refreshSessionList (line 160) | async function refreshSessionList() {
  function onSessionSearchChange (line 211) | function onSessionSearchChange() {
  function onSessionPageSizeChange (line 224) | function onSessionPageSizeChange() {
  function prevSessionPage (line 232) | function prevSessionPage() {
  function nextSessionPage (line 239) | function nextSessionPage() {
  function loadSelectedSession (line 246) | async function loadSelectedSession() {
  function refreshCurrentSession (line 279) | async function refreshCurrentSession() {
  function renderSessionHistoryToChat (line 303) | function renderSessionHistoryToChat(session) {
  function deleteSelectedSession (line 348) | async function deleteSelectedSession() {
  function addMessage (line 390) | function addMessage(role, content, imageData = null) {
  function updateAssistantMessage (line 422) | function updateAssistantMessage(messageDiv, content) {
  function showLoadingMessage (line 431) | function showLoadingMessage() {
  function removeLoadingMessage (line 447) | function removeLoadingMessage() {
  function addSystemMessage (line 455) | function addSystemMessage(content) {
  function logEvent (line 472) | function logEvent(type, data, isError = false) {
  function getDataPreview (line 520) | function getDataPreview(data) {
  function toggleEventDetails (line 562) | function toggleEventDetails(eventId) {
  function expandAllEvents (line 578) | function expandAllEvents() {
  function collapseAllEvents (line 588) | function collapseAllEvents() {
  function updateEventCount (line 598) | function updateEventCount() {
  function clearLog (line 606) | function clearLog() {
  function showLogDetail (line 613) | function showLogDetail(eventId, type, dataJson) {
  function newSession (line 683) | async function newSession() {
  function createServerSession (line 719) | async function createServerSession() {
  function loadServerSession (line 750) | async function loadServerSession() {
  function listServerSessions (line 773) | async function listServerSessions() {
  function deleteCurrentSession (line 797) | async function deleteCurrentSession() {
  function compressCurrentSession (line 825) | async function compressCurrentSession() {
  function compressCustomMessages (line 886) | async function compressCustomMessages() {
  function showCompressMessagesDialog (line 940) | function showCompressMessagesDialog() {
  function updateSessionStatusText (line 1013) | function updateSessionStatusText() {
  function updateStatus (line 1034) | function updateStatus(connected) {
  function connect (line 1046) | function connect() {
  function disconnect (line 1087) | function disconnect() {
  function handleEvent (line 1106) | function handleEvent(event) {
  function handleToolConfirmation (line 1247) | function handleToolConfirmation(event) {
  function handleUserQuestion (line 1252) | function handleUserQuestion(event) {
  function sendMessage (line 1261) | async function sendMessage() {
  function abortTask (line 1327) | async function abortTask() {
  function fetchRollbackPoints (line 1368) | async function fetchRollbackPoints(sessionId) {
  function buildRollbackPointsHtml (line 1382) | function buildRollbackPointsHtml(points) {
  function showRollbackDialogAndGetSelection (line 1438) | async function showRollbackDialogAndGetSelection(sessionId) {
  function rollbackSession (line 1506) | async function rollbackSession() {
  function sendResponse (line 1570) | async function sendResponse(type, requestId, response) {
  function handleImageSelect (line 1596) | function handleImageSelect(filesOrFile) {
  function showImagePreview (line 1623) | function showImagePreview(images) {
  function removeSelectedImage (line 1655) | function removeSelectedImage(index) {
  function clearImagePreview (line 1665) | function clearImagePreview() {

FILE: source/test/sse-client/dialogs.js
  function showToolConfirmationDialog (line 2) | function showToolConfirmationDialog(event, sendResponse) {
  function showUserQuestionDialog (line 103) | function showUserQuestionDialog(event, sendResponse) {

FILE: source/test/sse-client/json-viewer.js
  method render (line 18) | render(data, options = {}) {
  method renderTo (line 52) | renderTo(container, data, options = {}) {
  method renderTree (line 73) | renderTree(data, options = {}) {
  method _buildTree (line 98) | _buildTree(data, depth, maxDepth) {
  method toggle (line 192) | toggle(id) {
  method expandAll (line 218) | expandAll(container) {
  method collapseAll (line 238) | collapseAll(container) {
  method _generateId (line 259) | _generateId() {
  method escapeHtml (line 268) | escapeHtml(str) {

FILE: source/types/index.ts
  type SnowConfig (line 1) | interface SnowConfig {
  type Command (line 7) | interface Command {
  type AppState (line 13) | interface AppState {

FILE: source/ui/components/bash/BackgroundProcessPanel.tsx
  type BackgroundProcessPanelProps (line 7) | interface BackgroundProcessPanelProps {
  function truncateCommand (line 16) | function truncateCommand(text: string, maxWidth: number): string {
  function formatDuration (line 28) | function formatDuration(start: Date, end?: Date): string {

FILE: source/ui/components/bash/BashCommandConfirmation.tsx
  type BashCommandConfirmationProps (line 12) | interface BashCommandConfirmationProps {
  function sanitizePreviewLine (line 24) | function sanitizePreviewLine(text: string): string {
  function truncateCommand (line 37) | function truncateCommand(text: string, maxWidth: number = 100): string {
  function BashCommandConfirmation (line 46) | function BashCommandConfirmation({
  type BashCommandExecutionStatusProps (line 132) | interface BashCommandExecutionStatusProps {
  function truncateText (line 145) | function truncateText(text: string, maxWidth: number = 80): string {
  function BashCommandExecutionStatus (line 154) | function BashCommandExecutionStatus({

FILE: source/ui/components/bash/CustomCommandExecutionDisplay.tsx
  type CustomCommandExecutionDisplayProps (line 6) | interface CustomCommandExecutionDisplayProps {
  function sanitizePreviewLine (line 15) | function sanitizePreviewLine(text: string): string {
  function truncateText (line 25) | function truncateText(text: string, maxWidth: number = 80): string {
  function CustomCommandExecutionDisplay (line 40) | function CustomCommandExecutionDisplay({

FILE: source/ui/components/chat/ChatFooter.tsx
  type ChatFooterProps (line 24) | type ChatFooterProps = {

FILE: source/ui/components/chat/ChatInput.tsx
  function parseSkillIdFromHeaderLine (line 41) | function parseSkillIdFromHeaderLine(line: string): string {
  function parseGitLineShaFromHeaderLine (line 45) | function parseGitLineShaFromHeaderLine(line: string): string {
  function restoreTextWithSkillPlaceholders (line 49) | function restoreTextWithSkillPlaceholders(
  function calculateContextPercentage (line 167) | function calculateContextPercentage(contextUsage: {
  type Props (line 193) | type Props = {
  function ChatInput (line 267) | function ChatInput({

FILE: source/ui/components/chat/CodebaseSearchStatus.tsx
  type CodebaseSearchStatusData (line 5) | type CodebaseSearchStatusData = {
  type Props (line 16) | type Props = {
  function truncateQuery (line 21) | function truncateQuery(query: string, maxLength: number = 50): string {
  function CodebaseSearchStatus (line 28) | function CodebaseSearchStatus({status}: Props) {

FILE: source/ui/components/chat/LoadingIndicator.tsx
  function truncateErrorMessage (line 18) | function truncateErrorMessage(
  function formatTokens (line 28) | function formatTokens(count: number): string {
  type LoadingIndicatorProps (line 33) | type LoadingIndicatorProps = {
  function LoadingIndicator (line 65) | function LoadingIndicator({

FILE: source/ui/components/chat/MessageList.tsx
  type Message (line 7) | interface Message {
  type Props (line 96) | interface Props {
  constant STREAM_COLORS (line 101) | const STREAM_COLORS = ['#FF6EBF', 'green', 'blue', 'cyan', '#B588F8'] as...
  function formatCommandResultLines (line 103) | function formatCommandResultLines(content: string): string[] {
  function formatAiCompletionTime (line 109) | function formatAiCompletionTime(value: Date | string): string {

FILE: source/ui/components/chat/MessageRenderer.tsx
  function cleanThinkingContent (line 17) | function cleanThinkingContent(content: string): string {
  type Props (line 21) | type Props = {
  function MessageRenderer (line 29) | function MessageRenderer({

FILE: source/ui/components/chat/PendingMessages.tsx
  type PendingMessage (line 6) | interface PendingMessage {
  type Props (line 11) | interface Props {
  function PendingMessages (line 15) | function PendingMessages({pendingMessages}: Props) {

FILE: source/ui/components/chat/PendingToolCalls.tsx
  type Props (line 6) | interface Props {
  function PendingToolCalls (line 14) | function PendingToolCalls({messages}: Props) {

FILE: source/ui/components/chat/UserMessagePreview.tsx
  type Props (line 6) | type Props = {
  function UserMessagePreview (line 10) | function UserMessagePreview({content}: Props) {

FILE: source/ui/components/common/MarkdownRenderer.tsx
  method text (line 32) | text(token: any) {
  method start (line 52) | start(src: string) {
  method tokenizer (line 55) | tokenizer(src: string) {
  method renderer (line 67) | renderer(token: any) {
  method start (line 78) | start(src: string) {
  method tokenizer (line 81) | tokenizer(src: string) {
  method renderer (line 93) | renderer(token: any) {
  method walkTokens (line 107) | walkTokens(token: any) {
  type Props (line 114) | interface Props {
  function sanitizeMarkdownContent (line 122) | function sanitizeMarkdownContent(content: string): string {
  function renderFallback (line 130) | function renderFallback(content: string): React.ReactElement {
  constant ANSI_PATTERN (line 141) | const ANSI_PATTERN = /\x1b\[[0-9;]*m/g;
  function isEmptyLine (line 143) | function isEmptyLine(line: string): boolean {
  function trimLines (line 148) | function trimLines(lines: string[]): string[] {
  function renderMarkdownToLines (line 166) | function renderMarkdownToLines(content: string): string[] {
  function MarkdownRenderer (line 177) | function MarkdownRenderer({content}: Props) {

FILE: source/ui/components/common/Menu.tsx
  type MenuOption (line 7) | type MenuOption = {
  type Props (line 15) | type Props = {
  function Menu (line 23) | function Menu({

FILE: source/ui/components/common/PickerList.tsx
  constant DEFAULT_MAX_DISPLAY_ITEMS (line 5) | const DEFAULT_MAX_DISPLAY_ITEMS = 5;
  type DisplayWindow (line 7) | interface DisplayWindow<T> {
  function usePickerWindow (line 13) | function usePickerWindow<T>(
  type PickerListProps (line 61) | interface PickerListProps<T> {
  function PickerListInner (line 76) | function PickerListInner<T>({

FILE: source/ui/components/common/ScrollableSelectInput.tsx
  type SelectItem (line 4) | type SelectItem = {
  type IndicatorProps (line 11) | type IndicatorProps = {
  type RenderItemProps (line 15) | type RenderItemProps<T extends SelectItem> = T & {
  type Props (line 20) | type Props<T extends SelectItem> = {
  function DefaultIndicator (line 35) | function DefaultIndicator({isSelected}: IndicatorProps) {
  function DefaultItem (line 43) | function DefaultItem<T extends SelectItem>({
  function ScrollableSelectInput (line 50) | function ScrollableSelectInput<T extends SelectItem>({

FILE: source/ui/components/common/ShimmerText.tsx
  type ShimmerTextProps (line 5) | interface ShimmerTextProps {
  function ShimmerText (line 12) | function ShimmerText({text}: ShimmerTextProps) {

FILE: source/ui/components/common/StatusLine.tsx
  constant MEMORY_REFRESH_INTERVAL_MS (line 27) | const MEMORY_REFRESH_INTERVAL_MS = 5000;
  constant PROCESS_MEMORY_COMMAND_TIMEOUT_MS (line 28) | const PROCESS_MEMORY_COMMAND_TIMEOUT_MS = 1500;
  constant WINDOWS_POWERSHELL_CANDIDATES (line 30) | const WINDOWS_POWERSHELL_CANDIDATES = [
  function getFallbackProcessMemoryUsageMb (line 41) | function getFallbackProcessMemoryUsageMb(): number {
  function parseMacosPhysicalFootprintMb (line 45) | function parseMacosPhysicalFootprintMb(
  function parseWindowsMemoryUsageMb (line 81) | function parseWindowsMemoryUsageMb(commandOutput: string): number | unde...
  function getMacosProcessMemoryUsageMb (line 95) | async function getMacosProcessMemoryUsageMb(): Promise<number | undefine...
  function getWindowsProcessMemoryUsageMb (line 112) | async function getWindowsProcessMemoryUsageMb(): Promise<number | undefi...
  function getCurrentProcessMemoryUsageMb (line 141) | async function getCurrentProcessMemoryUsageMb(): Promise<number> {
  function formatMemoryUsage (line 159) | function formatMemoryUsage(memoryUsageMb: number): string {
  function useCurrentProcessMemoryUsage (line 167) | function useCurrentProcessMemoryUsage(): number {
  type Props (line 206) | type Props = {
  function calculateContextPercentage (line 242) | function calculateContextPercentage(
  function buildContextWindowState (line 261) | function buildContextWindowState(
  function StatusLine (line 284) | function StatusLine({

FILE: source/ui/components/common/UpdateNotice.tsx
  type UpdateNoticeProps (line 5) | type UpdateNoticeProps = {
  function UpdateNotice (line 11) | function UpdateNotice({

FILE: source/ui/components/common/statusline/builtinIds.ts
  constant BUILTIN_STATUSLINE_IDS (line 11) | const BUILTIN_STATUSLINE_IDS = {
  type BuiltinStatusLineId (line 30) | type BuiltinStatusLineId =
  constant BUILTIN_STATUSLINE_ID_VALUES (line 33) | const BUILTIN_STATUSLINE_ID_VALUES = new Set<string>(
  function isBuiltinStatusLineId (line 37) | function isBuiltinStatusLineId(id: string): id is BuiltinStatusLineId {

FILE: source/ui/components/common/statusline/gitBranch.ts
  constant GIT_BRANCH_REFRESH_INTERVAL_MS (line 5) | const GIT_BRANCH_REFRESH_INTERVAL_MS = 10000;
  function getGitBranch (line 8) | async function getGitBranch(cwd: string): Promise<string | undefined> {
  method getItems (line 29) | async getItems(context) {

FILE: source/ui/components/common/statusline/types.ts
  type VSCodeConnectionStatus (line 3) | type VSCodeConnectionStatus =
  type BackendConnectionStatus (line 9) | type BackendConnectionStatus =
  type StatusLineRenderItem (line 15) | interface StatusLineRenderItem {
  type StatusLineLabels (line 23) | interface StatusLineLabels {
  type StatusLineEditorContext (line 27) | interface StatusLineEditorContext {
  type StatusLineContextUsage (line 34) | interface StatusLineContextUsage {
  type StatusLineCodebaseProgress (line 42) | interface StatusLineCodebaseProgress {
  type StatusLineFileUpdateNotification (line 51) | interface StatusLineFileUpdateNotification {
  type StatusLineCopyStatusMessage (line 56) | interface StatusLineCopyStatusMessage {
  type StatusLineContextWindowMetrics (line 62) | interface StatusLineContextWindowMetrics {
  type StatusLineSystemState (line 70) | interface StatusLineSystemState {
  type StatusLineHookContext (line 139) | interface StatusLineHookContext {
  type StatusLineHookDefinition (line 148) | interface StatusLineHookDefinition {

FILE: source/ui/components/common/statusline/useStatusLineHooks.ts
  constant DEFAULT_STATUSLINE_HOOK_REFRESH_INTERVAL_MS (line 14) | const DEFAULT_STATUSLINE_HOOK_REFRESH_INTERVAL_MS = 5000;
  constant SUPPORTED_STATUSLINE_HOOK_EXTENSIONS (line 15) | const SUPPORTED_STATUSLINE_HOOK_EXTENSIONS = new Set(['.js', '.mjs', '.c...
  constant BUILTIN_STATUSLINE_HOOKS (line 16) | const BUILTIN_STATUSLINE_HOOKS: StatusLineHookDefinition[] = [
  type StatusLineHookModule (line 20) | type StatusLineHookModule = {
  function isStatusLineHookDefinition (line 26) | function isStatusLineHookDefinition(
  function isHookEnabled (line 37) | function isHookEnabled(hook: StatusLineHookDefinition): boolean {
  function normalizeStatusLineRenderItem (line 41) | function normalizeStatusLineRenderItem(
  function normalizeStatusLineItems (line 52) | function normalizeStatusLineItems(
  function normalizeStatusLineHookExports (line 68) | function normalizeStatusLineHookExports(
  function loadExternalStatusLineHooks (line 99) | async function loadExternalStatusLineHooks(): Promise<
  function mergeStatusLineHooks (line 143) | function mergeStatusLineHooks(
  function sortStatusLineItems (line 159) | function sortStatusLineItems(
  type UseStatusLineHookItemsResult (line 175) | type UseStatusLineHookItemsResult = {
  function useStatusLineHookItems (line 180) | function useStatusLineHookItems(

FILE: source/ui/components/compression/CompressionStatus.tsx
  type CompressionStep (line 6) | type CompressionStep =
  type CompressionStatus (line 15) | type CompressionStatus = {
  type CompressionStatusProps (line 23) | interface CompressionStatusProps {
  function CompressionStatus (line 48) | function CompressionStatus({

FILE: source/ui/components/panels/AgentPickerPanel.tsx
  type Props (line 9) | interface Props {

FILE: source/ui/components/panels/BranchPanel.tsx
  type BranchInfo (line 8) | interface BranchInfo {
  type Props (line 13) | interface Props {
  function getGitError (line 21) | function getGitError(error: unknown): string {
  function isGitRepo (line 41) | function isGitRepo(): boolean {
  function listBranches (line 56) | function listBranches(): BranchInfo[] {
  type CheckoutResult (line 75) | type CheckoutResult = {
  function checkoutBranch (line 84) | function checkoutBranch(branchName: string): CheckoutResult {
  function stashAndCheckout (line 105) | function stashAndCheckout(
  function createBranch (line 146) | function createBranch(
  function deleteBranch (line 166) | function deleteBranch(
  type PanelMode (line 199) | type PanelMode = 'list' | 'create' | 'confirmDelete' | 'confirmStash';

FILE: source/ui/components/panels/BtwPanel.tsx
  type Step (line 11) | type Step = 'streaming' | 'done' | 'error';
  constant VISIBLE_ROWS (line 13) | const VISIBLE_ROWS = 8;
  constant DEBOUNCE_MS (line 14) | const DEBOUNCE_MS = 80;
  constant ANSI_REGEX (line 15) | const ANSI_REGEX = /\x1b\[[0-9;]*m/g;
  function stripAnsiCodes (line 17) | function stripAnsiCodes(input: string): string {
  function wrapLineToWidth (line 21) | function wrapLineToWidth(line: string, width: number): string[] {
  type Props (line 47) | interface Props {

FILE: source/ui/components/panels/CommandArgsPanel.tsx
  type Props (line 7) | interface Props {

FILE: source/ui/components/panels/CommandPanel.tsx
  type Command (line 7) | interface Command {
  type Props (line 12) | interface Props {

FILE: source/ui/components/panels/ConnectionPanel.tsx
  type Props (line 13) | interface Props {

FILE: source/ui/components/panels/CustomCommandConfigPanel.tsx
  type Props (line 12) | interface Props {

FILE: source/ui/components/panels/DiffReviewPanel.tsx
  type Props (line 12) | type Props = {
  type MessageItem (line 24) | type MessageItem = {
  type ViewMode (line 30) | type ViewMode = 'messages' | 'files';
  function DiffReviewPanel (line 32) | function DiffReviewPanel({

FILE: source/ui/components/panels/GitLinePickerPanel.tsx
  type Props (line 9) | interface Props {
  function formatShortSha (line 22) | function formatShortSha(sha: string): string {
  function formatDate (line 26) | function formatDate(isoDate: string): string {
  function truncateText (line 31) | function truncateText(text: string, maxLen: number): string {

FILE: source/ui/components/panels/HelpPanel.tsx
  constant MAX_VISIBLE_LINES (line 5) | const MAX_VISIBLE_LINES = 10;
  type HelpLine (line 12) | type HelpLine =
  function HelpPanel (line 17) | function HelpPanel() {

FILE: source/ui/components/panels/IdeSelectPanel.tsx
  type Props (line 11) | interface Props {
  type OptionItem (line 25) | interface OptionItem {

FILE: source/ui/components/panels/MCPInfoPanel.tsx
  type ToolsListProps (line 24) | interface ToolsListProps {
  function ToolsList (line 34) | function ToolsList({
  type ToolInfo (line 150) | interface ToolInfo {
  type MCPConnectionStatus (line 155) | interface MCPConnectionStatus {
  type SelectItem (line 166) | interface SelectItem {
  type Props (line 177) | interface Props {
  function MCPInfoPanel (line 181) | function MCPInfoPanel({onClose}: Props) {

FILE: source/ui/components/panels/ModelsPanel.tsx
  type Props (line 20) | interface Props {
  type Tab (line 27) | type Tab = 'advanced' | 'basic' | 'thinking';
  type ThinkingInputMode (line 29) | type ThinkingInputMode = null | 'anthropicBudgetTokens';
  type ResponsesReasoningEffort (line 31) | type ResponsesReasoningEffort = 'none' | 'low' | 'medium' | 'high' | 'xh...
  type ResponsesVerbosity (line 32) | type ResponsesVerbosity = 'low' | 'medium' | 'high';

FILE: source/ui/components/panels/NewPromptPanel.tsx
  type Step (line 9) | type Step = 'input' | 'generating' | 'preview' | 'error';
  type Props (line 11) | interface Props {
  constant VISIBLE_LINES (line 16) | const VISIBLE_LINES = 15;

FILE: source/ui/components/panels/PanelsManager.tsx
  type PanelsManagerProps (line 32) | type PanelsManagerProps = {
  function PanelsManager (line 93) | function PanelsManager({

FILE: source/ui/components/panels/PermissionsPanel.tsx
  type Props (line 6) | type Props = {
  type PermissionsMessages (line 13) | type PermissionsMessages = {
  type ConfirmTarget (line 25) | type ConfirmTarget = number | 'clearAll' | null;
  function PermissionsPanel (line 27) | function PermissionsPanel({

FILE: source/ui/components/panels/ProfileEditPanel.tsx
  type Props (line 4) | type Props = {
  function ProfileEditPanel (line 21) | function ProfileEditPanel({profileName, onClose}: Props) {

FILE: source/ui/components/panels/ProfilePanel.tsx
  type ProfileItem (line 7) | interface ProfileItem {
  type Props (line 13) | interface Props {

FILE: source/ui/components/panels/ReviewCommitPanel.tsx
  type ReviewCommitSelection (line 8) | type ReviewCommitSelection =
  type CommitItem (line 13) | type CommitItem = {
  type Props (line 20) | type Props = {
  constant VISIBLE_ITEMS (line 27) | const VISIBLE_ITEMS = 6;
  constant PAGE_SIZE (line 28) | const PAGE_SIZE = 30;
  function formatShortSha (line 30) | function formatShortSha(sha: string): string {
  function formatDate (line 34) | function formatDate(isoDate: string): string {
  function truncateText (line 40) | function truncateText(text: string, maxLen: number): string {
  function ReviewCommitPanel (line 47) | function ReviewCommitPanel({

FILE: source/ui/components/panels/RoleCreationPanel.tsx
  type Step (line 10) | type Step = 'location' | 'confirm';
  type Props (line 12) | interface Props {

FILE: source/ui/components/panels/RoleDeletionPanel.tsx
  type Step (line 10) | type Step = 'location' | 'confirm';
  type Props (line 12) | interface Props {

FILE: source/ui/components/panels/RoleListPanel.tsx
  type Tab (line 15) | type Tab = 'global' | 'project';
  type Props (line 17) | interface Props {

FILE: source/ui/components/panels/RoleSubagentCreationPanel.tsx
  type Step (line 12) | type Step = 'location' | 'selectAgent' | 'confirm';
  type Props (line 14) | interface Props {

FILE: source/ui/components/panels/RoleSubagentDeletionPanel.tsx
  type Step (line 11) | type Step = 'location' | 'selectRole' | 'confirm';
  type Props (line 13) | interface Props {

FILE: source/ui/components/panels/RoleSubagentListPanel.tsx
  type Tab (line 12) | type Tab = 'global' | 'project';
  type Props (line 14) | interface Props {

FILE: source/ui/components/panels/RollbackMenuPanel.tsx
  type MessageItem (line 4) | type MessageItem = {
  type Translation (line 10) | type Translation = {
  type ThemeColors (line 18) | type ThemeColors = {
  type Props (line 25) | type Props = {
  constant MAX_VISIBLE_ITEMS (line 34) | const MAX_VISIBLE_ITEMS = 5;
  function RollbackMenuPanel (line 36) | function RollbackMenuPanel({

FILE: source/ui/components/panels/RunningAgentsPanel.tsx
  type Props (line 9) | interface Props {
  function truncatePrompt (line 17) | function truncatePrompt(prompt: string, maxLength: number): string {
  function formatElapsed (line 30) | function formatElapsed(startedAt: Date): string {

FILE: source/ui/components/panels/SessionListPanel.tsx
  type Props (line 11) | type Props = {
  function SessionListPanel (line 16) | function SessionListPanel({onSelectSession, onClose}: Props) {

FILE: source/ui/components/panels/SkillsCreationPanel.tsx
  type CreationMode (line 16) | type CreationMode = 'manual' | 'ai';
  type Step (line 18) | type Step =
  type Props (line 31) | interface Props {

FILE: source/ui/components/panels/SkillsListPanel.tsx
  type Props (line 11) | interface Props {
  constant NON_FOCUSED_SKILL_DESC_MAX_LEN (line 15) | const NON_FOCUSED_SKILL_DESC_MAX_LEN = 30;
  constant MAX_DISPLAY_ITEMS (line 16) | const MAX_DISPLAY_ITEMS = 8;
  function SkillsListPanel (line 18) | function SkillsListPanel({onClose}: Props) {

FILE: source/ui/components/panels/SkillsPickerPanel.tsx
  type SkillsPickerFocus (line 7) | type SkillsPickerFocus = 'search' | 'append';
  type SkillsPickerItem (line 9) | type SkillsPickerItem = {
  type Props (line 16) | interface Props {

FILE: source/ui/components/panels/SubAgentDepthPanel.tsx
  type Props (line 11) | type Props = {
  function SubAgentDepthPanel (line 16) | function SubAgentDepthPanel({visible, onClose}: Props) {

FILE: source/ui/components/panels/TodoListPanel.tsx
  type Props (line 11) | type Props = {
  type FlattenedTodoItem (line 15) | type FlattenedTodoItem = TodoItem & {
  function getStatusIcon (line 20) | function getStatusIcon(status: TodoItem['status']): string {
  function buildFlattenedTodos (line 26) | function buildFlattenedTodos(todos: TodoItem[]): FlattenedTodoItem[] {
  function isDescendantOf (line 72) | function isDescendantOf(
  function TodoListPanel (line 89) | function TodoListPanel({onClose}: Props) {

FILE: source/ui/components/panels/TodoPickerPanel.tsx
  type Props (line 9) | interface Props {

FILE: source/ui/components/panels/UsagePanel.tsx
  type UsageLogEntry (line 11) | interface UsageLogEntry {
  type ModelStats (line 21) | interface ModelStats {
  type AggregatedStats (line 29) | interface AggregatedStats {
  type Granularity (line 34) | type Granularity = 'hour' | 'day' | 'week' | 'month';
  function getModelShortName (line 36) | function getModelShortName(modelName: string, maxLength = 20): string {
  function loadUsageData (line 153) | async function loadUsageData(): Promise<UsageLogEntry[]> {
  function filterByGranularity (line 199) | function filterByGranularity(
  function aggregateByModel (line 226) | function aggregateByModel(entries: UsageLogEntry[]): AggregatedStats {
  function formatTokens (line 256) | function formatTokens(tokens: number, compact = false): string {
  function renderStackedBarChart (line 270) | function renderStackedBarChart(
  function UsagePanel (line 514) | function UsagePanel() {

FILE: source/ui/components/panels/WorkingDirectoryPanel.tsx
  type Props (line 17) | type Props = {
  type SSHAuthMethod (line 21) | type SSHAuthMethod = 'password' | 'privateKey' | 'agent';
  type SSHFormState (line 23) | type SSHFormState = {
  type SSHFormField (line 33) | type SSHFormField =
  function WorkingDirectoryPanel (line 42) | function WorkingDirectoryPanel({onClose}: Props) {

FILE: source/ui/components/pixel-editor/PixelEditor.tsx
  constant PALETTE (line 8) | const PALETTE = [
  constant BLOCK_CHAR (line 21) | const BLOCK_CHAR = '\u2580';
  function createEmptyGrid (line 23) | function createEmptyGrid(width: number, height: number): PixelGrid {
  function blendWithWhite (line 29) | function blendWithWhite(hex: string, ratio: number): string {
  function applyCursorEffect (line 42) | function applyCursorEffect(hex: string): string {
  type PixelEditorProps (line 61) | type PixelEditorProps = {
  function PixelEditor (line 70) | function PixelEditor({

FILE: source/ui/components/pixel-editor/types.ts
  type PixelColor (line 1) | type PixelColor = string;
  type PixelGrid (line 3) | type PixelGrid = PixelColor[][];
  type PixelEditorProps (line 5) | interface PixelEditorProps {

FILE: source/ui/components/scheduler/SchedulerCountdown.tsx
  type SchedulerCountdownProps (line 7) | interface SchedulerCountdownProps {
  function formatDuration (line 17) | function formatDuration(seconds: number): string {
  function getProgressBar (line 28) | function getProgressBar(
  function SchedulerCountdown (line 39) | function SchedulerCountdown({

FILE: source/ui/components/special/AskUserQuestion.tsx
  type AskUserQuestionResult (line 7) | interface AskUserQuestionResult {
  type Props (line 13) | interface Props {
  constant VISIBLE_OPTION_ROWS (line 21) | const VISIBLE_OPTION_ROWS = 5;
  constant NON_FOCUSED_OPTION_MAX_LEN (line 23) | const NON_FOCUSED_OPTION_MAX_LEN = 20;
  function AskUserQuestion (line 40) | function AskUserQuestion({question, options, onAnswer}: Props) {

FILE: source/ui/components/special/ChatHeader.tsx
  type ChatHeaderProps (line 7) | type ChatHeaderProps = {
  function ChatHeader (line 13) | function ChatHeader({
  function maskRevealedChars (line 89) | function maskRevealedChars(full: string, revealChars?: number): string {
  function ChatHeaderLogo (line 112) | function ChatHeaderLogo({

FILE: source/ui/components/special/HookErrorDisplay.tsx
  type HookErrorDisplayProps (line 5) | interface HookErrorDisplayProps {

FILE: source/ui/components/special/TodoTree.tsx
  type TodoItem (line 6) | interface TodoItem {
  type TodoTreeProps (line 13) | interface TodoTreeProps {
  function TodoTree (line 20) | function TodoTree({todos}: TodoTreeProps) {

FILE: source/ui/components/sse/SSEServerStatus.tsx
  type LogEntry (line 5) | interface LogEntry {
  type SSEServerStatusProps (line 11) | interface SSEServerStatusProps {

FILE: source/ui/components/tools/DiffViewer.tsx
  type Props (line 11) | interface Props {
  type DiffHunk (line 20) | interface DiffHunk {
  function expandTabsForDisplay (line 31) | function expandTabsForDisplay(line: string, tabWidth = 2): string {
  function stripLineNumbers (line 50) | function stripLineNumbers(content: string): string {
  constant MIN_SIDE_BY_SIDE_WIDTH (line 74) | const MIN_SIDE_BY_SIDE_WIDTH = 120;
  constant LANGUAGE_BY_EXTENSION (line 76) | const LANGUAGE_BY_EXTENSION: Record<string, string> = {
  function inferLanguageFromFilename (line 106) | function inferLanguageFromFilename(filename?: string): string | undefined {
  function highlightCodeContent (line 121) | function highlightCodeContent(content: string, language?: string): string {
  function normalizeHexColor (line 136) | function normalizeHexColor(hex: string): string | null {
  function blendHexColors (line 158) | function blendHexColors(
  function computeHunks (line 193) | function computeHunks(
  function DiffViewer (line 313) | function DiffViewer({
  function formatUnified (line 449) | function formatUnified(
  function formatSideBySide (line 478) | function formatSideBySide(

FILE: source/ui/components/tools/FileList.tsx
  type FileItem (line 23) | type FileItem = {
  type Props (line 34) | type Props = {
  type FileListRef (line 43) | type FileListRef = {
  type DisplayMode (line 52) | type DisplayMode = 'list' | 'tree';
  type DisplayItem (line 54) | type DisplayItem = {
  constant SEARCH_RESULT_TTL_MS (line 66) | const SEARCH_RESULT_TTL_MS = 30_000;

FILE: source/ui/components/tools/FileRollbackConfirmation.tsx
  type RollbackMode (line 8) | type RollbackMode = 'conversation' | 'both' | 'files';
  type Props (line 10) | type Props = {
  function FileRollbackConfirmation (line 21) | function FileRollbackConfirmation({

FILE: source/ui/components/tools/ToolConfirmation.tsx
  type ConfirmationResult (line 14) | type ConfirmationResult =
  type ToolCall (line 20) | interface ToolCall {
  type Props (line 29) | interface Props {
  function formatArgumentValue (line 38) | function formatArgumentValue(
  function formatArgumentsAsTree (line 58) | function formatArgumentsAsTree(
  function ToolConfirmation (line 93) | function ToolConfirmation({

FILE: source/ui/components/tools/ToolResultPreview.tsx
  type ToolResultPreviewProps (line 6) | interface ToolResultPreviewProps {
  function removeAnsiCodes (line 16) | function removeAnsiCodes(text: string): string {
  function ToolResultPreview (line 24) | function ToolResultPreview({
  function renderSubAgentPreview (line 79) | function renderSubAgentPreview(data: any, _maxLines: number, theme: Them...
  function renderTerminalExecutePreview (line 96) | function renderTerminalExecutePreview(
  function renderReadPreview (line 300) | function renderReadPreview(
  function renderACEPreview (line 340) | function renderACEPreview(
  function renderCreatePreview (line 475) | function renderCreatePreview(data: any, theme: Theme) {
  function renderEditSearchPreview (line 486) | function renderEditSearchPreview(data: any, theme: Theme) {
  function renderWebSearchPreview (line 509) | function renderWebSearchPreview(data: any, _maxLines: number, theme: The...
  function renderWebFetchPreview (line 530) | function renderWebFetchPreview(data: any, theme: Theme) {
  function renderGenericPreview (line 541) | function renderGenericPreview(data: any, maxLines: number, theme: Theme) {
  function renderTodoPreview (line 571) | function renderTodoPreview(
  function renderIdeDiagnosticsPreview (line 644) | function renderIdeDiagnosticsPreview(data: any, theme: Theme) {

FILE: source/ui/contexts/ThemeContext.tsx
  type ThemeContextType (line 16) | interface ThemeContextType {
  type ThemeProviderProps (line 29) | interface ThemeProviderProps {
  function ThemeProvider (line 33) | function ThemeProvider({children}: ThemeProviderProps) {
  function useTheme (line 88) | function useTheme(): ThemeContextType {

FILE: source/ui/pages/ChatScreen.tsx
  constant MIN_TERMINAL_HEIGHT (line 38) | const MIN_TERMINAL_HEIGHT = 10;
  type Props (line 40) | type Props = {
  function ChatScreen (line 47) | function ChatScreen({

FILE: source/ui/pages/CodeBaseConfigScreen.tsx
  type Props (line 16) | type Props = {
  type ConfigField (line 22) | type ConfigField =
  function CodeBaseConfigScreen (line 88) | function CodeBaseConfigScreen({

FILE: source/ui/pages/ConfigScreen.tsx
  function ConfigScreen (line 23) | function ConfigScreen({

FILE: source/ui/pages/CustomHeadersScreen.tsx
  type Props (line 16) | type Props = {
  type View (line 20) | type View = 'list' | 'add' | 'edit' | 'editHeaders' | 'confirmDelete';
  type ListAction (line 21) | type ListAction =
  function CustomHeadersScreen (line 29) | function CustomHeadersScreen({onBack}: Props) {

FILE: source/ui/pages/CustomThemeScreen.tsx
  type Props (line 18) | type Props = {
  type ColorKey (line 22) | type ColorKey = keyof ThemeColors;
  function CustomThemeScreen (line 55) | function CustomThemeScreen({onBack}: Props) {

FILE: source/ui/pages/ExitScreen.tsx
  type Props (line 16) | type Props = {
  function dotLine (line 20) | function dotLine(width: number): string {
  constant EXIT_IMAGE_PATH (line 25) | const EXIT_IMAGE_PATH = join(homedir(), '.snow', 'exit-image.json');
  constant BLOCK_CHAR (line 26) | const BLOCK_CHAR = '\u2580';
  function ExitScreen (line 28) | function ExitScreen({version = '1.0.0'}: Props) {

FILE: source/ui/pages/HeadlessModeScreen.tsx
  type Props (line 23) | type Props = {
  function renderConsoleMarkdown (line 30) | function renderConsoleMarkdown(content: string): string {
  function parseConsoleMarkdown (line 35) | function parseConsoleMarkdown(content: string): any[] {
  function renderConsoleBlock (line 131) | function renderConsoleBlock(block: any): string {
  function highlightConsoleCode (line 186) | function highlightConsoleCode(code: string, language: string): string {
  function renderInlineFormatting (line 240) | function renderInlineFormatting(text: string): string {
  function askHeadlessConfirmation (line 281) | async function askHeadlessConfirmation(
  function HeadlessModeScreen (line 351) | function HeadlessModeScreen({

FILE: source/ui/pages/HelpScreen.tsx
  type Props (line 9) | type Props = {
  function HelpScreen (line 14) | function HelpScreen({onBackDestination = 'chat'}: Props) {

FILE: source/ui/pages/HooksConfigScreen.tsx
  type Props (line 23) | type Props = {
  type Screen (line 29) | type Screen =
  type RuleField (line 36) | type RuleField = 'description' | 'matcher';
  type ActionField (line 37) | type ActionField = 'enabled' | 'type' | 'command' | 'prompt' | 'timeout';
  function HooksConfigScreen (line 39) | function HooksConfigScreen({

FILE: source/ui/pages/LanguageSettingsScreen.tsx
  type Props (line 9) | type Props = {
  function LanguageSettingsScreen (line 14) | function LanguageSettingsScreen({

FILE: source/ui/pages/MCPConfigScreen.tsx
  type Props (line 18) | type Props = {
  function checkCommandExists (line 23) | function checkCommandExists(command: string): boolean {
  function getSystemEditor (line 53) | function getSystemEditor(): string | null {
  function getConfigFilePath (line 79) | function getConfigFilePath(scope: MCPConfigScope): string {
  function getConfigByScope (line 86) | function getConfigByScope(scope: MCPConfigScope) {
  type I18nMessages (line 90) | interface I18nMessages {
  function openEditorForScope (line 99) | function openEditorForScope(
  function MCPConfigScreen (line 200) | function MCPConfigScreen({onBack}: Props) {

FILE: source/ui/pages/PixelEditorScreen.tsx
  constant DRAW_DIR (line 20) | const DRAW_DIR = join(homedir(), '.snow', 'draw');
  constant EXIT_IMAGE_PATH (line 21) | const EXIT_IMAGE_PATH = join(homedir(), '.snow', 'exit-image.json');
  function ensureDrawDir (line 23) | function ensureDrawDir(): void {
  function sanitizeFileName (line 29) | function sanitizeFileName(name: string): string {
  function cropGrid (line 33) | function cropGrid(grid: PixelGrid): PixelGrid {
  type DrawingFile (line 55) | interface DrawingFile {
  type View (line 61) | type View = 'menu' | 'editor' | 'manager';
  type Props (line 63) | type Props = {
  function PixelEditorScreen (line 67) | function PixelEditorScreen({onBack}: Props) {

FILE: source/ui/pages/ProxyConfigScreen.tsx
  type Props (line 21) | type Props = {
  function ProxyConfigScreen (line 27) | function ProxyConfigScreen({

FILE: source/ui/pages/SensitiveCommandConfigScreen.tsx
  type Props (line 49) | type Props = {
  type ViewMode (line 54) | type ViewMode = 'list' | 'scope-select' | 'add';
  type ScopeSelectPurpose (line 55) | type ScopeSelectPurpose = 'add' | 'reset';
  constant SCOPE_OPTIONS (line 57) | const SCOPE_OPTIONS: SensitiveCommandScope[] = ['project', 'global'];
  function SensitiveCommandConfigScreen (line 59) | function SensitiveCommandConfigScreen({

FILE: source/ui/pages/SubAgentConfigScreen.tsx
  type Props (line 65) | type Props = {
  type ToolCategory (line 72) | type ToolCategory = {
  type FormField (line 77) | type FormField = 'name' | 'description' | 'role' | 'configProfile' | 'to...
  function SubAgentConfigScreen (line 79) | function SubAgentConfigScreen({

FILE: source/ui/pages/SubAgentListScreen.tsx
  type Props (line 14) | type Props = {
  function SubAgentListScreen (line 23) | function SubAgentListScreen({

FILE: source/ui/pages/SystemPromptConfigScreen.tsx
  type Props (line 20) | type Props = {
  type View (line 24) | type View = 'list' | 'add' | 'edit' | 'confirmDelete' | 'editWithEditor';
  type ListAction (line 25) | type ListAction =
  function checkCommandExists (line 33) | function checkCommandExists(command: string): boolean {
  function getSystemEditor (line 65) | function getSystemEditor(): string | null {
  function SystemPromptConfigScreen (line 94) | function SystemPromptConfigScreen({onBack}: Props) {

FILE: source/ui/pages/TaskManagerScreen.tsx
  type Props (line 13) | type Props = {
  function TaskManagerScreen (line 18) | function TaskManagerScreen({onBack, onResumeTask}: Props) {

FILE: source/ui/pages/ThemeSettingsScreen.tsx
  type Props (line 21) | type Props = {
  type Screen (line 26) | type Screen = 'main' | 'custom';
  function ThemeSettingsScreen (line 38) | function ThemeSettingsScreen({

FILE: source/ui/pages/WelcomeScreen.tsx
  constant LOGO_REVEAL_MAX_CHARS (line 56) | const LOGO_REVEAL_MAX_CHARS = 63;
  constant LOGO_REVEAL_INTERVAL_MS (line 58) | const LOGO_REVEAL_INTERVAL_MS = 10;
  type Props (line 60) | type Props = {
  type InlineView (line 67) | type InlineView =
  function WelcomeScreen (line 83) | function WelcomeScreen({

FILE: source/ui/pages/chatScreen/ChatScreenConversationView.tsx
  type Props (line 26) | type Props = {
  function ChatScreenConversationView (line 47) | function ChatScreenConversationView({

FILE: source/ui/pages/chatScreen/ChatScreenPanels.tsx
  type SnapshotState (line 42) | type SnapshotState = {
  type Props (line 53) | type Props = {
  function ChatScreenPanels (line 77) | function ChatScreenPanels({

FILE: source/ui/pages/chatScreen/types.ts
  type PendingMessageInput (line 1) | type PendingMessageInput = {
  type InputImage (line 6) | type InputImage = {
  type RestoreInputContent (line 12) | type RestoreInputContent = {
  type DraftContent (line 17) | type DraftContent = RestoreInputContent;
  type BashSensitiveCommandState (line 19) | type BashSensitiveCommandState = {
  type CustomCommandExecutionState (line 24) | type CustomCommandExecutionState = {
  type PendingUserQuestionResult (line 33) | type PendingUserQuestionResult = {
  type PendingUserQuestionState (line 39) | type PendingUserQuestionState = {
  type CodebaseProgressState (line 46) | type CodebaseProgressState = {
  type FileUpdateNotificationState (line 55) | type FileUpdateNotificationState = {

FILE: source/ui/pages/chatScreen/useBackgroundProcessSelection.ts
  function useBackgroundProcessSelection (line 4) | function useBackgroundProcessSelection(processes: BackgroundProcess[]) {

FILE: source/ui/pages/chatScreen/useChatScreenCommands.ts
  function useChatScreenCommands (line 4) | function useChatScreenCommands(workingDirectory: string) {

FILE: source/ui/pages/chatScreen/useChatScreenInputHandler.ts
  type InputKey (line 15) | type InputKey = {
  type BackgroundProcessesState (line 23) | type BackgroundProcessesState = {
  type Options (line 29) | type Options = {
  function useChatScreenInputHandler (line 47) | function useChatScreenInputHandler({

FILE: source/ui/pages/chatScreen/useChatScreenLocalState.ts
  function useChatScreenLocalState (line 15) | function useChatScreenLocalState() {

FILE: source/ui/pages/chatScreen/useChatScreenModes.ts
  type Options (line 20) | type Options = {
  function useChatScreenModes (line 25) | function useChatScreenModes({enableYolo, enablePlan}: Options) {

FILE: source/ui/pages/chatScreen/useChatScreenSessionLifecycle.ts
  type Options (line 13) | type Options = {
  function useChatScreenSessionLifecycle (line 25) | function useChatScreenSessionLifecycle({

FILE: source/ui/pages/chatScreen/useCodebaseIndexing.ts
  type ProgressData (line 11) | type ProgressData = NonNullable<CodebaseProgressState>;
  function toProgressState (line 13) | function toProgressState(progressData: ProgressData): ProgressData {
  function useCodebaseIndexing (line 24) | function useCodebaseIndexing(workingDirectory: string) {

FILE: source/ui/pages/configScreen/ConfigFieldRenderer.tsx
  type Props (line 9) | type Props = {
  function ConfigFieldRenderer (line 14) | function ConfigFieldRenderer({field, state}: Props) {

FILE: source/ui/pages/configScreen/ConfigSelectPanel.tsx
  type Props (line 9) | type Props = {
  function ConfigSelectPanel (line 13) | function ConfigSelectPanel({state}: Props) {
  function ProfileSelect (line 259) | function ProfileSelect({state}: Props) {
  function SystemPromptSelect (line 360) | function SystemPromptSelect({state}: Props) {
  function ModelSelect (line 445) | function ModelSelect({state}: Props) {
  function ReasoningEffortSelect (line 505) | function ReasoningEffortSelect({state}: Props) {

FILE: source/ui/pages/configScreen/ConfigSubViews.tsx
  type SubViewProps (line 9) | type SubViewProps = {
  type ProfileNameInputViewProps (line 14) | type ProfileNameInputViewProps = SubViewProps & {
  function ProfileNameInputView (line 24) | function ProfileNameInputView({
  function ProfileCreateView (line 79) | function ProfileCreateView({state, inlineMode}: SubViewProps) {
  function ProfileRenameView (line 97) | function ProfileRenameView({state, inlineMode}: SubViewProps) {
  function ProfileDeleteView (line 115) | function ProfileDeleteView({state, inlineMode}: SubViewProps) {
  function LoadingView (line 169) | function LoadingView({state, inlineMode}: SubViewProps) {
  function ManualInputView (line 212) | function ManualInputView({state, inlineMode}: SubViewProps) {

FILE: source/ui/pages/configScreen/types.ts
  type ConfigField (line 3) | type ConfigField =
  type ProfileMode (line 36) | type ProfileMode = 'normal' | 'creating' | 'renaming' | 'deleting';
  type ConfigScreenProps (line 38) | type ConfigScreenProps = {
  constant MAX_VISIBLE_FIELDS (line 49) | const MAX_VISIBLE_FIELDS = 8;
  constant SELECT_FIELDS (line 93) | const SELECT_FIELDS: ConfigField[] = [
  constant NUMERIC_FIELDS (line 112) | const NUMERIC_FIELDS: ConfigField[] = [
  constant TOGGLE_FIELDS (line 121) | const TOGGLE_FIELDS: ConfigField[] = [
  type RequestMethodOption (line 133) | type RequestMethodOption = {

FILE: source/ui/pages/configScreen/useConfigInput.ts
  function useConfigInput (line 9) | function useConfigInput(

FILE: source/ui/pages/configScreen/useConfigState.ts
  type UseConfigStateOptions (line 37) | type UseConfigStateOptions = {
  function useConfigState (line 47) | function useConfigState(options?: UseConfigStateOptions) {
  type ConfigStateReturn (line 991) | type ConfigStateReturn = ReturnType<typeof useConfigState>;

FILE: source/ui/themes/index.ts
  type ThemeType (line 5) | type ThemeType =
  type ThemeColors (line 16) | interface ThemeColors {
  function loadCustomThemeColors (line 68) | function loadCustomThemeColors(): ThemeColors {
  type Theme (line 90) | interface Theme {
  function getCustomTheme (line 387) | function getCustomTheme(): Theme {

FILE: source/utils/acp/acpManager.ts
  constant ACP_PROTOCOL_VERSION (line 57) | const ACP_PROTOCOL_VERSION: ProtocolVersion = 1;
  type AcpSession (line 60) | interface AcpSession {
  type ToolCallStatus (line 70) | type ToolCallStatus = 'pending' | 'running' | 'completed' | 'failed';
  class AcpManager (line 76) | class AcpManager {
    method start (line 83) | async start(input: Readable, output: Writable): Promise<void> {
    method createAgentHandler (line 104) | private createAgentHandler(conn: AgentSideConnection): Agent {
    method handlePrompt (line 286) | private async handlePrompt(
    method sendToolCallUpdate (line 649) | private async sendToolCallUpdate(
    method requestToolPermission (line 675) | private async requestToolPermission(
    method getVersion (line 758) | private getVersion(): string {
    method isConnected (line 771) | isConnected(): boolean {
    method stop (line 778) | async stop(): Promise<void> {

FILE: source/utils/codebase/codebaseDatabase.ts
  function getSqlJs (line 17) | async function getSqlJs(): Promise<any> {
  type CodeChunk (line 39) | interface CodeChunk {
  type IndexProgress (line 54) | interface IndexProgress {
  class CodebaseDatabase (line 69) | class CodebaseDatabase {
    method constructor (line 74) | constructor(projectRoot: string) {
    method initialize (line 86) | async initialize(): Promise<void> {
    method createTables (line 114) | private createTables(): void {
    method save (line 162) | private save(): void {
    method insertChunks (line 171) | insertChunks(chunks: CodeChunk[]): void {
    method deleteChunksByFile (line 204) | deleteChunksByFile(filePath: string): void {
    method getChunksByFile (line 214) | getChunksByFile(filePath: string): CodeChunk[] {
    method hasFileHash (line 231) | hasFileHash(fileHash: string): boolean {
    method getTotalChunks (line 248) | getTotalChunks(): number {
    method searchSimilar (line 261) | searchSimilar(queryEmbedding: number[], limit: number = 10): CodeChunk...
    method searchSimilarInFiles (line 290) | searchSimilarInFiles(
    method updateProgress (line 326) | updateProgress(progress: Partial<IndexProgress>): void {
    method getProgress (line 379) | getProgress(): IndexProgress {
    method setWatcherEnabled (line 410) | setWatcherEnabled(enabled: boolean): void {
    method isWatcherEnabled (line 422) | isWatcherEnabled(): boolean {
    method clear (line 437) | clear(): void {
    method close (line 461) | close(): void {
    method resultsToObjects (line 473) | private resultsToObjects(result: {
    method rowToChunk (line 489) | private rowToChunk(row: any): CodeChunk {
    method cosineSimilarity (line 516) | private cosineSimilarity(a: number[], b: number[]): number {

FILE: source/utils/codebase/codebaseSearchEvents.ts
  type CodebaseSearchEvent (line 3) | type CodebaseSearchEvent = {
  class CodebaseSearchEventEmitter (line 16) | class CodebaseSearchEventEmitter extends EventEmitter {
    method emitSearchEvent (line 17) | emitSearchEvent(event: CodebaseSearchEvent) {
    method onSearchEvent (line 21) | onSearchEvent(callback: (event: CodebaseSearchEvent) => void) {
    method removeSearchEventListener (line 25) | removeSearchEventListener(callback: (event: CodebaseSearchEvent) => vo...

FILE: source/utils/codebase/conversationContext.ts
  function setConversationContext (line 12) | function setConversationContext(
  function getConversationContext (line 24) | function getConversationContext():
  function clearConversationContext (line 36) | function clearConversationContext(): void {

FILE: source/utils/codebase/gitignoreValidator.ts
  function validateGitignore (line 11) | function validateGitignore(workingDirectory: string): {

FILE: source/utils/codebase/hashBasedSnapshot.ts
  type FileBackup (line 11) | interface FileBackup {
  type SnapshotMetadata (line 21) | interface SnapshotMetadata {
  class HashBasedSnapshotManager (line 34) | class HashBasedSnapshotManager {
    method getRollbackPreviewForFile (line 41) | async getRollbackPreviewForFile(
    method constructor (line 155) | constructor() {
    method acquireLock (line 169) | private async acquireLock(filePath: string): Promise<() => void> {
    method ensureSnapshotsDir (line 192) | private async ensureSnapshotsDir(): Promise<void> {
    method getSnapshotPath (line 199) | private getSnapshotPath(sessionId: string, messageIndex: number): stri...
    method backupFile (line 212) | async backupFile(
    method removeFileBackup (line 295) | async removeFileBackup(
    method saveSnapshotMetadata (line 358) | private async saveSnapshotMetadata(
    method listSnapshots (line 373) | async listSnapshots(
    method getFilesToRollback (line 409) | async getFilesToRollback(
    method rollbackToMessageIndex (line 447) | async rollbackToMessageIndex(
    method deleteSnapshotsFromIndex (line 539) | async deleteSnapshotsFromIndex(
    method clearAllSnapshots (line 579) | async clearAllSnapshots(sessionId: string): Promise<void> {

FILE: source/utils/codebase/reindexCodebase.ts
  function reindexCodebase (line 18) | async function reindexCodebase(

FILE: source/utils/commands/autoformat.ts
  function getMessages (line 13) | function getMessages() {

FILE: source/utils/commands/btwStream.ts
  constant BTW_SYSTEM_SUFFIX (line 8) | const BTW_SYSTEM_SUFFIX = `
  function buildContextMessages (line 18) | function buildContextMessages(): ChatMessage[] {

FILE: source/utils/commands/custom.ts
  type CommandLocation (line 12) | type CommandLocation = 'global' | 'project';
  type CustomCommand (line 14) | interface CustomCommand {
  type CommandFileEntry (line 22) | type CommandFileEntry = {
  function isValidSlashCommandName (line 27) | function isValidSlashCommandName(name: string): boolean {
  function parseNamespacedCommandName (line 35) | function parseNamespacedCommandName(name: string): {
  function assertValidNamespacePath (line 54) | function assertValidNamespacePath(namespacePath: string): string[] {
  function getCommandJsonFilePath (line 79) | function getCommandJsonFilePath(commandsDir: string, name: string): stri...
  function listJsonCommandsRecursively (line 94) | async function listJsonCommandsRecursively(
  function loadCustomCommandFromFile (line 153) | async function loadCustomCommandFromFile(
  function loadCommandsFromDir (line 178) | async function loadCommandsFromDir(
  function getCustomCommandsDir (line 205) | function getCustomCommandsDir(
  function ensureCommandsDir (line 218) | async function ensureCommandsDir(
  function loadCustomCommands (line 229) | async function loadCustomCommands(
  function isCommandNameConflict (line 258) | function isCommandNameConflict(name: string): boolean {
  function checkCommandExists (line 264) | function checkCommandExists(
  function saveCustomCommand (line 279) | async function saveCustomCommand(
  function getCustomCommands (line 316) | function getCustomCommands(): CustomCommand[] {
  function deleteCustomCommand (line 325) | async function deleteCustomCommand(
  function registerCustomCommands (line 343) | async function registerCustomCommands(

FILE: source/utils/commands/deepresearch.ts
  constant PROMPT_PREVIEW_MAX (line 12) | const PROMPT_PREVIEW_MAX = 120;
  function truncatePrompt (line 14) | function truncatePrompt(text: string): string {

FILE: source/utils/commands/export.ts
  function getMessages (line 9) | function getMessages() {

FILE: source/utils/commands/loop.ts
  function format (line 13) | function format(template: string, params: Record<string, string>): string {

FILE: source/utils/commands/newPrompt.ts
  function readFileSafe (line 25) | function readFileSafe(filePath: string, maxLen = 8192): string | null {
  function detectTechStack (line 43) | function detectTechStack(cwd: string, rootFileSet: Set<string>): string {
  function gatherProjectContext (line 442) | function gatherProjectContext(): string {

FILE: source/utils/commands/role.ts
  type RoleLocation (line 12) | type RoleLocation = 'global' | 'project';
  type RoleConfig (line 14) | type RoleConfig = {
  constant DEFAULT_ACTIVE_ROLE_ID (line 19) | const DEFAULT_ACTIVE_ROLE_ID = 'active';
  function getRoleConfigPath (line 21) | function getRoleConfigPath(
  function readRoleConfig (line 32) | function readRoleConfig(
  function writeRoleConfig (line 46) | async function writeRoleConfig(
  function resolveActiveRoleId (line 57) | function resolveActiveRoleId(
  function getRoleFilePath (line 79) | function getRoleFilePath(
  function checkRoleExists (line 93) | function checkRoleExists(
  function createRoleFile (line 104) | async function createRoleFile(
  function deleteRoleFile (line 136) | async function deleteRoleFile(
  type RoleItem (line 171) | interface RoleItem {
  function generateRoleHash (line 184) | function generateRoleHash(): string {
  function getRoleDirectory (line 191) | function getRoleDirectory(
  function parseRoleFilename (line 206) | function parseRoleFilename(filename: string): string | null {
  function listRoles (line 214) | function listRoles(
  function switchActiveRole (line 273) | async function switchActiveRole(
  function createInactiveRole (line 299) | async function createInactiveRole(
  function deleteRole (line 332) | async function deleteRole(
  function toggleRoleOverride (line 375) | async function toggleRoleOverride(

FILE: source/utils/commands/roleSubagent.ts
  type RoleSubagentLocation (line 11) | type RoleSubagentLocation = 'global' | 'project';
  type RoleSubagentItem (line 13) | interface RoleSubagentItem {
  function getRoleSubagentDirectory (line 21) | function getRoleSubagentDirectory(
  function buildRoleSubagentFilename (line 31) | function buildRoleSubagentFilename(agentName: string): string {
  function parseRoleSubagentFilename (line 35) | function parseRoleSubagentFilename(filename: string): string | null {
  function getRoleSubagentFilePath (line 40) | function getRoleSubagentFilePath(
  function checkRoleSubagentExists (line 49) | function checkRoleSubagentExists(
  function createRoleSubagentFile (line 57) | async function createRoleSubagentFile(
  function deleteRoleSubagentFile (line 87) | async function deleteRoleSubagentFile(
  function listRoleSubagents (line 114) | function listRoleSubagents(
  function loadSubAgentCustomRole (line 155) | function loadSubAgentCustomRole(
  function getAvailableSubAgents (line 191) | function getAvailableSubAgents(): Array<{

FILE: source/utils/commands/simple.ts
  function applySimpleMode (line 12) | function applySimpleMode(value: boolean): void {
  function getMessages (line 18) | function getMessages() {

FILE: source/utils/commands/skills.ts
  type SkillMetadata (line 20) | interface SkillMetadata {
  type GeneratedSkillContent (line 25) | interface GeneratedSkillContent {
  type GeneratedSkillDraft (line 31) | interface GeneratedSkillDraft {
  type SkillLocation (line 38) | type SkillLocation = 'global' | 'project';
  function validateSkillId (line 41) | function validateSkillId(name: string): {
  function validateSkillName (line 109) | function validateSkillName(name: string): {
  function stripLeadingFrontMatter (line 116) | function stripLeadingFrontMatter(markdown: string): string {
  function sanitizeSkillName (line 125) | function sanitizeSkillName(input: string): string {
  function makeUniqueSkillName (line 133) | function makeUniqueSkillName(baseName: string, projectRoot?: string): st...
  function extractTaggedJson (line 156) | function extractTaggedJson(text: string): string | null {
  function extractTaggedFiles (line 164) | function extractTaggedFiles(text: string): Map<string, string> {
  function buildSkillGenerationSystemPrompt (line 178) | function buildSkillGenerationSystemPrompt(): string {
  function buildSkillGenerationUserPrompt (line 182) | function buildSkillGenerationUserPrompt(requirement: string): string {
  function callModelForText (line 211) | async function callModelForText(
  function generateSkillDraftWithAI (line 302) | async function generateSkillDraftWithAI(
  function generateSkillMarkdownWithFrontMatter (line 370) | function generateSkillMarkdownWithFrontMatter(
  function checkSkillExists (line 386) | function checkSkillExists(
  function getSkillDirectory (line 396) | function getSkillDirectory(
  function generateSkillTemplate (line 412) | function generateSkillTemplate(metadata: SkillMetadata): string {
  function generateReferenceTemplate (line 474) | function generateReferenceTemplate(): string {
  function generateExamplesTemplate (line 499) | function generateExamplesTemplate(): string {
  function createSkillFromGenerated (line 544) | async function createSkillFromGenerated(
  function createSkillTemplate (line 646) | async function createSkillTemplate(

FILE: source/utils/config/apiConfig.ts
  type RequestMethod (line 11) | type RequestMethod = 'chat' | 'responses' | 'gemini' | 'anthropic';
  type ThinkingConfig (line 12) | interface ThinkingConfig {
  type GeminiThinkingLevel (line 18) | type GeminiThinkingLevel = 'minimal' | 'low' | 'medium' | 'high';
  type GeminiThinkingConfig (line 20) | interface GeminiThinkingConfig {
  type ResponsesReasoningConfig (line 25) | interface ResponsesReasoningConfig {
  type ChatReasoningEffort (line 30) | type ChatReasoningEffort = 'low' | 'medium' | 'high' | 'max';
  type ChatThinkingConfig (line 32) | interface ChatThinkingConfig {
  type ApiConfig (line 37) | interface ApiConfig {
  type MCPServer (line 70) | interface MCPServer {
  type MCPConfig (line 82) | interface MCPConfig {
  type AppConfig (line 86) | interface AppConfig {
  type SystemPromptItem (line 93) | interface SystemPromptItem {
  type SystemPromptConfig (line 103) | interface SystemPromptConfig {
  type CustomHeadersItem (line 111) | interface CustomHeadersItem {
  type CustomHeadersConfig (line 121) | interface CustomHeadersConfig {
  constant DEFAULT_STREAM_IDLE_TIMEOUT_SEC (line 126) | const DEFAULT_STREAM_IDLE_TIMEOUT_SEC = 180;
  constant DEFAULT_AUTO_COMPRESS_THRESHOLD (line 127) | const DEFAULT_AUTO_COMPRESS_THRESHOLD = 80;
  constant DEFAULT_TOOL_RESULT_TOKEN_LIMIT_PERCENT (line 128) | const DEFAULT_TOOL_RESULT_TOKEN_LIMIT_PERCENT = 30;
  constant MAX_TOOL_RESULT_TOKEN_LIMIT_PERCENT (line 129) | const MAX_TOOL_RESULT_TOKEN_LIMIT_PERCENT = 80;
  constant MIN_TOOL_RESULT_TOKEN_LIMIT_PERCENT (line 130) | const MIN_TOOL_RESULT_TOKEN_LIMIT_PERCENT = 20;
  function normalizeStreamIdleTimeoutSec (line 131) | function normalizeStreamIdleTimeoutSec(value: unknown): number {
  constant DEFAULT_CONFIG (line 139) | const DEFAULT_CONFIG: AppConfig = {
  constant DEFAULT_MCP_CONFIG (line 154) | const DEFAULT_MCP_CONFIG: MCPConfig = {
  constant CONFIG_DIR (line 158) | const CONFIG_DIR = join(homedir(), '.snow');
  constant PROXY_CONFIG_FILE (line 159) | const PROXY_CONFIG_FILE = join(CONFIG_DIR, 'proxy-config.json');
  constant SYSTEM_PROMPT_FILE (line 161) | const SYSTEM_PROMPT_FILE = join(CONFIG_DIR, 'system-prompt.txt');
  constant SYSTEM_PROMPT_JSON_FILE (line 162) | const SYSTEM_PROMPT_JSON_FILE = join(CONFIG_DIR, 'system-prompt.json');
  constant CUSTOM_HEADERS_FILE (line 163) | const CUSTOM_HEADERS_FILE = join(CONFIG_DIR, 'custom-headers.json');
  constant STATUSLINE_HOOKS_DIR (line 164) | const STATUSLINE_HOOKS_DIR = join(CONFIG_DIR, 'plugin', 'statusline');
  constant SEARCH_ENGINES_DIR (line 165) | const SEARCH_ENGINES_DIR = join(CONFIG_DIR, 'plugin', 'search_engines');
  type MCPConfigScope (line 167) | type MCPConfigScope = 'global' | 'project';
  function getProjectMCPConfigDir (line 169) | function getProjectMCPConfigDir(): string {
  function getProjectMCPConfigFilePath (line 173) | function getProjectMCPConfigFilePath(): string {
  function getGlobalMCPConfigFilePath (line 177) | function getGlobalMCPConfigFilePath(): string {
  function migrateProxyConfigToNewFile (line 184) | function migrateProxyConfigToNewFile(legacyProxy: any): void {
  function normalizeRequestMethod (line 204) | function normalizeRequestMethod(method: unknown): RequestMethod {
  constant CONFIG_FILE (line 221) | const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
  constant MCP_CONFIG_FILE (line 222) | const MCP_CONFIG_FILE = join(CONFIG_DIR, 'mcp-config.json');
  function ensureConfigDirectory (line 224) | function ensureConfigDirectory(): void {
  function cloneDefaultMCPConfig (line 230) | function cloneDefaultMCPConfig(): MCPConfig {
  function loadConfig (line 239) | function loadConfig(): AppConfig {
  function saveConfig (line 323) | function saveConfig(config: AppConfig): void {
  function clearConfigCache (line 339) | function clearConfigCache(): void {
  function reloadConfig (line 346) | function reloadConfig(): AppConfig {
  function updateSnowConfig (line 351) | async function updateSnowConfig(
  function getSnowConfig (line 385) | function getSnowConfig(): ApiConfig {
  function validateApiConfig (line 390) | function validateApiConfig(config: Partial<ApiConfig>): string[] {
  function isValidUrl (line 404) | function isValidUrl(url: string): boolean {
  function updateMCPConfig (line 413) | function updateMCPConfig(
  function getGlobalMCPConfig (line 441) | function getGlobalMCPConfig(): MCPConfig {
  function getProjectMCPConfig (line 461) | function getProjectMCPConfig(): MCPConfig {
  function getMCPConfig (line 479) | function getMCPConfig(): MCPConfig {
  function getMCPServerSource (line 495) | function getMCPServerSource(serviceName: string): MCPConfigScope | null {
  function getMCPConfigByScope (line 506) | function getMCPConfigByScope(scope: MCPConfigScope): MCPConfig {
  function validateMCPConfig (line 510) | function validateMCPConfig(config: Partial<MCPConfig>): string[] {
  function migrateSystemPromptFromTxt (line 590) | function migrateSystemPromptFromTxt(): void {
  function getSystemPromptConfig (line 633) | function getSystemPromptConfig(): SystemPromptConfig | undefined {
  function saveSystemPromptConfig (line 671) | function saveSystemPromptConfig(config: SystemPromptConfig): void {
  function getCustomSystemPrompt (line 692) | function getCustomSystemPrompt(): string[] | undefined {
  function getCustomSystemPromptForConfig (line 696) | function getCustomSystemPromptForConfig(
  function getCustomHeaders (line 738) | function getCustomHeaders(): Record<string, string> {
  function getCustomHeadersForConfig (line 742) | function getCustomHeadersForConfig(
  function saveCustomHeaders (line 777) | function saveCustomHeaders(headers: Record<string, string>): void {
  function getCustomHeadersConfig (line 799) | function getCustomHeadersConfig(): CustomHeadersConfig | null {
  function saveCustomHeadersConfig (line 864) | function saveCustomHeadersConfig(config: CustomHeadersConfig): void {

FILE: source/utils/config/codebaseConfig.ts
  type CodebaseConfig (line 5) | interface CodebaseConfig {
  constant DEFAULT_CONFIG (line 35) | const DEFAULT_CONFIG: CodebaseConfig = {

FILE: source/utils/config/configEvents.ts
  type ConfigChangeEvent (line 3) | type ConfigChangeEvent = {
  class ConfigEventEmitter (line 8) | class ConfigEventEmitter extends EventEmitter {
    method emitConfigChange (line 9) | emitConfigChange(event: ConfigChangeEvent) {
    method onConfigChange (line 13) | onConfigChange(callback: (event: ConfigChangeEvent) => void) {
    method removeConfigChangeListener (line 17) | removeConfigChangeListener(callback: (event: ConfigChangeEvent) => voi...

FILE: source/utils/config/configManager.ts
  constant CONFIG_DIR (line 24) | const CONFIG_DIR = join(homedir(), '.snow');
  constant PROFILES_DIR (line 25) | const PROFILES_DIR = join(CONFIG_DIR, 'profiles');
  constant ACTIVE_PROFILE_FILE (line 26) | const ACTIVE_PROFILE_FILE = join(CONFIG_DIR, 'active-profile.json');
  constant LEGACY_ACTIVE_PROFILE_FILE (line 27) | const LEGACY_ACTIVE_PROFILE_FILE = join(CONFIG_DIR, 'active-profile.txt');
  constant LEGACY_CONFIG_FILE (line 28) | const LEGACY_CONFIG_FILE = join(CONFIG_DIR, 'config.json');
  function clearAllAgentCaches (line 34) | function clearAllAgentCaches(): void {
  type ConfigProfile (line 42) | interface ConfigProfile {
  function ensureProfilesDirectory (line 52) | function ensureProfilesDirectory(): void {
  function getActiveProfileName (line 65) | function getActiveProfileName(): string {
  function setActiveProfileName (line 105) | function setActiveProfileName(profileName: string): void {
  function getProfilePath (line 119) | function getProfilePath(profileName: string): string {
  function migrateLegacyConfig (line 127) | function migrateLegacyConfig(): void {
  function normalizeStreamIdleTimeoutSec (line 156) | function normalizeStreamIdleTimeoutSec(value: unknown): number {
  function loadProfile (line 168) | function loadProfile(profileName: string): AppConfig | undefined {
  function saveProfile (line 203) | function saveProfile(profileName: string, config: AppConfig): void {
  function getAllProfiles (line 219) | function getAllProfiles(): ConfigProfile[] {
  function getProfileDisplayName (line 267) | function getProfileDisplayName(profileName: string): string {
  function switchProfile (line 276) | function switchProfile(profileName: string): void {
  function getNextProfileName (line 327) | function getNextProfileName(): string {
  function createProfile (line 342) | function createProfile(profileName: string, config?: AppConfig): void {
  function deleteProfile (line 368) | function deleteProfile(profileName: string): void {
  function renameProfile (line 397) | function renameProfile(oldName: string, newName: string): void {
  function initializeProfiles (line 445) | function initializeProfiles(): void {

FILE: source/utils/config/disabledBuiltInTools.ts
  constant CONFIG_FILE (line 11) | const CONFIG_FILE = 'disabled-builtin-tools.json';
  constant DEFAULT_DISABLED_SERVICES (line 14) | const DEFAULT_DISABLED_SERVICES: string[] = ['scheduler'];
  function getProjectConfigPath (line 16) | function getProjectConfigPath(): string {
  function getGlobalConfigPath (line 20) | function getGlobalConfigPath(): string {
  function getConfigPath (line 24) | function getConfigPath(): string {
  function getDisabledBuiltInServices (line 32) | function getDisabledBuiltInServices(): string[] {
  function isBuiltInServiceEnabled (line 59) | function isBuiltInServiceEnabled(serviceName: string): boolean {
  function toggleBuiltInService (line 66) | function toggleBuiltInService(serviceName: string): boolean {

FILE: source/utils/config/disabledMCPTools.ts
  constant CONFIG_FILE (line 12) | const CONFIG_FILE = 'disabled-mcp-tools.json';
  constant OPT_IN_CONFIG_FILE (line 13) | const OPT_IN_CONFIG_FILE = 'opt-in-mcp-tools.json';
  type DisabledMCPToolsConfig (line 15) | interface DisabledMCPToolsConfig {
  type OptInMCPConfig (line 19) | interface OptInMCPConfig {
  constant DEFAULT_OPT_IN_DISABLED_KEYS (line 24) | const DEFAULT_OPT_IN_DISABLED_KEYS = new Set<string>(['filesystem:edit']);
  function getProjectConfigPath (line 26) | function getProjectConfigPath(): string {
  function getGlobalConfigPath (line 30) | function getGlobalConfigPath(): string {
  function getProjectOptInPath (line 34) | function getProjectOptInPath(): string {
  function getGlobalOptInPath (line 38) | function getGlobalOptInPath(): string {
  function readOptInEnabled (line 42) | function readOptInEnabled(configPath: string): string[] {
  function writeOptInEnabled (line 54) | function writeOptInEnabled(configPath: string, enabledTools: string[]): ...
  function readConfig (line 66) | function readConfig(configPath: string): string[] {
  function writeConfig (line 78) | function writeConfig(configPath: string, disabledTools: string[]): void {
  function makeToolKey (line 90) | function makeToolKey(serviceName: string, toolName: string): string {
  function isDefaultOptInDisabledKey (line 94) | function isDefaultOptInDisabledKey(key: string): boolean {
  function getOptInEnabledMCPKeysMerged (line 101) | function getOptInEnabledMCPKeysMerged(): string[] {
  function getDisabledMCPTools (line 110) | function getDisabledMCPTools(): string[] {
  function getDisabledMCPToolsByScope (line 119) | function getDisabledMCPToolsByScope(scope: MCPConfigScope): string[] {
  function isMCPToolEnabled (line 128) | function isMCPToolEnabled(
  function toggleMCPTool (line 142) | function toggleMCPTool(
  function isMCPToolDisabledInScope (line 187) | function isMCPToolDisabledInScope(

FILE: source/utils/config/disabledSkills.ts
  constant CONFIG_FILE (line 9) | const CONFIG_FILE = 'disabled-skills.json';
  function getConfigPath (line 11) | function getConfigPath(): string {
  function getDisabledSkills (line 18) | function getDisabledSkills(): string[] {
  function isSkillEnabled (line 34) | function isSkillEnabled(skillId: string): boolean {
  function toggleSkill (line 41) | function toggleSkill(skillId: string): boolean {

FILE: source/utils/config/hooksConfig.ts
  type HookType (line 15) | type HookType =
  type HookActionType (line 28) | type HookActionType = 'command' | 'prompt';
  type HookAction (line 33) | interface HookAction {
  type HookRule (line 44) | interface HookRule {
  type HookConfig (line 53) | interface HookConfig {
  type OnUserMessageContext (line 60) | interface OnUserMessageContext {
  type BeforeToolCallContext (line 66) | interface BeforeToolCallContext {
  type AfterToolCallContext (line 71) | interface AfterToolCallContext {
  type ToolConfirmationContext (line 78) | interface ToolConfirmationContext {
  type OnSubAgentCompleteContext (line 87) | interface OnSubAgentCompleteContext {
  type BeforeCompressContext (line 95) | interface BeforeCompressContext {
  type OnSessionStartContext (line 100) | interface OnSessionStartContext {
  type OnStopContext (line 105) | interface OnStopContext {
  type HookContextMap (line 109) | type HookContextMap = {
  type HookScope (line 123) | type HookScope = 'global' | 'project';
  function getGlobalHooksDir (line 128) | function getGlobalHooksDir(): string {
  function getProjectHooksDir (line 135) | function getProjectHooksDir(): string {
  function getHooksDir (line 142) | function getHooksDir(scope: HookScope): string {
  function ensureHooksDirectory (line 149) | function ensureHooksDirectory(scope: HookScope): void {
  function getHookFilePath (line 159) | function getHookFilePath(hookType: HookType, scope: HookScope): string {
  function loadHookConfig (line 166) | function loadHookConfig(
  function saveHookConfig (line 201) | function saveHookConfig(
  function deleteHookConfig (line 224) | function deleteHookConfig(hookType: HookType, scope: HookScope): void {
  function listConfiguredHooks (line 234) | function listConfiguredHooks(scope: HookScope): HookType[] {
  function getAllHookTypes (line 251) | function getAllHookTypes(): HookType[] {
  function isActionTypeAllowed (line 267) | function isActionTypeAllowed(

FILE: source/utils/config/languageConfig.ts
  type Language (line 5) | type Language = 'en' | 'zh' | 'zh-TW';
  constant CONFIG_DIR (line 7) | const CONFIG_DIR = join(homedir(), '.snow');
  constant LANGUAGE_CONFIG_FILE (line 8) | const LANGUAGE_CONFIG_FILE = join(CONFIG_DIR, 'language.json');
  type LanguageConfig (line 10) | interface LanguageConfig {
  constant DEFAULT_CONFIG (line 14) | const DEFAULT_CONFIG: LanguageConfig = {
  function ensureConfigDirectory (line 18) | function ensureConfigDirectory(): void {
  function loadLanguageConfig (line 27) | function loadLanguageConfig(): LanguageConfig {
  function saveLanguageConfig (line 51) | function saveLanguageConfig(config: LanguageConfig): void {
  function getCurrentLanguage (line 65) | function getCurrentLanguage(): Language {
  function setCurrentLanguage (line 73) | function setCurrentLanguage(language: Language): void {

FILE: source/utils/config/permissionsConfig.ts
  constant SNOW_DIR (line 4) | const SNOW_DIR = '.snow';
  constant PERMISSIONS_FILE (line 5) | const PERMISSIONS_FILE = 'permissions.json';
  type PermissionsConfig (line 7) | interface PermissionsConfig {
  constant DEFAULT_CONFIG (line 11) | const DEFAULT_CONFIG: PermissionsConfig = {
  function getSnowDirPath (line 18) | function getSnowDirPath(workingDirectory: string): string {
  function getPermissionsFilePath (line 25) | function getPermissionsFilePath(workingDirectory: string): string {
  function ensureConfigDirectory (line 32) | function ensureConfigDirectory(workingDirectory: string): void {
  function loadPermissionsConfig (line 42) | function loadPermissionsConfig(
  function savePermissionsConfig (line 69) | function savePermissionsConfig(
  function addToolToPermissions (line 88) | function addToolToPermissions(
  function addMultipleToolsToPermissions (line 102) | function addMultipleToolsToPermissions(
  function removeToolFromPermissions (line 124) | function removeToolFromPermissions(
  function clearAllPermissions (line 140) | function clearAllPermissions(workingDirectory: string): void {
  function getPermissionsConfigFilePath (line 147) | function getPermissionsConfigFilePath(workingDirectory: string): string {

FILE: source/utils/config/projectSettings.ts
  type ProjectSettings (line 5) | interface ProjectSettings {
  constant PROJECT_SNOW_DIR (line 17) | const PROJECT_SNOW_DIR = path.join(process.cwd(), '.snow');
  constant GLOBAL_SNOW_DIR (line 18) | const GLOBAL_SNOW_DIR = path.join(os.homedir(), '.snow');
  constant PROJECT_SETTINGS_FILE (line 19) | const PROJECT_SETTINGS_FILE = path.join(PROJECT_SNOW_DIR, 'settings.json');
  constant GLOBAL_SETTINGS_FILE (line 20) | const GLOBAL_SETTINGS_FILE = path.join(GLOBAL_SNOW_DIR, 'settings.json');
  constant DEFAULT_SUB_AGENT_MAX_SPAWN_DEPTH (line 22) | const DEFAULT_SUB_AGENT_MAX_SPAWN_DEPTH = 1;
  function ensureSnowDir (line 24) | function ensureSnowDir(): void {
  function loadSettings (line 30) | function loadSettings(): ProjectSettings {
  function saveSettings (line 50) | function saveSettings(settings: ProjectSettings): void {
  function normalizeSubAgentMaxSpawnDepth (line 63) | function normalizeSubAgentMaxSpawnDepth(depth: unknown): number {
  function getToolSearchEnabled (line 72) | function getToolSearchEnabled(): boolean {
  function setToolSearchEnabled (line 77) | function setToolSearchEnabled(enabled: boolean): void {
  function getAutoFormatEnabled (line 83) | function getAutoFormatEnabled(): boolean {
  function setAutoFormatEnabled (line 88) | function setAutoFormatEnabled(enabled: boolean): void {
  function getSubAgentMaxSpawnDepth (line 94) | function getSubAgentMaxSpawnDepth(): number {
  function setSubAgentMaxSpawnDepth (line 99) | function setSubAgentMaxSpawnDepth(depth: number): number {
  function getFileListDisplayMode (line 107) | function getFileListDisplayMode(): 'list' | 'tree' {
  function setFileListDisplayMode (line 112) | function setFileListDisplayMode(mode: 'list' | 'tree'): void {
  function getYoloMode (line 118) | function getYoloMode(): boolean {
  function setYoloMode (line 123) | function setYoloMode(enabled: boolean): void {
  function getPlanMode (line 129) | function getPlanMode(): boolean {
  function setPlanMode (line 134) | function setPlanMode(enabled: boolean): void {
  function getVulnerabilityHuntingMode (line 140) | function getVulnerabilityHuntingMode(): boolean {
  function setVulnerabilityHuntingMode (line 145) | function setVulnerabilityHuntingMode(enabled: boolean): void {
  function getHybridCompressEnabled (line 151) | function getHybridCompressEnabled(): boolean {
  function setHybridCompressEnabled (line 156) | function setHybridCompressEnabled(enabled: boolean): void {
  function getTeamMode (line 162) | function getTeamMode(): boolean {
  function setTeamMode (line 167) | function setTeamMode(enabled: boolean): void {

FILE: source/utils/config/proxyConfig.ts
  type SearchEngineId (line 13) | type SearchEngineId = string;
  type ProxyConfig (line 15) | interface ProxyConfig {
  constant DEFAULT_PROXY_CONFIG (line 27) | const DEFAULT_PROXY_CONFIG: ProxyConfig = {
  constant CONFIG_DIR (line 34) | const CONFIG_DIR = join(homedir(), '.snow');
  constant PROXY_CONFIG_FILE (line 35) | const PROXY_CONFIG_FILE = join(CONFIG_DIR, 'proxy-config.json');
  function ensureConfigDirectory (line 37) | function ensureConfigDirectory(): void {
  function loadProxyConfig (line 46) | function loadProxyConfig(): ProxyConfig {
  function saveProxyConfig (line 73) | function saveProxyConfig(config: ProxyConfig): void {
  function getProxyConfig (line 87) | function getProxyConfig(): ProxyConfig {
  function updateProxyConfig (line 94) | async function updateProxyConfig(

FILE: source/utils/config/subAgentConfig.ts
  type SubAgent (line 6) | interface SubAgent {
  type SubAgentsConfig (line 21) | interface SubAgentsConfig {
  constant CONFIG_DIR (line 25) | const CONFIG_DIR = join(homedir(), '.snow');
  constant SUB_AGENTS_CONFIG_FILE (line 26) | const SUB_AGENTS_CONFIG_FILE = join(CONFIG_DIR, 'sub-agents.json');
  function getBuiltinAgents (line 32) | function getBuiltinAgents(): SubAgent[] {
  function ensureConfigDirectory (line 41) | function ensureConfigDirectory(): void {
  function generateId (line 47) | function generateId(): string {
  function getUserSubAgents (line 54) | function getUserSubAgents(): SubAgent[] {
  function getSubAgents (line 75) | function getSubAgents(): SubAgent[] {
  function getSubAgent (line 93) | function getSubAgent(id: string): SubAgent | null {
  function saveSubAgents (line 101) | function saveSubAgents(agents: SubAgent[]): void {
  function createSubAgent (line 117) | function createSubAgent(
  function updateSubAgent (line 154) | function updateSubAgent(
  function deleteSubAgent (line 263) | function deleteSubAgent(id: string): boolean {
  function validateSubAgent (line 278) | function validateSubAgent(data: {

FILE: source/utils/config/themeConfig.ts
  constant CONFIG_DIR (line 6) | const CONFIG_DIR = join(homedir(), '.snow');
  constant THEME_CONFIG_FILE (line 7) | const THEME_CONFIG_FILE = join(CONFIG_DIR, 'theme.json');
  type ThemeConfig (line 9) | interface ThemeConfig {
  constant DEFAULT_CONFIG (line 15) | const DEFAULT_CONFIG: ThemeConfig = {
  function ensureConfigDirectory (line 21) | function ensureConfigDirectory(): void {
  function loadThemeConfig (line 30) | function loadThemeConfig(): ThemeConfig {
  function saveThemeConfig (line 54) | function saveThemeConfig(config: ThemeConfig): void {
  function getCurrentTheme (line 68) | function getCurrentTheme(): ThemeType {
  function setCurrentTheme (line 76) | function setCurrentTheme(theme: ThemeType): void {
  function getCustomColors (line 84) | function getCustomColors(): ThemeColors | undefined {
  function saveCustomColors (line 92) | function saveCustomColors(colors: ThemeColors): void {
  function getSimpleMode (line 100) | function getSimpleMode(): boolean {
  function setSimpleMode (line 108) | function setSimpleMode(simpleMode: boolean): void {
  function getDiffOpacity (line 116) | function getDiffOpacity(): number {
  function setDiffOpacity (line 124) | function setDiffOpacity(diffOpacity: number): void {

FILE: source/utils/config/toolDisplayConfig.ts
  constant TWO_STEP_TOOLS (line 10) | const TWO_STEP_TOOLS = new Set([
  constant TWO_STEP_DISPLAY_TOOL_NAMES (line 37) | const TWO_STEP_DISPLAY_TOOL_NAMES: readonly string[] =
  function isToolNeedTwoStepDisplay (line 45) | function isToolNeedTwoStepDisplay(toolName: string): boolean {
  function isToolOnlyShowCompleted (line 64) | function isToolOnlyShowCompleted(toolName: string): boolean {
  function extractFilesystemEditDiffDataForPersistence (line 72) | function extractFilesystemEditDiffDataForPersistence(

FILE: source/utils/config/workingDirConfig.ts
  constant SNOW_DIR (line 6) | const SNOW_DIR = '.snow';
  constant WORKING_DIR_FILE (line 7) | const WORKING_DIR_FILE = 'working-dirs.json';
  type SSHConfig (line 9) | interface SSHConfig {
  type WorkingDirectory (line 22) | interface WorkingDirectory {
  type WorkingDirConfig (line 33) | interface WorkingDirConfig {
  function getSnowDirPath (line 40) | function getSnowDirPath(): string {
  function getConfigFilePath (line 47) | function getConfigFilePath(): string {
  function ensureSnowDir (line 54) | async function ensureSnowDir(): Promise<void> {
  function loadWorkingDirConfig (line 67) | async function loadWorkingDirConfig(): Promise<WorkingDirConfig> {
  function saveWorkingDirConfig (line 95) | async function saveWorkingDirConfig(
  function addWorkingDirectory (line 112) | async function addWorkingDirectory(dirPath: string): Promise<boolean> {
  function removeWorkingDirectories (line 146) | async function removeWorkingDirectories(paths: string[]): Promise<void> {
  function getWorkingDirectories (line 160) | async function getWorkingDirectories(): Promise<WorkingDirectory[]> {
  function addSSHWorkingDirectory (line 168) | async function addSSHWorkingDirectory(

FILE: source/utils/connection/ConnectionManager.ts
  class ConnectionManager (line 27) | class ConnectionManager {
    method constructor (line 42) | constructor() {
    method setStreamingState (line 52) | setStreamingState(state: 'idle' | 'streaming' | 'stopping'): void {
    method onStatusChange (line 57) | onStatusChange(callback: StatusChangeCallback): () => void {
    method onMessage (line 62) | onMessage(type: string, callback: MessageCallback): () => void {
    method login (line 67) | async login(
    method connect (line 103) | async connect(): Promise<{success: boolean; message: string}> {
    method setupSignalRHandlers (line 213) | private setupSignalRHandlers(): void {
    method registerInstance (line 457) | private async registerInstance(): Promise<void> {
    method startHeartbeat (line 481) | private startHeartbeat(): void {
    method stopHeartbeat (line 500) | private stopHeartbeat(): void {
    method setupMessageListener (line 508) | private async setupMessageListener(): Promise<void> {
    method cleanupMessageListener (line 518) | private cleanupMessageListener(): void {
    method pushContextInfo (line 526) | private async pushContextInfo(): Promise<void> {
    method disconnect (line 540) | async disconnect(): Promise<{success: boolean; message: string}> {
    method saveConnectionConfig (line 571) | async saveConnectionConfig(config: ConnectionConfig): Promise<void> {
    method loadConnectionConfig (line 576) | loadConnectionConfig(): ConnectionConfig | null {
    method hasSavedConnection (line 581) | hasSavedConnection(): boolean {
    method clearSavedConnection (line 586) | clearSavedConnection(): void {
    method getState (line 591) | getState(): ConnectionState {
    method getInFlightState (line 595) | getInFlightState(): InFlightState {
    method isConnected (line 600) | isConnected(): boolean {
    method sendMessage (line 605) | async sendMessage(method: string, ...args: unknown[]): Promise<void> {
    method notifyToolConfirmationNeeded (line 614) | async notifyToolConfirmationNeeded(
    method notifyUserInteractionNeeded (line 629) | async notifyUserInteractionNeeded(
    method notifyRollbackConfirmationNeeded (line 644) | async notifyRollbackConfirmationNeeded(payload: {
    method sendToolConfirmationResult (line 653) | async sendToolConfirmationResult(
    method sendUserQuestionResult (line 666) | async sendUserQuestionResult(
    method notifyMessageProcessingCompleted (line 681) | async notifyMessageProcessingCompleted(): Promise<void> {
    method notifyCompactStarted (line 686) | async notifyCompactStarted(): Promise<void> {
    method notifyCompactCompleted (line 698) | async notifyCompactCompleted(result: {

FILE: source/utils/connection/configStore.ts
  class ConfigStore (line 5) | class ConfigStore {
    method constructor (line 9) | constructor() {
    method ensureSnowDir (line 15) | private ensureSnowDir(): void {
    method save (line 22) | async save(config: ConnectionConfig): Promise<void> {
    method load (line 33) | load(): ConnectionConfig | null {
    method hasSavedConfig (line 47) | hasSavedConfig(): boolean {
    method clear (line 56) | clear(): void {

FILE: source/utils/connection/contextManager.ts
  function updateGlobalTokenUsage (line 10) | function updateGlobalTokenUsage(usage: TokenUsageInfo | null): void {
  function getGlobalTokenUsage (line 17) | function getGlobalTokenUsage(): TokenUsageInfo | null {
  class ContextManager (line 21) | class ContextManager {
    method constructor (line 33) | constructor(stateManager: StateManager) {
    method truncateText (line 38) | private truncateText(text: string, maxLength: number): string {
    method shouldTruncateTool (line 48) | private shouldTruncateTool(
    method getContextInfo (line 59) | async getContextInfo(): Promise<string> {
    method setupMessageListener (line 168) | setupMessageListener(

FILE: source/utils/connection/instanceLock.ts
  class InstanceLockManager (line 4) | class InstanceLockManager {
    method constructor (line 7) | constructor() {
    method ensureLocksDir (line 12) | ensureLocksDir(): void {
    method getLockPath (line 19) | private getLockPath(instanceId: string): string {
    method isLocked (line 24) | isLocked(instanceId: string): boolean {
    method lock (line 55) | lock(instanceId: string): boolean {
    method unlock (line 78) | unlock(instanceId: string): void {

FILE: source/utils/connection/interactionManager.ts
  class InteractionManager (line 4) | class InteractionManager {
    method constructor (line 8) | constructor(stateManager: StateManager) {
    method setConnection (line 13) | setConnection(connection: signalR.HubConnection | null): void {
    method isConnected (line 18) | private isConnected(): boolean {
    method notifyToolConfirmationNeeded (line 23) | async notifyToolConfirmationNeeded(
    method notifyUserInteractionNeeded (line 53) | async notifyUserInteractionNeeded(
    method notifyRollbackConfirmationNeeded (line 84) | async notifyRollbackConfirmationNeeded(payload: {
    method sendToolConfirmationResult (line 110) | async sendToolConfirmationResult(
    method sendUserQuestionResult (line 134) | async sendUserQuestionResult(
    method notifyMessageProcessingCompleted (line 160) | async notifyMessageProcessingCompleted(): Promise<void> {

FILE: source/utils/connection/projectData.ts
  type SessionListItem (line 4) | interface SessionListItem {
  type SessionListResult (line 11) | interface SessionListResult {
  class ProjectDataManager (line 17) | class ProjectDataManager {
    method getFileList (line 19) | async getFileList(): Promise<string[]> {
    method getSessionList (line 70) | async getSessionList(

FILE: source/utils/connection/stateManager.ts
  class StateManager (line 11) | class StateManager {
    method onStatusChange (line 26) | onStatusChange(callback: StatusChangeCallback): () => void {
    method onMessage (line 39) | onMessage(type: string, callback: MessageCallback): () => void {
    method updateState (line 56) | updateState(newState: Partial<ConnectionState>): void {
    method notifyMessage (line 62) | notifyMessage(type: string, message: unknown): void {
    method getState (line 70) | getState(): ConnectionState {
    method isConnected (line 75) | isConnected(): boolean {
    method setStreamingState (line 80) | setStreamingState(state: 'idle' | 'streaming' | 'stopping'): void {
    method getStreamingState (line 85) | getStreamingState(): 'idle' | 'streaming' | 'stopping' {
    method hasPendingInteractions (line 90) | hasPendingInteractions(): boolean {
    method clearInFlightInteractions (line 99) | clearInFlightInteractions(): void {
    method addPendingToolConfirmation (line 106) | addPendingToolConfirmation(confirmation: PendingToolConfirmation): void {
    method removePendingToolConfirmation (line 111) | removePendingToolConfirmation(toolCallId: string): boolean {
    method addPendingQuestion (line 116) | addPendingQuestion(question: PendingQuestion): void {
    method removePendingQuestion (line 121) | removePendingQuestion(toolCallId: string): boolean {
    method setPendingRollbackConfirmation (line 126) | setPendingRollbackConfirmation(
    method getInFlightState (line 133) | getInFlightState(): InFlightState {
    method getPendingToolConfirmation (line 153) | getPendingToolConfirmation(
    method getPendingQuestion (line 159) | getPendingQuestion(toolCallId: string): PendingQuestion | undefined {
    method getPendingRollbackConfirmation (line 163) | getPendingRollbackConfirmation(): PendingRollbackConfirmation | null {

FILE: source/utils/connection/types.ts
  type ConnectionStatus (line 3) | type ConnectionStatus =
  type ConnectionConfig (line 9) | interface ConnectionConfig {
  type ConnectionState (line 17) | interface ConnectionState {
  type StatusChangeCallback (line 25) | type StatusChangeCallback = (state: ConnectionState) => void;
  type MessageCallback (line 26) | type MessageCallback = (message: unknown) => void;
  type PendingToolConfirmation (line 29) | interface PendingToolConfirmation {
  type PendingQuestion (line 35) | interface PendingQuestion {
  type PendingRollbackConfirmation (line 42) | interface PendingRollbackConfirmation {
  type InFlightState (line 47) | interface InFlightState {
  type SignalRMessageHandlers (line 55) | interface SignalRMessageHandlers {
  type ContextInfoMessage (line 93) | interface ContextInfoMessage {
  type TokenUsageInfo (line 108) | interface TokenUsageInfo {
  type ContextInfo (line 119) | interface ContextInfo {

FILE: source/utils/core/autoCompress.ts
  constant COMPRESSION_MAX_RETRIES (line 4) | const COMPRESSION_MAX_RETRIES = 3;
  constant COMPRESSION_RETRY_BASE_DELAY (line 5) | const COMPRESSION_RETRY_BASE_DELAY = 1000;
  constant COMPRESSION_ERROR_DISMISS_MS (line 6) | const COMPRESSION_ERROR_DISMISS_MS = 5000;
  function shouldAutoCompress (line 14) | function shouldAutoCompress(
  function performAutoCompression (line 27) | async function performAutoCompression(

FILE: source/utils/core/clipboard.ts
  function runClipboardCommand (line 3) | function runClipboardCommand(
  function sleep (line 20) | function sleep(milliseconds: number): void {
  function getClipboardErrorMessage (line 27) | function getClipboardErrorMessage(error: Error): string {
  function isClipboardToolMissing (line 44) | function isClipboardToolMissing(errorMsg: string): boolean {
  function isClipboardPermissionError (line 53) | function isClipboardPermissionError(errorMsg: string): boolean {
  function shouldRetryWindowsClipboard (line 63) | function shouldRetryWindowsClipboard(errorMsg: string): boolean {
  function copyToWindowsClipboard (line 75) | function copyToWindowsClipboard(content: string): void {
  function copyToClipboard (line 168) | async function copyToClipboard(content: string): Promise<void> {

FILE: source/utils/core/compressionCoordinator.ts
  type Waiter (line 14) | type Waiter = {
  class CompressionCoordinator (line 19) | class CompressionCoordinator {
    method acquireLock (line 27) | async acquireLock(id: string): Promise<void> {
    method releaseLock (line 36) | releaseLock(id: string): void {
    method isCompressing (line 44) | isCompressing(excludeId?: string): boolean {
    method waitUntilFree (line 56) | waitUntilFree(excludeId?: string): Promise<void> {
    method withLock (line 66) | async withLock<T>(id: string, fn: () => Promise<T>): Promise<T> {
    method _drainWaiters (line 75) | private _drainWaiters(): void {

FILE: source/utils/core/contextCompressor.ts
  function cleanThinkingContent (line 13) | function cleanThinkingContent(content: string): string {
  type CompressionResult (line 17) | interface CompressionResult {
  constant COMPRESSION_PROMPT (line 40) | const COMPRESSION_PROMPT = `**TASK: Create a comprehensive handover docu...
  function findPreserveStartIndex (line 107) | function findPreserveStartIndex(messages: ChatMessage[]): number {
  function cleanOrphanedToolCalls (line 164) | function cleanOrphanedToolCalls(messages: ChatMessage[]): void {
  function formatMessageForTranscript (line 315) | function formatMessageForTranscript(msg: ChatMessage): string | null {
  function prepareMessagesForCompression (line 375) | function prepareMessagesForCompression(
  function compressWithChatCompletions (line 426) | async function compressWithChatCompletions(
  function compressWithResponses (line 473) | async fu
Condensed preview — 606 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,442K chars).
[
  {
    "path": ".editorconfig",
    "chars": 175,
    "preview": "root = true\n\n[*]\nindent_style = tab\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newlin"
  },
  {
    "path": ".gitattributes",
    "chars": 19,
    "preview": "* text=auto eol=lf\n"
  },
  {
    "path": ".github/workflows/build_jetbrains.yml",
    "chars": 3339,
    "preview": "name: Build JetBrains Plugin\n\non:\n  push:\n    paths:\n      - '.github/workflows/build_jetbrains.yml'\n      - 'JetBrains/"
  },
  {
    "path": ".github/workflows/build_vsix.yml",
    "chars": 2750,
    "preview": "name: Build VSIX Package\n\non:\n  push:\n    paths:\n      - '.github/workflows/build_vsix.yml'\n      - 'VSIX/**'\n      - 'V"
  },
  {
    "path": ".github/workflows/publish.yml",
    "chars": 1677,
    "preview": "name: Publish to NPM\n\non:\n  push:\n    tags:\n      - 'v*'\n  workflow_dispatch:\n    inputs:\n      version:\n        descrip"
  },
  {
    "path": ".gitignore",
    "chars": 96,
    "preview": "node_modules\ndist\nbundle\nout\n.snow\nAGENTS.md\npr.md\nCHANGELOG.md\nCONTEXT.md\nROLE*.md\n.venv\n.idea\n"
  },
  {
    "path": ".npmrc",
    "chars": 347,
    "preview": "# 保持对等依赖兼容性\nlegacy-peer-deps=true\n\n# 安装速度优化配置\n# 使用 npm 镜像源(中国大陆用户)\nregistry=https://registry.npmmirror.com\n\n# 并行安装配置\nfet"
  },
  {
    "path": ".npmrc.ci",
    "chars": 323,
    "preview": "# CI 环境专用配置\n# 必须使用官方 npm registry 才能发布\n\n# 保持对等依赖兼容性\nlegacy-peer-deps=true\n\n# 使用官方 npm registry\nregistry=https://registry"
  },
  {
    "path": ".prettierignore",
    "chars": 5,
    "preview": "dist\n"
  },
  {
    "path": ".vscode/launch.json",
    "chars": 1208,
    "preview": "{\n\t\"version\": \"0.2.0\",\n\t\"configurations\": [\n\t\t{\n\t\t\t\"name\": \"Debug CLI (ts-node)\",\n\t\t\t\"type\": \"node\",\n\t\t\t\"request\": \"laun"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 2,
    "preview": "{}"
  },
  {
    "path": ".vscode/tasks.json",
    "chars": 580,
    "preview": "{\n\t\"version\": \"2.0.0\",\n\t\"tasks\": [\n\t\t{\n\t\t\t\"label\": \"npm: build\",\n\t\t\t\"type\": \"npm\",\n\t\t\t\"script\": \"build\",\n\t\t\t\"group\": \"bu"
  },
  {
    "path": "JetBrains/.gitignore",
    "chars": 269,
    "preview": "# Gradle\n.gradle/\nbuild/\n!gradle/\n!gradle/wrapper/\n!gradle/wrapper/gradle-wrapper.jar\n!gradle/wrapper/gradle-wrapper.pro"
  },
  {
    "path": "JetBrains/README.md",
    "chars": 1454,
    "preview": "# Snow CLI JetBrains Plugin\n\nJetBrains IDE plugin for integrating with Snow AI CLI. Provides intelligent code navigation"
  },
  {
    "path": "JetBrains/build.gradle.kts",
    "chars": 1415,
    "preview": "plugins {\n    id(\"java\")\n    id(\"org.jetbrains.kotlin.jvm\") version \"1.9.21\"\n    id(\"org.jetbrains.intellij\") version \"1"
  },
  {
    "path": "JetBrains/gradle/wrapper/gradle-wrapper.properties",
    "chars": 250,
    "preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
  },
  {
    "path": "JetBrains/gradle.properties",
    "chars": 1523,
    "preview": "# IntelliJ Platform Artifacts Repositories -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html\n\nplugi"
  },
  {
    "path": "JetBrains/gradlew",
    "chars": 8543,
    "preview": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "JetBrains/gradlew.bat",
    "chars": 2509,
    "preview": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \""
  },
  {
    "path": "JetBrains/settings.gradle.kts",
    "chars": 40,
    "preview": "rootProject.name = \"snow-cli-jetbrains\"\n"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/SnowCodeNavigator.kt",
    "chars": 6872,
    "preview": "package com.snow.plugin\n\nimport com.intellij.openapi.editor.LogicalPosition\nimport com.intellij.openapi.project.Project\n"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/SnowEditorContextTracker.kt",
    "chars": 5424,
    "preview": "package com.snow.plugin\n\nimport com.intellij.openapi.application.ApplicationManager\nimport com.intellij.openapi.diagnost"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/SnowMessageHandler.kt",
    "chars": 18012,
    "preview": "package com.snow.plugin\n\nimport com.intellij.codeInsight.daemon.impl.HighlightInfo\nimport com.intellij.codeInsight.daemo"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/SnowPluginLifecycle.kt",
    "chars": 2133,
    "preview": "package com.snow.plugin\n\nimport com.intellij.ide.AppLifecycleListener\nimport com.intellij.openapi.application.Applicatio"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/SnowProjectActivity.kt",
    "chars": 1091,
    "preview": "package com.snow.plugin\n\nimport com.intellij.openapi.actionSystem.ActionManager\nimport com.intellij.openapi.actionSystem"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/SnowWebSocketManager.kt",
    "chars": 14866,
    "preview": "package com.snow.plugin\n\nimport com.intellij.openapi.application.ApplicationManager\nimport com.intellij.openapi.diagnost"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/actions/GenerateCommitMessageAction.kt",
    "chars": 2908,
    "preview": "package com.snow.plugin.actions\n\nimport com.intellij.openapi.actionSystem.ActionUpdateThread\nimport com.intellij.openapi"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/actions/OpenSnowTerminalAction.kt",
    "chars": 971,
    "preview": "package com.snow.plugin.actions\n\nimport com.intellij.openapi.actionSystem.AnAction\nimport com.intellij.openapi.actionSys"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/actions/SendToSnowCLIAction.kt",
    "chars": 1907,
    "preview": "package com.snow.plugin.actions\n\nimport com.intellij.openapi.actionSystem.ActionUpdateThread\nimport com.intellij.openapi"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/actions/TestNotificationAction.kt",
    "chars": 1195,
    "preview": "package com.snow.plugin.actions\n\nimport com.intellij.notification.Notification\nimport com.intellij.notification.Notifica"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/commit/SnowCommitMessageGenerationService.kt",
    "chars": 22100,
    "preview": "package com.snow.plugin.commit\n\nimport com.intellij.notification.NotificationGroupManager\nimport com.intellij.notificati"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/toolwindow/SnowToolWindowFactory.kt",
    "chars": 2859,
    "preview": "package com.snow.plugin.toolwindow\n\nimport com.intellij.openapi.application.ApplicationManager\nimport com.intellij.opena"
  },
  {
    "path": "JetBrains/src/main/kotlin/com/snow/plugin/util/TerminalCompat.kt",
    "chars": 7073,
    "preview": "package com.snow.plugin.util\n\nimport com.intellij.openapi.application.ApplicationManager\nimport com.intellij.openapi.pro"
  },
  {
    "path": "JetBrains/src/main/kotlin/icons/SnowPluginIcons.kt",
    "chars": 2100,
    "preview": "package icons\n\nimport com.intellij.icons.AllIcons\nimport com.intellij.openapi.util.IconLoader\nimport java.awt.Component\n"
  },
  {
    "path": "JetBrains/src/main/resources/META-INF/plugin.xml",
    "chars": 3837,
    "preview": "<!-- Plugin Configuration File. Read more: https://plugins.jetbrains.com/docs/intellij/plugin-configuration-file.html --"
  },
  {
    "path": "LICENSE",
    "chars": 6851,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 8730,
    "preview": "<div align=\"center\">\n\n<img src=\"docs/images/logo.png\" alt=\"Snow AI CLI Logo\" width=\"200\"/>\n\n# snow-ai\n\n[![npm version](h"
  },
  {
    "path": "README_zh.md",
    "chars": 5543,
    "preview": "<div align=\"center\">\n\n<img src=\"docs/images/logo.png\" alt=\"Snow AI CLI Logo\" width=\"200\"/>\n\n# snow-ai\n\n[![npm version](h"
  },
  {
    "path": "VSIX/.vscodeignore",
    "chars": 739,
    "preview": ".vscode/**\n.vscode-test/**\n.tmp-vsix-check/**\nsrc/**\nout/**\nnode_modules/**\n!node_modules/node-pty/**\n!node_modules/node"
  },
  {
    "path": "VSIX/LICENSE",
    "chars": 1065,
    "preview": "MIT License\n\nCopyright (c) 2025 Snow CLI\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
  },
  {
    "path": "VSIX/README.md",
    "chars": 3331,
    "preview": "# Snow CLI Extension with ACE Code Search\n\nThis extension provides seamless integration between VSCode and Snow AI CLI, "
  },
  {
    "path": "VSIX/package.json",
    "chars": 9631,
    "preview": "{\n\t\"name\": \"snow-cli\",\n\t\"displayName\": \"Snow CLI\",\n\t\"description\": \"Snow AI CLI with ACE Code Search - Intelligent code "
  },
  {
    "path": "VSIX/res/sidebarTerminal.css",
    "chars": 6155,
    "preview": ":root {\n\t--terminal-bg: #181818;\n\t--terminal-drag-outline: #007acc;\n\t--terminal-error: #f14c4c;\n\t--terminal-border: var("
  },
  {
    "path": "VSIX/res/sidebarTerminal.js",
    "chars": 52276,
    "preview": "(function () {\n\tconst vscode = acquireVsCodeApi();\n\n\tconst normalizeLogMessage = value => {\n\t\tif (typeof value === 'stri"
  },
  {
    "path": "VSIX/src/aceHandlers.ts",
    "chars": 4393,
    "preview": "import * as vscode from 'vscode';\n\n/**\n * ACE Code Search Handlers\n * Provides Go to Definition, Find References, Get Sy"
  },
  {
    "path": "VSIX/src/commitMessageGenerator.ts",
    "chars": 17048,
    "preview": "import * as vscode from 'vscode';\nimport {execFile} from 'child_process';\nimport {existsSync, readFileSync} from 'fs';\ni"
  },
  {
    "path": "VSIX/src/diffHandlers.ts",
    "chars": 8943,
    "preview": "import * as vscode from 'vscode';\n\n/**\n * Diff Handlers\n * Provides showDiff, closeDiff, and showGitDiff functionality\n "
  },
  {
    "path": "VSIX/src/extension.ts",
    "chars": 11557,
    "preview": "import * as vscode from 'vscode';\nimport {\n\tstartWebSocketServer,\n\tstopWebSocketServer,\n\tsendEditorContext,\n} from './we"
  },
  {
    "path": "VSIX/src/gitBlameProvider.ts",
    "chars": 10126,
    "preview": "import * as vscode from 'vscode';\nimport {execFile, type ChildProcess} from 'child_process';\nimport * as path from 'path"
  },
  {
    "path": "VSIX/src/ptyManager.ts",
    "chars": 7480,
    "preview": "import * as os from 'os';\nimport * as path from 'path';\nimport * as vscode from 'vscode';\nimport {getSnowTerminalProxyEn"
  },
  {
    "path": "VSIX/src/sidebarTerminalProvider.ts",
    "chars": 44529,
    "preview": "import * as vscode from 'vscode';\nimport {resolveShellProfile} from './ptyManager';\nimport {\n\tSidebarTerminalSession,\n\tS"
  },
  {
    "path": "VSIX/src/sidebarTerminalSession.ts",
    "chars": 4411,
    "preview": "import {PtyManager, ResolvedShell, ShellFamily} from './ptyManager';\n\nexport type SidebarTerminalSize = {cols: number; r"
  },
  {
    "path": "VSIX/src/startupCommandManager.ts",
    "chars": 1084,
    "preview": "const DEFAULT_STARTUP_COMMAND = 'snow';\n\nfunction normalizeStartupCommand(command: string): string | undefined {\n\tconst "
  },
  {
    "path": "VSIX/src/terminalPathFormatter.ts",
    "chars": 851,
    "preview": "import {ShellFamily} from './ptyManager';\n\ntype TerminalPathFormatOptions = {\n\tshellFamily?: ShellFamily;\n\tplatform?: No"
  },
  {
    "path": "VSIX/src/terminalProxy.ts",
    "chars": 1234,
    "preview": "import * as vscode from 'vscode';\n\nexport type TerminalProxyEnv = Record<string, string>;\n\nfunction asOptionalNonEmptySt"
  },
  {
    "path": "VSIX/src/webSocketServer.ts",
    "chars": 9889,
    "preview": "import * as vscode from 'vscode';\nimport {WebSocketServer, WebSocket} from 'ws';\nimport {\n\thandleGoToDefinition,\n\thandle"
  },
  {
    "path": "VSIX/tsconfig.json",
    "chars": 383,
    "preview": "{\n\t\"compilerOptions\": {\n\t\t\"module\": \"commonjs\",\n\t\t\"target\": \"ES2020\",\n\t\t\"outDir\": \"dist\",\n\t\t\"lib\": [\"ES2020\"],\n\t\t\"source"
  },
  {
    "path": "VSIX/webpack.config.js",
    "chars": 759,
    "preview": "//@ts-check\n'use strict';\n\nconst path = require('path');\n\n/** @type {import('webpack').Configuration} */\nconst config = "
  },
  {
    "path": "build-ncc.mjs",
    "chars": 691,
    "preview": "import {exec} from 'child_process';\nimport {promisify} from 'util';\nimport {copyFileSync, mkdirSync, existsSync} from 'f"
  },
  {
    "path": "build-shim.js",
    "chars": 320,
    "preview": "import { fileURLToPath as _fileURLToPath } from 'url';\nimport { dirname as _dirname } from 'path';\nimport { createRequir"
  },
  {
    "path": "build.mjs",
    "chars": 6555,
    "preview": "import * as esbuild from 'esbuild';\nimport {copyFileSync, existsSync, mkdirSync} from 'fs';\nimport {builtinModules} from"
  },
  {
    "path": "docs/role/en/01.Snow CLI Plan Every Step.md",
    "chars": 2047,
    "preview": "# Snow CLI Plan Every Step\n\n> Note: This English version is being maintained incrementally.\n> For the latest complete co"
  },
  {
    "path": "docs/role/zh/01.Snow CLI 一步一规划.md",
    "chars": 1735,
    "preview": "# Snow CLI 一步一规划\n\n## 角色定位\n\n你是 Snow CLI 终端编程助手。你的目标是以最小必要分析完成高质量代码交付:快速理解需求、明确计划、可靠执行、严格验证。\n\n## 语言与沟通硬性约束\n\n1. 必须始终使用中文回复。"
  },
  {
    "path": "docs/usage/en/0.Catalogue.md",
    "chars": 3471,
    "preview": "# Snow CLI Usage Documentation - Catalogue\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## Quick Start\n\n- [In"
  },
  {
    "path": "docs/usage/en/01.Installation Guide.md",
    "chars": 3294,
    "preview": "# Snow CLI User Documentation - Installation Guide\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## Installati"
  },
  {
    "path": "docs/usage/en/02.First Time Configuration.md",
    "chars": 14489,
    "preview": "# Snow CLI User Documentation - First Time Configuration\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## Firs"
  },
  {
    "path": "docs/usage/en/03.Proxy and Browser Settings.md",
    "chars": 470,
    "preview": "# Snow CLI User Documentation - Proxy and Browser Settings\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## Pr"
  },
  {
    "path": "docs/usage/en/04.Codebase Setup.md",
    "chars": 6402,
    "preview": "# Snow CLI User Guide - Codebase Setup\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## Codebase Setup\n\nSnow C"
  },
  {
    "path": "docs/usage/en/05.Sub-Agent Configuration.md",
    "chars": 15343,
    "preview": "# Snow CLI User Guide - Sub-Agent Configuration\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## What are Sub-"
  },
  {
    "path": "docs/usage/en/06.Sensitive Commands Configuration.md",
    "chars": 11674,
    "preview": "# Snow CLI User Guide - Sensitive Commands Configuration\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## What"
  },
  {
    "path": "docs/usage/en/07.Hooks Configuration.md",
    "chars": 26514,
    "preview": "# Snow CLI User Guide - Hooks Configuration\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## What are Hooks\n\nH"
  },
  {
    "path": "docs/usage/en/08.Theme Settings.md",
    "chars": 15142,
    "preview": "# Snow CLI User Guide - Theme Settings\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## What is a Theme\n\nA the"
  },
  {
    "path": "docs/usage/en/09.Command Panel Guide.md",
    "chars": 29499,
    "preview": "# Snow CLI User Guide - Command Panel Guide\n\nThe command panel is a quick command system provided by Snow CLI, allowing "
  },
  {
    "path": "docs/usage/en/10.Command Injection Mode.md",
    "chars": 12939,
    "preview": "# Snow CLI Usage Documentation - Command Injection Mode & Bash Mode\n\nWelcome to Snow CLI! Agentic coding in your termina"
  },
  {
    "path": "docs/usage/en/11.Vulnerability Hunting Mode.md",
    "chars": 11799,
    "preview": "# Snow CLI Usage Documentation - Vulnerability Hunting Mode\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## W"
  },
  {
    "path": "docs/usage/en/12.Headless Mode.md",
    "chars": 14447,
    "preview": "# Snow CLI Usage Documentation - Headless Mode\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## What is Headle"
  },
  {
    "path": "docs/usage/en/13.Keyboard Shortcuts Guide.md",
    "chars": 12727,
    "preview": "# Keyboard Shortcuts Guide\n\nThis document lists all available keyboard shortcuts and features in SNOW AI CLI.\n\n## Table "
  },
  {
    "path": "docs/usage/en/14.MCP Configuration.md",
    "chars": 5831,
    "preview": "# Snow CLI User Documentation - MCP Configuration\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## MCP Configu"
  },
  {
    "path": "docs/usage/en/15.Async Task Management.md",
    "chars": 7629,
    "preview": "# Snow CLI User Guide - Async Task Management\n\nThe async task feature allows you to run time-consuming AI tasks in the b"
  },
  {
    "path": "docs/usage/en/16.Third-Party Relay Configuration.md",
    "chars": 15947,
    "preview": "# Snow CLI User Guide - Third-Party Relay Configuration\n\nThis document explains how to configure Snow CLI to access dome"
  },
  {
    "path": "docs/usage/en/17.LSP Configuration.md",
    "chars": 5517,
    "preview": "# Snow CLI User Guide - LSP Configuration and Usage\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## What is L"
  },
  {
    "path": "docs/usage/en/18.Skills Command Detailed Guide.md",
    "chars": 13550,
    "preview": "# Snow CLI Usage Documentation - Skills Command Detailed Guide\n\nSkills is a powerful extension feature of Snow CLI that "
  },
  {
    "path": "docs/usage/en/19.Startup Parameters Guide.md",
    "chars": 5456,
    "preview": "# Snow CLI User Documentation - Startup Parameters Guide\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## Star"
  },
  {
    "path": "docs/usage/en/20.SSE Service Mode.md",
    "chars": 37680,
    "preview": "# Snow CLI Usage Documentation - SSE Service Mode\n\nWelcome to Snow CLI! Agentic coding in your terminal.\n\n## Quick Start"
  },
  {
    "path": "docs/usage/en/21.Custom StatusLine Guide.md",
    "chars": 14937,
    "preview": "# Snow CLI User Guide - Custom StatusLine\n\n## Overview\n\nSnow CLI supports loading custom StatusLine plugins from your us"
  },
  {
    "path": "docs/usage/en/22.Team Mode Guide.md",
    "chars": 17055,
    "preview": "# Snow CLI User Guide - Team Mode\n\nTeam Mode (Multi-Agent Collaboration) is an advanced feature of Snow CLI that allows "
  },
  {
    "path": "docs/usage/en/23.Custom Search Engine Guide.md",
    "chars": 10740,
    "preview": "# Snow CLI User Guide - Custom Search Engine\n\n## Overview\n\nSnow CLI's web search (the `web-search` MCP tool) is driven b"
  },
  {
    "path": "docs/usage/zh/0.目录.md",
    "chars": 1364,
    "preview": "# Snow CLI 使用文档——目录\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 快速开始\n\n- [安装指南](./01.安装指南.md) - 系统要求、安装(更新、卸载)步骤、IDE 扩展安装\n- [首次"
  },
  {
    "path": "docs/usage/zh/01.安装指南.md",
    "chars": 2144,
    "preview": "# Snow CLI 使用文档——安装指南\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 安装指南\n\n### 1、系统环境要求\n\n1. 操作系统:Windows 10+ / macOS 10.15+ / Ubu"
  },
  {
    "path": "docs/usage/zh/02.首次配置.md",
    "chars": 6879,
    "preview": "# Snow CLI 使用文档——首次配置\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 首次配置\n\n### 1、在任意目录下进入命令行\n\n1. 键入 `snow` 启动 Snow CLI 或点击 IDE 插件"
  },
  {
    "path": "docs/usage/zh/03.代理和浏览器设置.md",
    "chars": 390,
    "preview": "# Snow CLI 使用文档——首次配置\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 代理和浏览器设置\n\n* 启用代理时,CLI的流量会通过自定义的端口传输\n\n* 浏览器设置:CLI 的联网搜索功能会使用浏"
  },
  {
    "path": "docs/usage/zh/04.代码库设置.md",
    "chars": 2975,
    "preview": "# Snow CLI 使用文档——代码库设置\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 代码库设置\n\nSnow CLI 支持启用本地代码库功能。\n\n_代码库是一个基于向量搜索的 Sqlite 数据库,用于存"
  },
  {
    "path": "docs/usage/zh/05.子代理设置.md",
    "chars": 6715,
    "preview": "# Snow CLI 使用文档——子代理设置\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 什么是子代理\n\n子代理是 Snow CLI 中主流程的分支,专门用于处理特定的单一需求以节约主流程的上下文占用\n\n##"
  },
  {
    "path": "docs/usage/zh/06.敏感命令配置.md",
    "chars": 4618,
    "preview": "# Snow CLI 使用文档——敏感命令配置\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 什么是敏感命令\n\n敏感命令是指在执行时可能对系统、数据或项目产生重大影响的命令。这些命令在执行前需要用户明确确认,以"
  },
  {
    "path": "docs/usage/zh/07.Hooks配置.md",
    "chars": 17360,
    "preview": "# Snow CLI 使用文档——Hooks 配置\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 什么是 Hooks\n\nHooks 是 Snow CLI 提供的强大扩展机制,允许您在 AI 工作流程的关键节点自"
  },
  {
    "path": "docs/usage/zh/08.主题设置.md",
    "chars": 7457,
    "preview": "# Snow CLI 使用文档——主题设置\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 什么是主题\n\n主题定义了 Snow CLI 终端界面的外观,包括颜色方案、代码高亮样式、菜单显示效果等。通过主题设置,您"
  },
  {
    "path": "docs/usage/zh/09.指令面板说明.md",
    "chars": 14998,
    "preview": "# Snow CLI 使用文档——指令面板说明\n\n指令面板是 Snow CLI 提供的快捷命令系统,让您可以通过简单的斜杠命令快速执行各种操作。\n\n## 指令面板概述\n\n所有指令都以 `/` 开头,在聊天输入框中输入即可执行。指令分为以下几"
  },
  {
    "path": "docs/usage/zh/10.命令注入模式.md",
    "chars": 5696,
    "preview": "# Snow CLI 使用文档——命令注入模式与 Bash 模式\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 什么是命令注入模式和 Bash 模式\n\nSnow CLI 提供了两种命令执行模式,让您可以在对话中"
  },
  {
    "path": "docs/usage/zh/11.漏洞猎人模式.md",
    "chars": 5044,
    "preview": "# Snow CLI 使用文档——漏洞猎人模式\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 什么是漏洞猎人模式\n\n漏洞猎人模式(Vulnerability Hunting Mode)是 Snow CLI 的一"
  },
  {
    "path": "docs/usage/zh/12.无头模式.md",
    "chars": 8439,
    "preview": "# Snow CLI 使用文档——无头模式\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 什么是无头模式\n\n无头模式(Headless Mode)是 Snow CLI 的快速对话功能,允许您直接在命令行中提问并"
  },
  {
    "path": "docs/usage/zh/13.快捷键指南.md",
    "chars": 7087,
    "preview": "# 快捷键指南\n\n本文档列出了 SNOW AI CLI 中所有可用的快捷键和功能。\n\n## 目录\n\n- [基本编辑](#基本编辑)\n- [光标移动](#光标移动)\n- [文本删除](#文本删除)\n- [模式切换](#模式切换)\n- [导航和"
  },
  {
    "path": "docs/usage/zh/14.MCP配置.md",
    "chars": 3499,
    "preview": "# Snow CLI 使用文档——MCP 配置\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## MCP 配置\n\nMCP(Model Context Protocol)是一个开放协议,允许 AI 助手与外部工具和服"
  },
  {
    "path": "docs/usage/zh/15.异步任务管理.md",
    "chars": 3221,
    "preview": "# Snow CLI 使用文档——异步任务管理\n\n异步任务功能允许你在后台运行耗时的 AI 任务,同时继续使用终端进行其他工作。任务会在独立进程中运行,不会阻塞你的操作。\n\n## 什么是异步任务\n\n异步任务适用于以下场景:\n\n- 需要长时间"
  },
  {
    "path": "docs/usage/zh/16.第三方中转配置.md",
    "chars": 26757,
    "preview": "# Snow CLI 使用文档——第三方中转配置\n\n本文档介绍如何配置 Snow CLI 访问国内的 Claude Code 和 Codex 中转服务。\n\n## 配置说明\n\n中转服务提供商会对第三方客户端设置拦截措施,因此你需要在 Snow"
  },
  {
    "path": "docs/usage/zh/17.LSP配置.md",
    "chars": 3425,
    "preview": "# Snow CLI 使用文档——LSP 配置与用法\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 什么是 LSP\n\nLSP(Language Server Protocol)是一套通用协议,用来让“语言服务器"
  },
  {
    "path": "docs/usage/zh/18.Skills指令详细说明.md",
    "chars": 6721,
    "preview": "# Snow CLI 使用文档——Skills 指令详细说明\n\nSkills 是 Snow CLI 的强大扩展功能,允许您创建和使用专门的知识库和工具集。每个技能都包含特定领域的专业知识和实用工具,可以通过 `skill-execute` "
  },
  {
    "path": "docs/usage/zh/19.启动参数说明.md",
    "chars": 2696,
    "preview": "# Snow CLI 使用文档——启动参数说明\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 启动参数说明\n\n### 基本命令\n\n#### 1. 默认启动\n\n```bash\nsnow\n```\n\n启动 Snow "
  },
  {
    "path": "docs/usage/zh/20.SSE服务模式.md",
    "chars": 29385,
    "preview": "# Snow CLI 使用文档——SSE 服务模式\n\n欢迎使用 Snow CLI!在终端中进行 Agentic 编程。\n\n## 快速体验\n\n想要快速体验 SSE 客户端?我们提供了一个完整的浏览器测试客户端:\n\n**位置**:`source"
  },
  {
    "path": "docs/usage/zh/21.自定义StatusLine指南.md",
    "chars": 11567,
    "preview": "# Snow CLI 使用文档——自定义 StatusLine 指南\n\n## 概述\n\nSnow CLI 支持从用户目录加载自定义 StatusLine 插件。你只需要把一个或多个 JavaScript 文件放到 `~/.snow/plugi"
  },
  {
    "path": "docs/usage/zh/22.Team模式指南.md",
    "chars": 9999,
    "preview": "# Snow CLI 使用文档——Team模式指南\n\nTeam模式(多智能体协作)是 Snow CLI 的高级功能,允许你同时启动多个独立工作的 AI 队友,通过共享任务列表协调工作,实现真正的并行开发。\n\n## 什么是Team模式\n\nTe"
  },
  {
    "path": "docs/usage/zh/23.自定义搜索引擎指南.md",
    "chars": 6652,
    "preview": "# Snow CLI 使用文档——自定义搜索引擎指南\n\n## 概述\n\nSnow CLI 的联网搜索(`web-search` MCP 工具)使用可插拔的搜索引擎层。内置引擎包括 `duckduckgo` 和 `bing`,二者均通过无头浏览"
  },
  {
    "path": "package.json",
    "chars": 4020,
    "preview": "{\n\t\"name\": \"snow-ai\",\n\t\"version\": \"0.7.26\",\n\t\"description\": \"Agentic coding in your terminal\",\n\t\"license\": \"MIT\",\n\t\"bin\""
  },
  {
    "path": "scripts/clean-build.cjs",
    "chars": 392,
    "preview": "/* eslint-disable unicorn/prefer-module */\n\n/**\n * 清理构建产物目录,避免 tsc 残留旧输出导致 bundle 与 source 不一致。\n *\n * 说明:\n * - tsc 默认不会删"
  },
  {
    "path": "scripts/postinstall.cjs",
    "chars": 5550,
    "preview": "#!/usr/bin/env node\n\n/**\n * Post-install script to provide installation optimization tips for users\n */\n\nconst https = r"
  },
  {
    "path": "source/agents/bashOutputSummaryAgent.ts",
    "chars": 4811,
    "preview": "import {getSnowConfig} from '../utils/config/apiConfig.js';\nimport {logger} from '../utils/core/logger.js';\nimport {crea"
  },
  {
    "path": "source/agents/codebaseIndexAgent.ts",
    "chars": 25912,
    "preview": "import path from 'node:path';\nimport fs from 'node:fs';\nimport crypto from 'node:crypto';\nimport ignore, {type Ignore} f"
  },
  {
    "path": "source/agents/codebaseReviewAgent.ts",
    "chars": 14713,
    "preview": "import {getSnowConfig} from '../utils/config/apiConfig.js';\nimport {logger} from '../utils/core/logger.js';\nimport {crea"
  },
  {
    "path": "source/agents/compactAgent.ts",
    "chars": 9983,
    "preview": "import {getSnowConfig} from '../utils/config/apiConfig.js';\nimport {logger} from '../utils/core/logger.js';\nimport {crea"
  },
  {
    "path": "source/agents/reviewAgent.ts",
    "chars": 13036,
    "preview": "import {\n\tgetSnowConfig,\n\tgetCustomSystemPrompt,\n} from '../utils/config/apiConfig.js';\nimport {logger} from '../utils/c"
  },
  {
    "path": "source/agents/summaryAgent.ts",
    "chars": 9909,
    "preview": "import {getSnowConfig} from '../utils/config/apiConfig.js';\nimport {logger} from '../utils/core/logger.js';\nimport {crea"
  },
  {
    "path": "source/api/anthropic.ts",
    "chars": 29370,
    "preview": "import {createHash, randomUUID} from 'crypto';\nimport {\n\tgetSnowConfig,\n\tgetCustomSystemPromptForConfig,\n\tgetCustomHeade"
  },
  {
    "path": "source/api/chat.ts",
    "chars": 20629,
    "preview": "import {\n\tgetSnowConfig,\n\tgetCustomHeadersForConfig,\n\tgetCustomSystemPromptForConfig,\n} from '../utils/config/apiConfig."
  },
  {
    "path": "source/api/embedding.ts",
    "chars": 10553,
    "preview": "import {loadCodebaseConfig} from '../utils/config/codebaseConfig.js';\nimport {logger} from '../utils/core/logger.js';\nim"
  },
  {
    "path": "source/api/gemini.ts",
    "chars": 23073,
    "preview": "import {\n\tgetSnowConfig,\n\tgetCustomSystemPromptForConfig,\n\tgetCustomHeadersForConfig,\n} from '../utils/config/apiConfig."
  },
  {
    "path": "source/api/models.ts",
    "chars": 6248,
    "preview": "import {\n\tgetSnowConfig,\n\tgetCustomHeaders,\n\tgetCustomHeadersForConfig,\n\ttype ApiConfig,\n} from '../utils/config/apiConf"
  },
  {
    "path": "source/api/rerank.ts",
    "chars": 9356,
    "preview": "import {loadCodebaseConfig} from '../utils/config/codebaseConfig.js';\nimport {logger} from '../utils/core/logger.js';\nim"
  },
  {
    "path": "source/api/responses.ts",
    "chars": 21983,
    "preview": "import {\n\tgetSnowConfig,\n\tgetCustomSystemPromptForConfig,\n\tgetCustomHeadersForConfig,\n} from '../utils/config/apiConfig."
  },
  {
    "path": "source/api/sse-server.ts",
    "chars": 21348,
    "preview": "import {createServer, IncomingMessage, ServerResponse} from 'http';\nimport {parse as parseUrl} from 'url';\n\n/**\n * SSE 事"
  },
  {
    "path": "source/api/types.ts",
    "chars": 2079,
    "preview": "/**\n * Shared API types for all AI providers\n */\n\nexport interface ImageContent {\n\ttype: 'image';\n\tdata: string; // Base"
  },
  {
    "path": "source/app.tsx",
    "chars": 10004,
    "preview": "import React, {useState, useEffect, Suspense} from 'react';\nimport {Box, Text} from 'ink';\nimport {Alert} from '@inkjs/u"
  },
  {
    "path": "source/cli.tsx",
    "chars": 24442,
    "preview": "#!/usr/bin/env node\n\n// Force color support for all chalk instances (must be set before any imports)\n// This ensures syn"
  },
  {
    "path": "source/hooks/conversation/chatLogic/types.ts",
    "chars": 4215,
    "preview": "import type {Message} from '../../../ui/components/chat/MessageList.js';\n\nexport type {Message};\n\nexport interface UseCh"
  },
  {
    "path": "source/hooks/conversation/chatLogic/useChatHandlers.ts",
    "chars": 10594,
    "preview": "import {useStdout} from 'ink';\nimport ansiEscapes from 'ansi-escapes';\nimport {useI18n} from '../../../i18n/index.js';\ni"
  },
  {
    "path": "source/hooks/conversation/chatLogic/useMessageProcessing.ts",
    "chars": 22613,
    "preview": "import {useRef, useEffect} from 'react';\nimport type {UseChatLogicProps, Message} from './types.js';\nimport {sessionMana"
  },
  {
    "path": "source/hooks/conversation/chatLogic/useRemoteEvents.ts",
    "chars": 9568,
    "preview": "import {useEffect} from 'react';\nimport type {UseChatLogicProps} from './types.js';\nimport type {RollbackMode} from '../"
  },
  {
    "path": "source/hooks/conversation/chatLogic/useRollback.ts",
    "chars": 15066,
    "preview": "import {useEffect, useCallback} from 'react';\nimport {useStdout} from 'ink';\nimport ansiEscapes from 'ansi-escapes';\nimp"
  },
  {
    "path": "source/hooks/conversation/core/autoCompressHandler.ts",
    "chars": 4501,
    "preview": "import type {Message} from '../../../ui/components/chat/MessageList.js';\nimport type {CompressionStatus} from '../../../"
  },
  {
    "path": "source/hooks/conversation/core/conversationSetup.ts",
    "chars": 3262,
    "preview": "import type {ChatMessage} from '../../../api/chat.js';\nimport {\n\tcollectAllMCPTools,\n\tgetMCPServicesInfo,\n\ttype MCPTool,"
  },
  {
    "path": "source/hooks/conversation/core/conversationTypes.ts",
    "chars": 3352,
    "preview": "import type {ConfirmationResult} from '../../../ui/components/tools/ToolConfirmation.js';\nimport type {CompressionStatus"
  },
  {
    "path": "source/hooks/conversation/core/editorContextBuilder.ts",
    "chars": 1401,
    "preview": "/**\n * Editor context structure\n */\nexport interface EditorContext {\n\tworkspaceFolder?: string;\n\tactiveFile?: string;\n\tc"
  },
  {
    "path": "source/hooks/conversation/core/encoderManager.ts",
    "chars": 1018,
    "preview": "import {encoding_for_model} from 'tiktoken';\nimport {resourceMonitor} from '../../../utils/core/resourceMonitor.js';\n\n/*"
  },
  {
    "path": "source/hooks/conversation/core/onStopHookHandler.ts",
    "chars": 1776,
    "preview": "import type {ChatMessage} from '../../../api/chat.js';\nimport type {Message} from '../../../ui/components/chat/MessageLi"
  },
  {
    "path": "source/hooks/conversation/core/pendingMessagesHandler.ts",
    "chars": 5878,
    "preview": "import type {Message} from '../../../ui/components/chat/MessageList.js';\nimport {sessionManager} from '../../../utils/se"
  },
  {
    "path": "source/hooks/conversation/core/sessionInitializer.ts",
    "chars": 2348,
    "preview": "import type {ChatMessage} from '../../../api/chat.js';\nimport {sessionManager} from '../../../utils/session/sessionManag"
  },
  {
    "path": "source/hooks/conversation/core/streamFactory.ts",
    "chars": 2715,
    "preview": "import {\n\tcreateStreamingChatCompletion,\n\ttype ChatMessage,\n} from '../../../api/chat.js';\nimport {createStreamingRespon"
  },
  {
    "path": "source/hooks/conversation/core/streamProcessor.ts",
    "chars": 9201,
    "preview": "import type {ChatMessage} from '../../../api/chat.js';\nimport {sessionManager} from '../../../utils/session/sessionManag"
  },
  {
    "path": "source/hooks/conversation/core/subAgentMessageHandler.ts",
    "chars": 38345,
    "preview": "import type {Message} from '../../../ui/components/chat/MessageList.js';\nimport type {SubAgentMessage} from '../../../ut"
  },
  {
    "path": "source/hooks/conversation/core/toolCallProcessor.ts",
    "chars": 3622,
    "preview": "import type {ChatMessage} from '../../../api/chat.js';\nimport type {Message} from '../../../ui/components/chat/MessageLi"
  },
  {
    "path": "source/hooks/conversation/core/toolCallRoundHandler.ts",
    "chars": 11800,
    "preview": "import {\n\texecuteToolCalls,\n\ttype ToolCall,\n} from '../../../utils/execution/toolExecutor.js';\nimport {toolSearchService"
  },
  {
    "path": "source/hooks/conversation/core/toolConfirmationFlow.ts",
    "chars": 6559,
    "preview": "import type {ToolCall} from '../../../utils/execution/toolExecutor.js';\nimport type {ConfirmationResult} from '../../../"
  },
  {
    "path": "source/hooks/conversation/core/toolRejectionHandler.ts",
    "chars": 3383,
    "preview": "import type {Message} from '../../../ui/components/chat/MessageList.js';\nimport type {ConfirmationResult} from '../../.."
  },
  {
    "path": "source/hooks/conversation/core/toolResultDisplay.ts",
    "chars": 3241,
    "preview": "import type {Message} from '../../../ui/components/chat/MessageList.js';\nimport type {ToolCall, ToolResult} from '../../"
  },
  {
    "path": "source/hooks/conversation/useChatLogic.ts",
    "chars": 8795,
    "preview": "import {useRef, useEffect, useCallback} from 'react';\nimport type {UseChatLogicProps} from './chatLogic/types.js';\nimpor"
  },
  {
    "path": "source/hooks/conversation/useCommandHandler.ts",
    "chars": 46058,
    "preview": "import {useStdout} from 'ink';\nimport {useCallback} from 'react';\nimport type {Message} from '../../ui/components/chat/M"
  },
  {
    "path": "source/hooks/conversation/useConversation.ts",
    "chars": 6787,
    "preview": "import type {ChatMessage} from '../../api/chat.js';\nimport {getSnowConfig} from '../../utils/config/apiConfig.js';\nimpor"
  },
  {
    "path": "source/hooks/conversation/useStreamingState.ts",
    "chars": 5326,
    "preview": "import {useState, useEffect} from 'react';\nimport type {UsageInfo} from '../../api/chat.js';\n\nexport type RetryStatus = "
  },
  {
    "path": "source/hooks/conversation/useToolConfirmation.ts",
    "chars": 4430,
    "preview": "import {useState, useRef, useCallback, useEffect} from 'react';\nimport type {ToolCall} from '../../utils/execution/toolE"
  },
  {
    "path": "source/hooks/conversation/utils/messageCleanup.ts",
    "chars": 2705,
    "preview": "import type {ChatMessage} from '../../../api/chat.js';\n\n/**\n * LAYER 3 PROTECTION: Clean orphaned tool_calls from conver"
  },
  {
    "path": "source/hooks/conversation/utils/thinkingExtractor.ts",
    "chars": 1978,
    "preview": "/**\n * Reasoning data structure from Responses API\n */\ninterface ReasoningData {\n\tsummary?: Array<{type: 'summary_text';"
  },
  {
    "path": "source/hooks/execution/useBackgroundProcesses.ts",
    "chars": 4780,
    "preview": "import {useState, useCallback} from 'react';\nimport {exec} from 'child_process';\n\nexport interface BackgroundProcess {\n\t"
  },
  {
    "path": "source/hooks/execution/useSchedulerExecutionState.ts",
    "chars": 3705,
    "preview": "import {useState, useCallback} from 'react';\n\nexport interface SchedulerExecutionState {\n\t/** 是否正在执行倒计时 */\n\tisRunning: b"
  },
  {
    "path": "source/hooks/execution/useTerminalExecutionState.ts",
    "chars": 4386,
    "preview": "import {useState, useCallback} from 'react';\n\nexport interface TerminalExecutionState {\n\tisExecuting: boolean;\n\tcommand:"
  },
  {
    "path": "source/hooks/input/keyboard/context.ts",
    "chars": 1983,
    "preview": "import type {Key} from 'ink';\nimport {TextBuffer} from '../../../utils/ui/textBuffer.js';\nimport type {\n\tHandlerContext,"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/arrowKeys.ts",
    "chars": 3980,
    "preview": "import type {HandlerContext} from '../types.js';\n\nexport function arrowKeysHandler(ctx: HandlerContext): boolean {\n\tcons"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/clipboard.ts",
    "chars": 526,
    "preview": "import type {HandlerContext} from '../types.js';\n\nexport function clipboardHandler(ctx: HandlerContext): boolean {\n\tcons"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/deleteAndBackspace.ts",
    "chars": 823,
    "preview": "import type {HandlerContext} from '../types.js';\n\nexport function deleteAndBackspaceHandler(ctx: HandlerContext): boolea"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/editing.ts",
    "chars": 5842,
    "preview": "import {editTextWithNotepad} from '../../../../utils/ui/externalEditor.js';\nimport {copyToClipboard} from '../../../../u"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/escape.ts",
    "chars": 2910,
    "preview": "import {setPickerActive} from '../../../../utils/ui/pickerState.js';\nimport type {HandlerContext} from '../types.js';\n\ne"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/focusFilter.ts",
    "chars": 1427,
    "preview": "import type {HandlerContext} from '../types.js';\n\nexport function focusFilterHandler(ctx: HandlerContext): boolean {\n\tco"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/modeToggle.ts",
    "chars": 1379,
    "preview": "import type {HandlerContext} from '../types.js';\n\nfunction cycleModes(ctx: HandlerContext): void {\n\tconst {options} = ct"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/newline.ts",
    "chars": 837,
    "preview": "import type {HandlerContext} from '../types.js';\n\nexport function newlineHandler(ctx: HandlerContext): boolean {\n\tconst "
  },
  {
    "path": "source/hooks/input/keyboard/handlers/pickers/agentPicker.ts",
    "chars": 1336,
    "preview": "import type {HandlerContext} from '../../types.js';\n\nexport function agentPickerHandler(ctx: HandlerContext): boolean {\n"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/pickers/argsPicker.ts",
    "chars": 1583,
    "preview": "import {setPickerActive} from '../../../../../utils/ui/pickerState.js';\nimport type {HandlerContext} from '../../types.j"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/pickers/commandPanel.ts",
    "chars": 4749,
    "preview": "import {executeCommand} from '../../../../../utils/execution/commandExecutor.js';\nimport {commandUsageManager} from '../"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/pickers/filePicker.ts",
    "chars": 1271,
    "preview": "import type {HandlerContext} from '../../types.js';\n\nexport function filePickerHandler(ctx: HandlerContext): boolean {\n\t"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/pickers/gitLinePicker.ts",
    "chars": 1358,
    "preview": "import type {HandlerContext} from '../../types.js';\n\nexport function gitLinePickerHandler(ctx: HandlerContext): boolean "
  },
  {
    "path": "source/hooks/input/keyboard/handlers/pickers/historyMenu.ts",
    "chars": 1164,
    "preview": "import type {HandlerContext} from '../../types.js';\n\nexport function historyMenuHandler(ctx: HandlerContext): boolean {\n"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/pickers/profilePicker.ts",
    "chars": 1905,
    "preview": "import type {HandlerContext} from '../../types.js';\n\nexport function profilePickerHandler(ctx: HandlerContext): boolean "
  },
  {
    "path": "source/hooks/input/keyboard/handlers/pickers/runningAgentsPicker.ts",
    "chars": 1389,
    "preview": "import type {HandlerContext} from '../../types.js';\n\nexport function runningAgentsPickerHandler(ctx: HandlerContext): bo"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/pickers/skillsPicker.ts",
    "chars": 1344,
    "preview": "import type {HandlerContext} from '../../types.js';\n\nexport function skillsPickerHandler(ctx: HandlerContext): boolean {"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/pickers/todoPicker.ts",
    "chars": 1851,
    "preview": "import type {HandlerContext} from '../../types.js';\n\nexport function todoPickerHandler(ctx: HandlerContext): boolean {\n\t"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/profileShortcut.ts",
    "chars": 505,
    "preview": "import type {HandlerContext} from '../types.js';\n\nexport function profileShortcutHandler(ctx: HandlerContext): boolean {"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/regularInput.ts",
    "chars": 5928,
    "preview": "import type {HandlerContext} from '../types.js';\n\nexport function regularInputHandler(ctx: HandlerContext): boolean {\n\tc"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/submit.ts",
    "chars": 5904,
    "preview": "import {executeCommand} from '../../../../utils/execution/commandExecutor.js';\nimport {commandUsageManager} from '../../"
  },
  {
    "path": "source/hooks/input/keyboard/handlers/tabArgsPicker.ts",
    "chars": 812,
    "preview": "import {COMMAND_ARGS_OPTIONS} from '../../../ui/useCommandPanel.js';\nimport type {HandlerContext} from '../types.js';\n\ne"
  },
  {
    "path": "source/hooks/input/keyboard/types.ts",
    "chars": 7465,
    "preview": "import type {Key} from 'ink';\nimport type React from 'react';\nimport {TextBuffer} from '../../../utils/ui/textBuffer.js'"
  },
  {
    "path": "source/hooks/input/keyboard/utils/wordBoundary.ts",
    "chars": 771,
    "preview": "// Helper function: find word boundaries (space and punctuation)\nexport function findWordBoundary(\n\ttext: string,\n\tstart"
  },
  {
    "path": "source/hooks/input/useBashMode.ts",
    "chars": 15425,
    "preview": "import {useState, useCallback} from 'react';\nimport {isSensitiveCommand} from '../../utils/execution/sensitiveCommandMan"
  },
  {
    "path": "source/hooks/input/useClipboard.ts",
    "chars": 7773,
    "preview": "import {useCallback} from 'react';\nimport {execSync} from 'child_process';\nimport {TextBuffer} from '../../utils/ui/text"
  },
  {
    "path": "source/hooks/input/useHistoryNavigation.ts",
    "chars": 6072,
    "preview": "import {useState, useCallback, useRef, useEffect} from 'react';\nimport {TextBuffer} from '../../utils/ui/textBuffer.js';"
  },
  {
    "path": "source/hooks/input/useInputBuffer.ts",
    "chars": 1394,
    "preview": "import {useReducer, useCallback, useEffect, useRef} from 'react';\nimport {TextBuffer, Viewport} from '../../utils/ui/tex"
  },
  {
    "path": "source/hooks/input/useKeyboardInput.ts",
    "chars": 5206,
    "preview": "import {useRef, useEffect} from 'react';\nimport {useInput, useStdin} from 'ink';\nimport type {HandlerContext, HandlerRef"
  },
  {
    "path": "source/hooks/integration/useGlobalExit.ts",
    "chars": 1020,
    "preview": "import {useInput} from 'ink';\nimport {useState} from 'react';\nimport {useI18n} from '../../i18n/index.js';\nimport {navig"
  },
  {
    "path": "source/hooks/integration/useGlobalNavigation.ts",
    "chars": 857,
    "preview": "import {EventEmitter} from 'events';\n\n// Global navigation event emitter\nconst navigationEmitter = new EventEmitter();\n/"
  },
  {
    "path": "source/hooks/integration/useVSCodeState.ts",
    "chars": 3580,
    "preview": "import {useState, useEffect, useRef} from 'react';\nimport {\n\tvscodeConnection,\n\ttype EditorContext,\n} from '../../utils/"
  },
  {
    "path": "source/hooks/picker/useAgentPicker.ts",
    "chars": 4708,
    "preview": "import {useState, useCallback, useEffect} from 'react';\nimport {TextBuffer} from '../../utils/ui/textBuffer.js';\nimport "
  },
  {
    "path": "source/hooks/picker/useFilePicker.ts",
    "chars": 8023,
    "preview": "import {useReducer, useCallback, useRef} from 'react';\nimport {TextBuffer} from '../../utils/ui/textBuffer.js';\nimport {"
  },
  {
    "path": "source/hooks/picker/useGitLinePicker.ts",
    "chars": 7742,
    "preview": "import {useCallback, useEffect, useMemo, useState} from 'react';\nimport {TextBuffer} from '../../utils/ui/textBuffer.js'"
  },
  {
    "path": "source/hooks/picker/useProfilePicker.ts",
    "chars": 668,
    "preview": "import {useState, useCallback} from 'react';\nimport {getAllProfiles} from '../../utils/config/configManager.js';\nimport "
  },
  {
    "path": "source/hooks/picker/useRunningAgentsPicker.ts",
    "chars": 9672,
    "preview": "import {useState, useCallback, useEffect, useSyncExternalStore, useMemo} from 'react';\nimport {TextBuffer} from '../../u"
  }
]

// ... and 406 more files (download for full content)

About this extraction

This page contains the full source code of the MayDay-wpf/snow-cli GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 606 files (4.4 MB), approximately 1.2M tokens, and a symbol index with 3382 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!