@midscene/cli 1.10.2-beta-20260706032158.0 → 1.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/es/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  /*! For license information please see index.mjs.LICENSE.txt */
2
- import node_path, { basename, dirname as external_node_path_dirname, extname, join, posix, relative as external_node_path_relative, resolve as external_node_path_resolve, sep as external_node_path_sep, win32 } from "node:path";
3
- import { ReportMergingTool, createReportCliCommands } from "@midscene/core";
2
+ import { ReportMergingTool, createReportCliCommands, runConnectivityTest } from "@midscene/core";
4
3
  import { runToolsCLI } from "@midscene/shared/cli";
4
+ import node_path, { basename, dirname as external_node_path_dirname, extname, join, posix, relative as external_node_path_relative, resolve as external_node_path_resolve, sep as external_node_path_sep, win32 } from "node:path";
5
5
  import { getDebug } from "@midscene/shared/logger";
6
6
  import { fileURLToPath, pathToFileURL } from "node:url";
7
7
  import { lstat, readdir, readlink, realpath } from "node:fs/promises";
@@ -23,6 +23,7 @@ import { processCacheConfig } from "@midscene/core/utils";
23
23
  import { AgentOverChromeBridge } from "@midscene/web/bridge-mode";
24
24
  import { stripVTControlCharacters } from "node:util";
25
25
  import { createRequire } from "node:module";
26
+ import { globalModelConfigManager } from "@midscene/shared/env";
26
27
  import * as __rspack_external_assert from "assert";
27
28
  import * as __rspack_external_crypto from "crypto";
28
29
  import * as __rspack_external_fs from "fs";
@@ -3024,9 +3025,9 @@ var __webpack_modules__ = {
3024
3025
  module.exports = (string, columns, options)=>String(string).normalize().replace(/\r\n/g, '\n').split('\n').map((line)=>exec(line, columns, options)).join('\n');
3025
3026
  },
3026
3027
  "./src/index.ts" (__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
3027
- var main = __webpack_require__("../../node_modules/.pnpm/dotenv@16.4.5/node_modules/dotenv/lib/main.js");
3028
- var main_default = /*#__PURE__*/ __webpack_require__.n(main);
3029
- var package_namespaceObject = JSON.parse('{"rE":"1.10.2-beta-20260706032158.0"}');
3028
+ var package_namespaceObject = {
3029
+ rE: "1.10.3"
3030
+ };
3030
3031
  var brace_expansion = __webpack_require__("../../node_modules/.pnpm/brace-expansion@2.0.1/node_modules/brace-expansion/index.js");
3031
3032
  const MAX_PATTERN_LENGTH = 65536;
3032
3033
  const assertValidPattern = (pattern)=>{
@@ -10887,7 +10888,7 @@ Usage:
10887
10888
  type: 'boolean',
10888
10889
  description: `Turn on logging to help debug why certain keys or values are not being set as you expect, default is ${config_factory_defaultConfig.dotenvDebug}`
10889
10890
  }
10890
- }).version('version', 'Show version number', "1.10.2-beta-20260706032158.0").help().epilogue(`For complete list of configuration options, please visit:
10891
+ }).version('version', 'Show version number', "1.10.3").help().epilogue(`For complete list of configuration options, please visit:
10891
10892
  • Web options: https://midscenejs.com/automate-with-scripts-in-yaml#the-web-part
10892
10893
  • Android options: https://midscenejs.com/automate-with-scripts-in-yaml#the-android-part
10893
10894
  • iOS options: https://midscenejs.com/automate-with-scripts-in-yaml#the-ios-part
@@ -10935,6 +10936,18 @@ Examples:
10935
10936
  });
10936
10937
  return files.filter((file)=>file.endsWith('.yml') || file.endsWith('.yaml')).sort();
10937
10938
  }
10939
+ var main = __webpack_require__("../../node_modules/.pnpm/dotenv@16.4.5/node_modules/dotenv/lib/main.js");
10940
+ var main_default = /*#__PURE__*/ __webpack_require__.n(main);
10941
+ function loadDotenvConfig(options = {}) {
10942
+ const dotEnvConfigFile = join(options.cwd ?? process.cwd(), '.env');
10943
+ if (!(0, __rspack_external_node_fs_5ea92f0c.existsSync)(dotEnvConfigFile)) return;
10944
+ options.log?.(` Env file: ${dotEnvConfigFile}`);
10945
+ main_default().config({
10946
+ path: dotEnvConfigFile,
10947
+ debug: options.dotenvDebug,
10948
+ override: options.dotenvOverride
10949
+ });
10950
+ }
10938
10951
  const warnRetryReport = getDebug('execution-summary', {
10939
10952
  console: true
10940
10953
  });
@@ -12607,6 +12620,172 @@ defineYamlBatchTest(test, testOptions);
12607
12620
  const success = printExecutionSummary(results, summaryPath);
12608
12621
  return success ? exitCode : 1;
12609
12622
  }
12623
+ const DEFAULT_OPENAI_BASE_URL = 'https://api.openai.com/v1';
12624
+ const MODEL_VERIFY_SEPARATOR = '────────────────────────────────────────';
12625
+ const MODEL_COMMAND_USAGE = `Usage:
12626
+ midscene model verify
12627
+ midscene model eval
12628
+ `;
12629
+ function assertNoModelVerifyOptions(args) {
12630
+ for (const arg of args)throw new Error(`Unknown option for midscene model verify: ${arg}`);
12631
+ }
12632
+ function shellSingleQuote(value) {
12633
+ return `'${value.replace(/'/g, "'\\''")}'`;
12634
+ }
12635
+ function buildChatCompletionsUrl(baseURL) {
12636
+ const normalizedBaseURL = (baseURL || DEFAULT_OPENAI_BASE_URL).replace(/\/+$/, '');
12637
+ if (normalizedBaseURL.endsWith('/chat/completions')) return normalizedBaseURL;
12638
+ return `${normalizedBaseURL}/chat/completions`;
12639
+ }
12640
+ function buildCurlCommand(modelConfig) {
12641
+ const payload = {
12642
+ model: modelConfig.modelName,
12643
+ messages: [
12644
+ {
12645
+ role: 'user',
12646
+ content: 'What is 1+1?'
12647
+ }
12648
+ ]
12649
+ };
12650
+ return [
12651
+ `curl -X POST ${shellSingleQuote(buildChatCompletionsUrl(modelConfig.openaiBaseURL))} \\`,
12652
+ ` -H ${shellSingleQuote(`Authorization: Bearer ${modelConfig.openaiApiKey || ''}`)} \\`,
12653
+ ` -H ${shellSingleQuote('Content-Type: application/json')} \\`,
12654
+ ` -d ${shellSingleQuote(JSON.stringify(payload, null, 2))}`
12655
+ ].join('\n');
12656
+ }
12657
+ function buildCurlDedupKey(modelConfig) {
12658
+ return JSON.stringify({
12659
+ baseURL: modelConfig.openaiBaseURL || DEFAULT_OPENAI_BASE_URL,
12660
+ apiKey: modelConfig.openaiApiKey || '',
12661
+ modelName: modelConfig.modelName
12662
+ });
12663
+ }
12664
+ function buildModelVerifyCurlCommands(configs) {
12665
+ const commandMap = new Map();
12666
+ for (const item of configs){
12667
+ const key = buildCurlDedupKey(item.modelConfig);
12668
+ const existing = commandMap.get(key);
12669
+ if (existing) {
12670
+ existing.intents.push(item.intent);
12671
+ continue;
12672
+ }
12673
+ commandMap.set(key, {
12674
+ intents: [
12675
+ item.intent
12676
+ ],
12677
+ curl: buildCurlCommand(item.modelConfig),
12678
+ usesDefaultBaseURL: !item.modelConfig.openaiBaseURL
12679
+ });
12680
+ }
12681
+ return [
12682
+ ...commandMap.values()
12683
+ ];
12684
+ }
12685
+ function formatModelVerifyFailureOutput(message, curlCommands) {
12686
+ const details = message?.trim() || 'No failure details were generated.';
12687
+ const curlSection = curlCommands.map((item)=>{
12688
+ const baseUrlNote = item.usesDefaultBaseURL ? ' (base URL not configured; using OpenAI SDK default)' : '';
12689
+ return source_default().gray(`# ${item.intents.join(', ')}${baseUrlNote}\n${item.curl}`);
12690
+ }).join('\n\n');
12691
+ return [
12692
+ source_default().red.bold('❌ Model verify failed with messages:'),
12693
+ MODEL_VERIFY_SEPARATOR,
12694
+ '',
12695
+ details,
12696
+ '',
12697
+ MODEL_VERIFY_SEPARATOR,
12698
+ 'Generated curl requests for basic API connectivity:',
12699
+ 'If the error is a basic connectivity issue, use these requests to test the base URL, API key, and model name directly.',
12700
+ 'These commands contain your API key. Do not share them publicly.',
12701
+ '',
12702
+ curlSection
12703
+ ].join('\n');
12704
+ }
12705
+ function getDefaultDeps(io) {
12706
+ return {
12707
+ loadDotenv: ()=>{
12708
+ loadDotenvConfig({
12709
+ dotenvDebug: true,
12710
+ dotenvOverride: true,
12711
+ log: io.stdout
12712
+ });
12713
+ },
12714
+ getModelConfig: (intent)=>globalModelConfigManager.getModelConfig(intent),
12715
+ verifyModel: runConnectivityTest
12716
+ };
12717
+ }
12718
+ async function runModelVerifyCommand(args, deps, io) {
12719
+ try {
12720
+ if (args.includes('--help') || args.includes('-h')) {
12721
+ io.stdout(MODEL_COMMAND_USAGE);
12722
+ return 0;
12723
+ }
12724
+ assertNoModelVerifyOptions(args);
12725
+ io.stdout('Model verify started. This usually takes about 5 seconds.\n');
12726
+ deps.loadDotenv();
12727
+ io.stdout('');
12728
+ const defaultModelConfig = deps.getModelConfig('default');
12729
+ const planningModelConfig = deps.getModelConfig('planning');
12730
+ const insightModelConfig = deps.getModelConfig('insight');
12731
+ const curlCommands = buildModelVerifyCurlCommands([
12732
+ {
12733
+ intent: 'default',
12734
+ modelConfig: defaultModelConfig
12735
+ },
12736
+ {
12737
+ intent: 'planning',
12738
+ modelConfig: planningModelConfig
12739
+ },
12740
+ {
12741
+ intent: 'insight',
12742
+ modelConfig: insightModelConfig
12743
+ }
12744
+ ]);
12745
+ const result = await deps.verifyModel({
12746
+ defaultModelConfig,
12747
+ planningModelConfig,
12748
+ insightModelConfig
12749
+ });
12750
+ if (result.passed) {
12751
+ io.stdout('✅ Model verify passed.');
12752
+ return 0;
12753
+ }
12754
+ io.stderr(formatModelVerifyFailureOutput(result.message, curlCommands));
12755
+ return 1;
12756
+ } catch (error) {
12757
+ const message = error instanceof Error ? error.message : String(error);
12758
+ io.stderr([
12759
+ MODEL_VERIFY_SEPARATOR,
12760
+ '❌ Model verify failed with messages:',
12761
+ '',
12762
+ message,
12763
+ MODEL_VERIFY_SEPARATOR
12764
+ ].join('\n'));
12765
+ return 1;
12766
+ }
12767
+ }
12768
+ async function runModelCommand(rawArgs, deps, io = {
12769
+ stdout: console.log,
12770
+ stderr: console.error
12771
+ }) {
12772
+ const [, action, ...restArgs] = rawArgs;
12773
+ const mergedDeps = {
12774
+ ...getDefaultDeps(io),
12775
+ ...deps
12776
+ };
12777
+ if (!action || '--help' === action || '-h' === action) {
12778
+ io.stdout(MODEL_COMMAND_USAGE);
12779
+ return 0;
12780
+ }
12781
+ if ('verify' === action) return runModelVerifyCommand(restArgs, mergedDeps, io);
12782
+ if ('eval' === action) {
12783
+ io.stderr('midscene model eval is not implemented yet. It is reserved for future model evaluation suites.');
12784
+ return 1;
12785
+ }
12786
+ io.stderr(`Unknown midscene model command: ${action}\n\n${MODEL_COMMAND_USAGE}`);
12787
+ return 1;
12788
+ }
12610
12789
  Promise.resolve((async ()=>{
12611
12790
  const rawArgs = process.argv.slice(2);
12612
12791
  const [firstArg] = rawArgs;
@@ -12619,6 +12798,11 @@ defineYamlBatchTest(test, testOptions);
12619
12798
  version: package_namespaceObject.rE,
12620
12799
  extraCommands: createReportCliCommands()
12621
12800
  });
12801
+ if ('model' === firstArg) {
12802
+ const exitCode = await runModelCommand(rawArgs);
12803
+ process.exit(exitCode);
12804
+ return;
12805
+ }
12622
12806
  const { options, path, files: cmdFiles } = await parseProcessArgs();
12623
12807
  const welcome = `\nWelcome to @midscene/cli v${package_namespaceObject.rE}\n`;
12624
12808
  console.log(welcome);
@@ -12667,15 +12851,11 @@ defineYamlBatchTest(test, testOptions);
12667
12851
  console.error('Could not create a valid configuration.');
12668
12852
  process.exit(1);
12669
12853
  }
12670
- const dotEnvConfigFile = join(process.cwd(), '.env');
12671
- if ((0, __rspack_external_node_fs_5ea92f0c.existsSync)(dotEnvConfigFile)) {
12672
- console.log(` Env file: ${dotEnvConfigFile}`);
12673
- main_default().config({
12674
- path: dotEnvConfigFile,
12675
- debug: config.dotenvDebug,
12676
- override: config.dotenvOverride
12677
- });
12678
- }
12854
+ loadDotenvConfig({
12855
+ dotenvDebug: config.dotenvDebug,
12856
+ dotenvOverride: config.dotenvOverride,
12857
+ log: console.log
12858
+ });
12679
12859
  const exitCode = await runFrameworkTestConfig(config);
12680
12860
  if (config.keepWindow) setInterval(()=>{
12681
12861
  console.log('browser is still running, use ctrl+c to stop it');