diff --git a/packages/cli/src/cli-utils.ts b/packages/cli/src/cli-utils.ts index 3098bd561..db1de6e68 100644 --- a/packages/cli/src/cli-utils.ts +++ b/packages/cli/src/cli-utils.ts @@ -1,49 +1,9 @@ -import assert from 'node:assert'; import { glob } from 'glob'; -import minimist from 'minimist'; -import { findOnlyItemInArgs, orderMattersParse } from './args'; import 'dotenv/config'; import { statSync } from 'node:fs'; import { existsSync } from 'node:fs'; import { join } from 'node:path'; -import { dump } from 'js-yaml'; import yargs from 'yargs/yargs'; -import type { - MidsceneYamlFlowItemAIAction, - MidsceneYamlFlowItemAIAssert, - MidsceneYamlFlowItemAIQuery, - MidsceneYamlFlowItemAIWaitFor, - MidsceneYamlFlowItemSleep, - MidsceneYamlScript, -} from './types'; - -const preferenceArgs = { - url: 'url', - serve: 'serve', - headed: 'headed', - viewportWidth: 'viewport-width', - viewportHeight: 'viewport-height', - viewportScale: 'viewport-scale', - useragent: 'user-agent', - output: 'output', - cookie: 'cookie', -}; - -const removedArgs = { - action: 'action', - assert: 'assert', - query: 'query', - waitFor: 'wait-for', -}; - -const actionArgs = { - ai: 'ai', - aiAction: 'aiAction', - aiAssert: 'aiAssert', - aiQuery: 'aiQuery', - aiWaitFor: 'aiWaitFor', - sleep: 'sleep', -}; export const parseProcessArgs = async (): Promise<{ path?: string; @@ -85,86 +45,6 @@ Usage: $0 [options] `, }; }; -export const parseArgsIntoYamlScript = async ( - input?: string[], -): Promise => { - const args = minimist(input || process.argv); - - if (findOnlyItemInArgs(args, 'version')) { - const versionFromPkgJson = require('../package.json').version; - console.log(`@midscene/cli version ${versionFromPkgJson}`); - process.exit(0); - } - - // check if any deprecated args are used - Object.keys(removedArgs).forEach((arg) => { - if (findOnlyItemInArgs(args, arg)) { - throw new Error( - `Parameter ${arg} has been removed, use --aiAction --aiAssert --aiQuery --aiWaitFor instead.`, - ); - } - }); - - // check each arg is either in the preferenceArgs or actionArgs - Object.keys(args).forEach((arg) => { - if (arg === '_') return; - assert( - Object.values(preferenceArgs).includes(arg) || - Object.values(actionArgs).includes(arg), - `Unknown argument: ${arg}`, - ); - }); - - const url = findOnlyItemInArgs(args, preferenceArgs.url) as - | string - | undefined; - - assert(url, 'url is required'); - const script: MidsceneYamlScript = { - target: { url }, - flow: [], - }; - - Object.entries(preferenceArgs).forEach(([key, value]) => { - const argValue = findOnlyItemInArgs(args, value); - if (argValue) { - Object.assign(script.target, { - [key]: argValue, - }); - } - }); - - const orderedArgs = orderMattersParse(process.argv); - for (const arg of orderedArgs) { - const argName = arg.name; - const argValue = arg.value; - if (argName === actionArgs.ai || argName === actionArgs.aiAction) { - script.flow.push({ - aiAction: argValue, - } as MidsceneYamlFlowItemAIAction); - } else if (argName === actionArgs.aiAssert) { - script.flow.push({ - aiAssert: argValue, - } as MidsceneYamlFlowItemAIAssert); - } else if (argName === actionArgs.aiQuery) { - script.flow.push({ - aiQuery: argValue, - } as MidsceneYamlFlowItemAIQuery); - } else if (argName === actionArgs.aiWaitFor) { - script.flow.push({ - aiWaitFor: argValue, - } as MidsceneYamlFlowItemAIWaitFor); - } else if (argName === actionArgs.sleep) { - script.flow.push({ - sleep: argValue, - } as MidsceneYamlFlowItemSleep); - } - } - - const yaml = dump(script); - return yaml; -}; - // match yml or yaml files export async function matchYamlFiles(fileGlob: string) { if (existsSync(fileGlob) && statSync(fileGlob).isDirectory()) { @@ -172,6 +52,7 @@ export async function matchYamlFiles(fileGlob: string) { } const files = await glob(fileGlob, { nodir: true, + windowsPathsNoEscape: true, }); return files .filter((file) => file.endsWith('.yml') || file.endsWith('.yaml')) diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index b49f16ebf..a20117ae6 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -35,5 +35,8 @@ Promise.resolve( process.exit(1); } process.exit(0); - })(), + })().catch((e) => { + console.error(e); + process.exit(1); + }), ); diff --git a/packages/cli/src/printer.ts b/packages/cli/src/printer.ts index 7ea6ce76d..b6af160c2 100644 --- a/packages/cli/src/printer.ts +++ b/packages/cli/src/printer.ts @@ -51,6 +51,11 @@ export const contextInfo = (context: MidsceneYamlFileContext) => { ? chalk.gray('(navigating)') : ''; + // error: ... + const errorText = context.player.errorInSetup + ? `\n${indent}${chalk.red('error:')} ${context.player.errorInSetup?.message}\n${indent}${indent}${context.player.errorInSetup?.stack}` + : ''; + // output: ... const outputFile = context.player.output; const outputText = @@ -66,7 +71,7 @@ export const contextInfo = (context: MidsceneYamlFileContext) => { : ''; const mergedText = - `${fileStatusText} ${fileNameToPrint} ${contextActionText}${outputText}${reportText}`.trim(); + `${fileStatusText} ${fileNameToPrint} ${contextActionText}${outputText}${reportText}${errorText}`.trim(); return { fileNameToPrint, @@ -127,17 +132,19 @@ export const contextTaskListSummary = ( const currentLine: string[] = []; const suffixText: string[] = []; const { mergedText: fileInfo } = contextInfo(context); - for (const task of taskStatusArray) { - const { mergedLine } = singleTaskInfo(task); + if (!context.player.errorInSetup) { + for (const task of taskStatusArray) { + const { mergedLine } = singleTaskInfo(task); - if (context.player.status === 'init') { - suffixText.push(mergedLine); - } else if (context.player.status === 'running') { - currentLine.push(mergedLine); - } else if (context.player.status === 'done') { - prefixLines.push(mergedLine); - } else if (context.player.status === 'error') { - prefixLines.push(mergedLine); + if (context.player.status === 'init') { + suffixText.push(mergedLine); + } else if (context.player.status === 'running') { + currentLine.push(mergedLine); + } else if (context.player.status === 'done') { + prefixLines.push(mergedLine); + } else if (context.player.status === 'error') { + prefixLines.push(mergedLine); + } } } const currentLineText = diff --git a/packages/web-integration/src/puppeteer/agent-launcher.ts b/packages/web-integration/src/puppeteer/agent-launcher.ts index 1e6a8c5ab..fb821c723 100644 --- a/packages/web-integration/src/puppeteer/agent-launcher.ts +++ b/packages/web-integration/src/puppeteer/agent-launcher.ts @@ -72,11 +72,12 @@ export async function puppeteerAgentForTarget( ); } const puppeteer = await import('puppeteer'); + // do not use 'no-sandbox' on windows https://www.perplexity.ai/search/how-to-solve-this-with-nodejs-dMHpdCypRa..JA8TkQzbeQ + const isWindows = process.platform === 'win32'; const browser = await puppeteer.launch({ headless: !headed, args: [ - '--no-sandbox', - '--disable-setuid-sandbox', + ...(isWindows ? [] : ['--no-sandbox', '--disable-setuid-sandbox']), '--disable-features=PasswordLeakDetection', '--disable-save-password-bubble', ],