claude-task-worker 0.104.0 → 0.106.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/README.md +2 -1
- package/dist/index.js +120 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,7 +105,8 @@ claude-task-worker init --force # 強制上書き
|
|
|
105
105
|
|
|
106
106
|
| ラベル | 用途 |
|
|
107
107
|
|---|---|
|
|
108
|
-
| `cc-triage-scope` | トリアージ対象マーク(Issue/PR
|
|
108
|
+
| `cc-triage-scope` | トリアージ対象マーク(Issue/PR)=ワーカーのキュー合流口 |
|
|
109
|
+
| `cc-issue-request` | 人が Issue テンプレートから作成を依頼した印。起票者を assignee に自動設定するワークフローの発火条件(`cc-triage-scope` と役割を分けてあり、ワーカーの自動起票では付かない) |
|
|
109
110
|
| `cc-issue-created` | `create-issue` 由来の Issue マーク |
|
|
110
111
|
| `cc-update-issue` / `cc-answer-issue-questions` / `cc-exec-issue` | Issue の更新 / 確認事項回答 / 実行トリガー |
|
|
111
112
|
| `cc-fix-onetime` / `cc-resolve-conflict` | PR の修正 / コンフリクト解消トリガー |
|
package/dist/index.js
CHANGED
|
@@ -1470,6 +1470,61 @@ async function listPrsClosingIssue(issueNumber) {
|
|
|
1470
1470
|
createdAt: node.createdAt ?? ""
|
|
1471
1471
|
}));
|
|
1472
1472
|
}
|
|
1473
|
+
async function fetchPrRef(owner, name, prNumber) {
|
|
1474
|
+
try {
|
|
1475
|
+
const parsed = JSON.parse(await execGh(["api", `repos/${owner}/${name}/pulls/${prNumber}`]));
|
|
1476
|
+
return {
|
|
1477
|
+
number: prNumber,
|
|
1478
|
+
state: parsed?.merged_at ? "MERGED" : String(parsed?.state ?? "").toUpperCase(),
|
|
1479
|
+
headRefName: parsed?.head?.ref ?? "",
|
|
1480
|
+
baseRefName: parsed?.base?.ref ?? "",
|
|
1481
|
+
createdAt: parsed?.created_at ?? "",
|
|
1482
|
+
body: typeof parsed?.body === "string" ? parsed.body : ""
|
|
1483
|
+
};
|
|
1484
|
+
} catch (err) {
|
|
1485
|
+
console.error(`[gh] failed to read PR #${prNumber}: ${err}`);
|
|
1486
|
+
return null;
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
function bodyClosesIssue(body, issueNumber) {
|
|
1490
|
+
const pattern = new RegExp(`\\b(close[sd]?|fix(?:e[sd])?|resolve[sd]?)\\s*:?\\s*#${issueNumber}\\b(?!\\d)`, "i");
|
|
1491
|
+
return pattern.test(body);
|
|
1492
|
+
}
|
|
1493
|
+
async function listPrsCrossReferencingIssue(issueNumber) {
|
|
1494
|
+
const { owner, name } = await getRepoInfo();
|
|
1495
|
+
const output = await execGh(["api", `repos/${owner}/${name}/issues/${issueNumber}/timeline`, "--paginate"]);
|
|
1496
|
+
const events = JSON.parse(output);
|
|
1497
|
+
const numbers = [
|
|
1498
|
+
...new Set(
|
|
1499
|
+
events.filter(
|
|
1500
|
+
(e) => e.event === "cross-referenced" && e.source?.issue?.pull_request != null && e.source.issue.repository?.full_name === `${owner}/${name}` && typeof e.source.issue.number === "number"
|
|
1501
|
+
).map((e) => e.source?.issue?.number)
|
|
1502
|
+
)
|
|
1503
|
+
];
|
|
1504
|
+
const refs = await Promise.all(numbers.map((number) => fetchPrRef(owner, name, number)));
|
|
1505
|
+
return refs.filter((ref) => ref !== null && bodyClosesIssue(ref.body, issueNumber)).map(({ body: _body, ...ref }) => ref);
|
|
1506
|
+
}
|
|
1507
|
+
var ADD_CLOSE_ISSUE_REFERENCES = `mutation($issueId: ID!, $prId: ID!) {
|
|
1508
|
+
addCloseIssueReferences(input: { issueId: $issueId, pullRequestIds: [$prId] }) { issue { number } }
|
|
1509
|
+
}`;
|
|
1510
|
+
async function linkClosingPr(issueNumber, prNumber) {
|
|
1511
|
+
const { owner, name } = await getRepoInfo();
|
|
1512
|
+
const issueId = JSON.parse(await execGh(["api", `repos/${owner}/${name}/issues/${issueNumber}`]))?.node_id;
|
|
1513
|
+
const prId = JSON.parse(await execGh(["api", `repos/${owner}/${name}/pulls/${prNumber}`]))?.node_id;
|
|
1514
|
+
if (typeof issueId !== "string" || typeof prId !== "string") {
|
|
1515
|
+
throw new Error(`node_id not found (issue #${issueNumber} / PR #${prNumber})`);
|
|
1516
|
+
}
|
|
1517
|
+
await execGh([
|
|
1518
|
+
"api",
|
|
1519
|
+
"graphql",
|
|
1520
|
+
"-f",
|
|
1521
|
+
`query=${ADD_CLOSE_ISSUE_REFERENCES}`,
|
|
1522
|
+
"-F",
|
|
1523
|
+
`issueId=${issueId}`,
|
|
1524
|
+
"-F",
|
|
1525
|
+
`prId=${prId}`
|
|
1526
|
+
]);
|
|
1527
|
+
}
|
|
1473
1528
|
async function getIssueSubIssuesSummary(issueNumber) {
|
|
1474
1529
|
const output = await execGh(["issue", "view", String(issueNumber), "--json", "subIssuesSummary"]);
|
|
1475
1530
|
const parsed = JSON.parse(output);
|
|
@@ -4007,19 +4062,31 @@ async function verifyPrCreated(issueNumber, worktreeId, output, ctx) {
|
|
|
4007
4062
|
console.log(`[exec-issue] #${issueNumber}: issue closed by skill (no-change path), skip cc-pr-created`);
|
|
4008
4063
|
return;
|
|
4009
4064
|
}
|
|
4065
|
+
const ownership = {
|
|
4066
|
+
cloud: ctx.cloud,
|
|
4067
|
+
expectedHeadRefName: worktreeId,
|
|
4068
|
+
baseBranch: ctx.baseBranch,
|
|
4069
|
+
startedAt: ctx.startedAt,
|
|
4070
|
+
now: Date.now()
|
|
4071
|
+
};
|
|
4010
4072
|
let prNumber = null;
|
|
4011
4073
|
if (!ctx.cloud) {
|
|
4012
4074
|
prNumber = await findPrNumberByHeadRef(worktreeId, "all");
|
|
4013
4075
|
}
|
|
4014
4076
|
if (prNumber === null) {
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
now: Date.now()
|
|
4077
|
+
prNumber = selectOwnedClosingPr(await listPrsClosingIssue(issueNumber), ownership);
|
|
4078
|
+
}
|
|
4079
|
+
if (prNumber === null) {
|
|
4080
|
+
const candidates = await listPrsCrossReferencingIssue(issueNumber).catch((err) => {
|
|
4081
|
+
console.error(`[exec-issue] listPrsCrossReferencingIssue failed for #${issueNumber}: ${err}`);
|
|
4082
|
+
return [];
|
|
4022
4083
|
});
|
|
4084
|
+
prNumber = selectOwnedClosingPr(candidates, ownership);
|
|
4085
|
+
if (prNumber !== null) {
|
|
4086
|
+
await linkClosingPr(issueNumber, prNumber).catch(
|
|
4087
|
+
(err) => console.error(`[exec-issue] linkClosingPr failed for #${issueNumber} -> #${prNumber}: ${err}`)
|
|
4088
|
+
);
|
|
4089
|
+
}
|
|
4023
4090
|
}
|
|
4024
4091
|
if (prNumber !== null) {
|
|
4025
4092
|
await addLabel("issue", issueNumber, "cc-pr-created");
|
|
@@ -4794,7 +4861,7 @@ var updateDesignMdWorker = createScheduledWorker({
|
|
|
4794
4861
|
init_table();
|
|
4795
4862
|
|
|
4796
4863
|
// src/commands/init.ts
|
|
4797
|
-
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2, access } from "node:fs/promises";
|
|
4864
|
+
import { mkdir as mkdir2, readFile as readFile2, rm as rm2, writeFile as writeFile2, access } from "node:fs/promises";
|
|
4798
4865
|
import { basename as basename3 } from "node:path";
|
|
4799
4866
|
|
|
4800
4867
|
// src/commands/codegraph.ts
|
|
@@ -4917,14 +4984,20 @@ var LABELS = [
|
|
|
4917
4984
|
// vivid bronze (H46 S100 L29 / L*50 C*56)
|
|
4918
4985
|
{ name: "cc-ui-design-ready", color: "0c73e9" },
|
|
4919
4986
|
// vivid azure (H212 S90 L48 / L*50 C*69)
|
|
4920
|
-
{ name: CLOUD_DONE_LABEL, color: "33cfff" }
|
|
4987
|
+
{ name: CLOUD_DONE_LABEL, color: "33cfff" },
|
|
4921
4988
|
// vivid sky blue (H194 S100 L60 / L*78 C*42)
|
|
4989
|
+
// 追加時点で有彩色ラベルが色相環をほぼ埋めており、上記6点を全て満たす色は残っていない。
|
|
4990
|
+
// 最寄り色相との差は27°が上限(H185 が最大)で、その相手は cc-cloud-done(クラウド実行中だけ
|
|
4991
|
+
// 現れる短命なマーカー・L*78 と明度が倍近く違う)=見分けたい相手ではない側に倒してある。
|
|
4992
|
+
{ name: "cc-issue-request", color: "03656d" }
|
|
4993
|
+
// vivid deep teal (H185 S95 L22 / L*39 C*24)
|
|
4922
4994
|
];
|
|
4923
4995
|
var ISSUE_TEMPLATE = `name: "[claude-task-worker] Issue\u4F5C\u6210\u4F9D\u983C"
|
|
4924
4996
|
description: claude-task-worker\u3067GitHub Issue\u3092\u4F5C\u6210\u3059\u308B
|
|
4925
4997
|
title: "[claude-task-worker] Issue\u4F5C\u6210\u4F9D\u983C"
|
|
4926
4998
|
labels:
|
|
4927
4999
|
- cc-triage-scope
|
|
5000
|
+
- cc-issue-request
|
|
4928
5001
|
body:
|
|
4929
5002
|
- type: textarea
|
|
4930
5003
|
id: request
|
|
@@ -4934,7 +5007,7 @@ body:
|
|
|
4934
5007
|
validations:
|
|
4935
5008
|
required: true
|
|
4936
5009
|
`;
|
|
4937
|
-
var ASSIGN_CREATOR_WORKFLOW = `name: Assign creator on
|
|
5010
|
+
var ASSIGN_CREATOR_WORKFLOW = `name: Assign creator on issue request
|
|
4938
5011
|
|
|
4939
5012
|
on:
|
|
4940
5013
|
issues:
|
|
@@ -4942,7 +5015,7 @@ on:
|
|
|
4942
5015
|
|
|
4943
5016
|
jobs:
|
|
4944
5017
|
assign:
|
|
4945
|
-
if: contains(github.event.issue.labels.*.name, 'cc-
|
|
5018
|
+
if: contains(github.event.issue.labels.*.name, 'cc-issue-request')
|
|
4946
5019
|
runs-on: ubuntu-latest
|
|
4947
5020
|
permissions:
|
|
4948
5021
|
issues: write
|
|
@@ -5000,6 +5073,25 @@ async function ensureLocalConfigGitIgnore() {
|
|
|
5000
5073
|
await writeFile2(path2, next, "utf-8");
|
|
5001
5074
|
console.log(`[init] Added ${entry} to ${path2}`);
|
|
5002
5075
|
}
|
|
5076
|
+
var LEGACY_PATHS = [
|
|
5077
|
+
".github/ISSUE_TEMPLATE/cc-triage-scope.yml",
|
|
5078
|
+
".github/workflows/assign-creator-on-cc-triage-scope.yml"
|
|
5079
|
+
];
|
|
5080
|
+
function isContentMismatch(result, expected, actual) {
|
|
5081
|
+
return result === "skipped" && actual !== expected;
|
|
5082
|
+
}
|
|
5083
|
+
async function removeLegacyIssueRequestFiles() {
|
|
5084
|
+
for (const path2 of LEGACY_PATHS) {
|
|
5085
|
+
try {
|
|
5086
|
+
await rm2(path2);
|
|
5087
|
+
console.log(`[init] Removed legacy file: ${path2}`);
|
|
5088
|
+
} catch (err) {
|
|
5089
|
+
if (err.code !== "ENOENT") {
|
|
5090
|
+
throw err;
|
|
5091
|
+
}
|
|
5092
|
+
}
|
|
5093
|
+
}
|
|
5094
|
+
}
|
|
5003
5095
|
async function init(options = {}) {
|
|
5004
5096
|
const force = options.force ?? false;
|
|
5005
5097
|
console.log(`[init] Creating labels...${force ? " (force mode)" : ""}`);
|
|
@@ -5013,12 +5105,25 @@ async function init(options = {}) {
|
|
|
5013
5105
|
}
|
|
5014
5106
|
console.log("[init] Creating issue template...");
|
|
5015
5107
|
await mkdir2(".github/ISSUE_TEMPLATE", { recursive: true });
|
|
5016
|
-
const templatePath = ".github/ISSUE_TEMPLATE/cc-
|
|
5017
|
-
|
|
5108
|
+
const templatePath = ".github/ISSUE_TEMPLATE/cc-issue-request.yml";
|
|
5109
|
+
const templateResult = await writeFileWithMode(templatePath, ISSUE_TEMPLATE, force);
|
|
5110
|
+
logWriteResult(templateResult, templatePath);
|
|
5018
5111
|
console.log("[init] Creating GitHub Actions workflow...");
|
|
5019
5112
|
await mkdir2(".github/workflows", { recursive: true });
|
|
5020
|
-
const workflowPath = ".github/workflows/assign-creator-on-
|
|
5021
|
-
|
|
5113
|
+
const workflowPath = ".github/workflows/assign-creator-on-issue-request.yml";
|
|
5114
|
+
const workflowResult = await writeFileWithMode(workflowPath, ASSIGN_CREATOR_WORKFLOW, force);
|
|
5115
|
+
logWriteResult(workflowResult, workflowPath);
|
|
5116
|
+
if (isContentMismatch(templateResult, ISSUE_TEMPLATE, await readFile2(templatePath, "utf-8"))) {
|
|
5117
|
+
throw new Error(
|
|
5118
|
+
`[init] ${templatePath} \u306F\u65E2\u5B58\u306E\u5185\u5BB9\u304C\u6700\u65B0\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002--force \u3067\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u65E7\u30D5\u30A1\u30A4\u30EB\u306F\u524A\u9664\u3057\u3066\u3044\u307E\u305B\u3093\u3002`
|
|
5119
|
+
);
|
|
5120
|
+
}
|
|
5121
|
+
if (isContentMismatch(workflowResult, ASSIGN_CREATOR_WORKFLOW, await readFile2(workflowPath, "utf-8"))) {
|
|
5122
|
+
throw new Error(
|
|
5123
|
+
`[init] ${workflowPath} \u306F\u65E2\u5B58\u306E\u5185\u5BB9\u304C\u6700\u65B0\u306E\u30EF\u30FC\u30AF\u30D5\u30ED\u30FC\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002--force \u3067\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u65E7\u30D5\u30A1\u30A4\u30EB\u306F\u524A\u9664\u3057\u3066\u3044\u307E\u305B\u3093\u3002`
|
|
5124
|
+
);
|
|
5125
|
+
}
|
|
5126
|
+
await removeLegacyIssueRequestFiles();
|
|
5022
5127
|
console.log("[init] Creating config file...");
|
|
5023
5128
|
await createConfig(force);
|
|
5024
5129
|
await ensureLocalConfigGitIgnore();
|