techunter 0.1.0 → 0.1.2
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/README.md +1 -1
- package/dist/index.js +533 -228
- package/dist/mcp.js +477 -199
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -17,12 +17,14 @@ __export(github_exports, {
|
|
|
17
17
|
closeTask: () => closeTask,
|
|
18
18
|
createPR: () => createPR,
|
|
19
19
|
createTask: () => createTask,
|
|
20
|
+
editTask: () => editTask,
|
|
20
21
|
ensureLabels: () => ensureLabels,
|
|
21
22
|
formatGuideAsMarkdown: () => formatGuideAsMarkdown,
|
|
22
23
|
getAuthenticatedUser: () => getAuthenticatedUser,
|
|
23
24
|
getBaseBranch: () => getBaseBranch,
|
|
24
25
|
getDefaultBranch: () => getDefaultBranch,
|
|
25
26
|
getTask: () => getTask,
|
|
27
|
+
isCollaborator: () => isCollaborator,
|
|
26
28
|
listComments: () => listComments,
|
|
27
29
|
listMyTasks: () => listMyTasks,
|
|
28
30
|
listTasks: () => listTasks,
|
|
@@ -49,6 +51,7 @@ function parseIssue(issue) {
|
|
|
49
51
|
title: issue.title,
|
|
50
52
|
body: issue.body ?? null,
|
|
51
53
|
state: issue.state,
|
|
54
|
+
author: issue.user?.login ?? null,
|
|
52
55
|
assignee: issue.assignee?.login ?? null,
|
|
53
56
|
labels: (issue.labels ?? []).map(
|
|
54
57
|
(l) => typeof l === "string" ? l : l.name ?? ""
|
|
@@ -59,46 +62,15 @@ function parseIssue(issue) {
|
|
|
59
62
|
async function listTasks(config) {
|
|
60
63
|
const octokit = createOctokit(config.githubToken);
|
|
61
64
|
const { owner, repo } = config.github;
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
owner,
|
|
72
|
-
repo,
|
|
73
|
-
labels: LABEL_CLAIMED,
|
|
74
|
-
state: "open",
|
|
75
|
-
per_page: 50
|
|
76
|
-
}),
|
|
77
|
-
octokit.issues.listForRepo({
|
|
78
|
-
owner,
|
|
79
|
-
repo,
|
|
80
|
-
labels: LABEL_IN_REVIEW,
|
|
81
|
-
state: "open",
|
|
82
|
-
per_page: 50
|
|
83
|
-
}),
|
|
84
|
-
octokit.issues.listForRepo({
|
|
85
|
-
owner,
|
|
86
|
-
repo,
|
|
87
|
-
labels: LABEL_CHANGES_NEEDED,
|
|
88
|
-
state: "open",
|
|
89
|
-
per_page: 50
|
|
90
|
-
})
|
|
91
|
-
]);
|
|
92
|
-
const allIssues = [...available.data, ...claimed.data, ...inReview.data, ...changesNeeded.data];
|
|
93
|
-
const seen = /* @__PURE__ */ new Set();
|
|
94
|
-
const unique = [];
|
|
95
|
-
for (const issue of allIssues) {
|
|
96
|
-
if (!seen.has(issue.number)) {
|
|
97
|
-
seen.add(issue.number);
|
|
98
|
-
unique.push(parseIssue(issue));
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return unique.sort((a, b) => a.number - b.number);
|
|
65
|
+
const { data } = await octokit.issues.listForRepo({
|
|
66
|
+
owner,
|
|
67
|
+
repo,
|
|
68
|
+
state: "open",
|
|
69
|
+
per_page: 100
|
|
70
|
+
});
|
|
71
|
+
return data.filter(
|
|
72
|
+
(issue) => !issue.pull_request && issue.labels.some((l) => TECHUNTER_LABELS.has(l.name ?? ""))
|
|
73
|
+
).map(parseIssue).sort((a, b) => a.number - b.number);
|
|
102
74
|
}
|
|
103
75
|
async function getTask(config, number) {
|
|
104
76
|
const octokit = createOctokit(config.githubToken);
|
|
@@ -256,6 +228,16 @@ async function getAuthenticatedUser(config) {
|
|
|
256
228
|
const { data } = await octokit.users.getAuthenticated();
|
|
257
229
|
return data.login;
|
|
258
230
|
}
|
|
231
|
+
async function isCollaborator(config, username) {
|
|
232
|
+
const octokit = createOctokit(config.githubToken);
|
|
233
|
+
const { owner, repo } = config.github;
|
|
234
|
+
try {
|
|
235
|
+
const { data } = await octokit.repos.getCollaboratorPermissionLevel({ owner, repo, username });
|
|
236
|
+
return data.permission === "admin" || data.permission === "write" || data.permission === "maintain";
|
|
237
|
+
} catch {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
259
241
|
async function listMyTasks(config, username) {
|
|
260
242
|
const octokit = createOctokit(config.githubToken);
|
|
261
243
|
const { owner, repo } = config.github;
|
|
@@ -316,6 +298,11 @@ async function ensureLabels(config) {
|
|
|
316
298
|
)
|
|
317
299
|
);
|
|
318
300
|
}
|
|
301
|
+
async function editTask(config, number, title, body) {
|
|
302
|
+
const octokit = createOctokit(config.githubToken);
|
|
303
|
+
const { owner, repo } = config.github;
|
|
304
|
+
await octokit.issues.update({ owner, repo, issue_number: number, title, body });
|
|
305
|
+
}
|
|
319
306
|
async function getDefaultBranch(config) {
|
|
320
307
|
const octokit = createOctokit(config.githubToken);
|
|
321
308
|
const { owner, repo } = config.github;
|
|
@@ -341,7 +328,7 @@ async function acceptTask(config, issueNumber) {
|
|
|
341
328
|
await closeTask(config, issueNumber);
|
|
342
329
|
return { prNumber: pr.number, prUrl: pr.html_url, sha: merge.sha ?? "" };
|
|
343
330
|
}
|
|
344
|
-
var LABEL_AVAILABLE, LABEL_CLAIMED, LABEL_IN_REVIEW, LABEL_CHANGES_NEEDED, LABELS;
|
|
331
|
+
var LABEL_AVAILABLE, LABEL_CLAIMED, LABEL_IN_REVIEW, LABEL_CHANGES_NEEDED, LABELS, TECHUNTER_LABELS;
|
|
345
332
|
var init_github = __esm({
|
|
346
333
|
"src/lib/github.ts"() {
|
|
347
334
|
"use strict";
|
|
@@ -355,6 +342,7 @@ var init_github = __esm({
|
|
|
355
342
|
{ name: LABEL_IN_REVIEW, color: "0075ca", description: "Task submitted for review" },
|
|
356
343
|
{ name: LABEL_CHANGES_NEEDED, color: "e11d48", description: "Task needs changes" }
|
|
357
344
|
];
|
|
345
|
+
TECHUNTER_LABELS = /* @__PURE__ */ new Set([LABEL_AVAILABLE, LABEL_CLAIMED, LABEL_IN_REVIEW, LABEL_CHANGES_NEEDED]);
|
|
358
346
|
}
|
|
359
347
|
});
|
|
360
348
|
|
|
@@ -362,6 +350,7 @@ var init_github = __esm({
|
|
|
362
350
|
import chalk14 from "chalk";
|
|
363
351
|
import readline from "readline";
|
|
364
352
|
import { createRequire } from "module";
|
|
353
|
+
import { input as input3 } from "@inquirer/prompts";
|
|
365
354
|
|
|
366
355
|
// src/commands/init.ts
|
|
367
356
|
import { input, password, select } from "@inquirer/prompts";
|
|
@@ -383,7 +372,11 @@ var configSchema = z.object({
|
|
|
383
372
|
owner: z.string().min(1),
|
|
384
373
|
repo: z.string().min(1),
|
|
385
374
|
baseBranch: z.string().optional()
|
|
386
|
-
})
|
|
375
|
+
}),
|
|
376
|
+
taskState: z.object({
|
|
377
|
+
activeIssueNumber: z.number().optional(),
|
|
378
|
+
baseCommit: z.string().optional()
|
|
379
|
+
}).optional()
|
|
387
380
|
});
|
|
388
381
|
var store = new Conf({
|
|
389
382
|
projectName: "techunter",
|
|
@@ -420,6 +413,12 @@ function setConfig(partial) {
|
|
|
420
413
|
if (partial.githubClientId !== void 0) {
|
|
421
414
|
current["githubClientId"] = partial.githubClientId;
|
|
422
415
|
}
|
|
416
|
+
if (partial.taskState !== void 0) {
|
|
417
|
+
current["taskState"] = {
|
|
418
|
+
...current["taskState"] ?? {},
|
|
419
|
+
...partial.taskState
|
|
420
|
+
};
|
|
421
|
+
}
|
|
423
422
|
store.store = current;
|
|
424
423
|
}
|
|
425
424
|
function getConfigPath() {
|
|
@@ -437,9 +436,6 @@ async function getCurrentBranch() {
|
|
|
437
436
|
const summary = await git.branch();
|
|
438
437
|
return summary.current;
|
|
439
438
|
}
|
|
440
|
-
async function createAndSwitchBranch(name) {
|
|
441
|
-
await git.checkoutLocalBranch(name);
|
|
442
|
-
}
|
|
443
439
|
async function pushBranch(name) {
|
|
444
440
|
await git.push("origin", name, ["--set-upstream"]);
|
|
445
441
|
}
|
|
@@ -467,6 +463,61 @@ function makeBranchName(issueNumber, username) {
|
|
|
467
463
|
const slug = username.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "user";
|
|
468
464
|
return `task-${issueNumber}-${slug}`;
|
|
469
465
|
}
|
|
466
|
+
function makeWorkerBranchName(username) {
|
|
467
|
+
const slug = username.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "user";
|
|
468
|
+
return `worker-${slug}`;
|
|
469
|
+
}
|
|
470
|
+
async function getCurrentCommit() {
|
|
471
|
+
return (await git.revparse(["HEAD"])).trim();
|
|
472
|
+
}
|
|
473
|
+
async function switchToBranchOrCreate(name) {
|
|
474
|
+
try {
|
|
475
|
+
const branches = await git.branch(["-a"]);
|
|
476
|
+
const exists = Object.keys(branches.branches).some(
|
|
477
|
+
(b) => b === name || b === `remotes/origin/${name}`
|
|
478
|
+
);
|
|
479
|
+
if (exists) {
|
|
480
|
+
await git.checkout(name);
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
await git.checkoutLocalBranch(name);
|
|
484
|
+
return true;
|
|
485
|
+
} catch {
|
|
486
|
+
await git.checkoutLocalBranch(name);
|
|
487
|
+
return true;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
async function getDiffFromCommit(baseCommit) {
|
|
491
|
+
const status = await git.status();
|
|
492
|
+
const parts = [];
|
|
493
|
+
const fileLines = [
|
|
494
|
+
...status.modified.map((f) => ` M ${f}`),
|
|
495
|
+
...status.created.map((f) => ` A ${f}`),
|
|
496
|
+
...status.deleted.map((f) => ` D ${f}`),
|
|
497
|
+
...status.renamed.map((f) => ` R ${f.from} \u2192 ${f.to}`),
|
|
498
|
+
...status.not_added.map((f) => ` ? ${f}`)
|
|
499
|
+
];
|
|
500
|
+
if (fileLines.length > 0) {
|
|
501
|
+
parts.push("## Uncommitted changes\n" + fileLines.join("\n"));
|
|
502
|
+
const uncommitted = await git.diff(["HEAD"]);
|
|
503
|
+
if (uncommitted) {
|
|
504
|
+
const capped = uncommitted.length > 8e3 ? uncommitted.slice(0, 8e3) + "\n... (truncated)" : uncommitted;
|
|
505
|
+
parts.push("## Uncommitted diff\n```diff\n" + capped + "\n```");
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
const log = await git.log({ from: baseCommit, to: "HEAD" });
|
|
509
|
+
if (log.total > 0) {
|
|
510
|
+
const logLines = log.all.map((c) => ` ${c.hash.slice(0, 7)} ${c.message}`);
|
|
511
|
+
parts.push(`## Commits since task claimed (${log.total} total)
|
|
512
|
+
` + logLines.join("\n"));
|
|
513
|
+
const branchDiff = await git.diff([baseCommit, "HEAD"]);
|
|
514
|
+
if (branchDiff) {
|
|
515
|
+
const capped = branchDiff.length > 12e3 ? branchDiff.slice(0, 12e3) + "\n... (truncated)" : branchDiff;
|
|
516
|
+
parts.push("## Full diff since task claimed\n```diff\n" + capped + "\n```");
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return parts.length > 0 ? parts.join("\n\n") : "No changes since task was claimed.";
|
|
520
|
+
}
|
|
470
521
|
async function findMergeBase(configuredBase) {
|
|
471
522
|
const candidates = configuredBase ? [`origin/${configuredBase}`, "origin/main", "origin/master"] : ["origin/main", "origin/master"];
|
|
472
523
|
const unique = [...new Set(candidates)];
|
|
@@ -762,7 +813,7 @@ AI model set to: ${val.trim()}
|
|
|
762
813
|
init_github();
|
|
763
814
|
|
|
764
815
|
// src/lib/agent.ts
|
|
765
|
-
import
|
|
816
|
+
import ora15 from "ora";
|
|
766
817
|
import chalk13 from "chalk";
|
|
767
818
|
|
|
768
819
|
// src/tools/pick/index.ts
|
|
@@ -944,8 +995,8 @@ import { select as select3, input as promptInput } from "@inquirer/prompts";
|
|
|
944
995
|
|
|
945
996
|
// src/lib/agent-ui.ts
|
|
946
997
|
import chalk6 from "chalk";
|
|
947
|
-
function formatInput(
|
|
948
|
-
return Object.entries(
|
|
998
|
+
function formatInput(input4) {
|
|
999
|
+
return Object.entries(input4).map(([k, v]) => {
|
|
949
1000
|
if (typeof v === "number") return `${k}=${v}`;
|
|
950
1001
|
if (typeof v === "string") {
|
|
951
1002
|
if (k === "body" || v.length > 50) return `${k}=[${v.length} chars]`;
|
|
@@ -958,8 +1009,8 @@ function summarize(result) {
|
|
|
958
1009
|
const first = result.split("\n").find((l) => l.trim()) ?? result;
|
|
959
1010
|
return first.length > 100 ? first.slice(0, 97) + "..." : first;
|
|
960
1011
|
}
|
|
961
|
-
function printToolCall(name,
|
|
962
|
-
const params = formatInput(
|
|
1012
|
+
function printToolCall(name, input4) {
|
|
1013
|
+
const params = formatInput(input4);
|
|
963
1014
|
console.log(` ${chalk6.cyan("\u2192")} ${chalk6.bold(name)}${params ? " " + chalk6.dim(params) : ""}`);
|
|
964
1015
|
}
|
|
965
1016
|
function printToolResult(result) {
|
|
@@ -995,15 +1046,15 @@ async function runSubAgentLoop(config, systemPrompt, userMessage, toolNames) {
|
|
|
995
1046
|
}
|
|
996
1047
|
if (choice.finish_reason === "tool_calls") {
|
|
997
1048
|
for (const tc of choice.message.tool_calls ?? []) {
|
|
998
|
-
let
|
|
1049
|
+
let input4;
|
|
999
1050
|
try {
|
|
1000
|
-
|
|
1051
|
+
input4 = JSON.parse(tc.function.arguments);
|
|
1001
1052
|
} catch {
|
|
1002
|
-
|
|
1053
|
+
input4 = {};
|
|
1003
1054
|
}
|
|
1004
|
-
printToolCall(tc.function.name,
|
|
1055
|
+
printToolCall(tc.function.name, input4);
|
|
1005
1056
|
const mod = selected.find((m) => m.definition.function.name === tc.function.name);
|
|
1006
|
-
const result = mod ? await mod.execute(
|
|
1057
|
+
const result = mod ? await mod.execute(input4, config) : `Unknown tool: ${tc.function.name}`;
|
|
1007
1058
|
printToolResult(result);
|
|
1008
1059
|
messages.push({ role: "tool", tool_call_id: tc.id, content: result });
|
|
1009
1060
|
}
|
|
@@ -1012,7 +1063,7 @@ async function runSubAgentLoop(config, systemPrompt, userMessage, toolNames) {
|
|
|
1012
1063
|
}
|
|
1013
1064
|
|
|
1014
1065
|
// src/tools/submit/prompts.ts
|
|
1015
|
-
var REVIEWER_SYSTEM_PROMPT = "You are a concise code reviewer. Use run_command to run tests/lint if needed, and read_file to inspect specific files. Then output your review: for each acceptance criterion mark \u2705 met or \u274C not met with a one-line reason. End with an overall verdict line: Ready to submit / Not ready. Reply in the same language as the task.";
|
|
1066
|
+
var REVIEWER_SYSTEM_PROMPT = "You are a concise code reviewer. The diff provided shows all changes on this worker branch since the task was claimed. The branch is shared across tasks, so the diff may contain changes unrelated to this specific task \u2014 use the task title and acceptance criteria to identify which changes are relevant, and ignore the rest. Use run_command to run tests/lint if needed, and read_file to inspect specific files. Then output your review: for each acceptance criterion mark \u2705 met or \u274C not met with a one-line reason. End with an overall verdict line: Ready to submit / Not ready. Reply in the same language as the task.";
|
|
1016
1067
|
|
|
1017
1068
|
// src/tools/submit/reviewer.ts
|
|
1018
1069
|
async function reviewChanges(config, issueNumber, issue, diff) {
|
|
@@ -1045,33 +1096,42 @@ var definition = {
|
|
|
1045
1096
|
}
|
|
1046
1097
|
}
|
|
1047
1098
|
};
|
|
1048
|
-
async function run(config) {
|
|
1049
|
-
const
|
|
1050
|
-
const
|
|
1051
|
-
if (!
|
|
1052
|
-
return
|
|
1099
|
+
async function run(_input, config) {
|
|
1100
|
+
const taskState = getConfig().taskState;
|
|
1101
|
+
const issueNumber = taskState?.activeIssueNumber;
|
|
1102
|
+
if (!issueNumber) {
|
|
1103
|
+
return "No active task found. Claim a task first with /pick.";
|
|
1053
1104
|
}
|
|
1054
|
-
const issueNumber = parseInt(match[1], 10);
|
|
1055
1105
|
let spinner = ora2("Loading task and diff\u2026").start();
|
|
1056
|
-
const
|
|
1106
|
+
const diffPromise = taskState?.baseCommit ? getDiffFromCommit(taskState.baseCommit) : getDiff(config.github.baseBranch);
|
|
1107
|
+
const [issue, defaultBranch, diff, me] = await Promise.all([
|
|
1057
1108
|
getTask(config, issueNumber),
|
|
1058
1109
|
getBaseBranch(config),
|
|
1059
|
-
|
|
1110
|
+
diffPromise,
|
|
1111
|
+
getAuthenticatedUser(config)
|
|
1060
1112
|
]);
|
|
1061
1113
|
spinner.stop();
|
|
1062
|
-
const
|
|
1114
|
+
const branch = await getCurrentBranch();
|
|
1115
|
+
const isSelfSubmit = issue.author !== null && issue.author === me;
|
|
1063
1116
|
let review = "";
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1117
|
+
if (!isSelfSubmit) {
|
|
1118
|
+
const reviewSpinner = ora2("Reviewing changes\u2026").start();
|
|
1119
|
+
try {
|
|
1120
|
+
review = await reviewChanges(config, issueNumber, issue, diff);
|
|
1121
|
+
} catch (err) {
|
|
1122
|
+
review = `(Review failed: ${err.message})`;
|
|
1123
|
+
}
|
|
1124
|
+
reviewSpinner.stop();
|
|
1068
1125
|
}
|
|
1069
|
-
reviewSpinner.stop();
|
|
1070
1126
|
const divider = chalk7.dim("\u2500".repeat(70));
|
|
1071
1127
|
console.log("\n" + divider);
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1128
|
+
if (isSelfSubmit) {
|
|
1129
|
+
console.log(chalk7.yellow(` Self-submit detected \u2014 AI review skipped.`));
|
|
1130
|
+
} else {
|
|
1131
|
+
console.log(chalk7.bold(` Review \u2014 task #${issueNumber} "${issue.title}"`));
|
|
1132
|
+
console.log(divider);
|
|
1133
|
+
console.log(renderMarkdown(review));
|
|
1134
|
+
}
|
|
1075
1135
|
console.log(divider + "\n");
|
|
1076
1136
|
let shouldProceed;
|
|
1077
1137
|
try {
|
|
@@ -1107,15 +1167,15 @@ async function run(config) {
|
|
|
1107
1167
|
spinner = ora2("Creating pull request\u2026").start();
|
|
1108
1168
|
let prUrl;
|
|
1109
1169
|
try {
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
issue.
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
);
|
|
1170
|
+
const prBody = [
|
|
1171
|
+
`Closes #${issueNumber}`,
|
|
1172
|
+
issue.body ? `
|
|
1173
|
+
${issue.body}` : "",
|
|
1174
|
+
review ? `
|
|
1175
|
+
## AI Review
|
|
1176
|
+
${review}` : ""
|
|
1177
|
+
].join("\n").trim();
|
|
1178
|
+
prUrl = await createPR(config, issue.title, prBody, branch, defaultBranch);
|
|
1119
1179
|
spinner.stop();
|
|
1120
1180
|
} catch (err) {
|
|
1121
1181
|
spinner.stop();
|
|
@@ -1129,27 +1189,33 @@ ${issue.body ?? ""}`.trim(),
|
|
|
1129
1189
|
spinner.stop();
|
|
1130
1190
|
return `PR created (${prUrl}) but failed to update label: ${err.message}`;
|
|
1131
1191
|
}
|
|
1192
|
+
setConfig({ taskState: { activeIssueNumber: void 0, baseCommit: void 0 } });
|
|
1132
1193
|
return `Task #${issueNumber} submitted.
|
|
1133
1194
|
Commit: "${commitMessage.trim()}"
|
|
1134
1195
|
PR: ${prUrl}`;
|
|
1135
1196
|
}
|
|
1136
|
-
async function execute(
|
|
1137
|
-
const
|
|
1138
|
-
const
|
|
1139
|
-
if (!
|
|
1140
|
-
const
|
|
1141
|
-
const [issue, defaultBranch, diff] = await Promise.all([
|
|
1197
|
+
async function execute(input4, config) {
|
|
1198
|
+
const taskState = getConfig().taskState;
|
|
1199
|
+
const issueNumber = taskState?.activeIssueNumber;
|
|
1200
|
+
if (!issueNumber) return "No active task found. Claim a task first.";
|
|
1201
|
+
const diffPromise = taskState?.baseCommit ? getDiffFromCommit(taskState.baseCommit) : getDiff(config.github.baseBranch);
|
|
1202
|
+
const [issue, defaultBranch, diff, branch, me] = await Promise.all([
|
|
1142
1203
|
getTask(config, issueNumber),
|
|
1143
1204
|
getBaseBranch(config),
|
|
1144
|
-
|
|
1205
|
+
diffPromise,
|
|
1206
|
+
getCurrentBranch(),
|
|
1207
|
+
getAuthenticatedUser(config)
|
|
1145
1208
|
]);
|
|
1209
|
+
const isSelfSubmit = issue.author !== null && issue.author === me;
|
|
1146
1210
|
let review = "";
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1211
|
+
if (!isSelfSubmit) {
|
|
1212
|
+
try {
|
|
1213
|
+
review = await reviewChanges(config, issueNumber, issue, diff);
|
|
1214
|
+
} catch (err) {
|
|
1215
|
+
review = `(Review failed: ${err.message})`;
|
|
1216
|
+
}
|
|
1151
1217
|
}
|
|
1152
|
-
const commitMessage =
|
|
1218
|
+
const commitMessage = input4["commit_message"]?.trim() || `complete: ${issue.title}`;
|
|
1153
1219
|
try {
|
|
1154
1220
|
await stageAllAndCommit(commitMessage);
|
|
1155
1221
|
} catch (err) {
|
|
@@ -1157,15 +1223,15 @@ async function execute(input3, config) {
|
|
|
1157
1223
|
}
|
|
1158
1224
|
let prUrl;
|
|
1159
1225
|
try {
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
issue.
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
);
|
|
1226
|
+
const prBody = [
|
|
1227
|
+
`Closes #${issueNumber}`,
|
|
1228
|
+
issue.body ? `
|
|
1229
|
+
${issue.body}` : "",
|
|
1230
|
+
review ? `
|
|
1231
|
+
## AI Review
|
|
1232
|
+
${review}` : ""
|
|
1233
|
+
].join("\n").trim();
|
|
1234
|
+
prUrl = await createPR(config, issue.title, prBody, branch, defaultBranch);
|
|
1169
1235
|
} catch (err) {
|
|
1170
1236
|
return `Committed but PR creation failed: ${err.message}`;
|
|
1171
1237
|
}
|
|
@@ -1206,8 +1272,8 @@ var definition2 = {
|
|
|
1206
1272
|
}
|
|
1207
1273
|
}
|
|
1208
1274
|
};
|
|
1209
|
-
async function run2(
|
|
1210
|
-
let issueNumber =
|
|
1275
|
+
async function run2(input4, config) {
|
|
1276
|
+
let issueNumber = input4["issue_number"];
|
|
1211
1277
|
if (!issueNumber) {
|
|
1212
1278
|
let tasks;
|
|
1213
1279
|
try {
|
|
@@ -1248,8 +1314,8 @@ async function run2(config, opts = {}) {
|
|
|
1248
1314
|
return `Error: ${err.message}`;
|
|
1249
1315
|
}
|
|
1250
1316
|
}
|
|
1251
|
-
async function execute2(
|
|
1252
|
-
const issueNumber =
|
|
1317
|
+
async function execute2(input4, config) {
|
|
1318
|
+
const issueNumber = input4["issue_number"];
|
|
1253
1319
|
const spinner = ora3(`Closing #${issueNumber}\u2026`).start();
|
|
1254
1320
|
try {
|
|
1255
1321
|
await closeTask(config, issueNumber);
|
|
@@ -1282,7 +1348,8 @@ var definition3 = {
|
|
|
1282
1348
|
}
|
|
1283
1349
|
}
|
|
1284
1350
|
};
|
|
1285
|
-
async function run3(
|
|
1351
|
+
async function run3(input4, config) {
|
|
1352
|
+
const preselected = input4["issue_number"];
|
|
1286
1353
|
let chosenNumber;
|
|
1287
1354
|
if (preselected !== void 0) {
|
|
1288
1355
|
chosenNumber = preselected;
|
|
@@ -1358,23 +1425,28 @@ Finish or submit it before claiming a new one.`;
|
|
|
1358
1425
|
let spinner = ora4(`Claiming #${issue.number}\u2026`).start();
|
|
1359
1426
|
await claimTask(config, issue.number, me);
|
|
1360
1427
|
spinner.stop();
|
|
1361
|
-
const branch =
|
|
1362
|
-
spinner = ora4(`
|
|
1428
|
+
const branch = makeWorkerBranchName(me);
|
|
1429
|
+
spinner = ora4(`Switching to branch ${branch}\u2026`).start();
|
|
1430
|
+
let isNew = false;
|
|
1363
1431
|
try {
|
|
1364
|
-
await
|
|
1432
|
+
isNew = await switchToBranchOrCreate(branch);
|
|
1365
1433
|
spinner.stop();
|
|
1366
1434
|
} catch {
|
|
1367
|
-
spinner.warn(`Could not
|
|
1435
|
+
spinner.warn(`Could not switch to branch ${branch}`);
|
|
1368
1436
|
}
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1437
|
+
if (isNew) {
|
|
1438
|
+
spinner = ora4("Pushing branch\u2026").start();
|
|
1439
|
+
try {
|
|
1440
|
+
await pushBranch(branch);
|
|
1441
|
+
spinner.stop();
|
|
1442
|
+
} catch {
|
|
1443
|
+
spinner.warn("Could not push branch");
|
|
1444
|
+
}
|
|
1375
1445
|
}
|
|
1446
|
+
const baseCommit = await getCurrentCommit();
|
|
1447
|
+
setConfig({ taskState: { activeIssueNumber: issue.number, baseCommit } });
|
|
1376
1448
|
console.log(chalk8.green(`
|
|
1377
|
-
Claimed! Branch: ${branch}
|
|
1449
|
+
Claimed! Branch: ${branch} (base: ${baseCommit.slice(0, 7)})
|
|
1378
1450
|
`));
|
|
1379
1451
|
let openClaude;
|
|
1380
1452
|
try {
|
|
@@ -1394,13 +1466,13 @@ Finish or submit it before claiming a new one.`;
|
|
|
1394
1466
|
return `Error claiming task: ${err.message}`;
|
|
1395
1467
|
}
|
|
1396
1468
|
}
|
|
1397
|
-
if (action === "submit") return run(config);
|
|
1398
|
-
if (action === "close") return run2(
|
|
1469
|
+
if (action === "submit") return run({}, config);
|
|
1470
|
+
if (action === "close") return run2({ issue_number: issue.number }, config);
|
|
1399
1471
|
return "Cancelled.";
|
|
1400
1472
|
}
|
|
1401
|
-
async function execute3(
|
|
1402
|
-
const issueNumber =
|
|
1403
|
-
const action =
|
|
1473
|
+
async function execute3(input4, config) {
|
|
1474
|
+
const issueNumber = input4["issue_number"];
|
|
1475
|
+
const action = input4["action"];
|
|
1404
1476
|
let issue;
|
|
1405
1477
|
try {
|
|
1406
1478
|
issue = await getTask(config, issueNumber);
|
|
@@ -1427,16 +1499,21 @@ async function execute3(input3, config) {
|
|
|
1427
1499
|
} catch (err) {
|
|
1428
1500
|
return `Error claiming task: ${err.message}`;
|
|
1429
1501
|
}
|
|
1430
|
-
const branch =
|
|
1502
|
+
const branch = makeWorkerBranchName(me);
|
|
1503
|
+
let isNew = false;
|
|
1431
1504
|
try {
|
|
1432
|
-
await
|
|
1505
|
+
isNew = await switchToBranchOrCreate(branch);
|
|
1433
1506
|
} catch {
|
|
1434
1507
|
}
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1508
|
+
if (isNew) {
|
|
1509
|
+
try {
|
|
1510
|
+
await pushBranch(branch);
|
|
1511
|
+
} catch {
|
|
1512
|
+
}
|
|
1438
1513
|
}
|
|
1439
|
-
|
|
1514
|
+
const baseCommit = await getCurrentCommit();
|
|
1515
|
+
setConfig({ taskState: { activeIssueNumber: issueNumber, baseCommit } });
|
|
1516
|
+
return `Task #${issueNumber} claimed. Branch: ${branch} (base commit: ${baseCommit.slice(0, 7)})`;
|
|
1440
1517
|
}
|
|
1441
1518
|
return `Unknown action: ${action}`;
|
|
1442
1519
|
}
|
|
@@ -1526,8 +1603,22 @@ var definition4 = {
|
|
|
1526
1603
|
}
|
|
1527
1604
|
}
|
|
1528
1605
|
};
|
|
1529
|
-
async function run4(
|
|
1530
|
-
|
|
1606
|
+
async function run4(input4, config) {
|
|
1607
|
+
const authSpinner = ora5("Checking permissions\u2026").start();
|
|
1608
|
+
let me;
|
|
1609
|
+
let allowed;
|
|
1610
|
+
try {
|
|
1611
|
+
me = await getAuthenticatedUser(config);
|
|
1612
|
+
allowed = await isCollaborator(config, me);
|
|
1613
|
+
authSpinner.stop();
|
|
1614
|
+
} catch (err) {
|
|
1615
|
+
authSpinner.stop();
|
|
1616
|
+
return `Error checking permissions: ${err.message}`;
|
|
1617
|
+
}
|
|
1618
|
+
if (!allowed) {
|
|
1619
|
+
return `Permission denied: only repository collaborators can create tasks.`;
|
|
1620
|
+
}
|
|
1621
|
+
let title = input4["title"]?.trim();
|
|
1531
1622
|
if (!title) {
|
|
1532
1623
|
try {
|
|
1533
1624
|
title = (await promptInput2({ message: "Task title:" })).trim();
|
|
@@ -1623,9 +1714,13 @@ async function run4(config, opts = {}) {
|
|
|
1623
1714
|
}
|
|
1624
1715
|
return `Created #${issueNumber} "${issueTitle}" \u2014 ${htmlUrl}`;
|
|
1625
1716
|
}
|
|
1626
|
-
async function execute4(
|
|
1627
|
-
const
|
|
1628
|
-
|
|
1717
|
+
async function execute4(input4, config) {
|
|
1718
|
+
const me = await getAuthenticatedUser(config);
|
|
1719
|
+
if (!await isCollaborator(config, me)) {
|
|
1720
|
+
return `Permission denied: only repository collaborators can create tasks.`;
|
|
1721
|
+
}
|
|
1722
|
+
const title = input4["title"].trim();
|
|
1723
|
+
const feedback = input4["feedback"];
|
|
1629
1724
|
let guide = await generateGuide(config, title);
|
|
1630
1725
|
if (feedback) {
|
|
1631
1726
|
guide = await generateGuide(config, title, { feedback, previousGuide: guide });
|
|
@@ -1660,7 +1755,7 @@ var definition5 = {
|
|
|
1660
1755
|
parameters: { type: "object", properties: {}, required: [] }
|
|
1661
1756
|
}
|
|
1662
1757
|
};
|
|
1663
|
-
async function run5(config) {
|
|
1758
|
+
async function run5(_input, config) {
|
|
1664
1759
|
const spinner = ora6("Fetching your tasks\u2026").start();
|
|
1665
1760
|
try {
|
|
1666
1761
|
const me = await getAuthenticatedUser(config);
|
|
@@ -1675,7 +1770,7 @@ ${lines.join("\n")}`;
|
|
|
1675
1770
|
return `Error: ${err.message}`;
|
|
1676
1771
|
}
|
|
1677
1772
|
}
|
|
1678
|
-
var execute5 =
|
|
1773
|
+
var execute5 = run5;
|
|
1679
1774
|
var terminal5 = true;
|
|
1680
1775
|
|
|
1681
1776
|
// src/tools/review/index.ts
|
|
@@ -1696,7 +1791,7 @@ var definition6 = {
|
|
|
1696
1791
|
parameters: { type: "object", properties: {}, required: [] }
|
|
1697
1792
|
}
|
|
1698
1793
|
};
|
|
1699
|
-
async function run6(config) {
|
|
1794
|
+
async function run6(_input, config) {
|
|
1700
1795
|
const spinner = ora7("Loading tasks for review\u2026").start();
|
|
1701
1796
|
try {
|
|
1702
1797
|
const me = await getAuthenticatedUser(config);
|
|
@@ -1711,7 +1806,7 @@ ${lines.join("\n")}`;
|
|
|
1711
1806
|
return `Error: ${err.message}`;
|
|
1712
1807
|
}
|
|
1713
1808
|
}
|
|
1714
|
-
var execute6 =
|
|
1809
|
+
var execute6 = run6;
|
|
1715
1810
|
var terminal6 = true;
|
|
1716
1811
|
|
|
1717
1812
|
// src/tools/refresh/index.ts
|
|
@@ -1730,7 +1825,7 @@ var definition7 = {
|
|
|
1730
1825
|
parameters: { type: "object", properties: {}, required: [] }
|
|
1731
1826
|
}
|
|
1732
1827
|
};
|
|
1733
|
-
async function run7(config) {
|
|
1828
|
+
async function run7(_input, config) {
|
|
1734
1829
|
const tasks = await printTaskList(config);
|
|
1735
1830
|
if (tasks.length === 0) return "No tasks found.";
|
|
1736
1831
|
const lines = tasks.map((t) => {
|
|
@@ -1741,7 +1836,7 @@ async function run7(config) {
|
|
|
1741
1836
|
return `Tasks (${tasks.length}):
|
|
1742
1837
|
${lines.join("\n")}`;
|
|
1743
1838
|
}
|
|
1744
|
-
var execute7 =
|
|
1839
|
+
var execute7 = run7;
|
|
1745
1840
|
var terminal7 = true;
|
|
1746
1841
|
|
|
1747
1842
|
// src/tools/open-code/index.ts
|
|
@@ -1761,7 +1856,7 @@ var definition8 = {
|
|
|
1761
1856
|
parameters: { type: "object", properties: {}, required: [] }
|
|
1762
1857
|
}
|
|
1763
1858
|
};
|
|
1764
|
-
async function run8(config) {
|
|
1859
|
+
async function run8(_input, config) {
|
|
1765
1860
|
let branch;
|
|
1766
1861
|
try {
|
|
1767
1862
|
branch = await getCurrentBranch();
|
|
@@ -1780,7 +1875,7 @@ async function run8(config) {
|
|
|
1780
1875
|
await launchClaudeCode(issue, branch);
|
|
1781
1876
|
return "Claude Code session ended.";
|
|
1782
1877
|
}
|
|
1783
|
-
var execute8 =
|
|
1878
|
+
var execute8 = run8;
|
|
1784
1879
|
var terminal8 = true;
|
|
1785
1880
|
|
|
1786
1881
|
// src/tools/reject/index.ts
|
|
@@ -1840,8 +1935,15 @@ var definition9 = {
|
|
|
1840
1935
|
}
|
|
1841
1936
|
}
|
|
1842
1937
|
};
|
|
1843
|
-
async function run9(
|
|
1844
|
-
const
|
|
1938
|
+
async function run9(input4, config) {
|
|
1939
|
+
const issueNumber = input4["issue_number"];
|
|
1940
|
+
const [me, issue] = await Promise.all([
|
|
1941
|
+
getAuthenticatedUser(config),
|
|
1942
|
+
getTask(config, issueNumber)
|
|
1943
|
+
]);
|
|
1944
|
+
if (issue.author && issue.author !== me) {
|
|
1945
|
+
return `Permission denied: only the task author (@${issue.author}) can reject task #${issueNumber}.`;
|
|
1946
|
+
}
|
|
1845
1947
|
let feedback;
|
|
1846
1948
|
try {
|
|
1847
1949
|
feedback = await promptInput3({
|
|
@@ -1908,9 +2010,16 @@ async function run9(config, opts) {
|
|
|
1908
2010
|
return `Task #${issueNumber} rejected. Label changed to changes-needed.`;
|
|
1909
2011
|
}
|
|
1910
2012
|
}
|
|
1911
|
-
async function execute9(
|
|
1912
|
-
const issueNumber =
|
|
1913
|
-
const feedback =
|
|
2013
|
+
async function execute9(input4, config) {
|
|
2014
|
+
const issueNumber = input4["issue_number"];
|
|
2015
|
+
const feedback = input4["feedback"];
|
|
2016
|
+
const [me, issue] = await Promise.all([
|
|
2017
|
+
getAuthenticatedUser(config),
|
|
2018
|
+
getTask(config, issueNumber)
|
|
2019
|
+
]);
|
|
2020
|
+
if (issue.author && issue.author !== me) {
|
|
2021
|
+
return `Permission denied: only the task author (@${issue.author}) can reject task #${issueNumber}.`;
|
|
2022
|
+
}
|
|
1914
2023
|
let comment;
|
|
1915
2024
|
try {
|
|
1916
2025
|
comment = await generateRejectionComment(config, issueNumber, feedback);
|
|
@@ -1960,18 +2069,18 @@ var definition10 = {
|
|
|
1960
2069
|
}
|
|
1961
2070
|
}
|
|
1962
2071
|
};
|
|
1963
|
-
async function run10(
|
|
1964
|
-
let issueNumber =
|
|
2072
|
+
async function run10(input4, config) {
|
|
2073
|
+
let issueNumber = input4["issue_number"];
|
|
1965
2074
|
if (!issueNumber) {
|
|
1966
|
-
const
|
|
2075
|
+
const spinner3 = ora9("Loading tasks for review\u2026").start();
|
|
1967
2076
|
let tasks;
|
|
1968
2077
|
let me;
|
|
1969
2078
|
try {
|
|
1970
2079
|
me = await getAuthenticatedUser(config);
|
|
1971
2080
|
tasks = await listTasksForReview(config, me);
|
|
1972
|
-
|
|
2081
|
+
spinner3.stop();
|
|
1973
2082
|
} catch (err) {
|
|
1974
|
-
|
|
2083
|
+
spinner3.stop();
|
|
1975
2084
|
return `Error: ${err.message}`;
|
|
1976
2085
|
}
|
|
1977
2086
|
if (tasks.length === 0) return "No tasks pending review.";
|
|
@@ -1987,6 +2096,22 @@ async function run10(config, opts) {
|
|
|
1987
2096
|
return "Cancelled.";
|
|
1988
2097
|
}
|
|
1989
2098
|
}
|
|
2099
|
+
const spinner2 = ora9("Verifying permissions\u2026").start();
|
|
2100
|
+
let me2;
|
|
2101
|
+
let issue;
|
|
2102
|
+
try {
|
|
2103
|
+
[me2, issue] = await Promise.all([
|
|
2104
|
+
getAuthenticatedUser(config),
|
|
2105
|
+
getTask(config, issueNumber)
|
|
2106
|
+
]);
|
|
2107
|
+
spinner2.stop();
|
|
2108
|
+
} catch (err) {
|
|
2109
|
+
spinner2.stop();
|
|
2110
|
+
return `Error: ${err.message}`;
|
|
2111
|
+
}
|
|
2112
|
+
if (issue.author && issue.author !== me2) {
|
|
2113
|
+
return `Permission denied: only the task author (@${issue.author}) can accept task #${issueNumber}.`;
|
|
2114
|
+
}
|
|
1990
2115
|
const baseBranch = config.github.baseBranch ?? "main";
|
|
1991
2116
|
let confirmed;
|
|
1992
2117
|
try {
|
|
@@ -2013,8 +2138,15 @@ Issue closed.`;
|
|
|
2013
2138
|
return `Error: ${err.message}`;
|
|
2014
2139
|
}
|
|
2015
2140
|
}
|
|
2016
|
-
async function execute10(
|
|
2017
|
-
const issueNumber =
|
|
2141
|
+
async function execute10(input4, config) {
|
|
2142
|
+
const issueNumber = input4["issue_number"];
|
|
2143
|
+
const [me, issue] = await Promise.all([
|
|
2144
|
+
getAuthenticatedUser(config),
|
|
2145
|
+
getTask(config, issueNumber)
|
|
2146
|
+
]);
|
|
2147
|
+
if (issue.author && issue.author !== me) {
|
|
2148
|
+
return `Permission denied: only the task author (@${issue.author}) can accept task #${issueNumber}.`;
|
|
2149
|
+
}
|
|
2018
2150
|
const spinner = ora9(`Merging PR for #${issueNumber}\u2026`).start();
|
|
2019
2151
|
try {
|
|
2020
2152
|
const result = await acceptTask(config, issueNumber);
|
|
@@ -2030,14 +2162,138 @@ Issue closed.`;
|
|
|
2030
2162
|
}
|
|
2031
2163
|
var terminal10 = true;
|
|
2032
2164
|
|
|
2165
|
+
// src/tools/edit-task/index.ts
|
|
2166
|
+
var edit_task_exports = {};
|
|
2167
|
+
__export(edit_task_exports, {
|
|
2168
|
+
definition: () => definition11,
|
|
2169
|
+
execute: () => execute11,
|
|
2170
|
+
run: () => run11,
|
|
2171
|
+
terminal: () => terminal11
|
|
2172
|
+
});
|
|
2173
|
+
init_github();
|
|
2174
|
+
import { select as select9, input as promptInput4 } from "@inquirer/prompts";
|
|
2175
|
+
import ora10 from "ora";
|
|
2176
|
+
var definition11 = {
|
|
2177
|
+
type: "function",
|
|
2178
|
+
function: {
|
|
2179
|
+
name: "edit_task",
|
|
2180
|
+
description: "Edit the title and/or body of an existing task (GitHub Issue). Equivalent to /edit.",
|
|
2181
|
+
parameters: {
|
|
2182
|
+
type: "object",
|
|
2183
|
+
properties: {
|
|
2184
|
+
issue_number: { type: "number", description: "Issue number to edit." },
|
|
2185
|
+
title: { type: "string", description: "New title." },
|
|
2186
|
+
body: { type: "string", description: "New body/description." }
|
|
2187
|
+
},
|
|
2188
|
+
required: ["issue_number", "title", "body"]
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
};
|
|
2192
|
+
async function run11(input4, config) {
|
|
2193
|
+
let issueNumber = input4["issue_number"];
|
|
2194
|
+
if (!issueNumber) {
|
|
2195
|
+
let tasks;
|
|
2196
|
+
try {
|
|
2197
|
+
tasks = await listTasks(config);
|
|
2198
|
+
} catch (err) {
|
|
2199
|
+
return `Error loading tasks: ${err.message}`;
|
|
2200
|
+
}
|
|
2201
|
+
if (tasks.length === 0) return "No tasks found.";
|
|
2202
|
+
try {
|
|
2203
|
+
issueNumber = await select9({
|
|
2204
|
+
message: "Select task to edit:",
|
|
2205
|
+
choices: tasks.map((t) => ({ name: `#${t.number} [${getStatus(t)}] ${t.title}`, value: t.number }))
|
|
2206
|
+
});
|
|
2207
|
+
} catch {
|
|
2208
|
+
return "Cancelled.";
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
let issue;
|
|
2212
|
+
try {
|
|
2213
|
+
issue = await getTask(config, issueNumber);
|
|
2214
|
+
} catch (err) {
|
|
2215
|
+
return `Error loading task: ${err.message}`;
|
|
2216
|
+
}
|
|
2217
|
+
let title;
|
|
2218
|
+
let body;
|
|
2219
|
+
try {
|
|
2220
|
+
title = await promptInput4({
|
|
2221
|
+
message: "Title:",
|
|
2222
|
+
default: issue.title
|
|
2223
|
+
});
|
|
2224
|
+
body = await promptInput4({
|
|
2225
|
+
message: "Description:",
|
|
2226
|
+
default: issue.body ?? ""
|
|
2227
|
+
});
|
|
2228
|
+
} catch {
|
|
2229
|
+
return "Cancelled.";
|
|
2230
|
+
}
|
|
2231
|
+
if (title.trim() === issue.title && body.trim() === (issue.body ?? "")) {
|
|
2232
|
+
return "No changes made.";
|
|
2233
|
+
}
|
|
2234
|
+
const spinner = ora10(`Updating #${issueNumber}\u2026`).start();
|
|
2235
|
+
try {
|
|
2236
|
+
await editTask(config, issueNumber, title.trim() || issue.title, body.trim());
|
|
2237
|
+
spinner.stop();
|
|
2238
|
+
return `Task #${issueNumber} updated.`;
|
|
2239
|
+
} catch (err) {
|
|
2240
|
+
spinner.stop();
|
|
2241
|
+
return `Error: ${err.message}`;
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
async function execute11(input4, config) {
|
|
2245
|
+
const issueNumber = input4["issue_number"];
|
|
2246
|
+
const title = input4["title"];
|
|
2247
|
+
const body = input4["body"];
|
|
2248
|
+
const spinner = ora10(`Updating #${issueNumber}\u2026`).start();
|
|
2249
|
+
try {
|
|
2250
|
+
await editTask(config, issueNumber, title, body);
|
|
2251
|
+
spinner.stop();
|
|
2252
|
+
return `Task #${issueNumber} updated.`;
|
|
2253
|
+
} catch (err) {
|
|
2254
|
+
spinner.stop();
|
|
2255
|
+
return `Error: ${err.message}`;
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
var terminal11 = true;
|
|
2259
|
+
|
|
2260
|
+
// src/tools/list-tasks/index.ts
|
|
2261
|
+
var list_tasks_exports = {};
|
|
2262
|
+
__export(list_tasks_exports, {
|
|
2263
|
+
definition: () => definition12,
|
|
2264
|
+
execute: () => execute12
|
|
2265
|
+
});
|
|
2266
|
+
init_github();
|
|
2267
|
+
var definition12 = {
|
|
2268
|
+
type: "function",
|
|
2269
|
+
function: {
|
|
2270
|
+
name: "list_tasks",
|
|
2271
|
+
description: "List all open tasks (GitHub Issues) with their status and assignee. Use this to answer questions about available work, task progress, or who is working on what.",
|
|
2272
|
+
parameters: {
|
|
2273
|
+
type: "object",
|
|
2274
|
+
properties: {},
|
|
2275
|
+
required: []
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
};
|
|
2279
|
+
async function execute12(_input, config) {
|
|
2280
|
+
const tasks = await listTasks(config);
|
|
2281
|
+
if (tasks.length === 0) return "No open tasks.";
|
|
2282
|
+
return tasks.map((t) => {
|
|
2283
|
+
const status = t.labels.find((l) => l.startsWith("techunter:"))?.replace("techunter:", "") ?? "unknown";
|
|
2284
|
+
const assignee = t.assignee ? `@${t.assignee}` : "\u2014";
|
|
2285
|
+
return `#${t.number} [${status}] ${assignee} ${t.title}`;
|
|
2286
|
+
}).join("\n");
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2033
2289
|
// src/tools/get-task/index.ts
|
|
2034
2290
|
var get_task_exports = {};
|
|
2035
2291
|
__export(get_task_exports, {
|
|
2036
|
-
definition: () =>
|
|
2037
|
-
execute: () =>
|
|
2292
|
+
definition: () => definition13,
|
|
2293
|
+
execute: () => execute13
|
|
2038
2294
|
});
|
|
2039
2295
|
init_github();
|
|
2040
|
-
var
|
|
2296
|
+
var definition13 = {
|
|
2041
2297
|
type: "function",
|
|
2042
2298
|
function: {
|
|
2043
2299
|
name: "get_task",
|
|
@@ -2051,8 +2307,8 @@ var definition11 = {
|
|
|
2051
2307
|
}
|
|
2052
2308
|
}
|
|
2053
2309
|
};
|
|
2054
|
-
async function
|
|
2055
|
-
const issue = await getTask(config,
|
|
2310
|
+
async function execute13(input4, config) {
|
|
2311
|
+
const issue = await getTask(config, input4["issue_number"]);
|
|
2056
2312
|
const status = issue.labels.find((l) => l.startsWith("techunter:"))?.replace("techunter:", "") ?? "unknown";
|
|
2057
2313
|
const assignee = issue.assignee ? `@${issue.assignee}` : "\u2014";
|
|
2058
2314
|
const lines = [
|
|
@@ -2068,12 +2324,12 @@ ${issue.body}`);
|
|
|
2068
2324
|
// src/tools/get-comments/index.ts
|
|
2069
2325
|
var get_comments_exports = {};
|
|
2070
2326
|
__export(get_comments_exports, {
|
|
2071
|
-
definition: () =>
|
|
2072
|
-
execute: () =>
|
|
2327
|
+
definition: () => definition14,
|
|
2328
|
+
execute: () => execute14
|
|
2073
2329
|
});
|
|
2074
2330
|
init_github();
|
|
2075
|
-
import
|
|
2076
|
-
var
|
|
2331
|
+
import ora11 from "ora";
|
|
2332
|
+
var definition14 = {
|
|
2077
2333
|
type: "function",
|
|
2078
2334
|
function: {
|
|
2079
2335
|
name: "get_comments",
|
|
@@ -2088,10 +2344,10 @@ var definition12 = {
|
|
|
2088
2344
|
}
|
|
2089
2345
|
}
|
|
2090
2346
|
};
|
|
2091
|
-
async function
|
|
2092
|
-
const issueNumber =
|
|
2093
|
-
const limit =
|
|
2094
|
-
const spinner =
|
|
2347
|
+
async function execute14(input4, config) {
|
|
2348
|
+
const issueNumber = input4["issue_number"];
|
|
2349
|
+
const limit = input4["limit"] ?? 5;
|
|
2350
|
+
const spinner = ora11(`Loading comments for #${issueNumber}...`).start();
|
|
2095
2351
|
try {
|
|
2096
2352
|
const comments = await listComments(config, issueNumber, limit);
|
|
2097
2353
|
spinner.stop();
|
|
@@ -2110,11 +2366,11 @@ ${lines.join("\n\n")}`;
|
|
|
2110
2366
|
// src/tools/get-diff/index.ts
|
|
2111
2367
|
var get_diff_exports = {};
|
|
2112
2368
|
__export(get_diff_exports, {
|
|
2113
|
-
definition: () =>
|
|
2114
|
-
execute: () =>
|
|
2369
|
+
definition: () => definition15,
|
|
2370
|
+
execute: () => execute15
|
|
2115
2371
|
});
|
|
2116
|
-
import
|
|
2117
|
-
var
|
|
2372
|
+
import ora12 from "ora";
|
|
2373
|
+
var definition15 = {
|
|
2118
2374
|
type: "function",
|
|
2119
2375
|
function: {
|
|
2120
2376
|
name: "get_diff",
|
|
@@ -2122,8 +2378,8 @@ var definition13 = {
|
|
|
2122
2378
|
parameters: { type: "object", properties: {}, required: [] }
|
|
2123
2379
|
}
|
|
2124
2380
|
};
|
|
2125
|
-
async function
|
|
2126
|
-
const spinner =
|
|
2381
|
+
async function execute15(_input, _config) {
|
|
2382
|
+
const spinner = ora12("Reading git diff...").start();
|
|
2127
2383
|
try {
|
|
2128
2384
|
const diff = await getDiff(_config.github.baseBranch);
|
|
2129
2385
|
spinner.stop();
|
|
@@ -2137,14 +2393,14 @@ async function execute13(_input, _config) {
|
|
|
2137
2393
|
// src/tools/run-command/index.ts
|
|
2138
2394
|
var run_command_exports = {};
|
|
2139
2395
|
__export(run_command_exports, {
|
|
2140
|
-
definition: () =>
|
|
2141
|
-
execute: () =>
|
|
2396
|
+
definition: () => definition16,
|
|
2397
|
+
execute: () => execute16
|
|
2142
2398
|
});
|
|
2143
2399
|
import { exec } from "child_process";
|
|
2144
2400
|
import { promisify } from "util";
|
|
2145
|
-
import
|
|
2401
|
+
import ora13 from "ora";
|
|
2146
2402
|
var execAsync = promisify(exec);
|
|
2147
|
-
var
|
|
2403
|
+
var definition16 = {
|
|
2148
2404
|
type: "function",
|
|
2149
2405
|
function: {
|
|
2150
2406
|
name: "run_command",
|
|
@@ -2158,10 +2414,10 @@ var definition14 = {
|
|
|
2158
2414
|
}
|
|
2159
2415
|
}
|
|
2160
2416
|
};
|
|
2161
|
-
async function
|
|
2162
|
-
const command =
|
|
2417
|
+
async function execute16(input4, _config) {
|
|
2418
|
+
const command = input4["command"];
|
|
2163
2419
|
const cwd = process.cwd();
|
|
2164
|
-
const spinner =
|
|
2420
|
+
const spinner = ora13(`$ ${command}`).start();
|
|
2165
2421
|
try {
|
|
2166
2422
|
const { stdout, stderr } = await execAsync(command, { cwd, timeout: 6e4, maxBuffer: 1024 * 1024 });
|
|
2167
2423
|
spinner.stop();
|
|
@@ -2180,10 +2436,10 @@ ${out || e.message}`;
|
|
|
2180
2436
|
// src/tools/scan-project/index.ts
|
|
2181
2437
|
var scan_project_exports = {};
|
|
2182
2438
|
__export(scan_project_exports, {
|
|
2183
|
-
definition: () =>
|
|
2184
|
-
execute: () =>
|
|
2439
|
+
definition: () => definition17,
|
|
2440
|
+
execute: () => execute17
|
|
2185
2441
|
});
|
|
2186
|
-
import
|
|
2442
|
+
import ora14 from "ora";
|
|
2187
2443
|
|
|
2188
2444
|
// src/lib/project.ts
|
|
2189
2445
|
import { readFile as readFile2 } from "fs/promises";
|
|
@@ -2334,7 +2590,7 @@ async function buildProjectContext(cwd, issueTitle, issueBody) {
|
|
|
2334
2590
|
}
|
|
2335
2591
|
|
|
2336
2592
|
// src/tools/scan-project/index.ts
|
|
2337
|
-
var
|
|
2593
|
+
var definition17 = {
|
|
2338
2594
|
type: "function",
|
|
2339
2595
|
function: {
|
|
2340
2596
|
name: "scan_project",
|
|
@@ -2351,9 +2607,9 @@ var definition15 = {
|
|
|
2351
2607
|
}
|
|
2352
2608
|
}
|
|
2353
2609
|
};
|
|
2354
|
-
async function
|
|
2355
|
-
const focus =
|
|
2356
|
-
const spinner =
|
|
2610
|
+
async function execute17(input4, _config) {
|
|
2611
|
+
const focus = input4["focus"] ?? "";
|
|
2612
|
+
const spinner = ora14("Scanning project...").start();
|
|
2357
2613
|
try {
|
|
2358
2614
|
const cwd = process.cwd();
|
|
2359
2615
|
const context = await buildProjectContext(cwd, focus, "");
|
|
@@ -2382,12 +2638,12 @@ ${content}
|
|
|
2382
2638
|
// src/tools/read-file/index.ts
|
|
2383
2639
|
var read_file_exports = {};
|
|
2384
2640
|
__export(read_file_exports, {
|
|
2385
|
-
definition: () =>
|
|
2386
|
-
execute: () =>
|
|
2641
|
+
definition: () => definition18,
|
|
2642
|
+
execute: () => execute18
|
|
2387
2643
|
});
|
|
2388
2644
|
import { readFile as readFile3 } from "fs/promises";
|
|
2389
2645
|
import path3 from "path";
|
|
2390
|
-
var
|
|
2646
|
+
var definition18 = {
|
|
2391
2647
|
type: "function",
|
|
2392
2648
|
function: {
|
|
2393
2649
|
name: "read_file",
|
|
@@ -2401,8 +2657,8 @@ var definition16 = {
|
|
|
2401
2657
|
}
|
|
2402
2658
|
}
|
|
2403
2659
|
};
|
|
2404
|
-
async function
|
|
2405
|
-
const filePath =
|
|
2660
|
+
async function execute18(input4, _config) {
|
|
2661
|
+
const filePath = input4["path"];
|
|
2406
2662
|
try {
|
|
2407
2663
|
const fullPath = path3.join(process.cwd(), filePath);
|
|
2408
2664
|
const content = await readFile3(fullPath, "utf-8");
|
|
@@ -2415,12 +2671,12 @@ async function execute16(input3, _config) {
|
|
|
2415
2671
|
// src/tools/ask-user/index.ts
|
|
2416
2672
|
var ask_user_exports = {};
|
|
2417
2673
|
__export(ask_user_exports, {
|
|
2418
|
-
definition: () =>
|
|
2419
|
-
execute: () =>
|
|
2674
|
+
definition: () => definition19,
|
|
2675
|
+
execute: () => execute19
|
|
2420
2676
|
});
|
|
2421
2677
|
import chalk12 from "chalk";
|
|
2422
|
-
import { select as
|
|
2423
|
-
var
|
|
2678
|
+
import { select as select10, input as promptInput5 } from "@inquirer/prompts";
|
|
2679
|
+
var definition19 = {
|
|
2424
2680
|
type: "function",
|
|
2425
2681
|
function: {
|
|
2426
2682
|
name: "ask_user",
|
|
@@ -2439,9 +2695,9 @@ var definition17 = {
|
|
|
2439
2695
|
}
|
|
2440
2696
|
}
|
|
2441
2697
|
};
|
|
2442
|
-
async function
|
|
2443
|
-
const question =
|
|
2444
|
-
const options =
|
|
2698
|
+
async function execute19(input4, _config) {
|
|
2699
|
+
const question = input4["question"];
|
|
2700
|
+
const options = input4["options"];
|
|
2445
2701
|
const OTHER = "__other__";
|
|
2446
2702
|
console.log("");
|
|
2447
2703
|
console.log(chalk12.dim(" \u250C\u2500 Agent question " + "\u2500".repeat(51)));
|
|
@@ -2452,14 +2708,14 @@ async function execute17(input3, _config) {
|
|
|
2452
2708
|
console.log(chalk12.dim(" \u2514" + "\u2500".repeat(67)));
|
|
2453
2709
|
let answer;
|
|
2454
2710
|
try {
|
|
2455
|
-
const chosen = await
|
|
2711
|
+
const chosen = await select10({
|
|
2456
2712
|
message: " ",
|
|
2457
2713
|
choices: [
|
|
2458
2714
|
...options.map((o) => ({ name: o, value: o })),
|
|
2459
2715
|
{ name: chalk12.dim("Other (describe below)"), value: OTHER }
|
|
2460
2716
|
]
|
|
2461
2717
|
});
|
|
2462
|
-
answer = chosen === OTHER ? await
|
|
2718
|
+
answer = chosen === OTHER ? await promptInput5({ message: "Your answer:" }) : chosen;
|
|
2463
2719
|
} catch {
|
|
2464
2720
|
answer = "User skipped this question \u2014 use your best judgement.";
|
|
2465
2721
|
}
|
|
@@ -2480,7 +2736,9 @@ var toolModules = [
|
|
|
2480
2736
|
open_code_exports,
|
|
2481
2737
|
reject_exports,
|
|
2482
2738
|
accept_exports,
|
|
2739
|
+
edit_task_exports,
|
|
2483
2740
|
// Low-level tools
|
|
2741
|
+
list_tasks_exports,
|
|
2484
2742
|
get_task_exports,
|
|
2485
2743
|
get_comments_exports,
|
|
2486
2744
|
get_diff_exports,
|
|
@@ -2492,11 +2750,12 @@ var toolModules = [
|
|
|
2492
2750
|
|
|
2493
2751
|
// src/lib/agent.ts
|
|
2494
2752
|
var tools = toolModules.map((m) => m.definition);
|
|
2495
|
-
async function executeTool(name,
|
|
2753
|
+
async function executeTool(name, input4, config) {
|
|
2496
2754
|
const mod = toolModules.find((m) => m.definition.function.name === name);
|
|
2497
2755
|
if (!mod) return `Unknown tool: ${name}`;
|
|
2498
2756
|
try {
|
|
2499
|
-
|
|
2757
|
+
const fn = mod.run ?? mod.execute;
|
|
2758
|
+
return await fn(input4, config);
|
|
2500
2759
|
} catch (err) {
|
|
2501
2760
|
return `Error: ${err.message}`;
|
|
2502
2761
|
}
|
|
@@ -2549,9 +2808,7 @@ async function runAgentLoop(config, messages) {
|
|
|
2549
2808
|
if (++iterations > MAX_ITERATIONS) {
|
|
2550
2809
|
throw new Error(`Agent exceeded ${MAX_ITERATIONS} iterations without finishing.`);
|
|
2551
2810
|
}
|
|
2552
|
-
const
|
|
2553
|
-
const spinner = isWindows ? null : ora14({ text: chalk13.dim("Thinking\u2026"), color: "cyan" }).start();
|
|
2554
|
-
if (isWindows) process.stdout.write(chalk13.dim(" Thinking\u2026"));
|
|
2811
|
+
const spinner = ora15({ text: chalk13.dim("Thinking\u2026"), color: "cyan" }).start();
|
|
2555
2812
|
let response;
|
|
2556
2813
|
try {
|
|
2557
2814
|
response = await client.chat.completions.create({
|
|
@@ -2560,12 +2817,10 @@ async function runAgentLoop(config, messages) {
|
|
|
2560
2817
|
messages: [systemMessage, ...messages]
|
|
2561
2818
|
});
|
|
2562
2819
|
} catch (err) {
|
|
2563
|
-
|
|
2564
|
-
else process.stdout.write("\r" + " ".repeat(14) + "\r");
|
|
2820
|
+
spinner.stop();
|
|
2565
2821
|
throw err;
|
|
2566
2822
|
}
|
|
2567
|
-
|
|
2568
|
-
else process.stdout.write("\r" + " ".repeat(14) + "\r");
|
|
2823
|
+
spinner.stop();
|
|
2569
2824
|
const choice = response.choices[0];
|
|
2570
2825
|
const assistantMessage = {
|
|
2571
2826
|
role: "assistant",
|
|
@@ -2598,7 +2853,7 @@ async function runAgentLoop(config, messages) {
|
|
|
2598
2853
|
return executeTool(tc.function.name, parsed, config);
|
|
2599
2854
|
})
|
|
2600
2855
|
);
|
|
2601
|
-
let
|
|
2856
|
+
let terminal12 = false;
|
|
2602
2857
|
for (let i = 0; i < toolCalls.length; i++) {
|
|
2603
2858
|
printToolResult(results[i]);
|
|
2604
2859
|
messages.push({
|
|
@@ -2607,10 +2862,10 @@ async function runAgentLoop(config, messages) {
|
|
|
2607
2862
|
content: results[i]
|
|
2608
2863
|
});
|
|
2609
2864
|
if (toolModules.find((m) => m.definition.function.name === toolCalls[i].function.name)?.terminal) {
|
|
2610
|
-
|
|
2865
|
+
terminal12 = true;
|
|
2611
2866
|
}
|
|
2612
2867
|
}
|
|
2613
|
-
if (
|
|
2868
|
+
if (terminal12) return results[results.length - 1];
|
|
2614
2869
|
} else {
|
|
2615
2870
|
return choice.message.content ?? "";
|
|
2616
2871
|
}
|
|
@@ -2633,6 +2888,8 @@ var SLASH_NAMES = [
|
|
|
2633
2888
|
"/s",
|
|
2634
2889
|
"/close",
|
|
2635
2890
|
"/d",
|
|
2891
|
+
"/edit",
|
|
2892
|
+
"/e",
|
|
2636
2893
|
"/review",
|
|
2637
2894
|
"/rv",
|
|
2638
2895
|
"/accept",
|
|
@@ -2642,7 +2899,8 @@ var SLASH_NAMES = [
|
|
|
2642
2899
|
"/code",
|
|
2643
2900
|
"/c",
|
|
2644
2901
|
"/config",
|
|
2645
|
-
"/cfg"
|
|
2902
|
+
"/cfg",
|
|
2903
|
+
"/init"
|
|
2646
2904
|
];
|
|
2647
2905
|
function completer(line) {
|
|
2648
2906
|
if (line.startsWith("/")) {
|
|
@@ -2663,10 +2921,12 @@ var COMMANDS = [
|
|
|
2663
2921
|
{ cmd: "/pick", alias: "/p", desc: "Browse tasks and view details" },
|
|
2664
2922
|
{ cmd: "/new", alias: "/n", desc: "Create a new task interactively" },
|
|
2665
2923
|
{ cmd: "/close", alias: "/d", desc: "Close (delete) a task" },
|
|
2924
|
+
{ cmd: "/edit", alias: "/e", desc: "Edit the title or description of a task" },
|
|
2666
2925
|
{ cmd: "/submit", alias: "/s", desc: "Commit, create PR, and mark in-review" },
|
|
2667
2926
|
{ cmd: "/review", alias: "/rv", desc: "List tasks waiting for your approval" },
|
|
2668
2927
|
{ cmd: "/accept", alias: "/ac", desc: "Accept a reviewed task: merge PR and close issue" },
|
|
2669
2928
|
{ cmd: "/config", alias: "/cfg", desc: "Change settings (branch, repo, API keys)" },
|
|
2929
|
+
{ cmd: "/init", desc: "Re-run setup wizard for this repo" },
|
|
2670
2930
|
{ cmd: "/status", alias: "/me", desc: "Show tasks assigned to you" },
|
|
2671
2931
|
{ cmd: "/code", alias: "/c", desc: "Open Claude Code for the current task branch" }
|
|
2672
2932
|
];
|
|
@@ -2695,6 +2955,30 @@ function printBanner(config) {
|
|
|
2695
2955
|
);
|
|
2696
2956
|
console.log("");
|
|
2697
2957
|
}
|
|
2958
|
+
async function initNewRepo(config, owner, repo) {
|
|
2959
|
+
console.log("");
|
|
2960
|
+
console.log(chalk14.bold.cyan(` New repo detected: ${owner}/${repo}`));
|
|
2961
|
+
console.log(chalk14.dim(" Setting up Techunter for this repository...\n"));
|
|
2962
|
+
const baseBranch = await input3({
|
|
2963
|
+
message: "Main branch to merge PRs into:",
|
|
2964
|
+
default: "main"
|
|
2965
|
+
});
|
|
2966
|
+
const newConfig = {
|
|
2967
|
+
...config,
|
|
2968
|
+
github: { owner, repo, baseBranch: baseBranch.trim() || "main" }
|
|
2969
|
+
};
|
|
2970
|
+
setConfig({ github: newConfig.github });
|
|
2971
|
+
const ora16 = (await import("ora")).default;
|
|
2972
|
+
const spinner = ora16("Creating Techunter labels...").start();
|
|
2973
|
+
try {
|
|
2974
|
+
await ensureLabels(newConfig);
|
|
2975
|
+
spinner.succeed("Labels ready");
|
|
2976
|
+
} catch (err) {
|
|
2977
|
+
spinner.fail(`Could not create labels: ${err.message}`);
|
|
2978
|
+
}
|
|
2979
|
+
console.log("");
|
|
2980
|
+
return newConfig;
|
|
2981
|
+
}
|
|
2698
2982
|
async function main() {
|
|
2699
2983
|
const args = process.argv.slice(2);
|
|
2700
2984
|
if (args[0] === "config") {
|
|
@@ -2726,11 +3010,10 @@ Setup failed: ${err.message}`));
|
|
|
2726
3010
|
const detected = parseOwnerRepo(remoteUrl);
|
|
2727
3011
|
if (detected) {
|
|
2728
3012
|
const isNewRepo = detected.owner !== config.github.owner || detected.repo !== config.github.repo;
|
|
2729
|
-
config = { ...config, github: { ...config.github, owner: detected.owner, repo: detected.repo, baseBranch: void 0 } };
|
|
2730
3013
|
if (isNewRepo) {
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
}
|
|
3014
|
+
config = await initNewRepo(config, detected.owner, detected.repo);
|
|
3015
|
+
} else {
|
|
3016
|
+
config = { ...config, github: { ...config.github, owner: detected.owner, repo: detected.repo } };
|
|
2734
3017
|
}
|
|
2735
3018
|
}
|
|
2736
3019
|
} else if (!config.github.owner) {
|
|
@@ -2769,13 +3052,13 @@ Setup failed: ${err.message}`));
|
|
|
2769
3052
|
break;
|
|
2770
3053
|
case "/refresh":
|
|
2771
3054
|
case "/r":
|
|
2772
|
-
await run7(config);
|
|
3055
|
+
await run7({}, config);
|
|
2773
3056
|
break;
|
|
2774
3057
|
case "/pick":
|
|
2775
3058
|
case "/p": {
|
|
2776
3059
|
const arg = userInput.slice(cmd.length).trim().replace(/^#/, "");
|
|
2777
3060
|
const preselected = arg ? parseInt(arg, 10) : void 0;
|
|
2778
|
-
const result = await run3(
|
|
3061
|
+
const result = await run3({ issue_number: Number.isNaN(preselected) ? void 0 : preselected }, config);
|
|
2779
3062
|
if (result && result !== "Cancelled.") {
|
|
2780
3063
|
console.log(chalk14.green(`
|
|
2781
3064
|
${result}
|
|
@@ -2786,7 +3069,7 @@ Setup failed: ${err.message}`));
|
|
|
2786
3069
|
}
|
|
2787
3070
|
case "/new":
|
|
2788
3071
|
case "/n": {
|
|
2789
|
-
const result = await run4(config);
|
|
3072
|
+
const result = await run4({}, config);
|
|
2790
3073
|
console.log(chalk14.green(`
|
|
2791
3074
|
${result}
|
|
2792
3075
|
`));
|
|
@@ -2795,14 +3078,25 @@ Setup failed: ${err.message}`));
|
|
|
2795
3078
|
}
|
|
2796
3079
|
case "/submit":
|
|
2797
3080
|
case "/s": {
|
|
2798
|
-
const result = await run(config);
|
|
3081
|
+
const result = await run({}, config);
|
|
2799
3082
|
console.log("\n" + renderMarkdown(result));
|
|
2800
3083
|
await printTaskList(config);
|
|
2801
3084
|
break;
|
|
2802
3085
|
}
|
|
3086
|
+
case "/edit":
|
|
3087
|
+
case "/e": {
|
|
3088
|
+
const arg = userInput.slice(cmd.length).trim().replace(/^#/, "");
|
|
3089
|
+
const preselected = arg ? parseInt(arg, 10) : void 0;
|
|
3090
|
+
const result = await run11({ issue_number: Number.isNaN(preselected) ? void 0 : preselected }, config);
|
|
3091
|
+
console.log(chalk14.green(`
|
|
3092
|
+
${result}
|
|
3093
|
+
`));
|
|
3094
|
+
await printTaskList(config);
|
|
3095
|
+
break;
|
|
3096
|
+
}
|
|
2803
3097
|
case "/close":
|
|
2804
3098
|
case "/d": {
|
|
2805
|
-
const result = await run2(config);
|
|
3099
|
+
const result = await run2({}, config);
|
|
2806
3100
|
console.log(chalk14.green(`
|
|
2807
3101
|
${result}
|
|
2808
3102
|
`));
|
|
@@ -2811,13 +3105,13 @@ Setup failed: ${err.message}`));
|
|
|
2811
3105
|
}
|
|
2812
3106
|
case "/review":
|
|
2813
3107
|
case "/rv": {
|
|
2814
|
-
const result = await run6(config);
|
|
3108
|
+
const result = await run6({}, config);
|
|
2815
3109
|
console.log("\n" + renderMarkdown(result));
|
|
2816
3110
|
break;
|
|
2817
3111
|
}
|
|
2818
3112
|
case "/status":
|
|
2819
3113
|
case "/me": {
|
|
2820
|
-
const result = await run5(config);
|
|
3114
|
+
const result = await run5({}, config);
|
|
2821
3115
|
console.log("\n" + renderMarkdown(result));
|
|
2822
3116
|
break;
|
|
2823
3117
|
}
|
|
@@ -2825,7 +3119,7 @@ Setup failed: ${err.message}`));
|
|
|
2825
3119
|
case "/ac": {
|
|
2826
3120
|
const arg = userInput.slice(cmd.length).trim().replace(/^#/, "");
|
|
2827
3121
|
const preselected = arg ? parseInt(arg, 10) : void 0;
|
|
2828
|
-
const result = await run10(
|
|
3122
|
+
const result = await run10({ issue_number: Number.isNaN(preselected) ? void 0 : preselected }, config);
|
|
2829
3123
|
console.log(chalk14.green(`
|
|
2830
3124
|
${result}
|
|
2831
3125
|
`));
|
|
@@ -2836,9 +3130,20 @@ Setup failed: ${err.message}`));
|
|
|
2836
3130
|
case "/cfg":
|
|
2837
3131
|
await configCommand();
|
|
2838
3132
|
break;
|
|
3133
|
+
case "/init":
|
|
3134
|
+
try {
|
|
3135
|
+
await initCommand();
|
|
3136
|
+
config = getConfig();
|
|
3137
|
+
await printTaskList(config);
|
|
3138
|
+
} catch (err) {
|
|
3139
|
+
console.error(chalk14.red(`
|
|
3140
|
+
Init failed: ${err.message}
|
|
3141
|
+
`));
|
|
3142
|
+
}
|
|
3143
|
+
break;
|
|
2839
3144
|
case "/code":
|
|
2840
3145
|
case "/c":
|
|
2841
|
-
await run8(config);
|
|
3146
|
+
await run8({}, config);
|
|
2842
3147
|
break;
|
|
2843
3148
|
default:
|
|
2844
3149
|
console.log(chalk14.yellow(` Unknown command: ${cmd} (try /help)`));
|