beeops 0.1.6 → 0.1.9

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/bin/beeops.js CHANGED
@@ -117,6 +117,32 @@ function checkPrerequisites() {
117
117
  return allOk;
118
118
  }
119
119
 
120
+ // ── .gitignore management ──
121
+
122
+ const GITIGNORE_ENTRIES = [
123
+ ".claude/tasks/",
124
+ ".claude/worktrees/",
125
+ ];
126
+
127
+ function updateGitignore(root) {
128
+ const gitignorePath = path.join(root, ".gitignore");
129
+ let content = "";
130
+ if (fs.existsSync(gitignorePath)) {
131
+ content = fs.readFileSync(gitignorePath, "utf8");
132
+ }
133
+
134
+ const lines = content.split("\n");
135
+ const missing = GITIGNORE_ENTRIES.filter((entry) => !lines.some((line) => line.trim() === entry));
136
+
137
+ if (missing.length === 0) return;
138
+
139
+ const block = "\n# beeops runtime artifacts\n" + missing.join("\n") + "\n";
140
+ fs.writeFileSync(gitignorePath, content.trimEnd() + block);
141
+ for (const entry of missing) {
142
+ console.log(` gitignore: added ${entry}`);
143
+ }
144
+ }
145
+
120
146
  // ── Hook registration ──
121
147
 
122
148
  function resolveSettingsFile(root, mode) {
@@ -267,16 +293,19 @@ function init(opts) {
267
293
  }
268
294
  }
269
295
 
270
- // 4. Register hooks (UserPromptSubmit)
296
+ // 4. Update .gitignore (runtime artifacts should not be tracked)
297
+ updateGitignore(root);
298
+
299
+ // 5. Register hooks (UserPromptSubmit)
271
300
  updateSettingsHook(root, opts.hookMode);
272
301
 
273
- // 5. Save locale preference
302
+ // 6. Save locale preference
274
303
  const boDir = path.join(claudeDir, "beeops");
275
304
  ensureDir(boDir);
276
305
  fs.writeFileSync(path.join(boDir, "locale"), opts.locale + "\n");
277
306
  console.log(` locale: ${opts.locale} (saved to .claude/beeops/locale)`);
278
307
 
279
- // 6. Copy contexts if --with-contexts
308
+ // 7. Copy contexts if --with-contexts
280
309
  if (opts.withContexts) {
281
310
  const destContexts = path.join(claudeDir, "beeops", "contexts");
282
311
  copyDir(CONTEXTS_SRC, destContexts);
package/command/bo.md CHANGED
@@ -86,17 +86,78 @@ done
86
86
 
87
87
  Polls for up to 120 seconds. Startup is complete when the `Claude Code` banner appears.
88
88
 
89
- ### Step 5: Send initial prompt
89
+ ### Step 5: Resolve execution mode and send initial prompt
90
90
 
91
- If `$ARGUMENTS` is non-empty, pass the user's instruction directly. Otherwise, send a default instruction to sync issues.
91
+ Determine what instruction to send to the Queen. Priority order:
92
+
93
+ 1. **`$ARGUMENTS` provided** → use it directly, skip settings/interactive
94
+ 2. **Settings file exists** (`.claude/beeops/settings.json`) → build instruction from settings
95
+ 3. **No arguments and no settings** → ask the user interactively
96
+
97
+ #### 5a. If `$ARGUMENTS` is non-empty
98
+
99
+ Use it directly:
92
100
 
93
101
  ```bash
94
102
  if [ -n "$ARGUMENTS" ]; then
95
103
  INSTRUCTION="$ARGUMENTS"
96
- else
97
- INSTRUCTION="Sync GitHub Issues to queue.yaml and complete all tasks."
98
104
  fi
105
+ ```
106
+
107
+ #### 5b. If no arguments, check for settings file
108
+
109
+ ```bash
110
+ SETTINGS_FILE=".claude/beeops/settings.json"
111
+ if [ -z "$ARGUMENTS" ] && [ -f "$SETTINGS_FILE" ]; then
112
+ echo "Found settings: $SETTINGS_FILE"
113
+ cat "$SETTINGS_FILE"
114
+ fi
115
+ ```
116
+
117
+ If the settings file exists, build the instruction based on its contents:
118
+
119
+ | Field | Type | Description |
120
+ |-------|------|-------------|
121
+ | `issues` | `number[]` | Specific issue numbers to process (e.g. `[42, 55]`) |
122
+ | `assignee` | `string` | `"me"` = only issues assigned to the current GitHub user, `"all"` = all open issues |
123
+ | `skip_review` | `boolean` | Skip review phase if true (default: false) |
124
+ | `priority` | `string` | Only process issues of this priority or higher (`"high"`, `"medium"`, `"low"`) |
125
+ | `labels` | `string[]` | Only process issues with these labels |
126
+
127
+ Build the `INSTRUCTION` string as follows:
128
+ - If `issues` is set: `"Sync GitHub Issues to queue.yaml and process only issues: #42, #55."`
129
+ - If `assignee` is `"me"`: `"Sync GitHub Issues to queue.yaml and process only issues assigned to me."`
130
+ - If `assignee` is `"all"` or not set: `"Sync GitHub Issues to queue.yaml and complete all tasks."`
131
+ - Append options: if `skip_review` is true, append `" Skip the review phase."`. If `priority` is set, append `" Only process issues with priority {priority} or higher."`. If `labels` is set, append `" Only process issues with labels: {labels}."`
132
+
133
+ #### 5c. If no arguments and no settings file, ask the user interactively
99
134
 
135
+ Present the following choices to the user (use AskUserQuestion or display the options and wait for input):
136
+
137
+ ```
138
+ How should the Queen process issues?
139
+
140
+ 1. Specify issue numbers (e.g. 42, 55, 100)
141
+ 2. Only issues assigned to me
142
+ 3. All open issues
143
+
144
+ Enter your choice (1/2/3):
145
+ ```
146
+
147
+ Based on the user's response:
148
+ - **Choice 1**: Ask for issue numbers, then set `INSTRUCTION="Sync GitHub Issues to queue.yaml and process only issues: #42, #55."`
149
+ - **Choice 2**: Set `INSTRUCTION="Sync GitHub Issues to queue.yaml and process only issues assigned to me."`
150
+ - **Choice 3**: Set `INSTRUCTION="Sync GitHub Issues to queue.yaml and complete all tasks."`
151
+
152
+ Optionally, after the mode is selected, ask:
153
+ ```
154
+ Save this as default settings? (y/n)
155
+ ```
156
+ If yes, write the corresponding `.claude/beeops/settings.json` file so the next run uses it automatically.
157
+
158
+ #### 5d. Send the instruction to the Queen
159
+
160
+ ```bash
100
161
  tmux send-keys -t "$SESSION:queen" "$INSTRUCTION"
101
162
  sleep 0.3
102
163
  tmux send-keys -t "$SESSION:queen" Enter
@@ -70,7 +70,12 @@ Analyze the received instructions (prompt) and formulate an execution plan.
70
70
 
71
71
  | Instruction Content | Action |
72
72
  |---------------------|--------|
73
- | No instructions / "Process Issues" etc. | Go directly to Phase 1 (Issue sync) |
73
+ | No instructions / "Process Issues" etc. | Go directly to Phase 1 (Issue sync) — process all open issues |
74
+ | "process only issues: #42, #55" etc. | Phase 1 with issue filter — only sync and process the specified issue numbers |
75
+ | "process only issues assigned to me" | Phase 1 with assignee filter — use `gh issue list --assignee @me` to fetch only assigned issues |
76
+ | "Only process issues with priority X or higher" | Phase 1 with priority filter — skip issues below the specified priority |
77
+ | "Only process issues with labels: X, Y" | Phase 1 with label filter — use `gh issue list --label X --label Y` |
78
+ | "Skip the review phase" | Set skip_review flag — after Leader completes, go directly to ci_checking instead of launching Review Leader |
74
79
  | Specific work instructions present | Decompose into tasks and add to queue.yaml |
75
80
 
76
81
  ### Task Decomposition Procedure
@@ -125,6 +130,11 @@ queued -> dispatched -> leader_working -> review_dispatched -> reviewing -> done
125
130
  ^ |
126
131
  +---- fixing <-- fix_required ----------------------------+
127
132
  (max 3 loops)
133
+
134
+ (shortcut: existing PR detected)
135
+ review_dispatched -> reviewing -> done
136
+ |
137
+ fixing <-- fix_required
128
138
  ```
129
139
 
130
140
  | Status | Meaning |
@@ -144,7 +154,7 @@ queued -> dispatched -> leader_working -> review_dispatched -> reviewing -> done
144
154
 
145
155
  ## Task Selection Rules
146
156
 
147
- 1. Select tasks that are `queued` and whose `depends_on` is empty (or all dependencies are `done`)
157
+ 1. Select tasks that are `queued` or `review_dispatched` (with existing PR) and whose `depends_on` is empty (or all dependencies are `done`)
148
158
  2. Skip tasks with a `blocked_reason` (record "Skipped: {reason}" in the log)
149
159
  3. Priority order: high -> medium -> low
150
160
  4. Within the same priority, process lower Issue numbers first
@@ -172,11 +182,17 @@ review_window: "review-42" # review window name
172
182
  3. Execute based on the task's type and assignee:
173
183
 
174
184
  ### type: issue (or assignee: leader)
175
- 1. Invoke **Skill: `bo-dispatch`** to launch a Leader
185
+
186
+ **First, check if the task already has a PR** (i.e. `pr` field is non-null when status is `review_dispatched`):
187
+ - **PR exists** → Skip Leader. Directly launch Review Leader via bo-dispatch to verify the existing PR meets the Issue requirements.
188
+ - **No PR** → Normal flow: launch Leader first.
189
+
190
+ After determining the starting point:
191
+ 1. Invoke **Skill: `bo-dispatch`** to launch a Leader (or Review Leader if PR exists)
176
192
  2. Based on the result (report content) returned by bo-dispatch:
177
193
  - Leader completed -> update to `review_dispatched` -> launch Review Leader (invoke bo-dispatch again)
178
194
  - Review Leader approve -> `ci_checking` -> verify CI
179
- - Review Leader fix_required -> if review_count < 3, set to `fixing` -> relaunch Leader (fix mode)
195
+ - Review Leader fix_required -> if review_count < 3, set to `fixing` -> relaunch Leader (fix mode, using existing branch)
180
196
  - Failure -> update to `error`
181
197
 
182
198
  ### type: adhoc, assignee: orchestrator
@@ -70,7 +70,12 @@ Phase 2: イベント駆動ループ
70
70
 
71
71
  | 指示の内容 | 処理 |
72
72
  |-----------|------|
73
- | 指示なし / 「Issue を消化」等 | Phase 1(Issue 同期)に直行 |
73
+ | 指示なし / 「Issue を消化」等 | Phase 1(Issue 同期)に直行 — 全オープン Issue を処理 |
74
+ | "process only issues: #42, #55" 等 | Phase 1(Issue フィルター付き) — 指定された Issue 番号のみ同期・処理 |
75
+ | "process only issues assigned to me" | Phase 1(担当者フィルター付き) — `gh issue list --assignee @me` で自分担当のみ取得 |
76
+ | "Only process issues with priority X or higher" | Phase 1(優先度フィルター付き) — 指定優先度未満をスキップ |
77
+ | "Only process issues with labels: X, Y" | Phase 1(ラベルフィルター付き) — `gh issue list --label X --label Y` |
78
+ | "Skip the review phase" | skip_review フラグ設定 — Leader 完了後、Review Leader を飛ばして直接 ci_checking へ |
74
79
  | 具体的な作業指示がある | タスク分解して queue.yaml に追加 |
75
80
 
76
81
  ### タスク分解の手順
@@ -125,6 +130,11 @@ queued → dispatched → leader_working → review_dispatched → reviewing →
125
130
  ↑ │
126
131
  └──── fixing ←── fix_required ───────────────────────────┘
127
132
  (最大3回ループ)
133
+
134
+ (短縮パス: 既存 PR 検出時)
135
+ review_dispatched → reviewing → done
136
+
137
+ fixing ←── fix_required
128
138
  ```
129
139
 
130
140
  | ステータス | 意味 |
@@ -144,7 +154,7 @@ queued → dispatched → leader_working → review_dispatched → reviewing →
144
154
 
145
155
  ## タスク選択ルール
146
156
 
147
- 1. `queued` かつ `depends_on` が空(または全て `done`)のタスクを選択
157
+ 1. `queued` または `review_dispatched`(既存 PR あり)かつ `depends_on` が空(または全て `done`)のタスクを選択
148
158
  2. `blocked_reason` があるタスクはスキップ(ログに「スキップ: {理由}」を記録)
149
159
  3. 優先度順: high → medium → low
150
160
  4. 同一優先度内では Issue 番号が小さい方を先に
@@ -172,11 +182,17 @@ review_window: "review-42" # review window 名
172
182
  3. タスクの type と assignee に応じて実行:
173
183
 
174
184
  ### type: issue(または assignee: leader)
175
- 1. **Skill: `bo-dispatch`** を発動し、Leader を起動
185
+
186
+ **まず、タスクに既存 PR があるか確認する**(`pr` フィールドが非null かつ status が `review_dispatched`):
187
+ - **PR あり** → Leader をスキップ。bo-dispatch で Review Leader を直接起動し、既存 PR が Issue の要件を満たしているか検証する。
188
+ - **PR なし** → 通常フロー: まず Leader を起動。
189
+
190
+ 開始ポイントを決定した後:
191
+ 1. **Skill: `bo-dispatch`** を発動し、Leader(または PR 既存なら Review Leader)を起動
176
192
  2. bo-dispatch が返す結果(レポート内容)に基づいて判定:
177
193
  - Leader completed → `review_dispatched` に更新 → Review Leader 起動(再度 bo-dispatch)
178
194
  - Review Leader approve → `ci_checking` → CI 確認
179
- - Review Leader fix_required → review_count < 3 なら `fixing` → Leader 再起動 (fix mode)
195
+ - Review Leader fix_required → review_count < 3 なら `fixing` → Leader 再起動(fix mode、既存ブランチを再利用)
180
196
  - 失敗 → `error` に更新
181
197
 
182
198
  ### type: adhoc, assignee: orchestrator
package/contexts/queen.md CHANGED
@@ -70,7 +70,12 @@ Analyze the received instructions (prompt) and formulate an execution plan.
70
70
 
71
71
  | Instruction Content | Action |
72
72
  |---------------------|--------|
73
- | No instructions / "Process Issues" etc. | Go directly to Phase 1 (Issue sync) |
73
+ | No instructions / "Process Issues" etc. | Go directly to Phase 1 (Issue sync) — process all open issues |
74
+ | "process only issues: #42, #55" etc. | Phase 1 with issue filter — only sync and process the specified issue numbers |
75
+ | "process only issues assigned to me" | Phase 1 with assignee filter — use `gh issue list --assignee @me` to fetch only assigned issues |
76
+ | "Only process issues with priority X or higher" | Phase 1 with priority filter — skip issues below the specified priority |
77
+ | "Only process issues with labels: X, Y" | Phase 1 with label filter — use `gh issue list --label X --label Y` |
78
+ | "Skip the review phase" | Set skip_review flag — after Leader completes, go directly to ci_checking instead of launching Review Leader |
74
79
  | Specific work instructions present | Decompose into tasks and add to queue.yaml |
75
80
 
76
81
  ### Task Decomposition Procedure
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beeops",
3
- "version": "0.1.6",
3
+ "version": "0.1.9",
4
4
  "description": "3-layer multi-agent orchestration system (Queen → Leader → Worker) powered by tmux",
5
5
  "author": "YuugouOhno",
6
6
  "license": "MIT",
@@ -26,6 +26,22 @@ gh issue list -R "$REPO" --state open --json number,title,labels,assignees --lim
26
26
 
27
27
  If 0 issues, display "No issues to process" and exit.
28
28
 
29
+ ### 2.5. Detect Existing PRs
30
+
31
+ For each open Issue, check if a linked PR already exists:
32
+
33
+ ```bash
34
+ gh pr list -R "$REPO" --search "linked:issue:{number}" --state open --json number,url,headRefName --limit 1
35
+ ```
36
+
37
+ If no result, also try keyword search as fallback:
38
+
39
+ ```bash
40
+ gh pr list -R "$REPO" --search "{issue_number} in:title" --state open --json number,url,headRefName --limit 1
41
+ ```
42
+
43
+ Store the results (PR URL + branch name) for use in Step 4.
44
+
29
45
  ### 3. Load queue.yaml
30
46
 
31
47
  If `.claude/tasks/queue.yaml` exists, read it. Otherwise initialize:
@@ -37,7 +53,9 @@ tasks: []
37
53
 
38
54
  ### 4. Diff Detection and Raw Addition
39
55
 
40
- Add Issues not present in queue.yaml with `raw` status:
56
+ Add Issues not present in queue.yaml. If an existing PR was detected in Step 2.5, start from `review_dispatched`; otherwise use `raw` status:
57
+
58
+ **No existing PR (normal flow):**
41
59
 
42
60
  ```yaml
43
61
  - id: "ISSUE-{number}"
@@ -53,6 +71,22 @@ Add Issues not present in queue.yaml with `raw` status:
53
71
  - "{ISO8601} created from gh issue"
54
72
  ```
55
73
 
74
+ **Existing PR detected (skip to review):**
75
+
76
+ ```yaml
77
+ - id: "ISSUE-{number}"
78
+ issue: {number}
79
+ title: "{title}"
80
+ status: review_dispatched
81
+ priority: high
82
+ branch: "{headRefName from PR}"
83
+ depends_on: []
84
+ review_count: 0
85
+ pr: "{PR URL}"
86
+ log:
87
+ - "{ISO8601} created from gh issue (existing PR #{pr_number} detected, starting from review)"
88
+ ```
89
+
56
90
  - Skip Issues already in queue.yaml (with status other than done)
57
91
  - Update status to `done` for Issues in queue.yaml that are closed on GitHub
58
92