Rust (Axum) + Vue 3 + SQLite. Features: - Project CRUD REST API with proper error handling - Per-project agent loop (mpsc + broadcast channels) - LLM-driven plan generation and replan on user feedback - SSH command execution with status streaming - WebSocket real-time updates to frontend - Four-zone UI: requirement, plan (left), execution (right), comment Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
70 lines
1.5 KiB
TypeScript
70 lines
1.5 KiB
TypeScript
export interface WsPlanUpdate {
|
|
type: 'PlanUpdate'
|
|
workflow_id: string
|
|
steps: { order: number; description: string; command: string }[]
|
|
}
|
|
|
|
export interface WsStepStatusUpdate {
|
|
type: 'StepStatusUpdate'
|
|
step_id: string
|
|
status: string
|
|
output: string
|
|
}
|
|
|
|
export interface WsWorkflowStatusUpdate {
|
|
type: 'WorkflowStatusUpdate'
|
|
workflow_id: string
|
|
status: string
|
|
}
|
|
|
|
export interface WsError {
|
|
type: 'Error'
|
|
message: string
|
|
}
|
|
|
|
export type WsMessage = WsPlanUpdate | WsStepStatusUpdate | WsWorkflowStatusUpdate | WsError
|
|
|
|
export type WsHandler = (msg: WsMessage) => void
|
|
|
|
export function connectWs(projectId: string, onMessage: WsHandler): { close: () => void } {
|
|
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:'
|
|
const url = `${proto}//${location.host}/ws/${projectId}`
|
|
let ws: WebSocket | null = null
|
|
let reconnectTimer: ReturnType<typeof setTimeout> | null = null
|
|
let closed = false
|
|
|
|
function connect() {
|
|
if (closed) return
|
|
ws = new WebSocket(url)
|
|
|
|
ws.onmessage = (e) => {
|
|
try {
|
|
const msg: WsMessage = JSON.parse(e.data)
|
|
onMessage(msg)
|
|
} catch {
|
|
// ignore malformed messages
|
|
}
|
|
}
|
|
|
|
ws.onclose = () => {
|
|
if (!closed) {
|
|
reconnectTimer = setTimeout(connect, 2000)
|
|
}
|
|
}
|
|
|
|
ws.onerror = () => {
|
|
ws?.close()
|
|
}
|
|
}
|
|
|
|
connect()
|
|
|
|
return {
|
|
close() {
|
|
closed = true
|
|
if (reconnectTimer) clearTimeout(reconnectTimer)
|
|
ws?.close()
|
|
},
|
|
}
|
|
}
|