aura-ai
Version:
AI-powered marketing strategist CLI tool for developers
88 lines (73 loc) • 2.08 kB
JavaScript
import express from 'express'
import expressWs from 'express-ws'
import pty from 'node-pty'
import { fileURLToPath } from 'url'
import { dirname, join } from 'path'
import fs from 'fs'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const app = express()
const wsInstance = expressWs(app)
// 提供靜態檔案
app.use(express.static(join(__dirname, 'public')))
// 儲存所有的終端實例
const terminals = {}
let terminalId = 0
// WebSocket 端點
app.ws('/terminal', (ws, req) => {
const id = terminalId++
console.log(`Terminal ${id} connected`)
// 啟動 Ink 應用
const shell = process.platform === 'win32' ? 'powershell.exe' : 'bash'
const term = pty.spawn('node', ['--no-warnings', join(__dirname, '../../dist/rina.js')], {
name: 'xterm-color',
cols: 80,
rows: 30,
cwd: process.cwd(),
env: process.env
})
terminals[id] = term
// 將終端輸出發送到前端
term.onData((data) => {
try {
ws.send(JSON.stringify({ type: 'output', data }))
} catch (ex) {
// 客戶端可能已斷線
}
})
// 處理前端輸入
ws.on('message', (msg) => {
try {
const message = JSON.parse(msg)
if (message.type === 'input') {
term.write(message.data)
} else if (message.type === 'resize') {
term.resize(message.cols, message.rows)
}
} catch (ex) {
console.error('Error handling message:', ex)
}
})
// 清理
ws.on('close', () => {
console.log(`Terminal ${id} disconnected`)
term.kill()
delete terminals[id]
})
})
// 健康檢查端點
app.get('/health', (req, res) => {
res.json({
status: 'ok',
terminals: Object.keys(terminals).length
})
})
// 主頁面
app.get('/', (req, res) => {
res.sendFile(join(__dirname, 'public', 'index.html'))
})
const PORT = process.env.PORT || 3001
app.listen(PORT, () => {
console.log(`🌐 Aura Web Terminal running at http://localhost:${PORT}`)
console.log(`📡 WebSocket endpoint: ws://localhost:${PORT}/terminal`)
})