Files
cherry-studio/cagents/python-cli-web-poc/public/script.js
T
Vaayne 75766dbfdc feat: Add POC command page structure and routing
- Created CommandPocPage.tsx with basic layout structure
- Added POC-specific TypeScript interfaces and types
- Implemented basic UI components: PocHeader, PocMessageList, PocMessageBubble, PocCommandInput, PocStatusBar
- Added /command-poc route to Router.tsx
- Set up component folder structure following PRD specifications

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-03 11:43:02 +08:00

222 lines
5.6 KiB
JavaScript

class PythonWebInterface {
constructor() {
this.ws = null
this.currentSessionId = null
this.isConnected = false
this.isRunning = false
this.initializeElements()
this.setupEventListeners()
this.connect()
}
initializeElements() {
this.statusIndicator = document.getElementById('status-indicator')
this.statusText = document.getElementById('status-text')
this.output = document.getElementById('output')
this.commandInput = document.getElementById('command-input')
this.userInput = document.getElementById('user-input')
this.userInputContainer = document.getElementById('user-input-container')
this.runBtn = document.getElementById('run-btn')
this.killBtn = document.getElementById('kill-btn')
this.sendBtn = document.getElementById('send-btn')
}
setupEventListeners() {
this.runBtn.addEventListener('click', () => this.runCommand())
this.killBtn.addEventListener('click', () => this.killSession())
this.sendBtn.addEventListener('click', () => this.sendInput())
this.commandInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && !this.isRunning) {
this.runCommand()
}
})
this.userInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
this.sendInput()
}
})
}
connect() {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
const wsUrl = `${protocol}//${window.location.host}`
this.ws = new WebSocket(wsUrl)
this.ws.onopen = () => {
this.isConnected = true
this.updateStatus('Connected', true)
this.addSystemMessage('Connected to server')
}
this.ws.onclose = () => {
this.isConnected = false
this.updateStatus('Disconnected', false)
this.addSystemMessage('Disconnected from server. Attempting to reconnect...')
// Attempt to reconnect after 3 seconds
setTimeout(() => {
if (!this.isConnected) {
this.connect()
}
}, 3000)
}
this.ws.onerror = (error) => {
this.addErrorMessage('WebSocket error occurred')
}
this.ws.onmessage = (event) => {
this.handleMessage(JSON.parse(event.data))
}
}
handleMessage(data) {
switch (data.type) {
case 'command_started':
this.isRunning = true
this.currentSessionId = data.sessionId
this.updateUIState()
this.showUserInput()
this.addSystemMessage(`Started: ${data.command}`)
break
case 'output':
this.addOutput(data.data, data.stream === 'stderr')
break
case 'command_finished':
this.isRunning = false
this.currentSessionId = null
this.updateUIState()
this.hideUserInput()
this.addSystemMessage(`Process finished with exit code: ${data.exitCode}`)
break
case 'error':
this.addErrorMessage(data.message)
this.isRunning = false
this.currentSessionId = null
this.updateUIState()
this.hideUserInput()
break
}
}
runCommand() {
const command = this.commandInput.value.trim()
if (!command || !this.isConnected || this.isRunning) return
this.addCommandMessage(command)
const sessionId = 'session_' + Date.now()
this.ws.send(
JSON.stringify({
type: 'run_command',
command: command,
sessionId: sessionId
})
)
this.commandInput.value = ''
}
sendInput() {
const input = this.userInput.value
if (!input || !this.currentSessionId) return
this.addInputMessage(input)
this.ws.send(
JSON.stringify({
type: 'send_input',
input: input,
sessionId: this.currentSessionId
})
)
this.userInput.value = ''
}
killSession() {
if (this.currentSessionId) {
this.ws.send(
JSON.stringify({
type: 'kill_session',
sessionId: this.currentSessionId
})
)
}
}
updateStatus(text, connected) {
this.statusText.textContent = text
this.statusIndicator.className = connected ? 'status-connected' : 'status-disconnected'
}
updateUIState() {
this.runBtn.disabled = !this.isConnected || this.isRunning
this.killBtn.disabled = !this.isRunning
this.commandInput.disabled = !this.isConnected || this.isRunning
}
showUserInput() {
this.userInputContainer.style.display = 'flex'
this.userInput.focus()
}
hideUserInput() {
this.userInputContainer.style.display = 'none'
}
addMessage(content, className) {
const messageDiv = document.createElement('div')
messageDiv.className = `message ${className}`
const timestamp = document.createElement('div')
timestamp.className = 'timestamp'
timestamp.textContent = new Date().toLocaleTimeString()
const contentDiv = document.createElement('pre')
contentDiv.textContent = content
messageDiv.appendChild(timestamp)
messageDiv.appendChild(contentDiv)
this.output.appendChild(messageDiv)
this.scrollToBottom()
}
addCommandMessage(command) {
this.addMessage(`$ ${command}`, 'command')
}
addInputMessage(input) {
this.addMessage(`> ${input}`, 'command')
}
addOutput(data, isError = false) {
this.addMessage(data, isError ? 'error' : 'output')
}
addSystemMessage(message) {
this.addMessage(message, 'system')
}
addErrorMessage(message) {
this.addMessage(`Error: ${message}`, 'error')
}
scrollToBottom() {
this.output.scrollTop = this.output.scrollHeight
}
}
// Initialize the interface when the page loads
document.addEventListener('DOMContentLoaded', () => {
new PythonWebInterface()
})