@link-assistant/hive-mind 1.59.7 → 1.60.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.
- package/CHANGELOG.md +6 -0
- package/package.json +3 -1
- package/src/cli-arguments.lib.mjs +68 -0
- package/src/configure-claude.lib.mjs +37 -14
- package/src/hive-screens.lib.mjs +36 -22
- package/src/hive.mjs +10 -16
- package/src/memory-check.mjs +10 -11
- package/src/review.mjs +72 -59
- package/src/reviewers-hive.mjs +108 -92
- package/src/solve.config.lib.mjs +10 -15
- package/src/start-screen.mjs +74 -15
- package/src/task.agent-command.lib.mjs +61 -0
- package/src/task.config.lib.mjs +122 -0
- package/src/task.mjs +217 -232
- package/src/task.split.lib.mjs +221 -0
- package/src/telegram-bot.mjs +27 -111
- package/src/telegram-command-execution.lib.mjs +98 -0
- package/src/telegram-solve-queue.lib.mjs +2 -1
- package/src/telegram-task-command.lib.mjs +133 -0
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@link-assistant/hive-mind",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.60.0",
|
|
4
4
|
"description": "AI-powered issue solver and hive mind for collaborative problem solving",
|
|
5
5
|
"main": "src/hive.mjs",
|
|
6
6
|
"type": "module",
|
|
@@ -72,8 +72,10 @@
|
|
|
72
72
|
"@secretlint/secretlint-rule-preset-recommend": "^11.2.5",
|
|
73
73
|
"@sentry/node": "^10.15.0",
|
|
74
74
|
"@sentry/profiling-node": "^10.15.0",
|
|
75
|
+
"agent-commander": "^0.4.2",
|
|
75
76
|
"dayjs": "^1.11.19",
|
|
76
77
|
"decimal.js-light": "^2.5.1",
|
|
78
|
+
"lino-arguments": "^0.3.0",
|
|
77
79
|
"secretlint": "^11.2.5",
|
|
78
80
|
"semver": "^7.7.3"
|
|
79
81
|
},
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { getenv, makeConfig, yargs as linoYargs } from 'lino-arguments';
|
|
2
|
+
|
|
3
|
+
export { getenv };
|
|
4
|
+
|
|
5
|
+
export const hideBin = argv => argv.slice(2);
|
|
6
|
+
|
|
7
|
+
export const getLinoYargsFactory = () => linoYargs;
|
|
8
|
+
|
|
9
|
+
const toKebabCase = key =>
|
|
10
|
+
key
|
|
11
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
12
|
+
.replace(/[_\s]+/g, '-')
|
|
13
|
+
.toLowerCase();
|
|
14
|
+
|
|
15
|
+
const toCamelCase = key => key.replace(/[-_\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''));
|
|
16
|
+
|
|
17
|
+
const ensureFullArgv = (argv, commandName) => {
|
|
18
|
+
if (argv.length >= 2 && (argv[0].includes('/') || argv[0] === 'node' || argv[0].endsWith('node'))) {
|
|
19
|
+
return argv;
|
|
20
|
+
}
|
|
21
|
+
return ['node', commandName, ...argv];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function addCliCompatibilityAliases(parsed, { positionalAliases = [] } = {}) {
|
|
25
|
+
const result = {};
|
|
26
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
27
|
+
if (value === undefined) continue;
|
|
28
|
+
result[key] = value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
for (const [key, value] of Object.entries(result)) {
|
|
32
|
+
const kebabKey = toKebabCase(key);
|
|
33
|
+
if (kebabKey && result[kebabKey] === undefined) {
|
|
34
|
+
result[kebabKey] = value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const positionalValues = [];
|
|
39
|
+
for (const alias of positionalAliases) {
|
|
40
|
+
const camelAlias = toCamelCase(alias);
|
|
41
|
+
const value = result[alias] ?? result[camelAlias];
|
|
42
|
+
if (value !== undefined) {
|
|
43
|
+
result[alias] = value;
|
|
44
|
+
result[camelAlias] = value;
|
|
45
|
+
positionalValues.push(value);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
result._ = positionalValues;
|
|
49
|
+
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function parseCliArgumentsWithLino({ argv = process.argv, commandName = 'cli', createYargsConfig, positionalAliases = [], lenv = { enabled: true }, env = { enabled: false }, getenv: getenvOptions = { enabled: true } } = {}) {
|
|
54
|
+
const fullArgv = ensureFullArgv(argv, commandName);
|
|
55
|
+
const parsed = makeConfig({
|
|
56
|
+
argv: fullArgv,
|
|
57
|
+
lenv,
|
|
58
|
+
env,
|
|
59
|
+
getenv: getenvOptions,
|
|
60
|
+
yargs: ({ yargs, getenv: getenvHelper }) => {
|
|
61
|
+
const parser = yargs.exitProcess(false);
|
|
62
|
+
const configured = createYargsConfig ? createYargsConfig(parser, getenvHelper) : parser;
|
|
63
|
+
return configured.exitProcess(false);
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return addCliCompatibilityAliases(parsed, { positionalAliases });
|
|
68
|
+
}
|
|
@@ -16,25 +16,48 @@ import os from 'node:os';
|
|
|
16
16
|
import path from 'node:path';
|
|
17
17
|
|
|
18
18
|
import { REQUIRED_CLAUDE_QUIET_ENV, REQUIRED_CLAUDE_QUIET_SETTINGS, REQUIRED_CLAUDE_QUIET_ATTRIBUTION, REQUIRED_CLAUDE_QUIET_PERMISSIONS, ensureClaudeQuietConfig } from './claude-quiet-config.lib.mjs';
|
|
19
|
+
import { parseCliArgumentsWithLino } from './cli-arguments.lib.mjs';
|
|
19
20
|
import { buildDisallowedToolsList, ensureDisallowedToolsInSettings } from './useless-tools.lib.mjs';
|
|
20
21
|
|
|
21
22
|
export const resolveSettingsPath = settingsPath => settingsPath || path.join(os.homedir(), '.claude', 'settings.json');
|
|
22
23
|
|
|
24
|
+
export const createConfigureClaudeYargsConfig = yargsInstance =>
|
|
25
|
+
yargsInstance
|
|
26
|
+
.usage('Usage: configure-claude [options]')
|
|
27
|
+
.option('settings-path', {
|
|
28
|
+
type: 'string',
|
|
29
|
+
description: 'Path to settings.json',
|
|
30
|
+
alias: 's',
|
|
31
|
+
})
|
|
32
|
+
.option('verify', {
|
|
33
|
+
type: 'boolean',
|
|
34
|
+
description: 'Report configuration status without writing',
|
|
35
|
+
default: false,
|
|
36
|
+
})
|
|
37
|
+
.option('help', {
|
|
38
|
+
type: 'boolean',
|
|
39
|
+
description: 'Show this help and exit',
|
|
40
|
+
alias: 'h',
|
|
41
|
+
default: false,
|
|
42
|
+
})
|
|
43
|
+
.help(false)
|
|
44
|
+
.version(false)
|
|
45
|
+
.strict();
|
|
46
|
+
|
|
23
47
|
export const parseConfigureClaudeArgs = argv => {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
return args;
|
|
48
|
+
const help = argv.includes('--help') || argv.includes('-h');
|
|
49
|
+
const parsed = parseCliArgumentsWithLino({
|
|
50
|
+
argv: argv.filter(arg => arg !== '--help' && arg !== '-h'),
|
|
51
|
+
commandName: 'configure-claude',
|
|
52
|
+
createYargsConfig: createConfigureClaudeYargsConfig,
|
|
53
|
+
lenv: { enabled: false },
|
|
54
|
+
getenv: { enabled: false },
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
settingsPath: parsed.settingsPath || parsed['settings-path'] || null,
|
|
58
|
+
verify: parsed.verify === true,
|
|
59
|
+
help,
|
|
60
|
+
};
|
|
38
61
|
};
|
|
39
62
|
|
|
40
63
|
export const CONFIGURE_CLAUDE_HELP = `Usage: configure-claude [options]
|
package/src/hive-screens.lib.mjs
CHANGED
|
@@ -15,6 +15,7 @@ import fs from 'node:fs/promises';
|
|
|
15
15
|
import os from 'node:os';
|
|
16
16
|
import path from 'node:path';
|
|
17
17
|
import { promisify } from 'node:util';
|
|
18
|
+
import { parseCliArgumentsWithLino } from './cli-arguments.lib.mjs';
|
|
18
19
|
|
|
19
20
|
const execAsync = promisify(execCallback);
|
|
20
21
|
|
|
@@ -52,6 +53,9 @@ References:
|
|
|
52
53
|
|
|
53
54
|
const ACTION_FLAGS = new Set(['--enter', '--close', '--list']);
|
|
54
55
|
const SELECTION_FLAGS = new Set(['--oldest', '--newest', '--all']);
|
|
56
|
+
const HIVE_SCREENS_FLAGS = new Set([...ACTION_FLAGS, ...SELECTION_FLAGS, '--help', '-h', '--verbose', '-v']);
|
|
57
|
+
|
|
58
|
+
const createHiveScreensYargsConfig = yargsInstance => yargsInstance.usage('Usage: hive-screens (--list | --enter | --close) [--oldest|--newest|--all] [--verbose]').option('enter', { type: 'boolean', default: false }).option('close', { type: 'boolean', default: false }).option('list', { type: 'boolean', default: false }).option('oldest', { type: 'boolean', default: false }).option('newest', { type: 'boolean', default: false }).option('all', { type: 'boolean', default: false }).option('verbose', { type: 'boolean', alias: 'v', default: false }).option('help', { type: 'boolean', alias: 'h', default: false }).help(false).version(false).strict(false);
|
|
55
59
|
|
|
56
60
|
/**
|
|
57
61
|
* Parse the argv for `hive-screens`. Returns the parsed flags plus an
|
|
@@ -59,6 +63,7 @@ const SELECTION_FLAGS = new Set(['--oldest', '--newest', '--all']);
|
|
|
59
63
|
* with a non-zero status without throwing).
|
|
60
64
|
*/
|
|
61
65
|
export const parseHiveScreensArgs = argv => {
|
|
66
|
+
const help = argv.includes('--help') || argv.includes('-h');
|
|
62
67
|
const result = {
|
|
63
68
|
enter: false,
|
|
64
69
|
close: false,
|
|
@@ -70,32 +75,41 @@ export const parseHiveScreensArgs = argv => {
|
|
|
70
75
|
};
|
|
71
76
|
|
|
72
77
|
for (const arg of argv) {
|
|
73
|
-
if (arg
|
|
74
|
-
result.
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
if (arg === '--verbose' || arg === '-v') {
|
|
78
|
-
result.verbose = true;
|
|
79
|
-
continue;
|
|
78
|
+
if (!HIVE_SCREENS_FLAGS.has(arg)) {
|
|
79
|
+
result.error = `Unknown option: ${arg}`;
|
|
80
|
+
return result;
|
|
80
81
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
result.error = `Unknown option: ${arg}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let parsed;
|
|
85
|
+
try {
|
|
86
|
+
parsed = parseCliArgumentsWithLino({
|
|
87
|
+
argv: argv.filter(arg => arg !== '--help' && arg !== '-h'),
|
|
88
|
+
commandName: 'hive-screens',
|
|
89
|
+
createYargsConfig: createHiveScreensYargsConfig,
|
|
90
|
+
lenv: { enabled: false },
|
|
91
|
+
getenv: { enabled: false },
|
|
92
|
+
});
|
|
93
|
+
} catch (err) {
|
|
94
|
+
result.error = err.message || String(err);
|
|
96
95
|
return result;
|
|
97
96
|
}
|
|
98
97
|
|
|
98
|
+
result.help = help;
|
|
99
|
+
result.verbose = parsed.verbose === true || parsed.v === true;
|
|
100
|
+
result.enter = parsed.enter === true;
|
|
101
|
+
result.close = parsed.close === true;
|
|
102
|
+
result.list = parsed.list === true;
|
|
103
|
+
|
|
104
|
+
for (const selection of ['oldest', 'newest', 'all']) {
|
|
105
|
+
if (parsed[selection] !== true) continue;
|
|
106
|
+
if (result.selection && result.selection !== selection) {
|
|
107
|
+
result.error = `Conflicting selection flags: --${result.selection} and --${selection}`;
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
result.selection = selection;
|
|
111
|
+
}
|
|
112
|
+
|
|
99
113
|
if (result.help) return result;
|
|
100
114
|
|
|
101
115
|
const actions = [result.enter, result.close, result.list].filter(Boolean).length;
|
package/src/hive.mjs
CHANGED
|
@@ -17,15 +17,9 @@ if (earlyArgs.includes('--version')) {
|
|
|
17
17
|
if (earlyArgs.includes('--help') || earlyArgs.includes('-h')) {
|
|
18
18
|
try {
|
|
19
19
|
// Load minimal modules needed for help
|
|
20
|
-
const {
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const { resolveYargsFactory } = await import('./yargs-factory.lib.mjs');
|
|
24
|
-
const yargs = resolveYargsFactory(yargsModule);
|
|
25
|
-
const helpersModuleHelp = await use('yargs@17.7.2/helpers');
|
|
26
|
-
const _helpersHelp = helpersModuleHelp.default || helpersModuleHelp;
|
|
27
|
-
const hideBinHelp = _helpersHelp.hideBin || (argv => argv.slice(2));
|
|
28
|
-
const rawArgs = hideBinHelp(process.argv);
|
|
20
|
+
const { getLinoYargsFactory, hideBin } = await import('./cli-arguments.lib.mjs');
|
|
21
|
+
const yargs = getLinoYargsFactory();
|
|
22
|
+
const rawArgs = hideBin(process.argv);
|
|
29
23
|
// Reuse createYargsConfig from shared module to avoid duplication
|
|
30
24
|
const { createYargsConfig } = await import('./hive.config.lib.mjs');
|
|
31
25
|
const helpYargs = createYargsConfig(yargs(rawArgs)).version(false);
|
|
@@ -71,12 +65,7 @@ if (isRunningDirectly) {
|
|
|
71
65
|
30000, // 30 second timeout
|
|
72
66
|
'loading command-stream'
|
|
73
67
|
);
|
|
74
|
-
const
|
|
75
|
-
const { resolveYargsFactory } = await import('./yargs-factory.lib.mjs');
|
|
76
|
-
const yargs = resolveYargsFactory(yargsModule);
|
|
77
|
-
const helpersModuleMain = await withTimeout(use('yargs@17.7.2/helpers'), 30000, 'loading yargs helpers');
|
|
78
|
-
const _helpersMain = helpersModuleMain.default || helpersModuleMain;
|
|
79
|
-
const hideBin = _helpersMain.hideBin || (argv => argv.slice(2));
|
|
68
|
+
const { parseCliArgumentsWithLino, hideBin } = await import('./cli-arguments.lib.mjs');
|
|
80
69
|
const path = (await withTimeout(use('path'), 30000, 'loading path')).default;
|
|
81
70
|
const fs = (await withTimeout(use('fs'), 30000, 'loading fs')).promises;
|
|
82
71
|
// Import shared library functions
|
|
@@ -258,7 +247,12 @@ if (isRunningDirectly) {
|
|
|
258
247
|
};
|
|
259
248
|
|
|
260
249
|
try {
|
|
261
|
-
argv =
|
|
250
|
+
argv = parseCliArgumentsWithLino({
|
|
251
|
+
argv: process.argv,
|
|
252
|
+
commandName: 'hive',
|
|
253
|
+
createYargsConfig,
|
|
254
|
+
positionalAliases: ['github-url'],
|
|
255
|
+
});
|
|
262
256
|
// Restore stderr if parsing succeeded
|
|
263
257
|
process.stderr.write = originalStderrWrite;
|
|
264
258
|
} catch (error) {
|
package/src/memory-check.mjs
CHANGED
|
@@ -6,7 +6,7 @@ if (typeof globalThis.use === 'undefined') {
|
|
|
6
6
|
globalThis.use = (await eval(await (await fetch('https://unpkg.com/use-m/use.js')).text())).use;
|
|
7
7
|
}
|
|
8
8
|
const use = globalThis.use;
|
|
9
|
-
const {
|
|
9
|
+
const { getLinoYargsFactory, hideBin, parseCliArgumentsWithLino } = await import('./cli-arguments.lib.mjs');
|
|
10
10
|
|
|
11
11
|
// Temporarily unset CI to avoid command-stream trace logs
|
|
12
12
|
const originalCI = process.env.CI;
|
|
@@ -18,12 +18,6 @@ const { $ } = await use('command-stream');
|
|
|
18
18
|
// These are filtered out by consuming code when parsing JSON
|
|
19
19
|
const $silent = $({ mirror: false, capture: true });
|
|
20
20
|
|
|
21
|
-
const yargsModule = await use('yargs@17.7.2');
|
|
22
|
-
const yargs = resolveYargsFactory(yargsModule);
|
|
23
|
-
const helpersModule = await use('yargs@17.7.2/helpers');
|
|
24
|
-
// Node 24 CJS/ESM interop may return the whole module object instead of named exports directly
|
|
25
|
-
const _helpers = helpersModule.default || helpersModule;
|
|
26
|
-
const hideBin = _helpers.hideBin || (argv => argv.slice(2));
|
|
27
21
|
const fs = (await use('fs')).promises;
|
|
28
22
|
|
|
29
23
|
// Import log function from lib.mjs
|
|
@@ -325,9 +319,8 @@ export const checkSystem = async (requirements = {}, options = {}) => {
|
|
|
325
319
|
};
|
|
326
320
|
|
|
327
321
|
// CLI interface when run directly
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const yargsInstance = yargs(hideBin(process.argv))
|
|
322
|
+
const createMemoryCheckYargsConfig = yargsInstance =>
|
|
323
|
+
yargsInstance
|
|
331
324
|
.scriptName('memory-check.mjs')
|
|
332
325
|
.usage('Usage: $0 [options]')
|
|
333
326
|
.option('min-memory', {
|
|
@@ -368,13 +361,19 @@ if (import.meta.url === `file://${process.argv[1]}`) {
|
|
|
368
361
|
.help('h')
|
|
369
362
|
.alias('h', 'help');
|
|
370
363
|
|
|
364
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
371
365
|
// Check for help before parsing
|
|
372
366
|
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
367
|
+
const yargsInstance = createMemoryCheckYargsConfig(getLinoYargsFactory()(hideBin(process.argv)));
|
|
373
368
|
yargsInstance.showHelp();
|
|
374
369
|
process.exit(0);
|
|
375
370
|
}
|
|
376
371
|
|
|
377
|
-
const argv =
|
|
372
|
+
const argv = parseCliArgumentsWithLino({
|
|
373
|
+
argv: process.argv,
|
|
374
|
+
commandName: 'memory-check.mjs',
|
|
375
|
+
createYargsConfig: createMemoryCheckYargsConfig,
|
|
376
|
+
});
|
|
378
377
|
|
|
379
378
|
// If we get here, help wasn't requested or yargs didn't handle it
|
|
380
379
|
// Set up logging based on options
|
package/src/review.mjs
CHANGED
|
@@ -38,13 +38,13 @@ const { use } = eval(await (await fetch('https://unpkg.com/use-m/use.js')).text(
|
|
|
38
38
|
const { $: __rawDollar$ } = await use('command-stream');
|
|
39
39
|
const { wrapDollarWithGhRetry } = await import('./github-rate-limit.lib.mjs');
|
|
40
40
|
const $ = wrapDollarWithGhRetry(__rawDollar$);
|
|
41
|
-
const yargs = (await use('yargs@latest')).default;
|
|
42
41
|
const os = (await use('os')).default;
|
|
43
42
|
const path = (await use('path')).default;
|
|
44
43
|
const fs = (await use('fs')).promises;
|
|
45
44
|
|
|
46
45
|
// Import shared functions from lib.mjs to follow DRY principle
|
|
47
46
|
import { log, setLogFile, getLogFile, formatAligned } from './lib.mjs';
|
|
47
|
+
import { parseCliArgumentsWithLino } from './cli-arguments.lib.mjs';
|
|
48
48
|
import { reportError } from './sentry.lib.mjs';
|
|
49
49
|
import * as memoryCheck from './memory-check.mjs';
|
|
50
50
|
|
|
@@ -53,64 +53,77 @@ import { executeClaudeCommand } from './claude.lib.mjs';
|
|
|
53
53
|
import { defaultModels, getClaudeModelChoices, buildModelOptionDescription } from './models/index.mjs';
|
|
54
54
|
|
|
55
55
|
// Configure command line arguments - GitHub PR URL as positional argument
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
56
|
+
const createReviewYargsConfig = yargsInstance =>
|
|
57
|
+
yargsInstance
|
|
58
|
+
.usage('Usage: $0 <pr-url> [options]')
|
|
59
|
+
.command('$0 <pr-url>', 'Review a GitHub pull request', yargs =>
|
|
60
|
+
yargs.positional('pr-url', {
|
|
61
|
+
type: 'string',
|
|
62
|
+
description: 'The GitHub pull request URL to review',
|
|
63
|
+
})
|
|
64
|
+
)
|
|
65
|
+
.option('resume', {
|
|
66
|
+
type: 'string',
|
|
67
|
+
description: 'Resume from a previous session ID (when limit was reached)',
|
|
68
|
+
alias: 'r',
|
|
69
|
+
})
|
|
70
|
+
.option('dry-run', {
|
|
71
|
+
type: 'boolean',
|
|
72
|
+
description: 'Prepare everything but do not execute Claude',
|
|
73
|
+
alias: 'n',
|
|
74
|
+
})
|
|
75
|
+
.option('model', {
|
|
76
|
+
type: 'string',
|
|
77
|
+
description: buildModelOptionDescription(),
|
|
78
|
+
alias: 'm',
|
|
79
|
+
default: defaultModels.claude,
|
|
80
|
+
choices: getClaudeModelChoices(),
|
|
81
|
+
})
|
|
82
|
+
.option('focus', {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'Focus areas for review (security, performance, logic, style, tests)',
|
|
85
|
+
alias: 'f',
|
|
86
|
+
default: 'all',
|
|
87
|
+
})
|
|
88
|
+
.option('approve', {
|
|
89
|
+
type: 'boolean',
|
|
90
|
+
description: 'If review passes, approve the PR',
|
|
91
|
+
default: false,
|
|
92
|
+
})
|
|
93
|
+
.option('verbose', {
|
|
94
|
+
type: 'boolean',
|
|
95
|
+
description: 'Enable verbose logging for debugging',
|
|
96
|
+
alias: 'v',
|
|
97
|
+
default: false,
|
|
98
|
+
})
|
|
99
|
+
.option('execute-tool-with-bun', {
|
|
100
|
+
type: 'boolean',
|
|
101
|
+
description: 'Execute the AI tool using bunx (experimental, may improve speed and memory usage)',
|
|
102
|
+
default: false,
|
|
103
|
+
})
|
|
104
|
+
.check(parsed => {
|
|
105
|
+
if (!parsed['pr-url'] && !parsed.prUrl && !parsed._?.[0]) {
|
|
106
|
+
throw new Error('The GitHub pull request URL is required');
|
|
107
|
+
}
|
|
108
|
+
return true;
|
|
109
|
+
})
|
|
110
|
+
.parserConfiguration({
|
|
111
|
+
'boolean-negation': true,
|
|
112
|
+
})
|
|
113
|
+
.help('h')
|
|
114
|
+
.alias('h', 'help')
|
|
115
|
+
// Use yargs built-in strict mode to reject unrecognized options
|
|
116
|
+
// This prevents issues like #453 and #482 where unknown options are silently ignored
|
|
117
|
+
.strict();
|
|
118
|
+
|
|
119
|
+
const argv = parseCliArgumentsWithLino({
|
|
120
|
+
argv: process.argv,
|
|
121
|
+
commandName: 'review',
|
|
122
|
+
createYargsConfig: createReviewYargsConfig,
|
|
123
|
+
positionalAliases: ['pr-url'],
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const prUrl = argv['pr-url'] || argv.prUrl || argv._[0];
|
|
114
127
|
|
|
115
128
|
// Set global verbose mode for log function
|
|
116
129
|
global.verboseMode = argv.verbose;
|