claude-task-worker 0.121.0 → 0.123.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.
@@ -184,20 +184,37 @@ async function listPrsClosingIssue(issueNumber) {
184
184
  }
185
185
  async function fetchPrRef(owner, name, prNumber) {
186
186
  try {
187
- const parsed = JSON.parse(await execGh(["api", `repos/${owner}/${name}/pulls/${prNumber}`]));
188
187
  return {
189
- number: prNumber,
190
- state: parsed?.merged_at ? "MERGED" : String(parsed?.state ?? "").toUpperCase(),
191
- headRefName: parsed?.head?.ref ?? "",
192
- baseRefName: parsed?.base?.ref ?? "",
193
- createdAt: parsed?.created_at ?? "",
194
- body: typeof parsed?.body === "string" ? parsed.body : ""
188
+ ...toPrRef(JSON.parse(await execGh(["api", `repos/${owner}/${name}/pulls/${prNumber}`]))),
189
+ number: prNumber
195
190
  };
196
191
  } catch (err) {
197
192
  console.error(`[gh] failed to read PR #${prNumber}: ${err}`);
198
193
  return null;
199
194
  }
200
195
  }
196
+ function toPrRef(parsed) {
197
+ return {
198
+ number: Number(parsed?.number),
199
+ state: parsed?.merged_at ? "MERGED" : String(parsed?.state ?? "").toUpperCase(),
200
+ headRefName: parsed?.head?.ref ?? "",
201
+ baseRefName: parsed?.base?.ref ?? "",
202
+ createdAt: parsed?.created_at ?? "",
203
+ headRepo: parsed?.head?.repo?.full_name ?? "",
204
+ headSha: parsed?.head?.sha ?? "",
205
+ title: parsed?.title ?? "",
206
+ body: typeof parsed?.body === "string" ? parsed.body : ""
207
+ };
208
+ }
209
+ async function listOpenPrsByBase(base) {
210
+ const { owner, name } = await getRepoInfo();
211
+ const output = await execGh([
212
+ "api",
213
+ `repos/${owner}/${name}/pulls?state=open&base=${encodeURIComponent(base)}&per_page=100`,
214
+ "--paginate"
215
+ ]);
216
+ return JSON.parse(output).map(toPrRef);
217
+ }
201
218
  async function getPrDetail(prNumber) {
202
219
  const { owner, name } = await getRepoInfo();
203
220
  return fetchPrRef(owner, name, prNumber);
@@ -223,7 +240,10 @@ function bodyClosesIssue(body, issueNumber) {
223
240
  const pattern = new RegExp(`\\b(close[sd]?|fix(?:e[sd])?|resolve[sd]?)\\s*:?\\s*#${issueNumber}\\b(?!\\d)`, "i");
224
241
  return pattern.test(body);
225
242
  }
226
- async function listPrsCrossReferencingIssue(issueNumber) {
243
+ function bodyMentionsIssue(body, issueNumber) {
244
+ return new RegExp(`#${issueNumber}(?!\\d)`).test(body);
245
+ }
246
+ async function listPrsCrossReferencingIssue(issueNumber, bodyFilter = bodyClosesIssue) {
227
247
  const { owner, name } = await getRepoInfo();
228
248
  const output = await execGh(["api", `repos/${owner}/${name}/issues/${issueNumber}/timeline`, "--paginate"]);
229
249
  const events = JSON.parse(output);
@@ -235,7 +255,30 @@ async function listPrsCrossReferencingIssue(issueNumber) {
235
255
  )
236
256
  ];
237
257
  const refs = await Promise.all(numbers.map((number) => fetchPrRef(owner, name, number)));
238
- return refs.filter((ref) => ref !== null && bodyClosesIssue(ref.body, issueNumber)).map(({ body: _body, ...ref }) => ref);
258
+ return refs.filter(
259
+ (ref) => ref !== null && bodyFilter(ref.body, issueNumber)
260
+ );
261
+ }
262
+ async function createRemoteBranch(branch, sha) {
263
+ const { owner, name } = await getRepoInfo();
264
+ await execGh([
265
+ "api",
266
+ "-X",
267
+ "POST",
268
+ `repos/${owner}/${name}/git/refs`,
269
+ "-f",
270
+ `ref=refs/heads/${branch}`,
271
+ "-f",
272
+ `sha=${sha}`
273
+ ]);
274
+ }
275
+ async function closePullRequest(prNumber) {
276
+ const { owner, name } = await getRepoInfo();
277
+ await execGh(["api", "-X", "PATCH", `repos/${owner}/${name}/pulls/${prNumber}`, "-f", "state=closed"]);
278
+ }
279
+ async function deleteRemoteBranch(branch) {
280
+ const { owner, name } = await getRepoInfo();
281
+ await execGh(["api", "-X", "DELETE", `repos/${owner}/${name}/git/refs/heads/${branch}`]);
239
282
  }
240
283
  var ADD_CLOSE_ISSUE_REFERENCES = `mutation($issueId: ID!, $prId: ID!) {
241
284
  addCloseIssueReferences(input: { issueId: $issueId, pullRequestIds: [$prId] }) { issue { number } }
@@ -3338,10 +3381,15 @@ export {
3338
3381
  getIssueBody,
3339
3382
  getIssueState,
3340
3383
  listPrsClosingIssue,
3384
+ listOpenPrsByBase,
3341
3385
  getPrDetail,
3342
3386
  closeIssue,
3343
3387
  parseClosingIssueNumbers,
3388
+ bodyMentionsIssue,
3344
3389
  listPrsCrossReferencingIssue,
3390
+ createRemoteBranch,
3391
+ closePullRequest,
3392
+ deleteRemoteBranch,
3345
3393
  linkClosingPr,
3346
3394
  getIssueSubIssuesSummary,
3347
3395
  listPullRequestsWithChecks,
@@ -3352,6 +3400,7 @@ export {
3352
3400
  removeLabel,
3353
3401
  commentOnPR,
3354
3402
  commentOnIssue,
3403
+ createPullRequest,
3355
3404
  createLabel,
3356
3405
  parseProjectFilters,
3357
3406
  hasProjectFilter,
package/dist/gh.d.ts CHANGED
@@ -51,15 +51,26 @@ export interface ClosingPrRef {
51
51
  headRefName: string;
52
52
  baseRefName: string;
53
53
  createdAt: string;
54
+ headRepo?: string;
55
+ headSha?: string;
56
+ title?: string;
57
+ body?: string;
54
58
  }
55
59
  export declare function listPrsClosingIssue(issueNumber: number): Promise<ClosingPrRef[]>;
60
+ export declare function listOpenPrsByBase(base: string): Promise<(ClosingPrRef & {
61
+ body: string;
62
+ })[]>;
56
63
  export declare function getPrDetail(prNumber: number): Promise<(ClosingPrRef & {
57
64
  body: string;
58
65
  }) | null>;
59
66
  export declare function closeIssue(issueNumber: number, reason?: "completed" | "not_planned"): Promise<void>;
60
67
  export declare function parseClosingIssueNumbers(body: string): number[];
61
68
  export declare function bodyClosesIssue(body: string, issueNumber: number): boolean;
62
- export declare function listPrsCrossReferencingIssue(issueNumber: number): Promise<ClosingPrRef[]>;
69
+ export declare function bodyMentionsIssue(body: string, issueNumber: number): boolean;
70
+ export declare function listPrsCrossReferencingIssue(issueNumber: number, bodyFilter?: (body: string, issueNumber: number) => boolean): Promise<ClosingPrRef[]>;
71
+ export declare function createRemoteBranch(branch: string, sha: string): Promise<void>;
72
+ export declare function closePullRequest(prNumber: number): Promise<void>;
73
+ export declare function deleteRemoteBranch(branch: string): Promise<void>;
63
74
  export declare function linkClosingPr(issueNumber: number, prNumber: number): Promise<void>;
64
75
  export declare function findPrNumberClosingIssue(issueNumber: number, expectedHeadRefName: string): Promise<number | null>;
65
76
  export declare function getIssueSubIssuesSummary(issueNumber: number): Promise<SubIssuesSummary>;
package/dist/index.js CHANGED
@@ -12,18 +12,23 @@ import {
12
12
  addLabel,
13
13
  assertCloudCompatibleCommand,
14
14
  assertProjectCompatibleCommand,
15
+ bodyMentionsIssue,
15
16
  buildForwardedCommand,
16
17
  buildScriptCommand,
17
18
  buildTokenLimitText,
18
19
  checkCloudConfig,
19
20
  closeIssue,
21
+ closePullRequest,
20
22
  commentOnIssue,
21
23
  commentOnPR,
22
24
  createIssuePollingWorker,
23
25
  createLabel,
24
26
  createPrPollingWorker,
27
+ createPullRequest,
28
+ createRemoteBranch,
25
29
  createScheduledWorker,
26
30
  defineWorker,
31
+ deleteRemoteBranch,
27
32
  disabledWorkerMessage,
28
33
  ensureRenderInterval,
29
34
  findOpenPrNumberByHeadRef,
@@ -48,6 +53,7 @@ import {
48
53
  isWorkerDefinition,
49
54
  isWorkerEnabled,
50
55
  linkClosingPr,
56
+ listOpenPrsByBase,
51
57
  listPrsClosingIssue,
52
58
  listPrsCrossReferencingIssue,
53
59
  loadConfig,
@@ -65,7 +71,7 @@ import {
65
71
  shutdown,
66
72
  waitForAllProcesses,
67
73
  writeLastRun
68
- } from "./chunk-Z2IEIKI3.js";
74
+ } from "./chunk-HZHIQMAQ.js";
69
75
  import {
70
76
  captureConsole
71
77
  } from "./chunk-N42YU3GJ.js";
@@ -289,6 +295,112 @@ var createIssueWorker = createIssuePollingWorker({
289
295
  }
290
296
  });
291
297
 
298
+ // src/workers/exec-issue.ts
299
+ var REPORT_TAIL_LIMIT = 3e3;
300
+ function formatSessionReport(output) {
301
+ const trimmed = output.trim();
302
+ if (trimmed === "") return "\uFF08\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u51FA\u529B\u306F\u3042\u308A\u307E\u305B\u3093\u3067\u3057\u305F\uFF09";
303
+ const tail = trimmed.length > REPORT_TAIL_LIMIT ? `\u2026\uFF08\u5148\u982D\u3092\u7701\u7565\uFF09
304
+ ${trimmed.slice(-REPORT_TAIL_LIMIT)}` : trimmed;
305
+ return ["```", tail, "```"].join("\n");
306
+ }
307
+ function selectOwnedClosingPr(candidates, ctx) {
308
+ const open = candidates.filter((c) => c.state === "MERGED" || c.state === "OPEN");
309
+ if (!ctx.cloud) {
310
+ const found2 = open.find((c) => c.headRefName === ctx.expectedHeadRefName);
311
+ return found2 ? found2.number : null;
312
+ }
313
+ const found = open.find((c) => {
314
+ if (c.baseRefName !== ctx.baseBranch) return false;
315
+ const createdAt = Date.parse(c.createdAt);
316
+ return !Number.isNaN(createdAt) && createdAt >= ctx.startedAt && createdAt <= ctx.now;
317
+ });
318
+ return found ? found.number : null;
319
+ }
320
+ function prMissingComment(worktreeId, output, cloud) {
321
+ const stateSection = cloud ? [
322
+ "## \u72B6\u614B\u306E\u78BA\u8A8D",
323
+ "- \u30AF\u30E9\u30A6\u30C9\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u4F5C\u696D\u30D6\u30E9\u30F3\u30C1\u540D\u3092\u81EA\u8EAB\u3067\u6C7A\u3081\u308B\u305F\u3081\u3001\u30ED\u30FC\u30AB\u30EB\u304B\u3089\u306F\u540D\u524D\u304C\u5206\u304B\u308A\u307E\u305B\u3093\u3002claude.ai \u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u753B\u9762\u3067\u4F5C\u696D\u30D6\u30E9\u30F3\u30C1\u3068 push \u72B6\u6CC1\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044"
324
+ ] : [
325
+ "## \u72B6\u614B\u306E\u78BA\u8A8D",
326
+ `- \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`
327
+ ];
328
+ return [
329
+ "## 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",
330
+ cloud ? "exec-issue \u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u6B63\u5E38\u7D42\u4E86\uFF08exit 0\uFF09\u3057\u307E\u3057\u305F\u304C\u3001\u672CIssue\u3092 closing \u53C2\u7167\u3059\u308BPR\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" : `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`,
331
+ "",
332
+ "## PR\u3092\u4F5C\u6210\u3057\u306A\u304B\u3063\u305F\u7406\u7531\uFF08\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u6700\u7D42\u5831\u544A\uFF09",
333
+ formatSessionReport(output),
334
+ "",
335
+ ...stateSection,
336
+ "",
337
+ "## \u5BFE\u5FDC\u5F8C\u306E\u9032\u3081\u65B9",
338
+ "- \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",
339
+ "- \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"
340
+ ].join("\n");
341
+ }
342
+ async function ensurePrTriageMetadata(prNumber) {
343
+ await addLabel("pr", prNumber, "cc-triage-scope").catch(
344
+ (err) => console.error(`[exec-issue] addLabel cc-triage-scope failed for PR #${prNumber}: ${err}`)
345
+ );
346
+ await getCurrentUser().then((user) => addAssignee("pr", prNumber, user)).catch((err) => console.error(`[exec-issue] addAssignee failed for PR #${prNumber}: ${err}`));
347
+ }
348
+ async function verifyPrCreated(issueNumber, worktreeId, output, ctx) {
349
+ if (await hasLabel("issue", issueNumber, "cc-need-human-check")) {
350
+ console.log(`[exec-issue] #${issueNumber}: cc-need-human-check present, skip cc-pr-created`);
351
+ return false;
352
+ }
353
+ if (await getIssueState(issueNumber) === "CLOSED") {
354
+ console.log(`[exec-issue] #${issueNumber}: issue closed by skill (no-change path), skip cc-pr-created`);
355
+ return;
356
+ }
357
+ const ownership = {
358
+ cloud: ctx.cloud,
359
+ expectedHeadRefName: worktreeId,
360
+ baseBranch: ctx.baseBranch,
361
+ startedAt: ctx.startedAt,
362
+ now: Date.now()
363
+ };
364
+ let prNumber = null;
365
+ if (!ctx.cloud) {
366
+ prNumber = await findPrNumberByHeadRef(worktreeId, "all");
367
+ }
368
+ if (prNumber === null) {
369
+ prNumber = selectOwnedClosingPr(await listPrsClosingIssue(issueNumber), ownership);
370
+ }
371
+ if (prNumber === null) {
372
+ const candidates = await listPrsCrossReferencingIssue(issueNumber).catch((err) => {
373
+ console.error(`[exec-issue] listPrsCrossReferencingIssue failed for #${issueNumber}: ${err}`);
374
+ return [];
375
+ });
376
+ prNumber = selectOwnedClosingPr(candidates, ownership);
377
+ if (prNumber !== null) {
378
+ await linkClosingPr(issueNumber, prNumber).catch(
379
+ (err) => console.error(`[exec-issue] linkClosingPr failed for #${issueNumber} -> #${prNumber}: ${err}`)
380
+ );
381
+ }
382
+ }
383
+ if (prNumber !== null) {
384
+ await addLabel("issue", issueNumber, "cc-pr-created");
385
+ await ensurePrTriageMetadata(prNumber);
386
+ return;
387
+ }
388
+ console.error(
389
+ `[exec-issue] #${issueNumber}: session exited without a PR (branch: ${worktreeId}); marking cc-need-human-check`
390
+ );
391
+ await addLabel("issue", issueNumber, "cc-need-human-check");
392
+ await commentOnIssue(issueNumber, prMissingComment(worktreeId, output, ctx.cloud)).catch(
393
+ (err) => console.error(`[exec-issue] commentOnIssue failed for #${issueNumber}: ${err}`)
394
+ );
395
+ return false;
396
+ }
397
+ var execIssueWorker = createIssuePollingWorker({
398
+ name: "exec-issue",
399
+ command: "/claude-task-worker:exec-issue",
400
+ triggerLabels: ["cc-exec-issue"],
401
+ onCompleted: verifyPrCreated
402
+ });
403
+
292
404
  // src/workers/create-ui-design.ts
293
405
  function designPrLabelingFailedComment(issueNumber, prNumber, error, yolo = false) {
294
406
  const message = error instanceof Error ? error.message : String(error);
@@ -309,6 +421,42 @@ function designPrLabelingFailedComment(issueNumber, prNumber, error, yolo = fals
309
421
  `- \u30E9\u30D9\u30EB\u4F5C\u6210\u5F8C\u306B\u3084\u308A\u76F4\u3059\u5834\u5408: \`cc-need-human-check\` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3001${yolo ? "`cc-ui-design`\u30FB`cc-triage-scope`" : "`cc-ui-design`"}\uFF08PR\u5074\uFF09\u3068 \`cc-ui-design-pr-created\`\uFF08Issue\u5074\uFF09\u3092\u624B\u52D5\u3067\u4ED8\u3051\u3066\u304F\u3060\u3055\u3044`
310
422
  ].join("\n");
311
423
  }
424
+ async function adoptCloudDesignPr(issueNumber, branch, ctx) {
425
+ const { owner, name } = await getRepoInfo();
426
+ const candidates = (await listOpenPrsByBase(ctx.baseBranch)).filter(
427
+ (c) => c.headRepo === `${owner}/${name}` && bodyMentionsIssue(c.body, issueNumber)
428
+ );
429
+ const prNumber = selectOwnedClosingPr(candidates, {
430
+ cloud: true,
431
+ expectedHeadRefName: branch,
432
+ baseBranch: ctx.baseBranch,
433
+ startedAt: ctx.startedAt,
434
+ now: Date.now()
435
+ });
436
+ if (prNumber === null) return null;
437
+ const pr = candidates.find((c) => c.number === prNumber);
438
+ if (!pr || pr.headRefName === branch) return prNumber;
439
+ if (!pr.headSha) throw new Error(`design PR #${prNumber} has no head sha`);
440
+ await deleteRemoteBranch(branch).catch(() => {
441
+ });
442
+ await createRemoteBranch(branch, pr.headSha);
443
+ const newPr = await createPullRequest(
444
+ pr.baseRefName,
445
+ branch,
446
+ pr.title || `UI design for #${issueNumber}`,
447
+ pr.body ?? ""
448
+ );
449
+ await commentOnPR(
450
+ prNumber,
451
+ `\u30D6\u30E9\u30F3\u30C1 \`${branch}\` \u304B\u3089\u4F5C\u308A\u76F4\u3057\u305F #${newPr} \u3078\u79FB\u884C\u3057\u305F\u305F\u3081\u3001\u3053\u306EPR\u3092\u9589\u3058\u307E\u3059\u3002`
452
+ ).catch(() => {
453
+ });
454
+ await closePullRequest(prNumber);
455
+ console.log(
456
+ `[create-ui-design] #${issueNumber}: recreated design PR #${prNumber} (${pr.headRefName}) as #${newPr} (${branch})`
457
+ );
458
+ return newPr;
459
+ }
312
460
  var createUiDesignWorker = defineWorker({
313
461
  name: "create-ui-design",
314
462
  kind: "issue",
@@ -324,7 +472,7 @@ var createUiDesignWorker = defineWorker({
324
472
  command: "/claude-task-worker:create-ui-design",
325
473
  triggerLabels: ["cc-create-ui-design"],
326
474
  excludeLabels: ["cc-ui-design-pr-created", "cc-ui-design-ready", "cc-exec-issue", "cc-pr-created"],
327
- onCompleted: async (issueNumber) => {
475
+ onCompleted: async (issueNumber, _worktreeId, _output, ctx) => {
328
476
  if (await hasLabel("issue", issueNumber, "cc-need-human-check")) {
329
477
  console.log(`[create-ui-design] #${issueNumber}: cc-need-human-check present, skip cc-ui-design-pr-created`);
330
478
  return false;
@@ -336,7 +484,13 @@ var createUiDesignWorker = defineWorker({
336
484
  }
337
485
  }
338
486
  const branch = designBranchName(issueNumber);
339
- const prNumber = await findPrNumberByHeadRef(branch, "open");
487
+ let prNumber = await findPrNumberByHeadRef(branch, "open");
488
+ if (prNumber === null && ctx.cloud) {
489
+ prNumber = await adoptCloudDesignPr(issueNumber, branch, ctx).catch((err) => {
490
+ console.error(`[create-ui-design] #${issueNumber}: adoptCloudDesignPr failed: ${err}`);
491
+ return null;
492
+ });
493
+ }
340
494
  if (prNumber === null) {
341
495
  console.error(
342
496
  `[create-ui-design] #${issueNumber}: session exited without an open design PR (branch: ${branch}); marking cc-need-human-check`
@@ -416,112 +570,6 @@ var epicIssueWorker = createIssuePollingWorker({
416
570
  }
417
571
  });
418
572
 
419
- // src/workers/exec-issue.ts
420
- var REPORT_TAIL_LIMIT = 3e3;
421
- function formatSessionReport(output) {
422
- const trimmed = output.trim();
423
- if (trimmed === "") return "\uFF08\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u51FA\u529B\u306F\u3042\u308A\u307E\u305B\u3093\u3067\u3057\u305F\uFF09";
424
- const tail = trimmed.length > REPORT_TAIL_LIMIT ? `\u2026\uFF08\u5148\u982D\u3092\u7701\u7565\uFF09
425
- ${trimmed.slice(-REPORT_TAIL_LIMIT)}` : trimmed;
426
- return ["```", tail, "```"].join("\n");
427
- }
428
- function selectOwnedClosingPr(candidates, ctx) {
429
- const open = candidates.filter((c) => c.state === "MERGED" || c.state === "OPEN");
430
- if (!ctx.cloud) {
431
- const found2 = open.find((c) => c.headRefName === ctx.expectedHeadRefName);
432
- return found2 ? found2.number : null;
433
- }
434
- const found = open.find((c) => {
435
- if (c.baseRefName !== ctx.baseBranch) return false;
436
- const createdAt = Date.parse(c.createdAt);
437
- return !Number.isNaN(createdAt) && createdAt >= ctx.startedAt && createdAt <= ctx.now;
438
- });
439
- return found ? found.number : null;
440
- }
441
- function prMissingComment(worktreeId, output, cloud) {
442
- const stateSection = cloud ? [
443
- "## \u72B6\u614B\u306E\u78BA\u8A8D",
444
- "- \u30AF\u30E9\u30A6\u30C9\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u4F5C\u696D\u30D6\u30E9\u30F3\u30C1\u540D\u3092\u81EA\u8EAB\u3067\u6C7A\u3081\u308B\u305F\u3081\u3001\u30ED\u30FC\u30AB\u30EB\u304B\u3089\u306F\u540D\u524D\u304C\u5206\u304B\u308A\u307E\u305B\u3093\u3002claude.ai \u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u753B\u9762\u3067\u4F5C\u696D\u30D6\u30E9\u30F3\u30C1\u3068 push \u72B6\u6CC1\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044"
445
- ] : [
446
- "## \u72B6\u614B\u306E\u78BA\u8A8D",
447
- `- \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`
448
- ];
449
- return [
450
- "## 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",
451
- cloud ? "exec-issue \u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u6B63\u5E38\u7D42\u4E86\uFF08exit 0\uFF09\u3057\u307E\u3057\u305F\u304C\u3001\u672CIssue\u3092 closing \u53C2\u7167\u3059\u308BPR\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" : `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`,
452
- "",
453
- "## PR\u3092\u4F5C\u6210\u3057\u306A\u304B\u3063\u305F\u7406\u7531\uFF08\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u6700\u7D42\u5831\u544A\uFF09",
454
- formatSessionReport(output),
455
- "",
456
- ...stateSection,
457
- "",
458
- "## \u5BFE\u5FDC\u5F8C\u306E\u9032\u3081\u65B9",
459
- "- \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",
460
- "- \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"
461
- ].join("\n");
462
- }
463
- async function ensurePrTriageMetadata(prNumber) {
464
- await addLabel("pr", prNumber, "cc-triage-scope").catch(
465
- (err) => console.error(`[exec-issue] addLabel cc-triage-scope failed for PR #${prNumber}: ${err}`)
466
- );
467
- await getCurrentUser().then((user) => addAssignee("pr", prNumber, user)).catch((err) => console.error(`[exec-issue] addAssignee failed for PR #${prNumber}: ${err}`));
468
- }
469
- async function verifyPrCreated(issueNumber, worktreeId, output, ctx) {
470
- if (await hasLabel("issue", issueNumber, "cc-need-human-check")) {
471
- console.log(`[exec-issue] #${issueNumber}: cc-need-human-check present, skip cc-pr-created`);
472
- return false;
473
- }
474
- if (await getIssueState(issueNumber) === "CLOSED") {
475
- console.log(`[exec-issue] #${issueNumber}: issue closed by skill (no-change path), skip cc-pr-created`);
476
- return;
477
- }
478
- const ownership = {
479
- cloud: ctx.cloud,
480
- expectedHeadRefName: worktreeId,
481
- baseBranch: ctx.baseBranch,
482
- startedAt: ctx.startedAt,
483
- now: Date.now()
484
- };
485
- let prNumber = null;
486
- if (!ctx.cloud) {
487
- prNumber = await findPrNumberByHeadRef(worktreeId, "all");
488
- }
489
- if (prNumber === null) {
490
- prNumber = selectOwnedClosingPr(await listPrsClosingIssue(issueNumber), ownership);
491
- }
492
- if (prNumber === null) {
493
- const candidates = await listPrsCrossReferencingIssue(issueNumber).catch((err) => {
494
- console.error(`[exec-issue] listPrsCrossReferencingIssue failed for #${issueNumber}: ${err}`);
495
- return [];
496
- });
497
- prNumber = selectOwnedClosingPr(candidates, ownership);
498
- if (prNumber !== null) {
499
- await linkClosingPr(issueNumber, prNumber).catch(
500
- (err) => console.error(`[exec-issue] linkClosingPr failed for #${issueNumber} -> #${prNumber}: ${err}`)
501
- );
502
- }
503
- }
504
- if (prNumber !== null) {
505
- await addLabel("issue", issueNumber, "cc-pr-created");
506
- await ensurePrTriageMetadata(prNumber);
507
- return;
508
- }
509
- console.error(
510
- `[exec-issue] #${issueNumber}: session exited without a PR (branch: ${worktreeId}); marking cc-need-human-check`
511
- );
512
- await addLabel("issue", issueNumber, "cc-need-human-check");
513
- await commentOnIssue(issueNumber, prMissingComment(worktreeId, output, ctx.cloud)).catch(
514
- (err) => console.error(`[exec-issue] commentOnIssue failed for #${issueNumber}: ${err}`)
515
- );
516
- return false;
517
- }
518
- var execIssueWorker = createIssuePollingWorker({
519
- name: "exec-issue",
520
- command: "/claude-task-worker:exec-issue",
521
- triggerLabels: ["cc-exec-issue"],
522
- onCompleted: verifyPrCreated
523
- });
524
-
525
573
  // src/workers/fix-review-point.ts
526
574
  var fixReviewPointWorker = createPrPollingWorker({
527
575
  name: "fix-review-point",
package/dist/lib.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  removeWorktreeByBranch,
59
59
  run,
60
60
  syncDefaultBranch
61
- } from "./chunk-Z2IEIKI3.js";
61
+ } from "./chunk-HZHIQMAQ.js";
62
62
  import "./chunk-N42YU3GJ.js";
63
63
  export {
64
64
  CLOUD_DONE_LABEL,
@@ -1,2 +1,6 @@
1
1
  export declare function designPrLabelingFailedComment(issueNumber: number, prNumber: number, error: unknown, yolo?: boolean): string;
2
+ export declare function adoptCloudDesignPr(issueNumber: number, branch: string, ctx: {
3
+ baseBranch: string;
4
+ startedAt: number;
5
+ }): Promise<number | null>;
2
6
  export declare const createUiDesignWorker: import("./worker-definition").WorkerDefinition;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-task-worker",
3
- "version": "0.121.0",
3
+ "version": "0.123.0",
4
4
  "description": "CLI tool that polls GitHub Issues/PRs and delegates work to Claude CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",