feat: 脚本录制功能完善

This commit is contained in:
duanshuwen
2026-04-12 22:12:57 +08:00
parent 6432634d17
commit 66db6c462e
16 changed files with 262 additions and 124 deletions

View File

@@ -1,4 +1,26 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
const electron = require("electron");
const OpenAI = require("openai");
const util = require("util");
@@ -13,7 +35,6 @@ const net = require("net");
const http = require("http");
const child_process = require("child_process");
const events = require("events");
const playwright = require("playwright");
require("bytenode");
const electronUpdater = require("electron-updater");
function _interopNamespaceDefault(e) {
@@ -88,6 +109,7 @@ var IPC_EVENTS = /* @__PURE__ */ ((IPC_EVENTS2) => {
IPC_EVENTS2["SCRIPT_RUN"] = "script:run";
IPC_EVENTS2["SCRIPT_RECORD_START"] = "script:record-start";
IPC_EVENTS2["SCRIPT_RECORD_STOP"] = "script:record-stop";
IPC_EVENTS2["SCRIPT_CODEGEN"] = "script:codegen";
IPC_EVENTS2["UPDATE_CHECK"] = "update:check";
IPC_EVENTS2["UPDATE_DOWNLOAD"] = "update:download";
IPC_EVENTS2["UPDATE_INSTALL"] = "update:install";
@@ -793,7 +815,7 @@ class WindowService {
}
_loadPage(window2, pageName) {
{
return window2.loadURL(`${"http://localhost:5173"}/${pageName}.html`);
return window2.loadURL(`${"http://localhost:5173/"}/${pageName}.html`);
}
}
_loadWindowTemplate(window2, name) {
@@ -1702,59 +1724,15 @@ async function runScriptById(id, channel) {
});
return result;
}
let recorderBrowser = null;
let recorderContext = null;
async function startRecording(url) {
try {
await launchLocalChrome();
if (recorderBrowser) {
await stopRecording();
}
recorderBrowser = await playwright.chromium.connectOverCDP("http://127.0.0.1:9222");
recorderContext = recorderBrowser.contexts()[0] || await recorderBrowser.newContext();
const page = await recorderContext.newPage();
const targetUrl = url || "about:blank";
await page.goto(targetUrl, { waitUntil: "domcontentloaded" });
await page.pause();
return {
success: true,
code: ""
};
} catch (error) {
log.error("[script-recorder-service] Failed to start recording:", error);
return {
success: false,
error: error?.message || "Failed to start recording"
};
}
}
async function stopRecording() {
try {
if (recorderContext) {
await recorderContext.close().catch(() => {
});
recorderContext = null;
}
if (recorderBrowser) {
await recorderBrowser.close().catch(() => {
});
recorderBrowser = null;
}
return { success: true, code: "" };
} catch (error) {
log.error("[script-recorder-service] Failed to stop recording:", error);
return {
success: false,
error: error?.message || "Failed to stop recording"
};
}
}
const openedTabIndexByChannelName = /* @__PURE__ */ new Map();
function getScriptsDir() {
return electron.app.isPackaged ? path.join(__dirname, "scripts") : path.join(process.cwd(), "electron/scripts");
}
function runTaskOperationService() {
const executeScriptServiceInstance = new executeScriptService();
const playwrightCoreDir = path.dirname(require.resolve("playwright-core"));
const cliPath = path.join(playwrightCoreDir, "cli.js");
let recorderProc = null;
electron.ipcMain.handle(IPC_EVENTS.SCRIPT_LIST, async () => {
try {
return listScripts();
@@ -1806,7 +1784,29 @@ function runTaskOperationService() {
});
electron.ipcMain.handle(IPC_EVENTS.SCRIPT_RECORD_START, async (_event, url) => {
try {
return await startRecording(url);
if (recorderProc) {
recorderProc.kill("SIGINT");
recorderProc = null;
}
const targetUrl = url || "about:blank";
recorderProc = child_process.spawn(process.execPath, [cliPath, "codegen", "--target", "javascript", "--channel", "chrome", "--viewport-size", "1920,1080", "--color-scheme", "light", targetUrl], {
env: { ...process.env, ELECTRON_RUN_AS_NODE: "1" },
stdio: "pipe"
});
recorderProc.on("error", (err) => {
log.error("[SCRIPT_RECORD_START] Failed to start codegen process:", err);
});
recorderProc.on("exit", (code, signal) => {
log.info(`[SCRIPT_RECORD_START] Process exited code=${code} signal=${signal}`);
recorderProc = null;
});
recorderProc.stdout?.on("data", (data) => {
log.info(`[SCRIPT_RECORD_START] stdout: ${data.toString()}`);
});
recorderProc.stderr?.on("data", (data) => {
log.error(`[SCRIPT_RECORD_START] stderr: ${data.toString()}`);
});
return { success: true };
} catch (error) {
log.error("[SCRIPT_RECORD_START] error:", error);
return { success: false, error: error?.message || "Recording start failed" };
@@ -1814,12 +1814,65 @@ function runTaskOperationService() {
});
electron.ipcMain.handle(IPC_EVENTS.SCRIPT_RECORD_STOP, async () => {
try {
return await stopRecording();
if (recorderProc) {
recorderProc.kill("SIGINT");
recorderProc = null;
}
return { success: true, code: "" };
} catch (error) {
log.error("[SCRIPT_RECORD_STOP] error:", error);
return { success: false, error: error?.message || "Recording stop failed" };
}
});
electron.ipcMain.handle(IPC_EVENTS.SCRIPT_CODEGEN, async (_event, id, url) => {
try {
const script = getScript(id);
if (!script) {
return { success: false, error: "Script not found" };
}
const scriptsDir = getScriptsDir();
const scriptPath = path.join(scriptsDir, script.filename);
const targetUrl = url || "about:blank";
log.info(`[SCRIPT_CODEGEN] Starting codegen for script ${id} at ${scriptPath} with url ${targetUrl}`);
return await new Promise((resolve) => {
const proc = child_process.spawn(process.execPath, [cliPath, "codegen", "--target", "javascript", "--channel", "chrome", "-o", scriptPath, targetUrl], {
env: { ...process.env, ELECTRON_RUN_AS_NODE: "1" },
stdio: "pipe"
});
proc.on("exit", () => {
try {
let generatedCode = fs.readFileSync(scriptPath, "utf-8");
if (generatedCode.includes("require('playwright')") && !generatedCode.includes("createRequire")) {
generatedCode = `import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
${generatedCode}`;
}
fs.writeFileSync(scriptPath, generatedCode, "utf-8");
saveScript({
id,
name: script.name,
description: script.description,
code: generatedCode,
channel: script.channel,
enabled: script.enabled
});
resolve({ success: true, code: generatedCode });
} catch (err) {
log.error("[SCRIPT_CODEGEN] Failed to process generated code:", err);
resolve({ success: false, error: err?.message || "Failed to process generated code" });
}
});
proc.on("error", (err) => {
log.error("[SCRIPT_CODEGEN] Failed to start codegen:", err);
resolve({ success: false, error: err.message });
});
});
} catch (error) {
log.error("[SCRIPT_CODEGEN] error:", error);
return { success: false, error: error?.message || "Codegen failed" };
}
});
electron.ipcMain.handle(IPC_EVENTS.OPEN_CHANNEL, async (_event, channels) => {
try {
await launchLocalChrome();

File diff suppressed because one or more lines are too long

Binary file not shown.