@mearl/setup 2.8.2 → 2.9.0

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.
@@ -488,11 +488,12 @@ export async function installMearlBrowserExtension(options = {}, dependencies =
488
488
  const setupManagedAtStart = setupManagedBrowserIds.length > 0;
489
489
  let cdpSession;
490
490
  const inspectOnce = async () => {
491
- if (!useSharedCdpSession)
492
- return inspectInstallation(chromeUserDataDirectory);
491
+ if (!useSharedCdpSession) {
492
+ return options.force ? null : inspectInstallation(chromeUserDataDirectory);
493
+ }
493
494
  const candidate = await connectCdp(chromeUserDataDirectory);
494
495
  try {
495
- const installed = await candidate.inspectInstallation();
496
+ const installed = options.force ? null : await candidate.inspectInstallation();
496
497
  cdpSession?.close();
497
498
  cdpSession = candidate;
498
499
  return installed;
package/dist/cli.js CHANGED
@@ -1,132 +1,140 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
+ import { Command, CommanderError } from 'commander';
3
4
  import { configureAgentBayApiKey, promptAgentBayApiKey, readAgentBayApiKeyFile, readAgentBayApiKeyStdin, } from './agentBay.js';
4
5
  import { installMearlBrowserExtension } from './browserExtension.js';
5
6
  import { runMearlLifecycle } from './lifecycle.js';
6
7
  import { isMearlReleaseLine } from './version.js';
7
8
  const require = createRequire(import.meta.url);
8
9
  export const SETUP_VERSION = require('../package.json').version;
9
- export function parseSetupArgs(argv) {
10
- if (argv.includes('--help') || argv.includes('-h')) {
11
- return { agentBayReadStdin: false, help: true, skipSkill: false, yes: false };
10
+ const baseParsedArgs = () => ({
11
+ agentBayReadStdin: false,
12
+ help: false,
13
+ skipSkill: false,
14
+ yes: false,
15
+ });
16
+ function commanderError(error) {
17
+ const message = error.message.replace(/^error:\s*/i, '');
18
+ if (error.code === 'commander.unknownCommand') {
19
+ return new Error(message.replace(/^unknown command/i, 'Unknown operation'));
12
20
  }
13
- if (argv.includes('--version') || argv.includes('-v')) {
14
- return {
15
- agentBayReadStdin: false,
16
- help: false,
17
- skipSkill: false,
18
- version: true,
19
- yes: false,
20
- };
21
+ if (error.code === 'commander.unknownOption') {
22
+ return new Error(message.replace(/^unknown option/i, 'Unknown option'));
21
23
  }
22
- const firstArg = argv[0];
23
- const operation = firstArg === undefined || firstArg.startsWith('-') ? 'install' : firstArg;
24
- const optionStart = operation === firstArg ? 1 : 0;
25
- if (operation === 'agentbay') {
26
- if (argv.length === 1) {
27
- return {
28
- agentBayReadStdin: false,
29
- help: false,
24
+ return new Error(message);
25
+ }
26
+ export function parseSetupArgs(argv) {
27
+ let parsed;
28
+ const program = new Command()
29
+ .name('mearl-setup')
30
+ .version(SETUP_VERSION, '-v, --version')
31
+ .exitOverride()
32
+ .configureOutput({ writeErr: () => { }, writeOut: () => { } });
33
+ const addLifecycleCommand = (operation) => {
34
+ const command = new Command(operation)
35
+ .exitOverride()
36
+ .configureOutput({ writeErr: () => { }, writeOut: () => { } })
37
+ .option('--local')
38
+ .option('--cloud')
39
+ .option('--qoder-cloud')
40
+ .option('--mcp')
41
+ .option('--target-line <major.minor.x>')
42
+ .option('--skip-skill')
43
+ .option('-y, --yes')
44
+ .option('--non-interactive')
45
+ .action(() => {
46
+ const options = command.opts();
47
+ if (options.cloud && options.qoderCloud) {
48
+ throw new Error('--cloud and --qoder-cloud cannot be used together');
49
+ }
50
+ if (options.targetLine && !isMearlReleaseLine(options.targetLine)) {
51
+ throw new Error('--target-line requires a valid Mearl release line such as 2.3.x');
52
+ }
53
+ if (operation === 'uninstall' && options.targetLine) {
54
+ throw new Error('--target-line is not available for uninstall');
55
+ }
56
+ const profiles = [];
57
+ if (options.local)
58
+ profiles.push('local');
59
+ if (options.cloud || options.qoderCloud)
60
+ profiles.push('cloud');
61
+ if (options.mcp)
62
+ profiles.push('mcp');
63
+ parsed = {
64
+ ...baseParsedArgs(),
30
65
  operation,
31
- skipSkill: false,
32
- yes: false,
66
+ ...(options.cloud || options.qoderCloud
67
+ ? { cloudMode: options.qoderCloud ? 'qoder' : 'websocket' }
68
+ : {}),
69
+ ...(profiles.length > 0 ? { profiles } : {}),
70
+ skipSkill: options.skipSkill === true,
71
+ targetLine: options.targetLine,
72
+ yes: options.yes === true || options.nonInteractive === true,
33
73
  };
74
+ });
75
+ program.addCommand(command);
76
+ };
77
+ addLifecycleCommand('install');
78
+ addLifecycleCommand('update');
79
+ addLifecycleCommand('uninstall');
80
+ const extension = new Command('extension')
81
+ .exitOverride()
82
+ .configureOutput({ writeErr: () => { }, writeOut: () => { } })
83
+ .option('--force')
84
+ .option('-y, --yes')
85
+ .option('--non-interactive')
86
+ .action(() => {
87
+ const options = extension.opts();
88
+ parsed = {
89
+ ...baseParsedArgs(),
90
+ ...(options.force ? { force: true } : {}),
91
+ operation: 'extension',
92
+ yes: options.yes === true || options.nonInteractive === true,
93
+ };
94
+ });
95
+ program.addCommand(extension);
96
+ const agentbay = new Command('agentbay')
97
+ .exitOverride()
98
+ .configureOutput({ writeErr: () => { }, writeOut: () => { } })
99
+ .argument('[api-key]')
100
+ .option('--stdin')
101
+ .option('--key-file <path>')
102
+ .action((apiKey) => {
103
+ const options = agentbay.opts();
104
+ if (apiKey) {
105
+ throw new Error('API keys are not accepted as command-line arguments');
34
106
  }
35
- if (argv.length === 2 && argv[1] === '--stdin') {
36
- return {
37
- agentBayReadStdin: true,
38
- help: false,
39
- operation,
40
- skipSkill: false,
41
- yes: false,
42
- };
107
+ if (options.stdin && options.keyFile) {
108
+ throw new Error('--stdin and --key-file cannot be used together');
43
109
  }
44
- if (argv.length === 3 && argv[1] === '--key-file' && argv[2]?.trim()) {
45
- return {
46
- agentBayKeyFile: argv[2],
47
- agentBayReadStdin: false,
48
- help: false,
49
- operation,
50
- skipSkill: false,
51
- yes: false,
52
- };
110
+ if (options.keyFile !== undefined && !options.keyFile.trim()) {
111
+ throw new Error('--key-file requires a non-empty path');
53
112
  }
54
- throw new Error('Usage: npx @mearl/setup agentbay [--stdin | --key-file <path>]. API keys are not accepted as command-line arguments.');
55
- }
56
- if (operation === 'extension') {
57
- const accepted = new Set(['--force', '--yes', '-y', '--non-interactive']);
58
- const confirmationFlags = new Set(['--yes', '-y', '--non-interactive']);
59
- const unknown = argv.slice(1).find(arg => !accepted.has(arg));
60
- if (unknown)
61
- throw new Error(`Unknown option: ${unknown}`);
62
- return {
63
- agentBayReadStdin: false,
64
- help: false,
65
- ...(argv.slice(1).includes('--force') ? { force: true } : {}),
66
- operation,
67
- skipSkill: false,
68
- yes: argv.slice(1).some(arg => confirmationFlags.has(arg)),
113
+ parsed = {
114
+ ...baseParsedArgs(),
115
+ ...(options.keyFile ? { agentBayKeyFile: options.keyFile } : {}),
116
+ agentBayReadStdin: options.stdin === true,
117
+ operation: 'agentbay',
69
118
  };
119
+ });
120
+ program.addCommand(agentbay);
121
+ const normalizedArgv = argv[0] === undefined || argv[0].startsWith('-') ? ['install', ...argv] : argv;
122
+ try {
123
+ program.parse(['node', 'mearl-setup', ...normalizedArgv]);
70
124
  }
71
- if (operation !== 'install' && operation !== 'update' && operation !== 'uninstall') {
72
- throw new Error(`Unknown operation: ${operation}`);
73
- }
74
- const profiles = [];
75
- let skipSkill = false;
76
- let targetLine;
77
- let yes = false;
78
- let cloudMode;
79
- for (let index = optionStart; index < argv.length; index += 1) {
80
- const arg = argv[index];
81
- if (arg === '--yes' || arg === '-y' || arg === '--non-interactive') {
82
- yes = true;
83
- continue;
84
- }
85
- if (arg === '--skip-skill') {
86
- skipSkill = true;
87
- continue;
88
- }
89
- if (arg === '--target-line') {
90
- const value = argv[index + 1];
91
- if (!isMearlReleaseLine(value)) {
92
- throw new Error('--target-line requires a valid Mearl release line such as 2.3.x');
93
- }
94
- targetLine = value;
95
- index += 1;
96
- continue;
97
- }
98
- if (arg === '--cloud' || arg === '--qoder-cloud') {
99
- const requestedMode = arg === '--qoder-cloud' ? 'qoder' : 'websocket';
100
- if (cloudMode && cloudMode !== requestedMode) {
101
- throw new Error('--cloud and --qoder-cloud cannot be used together');
102
- }
103
- cloudMode = requestedMode;
125
+ catch (error) {
126
+ if (error instanceof CommanderError) {
127
+ if (error.code === 'commander.helpDisplayed')
128
+ return { ...baseParsedArgs(), help: true };
129
+ if (error.code === 'commander.version')
130
+ return { ...baseParsedArgs(), version: true };
131
+ throw commanderError(error);
104
132
  }
105
- const candidate = arg === '--local'
106
- ? 'local'
107
- : arg === '--cloud' || arg === '--qoder-cloud'
108
- ? 'cloud'
109
- : arg === '--mcp'
110
- ? 'mcp'
111
- : undefined;
112
- if (!candidate)
113
- throw new Error(`Unknown option: ${arg}`);
114
- if (!profiles.includes(candidate))
115
- profiles.push(candidate);
116
- }
117
- if (operation === 'uninstall' && targetLine) {
118
- throw new Error('--target-line is not available for uninstall');
133
+ throw error;
119
134
  }
120
- return {
121
- agentBayReadStdin: false,
122
- help: false,
123
- operation,
124
- ...(cloudMode ? { cloudMode } : {}),
125
- ...(profiles.length > 0 ? { profiles } : {}),
126
- skipSkill,
127
- targetLine,
128
- yes,
129
- };
135
+ if (!parsed)
136
+ throw new Error('No setup operation was selected');
137
+ return parsed;
130
138
  }
131
139
  function printHelp(toError = false) {
132
140
  const output = `Mearl Setup v${SETUP_VERSION}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/setup",
3
- "version": "2.8.2",
3
+ "version": "2.9.0",
4
4
  "description": "One-shot environment setup and configuration for Mearl",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -56,15 +56,16 @@
56
56
  ],
57
57
  "license": "ISC",
58
58
  "engines": {
59
- "node": ">=18"
59
+ "node": ">=22.12.0"
60
60
  },
61
61
  "publishConfig": {
62
62
  "registry": "https://registry.npmjs.org"
63
63
  },
64
64
  "dependencies": {
65
+ "commander": "^15.0.0",
65
66
  "extract-zip": "^2.0.1",
66
67
  "ws": "^8.18.3",
67
- "@mearl/client": "2.8.2"
68
+ "@mearl/client": "2.9.0"
68
69
  },
69
70
  "devDependencies": {
70
71
  "@types/node": "^24.9.1",