@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/task.mjs
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { spawn } from 'child_process';
|
|
6
|
+
import { promises as fs } from 'fs';
|
|
7
|
+
import { buildStartAgentArgs, resolveStartAgentCommand } from './task.agent-command.lib.mjs';
|
|
8
|
+
import { getDefaultTaskModel, parseTaskArguments } from './task.config.lib.mjs';
|
|
9
|
+
import { validateModelName } from './models/index.mjs';
|
|
10
|
+
import { appendOrReplaceParentSplitSection, buildAddSubIssueApiArgs, buildIssueRestIdApiArgs, buildTaskSplitPrompt, buildTaskSplitSystemPrompt, extractTaskSplitJson, formatChildIssueBody, normalizeSplitTasks, parseCreatedIssueUrl, parseTaskIssueUrl } from './task.split.lib.mjs';
|
|
11
|
+
|
|
4
12
|
const earlyArgs = process.argv.slice(2);
|
|
5
13
|
|
|
6
14
|
if (earlyArgs.includes('--version')) {
|
|
7
15
|
const { getVersion } = await import('./version.lib.mjs');
|
|
8
16
|
try {
|
|
9
|
-
|
|
10
|
-
console.log(version);
|
|
17
|
+
console.log(await getVersion());
|
|
11
18
|
} catch {
|
|
12
19
|
console.error('Error: Unable to determine version');
|
|
13
20
|
process.exit(1);
|
|
@@ -15,8 +22,7 @@ if (earlyArgs.includes('--version')) {
|
|
|
15
22
|
process.exit(0);
|
|
16
23
|
}
|
|
17
24
|
|
|
18
|
-
if (earlyArgs.includes('--help') || earlyArgs.includes('-h')) {
|
|
19
|
-
// Show help and exit
|
|
25
|
+
if (earlyArgs.length === 0 || earlyArgs.includes('--help') || earlyArgs.includes('-h')) {
|
|
20
26
|
console.log('Usage: task.mjs <task-description> [options]');
|
|
21
27
|
console.log('\nOptions:');
|
|
22
28
|
console.log(' --version Show version number');
|
|
@@ -25,283 +31,262 @@ if (earlyArgs.includes('--help') || earlyArgs.includes('-h')) {
|
|
|
25
31
|
console.log(' --decompose Enable decomposition mode [default: true]');
|
|
26
32
|
console.log(' --only-clarify Only run clarification mode');
|
|
27
33
|
console.log(' --only-decompose Only run decomposition mode');
|
|
28
|
-
console.log(' --
|
|
34
|
+
console.log(' --split Split a GitHub issue into smaller issues');
|
|
35
|
+
console.log(' --split-count Number of issues to split into [default: 2]');
|
|
36
|
+
console.log(' --tool AI tool for agent-commander read-only mode (claude, codex, opencode, agent) [default: claude]');
|
|
37
|
+
console.log(' --model, -m Model to use');
|
|
38
|
+
console.log(' --isolation agent-commander isolation mode [default: screen]');
|
|
39
|
+
console.log(' --dry-run Print split output without creating GitHub issues');
|
|
29
40
|
console.log(' --verbose, -v Enable verbose logging');
|
|
30
41
|
console.log(' --output-format Output format (text or json) [default: text]');
|
|
31
|
-
process.exit(0);
|
|
42
|
+
process.exit(earlyArgs.length === 0 ? 1 : 0);
|
|
32
43
|
}
|
|
33
44
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// Import Claude execution functions
|
|
43
|
-
import { mapModelToId } from './claude.lib.mjs';
|
|
44
|
-
import { claudeModels, defaultModels, buildModelOptionDescription } from './models/index.mjs';
|
|
45
|
-
|
|
46
|
-
// Global log file reference
|
|
47
|
-
let logFile = null;
|
|
48
|
-
|
|
49
|
-
// Helper function to log to both console and file
|
|
50
|
-
const log = async (message, options = {}) => {
|
|
51
|
-
const { level = 'info', verbose = false } = options;
|
|
52
|
-
|
|
53
|
-
// Skip verbose logs unless --verbose is enabled
|
|
54
|
-
if (verbose && !global.verboseMode) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Write to file if log file is set
|
|
59
|
-
if (logFile) {
|
|
60
|
-
const logMessage = `[${new Date().toISOString()}] [${level.toUpperCase()}] ${message}`;
|
|
61
|
-
await fs.appendFile(logFile, logMessage + '\n').catch(() => {});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Write to console based on level
|
|
65
|
-
switch (level) {
|
|
66
|
-
case 'error':
|
|
67
|
-
console.error(message);
|
|
68
|
-
break;
|
|
69
|
-
case 'warning':
|
|
70
|
-
case 'warn':
|
|
71
|
-
console.warn(message);
|
|
72
|
-
break;
|
|
73
|
-
case 'info':
|
|
74
|
-
default:
|
|
75
|
-
console.log(message);
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// Configure command line arguments - task description as positional argument
|
|
81
|
-
// Use yargs().parse(args) instead of yargs(args).argv to ensure .strict() mode works
|
|
82
|
-
const argv = yargs()
|
|
83
|
-
.usage('Usage: $0 <task-description> [options]')
|
|
84
|
-
.positional('task-description', {
|
|
85
|
-
type: 'string',
|
|
86
|
-
description: 'The task to clarify and decompose',
|
|
87
|
-
})
|
|
88
|
-
.option('clarify', {
|
|
89
|
-
type: 'boolean',
|
|
90
|
-
description: 'Enable clarification mode (asks clarifying questions about the task)',
|
|
91
|
-
default: true,
|
|
92
|
-
})
|
|
93
|
-
.option('decompose', {
|
|
94
|
-
type: 'boolean',
|
|
95
|
-
description: 'Enable decomposition mode (breaks down the task into subtasks)',
|
|
96
|
-
default: true,
|
|
97
|
-
})
|
|
98
|
-
.option('only-clarify', {
|
|
99
|
-
type: 'boolean',
|
|
100
|
-
description: 'Only run clarification mode, skip decomposition',
|
|
101
|
-
default: false,
|
|
102
|
-
})
|
|
103
|
-
.option('only-decompose', {
|
|
104
|
-
type: 'boolean',
|
|
105
|
-
description: 'Only run decomposition mode, skip clarification',
|
|
106
|
-
default: false,
|
|
107
|
-
})
|
|
108
|
-
.option('model', {
|
|
109
|
-
type: 'string',
|
|
110
|
-
description: buildModelOptionDescription(),
|
|
111
|
-
alias: 'm',
|
|
112
|
-
default: defaultModels.claude,
|
|
113
|
-
choices: Object.keys(claudeModels),
|
|
114
|
-
})
|
|
115
|
-
.option('verbose', {
|
|
116
|
-
type: 'boolean',
|
|
117
|
-
description: 'Enable verbose logging for debugging',
|
|
118
|
-
alias: 'v',
|
|
119
|
-
default: false,
|
|
120
|
-
})
|
|
121
|
-
.option('output-format', {
|
|
122
|
-
type: 'string',
|
|
123
|
-
description: 'Output format (text or json)',
|
|
124
|
-
alias: 'o',
|
|
125
|
-
default: 'text',
|
|
126
|
-
choices: ['text', 'json'],
|
|
127
|
-
})
|
|
128
|
-
.option('execute-tool-with-bun', {
|
|
129
|
-
type: 'boolean',
|
|
130
|
-
description: 'Execute the AI tool using bunx (experimental, may improve speed and memory usage)',
|
|
131
|
-
default: false,
|
|
132
|
-
})
|
|
133
|
-
.check(argv => {
|
|
134
|
-
if (!argv['task-description'] && !argv._[0]) {
|
|
135
|
-
throw new Error('Please provide a task description');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Handle mutual exclusivity of only-clarify and only-decompose
|
|
139
|
-
if (argv['only-clarify'] && argv['only-decompose']) {
|
|
140
|
-
throw new Error('Cannot use both --only-clarify and --only-decompose at the same time');
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// If only-clarify is set, disable decompose
|
|
144
|
-
if (argv['only-clarify']) {
|
|
145
|
-
argv.decompose = false;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// If only-decompose is set, disable clarify
|
|
149
|
-
if (argv['only-decompose']) {
|
|
150
|
-
argv.clarify = false;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return true;
|
|
154
|
-
})
|
|
155
|
-
.parserConfiguration({
|
|
156
|
-
'boolean-negation': true,
|
|
157
|
-
})
|
|
158
|
-
.help()
|
|
159
|
-
.alias('h', 'help')
|
|
160
|
-
// Use yargs built-in strict mode to reject unrecognized options
|
|
161
|
-
// This prevents issues like #453 and #482 where unknown options are silently ignored
|
|
162
|
-
.strict()
|
|
163
|
-
.parse(process.argv.slice(2));
|
|
164
|
-
|
|
165
|
-
const taskDescription = argv['task-description'] || argv._[0];
|
|
45
|
+
let argv;
|
|
46
|
+
try {
|
|
47
|
+
argv = parseTaskArguments(process.argv);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(error.message || String(error));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
166
52
|
|
|
167
|
-
|
|
168
|
-
|
|
53
|
+
const taskInput = argv['task-input'] || argv.taskInput || argv._[0];
|
|
54
|
+
const selectedModel = argv.model || getDefaultTaskModel(argv.tool);
|
|
55
|
+
const modelValidation = validateModelName(selectedModel, argv.tool);
|
|
56
|
+
if (!modelValidation.valid) {
|
|
57
|
+
console.error(modelValidation.message);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
169
60
|
|
|
170
|
-
// Create permanent log file immediately with timestamp
|
|
171
61
|
const scriptDir = path.dirname(process.argv[1]);
|
|
172
62
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
173
|
-
logFile = path.join(scriptDir, `task-${timestamp}.log`);
|
|
63
|
+
const logFile = path.join(scriptDir, `task-${timestamp}.log`);
|
|
174
64
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
await
|
|
65
|
+
async function log(message, options = {}) {
|
|
66
|
+
const { level = 'info', verbose = false } = options;
|
|
67
|
+
if (verbose && !argv.verbose) return;
|
|
68
|
+
await fs.appendFile(logFile, `[${new Date().toISOString()}] [${level.toUpperCase()}] ${message}\n`).catch(() => {});
|
|
69
|
+
if (level === 'error') console.error(message);
|
|
70
|
+
else if (level === 'warning' || level === 'warn') console.warn(message);
|
|
71
|
+
else console.log(message);
|
|
72
|
+
}
|
|
179
73
|
|
|
180
|
-
|
|
181
|
-
const formatAligned = (icon, label, value, indent = 0) => {
|
|
74
|
+
function formatAligned(icon, label, value, indent = 0) {
|
|
182
75
|
const spaces = ' '.repeat(indent);
|
|
183
76
|
const labelWidth = 25 - indent;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
await log('\nšÆ Task Processing Started');
|
|
189
|
-
await log(formatAligned('š', 'Task description:', taskDescription));
|
|
190
|
-
await log(formatAligned('š¤', 'Model:', argv.model));
|
|
191
|
-
await log(formatAligned('š”', 'Clarify mode:', argv.clarify ? 'enabled' : 'disabled'));
|
|
192
|
-
await log(formatAligned('š', 'Decompose mode:', argv.decompose ? 'enabled' : 'disabled'));
|
|
193
|
-
await log(formatAligned('š', 'Output format:', argv.outputFormat));
|
|
194
|
-
|
|
195
|
-
const claudePath = argv.executeToolWithBun ? 'bunx claude' : process.env.CLAUDE_PATH || 'claude';
|
|
196
|
-
|
|
197
|
-
// Helper function to execute Claude command
|
|
198
|
-
const executeClaude = (prompt, model) => {
|
|
199
|
-
return new Promise((resolve, reject) => {
|
|
200
|
-
// Map model alias to full ID
|
|
201
|
-
const mappedModel = mapModelToId(model);
|
|
202
|
-
|
|
203
|
-
const args = ['-p', prompt, '--output-format', 'text', '--dangerously-skip-permissions', '--model', mappedModel];
|
|
77
|
+
return `${spaces}${icon} ${label.padEnd(labelWidth)} ${value || ''}`;
|
|
78
|
+
}
|
|
204
79
|
|
|
205
|
-
|
|
80
|
+
function runCommand(command, args, options = {}) {
|
|
81
|
+
return new Promise(resolve => {
|
|
82
|
+
const child = spawn(command, args, {
|
|
206
83
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
207
84
|
env: process.env,
|
|
85
|
+
...options,
|
|
208
86
|
});
|
|
209
|
-
|
|
210
87
|
let stdout = '';
|
|
211
88
|
let stderr = '';
|
|
212
|
-
|
|
213
89
|
child.stdout.on('data', data => {
|
|
214
90
|
stdout += data.toString();
|
|
215
91
|
});
|
|
216
|
-
|
|
217
92
|
child.stderr.on('data', data => {
|
|
218
93
|
stderr += data.toString();
|
|
219
94
|
});
|
|
220
|
-
|
|
95
|
+
child.on('error', error => {
|
|
96
|
+
resolve({ code: 1, stdout, stderr: stderr || error.message });
|
|
97
|
+
});
|
|
221
98
|
child.on('close', code => {
|
|
222
|
-
|
|
223
|
-
resolve(stdout.trim());
|
|
224
|
-
} else {
|
|
225
|
-
reject(new Error(`Claude exited with code ${code}: ${stderr}`));
|
|
226
|
-
}
|
|
99
|
+
resolve({ code, stdout, stderr });
|
|
227
100
|
});
|
|
101
|
+
});
|
|
102
|
+
}
|
|
228
103
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
104
|
+
async function commandOutput(command, args, options = {}) {
|
|
105
|
+
const result = await runCommand(command, args, options);
|
|
106
|
+
if (result.code !== 0) {
|
|
107
|
+
const output = `${result.stderr || ''}${result.stdout || ''}`.trim();
|
|
108
|
+
throw new Error(output || `${command} exited with code ${result.code}`);
|
|
109
|
+
}
|
|
110
|
+
return result.stdout.trim();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function buildScreenName(issue) {
|
|
114
|
+
const base = issue ? `task-split-${issue.owner}-${issue.repo}-${issue.number}` : 'task-agent';
|
|
115
|
+
return `${base}-${crypto.randomUUID().slice(0, 8)}`.replace(/[^A-Za-z0-9_.-]/g, '-');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function runAgentPrompt(prompt, systemPrompt, issue = null) {
|
|
119
|
+
const startAgent = await resolveStartAgentCommand({ runCommand });
|
|
120
|
+
if (!startAgent) {
|
|
121
|
+
throw new Error('agent-commander start-agent binary not found. Run npm install so the agent-commander dependency is available, or install start-agent on PATH.');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const args = buildStartAgentArgs({
|
|
125
|
+
tool: argv.tool,
|
|
126
|
+
workingDirectory: process.cwd(),
|
|
127
|
+
prompt,
|
|
128
|
+
systemPrompt,
|
|
129
|
+
model: selectedModel,
|
|
130
|
+
isolation: argv.isolation,
|
|
131
|
+
screenName: argv.isolation === 'screen' ? argv.screenName || buildScreenName(issue) : null,
|
|
132
|
+
verbose: argv.verbose,
|
|
232
133
|
});
|
|
233
|
-
};
|
|
234
134
|
|
|
235
|
-
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
135
|
+
await log(`Running agent-commander with tool=${argv.tool}, model=${selectedModel}, isolation=${argv.isolation}, readOnly=true`, { verbose: true });
|
|
136
|
+
const result = await runCommand(startAgent, args);
|
|
137
|
+
const output = `${result.stdout || ''}${result.stderr ? `\n${result.stderr}` : ''}`.trim();
|
|
138
|
+
if (result.code !== 0) {
|
|
139
|
+
throw new Error(output || `start-agent exited with code ${result.code}`);
|
|
140
|
+
}
|
|
141
|
+
return output;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function fetchIssue(issue) {
|
|
145
|
+
const issueJson = await commandOutput('gh', ['issue', 'view', String(issue.number), '--repo', `${issue.owner}/${issue.repo}`, '--json', 'title,body,number,url,labels']);
|
|
146
|
+
const data = JSON.parse(issueJson);
|
|
147
|
+
return {
|
|
148
|
+
owner: issue.owner,
|
|
149
|
+
repo: issue.repo,
|
|
150
|
+
number: data.number,
|
|
151
|
+
url: data.url,
|
|
152
|
+
title: data.title,
|
|
153
|
+
body: data.body || '',
|
|
154
|
+
labels: Array.isArray(data.labels) ? data.labels.map(label => label.name).filter(Boolean) : [],
|
|
241
155
|
};
|
|
156
|
+
}
|
|
242
157
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
158
|
+
async function fetchIssueRestId(issue) {
|
|
159
|
+
const id = Number(await commandOutput('gh', buildIssueRestIdApiArgs(issue)));
|
|
160
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
161
|
+
throw new Error(`Could not resolve REST id for issue #${issue.number}`);
|
|
162
|
+
}
|
|
163
|
+
return id;
|
|
164
|
+
}
|
|
247
165
|
|
|
248
|
-
|
|
166
|
+
async function createChildIssue(parentIssue, task, index, splitCount) {
|
|
167
|
+
const args = ['issue', 'create', '--repo', `${parentIssue.owner}/${parentIssue.repo}`, '--title', task.title, '--body', formatChildIssueBody({ parentIssue, task, index, splitCount })];
|
|
168
|
+
if (parentIssue.labels.length > 0) {
|
|
169
|
+
args.push('--label', parentIssue.labels.join(','));
|
|
170
|
+
}
|
|
249
171
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
172
|
+
const url = await commandOutput('gh', args);
|
|
173
|
+
const parsed = parseCreatedIssueUrl(url);
|
|
174
|
+
const restId = await fetchIssueRestId(parsed);
|
|
175
|
+
return {
|
|
176
|
+
owner: parsed.owner,
|
|
177
|
+
repo: parsed.repo,
|
|
178
|
+
number: parsed.number,
|
|
179
|
+
restId,
|
|
180
|
+
url,
|
|
181
|
+
title: task.title,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
255
184
|
|
|
256
|
-
|
|
185
|
+
async function linkChildIssue(parentIssue, childIssue) {
|
|
186
|
+
await commandOutput('gh', buildAddSubIssueApiArgs({ parentIssue, subIssueId: childIssue.restId }));
|
|
187
|
+
}
|
|
257
188
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
189
|
+
async function updateParentIssue(parentIssue, childIssues) {
|
|
190
|
+
const body = appendOrReplaceParentSplitSection(parentIssue.body, childIssues);
|
|
191
|
+
await commandOutput('gh', ['issue', 'edit', String(parentIssue.number), '--repo', `${parentIssue.owner}/${parentIssue.repo}`, '--body', body]);
|
|
192
|
+
const childList = childIssues.map(issue => `- #${issue.number} ${issue.title}`).join('\n');
|
|
193
|
+
await commandOutput('gh', ['issue', 'comment', String(parentIssue.number), '--repo', `${parentIssue.owner}/${parentIssue.repo}`, '--body', `Split into ${childIssues.length} tasks:\n\n${childList}`]);
|
|
194
|
+
}
|
|
263
195
|
|
|
264
|
-
|
|
265
|
-
|
|
196
|
+
async function runSplitMode() {
|
|
197
|
+
const parsedIssue = parseTaskIssueUrl(taskInput);
|
|
198
|
+
if (!parsedIssue.valid) {
|
|
199
|
+
throw new Error(parsedIssue.error || 'Invalid GitHub issue URL');
|
|
266
200
|
}
|
|
267
201
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
202
|
+
const parentIssue = await fetchIssue(parsedIssue);
|
|
203
|
+
const prompt = buildTaskSplitPrompt({ issue: parentIssue, splitCount: argv.splitCount });
|
|
204
|
+
const output = await runAgentPrompt(prompt, buildTaskSplitSystemPrompt(), parentIssue);
|
|
205
|
+
const tasks = normalizeSplitTasks(extractTaskSplitJson(output), argv.splitCount);
|
|
206
|
+
|
|
207
|
+
if (argv.dryRun) {
|
|
208
|
+
return {
|
|
209
|
+
parentIssue,
|
|
210
|
+
tasks,
|
|
211
|
+
createdIssues: [],
|
|
212
|
+
dryRun: true,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
272
215
|
|
|
273
|
-
|
|
216
|
+
const createdIssues = [];
|
|
217
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
218
|
+
createdIssues.push(await createChildIssue(parentIssue, tasks[i], i, tasks.length));
|
|
219
|
+
}
|
|
220
|
+
for (const childIssue of createdIssues) {
|
|
221
|
+
await linkChildIssue(parentIssue, childIssue);
|
|
222
|
+
}
|
|
223
|
+
await updateParentIssue(parentIssue, createdIssues);
|
|
274
224
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
225
|
+
return {
|
|
226
|
+
parentIssue,
|
|
227
|
+
tasks,
|
|
228
|
+
createdIssues,
|
|
229
|
+
dryRun: false,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
278
232
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
233
|
+
async function runClarifyOrDecomposeMode() {
|
|
234
|
+
const results = {
|
|
235
|
+
task: taskInput,
|
|
236
|
+
timestamp: new Date().toISOString(),
|
|
237
|
+
clarification: null,
|
|
238
|
+
decomposition: null,
|
|
239
|
+
};
|
|
285
240
|
|
|
286
|
-
|
|
241
|
+
if (argv.clarify) {
|
|
242
|
+
const prompt = `Task: "${taskInput}"
|
|
287
243
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
244
|
+
Please help clarify this task by:
|
|
245
|
+
1. Identifying ambiguous aspects of the task
|
|
246
|
+
2. Asking 3-5 specific clarifying questions
|
|
247
|
+
3. Suggesting assumptions that could be made if these questions are not answered
|
|
248
|
+
4. Identifying missing context or requirements`;
|
|
249
|
+
results.clarification = await runAgentPrompt(prompt, 'Return a concise clarification analysis. Do not modify files or run commands.');
|
|
250
|
+
}
|
|
293
251
|
|
|
294
|
-
|
|
295
|
-
|
|
252
|
+
if (argv.decompose) {
|
|
253
|
+
const prompt = `Task: "${taskInput}"
|
|
254
|
+
|
|
255
|
+
${results.clarification ? `Clarification analysis:\n${results.clarification}\n\n` : ''}Please decompose this task into actionable subtasks with dependencies, complexity, risks, and success criteria.`;
|
|
256
|
+
results.decomposition = await runAgentPrompt(prompt, 'Return a concise decomposition. Do not modify files or run commands.');
|
|
296
257
|
}
|
|
297
258
|
|
|
298
|
-
|
|
259
|
+
return results;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
try {
|
|
263
|
+
await fs.writeFile(logFile, `# Task Log - ${new Date().toISOString()}\n\n`);
|
|
264
|
+
await log(`š Log file: ${logFile}`);
|
|
265
|
+
await log('\nšÆ Task Processing Started');
|
|
266
|
+
await log(formatAligned('š', 'Task input:', taskInput));
|
|
267
|
+
await log(formatAligned('š ', 'Tool:', argv.tool));
|
|
268
|
+
await log(formatAligned('š¤', 'Model:', selectedModel));
|
|
269
|
+
await log(formatAligned('š', 'Isolation:', argv.isolation));
|
|
270
|
+
await log(formatAligned('āļø', 'Split mode:', argv.split ? `enabled (count: ${argv.splitCount})` : 'disabled'));
|
|
271
|
+
|
|
272
|
+
const result = argv.split ? await runSplitMode() : await runClarifyOrDecomposeMode();
|
|
273
|
+
|
|
299
274
|
if (argv.outputFormat === 'json') {
|
|
300
|
-
console.log(
|
|
275
|
+
console.log(JSON.stringify(result, null, 2));
|
|
276
|
+
} else if (argv.split) {
|
|
277
|
+
if (result.dryRun) {
|
|
278
|
+
console.log('\nPlanned split issues:');
|
|
279
|
+
result.tasks.forEach((task, index) => console.log(`${index + 1}. ${task.title}`));
|
|
280
|
+
} else {
|
|
281
|
+
console.log('\nCreated split issues:');
|
|
282
|
+
result.createdIssues.forEach(issue => console.log(`- #${issue.number} ${issue.url}`));
|
|
283
|
+
}
|
|
284
|
+
} else {
|
|
285
|
+
if (result.clarification) console.log(`\nClarification Results:\n${result.clarification}`);
|
|
286
|
+
if (result.decomposition) console.log(`\nDecomposition Results:\n${result.decomposition}`);
|
|
301
287
|
}
|
|
302
288
|
|
|
303
289
|
await log('\nš Task processing completed successfully');
|
|
304
|
-
await log(`š” Review the session log for details: ${logFile}`);
|
|
305
290
|
} catch (error) {
|
|
306
291
|
await log(`ā Error processing task: ${error.message}`, { level: 'error' });
|
|
307
292
|
process.exit(1);
|