claude-task-worker 0.34.0 → 0.35.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 +140 -21
- package/dist/index.js +423 -65
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,8 +51,12 @@ GitHub Issues/PRを定期ポーリングし、Claude Codeに処理を委譲す
|
|
|
51
51
|
| `resolve-conflict` | `cc-resolve-conflict` (PR) | `/claude-task-worker:resolve-pr-conflict` | 1分 |
|
|
52
52
|
| `check-dependabot` | `dependencies` (PR) | `/claude-task-worker:check-dependabot` | 1時間 |
|
|
53
53
|
| `epic-issue` | `cc-epic-issue` (Issue, sub-issues が全て Close) | `/claude-task-worker:create-epic-pr` | 5分 |
|
|
54
|
+
| `create-ui-design` | `cc-create-ui-design` (Issue) | `/claude-task-worker:create-ui-design` | 1分 |
|
|
55
|
+
| `apply-ui-design` | `cc-ui-design-pr-created` (Issue) | `/claude-task-worker:apply-ui-design` | 1分 |
|
|
54
56
|
|
|
55
57
|
> ℹ️ Issue 系ワーカーはすべて GitHub Issue Dependencies の `-is:blocked` 検索 qualifier でサーバ側絞り込みを行うため、未解決の blockedBy Issue を持つ Issue は対象外となる。
|
|
58
|
+
>
|
|
59
|
+
> ℹ️ `create-ui-design` / `apply-ui-design` は `claude-task-worker.json` の `uiDesign.enabled` が `true` のときだけ起動する(既定は `false`)。詳細は「[UIデザイン先行ワークフロー](#uiデザイン先行ワークフロー)」を参照。
|
|
56
60
|
|
|
57
61
|
### Epic(親Issue)連携
|
|
58
62
|
|
|
@@ -60,9 +64,63 @@ GitHub Issues/PRを定期ポーリングし、Claude Codeに処理を委譲す
|
|
|
60
64
|
|
|
61
65
|
`epic-issue` ワーカーは、`cc-epic-issue` ラベル付きの親Issueに紐づくサブIssueがすべて Close されたタイミングで `/claude-task-worker:create-epic-pr` を起動し、エピックブランチからまとめてPRを作成する。
|
|
62
66
|
|
|
67
|
+
### UIデザイン先行ワークフロー
|
|
68
|
+
|
|
69
|
+
UI実装Issueについて、実装の前に Pencil(`.pen`)でデザインを作り、それを独立したPRとしてマージしてから実装へ進むフロー。デザインの見た目・構成を実装PRとは別に単体でレビュー・合意でき、合意済みデザインがリポジトリに永続化される。
|
|
70
|
+
|
|
71
|
+
`claude-task-worker.json` の `uiDesign.enabled` によるオプトインで、既定(`false`)では2つのワーカーが起動しないため、Pencil を使っていないリポジトリの挙動は本機能の追加前と完全に一致する。
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"uiDesign": {
|
|
76
|
+
"enabled": true,
|
|
77
|
+
"designDir": "designs"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
| キー | 既定値 | 意味 |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| `uiDesign.enabled` | `false` | 本ワークフローの有効化。`false` の間は `triage-created-issue` がUI判定を行わず、2つのワーカーも起動しない |
|
|
85
|
+
| `uiDesign.designDir` | `"designs"` | `.pen` とスナップショットの配置先(リポジトリルートからの相対パス) |
|
|
86
|
+
|
|
87
|
+
フローは以下のとおり。
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
cc-issue-created + triage-created-issue(ルーティング)
|
|
91
|
+
├─ UI実装タスクでない → cc-exec-issue(従来どおり)
|
|
92
|
+
└─ UI実装タスク → cc-create-ui-design
|
|
93
|
+
→ create-ui-design ワーカー
|
|
94
|
+
・.pen を作成/更新 + snapshots/ に PNG 出力
|
|
95
|
+
・ブランチ cc-ui-design-<N> を push しデザインPRを作成(Refs #N。closing keyword は使わない)
|
|
96
|
+
・PR に cc-triage-scope + cc-ui-design、Issue に cc-ui-design-pr-created を付与
|
|
97
|
+
→ triage-pr / fix-review-point / resolve-conflict(既存フローでレビュー・マージ)
|
|
98
|
+
→ apply-ui-design ワーカー
|
|
99
|
+
・デザインPRが MERGED になるまで skip
|
|
100
|
+
・Issue description に「## UIデザイン」セクションを追記
|
|
101
|
+
・cc-ui-design-ready + cc-exec-issue を付与
|
|
102
|
+
→ exec-issue(デザインを参照元として実装)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
デザインPRは Epic PR ではないため `cc-release-ready` によるマージ保留の対象外で、`triage-pr` が通常どおりレビュー・マージする。`triage-pr` は `cc-ui-design` ラベル付きPRに対してコードレビューではなくデザイン向けの観点(差分が `.pen` とPNGに限定されているか、スナップショットとデザイン意図が読み取れるか、Issue要件を満たしているか)で評価する。
|
|
106
|
+
|
|
107
|
+
デザインが不要と判明した場合は `create-ui-design` が理由をコメントして `cc-ui-design-ready` + `cc-exec-issue` を付与し、人手を介さず実装へ復帰する。Pencil が使えない環境やデザインPRが却下された場合は `cc-need-human-check` に落ちて停止する(共通除外ラベルのため無限リトライしない)。
|
|
108
|
+
|
|
63
109
|
### `--project` 指定時(ディスパッチャーモード)
|
|
64
110
|
|
|
65
|
-
`--project` オプションを指定した場合、CLIは自身でワーカーを起動する代わりに [herdr](https://herdr.dev) 経由のディスパッチャーとして動作する。指定したプロジェクトごとにherdr
|
|
111
|
+
`--project` オプションを指定した場合、CLIは自身でワーカーを起動する代わりに [herdr](https://herdr.dev) 経由のディスパッチャーとして動作する。指定したプロジェクトごとにherdrのワークスペースを作成し、そのルートペインで(`--project` を除いた)同じコマンドを実行させ、稼働状況をステータステーブルで監視する。詳細は「[`--project <name>` オプション](#--project-name-オプション)」を参照。
|
|
112
|
+
|
|
113
|
+
### claude-task-worker プラグインの構成
|
|
114
|
+
|
|
115
|
+
| ディレクトリ | 内容 |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `plugin/skills/` | ワーカーが呼び出すスキル群と、対話セッションから使う補助スキル(`commit-push` / `create-pr` / `breakdown-issues` / `edit-pencil-design` など) |
|
|
118
|
+
| `plugin/agents/` | サブエージェント定義(`explore-agent` / `frontend-implementer` / `general-purpose-assistant` / `lightweight-assistant` / `pencil-design-updater` / `requirement-todo-organizer`) |
|
|
119
|
+
| `plugin/hooks/` | `SessionStart`(worktree セットアップ・`git fetch --prune`)と `UserPromptSubmit`(`codegraph prompt-hook`)のフック定義 |
|
|
120
|
+
| `plugin/scripts/` | フックから呼ばれるスクリプト(`setup-worktree.sh` / `stop-servers.mjs`) |
|
|
121
|
+
| `plugin/.mcp.json` | プラグインが提供する MCP サーバー定義(下記「[プラグインが利用する MCP サーバー](#プラグインが利用する-mcp-サーバー)」) |
|
|
122
|
+
|
|
123
|
+
ワーカー起動スキルには `Stop` フック(`plugin/scripts/stop-servers.mjs`)が設定されており、スキル終了時に `docker compose down` と、worktree を作業ディレクトリに持つ残留プロセスの `SIGTERM` をベストエフォートで実行する。worktree はスキル完了直後に削除されるため、切り離されたサーバープロセスが残ると削除の妨げになるのを防ぐ。
|
|
66
124
|
|
|
67
125
|
## 必要なライブラリ
|
|
68
126
|
|
|
@@ -77,8 +135,10 @@ CLI 本体に npm の実行時依存パッケージはない(ビルド時に e
|
|
|
77
135
|
| [Claude Code (`claude`)](https://docs.anthropic.com/en/docs/claude-code) | - | タスク実行エンジン。各ワーカーが Claude CLI プロセスとして起動する |
|
|
78
136
|
| [Git (`git`)](https://git-scm.com/) | - | worktree の作成・ブランチ操作 |
|
|
79
137
|
| [jq](https://jqlang.org/) | - | プラグインスキル内でのJSON加工(`check-dependabot` / `edit-pencil-design` スキルなどで使用) |
|
|
138
|
+
| [CodeGraph (`codegraph`)](https://www.npmjs.com/package/@colbymchenry/codegraph) | - | コード探索用のインデックス。MCP サーバー(`codegraph serve --mcp`)としてプラグインから起動される。`install` / `update` / `init` が面倒を見る。未インストールでもワーカーは動作する(探索がテキスト検索に落ちるだけ) |
|
|
80
139
|
| [Pencil CLI (`pencil`)](https://docs.pencil.dev/for-developers/pencil-cli) | - | `.pen` デザインファイルの編集・参照・コンフリクト解消(`edit-pencil-design` / `inspect-pencil-node` / `resolve-pencil-conflict` スキルで使用) |
|
|
81
|
-
| [herdr](https://herdr.dev) | - | `--project`
|
|
140
|
+
| [herdr](https://herdr.dev) | - | `--project` 使用時と `mode: "herdr"` 使用時にのみ必要。複数プロジェクトへのディスパッチ・セッション監視・一括停止、タスクのTUI実行に使用 |
|
|
141
|
+
| [Headroom (`headroom`)](https://github.com/headroom-ai/headroom) | - | `headroom: true` 使用時にのみ必要。タスクの claude をコンテキスト圧縮プロキシ経由で起動する |
|
|
82
142
|
| `claude-task-worker` プラグイン | - | 各ワーカーが呼び出すスキル群(本リポジトリの `plugin/`) |
|
|
83
143
|
|
|
84
144
|
Slack通知(任意)を使う場合は Slack Incoming Webhook URL が必要。Claude API使用状況の取得には、macOSでは `security` コマンド(Keychain)を使用し、それ以外の環境では `~/.claude/.credentials.json` にフォールバックする。
|
|
@@ -102,6 +162,7 @@ Slack通知(任意)を使う場合は Slack Incoming Webhook URL が必要
|
|
|
102
162
|
|
|
103
163
|
| サーバー | 接続方法 | 用途 |
|
|
104
164
|
|---|---|---|
|
|
165
|
+
| `codegraph` | `codegraph serve --mcp`(stdio) | シンボルの定義元・参照元・呼び出し関係をたどるコード探索。ワーカー起動セッションは `--append-system-prompt` の指示により、`Grep`/`Glob` より優先してこの MCP を使う |
|
|
105
166
|
| `context7` | HTTP(`https://mcp.context7.com/mcp`) | ライブラリの最新ドキュメント取得 |
|
|
106
167
|
| `next-devtools` | `npx -y next-devtools-mcp@latest` | Next.js 開発支援 |
|
|
107
168
|
| `shadcn` | `npx shadcn@latest mcp` | shadcn/ui コンポーネント情報の取得 |
|
|
@@ -114,7 +175,9 @@ Slack通知(任意)を使う場合は Slack Incoming Webhook URL が必要
|
|
|
114
175
|
- [GitHub CLI (`gh`)](https://cli.github.com/) がインストール・認証済みであること
|
|
115
176
|
- [Claude Code (`claude`)](https://docs.anthropic.com/en/docs/claude-code) がインストール済みであること
|
|
116
177
|
- `claude-task-worker` プラグインがインストール済みであること(下記インストール手順を参照)
|
|
117
|
-
- `--project`
|
|
178
|
+
- `--project` オプション・`mode: "herdr"` を使う場合のみ、[herdr](https://herdr.dev) がインストール済みであること
|
|
179
|
+
- `headroom: true` を使う場合のみ、[Headroom](https://github.com/headroom-ai/headroom) がインストール済みであること
|
|
180
|
+
- CodeGraph はコード探索の精度向上のために推奨(`install` / `init` が導入・インデックス構築を行う)。未導入でもワーカーは動作する
|
|
118
181
|
|
|
119
182
|
詳細は上記「[必要なライブラリ](#必要なライブラリ)」を参照。
|
|
120
183
|
|
|
@@ -122,7 +185,7 @@ Slack通知(任意)を使う場合は Slack Incoming Webhook URL が必要
|
|
|
122
185
|
|
|
123
186
|
#### 推奨手順(一発セットアップ)
|
|
124
187
|
|
|
125
|
-
以下のコマンド一発で、Claude Code マーケットプレイスの追加・プラグインのインストール・CLI
|
|
188
|
+
以下のコマンド一発で、Claude Code マーケットプレイスの追加・プラグインのインストール・CLI本体のグローバルインストール・CodeGraph CLI のインストールをまとめて行える。
|
|
126
189
|
|
|
127
190
|
```bash
|
|
128
191
|
npx claude-task-worker install
|
|
@@ -131,6 +194,7 @@ npx claude-task-worker install
|
|
|
131
194
|
- `claude plugin marketplace add getty104/claude-task-worker` — マーケットプレイスの追加(追加済みの場合のエラーはログのみで無視して続行)
|
|
132
195
|
- `claude plugin install claude-task-worker@claude-task-worker` — プラグインのインストール
|
|
133
196
|
- `npm install -g claude-task-worker@latest` — CLI 本体のグローバルインストール(`npx` 実行時でも `claude-task-worker` コマンドを常設化する)
|
|
197
|
+
- `npm install -g @colbymchenry/codegraph@latest` — CodeGraph CLI のインストール(MCP サーバーの登録はプラグインの `.mcp.json` が担うため、`codegraph install` は実行しない)
|
|
134
198
|
|
|
135
199
|
インストール後、Claude Code のセッションを再起動するとプラグインが有効化される。
|
|
136
200
|
|
|
@@ -173,7 +237,7 @@ brew install herdr
|
|
|
173
237
|
|
|
174
238
|
#### 更新
|
|
175
239
|
|
|
176
|
-
CLI
|
|
240
|
+
CLI・プラグイン(マーケットプレイス)・CodeGraph CLI をまとめて更新する。
|
|
177
241
|
|
|
178
242
|
```bash
|
|
179
243
|
claude-task-worker update
|
|
@@ -182,10 +246,11 @@ claude-task-worker update
|
|
|
182
246
|
- `claude plugin marketplace update claude-task-worker` — マーケットプレイスの更新
|
|
183
247
|
- `claude plugin update claude-task-worker@claude-task-worker` — プラグインの更新(反映にはセッション再起動が必要)
|
|
184
248
|
- `npm install -g claude-task-worker@latest` — CLI 本体の更新
|
|
249
|
+
- `codegraph upgrade` — CodeGraph CLI の更新(未インストール環境ではコマンドが無く失敗するため、`npm install -g @colbymchenry/codegraph@latest` へフォールバックする)
|
|
185
250
|
|
|
186
251
|
### 初期化
|
|
187
252
|
|
|
188
|
-
対象リポジトリで実行すると、必要なGitHubラベル・Issueテンプレート・GitHub Actions
|
|
253
|
+
対象リポジトリで実行すると、必要なGitHubラベル・Issueテンプレート・GitHub Actionsワークフロー・設定ファイルが作成され、CodeGraph のセットアップが行われる。既存ファイルは保護され、`--force` を指定すると上書きされる。
|
|
189
254
|
|
|
190
255
|
```bash
|
|
191
256
|
claude-task-worker init # 既存ファイルは保護
|
|
@@ -208,12 +273,21 @@ claude-task-worker init --force # 既存ファイルを強制上書き
|
|
|
208
273
|
| `cc-pr-created` | PR作成完了マーク |
|
|
209
274
|
| `cc-epic-issue` | エピックマーク(Issueではサブ全Closeで `epic-issue` ワーカー起動、PRではリリースゲート対象を示すマーク) |
|
|
210
275
|
| `cc-release-ready` | エピックPRがリリース可能(マージ問題なし)と判定されたマーク。実際のマージ(リリース)は人間が実施 |
|
|
276
|
+
| `cc-create-ui-design` | UIデザイン作成トリガー(`create-ui-design` ワーカー。`uiDesign.enabled` が `true` の場合のみ機能する) |
|
|
277
|
+
| `cc-ui-design-pr-created` | デザインPR作成済み・マージ待ちマーク(`apply-ui-design` ワーカーのトリガー) |
|
|
278
|
+
| `cc-ui-design-ready` | デザイン反映済みマーク(再デザイン抑止。デザイン不要と判定された場合も付与される) |
|
|
279
|
+
| `cc-ui-design` | デザインPRのマーカー(PR。`triage-pr` のレビュー観点切り替えに使う) |
|
|
211
280
|
|
|
212
281
|
作成されるファイル:
|
|
213
282
|
|
|
214
283
|
- `.github/ISSUE_TEMPLATE/cc-triage-scope.yml` — `cc-triage-scope` ラベル付きIssue作成用テンプレート
|
|
215
284
|
- `.github/workflows/assign-creator-on-cc-triage-scope.yml` — Issue作成者を自動アサインするワークフロー
|
|
216
|
-
- `claude-task-worker.json` —
|
|
285
|
+
- `claude-task-worker.json` — 設定ファイル(コマンド実行ディレクトリ直下。全ワーカーのデフォルト設定と `uiDesign`(既定は無効)が書き込まれた状態で作成される)
|
|
286
|
+
|
|
287
|
+
CodeGraph のセットアップ:
|
|
288
|
+
|
|
289
|
+
- グローバル gitignore(`$XDG_CONFIG_HOME/git/ignore`、未設定なら `~/.config/git/ignore`)へ `.codegraph/` を追記する(冪等)。`.codegraph/` はプロジェクトごとのローカルインデックスでコミット対象ではないが、対象リポジトリの `.gitignore` を汚さないためグローバル側に入れる
|
|
290
|
+
- `codegraph init` でインデックスを構築する。CodeGraph が未インストールでも `init` 全体は失敗せず、ログにエラーを出して続行する
|
|
217
291
|
|
|
218
292
|
## コマンド
|
|
219
293
|
|
|
@@ -282,9 +356,11 @@ claude-task-worker yolo --epic 100 --epic 200 --label priority-high
|
|
|
282
356
|
|
|
283
357
|
ディスパッチャーは以下の3つの機能を持つ。
|
|
284
358
|
|
|
285
|
-
- **一斉起動**: 対象プロジェクトごとに `ctw:<プロジェクト名>` ラベルのherdrワークスペースを作成し、そのプロジェクトのディレクトリで(`--project`
|
|
359
|
+
- **一斉起動**: 対象プロジェクトごとに `ctw:<プロジェクト名>` ラベルのherdrワークスペースを作成し、そのプロジェクトのディレクトリで(`--project` を除いた)同じコマンドを実行する。ペインのシェル初期化が終わるのを待ってからコマンドを送り、送信後はワーカープロセスが実際に起動したかを確認する(シェルのままなら再送し、それでも起動しなければそのプロジェクトは失敗としてタブを閉じる)
|
|
286
360
|
- **稼働一覧**: 各セッションのプロジェクト名・ワークスペースID・ペインID・ステータス・稼働時間をステータステーブルとして定期的に画面へ描画し、対象プロセスが終了したセッションは自動的に一覧から除去する
|
|
287
|
-
- **一括停止**: SIGTERM/SIGINTを受けると、稼働中の全セッションへ ctrl-c を送信して各プロジェクトのコマンドを終了させ、終了を待ってからherdrワークスペースを閉じる(`mode: "herdr"`
|
|
361
|
+
- **一括停止**: SIGTERM/SIGINTを受けると、稼働中の全セッションへ ctrl-c を送信して各プロジェクトのコマンドを終了させ、終了を待ってからherdrワークスペースを閉じる(`mode: "herdr"` でワーカーが作ったタスクタブもワークスペースごと片付く)。もう一度シグナルを送ると強制終了する
|
|
362
|
+
|
|
363
|
+
> ℹ️ herdr はワークスペースを閉じる際、閉じた対象がフォーカスされていなくても別のワークスペースへフォーカスを移す。ディスパッチャーはクローズ直前のフォーカス状態を控えて閉じた後に復元するため、無関係なワークスペースを見ていても表示は勝手に切り替わらない。
|
|
288
364
|
|
|
289
365
|
```bash
|
|
290
366
|
claude-task-worker all --project all
|
|
@@ -312,9 +388,9 @@ claude-task-worker exec-issue --project app-a --epic 100 --label priority-high
|
|
|
312
388
|
|
|
313
389
|
`mode: "herdr"` のときの1タスクの流れ:
|
|
314
390
|
|
|
315
|
-
1. worktree を作成し、`ctw:<プロジェクト名>:#<Issue/PR番号>` ラベルのタブで claude を TUI
|
|
316
|
-
2. herdr が持つ agent ステータスを監視し、`working` → `idle`
|
|
317
|
-
3.
|
|
391
|
+
1. worktree を作成し、`ctw:<プロジェクト名>:#<Issue/PR番号>` ラベルのタブで claude を TUI 起動する(タブを先に作ってからその中で起動するため、ユーザーが見ているタブにペインが割り込むことはない)
|
|
392
|
+
2. herdr が持つ agent ステータスを監視し、`done`(未確認完了)または `working` → `idle` の遷移をタスク完了とみなす。ワーカーのタスクタブは誰も開かないため、完了したタスクは通常 `done` として観測される
|
|
393
|
+
3. 完了したら claude のセッション transcript(`~/.claude/projects/*/<sessionId>.jsonl`)から最終レポートを回収して通知に使い、タブを閉じてラベル・worktree を後片付けする。transcript を引けない場合のみペインの内容にフォールバックする
|
|
318
394
|
|
|
319
395
|
補足:
|
|
320
396
|
|
|
@@ -347,12 +423,14 @@ claude-task-worker exec-issue --project app-a --epic 100 --label priority-high
|
|
|
347
423
|
| `headroom` | 実行されるコマンド |
|
|
348
424
|
|-----------|------------------|
|
|
349
425
|
| `false`(既定) | `claude <引数>` |
|
|
350
|
-
| `true` | `headroom wrap claude -- <引数>` |
|
|
426
|
+
| `true` | `headroom wrap claude --1m --memory --no-tokensave --no-serena -- <引数>` |
|
|
351
427
|
|
|
352
428
|
補足:
|
|
353
429
|
|
|
354
430
|
- `mode` とは独立して組み合わせられる(`mode: "herdr"` の TUI 起動も `headroom wrap claude` になる)
|
|
355
|
-
- claude へ渡す引数はすべて `--` の後ろに置かれる。`headroom wrap claude` 自身も `--port` / `--memory` などのオプションを持ち、`-p` のように衝突しうるフラグは `--` の後ろでないと claude
|
|
431
|
+
- claude へ渡す引数はすべて `--` の後ろに置かれる。`headroom wrap claude` 自身も `--port` / `--memory` などのオプションを持ち、`-p` のように衝突しうるフラグは `--` の後ろでないと claude に届かないため。逆に headroom 自身へのオプションは `--` の前に置く
|
|
432
|
+
- 1M コンテキストウィンドウは `--model` の値へ `[1m]` サフィックスを付けることで解放する(`--model 'sonnet[1m]'` のようになる)。headroom の `--1m` は `ANTHROPIC_MODEL` をセットするだけの実装で、CLI の `--model` が環境変数に勝つため、`--model` を明示するワーカー起動では単体では効かない
|
|
433
|
+
- `--no-tokensave` / `--no-serena` で headroom が既定で登録するコードグラフ系 MCP を止める。コード探索はプラグインの codegraph MCP が担うため機能面の損失はなく、タスク起動のたびに走る再登録・再インデックスと、ユーザーのグローバル設定(`~/.claude.json`)の書き換えを避けられる
|
|
356
434
|
- `headroom: true` で headroom コマンドが PATH に無い場合、ワーカーは起動時にエラー終了する(`mode: "herdr"` と同じく、サイレントに直接起動へフォールバックはしない)
|
|
357
435
|
- `headroom wrap claude` は claude を起動する前に起動バナー(枠線・`ANTHROPIC_BASE_URL=...` など)を stdout へ出力し、これを抑止するオプションは無い。ワーカーは空振りセッション検知(exit 0 かつ無出力を失敗とみなす判定)の前にこのバナーを取り除くため、検知は `headroom: true` でも従来どおり機能する。ただし Slack 通知の本文にはバナーがそのまま含まれる
|
|
358
436
|
|
|
@@ -430,9 +508,30 @@ claude-task-worker exec-issue --project app-a --epic 100 --label priority-high
|
|
|
430
508
|
- 完了後、親Issueに `cc-pr-created` ラベルを付与
|
|
431
509
|
- 完了後、作成されたエピックPR(`cc-epic-<親Issue番号>` ブランチ)に `cc-epic-issue` と `cc-triage-scope` ラベルを付与し、triage-pr のリリースゲート判定に引き継ぐ
|
|
432
510
|
|
|
511
|
+
### create-ui-design
|
|
512
|
+
|
|
513
|
+
`cc-create-ui-design` ラベルが付いたIssueを定期取得し、`/claude-task-worker:create-ui-design` を起動して Pencil デザイン(`.pen` + スナップショットPNG)を作成し、デザインのみのPRを作成する。(デフォルト1分間隔)
|
|
514
|
+
|
|
515
|
+
- `claude-task-worker.json` の `uiDesign.enabled` が `true` の場合のみ起動する(`false` なら1行ログを出して即終了)
|
|
516
|
+
- `cc-ui-design-pr-created` / `cc-ui-design-ready` が付いているIssueは除外
|
|
517
|
+
- デザインPRは `cc-ui-design-<Issue番号>` の固定名ブランチを head とする(後段の `apply-ui-design` が一意に特定するため)
|
|
518
|
+
- 完了後、デザインPRの実在を確認できた場合のみ、PRに `cc-ui-design` と `cc-triage-scope`、Issueに `cc-ui-design-pr-created` を付与する
|
|
519
|
+
- スキルが「デザイン不要」と判定した場合(`cc-ui-design-ready` 付与済み)は完了扱いとし、そのまま実装フェーズへ流す
|
|
520
|
+
- PRの実在を確認できない場合は `cc-need-human-check` を付与してIssueにコメントを残す
|
|
521
|
+
|
|
522
|
+
### apply-ui-design
|
|
523
|
+
|
|
524
|
+
`cc-ui-design-pr-created` ラベルが付いたIssueを定期取得し、デザインPRのマージ後に `/claude-task-worker:apply-ui-design` を起動して Issue description へデザイン参照セクション(`## UIデザイン`)を書き戻す。(デフォルト1分間隔)
|
|
525
|
+
|
|
526
|
+
- `claude-task-worker.json` の `uiDesign.enabled` が `true` の場合のみ起動する
|
|
527
|
+
- `cc-ui-design-ready` / `cc-exec-issue` が付いているIssueは除外
|
|
528
|
+
- preflight でデザインPR(`cc-ui-design-<Issue番号>` を head とするPR)の状態を確認し、`OPEN` の間はスキップしてマージを待つ
|
|
529
|
+
- 未マージのままクローズされた場合・PRが見つからない場合は `cc-need-human-check` を付与してスキップする
|
|
530
|
+
- 完了後、description に `## UIデザイン` セクションと `.pen` パスが載っていることを検証できた場合のみ `cc-ui-design-ready` と `cc-exec-issue` を付与する
|
|
531
|
+
|
|
433
532
|
### all
|
|
434
533
|
|
|
435
|
-
通常ワーカー
|
|
534
|
+
通常ワーカー9つ(exec-issue, fix-review-point, create-issue, update-issue, answer-issue-questions, resolve-conflict, epic-issue, create-ui-design, apply-ui-design)を同時にポーリングする。`--epic` / `--label` オプションでIssue系ワーカーの処理対象を絞り込み可能(どちらも複数指定可)。UIデザイン系2ワーカーは `uiDesign.enabled` が `false` なら起動しない。
|
|
436
535
|
|
|
437
536
|
### yolo
|
|
438
537
|
|
|
@@ -444,7 +543,7 @@ claude-task-worker exec-issue --project app-a --epic 100 --label priority-high
|
|
|
444
543
|
|
|
445
544
|
### install
|
|
446
545
|
|
|
447
|
-
`claude-task-worker` マーケットプレイスの追加・プラグインのインストール・CLI
|
|
546
|
+
`claude-task-worker` マーケットプレイスの追加・プラグインのインストール・CLI本体のグローバルインストール・CodeGraph CLI のインストールを一括で行う。
|
|
448
547
|
|
|
449
548
|
```bash
|
|
450
549
|
npx claude-task-worker install
|
|
@@ -453,12 +552,13 @@ npx claude-task-worker install
|
|
|
453
552
|
- `claude plugin marketplace add getty104/claude-task-worker` — マーケットプレイスの追加(追加済みの場合のエラーはログのみで無視して続行)
|
|
454
553
|
- `claude plugin install claude-task-worker@claude-task-worker` — プラグインのインストール
|
|
455
554
|
- `npm install -g claude-task-worker@latest` — CLI 本体のグローバルインストール
|
|
555
|
+
- `npm install -g @colbymchenry/codegraph@latest` — CodeGraph CLI のインストール
|
|
456
556
|
|
|
457
|
-
いずれかのステップが失敗しても処理は継続し、`[install]`
|
|
557
|
+
いずれかのステップが失敗しても処理は継続し、`[install]` プレフィックス付きでエラー内容がログ出力される(失敗があった場合の終了コードは 1)。
|
|
458
558
|
|
|
459
559
|
### update
|
|
460
560
|
|
|
461
|
-
`claude-task-worker`
|
|
561
|
+
`claude-task-worker` プラグイン/マーケットプレイス・CLI本体・CodeGraph CLI を更新する。
|
|
462
562
|
|
|
463
563
|
```bash
|
|
464
564
|
claude-task-worker update
|
|
@@ -467,8 +567,9 @@ claude-task-worker update
|
|
|
467
567
|
- `claude plugin marketplace update claude-task-worker` — マーケットプレイスの更新
|
|
468
568
|
- `claude plugin update claude-task-worker@claude-task-worker` — プラグインの更新(反映にはセッション再起動が必要)
|
|
469
569
|
- `npm install -g claude-task-worker@latest` — CLI 本体の更新
|
|
570
|
+
- `codegraph upgrade` — CodeGraph CLI の更新(失敗時は `npm install -g @colbymchenry/codegraph@latest` へフォールバック)
|
|
470
571
|
|
|
471
|
-
いずれかのステップが失敗しても処理は継続し、`[update]`
|
|
572
|
+
いずれかのステップが失敗しても処理は継続し、`[update]` プレフィックス付きでエラー内容がログ出力される(失敗があった場合の終了コードは 1)。
|
|
472
573
|
|
|
473
574
|
### version
|
|
474
575
|
|
|
@@ -480,7 +581,7 @@ claude-task-worker --version
|
|
|
480
581
|
claude-task-worker -v
|
|
481
582
|
```
|
|
482
583
|
|
|
483
|
-
`package.json` の `version` を出力する(例: `0.
|
|
584
|
+
`package.json` の `version` を出力する(例: `0.34.0`)。
|
|
484
585
|
|
|
485
586
|
## 設定ファイル
|
|
486
587
|
|
|
@@ -489,6 +590,7 @@ claude-task-worker -v
|
|
|
489
590
|
| キー | 型 | デフォルト | 説明 |
|
|
490
591
|
|---|---|---|---|
|
|
491
592
|
| `fixReviewPointCallbackCommentMessage` | string | - | fix-review-point 完了時にPRへ投稿するコメント(未設定の場合は投稿しない) |
|
|
593
|
+
| `uiDesign` | object | `{ "enabled": false, "designDir": "designs" }` | UIデザイン先行ワークフローの設定(詳細は「[UIデザイン先行ワークフロー](#uiデザイン先行ワークフロー)」) |
|
|
492
594
|
| `workers` | object | `{}` | ワーカーごとに Claude CLI に渡すスキル、`--model` / `--effort`、ポーリング間隔、クールダウン時間、最大同時実行数を上書きする設定(詳細は下記) |
|
|
493
595
|
|
|
494
596
|
### ワーカーごとの設定
|
|
@@ -507,6 +609,8 @@ claude-task-worker -v
|
|
|
507
609
|
| `resolve-conflict` | `/claude-task-worker:resolve-pr-conflict` | `sonnet` | `high` | 60 | 0 | 1 |
|
|
508
610
|
| `check-dependabot` | `/claude-task-worker:check-dependabot` | `sonnet` | `high` | 3600 | 0 | 1 |
|
|
509
611
|
| `epic-issue` | `/claude-task-worker:create-epic-pr` | `sonnet` | `high` | 300 | 0 | 1 |
|
|
612
|
+
| `create-ui-design` | `/claude-task-worker:create-ui-design` | `sonnet` | `high` | 60 | 0 | 1 |
|
|
613
|
+
| `apply-ui-design` | `/claude-task-worker:apply-ui-design` | `sonnet` | `high` | 60 | 0 | 1 |
|
|
510
614
|
|
|
511
615
|
各フィールドの値:
|
|
512
616
|
|
|
@@ -543,13 +647,27 @@ claude-task-worker all
|
|
|
543
647
|
|
|
544
648
|
通知にはClaude APIの使用状況(5時間/7日間の利用率とリセット時刻)も含まれる。未設定の場合、通知は送信されない。
|
|
545
649
|
|
|
650
|
+
使用状況を組み立てる際、[RunCat Neo](https://kyome.io/runcat/) 用のスナップショットを `~/.claude/runcat-usage.json`(`RUNCAT_OUT_FILE` で変更可)へ一時ファイル + rename で原子的に書き出す。Webhook 未設定でも通知が no-op になるだけでスナップショットは更新される。使用状況の取得自体は `/tmp/claude-usage-cache.json` の360秒キャッシュを挟むため、値は最大6分古くなりうる。
|
|
651
|
+
|
|
546
652
|
## プロセス管理
|
|
547
653
|
|
|
548
654
|
実行中のタスクはリアルタイムのステータステーブルで表示される。
|
|
549
655
|
|
|
550
656
|
- タスクID・タイトル・ステータス(running/completed/failed)・開始時刻・経過時間を表示
|
|
657
|
+
- `mode: "herdr"` では実行中の行に agent ステータスが併記される(`running:working` / `running:blocked` など)
|
|
551
658
|
- 同一Issue/PRの重複実行を自動防止
|
|
552
|
-
- SIGTERM/SIGINTで全子プロセスをgraceful shutdown
|
|
659
|
+
- SIGTERM/SIGINTで全子プロセスをgraceful shutdown(もう一度送ると強制終了し、ラベル・worktree の後片付けを試みる)
|
|
660
|
+
- 前回の異常終了で残った worktree はワーカー起動時に自動回収される(実行中タスク・対話セッションが掴んでいる worktree は保護される)
|
|
661
|
+
|
|
662
|
+
### タスク実行のガード
|
|
663
|
+
|
|
664
|
+
ワーカーは応答するユーザーがいない状態でスキルを起動するため、処理が未完のままセッションが終了してラベルだけ進む事故を防ぐガードを持つ。
|
|
665
|
+
|
|
666
|
+
- **バックグラウンド実行の無効化**: `CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1` を全タスクの環境変数として注入し、Bash の `run_in_background` やサブエージェントの自動バックグラウンド化を止める
|
|
667
|
+
- **ツールの無効化**: `--disallowedTools` で `Monitor` / `ScheduleWakeup` / `AskUserQuestion` / `EnterPlanMode` / `Cron*` / `RemoteTrigger` / `EnterWorktree` を無効化する(後続ウェイクアップ前提のもの、応答者が必要なもの、ワーカーの worktree 管理と競合するもの)
|
|
668
|
+
- **自律実行原則の注入**: `--append-system-prompt` で「ユーザーに質問しない・全ステップを完遂してから終了する・曖昧なら安全側を選ぶ・サブエージェントの完了報告を検証する」および CodeGraph 優先のコード探索方針を注入する
|
|
669
|
+
- **完了検証**: exec-issue / epic-issue は PR の実在(または Issue のクローズ)を確認できるまで `cc-pr-created` を付けず、確認できない場合は `cc-need-human-check` を付けて Issue にコメントを残す
|
|
670
|
+
- **空振り検知**: 正常終了しても出力が空のセッションは失敗として分類し、失敗通知(stderr の末尾を含む)を送る
|
|
553
671
|
|
|
554
672
|
## 開発
|
|
555
673
|
|
|
@@ -557,6 +675,7 @@ claude-task-worker all
|
|
|
557
675
|
npm install
|
|
558
676
|
npm run build # 型チェック(tsc --noEmit)+ esbuild で dist/index.js にバンドル
|
|
559
677
|
npm run dev # 型チェックの watch モード
|
|
678
|
+
npm test # ユニットテスト(node --experimental-strip-types --test)
|
|
560
679
|
npm run lint # ESLint
|
|
561
680
|
npm run lint:fix # ESLint(自動修正)
|
|
562
681
|
npm run format # Prettier で整形
|
package/dist/index.js
CHANGED
|
@@ -234,15 +234,16 @@ __export(herdr_exports, {
|
|
|
234
234
|
HerdrError: () => HerdrError,
|
|
235
235
|
HerdrUnavailableError: () => HerdrUnavailableError,
|
|
236
236
|
agentGet: () => agentGet,
|
|
237
|
-
agentStart: () => agentStart,
|
|
238
237
|
checkHerdrAvailable: () => checkHerdrAvailable,
|
|
239
238
|
getCurrentWorkspaceId: () => getCurrentWorkspaceId,
|
|
239
|
+
launchAgentInPane: () => launchAgentInPane,
|
|
240
240
|
paneClose: () => paneClose,
|
|
241
241
|
paneGet: () => paneGet,
|
|
242
242
|
paneProcessInfo: () => paneProcessInfo,
|
|
243
243
|
paneRead: () => paneRead,
|
|
244
244
|
paneSendKeys: () => paneSendKeys,
|
|
245
245
|
paneSendText: () => paneSendText,
|
|
246
|
+
shellQuoteArgv: () => shellQuoteArgv,
|
|
246
247
|
tabClose: () => tabClose,
|
|
247
248
|
tabCreate: () => tabCreate,
|
|
248
249
|
tabList: () => tabList,
|
|
@@ -395,32 +396,12 @@ async function workspaceClose(workspaceId) {
|
|
|
395
396
|
async function workspaceFocus(workspaceId) {
|
|
396
397
|
await execHerdr(["workspace", "focus", workspaceId]);
|
|
397
398
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
env
|
|
405
|
-
}) {
|
|
406
|
-
const result = await execHerdr([
|
|
407
|
-
"agent",
|
|
408
|
-
"start",
|
|
409
|
-
name,
|
|
410
|
-
...workspaceId ? ["--workspace", workspaceId] : [],
|
|
411
|
-
...targetTabId ? ["--tab", targetTabId] : [],
|
|
412
|
-
...cwdArgs(cwd),
|
|
413
|
-
...envArgs(env),
|
|
414
|
-
"--no-focus",
|
|
415
|
-
"--",
|
|
416
|
-
...argv
|
|
417
|
-
]);
|
|
418
|
-
const paneId = result?.agent?.pane_id;
|
|
419
|
-
const tabId = result?.agent?.tab_id;
|
|
420
|
-
if (!paneId || !tabId) {
|
|
421
|
-
throw new Error("Failed to start agent: invalid response structure from herdr");
|
|
422
|
-
}
|
|
423
|
-
return { paneId, tabId };
|
|
399
|
+
function shellQuoteArgv(argv) {
|
|
400
|
+
return argv.map((arg) => `'${arg.replace(/'/g, `'\\''`)}'`).join(" ");
|
|
401
|
+
}
|
|
402
|
+
async function launchAgentInPane(paneId, argv) {
|
|
403
|
+
await paneSendText(paneId, shellQuoteArgv(argv));
|
|
404
|
+
await paneSendKeys(paneId, "enter");
|
|
424
405
|
}
|
|
425
406
|
function toAgentStatus(value) {
|
|
426
407
|
return value === "working" || value === "idle" || value === "blocked" || value === "done" ? value : "unknown";
|
|
@@ -551,10 +532,14 @@ var init_herdr = __esm({
|
|
|
551
532
|
// src/herdr-runner.ts
|
|
552
533
|
var herdr_runner_exports = {};
|
|
553
534
|
__export(herdr_runner_exports, {
|
|
535
|
+
AGENT_DETECT_POLL_INTERVAL_MS: () => AGENT_DETECT_POLL_INTERVAL_MS,
|
|
536
|
+
AGENT_DETECT_TIMEOUT_MS: () => AGENT_DETECT_TIMEOUT_MS,
|
|
554
537
|
AGENT_POLL_INTERVAL_MS: () => AGENT_POLL_INTERVAL_MS,
|
|
555
538
|
CLAUDE_EXIT_POLL_INTERVAL_MS: () => CLAUDE_EXIT_POLL_INTERVAL_MS,
|
|
556
539
|
CLAUDE_EXIT_TIMEOUT_MS: () => CLAUDE_EXIT_TIMEOUT_MS,
|
|
557
540
|
PANE_OUTPUT_LINES: () => PANE_OUTPUT_LINES,
|
|
541
|
+
PANE_READY_POLL_INTERVAL_MS: () => PANE_READY_POLL_INTERVAL_MS,
|
|
542
|
+
PANE_READY_TIMEOUT_MS: () => PANE_READY_TIMEOUT_MS,
|
|
558
543
|
buildHerdrTaskResult: () => buildHerdrTaskResult,
|
|
559
544
|
createCompletionTracker: () => createCompletionTracker,
|
|
560
545
|
observeAgentStatus: () => observeAgentStatus,
|
|
@@ -608,23 +593,70 @@ async function startHerdrTask({
|
|
|
608
593
|
argv,
|
|
609
594
|
env,
|
|
610
595
|
workspaceId,
|
|
611
|
-
herdr
|
|
596
|
+
herdr,
|
|
597
|
+
timing
|
|
612
598
|
}) {
|
|
613
599
|
const mod = herdr ?? await loadHerdr();
|
|
614
|
-
const { tabId, paneId
|
|
615
|
-
let paneId;
|
|
600
|
+
const { tabId, paneId } = await mod.tabCreate({ label, cwd, workspaceId, env });
|
|
616
601
|
try {
|
|
617
|
-
|
|
602
|
+
const ready = await waitForPaneReady(paneId, mod, {
|
|
603
|
+
timeoutMs: timing?.paneReadyTimeoutMs,
|
|
604
|
+
pollIntervalMs: timing?.paneReadyPollIntervalMs
|
|
605
|
+
});
|
|
606
|
+
if (!ready) {
|
|
607
|
+
console.warn(`[herdr-runner] pane ${paneId} produced no prompt before the timeout, launching anyway`);
|
|
608
|
+
}
|
|
609
|
+
await mod.launchAgentInPane(paneId, argv);
|
|
610
|
+
const detected = await waitForAgentDetected(paneId, mod, {
|
|
611
|
+
timeoutMs: timing?.agentDetectTimeoutMs,
|
|
612
|
+
pollIntervalMs: timing?.agentDetectPollIntervalMs
|
|
613
|
+
});
|
|
614
|
+
if (!detected) {
|
|
615
|
+
throw new Error(
|
|
616
|
+
`claude was not detected in pane ${paneId} after launch (it may have failed to start; e.g. a skill preamble command failed)`
|
|
617
|
+
);
|
|
618
|
+
}
|
|
618
619
|
} catch (err) {
|
|
619
620
|
await mod.tabClose(tabId).catch(() => {
|
|
620
621
|
});
|
|
621
622
|
throw err;
|
|
622
623
|
}
|
|
623
|
-
await mod.paneClose(shellPaneId).catch((err) => {
|
|
624
|
-
console.error(`[herdr-runner] failed to close the placeholder shell pane ${shellPaneId}: ${err}`);
|
|
625
|
-
});
|
|
626
624
|
return { paneId, tabId };
|
|
627
625
|
}
|
|
626
|
+
async function waitForPaneReady(paneId, mod, options) {
|
|
627
|
+
const timeoutMs = options?.timeoutMs ?? PANE_READY_TIMEOUT_MS;
|
|
628
|
+
const pollIntervalMs = options?.pollIntervalMs ?? PANE_READY_POLL_INTERVAL_MS;
|
|
629
|
+
const deadline = Date.now() + timeoutMs;
|
|
630
|
+
for (; ; ) {
|
|
631
|
+
let content = "";
|
|
632
|
+
try {
|
|
633
|
+
content = await mod.paneRead(paneId, { source: "visible" });
|
|
634
|
+
} catch (err) {
|
|
635
|
+
console.error(`[herdr-runner] failed to read pane ${paneId} while waiting for its prompt: ${err}`);
|
|
636
|
+
}
|
|
637
|
+
if (content.trim() !== "") return true;
|
|
638
|
+
if (Date.now() >= deadline) return false;
|
|
639
|
+
await sleep(pollIntervalMs);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
async function waitForAgentDetected(paneId, mod, options) {
|
|
643
|
+
const timeoutMs = options?.timeoutMs ?? AGENT_DETECT_TIMEOUT_MS;
|
|
644
|
+
const pollIntervalMs = options?.pollIntervalMs ?? AGENT_DETECT_POLL_INTERVAL_MS;
|
|
645
|
+
const deadline = Date.now() + timeoutMs;
|
|
646
|
+
for (; ; ) {
|
|
647
|
+
try {
|
|
648
|
+
await mod.agentGet(paneId);
|
|
649
|
+
return true;
|
|
650
|
+
} catch (err) {
|
|
651
|
+
if (err instanceof mod.HerdrError && err.code === "pane_not_found") return false;
|
|
652
|
+
if (!(err instanceof mod.HerdrError && err.code === "agent_not_found")) {
|
|
653
|
+
console.error(`[herdr-runner] unexpected error while waiting for agent detection on pane ${paneId}: ${err}`);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (Date.now() >= deadline) return false;
|
|
657
|
+
await sleep(pollIntervalMs);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
628
660
|
async function waitForHerdrTask(paneId, options) {
|
|
629
661
|
const mod = options?.herdr ?? await loadHerdr();
|
|
630
662
|
const pollIntervalMs = options?.pollIntervalMs ?? AGENT_POLL_INTERVAL_MS;
|
|
@@ -640,10 +672,10 @@ async function waitForHerdrTask(paneId, options) {
|
|
|
640
672
|
status = agent.agentStatus;
|
|
641
673
|
if (agent.sessionId) sessionId = agent.sessionId;
|
|
642
674
|
} catch (err) {
|
|
643
|
-
if (err instanceof mod.HerdrError && err.code === "pane_not_found") {
|
|
675
|
+
if (err instanceof mod.HerdrError && (err.code === "pane_not_found" || err.code === "agent_not_found")) {
|
|
644
676
|
return {
|
|
645
677
|
status: "failed",
|
|
646
|
-
output: "[worker] the claude
|
|
678
|
+
output: "[worker] the claude agent disappeared before the task completed (claude died or the tab was closed)"
|
|
647
679
|
};
|
|
648
680
|
}
|
|
649
681
|
console.error(`[herdr-runner] failed to read agent status for pane ${paneId}: ${err}`);
|
|
@@ -672,15 +704,17 @@ async function readPaneOutput(paneId, mod) {
|
|
|
672
704
|
return "";
|
|
673
705
|
}
|
|
674
706
|
}
|
|
675
|
-
async function
|
|
707
|
+
async function waitForAgentGone(paneId, mod, options) {
|
|
676
708
|
const timeoutMs = options?.timeoutMs ?? CLAUDE_EXIT_TIMEOUT_MS;
|
|
677
709
|
const pollIntervalMs = options?.pollIntervalMs ?? CLAUDE_EXIT_POLL_INTERVAL_MS;
|
|
678
710
|
const deadline = Date.now() + timeoutMs;
|
|
679
711
|
for (; ; ) {
|
|
680
712
|
try {
|
|
681
|
-
await mod.
|
|
713
|
+
await mod.agentGet(paneId);
|
|
682
714
|
} catch (err) {
|
|
683
|
-
if (err instanceof mod.HerdrError && err.code === "pane_not_found")
|
|
715
|
+
if (err instanceof mod.HerdrError && (err.code === "agent_not_found" || err.code === "pane_not_found")) {
|
|
716
|
+
return true;
|
|
717
|
+
}
|
|
684
718
|
}
|
|
685
719
|
if (Date.now() >= deadline) return false;
|
|
686
720
|
await sleep(pollIntervalMs);
|
|
@@ -690,7 +724,7 @@ async function stopHerdrTask(task, herdr, options) {
|
|
|
690
724
|
const mod = herdr ?? await loadHerdr();
|
|
691
725
|
try {
|
|
692
726
|
await mod.paneSendKeys(task.paneId, "ctrl+c", "ctrl+c");
|
|
693
|
-
const exited = await
|
|
727
|
+
const exited = await waitForAgentGone(task.paneId, mod, {
|
|
694
728
|
timeoutMs: options?.exitTimeoutMs,
|
|
695
729
|
pollIntervalMs: options?.exitPollIntervalMs
|
|
696
730
|
});
|
|
@@ -712,7 +746,7 @@ async function stopHerdrTask(task, herdr, options) {
|
|
|
712
746
|
function sleep(ms) {
|
|
713
747
|
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
714
748
|
}
|
|
715
|
-
var AGENT_POLL_INTERVAL_MS, PANE_OUTPUT_LINES, CLAUDE_EXIT_TIMEOUT_MS, CLAUDE_EXIT_POLL_INTERVAL_MS;
|
|
749
|
+
var AGENT_POLL_INTERVAL_MS, PANE_OUTPUT_LINES, PANE_READY_TIMEOUT_MS, PANE_READY_POLL_INTERVAL_MS, AGENT_DETECT_TIMEOUT_MS, AGENT_DETECT_POLL_INTERVAL_MS, CLAUDE_EXIT_TIMEOUT_MS, CLAUDE_EXIT_POLL_INTERVAL_MS;
|
|
716
750
|
var init_herdr_runner = __esm({
|
|
717
751
|
"src/herdr-runner.ts"() {
|
|
718
752
|
"use strict";
|
|
@@ -720,6 +754,10 @@ var init_herdr_runner = __esm({
|
|
|
720
754
|
init_transcript();
|
|
721
755
|
AGENT_POLL_INTERVAL_MS = 3 * 1e3;
|
|
722
756
|
PANE_OUTPUT_LINES = 300;
|
|
757
|
+
PANE_READY_TIMEOUT_MS = 30 * 1e3;
|
|
758
|
+
PANE_READY_POLL_INTERVAL_MS = 200;
|
|
759
|
+
AGENT_DETECT_TIMEOUT_MS = 120 * 1e3;
|
|
760
|
+
AGENT_DETECT_POLL_INTERVAL_MS = 500;
|
|
723
761
|
CLAUDE_EXIT_TIMEOUT_MS = 15 * 1e3;
|
|
724
762
|
CLAUDE_EXIT_POLL_INTERVAL_MS = 200;
|
|
725
763
|
}
|
|
@@ -772,8 +810,8 @@ var init_run_command = __esm({
|
|
|
772
810
|
var dispatcher_exports = {};
|
|
773
811
|
__export(dispatcher_exports, {
|
|
774
812
|
LABEL_PREFIX: () => LABEL_PREFIX,
|
|
775
|
-
PANE_READY_POLL_INTERVAL_MS: () =>
|
|
776
|
-
PANE_READY_TIMEOUT_MS: () =>
|
|
813
|
+
PANE_READY_POLL_INTERVAL_MS: () => PANE_READY_POLL_INTERVAL_MS2,
|
|
814
|
+
PANE_READY_TIMEOUT_MS: () => PANE_READY_TIMEOUT_MS2,
|
|
777
815
|
POLL_INTERVAL_MS: () => POLL_INTERVAL_MS,
|
|
778
816
|
SEND_MAX_ATTEMPTS: () => SEND_MAX_ATTEMPTS,
|
|
779
817
|
SHUTDOWN_RETRY_TIMEOUT_MS: () => SHUTDOWN_RETRY_TIMEOUT_MS,
|
|
@@ -793,7 +831,7 @@ __export(dispatcher_exports, {
|
|
|
793
831
|
runDispatcher: () => runDispatcher,
|
|
794
832
|
shutdownDispatcher: () => shutdownDispatcher,
|
|
795
833
|
startWorkerInPane: () => startWorkerInPane,
|
|
796
|
-
waitForPaneReady: () =>
|
|
834
|
+
waitForPaneReady: () => waitForPaneReady2,
|
|
797
835
|
waitForWorkerStartup: () => waitForWorkerStartup,
|
|
798
836
|
workspaceLabelFor: () => workspaceLabelFor
|
|
799
837
|
});
|
|
@@ -834,9 +872,9 @@ function isWorkerProcess(process2) {
|
|
|
834
872
|
function isShellProcess(process2) {
|
|
835
873
|
return SHELL_NAME_PATTERN.test(process2.name ?? "") || SHELL_NAME_PATTERN.test(process2.cmdline ?? "");
|
|
836
874
|
}
|
|
837
|
-
async function
|
|
838
|
-
const timeoutMs = options?.timeoutMs ??
|
|
839
|
-
const pollIntervalMs = options?.pollIntervalMs ??
|
|
875
|
+
async function waitForPaneReady2(paneId, herdr, options) {
|
|
876
|
+
const timeoutMs = options?.timeoutMs ?? PANE_READY_TIMEOUT_MS2;
|
|
877
|
+
const pollIntervalMs = options?.pollIntervalMs ?? PANE_READY_POLL_INTERVAL_MS2;
|
|
840
878
|
const deadline = Date.now() + timeoutMs;
|
|
841
879
|
for (; ; ) {
|
|
842
880
|
const content = await herdr.paneRead(paneId, { source: "visible" });
|
|
@@ -860,7 +898,7 @@ async function waitForWorkerStartup(paneId, herdr, options) {
|
|
|
860
898
|
async function startWorkerInPane(paneId, forwardedCommand, herdr, options) {
|
|
861
899
|
const maxAttempts = options?.sendMaxAttempts ?? SEND_MAX_ATTEMPTS;
|
|
862
900
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
863
|
-
const ready = await
|
|
901
|
+
const ready = await waitForPaneReady2(paneId, herdr, {
|
|
864
902
|
timeoutMs: options?.paneReadyTimeoutMs,
|
|
865
903
|
pollIntervalMs: options?.paneReadyPollIntervalMs
|
|
866
904
|
});
|
|
@@ -1162,15 +1200,15 @@ function createDispatcherShutdownHandler(shutdown2) {
|
|
|
1162
1200
|
};
|
|
1163
1201
|
return { handle, isShuttingDown: () => shuttingDown2 };
|
|
1164
1202
|
}
|
|
1165
|
-
var getDisplayWidth2, truncateToWidth2, padToWidth2, POLL_INTERVAL_MS, SHUTDOWN_TIMEOUT_MS,
|
|
1203
|
+
var getDisplayWidth2, truncateToWidth2, padToWidth2, POLL_INTERVAL_MS, SHUTDOWN_TIMEOUT_MS, PANE_READY_TIMEOUT_MS2, PANE_READY_POLL_INTERVAL_MS2, WORKER_STARTUP_TIMEOUT_MS, WORKER_STARTUP_POLL_INTERVAL_MS, SEND_MAX_ATTEMPTS, LABEL_PREFIX, SHELL_NAME_PATTERN, SHUTDOWN_RETRY_TIMEOUT_MS, CTRL_C_KEY, shutdownPromise;
|
|
1166
1204
|
var init_dispatcher = __esm({
|
|
1167
1205
|
async "src/dispatcher.ts"() {
|
|
1168
1206
|
"use strict";
|
|
1169
1207
|
({ getDisplayWidth: getDisplayWidth2, truncateToWidth: truncateToWidth2, padToWidth: padToWidth2 } = await loadTable());
|
|
1170
1208
|
POLL_INTERVAL_MS = 7 * 1e3;
|
|
1171
1209
|
SHUTDOWN_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
1172
|
-
|
|
1173
|
-
|
|
1210
|
+
PANE_READY_TIMEOUT_MS2 = 30 * 1e3;
|
|
1211
|
+
PANE_READY_POLL_INTERVAL_MS2 = 200;
|
|
1174
1212
|
WORKER_STARTUP_TIMEOUT_MS = 30 * 1e3;
|
|
1175
1213
|
WORKER_STARTUP_POLL_INTERVAL_MS = 500;
|
|
1176
1214
|
SEND_MAX_ATTEMPTS = 3;
|
|
@@ -1291,6 +1329,28 @@ async function findPrNumberByHeadRef(headRefName, state = "open") {
|
|
|
1291
1329
|
const prs = JSON.parse(output);
|
|
1292
1330
|
return prs.length > 0 ? prs[0].number : null;
|
|
1293
1331
|
}
|
|
1332
|
+
async function findPrStateByHeadRef(headRefName) {
|
|
1333
|
+
const output = await execGh([
|
|
1334
|
+
"pr",
|
|
1335
|
+
"list",
|
|
1336
|
+
"--state",
|
|
1337
|
+
"all",
|
|
1338
|
+
"--head",
|
|
1339
|
+
headRefName,
|
|
1340
|
+
"--json",
|
|
1341
|
+
"number,state,mergedAt",
|
|
1342
|
+
"--limit",
|
|
1343
|
+
"1"
|
|
1344
|
+
]);
|
|
1345
|
+
const prs = JSON.parse(output);
|
|
1346
|
+
if (prs.length === 0) return null;
|
|
1347
|
+
return { number: prs[0].number, state: prs[0].state, mergedAt: prs[0].mergedAt ?? null };
|
|
1348
|
+
}
|
|
1349
|
+
async function getIssueBody(issueNumber) {
|
|
1350
|
+
const output = await execGh(["issue", "view", String(issueNumber), "--json", "body"]);
|
|
1351
|
+
const parsed = JSON.parse(output);
|
|
1352
|
+
return typeof parsed?.body === "string" ? parsed.body : "";
|
|
1353
|
+
}
|
|
1294
1354
|
async function getIssueState(issueNumber) {
|
|
1295
1355
|
const output = await execGh(["issue", "view", String(issueNumber), "--json", "state"]);
|
|
1296
1356
|
const parsed = JSON.parse(output);
|
|
@@ -1531,7 +1591,11 @@ function buildClaudeEnv(mode) {
|
|
|
1531
1591
|
|
|
1532
1592
|
// src/config.ts
|
|
1533
1593
|
import { readFileSync } from "node:fs";
|
|
1534
|
-
import { join } from "node:path";
|
|
1594
|
+
import { isAbsolute, join, normalize, sep as SEP } from "node:path";
|
|
1595
|
+
var DEFAULT_UI_DESIGN_CONFIG = {
|
|
1596
|
+
enabled: false,
|
|
1597
|
+
designDir: "designs"
|
|
1598
|
+
};
|
|
1535
1599
|
var DEFAULT_WORKER_CONFIG = {
|
|
1536
1600
|
skill: "",
|
|
1537
1601
|
model: "sonnet",
|
|
@@ -1620,10 +1684,27 @@ var WORKER_DEFAULTS = {
|
|
|
1620
1684
|
pollingIntervalSeconds: 300,
|
|
1621
1685
|
cooldownSeconds: 0,
|
|
1622
1686
|
maxConcurrentTasks: 1
|
|
1687
|
+
},
|
|
1688
|
+
"create-ui-design": {
|
|
1689
|
+
skill: "/claude-task-worker:create-ui-design",
|
|
1690
|
+
model: "sonnet",
|
|
1691
|
+
effort: "high",
|
|
1692
|
+
pollingIntervalSeconds: 60,
|
|
1693
|
+
cooldownSeconds: 0,
|
|
1694
|
+
maxConcurrentTasks: 1
|
|
1695
|
+
},
|
|
1696
|
+
"apply-ui-design": {
|
|
1697
|
+
skill: "/claude-task-worker:apply-ui-design",
|
|
1698
|
+
model: "sonnet",
|
|
1699
|
+
effort: "high",
|
|
1700
|
+
pollingIntervalSeconds: 300,
|
|
1701
|
+
cooldownSeconds: 0,
|
|
1702
|
+
maxConcurrentTasks: 1
|
|
1623
1703
|
}
|
|
1624
1704
|
};
|
|
1625
1705
|
var DEFAULT_CONFIG = {
|
|
1626
1706
|
fixReviewPointCallbackCommentMessage: "",
|
|
1707
|
+
uiDesign: { ...DEFAULT_UI_DESIGN_CONFIG },
|
|
1627
1708
|
workers: {}
|
|
1628
1709
|
};
|
|
1629
1710
|
var CONFIG_PATH = join(process.cwd(), "claude-task-worker.json");
|
|
@@ -1691,6 +1772,35 @@ function parseWorkerEntry(name, val) {
|
|
|
1691
1772
|
}
|
|
1692
1773
|
return result;
|
|
1693
1774
|
}
|
|
1775
|
+
function parseUiDesignEntry(val) {
|
|
1776
|
+
const result = { ...DEFAULT_UI_DESIGN_CONFIG };
|
|
1777
|
+
if (typeof val !== "object" || val === null || Array.isArray(val)) {
|
|
1778
|
+
console.warn(`[config] invalid uiDesign: expected object, using defaults`);
|
|
1779
|
+
return result;
|
|
1780
|
+
}
|
|
1781
|
+
const entry = val;
|
|
1782
|
+
if ("enabled" in entry) {
|
|
1783
|
+
if (typeof entry.enabled === "boolean") {
|
|
1784
|
+
result.enabled = entry.enabled;
|
|
1785
|
+
} else {
|
|
1786
|
+
console.warn(
|
|
1787
|
+
`[config] invalid uiDesign.enabled: ${String(entry.enabled)}, using default ${DEFAULT_UI_DESIGN_CONFIG.enabled}`
|
|
1788
|
+
);
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
if ("designDir" in entry) {
|
|
1792
|
+
const normalized = typeof entry.designDir === "string" && entry.designDir.length > 0 ? normalize(entry.designDir) : null;
|
|
1793
|
+
const isContained = normalized !== null && !isAbsolute(normalized) && normalized !== ".." && !normalized.startsWith(`..${SEP}`);
|
|
1794
|
+
if (isContained) {
|
|
1795
|
+
result.designDir = normalized;
|
|
1796
|
+
} else {
|
|
1797
|
+
console.warn(
|
|
1798
|
+
`[config] invalid uiDesign.designDir: ${String(entry.designDir)}, using default ${DEFAULT_UI_DESIGN_CONFIG.designDir}`
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
return result;
|
|
1803
|
+
}
|
|
1694
1804
|
function loadConfig() {
|
|
1695
1805
|
const configPath = CONFIG_PATH;
|
|
1696
1806
|
let raw;
|
|
@@ -1698,17 +1808,20 @@ function loadConfig() {
|
|
|
1698
1808
|
raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
1699
1809
|
} catch (err) {
|
|
1700
1810
|
if (err.code === "ENOENT") {
|
|
1701
|
-
return { ...DEFAULT_CONFIG, workers: {} };
|
|
1811
|
+
return { ...DEFAULT_CONFIG, uiDesign: { ...DEFAULT_UI_DESIGN_CONFIG }, workers: {} };
|
|
1702
1812
|
}
|
|
1703
1813
|
throw err;
|
|
1704
1814
|
}
|
|
1705
|
-
const result = { ...DEFAULT_CONFIG, workers: {} };
|
|
1815
|
+
const result = { ...DEFAULT_CONFIG, uiDesign: { ...DEFAULT_UI_DESIGN_CONFIG }, workers: {} };
|
|
1706
1816
|
if ("fixReviewPointCallbackCommentMessage" in raw) {
|
|
1707
1817
|
const val = raw["fixReviewPointCallbackCommentMessage"];
|
|
1708
1818
|
if (typeof val === "string") {
|
|
1709
1819
|
result.fixReviewPointCallbackCommentMessage = val;
|
|
1710
1820
|
}
|
|
1711
1821
|
}
|
|
1822
|
+
if ("uiDesign" in raw) {
|
|
1823
|
+
result.uiDesign = parseUiDesignEntry(raw["uiDesign"]);
|
|
1824
|
+
}
|
|
1712
1825
|
if ("workers" in raw) {
|
|
1713
1826
|
const workers = raw["workers"];
|
|
1714
1827
|
if (typeof workers !== "object" || workers === null || Array.isArray(workers)) {
|
|
@@ -1726,6 +1839,14 @@ function getWorkerConfig(workerName) {
|
|
|
1726
1839
|
const config = loadConfig();
|
|
1727
1840
|
return config.workers[workerName] ?? { ...defaultsFor(workerName) };
|
|
1728
1841
|
}
|
|
1842
|
+
function getUiDesignConfig() {
|
|
1843
|
+
try {
|
|
1844
|
+
return loadConfig().uiDesign;
|
|
1845
|
+
} catch (err) {
|
|
1846
|
+
console.warn(`[config] failed to load uiDesign config, using defaults: ${err}`);
|
|
1847
|
+
return { ...DEFAULT_UI_DESIGN_CONFIG };
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1729
1850
|
|
|
1730
1851
|
// src/git.ts
|
|
1731
1852
|
import { execSync, execFile } from "node:child_process";
|
|
@@ -1779,7 +1900,7 @@ init_task_result();
|
|
|
1779
1900
|
// src/user-config.ts
|
|
1780
1901
|
import { readFileSync as readFileSync2, statSync } from "node:fs";
|
|
1781
1902
|
import { homedir } from "node:os";
|
|
1782
|
-
import { isAbsolute, join as join2, resolve } from "node:path";
|
|
1903
|
+
import { isAbsolute as isAbsolute2, join as join2, resolve } from "node:path";
|
|
1783
1904
|
var RESERVED_ALL = "all";
|
|
1784
1905
|
var DEFAULT_RUN_MODE = "default";
|
|
1785
1906
|
var DEFAULT_HEADROOM = false;
|
|
@@ -1876,7 +1997,7 @@ function loadUserConfig() {
|
|
|
1876
1997
|
if (name === "__proto__") {
|
|
1877
1998
|
throw new UserConfigError(`"__proto__" cannot be used as a key in "projects": ${path}`);
|
|
1878
1999
|
}
|
|
1879
|
-
if (typeof value !== "string" || !
|
|
2000
|
+
if (typeof value !== "string" || !isAbsolute2(value)) {
|
|
1880
2001
|
console.warn(`[config] invalid projects.${name}: expected an absolute path, skipping`);
|
|
1881
2002
|
continue;
|
|
1882
2003
|
}
|
|
@@ -3231,13 +3352,238 @@ var epicIssueWorker = (opts = {}) => createIssuePollingWorker({
|
|
|
3231
3352
|
}
|
|
3232
3353
|
})();
|
|
3233
3354
|
|
|
3355
|
+
// src/workers/ui-design.ts
|
|
3356
|
+
var DESIGN_REFERENCE_HEADING = "## UI\u30C7\u30B6\u30A4\u30F3";
|
|
3357
|
+
function designBranchName(issueNumber) {
|
|
3358
|
+
return `cc-ui-design-${issueNumber}`;
|
|
3359
|
+
}
|
|
3360
|
+
var DESIGN_REFERENCE_HEADING_LINE = /^## UIデザイン[ \t]*$/m;
|
|
3361
|
+
var DESIGN_FILE_LINE = /^-\s*デザインファイル:\s*`([^`]+)`/m;
|
|
3362
|
+
function extractDesignSection(body) {
|
|
3363
|
+
const headingMatch = DESIGN_REFERENCE_HEADING_LINE.exec(body);
|
|
3364
|
+
if (headingMatch === null) return null;
|
|
3365
|
+
const rest = body.slice(headingMatch.index + headingMatch[0].length);
|
|
3366
|
+
const nextHeadingMatch = /^## /m.exec(rest);
|
|
3367
|
+
return nextHeadingMatch === null ? rest : rest.slice(0, nextHeadingMatch.index);
|
|
3368
|
+
}
|
|
3369
|
+
function extractDesignFilePath(body) {
|
|
3370
|
+
const section = extractDesignSection(body);
|
|
3371
|
+
if (section === null) return null;
|
|
3372
|
+
const match = DESIGN_FILE_LINE.exec(section);
|
|
3373
|
+
if (match === null) return null;
|
|
3374
|
+
const path = match[1].trim();
|
|
3375
|
+
if (path.length === 0 || path.includes("<") || path.includes(">") || !path.endsWith(".pen")) return null;
|
|
3376
|
+
return path;
|
|
3377
|
+
}
|
|
3378
|
+
function classifyDesignPr(pr) {
|
|
3379
|
+
if (pr === null) return "needs-human";
|
|
3380
|
+
if (pr.state === "MERGED" || pr.mergedAt !== null) return "proceed";
|
|
3381
|
+
if (pr.state === "OPEN") return "wait";
|
|
3382
|
+
return "needs-human";
|
|
3383
|
+
}
|
|
3384
|
+
function designPrMissingComment(issueNumber) {
|
|
3385
|
+
return [
|
|
3386
|
+
"## \u30C7\u30B6\u30A4\u30F3PR\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\uFF08\u8981\u4EBA\u624B\u78BA\u8A8D\uFF09",
|
|
3387
|
+
`apply-ui-design \u306F\u30C7\u30B6\u30A4\u30F3\u30D6\u30E9\u30F3\u30C1 \`${designBranchName(issueNumber)}\` \u3092 head \u3068\u3059\u308BPR\u3092\u5F85\u3063\u3066\u3044\u307E\u3059\u304C\u3001\u305D\u306EPR\u304C\u898B\u3064\u304B\u3089\u306A\u3044\u304B\u3001\u30DE\u30FC\u30B8\u3055\u308C\u305A\u30AF\u30ED\u30FC\u30BA\u3055\u308C\u3066\u3044\u307E\u3059\u3002`,
|
|
3388
|
+
"",
|
|
3389
|
+
"## \u72B6\u614B\u306E\u78BA\u8A8D",
|
|
3390
|
+
`- \u30C7\u30B6\u30A4\u30F3PR\u304C\u5374\u4E0B\u3055\u308C\u305F\u5834\u5408: \u3053\u306EIssue\u3092\u30C7\u30B6\u30A4\u30F3\u306A\u3057\u3067\u9032\u3081\u308B\u304B\u3001\u30C7\u30B6\u30A4\u30F3\u3092\u3084\u308A\u76F4\u3059\u304B\u3092\u6C7A\u3081\u3066\u304F\u3060\u3055\u3044`,
|
|
3391
|
+
`- \u30C7\u30B6\u30A4\u30F3PR\u304C\u305D\u3082\u305D\u3082\u4F5C\u3089\u308C\u3066\u3044\u306A\u3044\u5834\u5408: \u30EA\u30E2\u30FC\u30C8\u30D6\u30E9\u30F3\u30C1 \`${designBranchName(issueNumber)}\` \u306E\u6709\u7121\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044`,
|
|
3392
|
+
"",
|
|
3393
|
+
"## \u5BFE\u5FDC\u5F8C\u306E\u9032\u3081\u65B9",
|
|
3394
|
+
"- \u30C7\u30B6\u30A4\u30F3\u3092\u3084\u308A\u76F4\u3059\u5834\u5408: `cc-need-human-check` / `cc-ui-design-pr-created` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3001`cc-create-ui-design` \u30E9\u30D9\u30EB\u3092\u4ED8\u3051\u76F4\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
3395
|
+
"- \u30C7\u30B6\u30A4\u30F3\u306A\u3057\u3067\u5B9F\u88C5\u3078\u9032\u3081\u308B\u5834\u5408: `cc-need-human-check` / `cc-ui-design-pr-created` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3001`cc-exec-issue` \u30E9\u30D9\u30EB\u306E\u307F\u4ED8\u3051\u3066\u304F\u3060\u3055\u3044"
|
|
3396
|
+
].join("\n");
|
|
3397
|
+
}
|
|
3398
|
+
function designPrNotCreatedComment(issueNumber) {
|
|
3399
|
+
return [
|
|
3400
|
+
"## \u30C7\u30B6\u30A4\u30F3PR\u672A\u4F5C\u6210\u306E\u307E\u307E\u81EA\u52D5\u5B9F\u884C\u304C\u7D42\u4E86\u3057\u307E\u3057\u305F\uFF08\u8981\u4EBA\u624B\u78BA\u8A8D\uFF09",
|
|
3401
|
+
`create-ui-design \u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u6B63\u5E38\u7D42\u4E86\uFF08exit 0\uFF09\u3057\u307E\u3057\u305F\u304C\u3001\u30C7\u30B6\u30A4\u30F3\u30D6\u30E9\u30F3\u30C1 \`${designBranchName(issueNumber)}\` \u3092 head \u3068\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`,
|
|
3402
|
+
"",
|
|
3403
|
+
"## \u72B6\u614B\u306E\u78BA\u8A8D",
|
|
3404
|
+
`- \u5909\u66F4\u304C push \u6E08\u307F\u306E\u5834\u5408\u306F\u30EA\u30E2\u30FC\u30C8\u30D6\u30E9\u30F3\u30C1 \`${designBranchName(issueNumber)}\` \u304C\u6B8B\u3063\u3066\u3044\u307E\u3059\u3002\u5185\u5BB9\u3092\u78BA\u8A8D\u3057\u3001\u5FC5\u8981\u306A\u3089\u624B\u52D5\u3067\u30C7\u30B6\u30A4\u30F3PR\u3092\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044`,
|
|
3405
|
+
"",
|
|
3406
|
+
"## \u5BFE\u5FDC\u5F8C\u306E\u9032\u3081\u65B9",
|
|
3407
|
+
"- \u81EA\u52D5\u5B9F\u884C\u3092\u3084\u308A\u76F4\u3059\u5834\u5408: `cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3001`cc-create-ui-design` \u30E9\u30D9\u30EB\u3092\u4ED8\u3051\u76F4\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
3408
|
+
"- \u624B\u52D5\u3067\u30C7\u30B6\u30A4\u30F3PR\u3092\u4F5C\u6210\u3057\u305F\u5834\u5408: `cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3001`cc-ui-design-pr-created` \u30E9\u30D9\u30EB\u3092\u4ED8\u3051\u3066\u304F\u3060\u3055\u3044",
|
|
3409
|
+
"- \u30C7\u30B6\u30A4\u30F3\u3092\u8AE6\u3081\u3066\u305D\u306E\u307E\u307E\u5B9F\u88C5\u3078\u9032\u3081\u308B\u5834\u5408: `cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3001`cc-exec-issue` \u30E9\u30D9\u30EB\u306E\u307F\u4ED8\u3051\u3066\u304F\u3060\u3055\u3044"
|
|
3410
|
+
].join("\n");
|
|
3411
|
+
}
|
|
3412
|
+
function designReferenceMissingComment(issueNumber) {
|
|
3413
|
+
return [
|
|
3414
|
+
"## \u30C7\u30B6\u30A4\u30F3\u53C2\u7167\u306E\u66F8\u304D\u623B\u3057\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\uFF08\u8981\u4EBA\u624B\u78BA\u8A8D\uFF09",
|
|
3415
|
+
`apply-ui-design \u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u6B63\u5E38\u7D42\u4E86\uFF08exit 0\uFF09\u3057\u307E\u3057\u305F\u304C\u3001Issue #${issueNumber} \u306E description \u306B \`${DESIGN_REFERENCE_HEADING}\` \u30BB\u30AF\u30B7\u30E7\u30F3\uFF08\`.pen\` \u306E\u30D1\u30B9\u3092\u542B\u3080\uFF09\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002`,
|
|
3416
|
+
"",
|
|
3417
|
+
"## \u306A\u305C\u6B62\u3081\u3066\u3044\u308B\u304B",
|
|
3418
|
+
"- \u30C7\u30B6\u30A4\u30F3\u53C2\u7167\u304C description \u306B\u7121\u3044\u3068\u3001`exec-issue` \u306F\u30C7\u30B6\u30A4\u30F3\u3092\u5165\u529B\u306B\u3067\u304D\u305A\u3001\u5408\u610F\u6E08\u307F\u306E\u30C7\u30B6\u30A4\u30F3\u3068\u7121\u95A2\u4FC2\u306A\u5B9F\u88C5\u306B\u306A\u308A\u307E\u3059",
|
|
3419
|
+
"",
|
|
3420
|
+
"## \u5BFE\u5FDC\u5F8C\u306E\u9032\u3081\u65B9",
|
|
3421
|
+
"- \u81EA\u52D5\u5B9F\u884C\u3092\u3084\u308A\u76F4\u3059\u5834\u5408: `cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3001`cc-ui-design-pr-created` \u30E9\u30D9\u30EB\u3092\u4ED8\u3051\u76F4\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
3422
|
+
"- \u624B\u52D5\u3067 description \u306B\u53C2\u7167\u3092\u8FFD\u8A18\u3057\u305F\u5834\u5408: `cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3001`cc-ui-design-ready` \u3068 `cc-exec-issue` \u30E9\u30D9\u30EB\u3092\u4ED8\u3051\u3066\u304F\u3060\u3055\u3044"
|
|
3423
|
+
].join("\n");
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3426
|
+
// src/workers/create-ui-design.ts
|
|
3427
|
+
function designPrLabelingFailedComment(issueNumber, prNumber, error) {
|
|
3428
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3429
|
+
return [
|
|
3430
|
+
"## \u30C7\u30B6\u30A4\u30F3PR\u3078\u306E\u30E9\u30D9\u30EB\u4ED8\u4E0E\u306B\u5931\u6557\u3057\u307E\u3057\u305F\uFF08\u8981\u4EBA\u624B\u78BA\u8A8D\uFF09",
|
|
3431
|
+
`\u30C7\u30B6\u30A4\u30F3PR #${prNumber}\uFF08\u30D6\u30E9\u30F3\u30C1 \`${designBranchName(issueNumber)}\`\uFF09\u306F\u4F5C\u6210\u3055\u308C\u307E\u3057\u305F\u304C\u3001\u5F8C\u7D9A\u30E9\u30D9\u30EB\uFF08\`cc-ui-design\` / \`cc-triage-scope\` / \`cc-ui-design-pr-created\`\uFF09\u306E\u4ED8\u4E0E\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002`,
|
|
3432
|
+
"",
|
|
3433
|
+
"## \u8D77\u3053\u308A\u3046\u308B\u539F\u56E0",
|
|
3434
|
+
"- \u672C\u30EF\u30FC\u30AF\u30D5\u30ED\u30FC\u8FFD\u52A0\u6642\u306E\u30E9\u30D9\u30EB\u304C\u672A\u4F5C\u6210\u306E\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002`claude-task-worker init` \u3092\u518D\u5B9F\u884C\u3057\u3066\u30E9\u30D9\u30EB\u3092\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044",
|
|
3435
|
+
"",
|
|
3436
|
+
"## \u30A8\u30E9\u30FC\u5185\u5BB9",
|
|
3437
|
+
"```",
|
|
3438
|
+
message,
|
|
3439
|
+
"```",
|
|
3440
|
+
"",
|
|
3441
|
+
"## \u5BFE\u5FDC\u5F8C\u306E\u9032\u3081\u65B9",
|
|
3442
|
+
"- \u30E9\u30D9\u30EB\u4F5C\u6210\u5F8C\u306B\u3084\u308A\u76F4\u3059\u5834\u5408: `cc-need-human-check` \u30E9\u30D9\u30EB\u3092\u5916\u3057\u3001`cc-ui-design`\u30FB`cc-triage-scope`\uFF08PR\u5074\uFF09\u3068 `cc-ui-design-pr-created`\uFF08Issue\u5074\uFF09\u3092\u624B\u52D5\u3067\u4ED8\u3051\u3066\u304F\u3060\u3055\u3044"
|
|
3443
|
+
].join("\n");
|
|
3444
|
+
}
|
|
3445
|
+
var createUiDesignWorker = async (opts = {}) => {
|
|
3446
|
+
if (!getUiDesignConfig().enabled) {
|
|
3447
|
+
console.log("[create-ui-design] uiDesign.enabled is false, skipping");
|
|
3448
|
+
return;
|
|
3449
|
+
}
|
|
3450
|
+
await createIssuePollingWorker({
|
|
3451
|
+
name: "create-ui-design",
|
|
3452
|
+
command: "/claude-task-worker:create-ui-design",
|
|
3453
|
+
triggerLabels: ["cc-create-ui-design"],
|
|
3454
|
+
excludeLabels: ["cc-ui-design-pr-created", "cc-ui-design-ready", "cc-exec-issue", "cc-pr-created"],
|
|
3455
|
+
epicFilters: opts.epicFilters,
|
|
3456
|
+
labelFilters: opts.labelFilters,
|
|
3457
|
+
onCompleted: async (issueNumber) => {
|
|
3458
|
+
if (await hasLabel("issue", issueNumber, "cc-need-human-check")) {
|
|
3459
|
+
console.log(`[create-ui-design] #${issueNumber}: cc-need-human-check present, skip cc-ui-design-pr-created`);
|
|
3460
|
+
return false;
|
|
3461
|
+
}
|
|
3462
|
+
if (await hasLabel("issue", issueNumber, "cc-ui-design-ready")) {
|
|
3463
|
+
console.log(`[create-ui-design] #${issueNumber}: design not needed (cc-ui-design-ready), completing`);
|
|
3464
|
+
return;
|
|
3465
|
+
}
|
|
3466
|
+
const branch = designBranchName(issueNumber);
|
|
3467
|
+
const prNumber = await findPrNumberByHeadRef(branch, "open");
|
|
3468
|
+
if (prNumber === null) {
|
|
3469
|
+
console.error(
|
|
3470
|
+
`[create-ui-design] #${issueNumber}: session exited without an open design PR (branch: ${branch}); marking cc-need-human-check`
|
|
3471
|
+
);
|
|
3472
|
+
await addLabel("issue", issueNumber, "cc-need-human-check");
|
|
3473
|
+
await commentOnIssue(issueNumber, designPrNotCreatedComment(issueNumber)).catch(
|
|
3474
|
+
(err) => console.error(`[create-ui-design] commentOnIssue failed for #${issueNumber}: ${err}`)
|
|
3475
|
+
);
|
|
3476
|
+
return false;
|
|
3477
|
+
}
|
|
3478
|
+
try {
|
|
3479
|
+
await addLabel("pr", prNumber, "cc-ui-design");
|
|
3480
|
+
await addLabel("pr", prNumber, "cc-triage-scope");
|
|
3481
|
+
await addLabel("issue", issueNumber, "cc-ui-design-pr-created");
|
|
3482
|
+
} catch (err) {
|
|
3483
|
+
console.error(`[create-ui-design] #${issueNumber}: labeling design PR #${prNumber} failed: ${err}`);
|
|
3484
|
+
await addLabel("issue", issueNumber, "cc-need-human-check");
|
|
3485
|
+
await commentOnIssue(issueNumber, designPrLabelingFailedComment(issueNumber, prNumber, err)).catch(
|
|
3486
|
+
(commentErr) => console.error(`[create-ui-design] commentOnIssue failed for #${issueNumber}: ${commentErr}`)
|
|
3487
|
+
);
|
|
3488
|
+
return false;
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
})();
|
|
3492
|
+
};
|
|
3493
|
+
|
|
3494
|
+
// src/workers/apply-ui-design.ts
|
|
3495
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
3496
|
+
import { join as join6 } from "node:path";
|
|
3497
|
+
function designFileExistsInWorktree(worktreeId, designFilePath) {
|
|
3498
|
+
return existsSync2(join6(getWorktreePath(worktreeId), designFilePath));
|
|
3499
|
+
}
|
|
3500
|
+
async function markDesignReferenceMissing(issueNumber, logMessage) {
|
|
3501
|
+
console.error(logMessage);
|
|
3502
|
+
await addLabel("issue", issueNumber, "cc-need-human-check").catch(
|
|
3503
|
+
(err) => console.error(`[apply-ui-design] addLabel cc-need-human-check failed for #${issueNumber}: ${err}`)
|
|
3504
|
+
);
|
|
3505
|
+
await commentOnIssue(issueNumber, designReferenceMissingComment(issueNumber)).catch(
|
|
3506
|
+
(err) => console.error(`[apply-ui-design] commentOnIssue failed for #${issueNumber}: ${err}`)
|
|
3507
|
+
);
|
|
3508
|
+
}
|
|
3509
|
+
var applyUiDesignWorker = async (opts = {}) => {
|
|
3510
|
+
if (!getUiDesignConfig().enabled) {
|
|
3511
|
+
console.log("[apply-ui-design] uiDesign.enabled is false, skipping");
|
|
3512
|
+
return;
|
|
3513
|
+
}
|
|
3514
|
+
await createIssuePollingWorker({
|
|
3515
|
+
name: "apply-ui-design",
|
|
3516
|
+
command: "/claude-task-worker:apply-ui-design",
|
|
3517
|
+
triggerLabels: ["cc-ui-design-pr-created"],
|
|
3518
|
+
excludeLabels: ["cc-ui-design-ready", "cc-exec-issue"],
|
|
3519
|
+
epicFilters: opts.epicFilters,
|
|
3520
|
+
labelFilters: opts.labelFilters,
|
|
3521
|
+
preflight: async (issue) => {
|
|
3522
|
+
const branch = designBranchName(issue.number);
|
|
3523
|
+
let pr;
|
|
3524
|
+
try {
|
|
3525
|
+
pr = await findPrStateByHeadRef(branch);
|
|
3526
|
+
} catch (err) {
|
|
3527
|
+
console.error(`[apply-ui-design] #${issue.number}: findPrStateByHeadRef failed for ${branch}: ${err}`);
|
|
3528
|
+
return "skip";
|
|
3529
|
+
}
|
|
3530
|
+
const disposition = classifyDesignPr(pr);
|
|
3531
|
+
if (disposition === "proceed") return "proceed";
|
|
3532
|
+
if (disposition === "wait") {
|
|
3533
|
+
console.log(`[apply-ui-design] #${issue.number}: design PR #${pr?.number} is still open, waiting for merge`);
|
|
3534
|
+
return "skip";
|
|
3535
|
+
}
|
|
3536
|
+
console.error(`[apply-ui-design] #${issue.number}: design PR for ${branch} is missing or closed unmerged`);
|
|
3537
|
+
try {
|
|
3538
|
+
await addLabel("issue", issue.number, "cc-need-human-check");
|
|
3539
|
+
await commentOnIssue(issue.number, designPrMissingComment(issue.number)).catch(
|
|
3540
|
+
(err) => console.error(`[apply-ui-design] commentOnIssue failed for #${issue.number}: ${err}`)
|
|
3541
|
+
);
|
|
3542
|
+
} catch (err) {
|
|
3543
|
+
console.error(`[apply-ui-design] addLabel cc-need-human-check failed for #${issue.number}: ${err}`);
|
|
3544
|
+
}
|
|
3545
|
+
return "skip";
|
|
3546
|
+
},
|
|
3547
|
+
onCompleted: async (issueNumber, worktreeId) => {
|
|
3548
|
+
let body;
|
|
3549
|
+
try {
|
|
3550
|
+
body = await getIssueBody(issueNumber);
|
|
3551
|
+
} catch (err) {
|
|
3552
|
+
console.error(`[apply-ui-design] #${issueNumber}: getIssueBody failed: ${err}`);
|
|
3553
|
+
body = "";
|
|
3554
|
+
}
|
|
3555
|
+
const designFilePath = extractDesignFilePath(body);
|
|
3556
|
+
if (designFilePath === null) {
|
|
3557
|
+
await markDesignReferenceMissing(
|
|
3558
|
+
issueNumber,
|
|
3559
|
+
`[apply-ui-design] #${issueNumber}: session exited without a design reference section; marking cc-need-human-check`
|
|
3560
|
+
);
|
|
3561
|
+
return false;
|
|
3562
|
+
}
|
|
3563
|
+
if (!designFileExistsInWorktree(worktreeId, designFilePath)) {
|
|
3564
|
+
await markDesignReferenceMissing(
|
|
3565
|
+
issueNumber,
|
|
3566
|
+
`[apply-ui-design] #${issueNumber}: design reference points to ${designFilePath}, which does not exist in worktree ${worktreeId}; marking cc-need-human-check`
|
|
3567
|
+
);
|
|
3568
|
+
return false;
|
|
3569
|
+
}
|
|
3570
|
+
await addLabel("issue", issueNumber, "cc-exec-issue").catch(
|
|
3571
|
+
(err) => console.error(`[apply-ui-design] addLabel cc-exec-issue failed for #${issueNumber}: ${err}`)
|
|
3572
|
+
);
|
|
3573
|
+
await addLabel("issue", issueNumber, "cc-ui-design-ready").catch(
|
|
3574
|
+
(err) => console.error(`[apply-ui-design] addLabel cc-ui-design-ready failed for #${issueNumber}: ${err}`)
|
|
3575
|
+
);
|
|
3576
|
+
}
|
|
3577
|
+
})();
|
|
3578
|
+
};
|
|
3579
|
+
|
|
3234
3580
|
// src/commands/init.ts
|
|
3235
3581
|
import { mkdir as mkdir2, writeFile as writeFile2, access } from "node:fs/promises";
|
|
3236
3582
|
|
|
3237
3583
|
// src/commands/codegraph.ts
|
|
3238
3584
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3239
3585
|
import { homedir as homedir5 } from "node:os";
|
|
3240
|
-
import { dirname as dirname2, join as
|
|
3586
|
+
import { dirname as dirname2, join as join7 } from "node:path";
|
|
3241
3587
|
async function loadRunCommand() {
|
|
3242
3588
|
return await Promise.resolve().then(() => (init_run_command(), run_command_exports));
|
|
3243
3589
|
}
|
|
@@ -3245,8 +3591,8 @@ var CODEGRAPH_PACKAGE = "@colbymchenry/codegraph";
|
|
|
3245
3591
|
var CODEGRAPH_IGNORE_ENTRY = ".codegraph/";
|
|
3246
3592
|
function globalGitIgnorePath(env = process.env, home = homedir5()) {
|
|
3247
3593
|
const xdg = env.XDG_CONFIG_HOME?.trim();
|
|
3248
|
-
const base = xdg ? xdg :
|
|
3249
|
-
return
|
|
3594
|
+
const base = xdg ? xdg : join7(home, ".config");
|
|
3595
|
+
return join7(base, "git", "ignore");
|
|
3250
3596
|
}
|
|
3251
3597
|
function appendIgnoreEntry(current, entry) {
|
|
3252
3598
|
const bare = entry.replace(/\/$/, "");
|
|
@@ -3333,7 +3679,11 @@ var LABELS = [
|
|
|
3333
3679
|
{ name: "cc-triage-scope", color: "c5def5" },
|
|
3334
3680
|
{ name: "cc-resolve-conflict", color: "fbca04" },
|
|
3335
3681
|
{ name: "cc-epic-issue", color: "8b5cf6" },
|
|
3336
|
-
{ name: "cc-release-ready", color: "2da44e" }
|
|
3682
|
+
{ name: "cc-release-ready", color: "2da44e" },
|
|
3683
|
+
{ name: "cc-create-ui-design", color: "ff8ad8" },
|
|
3684
|
+
{ name: "cc-ui-design-pr-created", color: "d4a5e8" },
|
|
3685
|
+
{ name: "cc-ui-design-ready", color: "bfd4f2" },
|
|
3686
|
+
{ name: "cc-ui-design", color: "ec4899" }
|
|
3337
3687
|
];
|
|
3338
3688
|
var ISSUE_TEMPLATE = `name: "[claude-task-worker] Issue\u4F5C\u6210\u4F9D\u983C"
|
|
3339
3689
|
description: claude-task-worker\u3067GitHub Issue\u3092\u4F5C\u6210\u3059\u308B
|
|
@@ -3521,11 +3871,11 @@ async function update() {
|
|
|
3521
3871
|
|
|
3522
3872
|
// src/commands/version.ts
|
|
3523
3873
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
3524
|
-
import { dirname as dirname3, join as
|
|
3874
|
+
import { dirname as dirname3, join as join8 } from "node:path";
|
|
3525
3875
|
import { fileURLToPath } from "node:url";
|
|
3526
3876
|
function version() {
|
|
3527
3877
|
const here = dirname3(fileURLToPath(import.meta.url));
|
|
3528
|
-
const pkgPath =
|
|
3878
|
+
const pkgPath = join8(here, "..", "package.json");
|
|
3529
3879
|
try {
|
|
3530
3880
|
const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
|
|
3531
3881
|
console.log(pkg.version ?? "unknown");
|
|
@@ -3589,7 +3939,9 @@ var WORKERS = {
|
|
|
3589
3939
|
"triage-pr": triagePrWorker,
|
|
3590
3940
|
"resolve-conflict": resolveConflictWorker,
|
|
3591
3941
|
"check-dependabot": checkDependabotWorker,
|
|
3592
|
-
"epic-issue": epicIssueWorker
|
|
3942
|
+
"epic-issue": epicIssueWorker,
|
|
3943
|
+
"create-ui-design": createUiDesignWorker,
|
|
3944
|
+
"apply-ui-design": applyUiDesignWorker
|
|
3593
3945
|
};
|
|
3594
3946
|
function printUsage() {
|
|
3595
3947
|
console.log(`Usage: claude-task-worker <command> [--project <name>] [--epic <issue-number>] [--label <label-name>]
|
|
@@ -3612,6 +3964,8 @@ Workers:
|
|
|
3612
3964
|
resolve-conflict Poll cc-resolve-conflict PRs and run /resolve-conflict
|
|
3613
3965
|
check-dependabot Poll dependabot PRs every 1 hour
|
|
3614
3966
|
epic-issue Poll cc-epic-issue issues and create epic PR when all sub-issues are closed
|
|
3967
|
+
create-ui-design Poll cc-create-ui-design issues and create a Pencil design PR (requires uiDesign.enabled)
|
|
3968
|
+
apply-ui-design Poll cc-ui-design-pr-created issues and write the design reference back once the design PR is merged (requires uiDesign.enabled)
|
|
3615
3969
|
all Poll all workers except triage-created-issue, triage-pr, check-dependabot
|
|
3616
3970
|
yolo Poll all workers including triage-created-issue, triage-pr, check-dependabot
|
|
3617
3971
|
|
|
@@ -3806,7 +4160,9 @@ if (hasProjectFilter()) {
|
|
|
3806
4160
|
updateIssueWorker({ epicFilters, labelFilters }),
|
|
3807
4161
|
answerIssueQuestionsWorker({ epicFilters, labelFilters }),
|
|
3808
4162
|
resolveConflictWorker(),
|
|
3809
|
-
epicIssueWorker({ epicFilters, labelFilters })
|
|
4163
|
+
epicIssueWorker({ epicFilters, labelFilters }),
|
|
4164
|
+
createUiDesignWorker({ epicFilters, labelFilters }),
|
|
4165
|
+
applyUiDesignWorker({ epicFilters, labelFilters })
|
|
3810
4166
|
]);
|
|
3811
4167
|
})();
|
|
3812
4168
|
} else if (workerType === "yolo") {
|
|
@@ -3825,7 +4181,9 @@ if (hasProjectFilter()) {
|
|
|
3825
4181
|
checkDependabotWorker(),
|
|
3826
4182
|
triagePrWorker(),
|
|
3827
4183
|
resolveConflictWorker(),
|
|
3828
|
-
epicIssueWorker({ epicFilters, labelFilters })
|
|
4184
|
+
epicIssueWorker({ epicFilters, labelFilters }),
|
|
4185
|
+
createUiDesignWorker({ epicFilters, labelFilters }),
|
|
4186
|
+
applyUiDesignWorker({ epicFilters, labelFilters })
|
|
3829
4187
|
]);
|
|
3830
4188
|
})();
|
|
3831
4189
|
} else {
|