Initialize smartkvm package
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import { createWrappedKvmCommand, parseWrappedKvmCommandOutput } from './smartkvm.commandwrappers.js';
|
||||
import type {
|
||||
IKvmTerminalCommandResult,
|
||||
IKvmTerminalOptions,
|
||||
} from './smartkvm.interfaces.js';
|
||||
|
||||
export class SmartKvmTerminal {
|
||||
private options: IKvmTerminalOptions;
|
||||
|
||||
constructor(options: IKvmTerminalOptions) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public async bootstrap(): Promise<void> {
|
||||
const osHint = this.options.osHint ?? 'unknown';
|
||||
|
||||
switch (osHint) {
|
||||
case 'windows':
|
||||
await this.options.kvm.pressShortcut(['Meta', 'R']);
|
||||
await this.options.kvm.wait(500);
|
||||
await this.options.kvm.typeText('powershell -NoLogo');
|
||||
await this.options.kvm.pressKey('Enter');
|
||||
await this.options.kvm.wait(1500);
|
||||
break;
|
||||
case 'macos':
|
||||
await this.options.kvm.pressShortcut(['Meta', 'Space']);
|
||||
await this.options.kvm.wait(500);
|
||||
await this.options.kvm.typeText('Terminal');
|
||||
await this.options.kvm.pressKey('Enter');
|
||||
await this.options.kvm.wait(1500);
|
||||
break;
|
||||
case 'linux':
|
||||
await this.options.kvm.pressShortcut(['Control', 'Alt', 'T']);
|
||||
await this.options.kvm.wait(1500);
|
||||
break;
|
||||
case 'unknown':
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public async runCommand(command: string): Promise<IKvmTerminalCommandResult> {
|
||||
const wrappedCommand = createWrappedKvmCommand(command, this.options.shellHint ?? 'unknown');
|
||||
const commandTimeoutMs = this.options.commandTimeoutMs ?? 30000;
|
||||
const ocrPollIntervalMs = this.options.ocrPollIntervalMs ?? 500;
|
||||
const startedAt = Date.now();
|
||||
let rawOcrText = '';
|
||||
let attempts = 0;
|
||||
|
||||
await this.options.kvm.focusViewer();
|
||||
await this.options.kvm.typeText(wrappedCommand.textToType);
|
||||
await this.options.kvm.pressKey('Enter');
|
||||
|
||||
while (true) {
|
||||
attempts++;
|
||||
rawOcrText = await this.observeText();
|
||||
const parsedResult = parseWrappedKvmCommandOutput({
|
||||
commandId: wrappedCommand.commandId,
|
||||
startMarker: wrappedCommand.startMarker,
|
||||
endMarkerPrefix: wrappedCommand.endMarkerPrefix,
|
||||
rawText: rawOcrText,
|
||||
});
|
||||
|
||||
if (parsedResult.completed) {
|
||||
return {
|
||||
commandId: wrappedCommand.commandId,
|
||||
command,
|
||||
completed: true,
|
||||
timedOut: false,
|
||||
exitCode: parsedResult.exitCode,
|
||||
combinedText: parsedResult.combinedText,
|
||||
rawOcrText,
|
||||
};
|
||||
}
|
||||
|
||||
const reachedMaxAttempts =
|
||||
typeof this.options.ocrMaxAttempts === 'number' && attempts >= this.options.ocrMaxAttempts;
|
||||
const reachedTimeout = Date.now() - startedAt >= commandTimeoutMs;
|
||||
if (reachedMaxAttempts || reachedTimeout) {
|
||||
return {
|
||||
commandId: wrappedCommand.commandId,
|
||||
command,
|
||||
completed: false,
|
||||
timedOut: true,
|
||||
combinedText: rawOcrText,
|
||||
rawOcrText,
|
||||
};
|
||||
}
|
||||
|
||||
const remainingTimeMs = commandTimeoutMs - (Date.now() - startedAt);
|
||||
await this.options.kvm.wait(Math.min(ocrPollIntervalMs, Math.max(remainingTimeMs, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
public async observeText(): Promise<string> {
|
||||
const frame = await this.options.kvm.captureFrame();
|
||||
const result = await this.options.ocrEngine.recognize(frame, {
|
||||
crop: this.options.ocrCrop,
|
||||
language: 'eng',
|
||||
});
|
||||
return result.text;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user