#!/usr/bin/env node
import { TerminalManager } from "../terminal-manager.js";
import * as readline from "readline";
/**
* 交互式演示
* 允许用户通过命令行界面与终端会话交互
*/
class InteractiveDemo {
terminalManager;
rl;
currentTerminalId = null;
isRunning = true;
constructor() {
this.terminalManager = new TerminalManager();
this.rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
// 监听终端输出
this.terminalManager.on("terminalOutput", (terminalId, data) => {
if (terminalId === this.currentTerminalId) {
console.log("\n--- Terminal Output ---");
console.log(data.replace(/\n$/, ""));
console.log("--- End Output ---");
this.showPrompt();
}
});
}
async start() {
console.log("=== Interactive Terminal Demo ===");
console.log("Commands:");
console.log(" create [shell] [cwd] - Create new terminal");
console.log(" list - List all terminals");
console.log(" select <id> - Select terminal to interact with");
console.log(" send <input> - Send input to selected terminal");
console.log(" read [since] [lines] - Read terminal output");
console.log(" kill <id> - Kill terminal");
console.log(" stats - Show manager statistics");
console.log(" help - Show this help");
console.log(" exit - Exit demo");
console.log();
this.showPrompt();
this.rl.on("line", this.handleCommand.bind(this));
this.rl.on("close", this.cleanup.bind(this));
}
showPrompt() {
const terminalInfo = this.currentTerminalId
? ` [${this.currentTerminalId.substring(0, 8)}...]`
: "";
this.rl.setPrompt(`demo${terminalInfo}> `);
this.rl.prompt();
}
async handleCommand(line) {
const args = line.trim().split(" ");
const command = args[0]?.toLowerCase() || "";
try {
switch (command) {
case "create":
await this.createTerminal(args[1], args[2]);
break;
case "list":
await this.listTerminals();
break;
case "select":
await this.selectTerminal(args[1] || "");
break;
case "send":
await this.sendInput(args.slice(1).join(" "));
break;
case "read":
await this.readOutput(
args[1] ? parseInt(args[1]) : undefined,
args[2] ? parseInt(args[2]) : undefined,
);
break;
case "kill":
await this.killTerminal(args[1] || "");
break;
case "stats":
await this.showStats();
break;
case "help":
this.showHelp();
break;
case "exit":
await this.cleanup();
return;
case "":
break;
default:
console.log(
`Unknown command: ${command}. Type 'help' for available commands.`,
);
}
} catch (error) {
console.error(
"Error:",
error instanceof Error ? error.message : String(error),
);
}
if (this.isRunning) {
this.showPrompt();
}
}
async createTerminal(shell, cwd) {
console.log("Creating terminal...");
const terminalId = await this.terminalManager.createTerminal({
shell: shell || undefined,
cwd: cwd || undefined,
});
const session = this.terminalManager.getTerminalInfo(terminalId);
console.log(`Terminal created: ${terminalId}`);
console.log(`PID: ${session?.pid}, Shell: ${session?.shell}`);
if (!this.currentTerminalId) {
this.currentTerminalId = terminalId;
console.log("Automatically selected as current terminal");
}
}
async listTerminals() {
const result = await this.terminalManager.listTerminals();
if (result.terminals.length === 0) {
console.log("No terminals found");
return;
}
console.log(`Found ${result.terminals.length} terminal(s):`);
result.terminals.forEach((terminal) => {
const current =
terminal.id === this.currentTerminalId ? " (current)" : "";
console.log(
` ${terminal.id.substring(0, 8)}... - ${terminal.status} - PID: ${terminal.pid}${current}`,
);
});
}
async selectTerminal(terminalId) {
if (!terminalId) {
console.log("Please provide a terminal ID");
return;
}
// 支持短 ID 匹配
const result = await this.terminalManager.listTerminals();
const terminal = result.terminals.find(
(t) => t.id === terminalId || t.id.startsWith(terminalId),
);
if (!terminal) {
console.log("Terminal not found");
return;
}
this.currentTerminalId = terminal.id;
console.log(`Selected terminal: ${terminal.id}`);
}
async sendInput(input) {
if (!this.currentTerminalId) {
console.log('No terminal selected. Use "select <id>" first.');
return;
}
if (!input) {
console.log("Please provide input to send");
return;
}
// 如果输入不以换行符结尾,添加一个
if (!input.endsWith("\n")) {
input += "\n";
}
await this.terminalManager.writeToTerminal({
terminalId: this.currentTerminalId,
input,
});
console.log("Input sent");
}
async readOutput(since, maxLines) {
if (!this.currentTerminalId) {
console.log('No terminal selected. Use "select <id>" first.');
return;
}
const result = await this.terminalManager.readFromTerminal({
terminalId: this.currentTerminalId,
since: since || undefined,
maxLines: maxLines || undefined,
});
console.log("--- Terminal Output ---");
console.log(result.output);
console.log("--- End Output ---");
console.log(
`Total lines: ${result.totalLines}, Has more: ${result.hasMore}`,
);
}
async killTerminal(terminalId) {
if (!terminalId) {
console.log("Please provide a terminal ID");
return;
}
// 支持短 ID 匹配
const result = await this.terminalManager.listTerminals();
const terminal = result.terminals.find(
(t) => t.id === terminalId || t.id.startsWith(terminalId),
);
if (!terminal) {
console.log("Terminal not found");
return;
}
await this.terminalManager.killTerminal(terminal.id);
console.log(`Terminal ${terminal.id} killed`);
if (this.currentTerminalId === terminal.id) {
this.currentTerminalId = null;
console.log("Current terminal cleared");
}
}
async showStats() {
const stats = this.terminalManager.getStats();
console.log("Manager Statistics:");
console.log(JSON.stringify(stats, null, 2));
}
showHelp() {
console.log("Available commands:");
console.log(" create [shell] [cwd] - Create new terminal");
console.log(" list - List all terminals");
console.log(" select <id> - Select terminal to interact with");
console.log(" send <input> - Send input to selected terminal");
console.log(" read [since] [lines] - Read terminal output");
console.log(" kill <id> - Kill terminal");
console.log(" stats - Show manager statistics");
console.log(" help - Show this help");
console.log(" exit - Exit demo");
console.log();
console.log("Tips:");
console.log("- You can use partial terminal IDs (first 8 characters)");
console.log("- Terminal output is automatically displayed when available");
console.log("- Use Ctrl+C to exit");
}
async cleanup() {
if (!this.isRunning) return;
this.isRunning = false;
console.log("\nShutting down...");
this.rl.close();
await this.terminalManager.shutdown();
console.log("Demo ended");
process.exit(0);
}
}
// 运行交互式演示
if (import.meta.url === `file://${process.argv[1]}`) {
const demo = new InteractiveDemo();
demo.start().catch(console.error);
// 处理 Ctrl+C
process.on("SIGINT", () => {
console.log("\nReceived SIGINT, shutting down...");
process.exit(0);
});
}
//# sourceMappingURL=interactive-demo.js.map