claude-task-worker 0.19.0 → 0.21.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/dist/index.js +172 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -572,11 +572,14 @@ async function listIssuesByNumbers(assignee, labels, excludeLabels, numbers) {
|
|
|
572
572
|
return results;
|
|
573
573
|
}
|
|
574
574
|
async function findOpenPrNumberByHeadRef(headRefName) {
|
|
575
|
+
return findPrNumberByHeadRef(headRefName, "open");
|
|
576
|
+
}
|
|
577
|
+
async function findPrNumberByHeadRef(headRefName, state = "open") {
|
|
575
578
|
const output = await execGh([
|
|
576
579
|
"pr",
|
|
577
580
|
"list",
|
|
578
581
|
"--state",
|
|
579
|
-
|
|
582
|
+
state,
|
|
580
583
|
"--head",
|
|
581
584
|
headRefName,
|
|
582
585
|
"--json",
|
|
@@ -587,6 +590,37 @@ async function findOpenPrNumberByHeadRef(headRefName) {
|
|
|
587
590
|
const prs = JSON.parse(output);
|
|
588
591
|
return prs.length > 0 ? prs[0].number : null;
|
|
589
592
|
}
|
|
593
|
+
async function getIssueState(issueNumber) {
|
|
594
|
+
const output = await execGh(["issue", "view", String(issueNumber), "--json", "state"]);
|
|
595
|
+
const parsed = JSON.parse(output);
|
|
596
|
+
return parsed.state;
|
|
597
|
+
}
|
|
598
|
+
async function findPrNumberClosingIssue(issueNumber) {
|
|
599
|
+
const { owner, name } = await getRepoInfo();
|
|
600
|
+
const query = `query($owner: String!, $name: String!, $number: Int!) {
|
|
601
|
+
repository(owner: $owner, name: $name) {
|
|
602
|
+
issue(number: $number) {
|
|
603
|
+
closedByPullRequestsReferences(first: 10, includeClosedPrs: true) { nodes { number state } }
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}`;
|
|
607
|
+
const output = await execGh([
|
|
608
|
+
"api",
|
|
609
|
+
"graphql",
|
|
610
|
+
"-f",
|
|
611
|
+
`query=${query}`,
|
|
612
|
+
"-F",
|
|
613
|
+
`owner=${owner}`,
|
|
614
|
+
"-F",
|
|
615
|
+
`name=${name}`,
|
|
616
|
+
"-F",
|
|
617
|
+
`number=${issueNumber}`
|
|
618
|
+
]);
|
|
619
|
+
const parsed = JSON.parse(output);
|
|
620
|
+
const nodes = parsed?.data?.repository?.issue?.closedByPullRequestsReferences?.nodes ?? [];
|
|
621
|
+
const validPr = nodes.find((node) => node.state === "MERGED" || node.state === "OPEN");
|
|
622
|
+
return validPr ? validPr.number : null;
|
|
623
|
+
}
|
|
590
624
|
async function getIssueSubIssuesSummary(issueNumber) {
|
|
591
625
|
const output = await execGh(["issue", "view", String(issueNumber), "--json", "subIssuesSummary"]);
|
|
592
626
|
const parsed = JSON.parse(output);
|
|
@@ -694,6 +728,9 @@ async function removeLabel(type, number, label) {
|
|
|
694
728
|
async function commentOnPR(prNumber, body) {
|
|
695
729
|
await execGh(["pr", "comment", String(prNumber), "--body", body]);
|
|
696
730
|
}
|
|
731
|
+
async function commentOnIssue(issueNumber, body) {
|
|
732
|
+
await execGh(["issue", "comment", String(issueNumber), "--body", body]);
|
|
733
|
+
}
|
|
697
734
|
async function createLabel(name, color, force) {
|
|
698
735
|
try {
|
|
699
736
|
const args = ["label", "create", name];
|
|
@@ -712,6 +749,10 @@ var DISALLOWED_TOOLS = [
|
|
|
712
749
|
// 呼ぶと処理未完のままプロセスが終了する。
|
|
713
750
|
"Monitor",
|
|
714
751
|
"ScheduleWakeup",
|
|
752
|
+
// SendMessage は過去に起動したサブエージェントをバックグラウンドでしか再開できず、
|
|
753
|
+
// 「完了通知を待ちます」でターンを終える誘因になる。未完のサブエージェントへの追加指示は
|
|
754
|
+
// フォアグラウンドの新規 Agent 起動で代替させる。
|
|
755
|
+
"SendMessage",
|
|
715
756
|
// 対話 / 承認: 自律実行セッションには回答・承認するユーザーが存在しない。
|
|
716
757
|
"AskUserQuestion",
|
|
717
758
|
"EnterPlanMode",
|
|
@@ -727,6 +768,15 @@ var DISALLOWED_TOOLS = [
|
|
|
727
768
|
"EnterWorktree"
|
|
728
769
|
];
|
|
729
770
|
var DISALLOWED_TOOLS_ARG = DISALLOWED_TOOLS.join(",");
|
|
771
|
+
var SUBAGENT_SYSTEM_PROMPT = `\u3042\u306A\u305F\u306F claude-task-worker \u306E\u30EF\u30FC\u30AB\u30FC\u304C \`claude -p\`\uFF08\u975E\u5BFE\u8A71 print \u30E2\u30FC\u30C9\uFF09\u3067\u81EA\u52D5\u8D77\u52D5\u3057\u305F\u30BB\u30C3\u30B7\u30E7\u30F3\u5185\u306E\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u3067\u3059\u3002print \u30E2\u30FC\u30C9\u306B\u306F\u518D\u8D77\u52D5\u30EB\u30FC\u30D7\u304C\u7121\u304F\u3001\u89AA\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u304C\u30BF\u30FC\u30F3\u3092\u7D42\u3048\u305F\u6642\u70B9\u3067\u30D7\u30ED\u30BB\u30B9\u304C\u6B63\u5E38\u7D42\u4E86\u3057\u307E\u3059\u3002\u3042\u306A\u305F\u304C\u51E6\u7406\u3092\u30D0\u30C3\u30AF\u30B0\u30E9\u30A6\u30F3\u30C9\u5316\u3057\u3066\u672A\u5B8C\u306E\u307E\u307E\u5236\u5FA1\u3092\u8FD4\u3059\u3068\u3001\u5916\u5074\u306E\u30EF\u30FC\u30AB\u30FC\u304C\u300C\u6B63\u5E38\u5B8C\u4E86\u300D\u3068\u8AA4\u8A8D\u3057\u3066 GitHub Issue/PR \u306E\u30E9\u30D9\u30EB\u72B6\u614B\u304C\u58CA\u308C\u307E\u3059\u3002\u4EE5\u4E0B\u306E\u30EB\u30FC\u30EB\u3092\u5FC5\u305A\u9075\u5B88\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
772
|
+
|
|
773
|
+
- \`Bash\` \u3092 \`run_in_background: true\` \u3067\u547C\u3070\u306A\u3044\u3002\u30B3\u30DE\u30F3\u30C9\u672B\u5C3E\u306B \`&\` \u3092\u4ED8\u3051\u305A\u3001\`nohup\` / \`disown\` / \`setsid\` \u3067\u30D7\u30ED\u30BB\u30B9\u3092\u30C7\u30BF\u30C3\u30C1\u3057\u306A\u3044
|
|
774
|
+
- \`Agent\` \u30C4\u30FC\u30EB\u306F\u65E2\u5B9A\u304C\u30D0\u30C3\u30AF\u30B0\u30E9\u30A6\u30F3\u30C9\u5B9F\u884C\u306E\u305F\u3081\u3001\u547C\u3073\u51FA\u3057\u3054\u3068\u306B\u5FC5\u305A \`run_in_background: false\` \u3092\u660E\u793A\u3057\u3001\u30D5\u30A9\u30A2\u30B0\u30E9\u30A6\u30F3\u30C9\u3067\u5B8C\u4E86\u3092\u5F85\u3063\u3066\u304B\u3089\u6B21\u3078\u9032\u3080
|
|
775
|
+
- \`Skill\` \u30C4\u30FC\u30EB\u306B \`run_in_background: true\` \u3092\u6307\u5B9A\u3057\u306A\u3044
|
|
776
|
+
- \`Monitor\` / \`ScheduleWakeup\` / \`SendMessage\` \u306A\u3069\u3067\u51E6\u7406\u3092\u5F8C\u56DE\u3057\u306B\u3057\u306A\u3044\u3002\u300C\u5B8C\u4E86\u901A\u77E5\u3092\u5F85\u3061\u307E\u3059\u300D\u306E\u3088\u3046\u306A\u901A\u77E5\u5F85\u3061\u72B6\u614B\u3067\u30BF\u30FC\u30F3\u3092\u7D42\u3048\u306A\u3044
|
|
777
|
+
- E2E \u30C6\u30B9\u30C8\u306E\u3088\u3046\u306B\u6642\u9593\u306E\u304B\u304B\u308B\u51E6\u7406\u3082\u3001\u540C\u671F\u5B9F\u884C\u3067\u5B8C\u4E86\u3092\u5F85\u3064\u306E\u304C\u6B63\u3057\u3044\u6319\u52D5\u3067\u3042\u308A\u3001\u30D0\u30C3\u30AF\u30B0\u30E9\u30A6\u30F3\u30C9\u5316\u3057\u3066\u5F85\u305F\u305A\u306B\u9032\u3093\u3067\u306F\u306A\u3089\u306A\u3044
|
|
778
|
+
- \u30D0\u30C3\u30AF\u30B0\u30E9\u30A6\u30F3\u30C9\u30BF\u30B9\u30AF\u304C\u6B8B\u3063\u305F\u72B6\u614B\u3067\u5B8C\u4E86\u5831\u544A\u3057\u3066\u30BF\u30FC\u30F3\u3092\u7D42\u3048\u306A\u3044\u3002\u672A\u5B8C\u306E\u51E6\u7406\u306F\u30D5\u30A9\u30A2\u30B0\u30E9\u30A6\u30F3\u30C9\u3067\u5B8C\u4E86\u307E\u3067\u5B9F\u884C\u3057\u5207\u3063\u3066\u304B\u3089\u5831\u544A\u3059\u308B
|
|
779
|
+
- \u30E6\u30FC\u30B6\u30FC\u3078\u306E\u78BA\u8A8D\u30FB\u8CEA\u554F\u306F\u884C\u308F\u306A\u3044\uFF08\u56DE\u7B54\u3059\u308B\u30E6\u30FC\u30B6\u30FC\u306F\u5B58\u5728\u3057\u306A\u3044\uFF09\u3002\u66D6\u6627\u306A\u5834\u5408\u306F\u7834\u58CA\u7684\u3067\u306A\u3044\u5074\u3092\u9078\u3073\u3001\u305D\u306E\u5224\u65AD\u3068\u6839\u62E0\u3092\u6700\u7D42\u5831\u544A\u306B\u660E\u8A18\u3059\u308B`;
|
|
730
780
|
|
|
731
781
|
// src/config.ts
|
|
732
782
|
import { readFileSync } from "node:fs";
|
|
@@ -972,8 +1022,32 @@ async function assertRemoteTrackingExists(epicBranch) {
|
|
|
972
1022
|
// src/process-manager.ts
|
|
973
1023
|
import { spawn } from "node:child_process";
|
|
974
1024
|
init_table();
|
|
975
|
-
|
|
1025
|
+
|
|
1026
|
+
// src/task-result.ts
|
|
976
1027
|
var TASK_TIMEOUT_MS = 90 * 60 * 1e3;
|
|
1028
|
+
var STDERR_TAIL_LIMIT = 8 * 1024;
|
|
1029
|
+
function buildTaskResult(code, timedOut, stdout, stderrTail) {
|
|
1030
|
+
const emptyOutput = stdout.trim() === "";
|
|
1031
|
+
const completed = !timedOut && code === 0 && !emptyOutput;
|
|
1032
|
+
let output = stdout;
|
|
1033
|
+
if (timedOut) {
|
|
1034
|
+
output += `
|
|
1035
|
+
[worker] task timed out after ${TASK_TIMEOUT_MS / 1e3}s`;
|
|
1036
|
+
} else if (code === 0 && emptyOutput) {
|
|
1037
|
+
output += "[worker] claude exited with code 0 but produced no output (session aborted before the model ran; e.g. a skill preamble command failed)";
|
|
1038
|
+
} else if (!completed) {
|
|
1039
|
+
output += `
|
|
1040
|
+
[worker] claude exited with code ${code}`;
|
|
1041
|
+
}
|
|
1042
|
+
if (!completed && stderrTail.trim() !== "") {
|
|
1043
|
+
output += `
|
|
1044
|
+
[stderr] ${stderrTail.trim()}`;
|
|
1045
|
+
}
|
|
1046
|
+
return { status: completed ? "completed" : "failed", output };
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// src/process-manager.ts
|
|
1050
|
+
var childProcesses = /* @__PURE__ */ new Map();
|
|
977
1051
|
var tasks = /* @__PURE__ */ new Map();
|
|
978
1052
|
var shuttingDown = false;
|
|
979
1053
|
function setShuttingDown() {
|
|
@@ -1105,11 +1179,20 @@ function run(command, args, id, title, workerName, path, onComplete, cwd) {
|
|
|
1105
1179
|
...cwd ? { cwd } : {}
|
|
1106
1180
|
});
|
|
1107
1181
|
childProcesses.set(id, child);
|
|
1108
|
-
child.stderr?.resume();
|
|
1109
1182
|
const outputChunks = [];
|
|
1110
1183
|
child.stdout?.on("data", (chunk) => {
|
|
1111
1184
|
outputChunks.push(chunk);
|
|
1112
1185
|
});
|
|
1186
|
+
const stderrChunks = [];
|
|
1187
|
+
let stderrLen = 0;
|
|
1188
|
+
child.stderr?.on("data", (chunk) => {
|
|
1189
|
+
stderrChunks.push(chunk);
|
|
1190
|
+
stderrLen += chunk.length;
|
|
1191
|
+
while (stderrChunks.length > 1 && stderrLen - stderrChunks[0].length >= STDERR_TAIL_LIMIT) {
|
|
1192
|
+
stderrLen -= stderrChunks[0].length;
|
|
1193
|
+
stderrChunks.shift();
|
|
1194
|
+
}
|
|
1195
|
+
});
|
|
1113
1196
|
let timedOut = false;
|
|
1114
1197
|
const timeoutHandle = setTimeout(() => {
|
|
1115
1198
|
timedOut = true;
|
|
@@ -1128,9 +1211,12 @@ function run(command, args, id, title, workerName, path, onComplete, cwd) {
|
|
|
1128
1211
|
timeoutHandle.unref();
|
|
1129
1212
|
child.on("close", async (code) => {
|
|
1130
1213
|
clearTimeout(timeoutHandle);
|
|
1131
|
-
const
|
|
1132
|
-
|
|
1133
|
-
|
|
1214
|
+
const { status: finalStatus, output } = buildTaskResult(
|
|
1215
|
+
code,
|
|
1216
|
+
timedOut,
|
|
1217
|
+
Buffer.concat(outputChunks).toString("utf-8"),
|
|
1218
|
+
Buffer.concat(stderrChunks).toString("utf-8").slice(-STDERR_TAIL_LIMIT)
|
|
1219
|
+
);
|
|
1134
1220
|
try {
|
|
1135
1221
|
await Promise.race([
|
|
1136
1222
|
onComplete?.(finalStatus, output) ?? Promise.resolve(),
|
|
@@ -1651,6 +1737,14 @@ async function deleteLocalBranch(branchName) {
|
|
|
1651
1737
|
console.error(`[worktree] Failed to delete local branch ${branchName}: ${stderr.trim()}`);
|
|
1652
1738
|
}
|
|
1653
1739
|
}
|
|
1740
|
+
async function localBranchExists(branchName) {
|
|
1741
|
+
try {
|
|
1742
|
+
await execFileAsync2("git", ["rev-parse", "--verify", "--quiet", `refs/heads/${branchName}`]);
|
|
1743
|
+
return true;
|
|
1744
|
+
} catch {
|
|
1745
|
+
return false;
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1654
1748
|
function getWorktreePath(worktreeId) {
|
|
1655
1749
|
return `${WORKTREES_DIR}/${worktreeId}`;
|
|
1656
1750
|
}
|
|
@@ -1778,6 +1872,8 @@ function createIssuePollingWorker(config) {
|
|
|
1778
1872
|
"--dangerously-skip-permissions",
|
|
1779
1873
|
"--disallowedTools",
|
|
1780
1874
|
DISALLOWED_TOOLS_ARG,
|
|
1875
|
+
"--append-subagent-system-prompt",
|
|
1876
|
+
SUBAGENT_SYSTEM_PROMPT,
|
|
1781
1877
|
"--model",
|
|
1782
1878
|
model,
|
|
1783
1879
|
"--effort",
|
|
@@ -1814,13 +1910,20 @@ function createIssuePollingWorker(config) {
|
|
|
1814
1910
|
}
|
|
1815
1911
|
try {
|
|
1816
1912
|
if (status === "completed") {
|
|
1817
|
-
await config.onCompleted?.(issue.number);
|
|
1818
|
-
|
|
1913
|
+
const verified = await config.onCompleted?.(issue.number, worktreeId) ?? true;
|
|
1914
|
+
if (verified === false) {
|
|
1915
|
+
await notifyTaskFailed(config.name, name, issue.number, issue.title, issueUrl, output);
|
|
1916
|
+
} else {
|
|
1917
|
+
await notifyTaskCompleted(config.name, name, issue.number, issue.title, issueUrl, output);
|
|
1918
|
+
}
|
|
1819
1919
|
} else {
|
|
1820
1920
|
await notifyTaskFailed(config.name, name, issue.number, issue.title, issueUrl, output);
|
|
1821
1921
|
}
|
|
1822
1922
|
} catch (err) {
|
|
1823
1923
|
console.error(`[${config.name}] post-task error for #${issue.number}: ${err}`);
|
|
1924
|
+
await notifyTaskFailed(config.name, name, issue.number, issue.title, issueUrl, output).catch(
|
|
1925
|
+
(notifyErr) => console.error(`[${config.name}] notifyTaskFailed failed for #${issue.number}: ${notifyErr}`)
|
|
1926
|
+
);
|
|
1824
1927
|
} finally {
|
|
1825
1928
|
await removeLabel("issue", issue.number, "cc-in-progress").catch(
|
|
1826
1929
|
(err) => console.error(`[${config.name}] removeLabel cc-in-progress failed for #${issue.number}: ${err}`)
|
|
@@ -1852,18 +1955,47 @@ function createIssuePollingWorker(config) {
|
|
|
1852
1955
|
}
|
|
1853
1956
|
|
|
1854
1957
|
// src/workers/exec-issue.ts
|
|
1958
|
+
function prMissingComment(worktreeId) {
|
|
1959
|
+
return [
|
|
1960
|
+
"## PR\u672A\u4F5C\u6210\u306E\u307E\u307E\u81EA\u52D5\u5B9F\u884C\u304C\u7D42\u4E86\u3057\u307E\u3057\u305F\uFF08\u8981\u4EBA\u624B\u78BA\u8A8D\uFF09",
|
|
1961
|
+
`exec-issue \u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u6B63\u5E38\u7D42\u4E86\uFF08exit 0\uFF09\u3057\u307E\u3057\u305F\u304C\u3001\u3053\u306E\u5B9F\u884C\u306E\u4F5C\u696D\u30D6\u30E9\u30F3\u30C1\uFF08\`${worktreeId}\`\uFF09\u3092 head \u3068\u3059\u308BPR\u3082\u3001\u672CIssue\u3092 closing \u53C2\u7167\u3059\u308BPR\u3082\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002PR\u4F5C\u6210\u524D\u306B\u30BB\u30C3\u30B7\u30E7\u30F3\u304C\u7D42\u4E86\u3057\u305F\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002`,
|
|
1962
|
+
"",
|
|
1963
|
+
"## \u72B6\u614B\u306E\u78BA\u8A8D",
|
|
1964
|
+
`- \u5909\u66F4\u304C push \u6E08\u307F\u306E\u5834\u5408\u306F\u30EA\u30E2\u30FC\u30C8\u30D6\u30E9\u30F3\u30C1 \`${worktreeId}\` \u304C\u6B8B\u3063\u3066\u3044\u307E\u3059\u3002\u5185\u5BB9\u3092\u78BA\u8A8D\u3057\u3001\u5FC5\u8981\u306A\u3089\u624B\u52D5\u3067PR\u3092\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044`,
|
|
1965
|
+
"",
|
|
1966
|
+
"## \u5BFE\u5FDC\u5F8C\u306E\u9032\u3081\u65B9",
|
|
1967
|
+
"- \u81EA\u52D5\u5B9F\u884C\u3092\u3084\u308A\u76F4\u3059\u5834\u5408: `cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3001`cc-exec-issue` \u30E9\u30D9\u30EB\u3092\u4ED8\u3051\u76F4\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
1968
|
+
"- \u624B\u52D5\u3067PR\u3092\u4F5C\u6210\u3057\u305F\u5834\u5408\u306A\u3069\u5BFE\u5FDC\u6E08\u307F\u306E\u5834\u5408: `cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
1969
|
+
].join("\n");
|
|
1970
|
+
}
|
|
1855
1971
|
var execIssueWorker = (opts = {}) => createIssuePollingWorker({
|
|
1856
1972
|
name: "exec-issue",
|
|
1857
1973
|
command: "/claude-task-worker:exec-issue",
|
|
1858
1974
|
triggerLabels: ["cc-exec-issue"],
|
|
1859
1975
|
epicFilters: opts.epicFilters,
|
|
1860
1976
|
labelFilters: opts.labelFilters,
|
|
1861
|
-
onCompleted: async (issueNumber) => {
|
|
1977
|
+
onCompleted: async (issueNumber, worktreeId) => {
|
|
1862
1978
|
if (await hasLabel("issue", issueNumber, "cc-need-human-check")) {
|
|
1863
1979
|
console.log(`[exec-issue] #${issueNumber}: cc-need-human-check present, skip cc-pr-created`);
|
|
1980
|
+
return false;
|
|
1981
|
+
}
|
|
1982
|
+
if (await getIssueState(issueNumber) === "CLOSED") {
|
|
1983
|
+
console.log(`[exec-issue] #${issueNumber}: issue closed by skill (no-change path), skip cc-pr-created`);
|
|
1864
1984
|
return;
|
|
1865
1985
|
}
|
|
1866
|
-
await
|
|
1986
|
+
const prNumber = await findPrNumberByHeadRef(worktreeId, "all") ?? await findPrNumberClosingIssue(issueNumber);
|
|
1987
|
+
if (prNumber !== null) {
|
|
1988
|
+
await addLabel("issue", issueNumber, "cc-pr-created");
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1991
|
+
console.error(
|
|
1992
|
+
`[exec-issue] #${issueNumber}: session exited without a PR (branch: ${worktreeId}); marking cc-need-human-check`
|
|
1993
|
+
);
|
|
1994
|
+
await addLabel("issue", issueNumber, "cc-need-human-check");
|
|
1995
|
+
await commentOnIssue(issueNumber, prMissingComment(worktreeId)).catch(
|
|
1996
|
+
(err) => console.error(`[exec-issue] commentOnIssue failed for #${issueNumber}: ${err}`)
|
|
1997
|
+
);
|
|
1998
|
+
return false;
|
|
1867
1999
|
}
|
|
1868
2000
|
})();
|
|
1869
2001
|
|
|
@@ -1897,6 +2029,14 @@ function createPrPollingWorker(config) {
|
|
|
1897
2029
|
try {
|
|
1898
2030
|
await removeWorktreeByBranch(pr.headRefName);
|
|
1899
2031
|
await deleteLocalBranch(pr.headRefName);
|
|
2032
|
+
if (await localBranchExists(pr.headRefName)) {
|
|
2033
|
+
console.error(
|
|
2034
|
+
`[${config.name}] PR #${pr.number}: branch ${pr.headRefName} is still checked out by another worktree; skipping this tick`
|
|
2035
|
+
);
|
|
2036
|
+
await removeLabel("pr", pr.number, LABEL_IN_PROGRESS).catch(() => {
|
|
2037
|
+
});
|
|
2038
|
+
continue;
|
|
2039
|
+
}
|
|
1900
2040
|
syncDefaultBranch(defaultBranch);
|
|
1901
2041
|
await createWorktreeFromBranch(worktreeId, defaultBranch);
|
|
1902
2042
|
const cwd = getWorktreePath(worktreeId);
|
|
@@ -1910,6 +2050,8 @@ function createPrPollingWorker(config) {
|
|
|
1910
2050
|
"--dangerously-skip-permissions",
|
|
1911
2051
|
"--disallowedTools",
|
|
1912
2052
|
DISALLOWED_TOOLS_ARG,
|
|
2053
|
+
"--append-subagent-system-prompt",
|
|
2054
|
+
SUBAGENT_SYSTEM_PROMPT,
|
|
1913
2055
|
"--model",
|
|
1914
2056
|
model,
|
|
1915
2057
|
"--effort",
|
|
@@ -2074,6 +2216,19 @@ var checkDependabotWorker = createPrPollingWorker({
|
|
|
2074
2216
|
});
|
|
2075
2217
|
|
|
2076
2218
|
// src/workers/epic-issue.ts
|
|
2219
|
+
function epicPrMissingComment(issueNumber) {
|
|
2220
|
+
return [
|
|
2221
|
+
"## Epic PR\u672A\u4F5C\u6210\u306E\u307E\u307E\u81EA\u52D5\u5B9F\u884C\u304C\u7D42\u4E86\u3057\u307E\u3057\u305F\uFF08\u8981\u4EBA\u624B\u78BA\u8A8D\uFF09",
|
|
2222
|
+
`create-epic-pr \u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u6B63\u5E38\u7D42\u4E86\uFF08exit 0\uFF09\u3057\u307E\u3057\u305F\u304C\u3001Epic \u30D6\u30E9\u30F3\u30C1 \`cc-epic-${issueNumber}\` \u3092 head \u3068\u3059\u308B\u30AA\u30FC\u30D7\u30F3\u306APR\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002PR\u4F5C\u6210\u524D\u306B\u30BB\u30C3\u30B7\u30E7\u30F3\u304C\u7D42\u4E86\u3057\u305F\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002`,
|
|
2223
|
+
"",
|
|
2224
|
+
"## \u72B6\u614B\u306E\u78BA\u8A8D",
|
|
2225
|
+
`- \u5909\u66F4\u304C push \u6E08\u307F\u306E\u5834\u5408\u306F\u30EA\u30E2\u30FC\u30C8\u30D6\u30E9\u30F3\u30C1 \`cc-epic-${issueNumber}\` \u304C\u6B8B\u3063\u3066\u3044\u307E\u3059\u3002\u5185\u5BB9\u3092\u78BA\u8A8D\u3057\u3001\u5FC5\u8981\u306A\u3089\u624B\u52D5\u3067PR\u3092\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044`,
|
|
2226
|
+
"",
|
|
2227
|
+
"## \u5BFE\u5FDC\u5F8C\u306E\u9032\u3081\u65B9",
|
|
2228
|
+
"- \u81EA\u52D5\u5B9F\u884C\u3092\u3084\u308A\u76F4\u3059\u5834\u5408: `cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3001`cc-epic-issue` \u30E9\u30D9\u30EB\u3092\u4ED8\u3051\u76F4\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
2229
|
+
"- \u624B\u52D5\u3067PR\u3092\u4F5C\u6210\u3057\u305F\u5834\u5408\u306A\u3069\u5BFE\u5FDC\u6E08\u307F\u306E\u5834\u5408: `cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
2230
|
+
].join("\n");
|
|
2231
|
+
}
|
|
2077
2232
|
var epicIssueWorker = (opts = {}) => createIssuePollingWorker({
|
|
2078
2233
|
name: "epic-issue",
|
|
2079
2234
|
command: "/claude-task-worker:create-epic-pr",
|
|
@@ -2088,12 +2243,16 @@ var epicIssueWorker = (opts = {}) => createIssuePollingWorker({
|
|
|
2088
2243
|
return "proceed";
|
|
2089
2244
|
},
|
|
2090
2245
|
onCompleted: async (issueNumber) => {
|
|
2091
|
-
await addLabel("issue", issueNumber, "cc-pr-created");
|
|
2092
2246
|
const prNumber = await findOpenPrNumberByHeadRef(`cc-epic-${issueNumber}`);
|
|
2093
2247
|
if (prNumber === null) {
|
|
2094
|
-
console.error(`[epic-issue] Epic PR for branch cc-epic-${issueNumber} not found; skip
|
|
2095
|
-
|
|
2248
|
+
console.error(`[epic-issue] Epic PR for branch cc-epic-${issueNumber} not found; skip cc-pr-created`);
|
|
2249
|
+
await addLabel("issue", issueNumber, "cc-need-human-check");
|
|
2250
|
+
await commentOnIssue(issueNumber, epicPrMissingComment(issueNumber)).catch(
|
|
2251
|
+
(err) => console.error(`[epic-issue] commentOnIssue failed for #${issueNumber}: ${err}`)
|
|
2252
|
+
);
|
|
2253
|
+
return false;
|
|
2096
2254
|
}
|
|
2255
|
+
await addLabel("issue", issueNumber, "cc-pr-created");
|
|
2097
2256
|
await addLabel("pr", prNumber, "cc-epic-issue");
|
|
2098
2257
|
await addLabel("pr", prNumber, "cc-triage-scope");
|
|
2099
2258
|
}
|