codex-linux 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +10 -0
- package/.eslintrc.json +27 -0
- package/.github/workflows/ci.yml +156 -0
- package/.huskyrc +7 -0
- package/.lintstagedrc +13 -0
- package/.prettierrc +12 -0
- package/CLAUDE.md +163 -0
- package/DESIGN_SUPERIOR.md +73 -0
- package/Dockerfile +64 -0
- package/INSTALLATION.md +152 -0
- package/LICENSE +21 -0
- package/README.md +245 -0
- package/assets/skills/code-review/instructions.md +102 -0
- package/assets/skills/code-review/skill.yaml +15 -0
- package/assets/skills/refactoring/instructions.md +149 -0
- package/assets/skills/refactoring/skill.yaml +15 -0
- package/assets/skills/testing/skill.yaml +15 -0
- package/commitlint.config.js +23 -0
- package/dist/main/DatabaseManager.js +763 -0
- package/dist/main/DatabaseManager.js.map +1 -0
- package/dist/main/SettingsManager.js +61 -0
- package/dist/main/SettingsManager.js.map +1 -0
- package/dist/main/agents/AgentOrchestrator.js +787 -0
- package/dist/main/agents/AgentOrchestrator.js.map +1 -0
- package/dist/main/agents/AgentSDK.js +219 -0
- package/dist/main/agents/AgentSDK.js.map +1 -0
- package/dist/main/agents/AgentTools.js +348 -0
- package/dist/main/agents/AgentTools.js.map +1 -0
- package/dist/main/agents/CodeIndex.js +233 -0
- package/dist/main/agents/CodeIndex.js.map +1 -0
- package/dist/main/agents/EmbeddingService.js +80 -0
- package/dist/main/agents/EmbeddingService.js.map +1 -0
- package/dist/main/agents/NativeToolCalling.js +206 -0
- package/dist/main/agents/NativeToolCalling.js.map +1 -0
- package/dist/main/api/APIServer.js +278 -0
- package/dist/main/api/APIServer.js.map +1 -0
- package/dist/main/api/RateLimiter.js +138 -0
- package/dist/main/api/RateLimiter.js.map +1 -0
- package/dist/main/api/WebSocketManager.js +300 -0
- package/dist/main/api/WebSocketManager.js.map +1 -0
- package/dist/main/assistant/ContextOptimizer.js +192 -0
- package/dist/main/assistant/ContextOptimizer.js.map +1 -0
- package/dist/main/assistant/PredictedOutputManager.js +172 -0
- package/dist/main/assistant/PredictedOutputManager.js.map +1 -0
- package/dist/main/assistant/PromptCacheManager.js +193 -0
- package/dist/main/assistant/PromptCacheManager.js.map +1 -0
- package/dist/main/assistant/PromptOptimizer.js +626 -0
- package/dist/main/assistant/PromptOptimizer.js.map +1 -0
- package/dist/main/assistant/SmartCodeAssistant.js +224 -0
- package/dist/main/assistant/SmartCodeAssistant.js.map +1 -0
- package/dist/main/auth/SessionManager.js +300 -0
- package/dist/main/auth/SessionManager.js.map +1 -0
- package/dist/main/automations/AdvancedWebhookSystem.js +212 -0
- package/dist/main/automations/AdvancedWebhookSystem.js.map +1 -0
- package/dist/main/automations/AutomationScheduler.js +269 -0
- package/dist/main/automations/AutomationScheduler.js.map +1 -0
- package/dist/main/automations/BatchProcessingSystem.js +159 -0
- package/dist/main/automations/BatchProcessingSystem.js.map +1 -0
- package/dist/main/automations/BrowserAutomationManager.js +195 -0
- package/dist/main/automations/BrowserAutomationManager.js.map +1 -0
- package/dist/main/automations/GitHubActionsManager.js +129 -0
- package/dist/main/automations/GitHubActionsManager.js.map +1 -0
- package/dist/main/automations/GitLabCIManager.js +122 -0
- package/dist/main/automations/GitLabCIManager.js.map +1 -0
- package/dist/main/automations/PriorityQueueManager.js +240 -0
- package/dist/main/automations/PriorityQueueManager.js.map +1 -0
- package/dist/main/background/BackgroundModeManager.js +117 -0
- package/dist/main/background/BackgroundModeManager.js.map +1 -0
- package/dist/main/backup/BackupManager.js +254 -0
- package/dist/main/backup/BackupManager.js.map +1 -0
- package/dist/main/backup/MigrationManager.js +114 -0
- package/dist/main/backup/MigrationManager.js.map +1 -0
- package/dist/main/commands/SlashCommandManager.js +399 -0
- package/dist/main/commands/SlashCommandManager.js.map +1 -0
- package/dist/main/config/ClaudeMdParser.js +519 -0
- package/dist/main/config/ClaudeMdParser.js.map +1 -0
- package/dist/main/config/CustomizationManager.js +381 -0
- package/dist/main/config/CustomizationManager.js.map +1 -0
- package/dist/main/config/LaunchConfigManager.js +211 -0
- package/dist/main/config/LaunchConfigManager.js.map +1 -0
- package/dist/main/config/SettingsManager.js +166 -0
- package/dist/main/config/SettingsManager.js.map +1 -0
- package/dist/main/connectors/ConnectorManager.js +151 -0
- package/dist/main/connectors/ConnectorManager.js.map +1 -0
- package/dist/main/connectors/DatabaseConnector.js +222 -0
- package/dist/main/connectors/DatabaseConnector.js.map +1 -0
- package/dist/main/cowork/CoworkManager.js +324 -0
- package/dist/main/cowork/CoworkManager.js.map +1 -0
- package/dist/main/evals/AgentEvalFramework.js +538 -0
- package/dist/main/evals/AgentEvalFramework.js.map +1 -0
- package/dist/main/evals/GraderManager.js +285 -0
- package/dist/main/evals/GraderManager.js.map +1 -0
- package/dist/main/git/GitWorktreeManager.js +214 -0
- package/dist/main/git/GitWorktreeManager.js.map +1 -0
- package/dist/main/github/GitHubPRMonitor.js +244 -0
- package/dist/main/github/GitHubPRMonitor.js.map +1 -0
- package/dist/main/ide/ContinueInManager.js +181 -0
- package/dist/main/ide/ContinueInManager.js.map +1 -0
- package/dist/main/ide/IDEIntegration.js +277 -0
- package/dist/main/ide/IDEIntegration.js.map +1 -0
- package/dist/main/integrations/LinearManager.js +252 -0
- package/dist/main/integrations/LinearManager.js.map +1 -0
- package/dist/main/integrations/SlackBotManager.js +247 -0
- package/dist/main/integrations/SlackBotManager.js.map +1 -0
- package/dist/main/lsp/LSPManager.js +394 -0
- package/dist/main/lsp/LSPManager.js.map +1 -0
- package/dist/main/main.js +1087 -0
- package/dist/main/main.js.map +1 -0
- package/dist/main/mcp/MCPConfigurationManager.js +281 -0
- package/dist/main/mcp/MCPConfigurationManager.js.map +1 -0
- package/dist/main/mcp/MCPManager.js +710 -0
- package/dist/main/mcp/MCPManager.js.map +1 -0
- package/dist/main/mcp/MCPRegistry.js +272 -0
- package/dist/main/mcp/MCPRegistry.js.map +1 -0
- package/dist/main/monitoring/ErrorRecoveryManager.js +268 -0
- package/dist/main/monitoring/ErrorRecoveryManager.js.map +1 -0
- package/dist/main/monitoring/ErrorTracker.js +57 -0
- package/dist/main/monitoring/ErrorTracker.js.map +1 -0
- package/dist/main/monitoring/MetricsCollector.js +155 -0
- package/dist/main/monitoring/MetricsCollector.js.map +1 -0
- package/dist/main/monitoring/TraceGradingSystem.js +148 -0
- package/dist/main/monitoring/TraceGradingSystem.js.map +1 -0
- package/dist/main/notifications/NotificationManager.js +67 -0
- package/dist/main/notifications/NotificationManager.js.map +1 -0
- package/dist/main/pair/AIPairProgramming.js +200 -0
- package/dist/main/pair/AIPairProgramming.js.map +1 -0
- package/dist/main/plugins/PluginManager.js +222 -0
- package/dist/main/plugins/PluginManager.js.map +1 -0
- package/dist/main/plugins/PluginMarketplace.js +237 -0
- package/dist/main/plugins/PluginMarketplace.js.map +1 -0
- package/dist/main/preload.js +189 -0
- package/dist/main/preload.js.map +1 -0
- package/dist/main/preview/PreviewSessionManager.js +170 -0
- package/dist/main/preview/PreviewSessionManager.js.map +1 -0
- package/dist/main/providers/AIProviderManager.js +327 -0
- package/dist/main/providers/AIProviderManager.js.map +1 -0
- package/dist/main/providers/FineTuningManager.js +276 -0
- package/dist/main/providers/FineTuningManager.js.map +1 -0
- package/dist/main/providers/FreeModelsProvider.js +1104 -0
- package/dist/main/providers/FreeModelsProvider.js.map +1 -0
- package/dist/main/realtime/RealtimeManager.js +116 -0
- package/dist/main/realtime/RealtimeManager.js.map +1 -0
- package/dist/main/remote/CloudEnvironmentManager.js +232 -0
- package/dist/main/remote/CloudEnvironmentManager.js.map +1 -0
- package/dist/main/remote/RemoteSessionManager.js +255 -0
- package/dist/main/remote/RemoteSessionManager.js.map +1 -0
- package/dist/main/search/DeepResearchManager.js +335 -0
- package/dist/main/search/DeepResearchManager.js.map +1 -0
- package/dist/main/search/WebSearchIntegration.js +147 -0
- package/dist/main/search/WebSearchIntegration.js.map +1 -0
- package/dist/main/security/AdminConsoleManager.js +223 -0
- package/dist/main/security/AdminConsoleManager.js.map +1 -0
- package/dist/main/security/AuditLogger.js +136 -0
- package/dist/main/security/AuditLogger.js.map +1 -0
- package/dist/main/security/PermissionManager.js +144 -0
- package/dist/main/security/PermissionManager.js.map +1 -0
- package/dist/main/security/SSOManager.js +173 -0
- package/dist/main/security/SSOManager.js.map +1 -0
- package/dist/main/security/SecurityManager.js +152 -0
- package/dist/main/security/SecurityManager.js.map +1 -0
- package/dist/main/skills/SkillsManager.js +223 -0
- package/dist/main/skills/SkillsManager.js.map +1 -0
- package/dist/main/ssh/SSHManager.js +65 -0
- package/dist/main/ssh/SSHManager.js.map +1 -0
- package/dist/main/streaming/StreamingManager.js +225 -0
- package/dist/main/streaming/StreamingManager.js.map +1 -0
- package/dist/main/sync/CloudSyncManager.js +422 -0
- package/dist/main/sync/CloudSyncManager.js.map +1 -0
- package/dist/main/types.js +28 -0
- package/dist/main/types.js.map +1 -0
- package/dist/main/verification/AutoVerifyManager.js +235 -0
- package/dist/main/verification/AutoVerifyManager.js.map +1 -0
- package/dist/main/vision/ComputerUseManager.js +376 -0
- package/dist/main/vision/ComputerUseManager.js.map +1 -0
- package/dist/main/vision/ImageVideoGenerationManager.js +401 -0
- package/dist/main/vision/ImageVideoGenerationManager.js.map +1 -0
- package/dist/main/vision/VisionManager.js +172 -0
- package/dist/main/vision/VisionManager.js.map +1 -0
- package/dist/renderer/assets/main-DJlZQBCA.js +304 -0
- package/dist/renderer/assets/main-N33ZXEr8.css +1 -0
- package/dist/renderer/index.html +21 -0
- package/dist/renderer/manifest.json +42 -0
- package/dist/renderer/sw.ts +109 -0
- package/dist/shared/types.js +35 -0
- package/dist/shared/types.js.map +1 -0
- package/docker-compose.yml +65 -0
- package/docs/API.md +307 -0
- package/docs/USER_GUIDE.md +476 -0
- package/examples/plugins/sample-plugin/package.json +41 -0
- package/examples/plugins/sample-plugin/src/index.ts +75 -0
- package/index.html +20 -0
- package/jest.config.js +39 -0
- package/package.json +180 -0
- package/packages/cli/package.json +29 -0
- package/packages/cli/src/commands/agents.ts +199 -0
- package/packages/cli/src/commands/tasks.ts +61 -0
- package/packages/cli/src/index.ts +91 -0
- package/packages/cli/src/utils/api.ts +45 -0
- package/packages/cli/src/utils/config.ts +61 -0
- package/packages/npm-installer/bin/codex-linux +126 -0
- package/packages/npm-installer/lib/download.js +273 -0
- package/packages/npm-installer/package.json +42 -0
- package/packages/vscode-extension/package.json +167 -0
- package/packages/vscode-extension/src/api.ts +68 -0
- package/packages/vscode-extension/src/extension.ts +161 -0
- package/packages/vscode-extension/src/panels/chatPanel.ts +265 -0
- package/packages/vscode-extension/src/panels/createAgentPanel.ts +227 -0
- package/packages/vscode-extension/src/providers/agentsProvider.ts +80 -0
- package/postcss.config.js +6 -0
- package/public/manifest.json +42 -0
- package/public/sw.ts +109 -0
- package/scripts/install-dev.sh +103 -0
- package/scripts/install.sh +275 -0
- package/src/main/DatabaseManager.ts +950 -0
- package/src/main/SettingsManager.ts +63 -0
- package/src/main/agents/AgentOrchestrator.ts +930 -0
- package/src/main/agents/AgentSDK.ts +269 -0
- package/src/main/agents/AgentTools.ts +380 -0
- package/src/main/agents/CodeIndex.ts +240 -0
- package/src/main/agents/EmbeddingService.ts +88 -0
- package/src/main/agents/NativeToolCalling.ts +245 -0
- package/src/main/api/APIServer.ts +316 -0
- package/src/main/api/RateLimiter.ts +165 -0
- package/src/main/api/WebSocketManager.ts +398 -0
- package/src/main/assistant/ContextOptimizer.ts +214 -0
- package/src/main/assistant/PredictedOutputManager.ts +265 -0
- package/src/main/assistant/PromptCacheManager.ts +280 -0
- package/src/main/assistant/PromptOptimizer.ts +746 -0
- package/src/main/assistant/SmartCodeAssistant.ts +234 -0
- package/src/main/auth/SessionManager.ts +415 -0
- package/src/main/automations/AdvancedWebhookSystem.ts +281 -0
- package/src/main/automations/AutomationScheduler.ts +272 -0
- package/src/main/automations/BatchProcessingSystem.ts +207 -0
- package/src/main/automations/BrowserAutomationManager.ts +203 -0
- package/src/main/automations/GitHubActionsManager.ts +151 -0
- package/src/main/automations/GitLabCIManager.ts +206 -0
- package/src/main/automations/PriorityQueueManager.ts +328 -0
- package/src/main/background/BackgroundModeManager.ts +130 -0
- package/src/main/backup/BackupManager.ts +287 -0
- package/src/main/backup/MigrationManager.ts +132 -0
- package/src/main/commands/SlashCommandManager.ts +407 -0
- package/src/main/config/ClaudeMdParser.ts +539 -0
- package/src/main/config/CustomizationManager.ts +493 -0
- package/src/main/config/LaunchConfigManager.ts +212 -0
- package/src/main/config/SettingsManager.ts +163 -0
- package/src/main/connectors/ConnectorManager.ts +175 -0
- package/src/main/connectors/DatabaseConnector.ts +212 -0
- package/src/main/cowork/CoworkManager.ts +431 -0
- package/src/main/evals/AgentEvalFramework.ts +665 -0
- package/src/main/evals/GraderManager.ts +417 -0
- package/src/main/git/GitWorktreeManager.ts +211 -0
- package/src/main/github/GitHubPRMonitor.ts +317 -0
- package/src/main/ide/ContinueInManager.ts +180 -0
- package/src/main/ide/IDEIntegration.ts +288 -0
- package/src/main/integrations/LinearManager.ts +327 -0
- package/src/main/integrations/SlackBotManager.ts +312 -0
- package/src/main/lsp/LSPManager.ts +445 -0
- package/src/main/main.ts +1221 -0
- package/src/main/mcp/MCPConfigurationManager.ts +281 -0
- package/src/main/mcp/MCPManager.ts +799 -0
- package/src/main/mcp/MCPRegistry.ts +273 -0
- package/src/main/monitoring/ErrorRecoveryManager.ts +359 -0
- package/src/main/monitoring/ErrorTracker.ts +60 -0
- package/src/main/monitoring/MetricsCollector.ts +196 -0
- package/src/main/monitoring/TraceGradingSystem.ts +196 -0
- package/src/main/notifications/NotificationManager.ts +96 -0
- package/src/main/pair/AIPairProgramming.ts +290 -0
- package/src/main/plugins/PluginManager.ts +266 -0
- package/src/main/plugins/PluginMarketplace.ts +318 -0
- package/src/main/preload.ts +215 -0
- package/src/main/preview/PreviewSessionManager.ts +186 -0
- package/src/main/providers/AIProviderManager.ts +394 -0
- package/src/main/providers/FineTuningManager.ts +390 -0
- package/src/main/providers/FreeModelsProvider.ts +1156 -0
- package/src/main/realtime/RealtimeManager.ts +147 -0
- package/src/main/remote/CloudEnvironmentManager.ts +253 -0
- package/src/main/remote/RemoteSessionManager.ts +323 -0
- package/src/main/search/DeepResearchManager.ts +458 -0
- package/src/main/search/WebSearchIntegration.ts +203 -0
- package/src/main/security/AdminConsoleManager.ts +244 -0
- package/src/main/security/AuditLogger.ts +143 -0
- package/src/main/security/PermissionManager.ts +184 -0
- package/src/main/security/SSOManager.ts +241 -0
- package/src/main/security/SecurityManager.ts +139 -0
- package/src/main/skills/SkillsManager.ts +218 -0
- package/src/main/ssh/SSHManager.ts +86 -0
- package/src/main/streaming/StreamingManager.ts +306 -0
- package/src/main/sync/CloudSyncManager.ts +532 -0
- package/src/main/verification/AutoVerifyManager.ts +285 -0
- package/src/main/vision/ComputerUseManager.ts +475 -0
- package/src/main/vision/ImageVideoGenerationManager.ts +526 -0
- package/src/main/vision/VisionManager.ts +186 -0
- package/src/renderer/App.tsx +314 -0
- package/src/renderer/components/AdvancedSettingsPanel.tsx +225 -0
- package/src/renderer/components/AgentPanel.tsx +760 -0
- package/src/renderer/components/AppPreview.tsx +220 -0
- package/src/renderer/components/AuditTrailPanel.tsx +148 -0
- package/src/renderer/components/AutomationPanel.tsx +220 -0
- package/src/renderer/components/ChatInterface.tsx +595 -0
- package/src/renderer/components/ChatTab.tsx +296 -0
- package/src/renderer/components/CodeEditor.tsx +257 -0
- package/src/renderer/components/CodeReviewPanel.tsx +256 -0
- package/src/renderer/components/CodeWorkspace.tsx +192 -0
- package/src/renderer/components/CodebaseDashboard.tsx +295 -0
- package/src/renderer/components/ComputerUsePanel.tsx +262 -0
- package/src/renderer/components/ConnectorsPanel.tsx +471 -0
- package/src/renderer/components/ContextMenu.tsx +155 -0
- package/src/renderer/components/ContextUsageDisplay.tsx +248 -0
- package/src/renderer/components/CoworkPanel.tsx +415 -0
- package/src/renderer/components/DiffViewer.tsx +452 -0
- package/src/renderer/components/ErrorBoundary.tsx +273 -0
- package/src/renderer/components/ExtendedThinkingToggle.tsx +244 -0
- package/src/renderer/components/FileAttachments.tsx +247 -0
- package/src/renderer/components/FileExplorer.tsx +242 -0
- package/src/renderer/components/FileExplorerPanel.tsx +302 -0
- package/src/renderer/components/GitPanel.tsx +154 -0
- package/src/renderer/components/Header.tsx +113 -0
- package/src/renderer/components/MCPPanel.tsx +326 -0
- package/src/renderer/components/MentionAutocomplete.tsx +239 -0
- package/src/renderer/components/PermissionPanel.tsx +159 -0
- package/src/renderer/components/PermissionSelector.tsx +203 -0
- package/src/renderer/components/PluginMarketplace.tsx +325 -0
- package/src/renderer/components/PromptOptimizerPanel.tsx +399 -0
- package/src/renderer/components/SearchPanel.tsx +173 -0
- package/src/renderer/components/SearchReplace.tsx +284 -0
- package/src/renderer/components/SessionSidebar.tsx +367 -0
- package/src/renderer/components/SettingsPanel.tsx +426 -0
- package/src/renderer/components/Sidebar.tsx +100 -0
- package/src/renderer/components/SkillsPanel.tsx +245 -0
- package/src/renderer/components/SplitPane.tsx +173 -0
- package/src/renderer/components/Terminal.tsx +190 -0
- package/src/renderer/components/VoiceCommand.tsx +129 -0
- package/src/renderer/components/WorktreePanel.tsx +163 -0
- package/src/renderer/components/ui/AriaComponents.tsx +193 -0
- package/src/renderer/components/ui/Button.tsx +68 -0
- package/src/renderer/components/ui/Card.tsx +102 -0
- package/src/renderer/components/ui/Input.tsx +44 -0
- package/src/renderer/components/ui/Skeleton.tsx +55 -0
- package/src/renderer/components/ui/VirtualList.tsx +196 -0
- package/src/renderer/i18n/I18nProvider.tsx +101 -0
- package/src/renderer/i18n/de.ts +161 -0
- package/src/renderer/i18n/en.ts +163 -0
- package/src/renderer/i18n/es.ts +161 -0
- package/src/renderer/i18n/fr.ts +161 -0
- package/src/renderer/i18n/index.ts +44 -0
- package/src/renderer/index.css +129 -0
- package/src/renderer/lib/accessibility.tsx +287 -0
- package/src/renderer/lib/hooks.ts +304 -0
- package/src/renderer/lib/utils.ts +6 -0
- package/src/renderer/main.tsx +25 -0
- package/src/renderer/styles/minimalist.css +539 -0
- package/src/renderer/sw.ts +180 -0
- package/src/renderer/types.d.ts +138 -0
- package/src/shared/types.ts +813 -0
- package/supabase/schema.sql +234 -0
- package/tailwind.config.js +78 -0
- package/tests/e2e/package.json +15 -0
- package/tests/e2e/playwright.config.ts +31 -0
- package/tests/e2e/specs/app.spec.ts +194 -0
- package/tests/setup.ts +99 -0
- package/tests/unit/AgentOrchestrator.test.ts +274 -0
- package/tests/unit/DatabaseManager.test.ts +262 -0
- package/tests/unit/GitWorktreeManager.test.ts +150 -0
- package/tests/unit/SecurityManager.test.ts +110 -0
- package/tsconfig.main.json +22 -0
- package/tsconfig.renderer.json +27 -0
- package/vite.config.ts +28 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
interface PromptAnalysis {
|
|
4
|
+
originalPrompt: string;
|
|
5
|
+
optimizedPrompt: string;
|
|
6
|
+
improvements: Array<{
|
|
7
|
+
type: string;
|
|
8
|
+
description: string;
|
|
9
|
+
before: string;
|
|
10
|
+
after: string;
|
|
11
|
+
impact: 'high' | 'medium' | 'low';
|
|
12
|
+
}>;
|
|
13
|
+
metrics: {
|
|
14
|
+
clarity: number;
|
|
15
|
+
specificity: number;
|
|
16
|
+
context: number;
|
|
17
|
+
structure: number;
|
|
18
|
+
overall: number;
|
|
19
|
+
};
|
|
20
|
+
estimatedTokens: number;
|
|
21
|
+
suggestions: string[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface PromptTemplate {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
category: string;
|
|
29
|
+
template: string;
|
|
30
|
+
variables: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface PromptOptimizerPanelProps {
|
|
34
|
+
onAnalyze?: (prompt: string) => Promise<PromptAnalysis>;
|
|
35
|
+
onOptimize?: (prompt: string, options?: any) => Promise<PromptAnalysis>;
|
|
36
|
+
onTest?: (prompt: string, input?: string) => Promise<any>;
|
|
37
|
+
templates?: PromptTemplate[];
|
|
38
|
+
onGenerateFromTemplate?: (templateId: string, variables: Record<string, string>) => Promise<string>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const PromptOptimizerPanel: React.FC<PromptOptimizerPanelProps> = ({
|
|
42
|
+
onAnalyze,
|
|
43
|
+
onOptimize,
|
|
44
|
+
onTest,
|
|
45
|
+
templates = [],
|
|
46
|
+
onGenerateFromTemplate,
|
|
47
|
+
}) => {
|
|
48
|
+
const [prompt, setPrompt] = useState('');
|
|
49
|
+
const [analysis, setAnalysis] = useState<PromptAnalysis | null>(null);
|
|
50
|
+
const [isAnalyzing, setIsAnalyzing] = useState(false);
|
|
51
|
+
const [isOptimizing, setIsOptimizing] = useState(false);
|
|
52
|
+
const [showOptimized, setShowOptimized] = useState(false);
|
|
53
|
+
const [selectedTemplate, setSelectedTemplate] = useState<string>('');
|
|
54
|
+
const [templateVars, setTemplateVars] = useState<Record<string, string>>({});
|
|
55
|
+
const [activeTab, setActiveTab] = useState<'analyzer' | 'templates' | 'testing'>('analyzer');
|
|
56
|
+
|
|
57
|
+
const categories = [...new Set(templates.map(t => t.category))];
|
|
58
|
+
|
|
59
|
+
const handleAnalyze = useCallback(async () => {
|
|
60
|
+
if (!prompt || !onAnalyze) return;
|
|
61
|
+
|
|
62
|
+
setIsAnalyzing(true);
|
|
63
|
+
try {
|
|
64
|
+
const result = await onAnalyze(prompt);
|
|
65
|
+
setAnalysis(result);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('Analysis failed:', error);
|
|
68
|
+
} finally {
|
|
69
|
+
setIsAnalyzing(false);
|
|
70
|
+
}
|
|
71
|
+
}, [prompt, onAnalyze]);
|
|
72
|
+
|
|
73
|
+
const handleOptimize = useCallback(async () => {
|
|
74
|
+
if (!prompt || !onOptimize) return;
|
|
75
|
+
|
|
76
|
+
setIsOptimizing(true);
|
|
77
|
+
try {
|
|
78
|
+
const result = await onOptimize(prompt, {
|
|
79
|
+
style: 'detailed',
|
|
80
|
+
addExamples: true,
|
|
81
|
+
addConstraints: true,
|
|
82
|
+
improveStructure: true,
|
|
83
|
+
});
|
|
84
|
+
setAnalysis(result);
|
|
85
|
+
setShowOptimized(true);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error('Optimization failed:', error);
|
|
88
|
+
} finally {
|
|
89
|
+
setIsOptimizing(false);
|
|
90
|
+
}
|
|
91
|
+
}, [prompt, onOptimize]);
|
|
92
|
+
|
|
93
|
+
const handleUseOptimized = useCallback(() => {
|
|
94
|
+
if (analysis?.optimizedPrompt) {
|
|
95
|
+
setPrompt(analysis.optimizedPrompt);
|
|
96
|
+
setShowOptimized(false);
|
|
97
|
+
}
|
|
98
|
+
}, [analysis]);
|
|
99
|
+
|
|
100
|
+
const handleTemplateSelect = useCallback((templateId: string) => {
|
|
101
|
+
setSelectedTemplate(templateId);
|
|
102
|
+
const template = templates.find(t => t.id === templateId);
|
|
103
|
+
if (template) {
|
|
104
|
+
const vars: Record<string, string> = {};
|
|
105
|
+
template.variables.forEach(v => vars[v] = '');
|
|
106
|
+
setTemplateVars(vars);
|
|
107
|
+
}
|
|
108
|
+
}, [templates]);
|
|
109
|
+
|
|
110
|
+
const handleGenerateFromTemplate = useCallback(async () => {
|
|
111
|
+
if (!selectedTemplate || !onGenerateFromTemplate) return;
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const generatedPrompt = await onGenerateFromTemplate(selectedTemplate, templateVars);
|
|
115
|
+
setPrompt(generatedPrompt);
|
|
116
|
+
setSelectedTemplate('');
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error('Template generation failed:', error);
|
|
119
|
+
}
|
|
120
|
+
}, [selectedTemplate, templateVars, onGenerateFromTemplate]);
|
|
121
|
+
|
|
122
|
+
const getMetricColor = (value: number): string => {
|
|
123
|
+
if (value >= 80) return 'text-green-400';
|
|
124
|
+
if (value >= 60) return 'text-yellow-400';
|
|
125
|
+
return 'text-red-400';
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const getImpactColor = (impact: string): string => {
|
|
129
|
+
switch (impact) {
|
|
130
|
+
case 'high': return 'bg-red-500/20 text-red-400 border-red-500/30';
|
|
131
|
+
case 'medium': return 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30';
|
|
132
|
+
default: return 'bg-gray-500/20 text-gray-400 border-gray-500/30';
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<div className="flex flex-col h-full bg-gray-900 text-gray-100 p-4">
|
|
138
|
+
{/* Header */}
|
|
139
|
+
<div className="mb-4">
|
|
140
|
+
<h2 className="text-2xl font-bold mb-2">✨ Prompt Optimizer</h2>
|
|
141
|
+
<p className="text-gray-400 text-sm">
|
|
142
|
+
Analyze, optimize, and test your prompts for better AI responses
|
|
143
|
+
</p>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
{/* Tabs */}
|
|
147
|
+
<div className="flex gap-2 mb-4">
|
|
148
|
+
{(['analyzer', 'templates', 'testing'] as const).map((tab) => (
|
|
149
|
+
<button
|
|
150
|
+
key={tab}
|
|
151
|
+
onClick={() => setActiveTab(tab)}
|
|
152
|
+
className={`px-4 py-2 rounded font-medium transition-colors ${
|
|
153
|
+
activeTab === tab
|
|
154
|
+
? 'bg-blue-600 text-white'
|
|
155
|
+
: 'bg-gray-800 text-gray-400 hover:bg-gray-700'
|
|
156
|
+
}`}
|
|
157
|
+
>
|
|
158
|
+
{tab === 'analyzer' ? '🔍 Analyzer' : tab === 'templates' ? '📋 Templates' : '🧪 Testing'}
|
|
159
|
+
</button>
|
|
160
|
+
))}
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
{/* Analyzer Tab */}
|
|
164
|
+
{activeTab === 'analyzer' && (
|
|
165
|
+
<div className="flex-1 flex flex-col overflow-hidden">
|
|
166
|
+
{/* Prompt Input */}
|
|
167
|
+
<div className="mb-4">
|
|
168
|
+
<label className="block text-sm font-medium mb-2">Your Prompt</label>
|
|
169
|
+
<textarea
|
|
170
|
+
value={prompt}
|
|
171
|
+
onChange={(e) => setPrompt(e.target.value)}
|
|
172
|
+
placeholder="Enter your prompt to analyze and optimize..."
|
|
173
|
+
rows={6}
|
|
174
|
+
className="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-white placeholder-gray-500 focus:outline-none focus:border-blue-500 resize-none font-mono text-sm"
|
|
175
|
+
/>
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
{/* Action Buttons */}
|
|
179
|
+
<div className="flex gap-2 mb-4">
|
|
180
|
+
<button
|
|
181
|
+
onClick={handleAnalyze}
|
|
182
|
+
disabled={!prompt || isAnalyzing}
|
|
183
|
+
className="flex-1 bg-gray-700 hover:bg-gray-600 disabled:bg-gray-800 disabled:cursor-not-allowed text-white py-2 px-4 rounded transition-colors flex items-center justify-center gap-2"
|
|
184
|
+
>
|
|
185
|
+
{isAnalyzing ? '⏳' : '🔍'} Analyze
|
|
186
|
+
</button>
|
|
187
|
+
<button
|
|
188
|
+
onClick={handleOptimize}
|
|
189
|
+
disabled={!prompt || isOptimizing}
|
|
190
|
+
className="flex-1 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-800 disabled:cursor-not-allowed text-white py-2 px-4 rounded transition-colors flex items-center justify-center gap-2"
|
|
191
|
+
>
|
|
192
|
+
{isOptimizing ? '⏳' : '⚡'} Optimize
|
|
193
|
+
</button>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
{/* Results */}
|
|
197
|
+
{analysis && (
|
|
198
|
+
<div className="flex-1 overflow-y-auto">
|
|
199
|
+
{/* Metrics */}
|
|
200
|
+
<div className="bg-gray-800 rounded-lg p-4 mb-4">
|
|
201
|
+
<h3 className="font-semibold mb-3">Quality Metrics</h3>
|
|
202
|
+
<div className="grid grid-cols-2 gap-4">
|
|
203
|
+
{Object.entries(analysis.metrics).map(([key, value]) => (
|
|
204
|
+
<div key={key}>
|
|
205
|
+
<div className="flex justify-between text-sm mb-1">
|
|
206
|
+
<span className="text-gray-400 capitalize">{key}</span>
|
|
207
|
+
<span className={`font-medium ${getMetricColor(value)}`}>{value}%</span>
|
|
208
|
+
</div>
|
|
209
|
+
<div className="w-full bg-gray-700 rounded-full h-2">
|
|
210
|
+
<div
|
|
211
|
+
className={`h-2 rounded-full ${value >= 80 ? 'bg-green-500' : value >= 60 ? 'bg-yellow-500' : 'bg-red-500'}`}
|
|
212
|
+
style={{ width: `${value}%` }}
|
|
213
|
+
/>
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
))}
|
|
217
|
+
</div>
|
|
218
|
+
<div className="mt-3 text-sm text-gray-400">
|
|
219
|
+
Estimated tokens: ~{analysis.estimatedTokens}
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
{/* Improvements */}
|
|
224
|
+
{analysis.improvements.length > 0 && (
|
|
225
|
+
<div className="bg-gray-800 rounded-lg p-4 mb-4">
|
|
226
|
+
<h3 className="font-semibold mb-3">Suggested Improvements</h3>
|
|
227
|
+
<div className="space-y-3">
|
|
228
|
+
{analysis.improvements.map((improvement, index) => (
|
|
229
|
+
<div
|
|
230
|
+
key={index}
|
|
231
|
+
className={`p-3 rounded-lg border ${getImpactColor(improvement.impact)}`}
|
|
232
|
+
>
|
|
233
|
+
<div className="flex items-center gap-2 mb-2">
|
|
234
|
+
<span className="text-xs uppercase font-medium">{improvement.type}</span>
|
|
235
|
+
<span className="text-xs px-2 py-0.5 rounded bg-black/20">{improvement.impact} impact</span>
|
|
236
|
+
</div>
|
|
237
|
+
<p className="text-sm mb-2">{improvement.description}</p>
|
|
238
|
+
{showOptimized && (
|
|
239
|
+
<div className="text-xs font-mono bg-black/20 p-2 rounded">
|
|
240
|
+
<div className="text-red-400 line-through mb-1">{improvement.before.substring(0, 50)}...</div>
|
|
241
|
+
<div className="text-green-400">{improvement.after.substring(0, 50)}...</div>
|
|
242
|
+
</div>
|
|
243
|
+
)}
|
|
244
|
+
</div>
|
|
245
|
+
))}
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
248
|
+
)}
|
|
249
|
+
|
|
250
|
+
{/* Suggestions */}
|
|
251
|
+
{analysis.suggestions.length > 0 && (
|
|
252
|
+
<div className="bg-gray-800 rounded-lg p-4 mb-4">
|
|
253
|
+
<h3 className="font-semibold mb-3">Additional Suggestions</h3>
|
|
254
|
+
<ul className="space-y-2">
|
|
255
|
+
{analysis.suggestions.map((suggestion, index) => (
|
|
256
|
+
<li key={index} className="flex items-start gap-2 text-sm">
|
|
257
|
+
<span className="text-blue-400">•</span>
|
|
258
|
+
<span className="text-gray-300">{suggestion}</span>
|
|
259
|
+
</li>
|
|
260
|
+
))}
|
|
261
|
+
</ul>
|
|
262
|
+
</div>
|
|
263
|
+
)}
|
|
264
|
+
|
|
265
|
+
{/* Optimized Prompt */}
|
|
266
|
+
{showOptimized && analysis.optimizedPrompt !== analysis.originalPrompt && (
|
|
267
|
+
<div className="bg-gray-800 rounded-lg p-4 mb-4">
|
|
268
|
+
<div className="flex justify-between items-center mb-3">
|
|
269
|
+
<h3 className="font-semibold">Optimized Prompt</h3>
|
|
270
|
+
<button
|
|
271
|
+
onClick={handleUseOptimized}
|
|
272
|
+
className="text-sm bg-green-600 hover:bg-green-700 text-white px-3 py-1 rounded transition-colors"
|
|
273
|
+
>
|
|
274
|
+
Use This Prompt
|
|
275
|
+
</button>
|
|
276
|
+
</div>
|
|
277
|
+
<pre className="text-sm font-mono bg-black/30 p-3 rounded overflow-x-auto whitespace-pre-wrap">
|
|
278
|
+
{analysis.optimizedPrompt}
|
|
279
|
+
</pre>
|
|
280
|
+
</div>
|
|
281
|
+
)}
|
|
282
|
+
</div>
|
|
283
|
+
)}
|
|
284
|
+
</div>
|
|
285
|
+
)}
|
|
286
|
+
|
|
287
|
+
{/* Templates Tab */}
|
|
288
|
+
{activeTab === 'templates' && (
|
|
289
|
+
<div className="flex-1 flex flex-col overflow-hidden">
|
|
290
|
+
<div className="mb-4">
|
|
291
|
+
<label className="block text-sm font-medium mb-2">Select a Template</label>
|
|
292
|
+
<select
|
|
293
|
+
value={selectedTemplate}
|
|
294
|
+
onChange={(e) => handleTemplateSelect(e.target.value)}
|
|
295
|
+
className="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-white focus:outline-none focus:border-blue-500"
|
|
296
|
+
>
|
|
297
|
+
<option value="">Choose a template...</option>
|
|
298
|
+
{templates.map((template) => (
|
|
299
|
+
<option key={template.id} value={template.id}>
|
|
300
|
+
{template.name} - {template.description}
|
|
301
|
+
</option>
|
|
302
|
+
))}
|
|
303
|
+
</select>
|
|
304
|
+
</div>
|
|
305
|
+
|
|
306
|
+
{selectedTemplate && (
|
|
307
|
+
<div className="flex-1 overflow-y-auto">
|
|
308
|
+
{(() => {
|
|
309
|
+
const template = templates.find(t => t.id === selectedTemplate);
|
|
310
|
+
if (!template) return null;
|
|
311
|
+
|
|
312
|
+
return (
|
|
313
|
+
<>
|
|
314
|
+
<div className="bg-gray-800 rounded-lg p-4 mb-4">
|
|
315
|
+
<h3 className="font-semibold mb-2">{template.name}</h3>
|
|
316
|
+
<p className="text-sm text-gray-400 mb-3">{template.description}</p>
|
|
317
|
+
<div className="flex flex-wrap gap-2">
|
|
318
|
+
{template.variables.map(v => (
|
|
319
|
+
<span key={v} className="text-xs bg-blue-500/20 text-blue-400 px-2 py-1 rounded">
|
|
320
|
+
{`{{${v}}}`}
|
|
321
|
+
</span>
|
|
322
|
+
))}
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|
|
325
|
+
|
|
326
|
+
<div className="mb-4">
|
|
327
|
+
<h4 className="text-sm font-medium mb-2">Fill Variables</h4>
|
|
328
|
+
{template.variables.map(variable => (
|
|
329
|
+
<div key={variable} className="mb-3">
|
|
330
|
+
<label className="block text-xs text-gray-400 mb-1 capitalize">
|
|
331
|
+
{variable.replace(/([A-Z])/g, ' $1').trim()}
|
|
332
|
+
</label>
|
|
333
|
+
<input
|
|
334
|
+
type="text"
|
|
335
|
+
value={templateVars[variable] || ''}
|
|
336
|
+
onChange={(e) => setTemplateVars(prev => ({ ...prev, [variable]: e.target.value }))}
|
|
337
|
+
className="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-white text-sm focus:outline-none focus:border-blue-500"
|
|
338
|
+
placeholder={`Enter ${variable}...`}
|
|
339
|
+
/>
|
|
340
|
+
</div>
|
|
341
|
+
))}
|
|
342
|
+
</div>
|
|
343
|
+
|
|
344
|
+
<button
|
|
345
|
+
onClick={handleGenerateFromTemplate}
|
|
346
|
+
disabled={Object.values(templateVars).some(v => !v)}
|
|
347
|
+
className="w-full bg-blue-600 hover:bg-blue-700 disabled:bg-gray-700 disabled:cursor-not-allowed text-white py-2 px-4 rounded transition-colors"
|
|
348
|
+
>
|
|
349
|
+
Generate Prompt
|
|
350
|
+
</button>
|
|
351
|
+
</>
|
|
352
|
+
);
|
|
353
|
+
})()}
|
|
354
|
+
</div>
|
|
355
|
+
)}
|
|
356
|
+
</div>
|
|
357
|
+
)}
|
|
358
|
+
|
|
359
|
+
{/* Testing Tab */}
|
|
360
|
+
{activeTab === 'testing' && (
|
|
361
|
+
<div className="flex-1 flex flex-col overflow-hidden">
|
|
362
|
+
<div className="mb-4">
|
|
363
|
+
<label className="block text-sm font-medium mb-2">Prompt to Test</label>
|
|
364
|
+
<textarea
|
|
365
|
+
value={prompt}
|
|
366
|
+
onChange={(e) => setPrompt(e.target.value)}
|
|
367
|
+
placeholder="Enter the prompt you want to test..."
|
|
368
|
+
rows={4}
|
|
369
|
+
className="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-white placeholder-gray-500 focus:outline-none focus:border-blue-500 resize-none font-mono text-sm"
|
|
370
|
+
/>
|
|
371
|
+
</div>
|
|
372
|
+
|
|
373
|
+
<div className="mb-4">
|
|
374
|
+
<label className="block text-sm font-medium mb-2">Test Input (Optional)</label>
|
|
375
|
+
<textarea
|
|
376
|
+
placeholder="Additional context or test data..."
|
|
377
|
+
rows={3}
|
|
378
|
+
className="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-white placeholder-gray-500 focus:outline-none focus:border-blue-500 resize-none text-sm"
|
|
379
|
+
/>
|
|
380
|
+
</div>
|
|
381
|
+
|
|
382
|
+
<button
|
|
383
|
+
onClick={() => onTest?.(prompt)}
|
|
384
|
+
disabled={!prompt}
|
|
385
|
+
className="w-full bg-purple-600 hover:bg-purple-700 disabled:bg-gray-700 disabled:cursor-not-allowed text-white py-2 px-4 rounded transition-colors flex items-center justify-center gap-2"
|
|
386
|
+
>
|
|
387
|
+
🧪 Run Test
|
|
388
|
+
</button>
|
|
389
|
+
|
|
390
|
+
<div className="mt-4 text-center text-gray-500 text-sm">
|
|
391
|
+
Test results will show response quality, relevance, and completeness metrics
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
394
|
+
)}
|
|
395
|
+
</div>
|
|
396
|
+
);
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
export default PromptOptimizerPanel;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import React, { useState, useCallback, useEffect } from 'react';
|
|
2
|
+
import { Search, FileText, Loader2, X, ChevronRight } from 'lucide-react';
|
|
3
|
+
import { debounce } from 'lodash';
|
|
4
|
+
|
|
5
|
+
interface SearchResult {
|
|
6
|
+
path: string;
|
|
7
|
+
matches: Array<{ line: number; content: string }>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface SearchPanelProps {
|
|
11
|
+
rootPath: string;
|
|
12
|
+
onFileSelect: (path: string) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const SearchPanel: React.FC<SearchPanelProps> = ({ rootPath, onFileSelect }) => {
|
|
16
|
+
const [query, setQuery] = useState('');
|
|
17
|
+
const [results, setResults] = useState<SearchResult[]>([]);
|
|
18
|
+
const [isSearching, setIsSearching] = useState(false);
|
|
19
|
+
const [pattern, setPattern] = useState('');
|
|
20
|
+
const [selectedResult, setSelectedResult] = useState<number | null>(null);
|
|
21
|
+
|
|
22
|
+
const performSearch = useCallback(
|
|
23
|
+
debounce(async (searchQuery: string) => {
|
|
24
|
+
if (!searchQuery.trim() || searchQuery.length < 2) {
|
|
25
|
+
setResults([]);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
setIsSearching(true);
|
|
30
|
+
try {
|
|
31
|
+
const searchResults = await window.electronAPI.search.files({
|
|
32
|
+
query: searchQuery,
|
|
33
|
+
path: rootPath,
|
|
34
|
+
pattern: pattern || undefined
|
|
35
|
+
});
|
|
36
|
+
setResults(searchResults);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error('Search failed:', error);
|
|
39
|
+
}
|
|
40
|
+
setIsSearching(false);
|
|
41
|
+
}, 300),
|
|
42
|
+
[rootPath, pattern]
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
performSearch(query);
|
|
47
|
+
}, [query, performSearch]);
|
|
48
|
+
|
|
49
|
+
const clearSearch = () => {
|
|
50
|
+
setQuery('');
|
|
51
|
+
setResults([]);
|
|
52
|
+
setSelectedResult(null);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const highlightMatch = (content: string, searchTerm: string) => {
|
|
56
|
+
const parts = content.split(new RegExp(`(${searchTerm})`, 'gi'));
|
|
57
|
+
return parts.map((part, i) =>
|
|
58
|
+
part.toLowerCase() === searchTerm.toLowerCase() ? (
|
|
59
|
+
<mark key={i} className="bg-yellow-500/30 text-yellow-900 dark:text-yellow-100">
|
|
60
|
+
{part}
|
|
61
|
+
</mark>
|
|
62
|
+
) : (
|
|
63
|
+
part
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<div className="flex flex-col h-full bg-card">
|
|
70
|
+
{/* Search Header */}
|
|
71
|
+
<div className="p-4 border-b border-border">
|
|
72
|
+
<div className="relative mb-3">
|
|
73
|
+
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
|
|
74
|
+
<input
|
|
75
|
+
type="text"
|
|
76
|
+
value={query}
|
|
77
|
+
onChange={e => setQuery(e.target.value)}
|
|
78
|
+
placeholder="Search in files..."
|
|
79
|
+
className="w-full pl-10 pr-10 py-2 bg-background border border-input rounded-md"
|
|
80
|
+
autoFocus
|
|
81
|
+
/>
|
|
82
|
+
{query && (
|
|
83
|
+
<button
|
|
84
|
+
onClick={clearSearch}
|
|
85
|
+
className="absolute right-3 top-1/2 -translate-y-1/2 p-1 hover:bg-muted rounded"
|
|
86
|
+
>
|
|
87
|
+
<X className="w-3 h-3" />
|
|
88
|
+
</button>
|
|
89
|
+
)}
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<div className="flex gap-2">
|
|
93
|
+
<input
|
|
94
|
+
type="text"
|
|
95
|
+
value={pattern}
|
|
96
|
+
onChange={e => setPattern(e.target.value)}
|
|
97
|
+
placeholder="File pattern (e.g., *.js)"
|
|
98
|
+
className="flex-1 px-3 py-1.5 bg-background border border-input rounded-md text-sm"
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
{/* Results */}
|
|
104
|
+
<div className="flex-1 overflow-auto">
|
|
105
|
+
{isSearching ? (
|
|
106
|
+
<div className="flex items-center justify-center py-12">
|
|
107
|
+
<Loader2 className="w-6 h-6 animate-spin text-muted-foreground" />
|
|
108
|
+
</div>
|
|
109
|
+
) : results.length > 0 ? (
|
|
110
|
+
<div className="divide-y divide-border">
|
|
111
|
+
{results.map((result, resultIndex) => (
|
|
112
|
+
<div key={result.path} className="p-3 hover:bg-muted/50">
|
|
113
|
+
<button
|
|
114
|
+
onClick={() => {
|
|
115
|
+
setSelectedResult(resultIndex);
|
|
116
|
+
onFileSelect(result.path);
|
|
117
|
+
}}
|
|
118
|
+
className="flex items-center gap-2 text-sm font-medium text-primary hover:underline mb-2"
|
|
119
|
+
>
|
|
120
|
+
<FileText className="w-4 h-4" />
|
|
121
|
+
{result.path.replace(rootPath, '')}
|
|
122
|
+
<span className="text-xs text-muted-foreground">
|
|
123
|
+
({result.matches.length} matches)
|
|
124
|
+
</span>
|
|
125
|
+
</button>
|
|
126
|
+
|
|
127
|
+
<div className="space-y-1">
|
|
128
|
+
{result.matches.slice(0, 3).map((match, matchIndex) => (
|
|
129
|
+
<div
|
|
130
|
+
key={matchIndex}
|
|
131
|
+
className="flex items-start gap-3 px-2 py-1.5 text-sm text-muted-foreground hover:bg-muted rounded cursor-pointer"
|
|
132
|
+
onClick={() => onFileSelect(result.path)}
|
|
133
|
+
>
|
|
134
|
+
<span className="text-xs text-muted-foreground w-8 flex-shrink-0">
|
|
135
|
+
{match.line}
|
|
136
|
+
</span>
|
|
137
|
+
<code className="flex-1 truncate font-mono text-xs">
|
|
138
|
+
{highlightMatch(match.content, query)}
|
|
139
|
+
</code>
|
|
140
|
+
</div>
|
|
141
|
+
))}
|
|
142
|
+
{result.matches.length > 3 && (
|
|
143
|
+
<div className="px-2 py-1 text-xs text-muted-foreground">
|
|
144
|
+
+{result.matches.length - 3} more matches
|
|
145
|
+
</div>
|
|
146
|
+
)}
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
))}
|
|
150
|
+
</div>
|
|
151
|
+
) : query.length >= 2 ? (
|
|
152
|
+
<div className="flex flex-col items-center justify-center py-12 text-muted-foreground">
|
|
153
|
+
<Search className="w-12 h-12 mb-2 opacity-30" />
|
|
154
|
+
<p className="text-sm">No results found</p>
|
|
155
|
+
</div>
|
|
156
|
+
) : (
|
|
157
|
+
<div className="flex flex-col items-center justify-center py-12 text-muted-foreground">
|
|
158
|
+
<Search className="w-12 h-12 mb-2 opacity-30" />
|
|
159
|
+
<p className="text-sm">Type to search</p>
|
|
160
|
+
<p className="text-xs mt-1">Search across all files in the workspace</p>
|
|
161
|
+
</div>
|
|
162
|
+
)}
|
|
163
|
+
</div>
|
|
164
|
+
|
|
165
|
+
{/* Status Bar */}
|
|
166
|
+
{results.length > 0 && (
|
|
167
|
+
<div className="px-4 py-2 border-t border-border text-xs text-muted-foreground">
|
|
168
|
+
{results.length} files with {results.reduce((sum, r) => sum + r.matches.length, 0)} matches
|
|
169
|
+
</div>
|
|
170
|
+
)}
|
|
171
|
+
</div>
|
|
172
|
+
);
|
|
173
|
+
};
|