@link-assistant/hive-mind 1.59.6 → 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 +44 -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.auto-merge.lib.mjs +37 -0
- package/src/solve.config.lib.mjs +12 -17
- package/src/solve.mjs +17 -35
- package/src/solve.results.lib.mjs +86 -12
- package/src/solve.watch.lib.mjs +36 -0
- 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/src/tool-comments.lib.mjs +12 -1
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
|
+
});
|