Files
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
7.8 KiB
JSON

{"repo": "chris-davisson/ai-pentesting", "files": {"frontend/src/components/settings/ProviderSelect.jsx": {"9dbd81e1318e64afe12075d0a99c13a0e7cf7e83": {"t": 1786068460.45591, "n": 7523, "h": "ee4c97f5505bb3cc", "c": "import { useState, useEffect, useCallback } from 'react'\nimport { api, apiPut } from '../../api'\n\nconst PROVIDERS = {\n deepseek: {\n label: 'DeepSeek (API)',\n backend: 'api',\n model: 'deepseek-chat',\n host: 'https://api.deepseek.com',\n },\n local: {\n label: 'Local (vLLM)',\n backend: 'vllm',\n model: 'Qwen/Qwen2.5-7B-Instruct',\n host: '', // filled from IP/port inputs\n },\n ollama: {\n label: 'Local (Ollama)',\n backend: 'ollama',\n model: 'llama3',\n host: '', // filled from IP/port inputs\n },\n}\n\nconst DEFAULT_LOCAL_IP = 'localhost'\nconst DEFAULT_LOCAL_PORT = '8000'\n\nexport default function ProviderSelect() {\n const [provider, setProvider] = useState('deepseek')\n const [localIp, setLocalIp] = useState(DEFAULT_LOCAL_IP)\n const [localPort, setLocalPort] = useState(DEFAULT_LOCAL_PORT)\n const [localModel, setLocalModel] = useState(PROVIDERS.local.model)\n const [apiKey, setApiKey] = useState('')\n const [status, setStatus] = useState(null) // null | 'saving' | 'saved' | 'error'\n const [ollamaLocal, setOllamaLocal] = useState([]) // pulled models\n const [ollamaLibrary, setOllamaLibrary] = useState([]) // available to pull\n const [ollamaLoading, setOllamaLoading] = useState(false)\n const [customModel, setCustomModel] = useState(false) // typing a custom model name\n\n const fetchOllamaModels = useCallback((ip, port) => {\n const host = `http://${ip || localIp}:${port || localPort}`\n setOllamaLoading(true)\n api(`/ollama/models?host=${encodeURIComponent(host)}`)\n .then(data => {\n setOllamaLocal(data.local || [])\n setOllamaLibrary(data.library || [])\n })\n .catch(() => {\n setOllamaLocal([])\n setOllamaLibrary([])\n })\n .finally(() => setOllamaLoading(false))\n }, [localIp, localPort])\n\n // Load current settings on mount\n useEffect(() => {\n api('/settings').then(data => {\n if (data.backend === 'api') {\n setProvider('deepseek')\n } else if (data.backend === 'ollama') {\n setProvider('ollama')\n let ip = DEFAULT_LOCAL_IP, port = '11434'\n try {\n const url = new URL(data.host)\n ip = url.hostname\n port = url.port || '11434'\n } catch { /* keep defaults */ }\n setLocalIp(ip)\n setLocalPort(port)\n if (data.model) setLocalModel(data.model)\n // Fetch available models from this Ollama instance\n fetchOllamaModels(ip, port)\n } else {\n setProvider('local')\n try {\n const url = new URL(data.host)\n setLocalIp(url.hostname)\n setLocalPort(url.port || '8000')\n } catch {\n // keep defaults\n }\n if (data.model) setLocalModel(data.model)\n }\n }).catch(() => {})\n }, [fetchOllamaModels])\n\n const save = async () => {\n setStatus('saving')\n try {\n let body\n if (provider === 'deepseek') {\n body = {\n backend: 'api',\n model: PROVIDERS.deepseek.model,\n host: PROVIDERS.deepseek.host,\n api_key: apiKey,\n }\n } else {\n body = {\n backend: PROVIDERS[provider].backend,\n model: localModel,\n host: `http://${localIp}:${localPort}`,\n api_key: 'EMPTY',\n }\n }\n await apiPut('/settings', body)\n setStatus('saved')\n setTimeout(() => setStatus(null), 2000)\n } catch {\n setStatus('error')\n setTimeout(() => setStatus(null), 3000)\n }\n }\n\n return (\n <div className=\"provider-select\">\n <select\n className=\"provider-dropdown\"\n value={provider}\n onChange={(e) => {\n const v = e.target.value\n setProvider(v)\n setStatus(null)\n setCustomModel(false)\n if (v === 'ollama') {\n setLocalPort('11434')\n setLocalModel(PROVIDERS.ollama.model)\n fetchOllamaModels(localIp, '11434')\n }\n if (v === 'local') { setLocalPort('8000'); setLocalModel(PROVIDERS.local.model) }\n }}\n >\n {Object.entries(PROVIDERS).map(([key, p]) => (\n <option key={key} value={key}>{p.label}</option>\n ))}\n </select>\n\n {(provider === 'local' || provider === 'ollama') && (\n <div className=\"provider-fields\">\n <input\n className=\"provider-input\"\n type=\"text\"\n value={localIp}\n onChange={(e) => setLocalIp(e.target.value)}\n placeholder=\"IP address\"\n />\n <span className=\"provider-colon\">:</span>\n <input\n className=\"provider-input provider-port\"\n type=\"text\"\n value={localPort}\n onChange={(e) => setLocalPort(e.target.value)}\n placeholder=\"Port\"\n />\n {provider === 'ollama' && !customModel ? (\n <div className=\"model-select-group\">\n <select\n className=\"provider-input provider-model\"\n value={localModel}\n onChange={(e) => {\n if (e.target.value === '__custom__') {\n setCustomModel(true)\n setLocalModel('')\n } else {\n setLocalModel(e.target.value)\n }\n }}\n >\n {ollamaLocal.length > 0 && (\n <optgroup label=\"Pulled (local)\">\n {ollamaLocal.map(m => <option key={m} value={m}>{m}</option>)}\n </optgroup>\n )}\n {ollamaLibrary.length > 0 && (\n <optgroup label=\"Available to pull\">\n {ollamaLibrary.map(m => <option key={m} value={m}>{m}</option>)}\n </optgroup>\n )}\n <option value=\"__custom__\">Custom...</option>\n </select>\n <button\n className=\"btn btn-secondary btn-xs\"\n onClick={() => fetchOllamaModels()}\n disabled={ollamaLoading}\n title=\"Refresh model list\"\n >\n {ollamaLoading ? '...' : '\\u21BB'}\n </button>\n </div>\n ) : (\n <div className=\"model-select-group\">\n <input\n className=\"provider-input provider-model\"\n type=\"text\"\n value={localModel}\n onChange={(e) => setLocalModel(e.target.value)}\n placeholder=\"Model name\"\n />\n {provider === 'ollama' && (\n <button\n className=\"btn btn-secondary btn-xs\"\n onClick={() => { setCustomModel(false); fetchOllamaModels() }}\n title=\"Back to model list\"\n >\n List\n </button>\n )}\n </div>\n )}\n </div>\n )}\n\n {provider === 'deepseek' && (\n <div className=\"provider-fields\">\n <input\n className=\"provider-input provider-key\"\n type=\"password\"\n value={apiKey}\n onChange={(e) => setApiKey(e.target.value)}\n placeholder=\"API key (leave blank to keep current)\"\n />\n </div>\n )}\n\n <button\n className=\"btn btn-primary btn-sm\"\n onClick={save}\n disabled={status === 'saving'}\n >\n {status === 'saving' ? 'Saving...' : status === 'saved' ? 'Saved' : status === 'error' ? 'Error' : 'Apply'}\n </button>\n </div>\n )\n}\n"}}}}