All checks were successful
Beta Release / beta (push) Successful in 38s
- Config: sidebar navigation with 5 panels (Profile, AI Providers, Updates, Locale, Skills) - Dashboard: remove duplicated system overview section, keep workflows and activity log - New CSS for config window layout, cards, provider cards, update rows - Add i18n panel keys (FR/EN) 💾 Generated with Crush Assisted-by: GLM-5-Turbo via Crush <crush@charm.land>
77 lines
3.2 KiB
JavaScript
77 lines
3.2 KiB
JavaScript
const API_BASE = '/api'
|
|
|
|
async function request(path, options = {}) {
|
|
const res = await fetch(`${API_BASE}${path}`, {
|
|
headers: { 'Content-Type': 'application/json' },
|
|
...options,
|
|
})
|
|
if (!res.ok) {
|
|
const err = await res.json().catch(() => ({ error: res.statusText }))
|
|
throw new Error(err.error || res.statusText)
|
|
}
|
|
return res.json()
|
|
}
|
|
|
|
const api = {
|
|
getInfo: () => request('/info'),
|
|
getSystem: () => request('/system'),
|
|
getTools: () => request('/tools'),
|
|
getConfig: () => request('/config'),
|
|
getProviders: () => request('/providers'),
|
|
getSkills: () => request('/skills'),
|
|
getLSP: () => request('/lsp'),
|
|
getMCP: () => request('/mcp'),
|
|
getUpdates: () => request('/updates'),
|
|
runScan: () => request('/scan', { method: 'POST' }),
|
|
installTools: (tools) => request('/install', { method: 'POST', body: JSON.stringify({ tools }) }),
|
|
configureMCP: () => request('/mcp/configure', { method: 'POST' }),
|
|
savePreferences: (prefs) => request('/preferences', { method: 'PUT', body: JSON.stringify(prefs) }),
|
|
saveProfile: (profile) => request('/config/profile', { method: 'PUT', body: JSON.stringify(profile) }),
|
|
saveProvider: (provider) => request('/config/provider', { method: 'PUT', body: JSON.stringify(provider) }),
|
|
runUpdate: (tool) => request('/update/run', { method: 'POST', body: JSON.stringify({ tool: tool || '' }) }),
|
|
runCommand: (command, cwd) => request('/terminal', { method: 'POST', body: JSON.stringify({ command, cwd }) }),
|
|
getTerminalSessions: () => request('/terminal/sessions'),
|
|
addSSHConnection: (conn) => request('/terminal/sessions', { method: 'POST', body: JSON.stringify(conn) }),
|
|
deleteSSHConnection: (name) => request(`/terminal/sessions/${encodeURIComponent(name)}`, { method: 'DELETE' }),
|
|
getChatHistory: () => request('/chat/history'),
|
|
clearChat: () => request('/chat/clear', { method: 'POST' }),
|
|
sendChat: (message, stream = true) => {
|
|
if (!stream) {
|
|
return request('/chat', { method: 'POST', body: JSON.stringify({ message, stream: false }) })
|
|
}
|
|
return new Promise((resolve, reject) => {
|
|
fetch(`${API_BASE}/chat`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ message, stream: true }),
|
|
}).then(async (res) => {
|
|
if (!res.ok) {
|
|
const err = await res.json().catch(() => ({ error: res.statusText }))
|
|
reject(new Error(err.error || res.statusText))
|
|
return
|
|
}
|
|
const reader = res.body.getReader()
|
|
const decoder = new TextDecoder()
|
|
let full = ''
|
|
while (true) {
|
|
const { done, value } = await reader.read()
|
|
if (done) break
|
|
const text = decoder.decode(value, { stream: true })
|
|
for (const line of text.split('\n')) {
|
|
if (!line.startsWith('data: ')) continue
|
|
try {
|
|
const data = JSON.parse(line.slice(6))
|
|
if (data.error) { reject(new Error(data.error)); return }
|
|
if (data.done) { resolve(full); return }
|
|
if (data.content) full += data.content
|
|
} catch {}
|
|
}
|
|
}
|
|
resolve(full)
|
|
}).catch(reject)
|
|
})
|
|
},
|
|
}
|
|
|
|
export default api
|