@link-assistant/hive-mind 1.59.7 → 1.61.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 +12 -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.issue-creation.lib.mjs +203 -0
- package/src/task.mjs +217 -232
- package/src/task.split.lib.mjs +221 -0
- package/src/telegram-bot.mjs +30 -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 +191 -0
package/src/reviewers-hive.mjs
CHANGED
|
@@ -7,7 +7,7 @@ const { use } = eval(await (await fetch('https://unpkg.com/use-m/use.js')).text(
|
|
|
7
7
|
const { $: __rawDollar$ } = await use('command-stream');
|
|
8
8
|
const { wrapDollarWithGhRetry } = await import('./github-rate-limit.lib.mjs');
|
|
9
9
|
const $ = wrapDollarWithGhRetry(__rawDollar$);
|
|
10
|
-
const
|
|
10
|
+
const { getLinoYargsFactory, hideBin, parseCliArgumentsWithLino } = await import('./cli-arguments.lib.mjs');
|
|
11
11
|
const path = (await use('path')).default;
|
|
12
12
|
const fs = (await use('fs')).promises;
|
|
13
13
|
|
|
@@ -46,97 +46,113 @@ const log = async (message, options = {}) => {
|
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
// Configure command line arguments
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
49
|
+
const createReviewersHiveYargsConfig = yargsInstance =>
|
|
50
|
+
yargsInstance
|
|
51
|
+
.usage('Usage: $0 <github-url> [options]')
|
|
52
|
+
.command('$0 <github-url>', 'Monitor pull requests for review', yargs =>
|
|
53
|
+
yargs.positional('github-url', {
|
|
54
|
+
type: 'string',
|
|
55
|
+
description: 'GitHub organization, repository, or user URL to monitor for pull requests',
|
|
56
|
+
})
|
|
57
|
+
)
|
|
58
|
+
.option('review-label', {
|
|
59
|
+
type: 'string',
|
|
60
|
+
description: 'GitHub label to identify PRs needing review',
|
|
61
|
+
default: 'needs-review',
|
|
62
|
+
alias: 'l',
|
|
63
|
+
})
|
|
64
|
+
.option('all-prs', {
|
|
65
|
+
type: 'boolean',
|
|
66
|
+
description: 'Review all open pull requests regardless of labels',
|
|
67
|
+
default: false,
|
|
68
|
+
alias: 'a',
|
|
69
|
+
})
|
|
70
|
+
.option('skip-draft', {
|
|
71
|
+
type: 'boolean',
|
|
72
|
+
description: 'Skip draft pull requests',
|
|
73
|
+
default: true,
|
|
74
|
+
alias: 'd',
|
|
75
|
+
})
|
|
76
|
+
.option('skip-approved', {
|
|
77
|
+
type: 'boolean',
|
|
78
|
+
description: 'Skip pull requests that already have approvals',
|
|
79
|
+
default: true,
|
|
80
|
+
})
|
|
81
|
+
.option('concurrency', {
|
|
82
|
+
type: 'number',
|
|
83
|
+
description: 'Number of concurrent review.mjs instances',
|
|
84
|
+
default: 2,
|
|
85
|
+
alias: 'c',
|
|
86
|
+
})
|
|
87
|
+
.option('reviews-per-pr', {
|
|
88
|
+
type: 'number',
|
|
89
|
+
description: 'Number of reviews to generate per PR (for diverse perspectives)',
|
|
90
|
+
default: 1,
|
|
91
|
+
alias: 'r',
|
|
92
|
+
})
|
|
93
|
+
.option('model', {
|
|
94
|
+
type: 'string',
|
|
95
|
+
description: 'Model to use for review.mjs (opus or sonnet)',
|
|
96
|
+
alias: 'm',
|
|
97
|
+
default: 'opus',
|
|
98
|
+
choices: ['opus', 'sonnet'],
|
|
99
|
+
})
|
|
100
|
+
.option('focus', {
|
|
101
|
+
type: 'string',
|
|
102
|
+
description: 'Focus areas for reviews (security, performance, logic, style, tests, all)',
|
|
103
|
+
default: 'all',
|
|
104
|
+
alias: 'f',
|
|
105
|
+
})
|
|
106
|
+
.option('auto-approve', {
|
|
107
|
+
type: 'boolean',
|
|
108
|
+
description: 'Auto-approve PRs that pass review criteria',
|
|
109
|
+
default: false,
|
|
110
|
+
})
|
|
111
|
+
.option('interval', {
|
|
112
|
+
type: 'number',
|
|
113
|
+
description: 'Polling interval in seconds',
|
|
114
|
+
default: 300, // 5 minutes
|
|
115
|
+
alias: 'i',
|
|
116
|
+
})
|
|
117
|
+
.option('max-prs', {
|
|
118
|
+
type: 'number',
|
|
119
|
+
description: 'Maximum number of PRs to process (0 = unlimited)',
|
|
120
|
+
default: 0,
|
|
121
|
+
})
|
|
122
|
+
.option('dry-run', {
|
|
123
|
+
type: 'boolean',
|
|
124
|
+
description: 'List PRs that would be reviewed without actually reviewing them',
|
|
125
|
+
default: false,
|
|
126
|
+
})
|
|
127
|
+
.option('verbose', {
|
|
128
|
+
type: 'boolean',
|
|
129
|
+
description: 'Enable verbose logging',
|
|
130
|
+
alias: 'v',
|
|
131
|
+
default: false,
|
|
132
|
+
})
|
|
133
|
+
.option('once', {
|
|
134
|
+
type: 'boolean',
|
|
135
|
+
description: 'Run once and exit instead of continuous monitoring',
|
|
136
|
+
default: false,
|
|
137
|
+
})
|
|
138
|
+
.demandCommand(1, 'GitHub URL is required')
|
|
139
|
+
.help('h')
|
|
140
|
+
.alias('h', 'help');
|
|
141
|
+
|
|
142
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
143
|
+
const helpYargs = createReviewersHiveYargsConfig(getLinoYargsFactory()(hideBin(process.argv)));
|
|
144
|
+
helpYargs.showHelp();
|
|
145
|
+
process.exit(0);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const argv = parseCliArgumentsWithLino({
|
|
149
|
+
argv: process.argv,
|
|
150
|
+
commandName: 'reviewers-hive',
|
|
151
|
+
createYargsConfig: createReviewersHiveYargsConfig,
|
|
152
|
+
positionalAliases: ['github-url'],
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const githubUrl = argv['github-url'] || argv.githubUrl || argv._[0];
|
|
140
156
|
|
|
141
157
|
// Set global verbose mode
|
|
142
158
|
global.verboseMode = argv.verbose;
|
package/src/solve.config.lib.mjs
CHANGED
|
@@ -10,23 +10,13 @@
|
|
|
10
10
|
import { enhanceErrorMessage, detectMalformedFlags } from './option-suggestions.lib.mjs';
|
|
11
11
|
import { defaultModels, buildModelOptionDescription, resolveDefaultFallbackModel, resolveRuntimeDefaultModel } from './models/index.mjs';
|
|
12
12
|
import { validateBranchName } from './solve.branch.lib.mjs';
|
|
13
|
-
import {
|
|
13
|
+
import { getLinoYargsFactory, hideBin, parseCliArgumentsWithLino } from './cli-arguments.lib.mjs';
|
|
14
14
|
|
|
15
15
|
// Re-export for use by telegram-bot.mjs (avoids extra import lines there)
|
|
16
16
|
export { detectMalformedFlags };
|
|
17
17
|
|
|
18
18
|
// Export an initialization function that accepts 'use'
|
|
19
|
-
export const initializeConfig = async
|
|
20
|
-
// Import yargs with specific version for hideBin support
|
|
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
|
-
|
|
28
|
-
return { yargs, hideBin };
|
|
29
|
-
};
|
|
19
|
+
export const initializeConfig = async () => ({ yargs: getLinoYargsFactory(), hideBin });
|
|
30
20
|
|
|
31
21
|
// Solve option definitions as a plain data structure.
|
|
32
22
|
// This is the single source of truth for all solve command options.
|
|
@@ -582,8 +572,8 @@ export const createYargsConfig = yargsInstance => {
|
|
|
582
572
|
};
|
|
583
573
|
|
|
584
574
|
// Parse command line arguments - now needs yargs and hideBin passed in
|
|
585
|
-
export const parseArguments = async (yargs, hideBin) => {
|
|
586
|
-
const rawArgs =
|
|
575
|
+
export const parseArguments = async (yargs = getLinoYargsFactory(), hideBinFn = hideBin) => {
|
|
576
|
+
const rawArgs = hideBinFn(process.argv);
|
|
587
577
|
|
|
588
578
|
// Issue #1092: Detect malformed flag patterns BEFORE yargs parsing
|
|
589
579
|
// This catches cases like "-- model" which yargs silently treats as positional arguments
|
|
@@ -621,7 +611,12 @@ export const parseArguments = async (yargs, hideBin) => {
|
|
|
621
611
|
|
|
622
612
|
try {
|
|
623
613
|
yargsInstance = createYargsConfig(yargs());
|
|
624
|
-
argv =
|
|
614
|
+
argv = parseCliArgumentsWithLino({
|
|
615
|
+
argv: process.argv,
|
|
616
|
+
commandName: 'solve',
|
|
617
|
+
createYargsConfig,
|
|
618
|
+
positionalAliases: ['issue-url'],
|
|
619
|
+
});
|
|
625
620
|
} finally {
|
|
626
621
|
// Always restore stderr.write
|
|
627
622
|
process.stderr.write = originalStderrWrite;
|
package/src/start-screen.mjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import { exec } from 'child_process';
|
|
5
5
|
import { promisify } from 'util';
|
|
6
|
+
import { parseCliArgumentsWithLino } from './cli-arguments.lib.mjs';
|
|
6
7
|
|
|
7
8
|
const execAsync = promisify(exec);
|
|
8
9
|
|
|
@@ -10,6 +11,72 @@ const execAsync = promisify(exec);
|
|
|
10
11
|
// This ensures consistent URL validation across all commands (hive, solve, start-screen)
|
|
11
12
|
const { parseGitHubUrl } = await import('./github.lib.mjs');
|
|
12
13
|
|
|
14
|
+
const START_SCREEN_USAGE = ['Usage: start-screen [--auto-terminate] <solve|hive> <github-url> [additional-args...]', '', 'Options:', ' --auto-terminate Session terminates after command completes (old behavior)', ' By default, session stays alive for review and reattachment', '', 'Examples:', ' start-screen solve https://github.com/user/repo/issues/123 --dry-run', ' start-screen --auto-terminate solve https://github.com/user/repo/issues/456', ' start-screen hive https://github.com/user/repo --flag value'];
|
|
15
|
+
|
|
16
|
+
const printUsage = (log = console.error) => {
|
|
17
|
+
for (const line of START_SCREEN_USAGE) {
|
|
18
|
+
log(line);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const createStartScreenYargsConfig = yargsInstance =>
|
|
23
|
+
yargsInstance
|
|
24
|
+
.usage(START_SCREEN_USAGE[0])
|
|
25
|
+
.command('$0 <command> <github-url> [additional-args..]', 'Launch solve or hive in a GNU screen session', yargs =>
|
|
26
|
+
yargs
|
|
27
|
+
.positional('command', {
|
|
28
|
+
type: 'string',
|
|
29
|
+
description: 'Command to run',
|
|
30
|
+
})
|
|
31
|
+
.positional('github-url', {
|
|
32
|
+
type: 'string',
|
|
33
|
+
description: 'GitHub repository or issue URL',
|
|
34
|
+
})
|
|
35
|
+
.positional('additional-args', {
|
|
36
|
+
array: true,
|
|
37
|
+
type: 'string',
|
|
38
|
+
description: 'Arguments to pass through to the command',
|
|
39
|
+
})
|
|
40
|
+
)
|
|
41
|
+
.option('auto-terminate', {
|
|
42
|
+
type: 'boolean',
|
|
43
|
+
description: 'Session terminates after command completes',
|
|
44
|
+
default: false,
|
|
45
|
+
})
|
|
46
|
+
.option('help', {
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
description: 'Show help',
|
|
49
|
+
alias: 'h',
|
|
50
|
+
default: false,
|
|
51
|
+
})
|
|
52
|
+
.parserConfiguration({
|
|
53
|
+
'boolean-negation': true,
|
|
54
|
+
'unknown-options-as-args': true,
|
|
55
|
+
})
|
|
56
|
+
.help(false)
|
|
57
|
+
.version(false)
|
|
58
|
+
.strict(false);
|
|
59
|
+
|
|
60
|
+
const parseStartScreenArgs = args => {
|
|
61
|
+
const help = args.includes('--help') || args.includes('-h');
|
|
62
|
+
const parsed = parseCliArgumentsWithLino({
|
|
63
|
+
argv: args.filter(arg => arg !== '--help' && arg !== '-h'),
|
|
64
|
+
commandName: 'start-screen',
|
|
65
|
+
createYargsConfig: createStartScreenYargsConfig,
|
|
66
|
+
positionalAliases: ['command', 'github-url', 'additional-args'],
|
|
67
|
+
lenv: { enabled: false },
|
|
68
|
+
getenv: { enabled: false },
|
|
69
|
+
});
|
|
70
|
+
const additionalArgs = parsed.additionalArgs || parsed['additional-args'] || [];
|
|
71
|
+
return {
|
|
72
|
+
autoTerminate: parsed.autoTerminate === true || parsed['auto-terminate'] === true,
|
|
73
|
+
help,
|
|
74
|
+
command: parsed.command,
|
|
75
|
+
githubUrl: parsed.githubUrl || parsed['github-url'],
|
|
76
|
+
commandArgs: Array.isArray(additionalArgs) ? additionalArgs : [additionalArgs],
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
13
80
|
/**
|
|
14
81
|
* Generate a screen session name based on the command and GitHub URL
|
|
15
82
|
* @param {string} command - Either 'solve' or 'hive'
|
|
@@ -221,23 +288,18 @@ async function createOrEnterScreen(sessionName, command, args, autoTerminate = f
|
|
|
221
288
|
async function main() {
|
|
222
289
|
const args = process.argv.slice(2);
|
|
223
290
|
|
|
291
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
292
|
+
printUsage(console.log);
|
|
293
|
+
process.exit(0);
|
|
294
|
+
}
|
|
295
|
+
|
|
224
296
|
if (args.length < 2) {
|
|
225
|
-
console.error
|
|
226
|
-
console.error('');
|
|
227
|
-
console.error('Options:');
|
|
228
|
-
console.error(' --auto-terminate Session terminates after command completes (old behavior)');
|
|
229
|
-
console.error(' By default, session stays alive for review and reattachment');
|
|
230
|
-
console.error('');
|
|
231
|
-
console.error('Examples:');
|
|
232
|
-
console.error(' start-screen solve https://github.com/user/repo/issues/123 --dry-run');
|
|
233
|
-
console.error(' start-screen --auto-terminate solve https://github.com/user/repo/issues/456');
|
|
234
|
-
console.error(' start-screen hive https://github.com/user/repo --flag value');
|
|
297
|
+
printUsage(console.error);
|
|
235
298
|
process.exit(1);
|
|
236
299
|
}
|
|
237
300
|
|
|
238
301
|
// Check for --auto-terminate flag at the beginning
|
|
239
302
|
// Also validate that first arg is not an unrecognized option with em-dash or other invalid dash
|
|
240
|
-
let autoTerminate = false;
|
|
241
303
|
let argsOffset = 0;
|
|
242
304
|
|
|
243
305
|
// Check for various dash characters in first argument (em-dash \u2014, en-dash \u2013, etc.)
|
|
@@ -249,7 +311,6 @@ async function main() {
|
|
|
249
311
|
}
|
|
250
312
|
|
|
251
313
|
if (args[0] === '--auto-terminate') {
|
|
252
|
-
autoTerminate = true;
|
|
253
314
|
argsOffset = 1;
|
|
254
315
|
|
|
255
316
|
if (args.length < 3) {
|
|
@@ -277,9 +338,7 @@ async function main() {
|
|
|
277
338
|
}
|
|
278
339
|
}
|
|
279
340
|
|
|
280
|
-
const command = args
|
|
281
|
-
const githubUrl = args[argsOffset + 1];
|
|
282
|
-
const commandArgs = args.slice(argsOffset + 2);
|
|
341
|
+
const { autoTerminate, command, githubUrl, commandArgs } = parseStartScreenArgs(args);
|
|
283
342
|
|
|
284
343
|
// Validate command
|
|
285
344
|
if (command !== 'solve' && command !== 'hive') {
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { constants as fsConstants, promises as fs } from 'fs';
|
|
3
|
+
import { createRequire } from 'module';
|
|
4
|
+
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
|
|
7
|
+
function startAgentExecutableName() {
|
|
8
|
+
return process.platform === 'win32' ? 'start-agent.cmd' : 'start-agent';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function canExecute(filePath) {
|
|
12
|
+
try {
|
|
13
|
+
await fs.access(filePath, fsConstants.X_OK);
|
|
14
|
+
return true;
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getBundledStartAgentCandidate() {
|
|
21
|
+
try {
|
|
22
|
+
const entryPath = require.resolve('agent-commander');
|
|
23
|
+
return path.join(path.dirname(path.dirname(entryPath)), 'bin', 'start-agent.mjs');
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function resolveStartAgentCommand(options = {}) {
|
|
30
|
+
const { cwd = process.cwd(), runCommand } = options;
|
|
31
|
+
const candidates = [getBundledStartAgentCandidate(), path.join(cwd, 'node_modules', '.bin', startAgentExecutableName())].filter(Boolean);
|
|
32
|
+
|
|
33
|
+
for (const candidate of candidates) {
|
|
34
|
+
if (await canExecute(candidate)) return candidate;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!runCommand) return null;
|
|
38
|
+
|
|
39
|
+
const lookupCommand = process.platform === 'win32' ? 'where' : 'which';
|
|
40
|
+
const result = await runCommand(lookupCommand, ['start-agent']);
|
|
41
|
+
if (result.code !== 0) return null;
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
(result.stdout || '')
|
|
45
|
+
.split(/\r?\n/)
|
|
46
|
+
.map(line => line.trim())
|
|
47
|
+
.find(Boolean) || null
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function buildStartAgentArgs(options) {
|
|
52
|
+
const { tool, workingDirectory, prompt, systemPrompt, model, isolation, screenName, verbose } = options;
|
|
53
|
+
const args = ['--tool', tool, '--working-directory', workingDirectory, '--prompt', prompt, '--system-prompt', systemPrompt, '--model', model, '--isolation', isolation, '--read-only'];
|
|
54
|
+
|
|
55
|
+
if (isolation === 'screen' && screenName) {
|
|
56
|
+
args.push('--screen-name', screenName);
|
|
57
|
+
}
|
|
58
|
+
if (verbose) args.push('--verbose');
|
|
59
|
+
|
|
60
|
+
return args;
|
|
61
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { buildModelOptionDescription, defaultModels } from './models/index.mjs';
|
|
2
|
+
import { parseCliArgumentsWithLino } from './cli-arguments.lib.mjs';
|
|
3
|
+
|
|
4
|
+
export const TASK_TOOL_CHOICES = ['claude', 'codex', 'opencode', 'agent'];
|
|
5
|
+
|
|
6
|
+
export function getDefaultTaskModel(tool) {
|
|
7
|
+
return defaultModels[tool] || defaultModels.claude;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const createYargsConfig = yargsInstance =>
|
|
11
|
+
yargsInstance
|
|
12
|
+
.usage('Usage: task.mjs <task-description> [options]')
|
|
13
|
+
.command('$0 <task-input>', 'Clarify, decompose, or split a task', yargs => {
|
|
14
|
+
yargs.positional('task-input', {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'GitHub issue URL for --split, or a task description for clarify/decompose mode',
|
|
17
|
+
});
|
|
18
|
+
})
|
|
19
|
+
.option('clarify', {
|
|
20
|
+
type: 'boolean',
|
|
21
|
+
description: 'Enable clarification mode',
|
|
22
|
+
default: true,
|
|
23
|
+
})
|
|
24
|
+
.option('decompose', {
|
|
25
|
+
type: 'boolean',
|
|
26
|
+
description: 'Enable decomposition mode',
|
|
27
|
+
default: true,
|
|
28
|
+
})
|
|
29
|
+
.option('only-clarify', {
|
|
30
|
+
type: 'boolean',
|
|
31
|
+
description: 'Only run clarification mode',
|
|
32
|
+
default: false,
|
|
33
|
+
})
|
|
34
|
+
.option('only-decompose', {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'Only run decomposition mode',
|
|
37
|
+
default: false,
|
|
38
|
+
})
|
|
39
|
+
.option('split', {
|
|
40
|
+
type: 'boolean',
|
|
41
|
+
description: 'Split a GitHub issue into smaller GitHub issues',
|
|
42
|
+
default: false,
|
|
43
|
+
})
|
|
44
|
+
.option('split-count', {
|
|
45
|
+
type: 'number',
|
|
46
|
+
description: 'Number of issues to split into',
|
|
47
|
+
default: 2,
|
|
48
|
+
})
|
|
49
|
+
.option('tool', {
|
|
50
|
+
type: 'string',
|
|
51
|
+
description: 'AI tool to use through agent-commander read-only mode',
|
|
52
|
+
choices: TASK_TOOL_CHOICES,
|
|
53
|
+
default: 'claude',
|
|
54
|
+
})
|
|
55
|
+
.option('model', {
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: buildModelOptionDescription(),
|
|
58
|
+
alias: 'm',
|
|
59
|
+
})
|
|
60
|
+
.option('isolation', {
|
|
61
|
+
type: 'string',
|
|
62
|
+
description: 'agent-commander isolation mode',
|
|
63
|
+
choices: ['screen', 'none', 'docker'],
|
|
64
|
+
default: 'screen',
|
|
65
|
+
})
|
|
66
|
+
.option('screen-name', {
|
|
67
|
+
type: 'string',
|
|
68
|
+
description: 'Screen session name when --isolation screen is used',
|
|
69
|
+
})
|
|
70
|
+
.option('dry-run', {
|
|
71
|
+
type: 'boolean',
|
|
72
|
+
description: 'Print planned split issues without creating or linking GitHub issues',
|
|
73
|
+
default: false,
|
|
74
|
+
})
|
|
75
|
+
.option('verbose', {
|
|
76
|
+
type: 'boolean',
|
|
77
|
+
description: 'Enable verbose logging',
|
|
78
|
+
alias: 'v',
|
|
79
|
+
default: false,
|
|
80
|
+
})
|
|
81
|
+
.option('output-format', {
|
|
82
|
+
type: 'string',
|
|
83
|
+
description: 'Output format',
|
|
84
|
+
alias: 'o',
|
|
85
|
+
choices: ['text', 'json'],
|
|
86
|
+
default: 'text',
|
|
87
|
+
})
|
|
88
|
+
.check(argv => {
|
|
89
|
+
if (!argv['task-input'] && !argv._[0]) {
|
|
90
|
+
throw new Error('Please provide a GitHub issue URL or task description');
|
|
91
|
+
}
|
|
92
|
+
if (argv['only-clarify'] && argv['only-decompose']) {
|
|
93
|
+
throw new Error('Cannot use both --only-clarify and --only-decompose at the same time');
|
|
94
|
+
}
|
|
95
|
+
if (argv.split && (argv['only-clarify'] || argv['only-decompose'])) {
|
|
96
|
+
throw new Error('Cannot use --split with --only-clarify or --only-decompose');
|
|
97
|
+
}
|
|
98
|
+
if (argv.split && argv['split-count'] < 2) {
|
|
99
|
+
throw new Error('--split-count must be at least 2');
|
|
100
|
+
}
|
|
101
|
+
if (argv['only-clarify']) argv.decompose = false;
|
|
102
|
+
if (argv['only-decompose']) argv.clarify = false;
|
|
103
|
+
if (argv.split) {
|
|
104
|
+
argv.clarify = false;
|
|
105
|
+
argv.decompose = false;
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
})
|
|
109
|
+
.parserConfiguration({
|
|
110
|
+
'boolean-negation': true,
|
|
111
|
+
})
|
|
112
|
+
.strict()
|
|
113
|
+
.help('h')
|
|
114
|
+
.alias('h', 'help');
|
|
115
|
+
|
|
116
|
+
export const parseTaskArguments = (argv = process.argv) =>
|
|
117
|
+
parseCliArgumentsWithLino({
|
|
118
|
+
argv,
|
|
119
|
+
commandName: 'task',
|
|
120
|
+
createYargsConfig,
|
|
121
|
+
positionalAliases: ['task-input'],
|
|
122
|
+
});
|