claude-task-worker 0.107.0 → 0.108.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.
Files changed (3) hide show
  1. package/README.md +14 -1
  2. package/dist/index.js +44 -13
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -122,7 +122,7 @@ claude-task-worker init --force # 強制上書き
122
122
  ## コマンド
123
123
 
124
124
  ```bash
125
- claude-task-worker <command> [--epic <issue-number>]... [--label <label>]... [--project <name>]... [--cloud]
125
+ claude-task-worker <command> [--epic <issue-number>]... [--label <label>]... [--project <name>]... [--cloud] [--debug]
126
126
  ```
127
127
 
128
128
  | コマンド | 内容 |
@@ -210,6 +210,19 @@ npx claude-task-worker cloud-setup
210
210
 
211
211
  詳細は [`docs/prd-cloud-worker-execution.md`](./docs/prd-cloud-worker-execution.md) を参照。
212
212
 
213
+ ### `--debug`
214
+
215
+ 各タスクの最終報告を対象 Issue/PR へコメントとして残す。ローカル実行(`default` / `herdr`)でもクラウド実行(`--cloud`)でも使える。
216
+
217
+ ```bash
218
+ claude-task-worker exec-issue --debug
219
+ claude-task-worker exec-issue --cloud --debug
220
+ ```
221
+
222
+ 既定(`--debug` なし)では最終報告は Slack 通知にのみ載り、Issue/PR にはコメントされない。毎タスク投稿すると Issue/PR がワーカーの実行ログで埋まるため。
223
+
224
+ 投稿の担当は実行形態で違う。ローカルはワーカーが報告そのもの(`claude -p` の stdout / transcript)を持っているのでワーカーが投稿し、クラウドはワーカーに報告が届かないのでセッション自身に投稿させる(ワーカーはそれを回収して Slack へ載せる)。定期ワーカー(`update-*`)の投稿先は実行記録PR(`ctw-last-run-<ワーカー名>`)。クラウド実行の完了検知(`cc-cloud-done`)はフラグの有無に関わらず従来どおり動く。
225
+
213
226
  ### Pen CLI のログイン
214
227
 
215
228
  `.pen` を扱うスキルは Pen CLI の認証を必要とする。UIデザイン先行ワークフローを使うなら一度ログインしておく。
package/dist/index.js CHANGED
@@ -1732,6 +1732,13 @@ function hasCloudFlag() {
1732
1732
  }
1733
1733
  return cachedCloudFlag;
1734
1734
  }
1735
+ var cachedDebugFlag;
1736
+ function hasDebugFlag() {
1737
+ if (cachedDebugFlag === void 0) {
1738
+ cachedDebugFlag = process.argv.includes("--debug");
1739
+ }
1740
+ return cachedDebugFlag;
1741
+ }
1735
1742
  function assertCloudCompatibleCommand(command) {
1736
1743
  if (FLAG_INCOMPATIBLE_COMMANDS.includes(command)) {
1737
1744
  console.error(`[worker] --cloud cannot be used with the "${command}" command`);
@@ -2585,12 +2592,12 @@ function buildClaudeArgs({
2585
2592
  function buildCloudCreateArgs(commonArgs, prompt) {
2586
2593
  return ["--cloud", prompt, ...commonArgs];
2587
2594
  }
2588
- function appendCloudDoneInstruction(prompt, target) {
2595
+ function appendCloudDoneInstruction(prompt, target, debug = false) {
2589
2596
  const targetLabel = target.type === "issue" ? `Issue #${target.number}` : `PR #${target.number}`;
2590
2597
  const checkoutInstruction = buildCloudCheckoutInstruction(target);
2591
2598
  const worktreeInstruction = buildCloudWorktreeInstruction(prompt);
2592
- const reportInstruction = `\`${CLOUD_DONE_LABEL}\` \u30E9\u30D9\u30EB\u3092\u4ED8\u3051\u308B\u76F4\u524D\u306B\u3001${targetLabel} \u3078 \`${CLOUD_REPORT_HEADING}\` \u3092\u898B\u51FA\u3057\u3068\u3059\u308B\u30B3\u30E1\u30F3\u30C8\u30921\u4EF6\u6295\u7A3F\u3057\u3001\u672C\u6587\u306B\u6700\u7D42\u5831\u544A\uFF08\u5B8C\u4E86\u30FB\u4E2D\u65AD\u306B\u304B\u304B\u308F\u3089\u305A\uFF09\u3092\u66F8\u304F\u3053\u3068\u3002GitHub MCP\uFF08\`add_issue_comment\`\uFF09\u3092\u512A\u5148\u3057\u3001\u5931\u6557\u3057\u305F\u5834\u5408\u306E\u307F \`gh ${target.type} comment ${target.number} --body-file -\` \u3078\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u3059\u308B\u3053\u3068\uFF08\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u306F1\u56DE\u307E\u3067\uFF09\u3002\u30EF\u30FC\u30AB\u30FC\u306F\u3053\u306E\u30B3\u30E1\u30F3\u30C8\u3092\u6700\u7D42\u30EC\u30DD\u30FC\u30C8\u3068\u3057\u3066\u56DE\u53CE\u3057 Slack \u901A\u77E5\u306B\u8F09\u305B\u308B\u3002`;
2593
- const labelInstruction = `\u4E0A\u8A18\u30B3\u30E1\u30F3\u30C8\u306E\u6295\u7A3F\u5F8C\u3001\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u6700\u5F8C\u306E\u64CD\u4F5C\u3068\u3057\u3066 ${targetLabel} \u306B \`${CLOUD_DONE_LABEL}\` \u30E9\u30D9\u30EB\u3092\u4ED8\u4E0E\u3059\u308B\u3053\u3068\u3002GitHub MCP\uFF08\`issue_write\` / method: \`update\`\uFF09\u3092\u512A\u5148\u3057\u3001\u5931\u6557\u3057\u305F\u5834\u5408\u306E\u307F \`gh ${target.type} edit ${target.number} --add-label ${CLOUD_DONE_LABEL}\` \u3078\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u3059\u308B\u3053\u3068\uFF08\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u306F1\u56DE\u307E\u3067\uFF09\u3002\u30EF\u30FC\u30AB\u30FC\u306F\u3053\u306E\u30E9\u30D9\u30EB\u3067\u30BF\u30B9\u30AF\u306E\u7D42\u4E86\u3092\u691C\u77E5\u3057\u3066\u304A\u308A\u3001\u4ED8\u4E0E\u3055\u308C\u306A\u3044\u3068\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u307E\u3067\u5B8C\u4E86\u6271\u3044\u306B\u306A\u3089\u306A\u3044\u3002`;
2599
+ const reportInstruction = debug ? `\`${CLOUD_DONE_LABEL}\` \u30E9\u30D9\u30EB\u3092\u4ED8\u3051\u308B\u76F4\u524D\u306B\u3001${targetLabel} \u3078 \`${CLOUD_REPORT_HEADING}\` \u3092\u898B\u51FA\u3057\u3068\u3059\u308B\u30B3\u30E1\u30F3\u30C8\u30921\u4EF6\u6295\u7A3F\u3057\u3001\u672C\u6587\u306B\u6700\u7D42\u5831\u544A\uFF08\u5B8C\u4E86\u30FB\u4E2D\u65AD\u306B\u304B\u304B\u308F\u3089\u305A\uFF09\u3092\u66F8\u304F\u3053\u3068\u3002GitHub MCP\uFF08\`add_issue_comment\`\uFF09\u3092\u512A\u5148\u3057\u3001\u5931\u6557\u3057\u305F\u5834\u5408\u306E\u307F \`gh ${target.type} comment ${target.number} --body-file -\` \u3078\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u3059\u308B\u3053\u3068\uFF08\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u306F1\u56DE\u307E\u3067\uFF09\u3002\u30EF\u30FC\u30AB\u30FC\u306F\u3053\u306E\u30B3\u30E1\u30F3\u30C8\u3092\u6700\u7D42\u30EC\u30DD\u30FC\u30C8\u3068\u3057\u3066\u56DE\u53CE\u3057 Slack \u901A\u77E5\u306B\u8F09\u305B\u308B\u3002` : "";
2600
+ const labelInstruction = `${debug ? "\u4E0A\u8A18\u30B3\u30E1\u30F3\u30C8\u306E\u6295\u7A3F\u5F8C\u3001" : ""}\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u6700\u5F8C\u306E\u64CD\u4F5C\u3068\u3057\u3066 ${targetLabel} \u306B \`${CLOUD_DONE_LABEL}\` \u30E9\u30D9\u30EB\u3092\u4ED8\u4E0E\u3059\u308B\u3053\u3068\u3002GitHub MCP\uFF08\`issue_write\` / method: \`update\`\uFF09\u3092\u512A\u5148\u3057\u3001\u5931\u6557\u3057\u305F\u5834\u5408\u306E\u307F \`gh ${target.type} edit ${target.number} --add-label ${CLOUD_DONE_LABEL}\` \u3078\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u3059\u308B\u3053\u3068\uFF08\u30D5\u30A9\u30FC\u30EB\u30D0\u30C3\u30AF\u306F1\u56DE\u307E\u3067\uFF09\u3002\u30EF\u30FC\u30AB\u30FC\u306F\u3053\u306E\u30E9\u30D9\u30EB\u3067\u30BF\u30B9\u30AF\u306E\u7D42\u4E86\u3092\u691C\u77E5\u3057\u3066\u304A\u308A\u3001\u4ED8\u4E0E\u3055\u308C\u306A\u3044\u3068\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u307E\u3067\u5B8C\u4E86\u6271\u3044\u306B\u306A\u3089\u306A\u3044\u3002`;
2594
2601
  return [prompt, checkoutInstruction, worktreeInstruction, reportInstruction, labelInstruction].filter((part) => part !== "").join("\n\n");
2595
2602
  }
2596
2603
  var CLOUD_WORKTREE_EXEMPT_SKILLS = ["exec-issue", "fix-review-point", "create-ui-design"];
@@ -2609,7 +2616,7 @@ function buildCloudGitHubAccessInstruction() {
2609
2616
  function buildCloudToolRestriction() {
2610
2617
  return `\u30AF\u30E9\u30A6\u30C9\u5B9F\u884C\u3067\u306F \`--disallowedTools\` \u30D5\u30E9\u30B0\u306B\u3088\u308B\u30C4\u30FC\u30EB\u5236\u9650\u304C\u53CD\u6620\u3055\u308C\u306A\u3044\u305F\u3081\u3001\u4EE5\u4E0B\u306E\u30C4\u30FC\u30EB\u3092\u4F7F\u308F\u306A\u3044\u3053\u3068: ${DISALLOWED_TOOLS.join(", ")}`;
2611
2618
  }
2612
- function buildCloudPrompt(prompt, model, target) {
2619
+ function buildCloudPrompt(prompt, model, target, debug = false) {
2613
2620
  const principles = `\u4EE5\u4E0B\u306F\u3053\u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306E\u5B9F\u884C\u539F\u5247\u3067\u3042\u308B\u3002\u30AF\u30E9\u30A6\u30C9\u5B9F\u884C\u3067\u306F\u30B7\u30B9\u30C6\u30E0\u30D7\u30ED\u30F3\u30D7\u30C8\u306B\u3088\u308B\u6CE8\u5165\u304C\u53CD\u6620\u3055\u308C\u306A\u3044\u305F\u3081\u3001\u30D7\u30ED\u30F3\u30D7\u30C8\u672C\u6587\u3068\u3057\u3066\u6E21\u3057\u3066\u3044\u308B\u3002
2614
2621
 
2615
2622
  ${systemPromptFor(model)}
@@ -2620,7 +2627,7 @@ ${buildCloudGitHubAccessInstruction()}`;
2620
2627
  const withPrinciples = `${prompt}
2621
2628
 
2622
2629
  ${principles}`;
2623
- return target ? appendCloudDoneInstruction(withPrinciples, target) : withPrinciples;
2630
+ return target ? appendCloudDoneInstruction(withPrinciples, target, debug) : withPrinciples;
2624
2631
  }
2625
2632
  function shellQuote2(value) {
2626
2633
  return `'${value.replace(/'/g, "'\\''")}'`;
@@ -2819,6 +2826,21 @@ async function finishTask(id, result, onComplete) {
2819
2826
  pruneTaskHistory();
2820
2827
  renderTable();
2821
2828
  }
2829
+ function onCompleteWithDebugReport(onComplete, target) {
2830
+ if (!target || !hasDebugFlag()) return onComplete;
2831
+ return async (status, output, cloudSessionId) => {
2832
+ const body = output.trim();
2833
+ if (body !== "") {
2834
+ const comment = target.type === "issue" ? commentOnIssue : commentOnPR;
2835
+ await comment(target.number, `${CLOUD_REPORT_HEADING}
2836
+
2837
+ ${body}`).catch(
2838
+ (err) => console.error(`[worker] failed to post the debug report to ${target.type} #${target.number}: ${err}`)
2839
+ );
2840
+ }
2841
+ await onComplete?.(status, output, cloudSessionId);
2842
+ };
2843
+ }
2822
2844
  function resolveProjectName(cwd = process.cwd()) {
2823
2845
  const injected = process.env.CTW_PROJECT_NAME;
2824
2846
  if (injected && injected.length > 0) return injected;
@@ -2992,7 +3014,8 @@ async function createCloudSession(args, initialPrompt, cwd, env) {
2992
3014
  }
2993
3015
  async function runViaCloud(args, prompt, id, onComplete, cwd, env, cloudTarget, model) {
2994
3016
  herdrTasks.set(id, { paneId: "", tabId: "" });
2995
- const initialPrompt = buildCloudPrompt(prompt, model ?? "", cloudTarget);
3017
+ const debug = hasDebugFlag();
3018
+ const initialPrompt = buildCloudPrompt(prompt, model ?? "", cloudTarget, debug);
2996
3019
  let result;
2997
3020
  let cloudSessionId;
2998
3021
  try {
@@ -3010,7 +3033,7 @@ async function runViaCloud(args, prompt, id, onComplete, cwd, env, cloudTarget,
3010
3033
  });
3011
3034
  let reportBody = null;
3012
3035
  const startedAt = tasks.get(id)?.startedAt;
3013
- if (startedAt) {
3036
+ if (debug && startedAt) {
3014
3037
  try {
3015
3038
  reportBody = await findCommentSince(targetNumber, startedAt, CLOUD_REPORT_HEADING);
3016
3039
  } catch (err) {
@@ -3080,8 +3103,9 @@ function run(command, args, id, title, workerName, path2, onComplete, cwd, env,
3080
3103
  void runViaCloud(args, prompt ?? "", id, onComplete, cwd, env, cloudTarget, model);
3081
3104
  return;
3082
3105
  }
3106
+ const onCompleteWithReport = onCompleteWithDebugReport(onComplete, cloudTarget);
3083
3107
  if (getRunMode() === "herdr") {
3084
- void runViaHerdr(args, prompt ?? "", id, onComplete, cwd, env);
3108
+ void runViaHerdr(args, prompt ?? "", id, onCompleteWithReport, cwd, env);
3085
3109
  return;
3086
3110
  }
3087
3111
  const child = spawn(command, args, {
@@ -3117,12 +3141,12 @@ function run(command, args, id, title, workerName, path2, onComplete, cwd, env,
3117
3141
  Buffer.concat(outputChunks).toString("utf-8"),
3118
3142
  Buffer.concat(stderrChunks).toString("utf-8").slice(-STDERR_TAIL_LIMIT)
3119
3143
  );
3120
- await finishTask(id, result, onComplete);
3144
+ await finishTask(id, result, onCompleteWithReport);
3121
3145
  childProcesses.delete(id);
3122
3146
  });
3123
3147
  child.on("error", async (err) => {
3124
3148
  console.error(`[worker] failed to spawn process for #${id}: ${err.message}`);
3125
- await finishTask(id, { status: "failed", output: err.message }, onComplete);
3149
+ await finishTask(id, { status: "failed", output: err.message }, onCompleteWithReport);
3126
3150
  childProcesses.delete(id);
3127
3151
  });
3128
3152
  }
@@ -3984,7 +4008,9 @@ function createIssuePollingWorker(config) {
3984
4008
  buildClaudeEnv(mode, cloud),
3985
4009
  execution.prompt,
3986
4010
  cloud,
3987
- cloud ? { type: "issue", number: issue.number } : void 0,
4011
+ // クラウドでは cc-cloud-done の探索先、ローカルでは --debug の報告コメントの
4012
+ // 投稿先。どちらも対象は同じ Issue なので実行形態で出し分けない。
4013
+ { type: "issue", number: issue.number },
3988
4014
  model
3989
4015
  );
3990
4016
  } catch (err) {
@@ -4241,7 +4267,9 @@ function createPrPollingWorker(config) {
4241
4267
  buildClaudeEnv(mode, isCloud),
4242
4268
  execution.prompt,
4243
4269
  isCloud,
4244
- isCloud ? { type: "pr", number: pr.number, onBranch: true } : void 0,
4270
+ // クラウドでは cc-cloud-done の探索先、ローカルでは --debug の報告コメントの
4271
+ // 投稿先。onBranch は `--on-branch` を渡したか(=クラウドのみ)を表す。
4272
+ { type: "pr", number: pr.number, onBranch: isCloud },
4245
4273
  model
4246
4274
  );
4247
4275
  } catch (err) {
@@ -4837,7 +4865,9 @@ function createScheduledWorker(config) {
4837
4865
  buildClaudeEnv(mode, cloud),
4838
4866
  execution.prompt,
4839
4867
  cloud,
4840
- cloud && lastRunPr !== null ? { type: "pr", number: lastRunPr } : void 0,
4868
+ // 定期ワーカーは Issue/PR を起点に走らないため、クラウドの cc-cloud-done
4869
+ // ローカル --debug の報告コメントも実行記録PRを置き先にする。
4870
+ lastRunPr !== null ? { type: "pr", number: lastRunPr } : void 0,
4841
4871
  model
4842
4872
  );
4843
4873
  } catch (err) {
@@ -5543,6 +5573,7 @@ Workers:
5543
5573
 
5544
5574
  Options:
5545
5575
  --project <name> Dispatch to project(s) via herdr instead of running the worker locally. Accepts a project name, a project group name, or "all". Repeatable.
5576
+ --debug Post each task's final report as a comment on the target Issue/PR (off by default; the report is only sent to Slack). Works in both local and --cloud runs.
5546
5577
  --epic <number> Limit issue-based workers to sub-issues of the specified epic issue. Repeatable: any matching parent (OR).
5547
5578
  --label <name> Limit issue-based workers to issues that also carry the specified label. Repeatable: all must be present (AND).
5548
5579
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-task-worker",
3
- "version": "0.107.0",
3
+ "version": "0.108.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",