This commit is contained in:
149
src/parsers/screenParser.ts
Normal file
149
src/parsers/screenParser.ts
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
import { shellUtils } from '../utils/shellUtils';
|
||||||
|
import { Layout, Session, Window, Pane, ParserResult, TerminalType } from '../models/types';
|
||||||
|
|
||||||
|
interface ScreenWindowInfo {
|
||||||
|
number: number;
|
||||||
|
title: string;
|
||||||
|
layout?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ScreenSessionInfo {
|
||||||
|
session_name: string;
|
||||||
|
windows: ScreenWindowInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ScreenParser {
|
||||||
|
async isAvailable(): Promise<boolean> {
|
||||||
|
return shellUtils.isCommandAvailable('screen');
|
||||||
|
}
|
||||||
|
|
||||||
|
async listSessions(): Promise<string[]> {
|
||||||
|
const result = await shellUtils.exec('screen -ls | grep -o "[0-9]*\\.[^[:space:]]*"');
|
||||||
|
if (!result.success) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return result.stdout.split('\n').filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
async captureSession(sessionName?: string): Promise<ParserResult<Layout>> {
|
||||||
|
try {
|
||||||
|
const sessions = await this.listSessions();
|
||||||
|
if (sessions.length === 0) {
|
||||||
|
return { success: false, error: 'No screen sessions found' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetSession = sessionName || sessions[0];
|
||||||
|
const sessionInfo = await this.getSessionInfo(targetSession);
|
||||||
|
|
||||||
|
if (!sessionInfo) {
|
||||||
|
return { success: false, error: `Failed to capture session: ${targetSession}` };
|
||||||
|
}
|
||||||
|
|
||||||
|
const layout = this.convertToLayout(sessionInfo);
|
||||||
|
return { success: true, data: layout };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: (error as Error).message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getSessionInfo(sessionName: string): Promise<ScreenSessionInfo | null> {
|
||||||
|
const result = await shellUtils.exec(`screen -S "${sessionName}" -Q windows`);
|
||||||
|
if (!result.success) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const windows: ScreenWindowInfo[] = [];
|
||||||
|
const lines = result.stdout.split('\n');
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
const match = line.match(/(\d+)\s+(\*)?(.+)/);
|
||||||
|
if (match) {
|
||||||
|
windows.push({
|
||||||
|
number: parseInt(match[1], 10),
|
||||||
|
title: match[3].trim(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
session_name: sessionName,
|
||||||
|
windows,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private convertToLayout(sessionInfo: ScreenSessionInfo): Layout {
|
||||||
|
const windows: Window[] = sessionInfo.windows.map((w) => {
|
||||||
|
const panes: Pane[] = [
|
||||||
|
{
|
||||||
|
id: 'p0',
|
||||||
|
index: 0,
|
||||||
|
layout: { x: 0, y: 0, width: 80, height: 24 },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: `w${w.number}`,
|
||||||
|
index: w.number,
|
||||||
|
name: w.title || `window-${w.number}`,
|
||||||
|
panes,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const session: Session = {
|
||||||
|
id: `s-${sessionInfo.session_name}`,
|
||||||
|
name: sessionInfo.session_name,
|
||||||
|
windows,
|
||||||
|
activeWindowIndex: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: '1.0.0',
|
||||||
|
terminalType: 'screen' as TerminalType,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
session,
|
||||||
|
metadata: {
|
||||||
|
description: `Captured screen session: ${sessionInfo.session_name}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateRestoreCommands(layout: Layout, sessionName?: string): Promise<string[]> {
|
||||||
|
const commands: string[] = [];
|
||||||
|
const targetSession = sessionName || layout.session.name;
|
||||||
|
|
||||||
|
commands.push(`screen -dmS "${targetSession}"`);
|
||||||
|
|
||||||
|
for (let i = 0; i < layout.session.windows.length; i++) {
|
||||||
|
const window = layout.session.windows[i];
|
||||||
|
|
||||||
|
if (i === 0) {
|
||||||
|
commands.push(`screen -S "${targetSession}" -X title "${window.name}"`);
|
||||||
|
} else {
|
||||||
|
commands.push(`screen -S "${targetSession}" -X screen ${window.index}`);
|
||||||
|
commands.push(`screen -S "${targetSession}" -X title "${window.name}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
async restoreLayout(layout: Layout, sessionName?: string): Promise<ParserResult<void>> {
|
||||||
|
try {
|
||||||
|
const commands = await this.generateRestoreCommands(layout, sessionName);
|
||||||
|
|
||||||
|
for (const command of commands) {
|
||||||
|
const result = await shellUtils.exec(command);
|
||||||
|
if (!result.success) {
|
||||||
|
return { success: false, error: `Failed to execute: ${command}\n${result.stderr}` };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: (error as Error).message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const screenParser = new ScreenParser();
|
||||||
Reference in New Issue
Block a user