bumblebee-cli 0.2.0 → 0.3.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 (34) hide show
  1. package/dist/index.js +4214 -0
  2. package/dist/index.js.map +1 -0
  3. package/package.json +32 -18
  4. package/templates/skills/bb-agent/SKILL.md +180 -0
  5. package/templates/skills/bb-agent/references/bb-commands.md +124 -0
  6. package/templates/skills/bb-agent/references/investigate-workflow.md +150 -0
  7. package/templates/skills/bb-agent/references/parallel-workflow.md +105 -0
  8. package/templates/skills/bb-agent/references/prompts.md +144 -0
  9. package/templates/skills/bb-agent/references/status-transitions.md +93 -0
  10. package/templates/skills/bb-agent/references/workflow.md +178 -0
  11. package/README.md +0 -49
  12. package/bin/bb.mjs +0 -132
  13. package/python/bb_cli/__init__.py +0 -0
  14. package/python/bb_cli/__main__.py +0 -3
  15. package/python/bb_cli/api_client.py +0 -45
  16. package/python/bb_cli/commands/__init__.py +0 -0
  17. package/python/bb_cli/commands/agent.py +0 -2287
  18. package/python/bb_cli/commands/auth.py +0 -79
  19. package/python/bb_cli/commands/board.py +0 -47
  20. package/python/bb_cli/commands/comment.py +0 -34
  21. package/python/bb_cli/commands/daemon.py +0 -153
  22. package/python/bb_cli/commands/init.py +0 -83
  23. package/python/bb_cli/commands/item.py +0 -192
  24. package/python/bb_cli/commands/label.py +0 -43
  25. package/python/bb_cli/commands/project.py +0 -175
  26. package/python/bb_cli/commands/sprint.py +0 -84
  27. package/python/bb_cli/config.py +0 -136
  28. package/python/bb_cli/main.py +0 -44
  29. package/python/bb_cli/progress.py +0 -117
  30. package/python/bb_cli/streaming.py +0 -168
  31. package/python/pyproject.toml +0 -18
  32. package/python/requirements.txt +0 -4
  33. package/scripts/build.sh +0 -20
  34. package/scripts/postinstall.mjs +0 -146
@@ -1,168 +0,0 @@
1
- """Buffered agent output streaming with local log fallback."""
2
-
3
- from __future__ import annotations
4
-
5
- import json
6
- import queue
7
- import threading
8
- import time
9
- from pathlib import Path
10
-
11
- from .api_client import api_post
12
-
13
-
14
- def _logs_dir() -> Path:
15
- d = Path.home() / ".bumblebee" / "logs"
16
- d.mkdir(parents=True, exist_ok=True)
17
- return d
18
-
19
-
20
- class AgentStreamer:
21
- """Thread-safe buffered relay for Claude CLI stream-json output.
22
-
23
- - Reads JSON lines via feed()
24
- - Writes each line to a local log file immediately (safety net)
25
- - Batches events and POSTs to /relay-batch every FLUSH_INTERVAL_S or BATCH_SIZE events
26
- - Extracts text blocks for summary
27
- """
28
-
29
- BATCH_SIZE = 20
30
- FLUSH_INTERVAL_S = 0.5
31
-
32
- def __init__(self, session_id: int | str):
33
- self._session_id = session_id
34
- self._queue: queue.Queue[dict] = queue.Queue()
35
- self._done = threading.Event()
36
- self._text_blocks: list[str] = []
37
- self._log_path = _logs_dir() / f"session-{session_id}.jsonl"
38
- self._log_file = open(self._log_path, "a", encoding="utf-8")
39
- self._sender_thread: threading.Thread | None = None
40
- self._callback: callable | None = None
41
-
42
- @property
43
- def text_blocks(self) -> list[str]:
44
- return self._text_blocks
45
-
46
- @property
47
- def log_path(self) -> Path:
48
- return self._log_path
49
-
50
- def set_callback(self, cb: callable):
51
- """Set a callback(payload: dict, text: str|None) for each event."""
52
- self._callback = cb
53
-
54
- def start(self):
55
- """Start the background sender thread."""
56
- self._sender_thread = threading.Thread(
57
- target=self._sender_loop, daemon=True, name=f"streamer-{self._session_id}"
58
- )
59
- self._sender_thread.start()
60
-
61
- def feed(self, line: str):
62
- """Feed a raw line from Claude CLI stdout."""
63
- line = line.strip()
64
- if not line:
65
- return
66
-
67
- try:
68
- payload = json.loads(line)
69
- except json.JSONDecodeError:
70
- return
71
-
72
- # Write to log file immediately
73
- self._log_file.write(line + "\n")
74
- self._log_file.flush()
75
-
76
- # Extract text blocks
77
- text = None
78
- if payload.get("type") == "assistant":
79
- for block in payload.get("content", []):
80
- if block.get("type") == "text":
81
- text = block["text"]
82
- self._text_blocks.append(text)
83
-
84
- # Notify callback (for terminal display, progress tracker, etc.)
85
- if self._callback:
86
- try:
87
- self._callback(payload, text)
88
- except Exception:
89
- pass
90
-
91
- # Enqueue for batch relay
92
- self._queue.put(payload)
93
-
94
- def stop(self) -> list[str]:
95
- """Signal completion, flush remaining events, return text blocks."""
96
- self._done.set()
97
- if self._sender_thread:
98
- self._sender_thread.join(timeout=10)
99
- self._log_file.close()
100
- return self._text_blocks
101
-
102
- def _sender_loop(self):
103
- """Background thread: batch events and POST to API."""
104
- buffer: list[dict] = []
105
- last_flush = time.monotonic()
106
-
107
- while not self._done.is_set() or not self._queue.empty():
108
- # Drain queue
109
- try:
110
- item = self._queue.get(timeout=0.25)
111
- buffer.append(item)
112
- except queue.Empty:
113
- pass
114
-
115
- # Flush conditions
116
- now = time.monotonic()
117
- should_flush = (
118
- len(buffer) >= self.BATCH_SIZE
119
- or (buffer and now - last_flush >= self.FLUSH_INTERVAL_S)
120
- or (buffer and self._done.is_set())
121
- )
122
-
123
- if should_flush:
124
- self._flush(buffer)
125
- buffer = []
126
- last_flush = now
127
-
128
- def _flush(self, events: list[dict]):
129
- """POST batch to API. Swallow errors — log file is the safety net."""
130
- if not events:
131
- return
132
- try:
133
- api_post(
134
- f"/api/agent-sessions/{self._session_id}/relay-batch",
135
- json={"events": events},
136
- )
137
- except Exception:
138
- pass # Data preserved in log file
139
-
140
-
141
- def api_patch(path: str, json: dict) -> dict:
142
- """PATCH request helper (not in api_client.py yet)."""
143
- from .api_client import get_client
144
-
145
- with get_client() as client:
146
- resp = client.patch(path, json=json)
147
- resp.raise_for_status()
148
- return resp.json()
149
-
150
-
151
- def update_phase(session_id: int | str, phase: str, **kwargs):
152
- """Update agent session phase via API."""
153
- body: dict = {"phase": phase}
154
- body.update(kwargs)
155
- try:
156
- api_patch(f"/api/agent-sessions/{session_id}/phase", json=body)
157
- except Exception:
158
- pass
159
-
160
-
161
- def complete_session(session_id: int | str, status: str, **kwargs):
162
- """Mark agent session as completed/failed via API."""
163
- body: dict = {"status": status}
164
- body.update(kwargs)
165
- try:
166
- api_post(f"/api/agent-sessions/{session_id}/complete", json=body)
167
- except Exception:
168
- pass
@@ -1,18 +0,0 @@
1
- [project]
2
- name = "bumblebee-cli"
3
- version = "0.2.0"
4
- description = "Bumblebee CLI - bb command for dev task management"
5
- requires-python = ">=3.12"
6
- dependencies = [
7
- "typer>=0.15.0",
8
- "httpx>=0.28.0",
9
- "rich>=13.9.0",
10
- "toml>=0.10.2",
11
- ]
12
-
13
- [project.scripts]
14
- bb = "bb_cli.main:app"
15
-
16
- [build-system]
17
- requires = ["setuptools>=75.0"]
18
- build-backend = "setuptools.build_meta"
@@ -1,4 +0,0 @@
1
- typer>=0.15.0
2
- httpx>=0.28.0
3
- rich>=13.9.0
4
- toml>=0.10.2
package/scripts/build.sh DELETED
@@ -1,20 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- # Build script: copies the Python CLI source into the npm package for publishing.
5
- # Run from repo root: bash packages/npm-cli/scripts/build.sh
6
-
7
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
- PKG_DIR="$(dirname "$SCRIPT_DIR")"
9
- REPO_ROOT="$(dirname "$(dirname "$PKG_DIR")")"
10
-
11
- DEST="$PKG_DIR/python"
12
-
13
- echo "Copying CLI source to $DEST..."
14
- rm -rf "$DEST"
15
- cp -r "$REPO_ROOT/cli" "$DEST"
16
-
17
- # Clean up build artifacts
18
- rm -rf "$DEST"/__pycache__ "$DEST"/**/__pycache__ "$DEST"/*.egg-info "$DEST"/dist "$DEST"/build
19
-
20
- echo "Build complete. Ready to publish with: cd $PKG_DIR && npm publish"
@@ -1,146 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Postinstall script for bumblebee-cli
5
- *
6
- * - Checks for Python 3.12+
7
- * - Skips if a real (pip-installed) `bb` is already on PATH
8
- * - Creates a local .venv and installs the Python CLI
9
- * - NEVER fails npm install — warns instead
10
- */
11
-
12
- import { execSync } from "node:child_process";
13
- import { existsSync } from "node:fs";
14
- import { dirname, join, resolve } from "node:path";
15
- import { fileURLToPath } from "node:url";
16
-
17
- const __dirname = dirname(fileURLToPath(import.meta.url));
18
- const pkgRoot = join(__dirname, "..");
19
- const pythonDir = join(pkgRoot, "python");
20
-
21
- function log(msg) {
22
- console.log(`[bumblebee-cli] ${msg}`);
23
- }
24
-
25
- function warn(msg) {
26
- console.warn(`[bumblebee-cli] WARNING: ${msg}`);
27
- }
28
-
29
- // Check if a real (non-npm-wrapper) bb is already available
30
- function isPipBbInstalled() {
31
- try {
32
- // Try running bb --help and check if it's the Python CLI (not our wrapper)
33
- const which = process.platform === "win32" ? "where" : "which";
34
- const result = execSync(`${which} bb`, { encoding: "utf8", stdio: "pipe" });
35
- const paths = result.trim().split(/\r?\n/);
36
-
37
- // Get npm global prefix to filter out our own wrapper
38
- let npmPrefix = null;
39
- try {
40
- npmPrefix = execSync("npm prefix -g", { encoding: "utf8", stdio: "pipe" }).trim();
41
- } catch {}
42
-
43
- for (const bbPath of paths) {
44
- const p = bbPath.trim();
45
- if (!p) continue;
46
- const normalized = resolve(p).toLowerCase();
47
- // Skip if it's inside npm global prefix (that's our own wrapper)
48
- if (npmPrefix && normalized.startsWith(resolve(npmPrefix).toLowerCase())) {
49
- continue;
50
- }
51
- // Skip if it's inside node_modules
52
- if (normalized.includes("node_modules") && normalized.includes("bumblebee-cli")) {
53
- continue;
54
- }
55
- // Found a real bb (pip-installed)
56
- return true;
57
- }
58
- } catch {
59
- // not found
60
- }
61
- return false;
62
- }
63
-
64
- // Find python and check version
65
- function findPython() {
66
- const candidates =
67
- process.platform === "win32" ? ["python", "python3"] : ["python3", "python"];
68
- for (const cmd of candidates) {
69
- try {
70
- const version = execSync(`${cmd} --version`, {
71
- encoding: "utf8",
72
- stdio: ["pipe", "pipe", "pipe"],
73
- }).trim();
74
- // Parse "Python 3.12.x"
75
- const match = version.match(/Python (\d+)\.(\d+)/);
76
- if (match) {
77
- const major = parseInt(match[1], 10);
78
- const minor = parseInt(match[2], 10);
79
- if (major === 3 && minor >= 12) {
80
- return { cmd, version };
81
- }
82
- }
83
- } catch {
84
- // try next
85
- }
86
- }
87
- return null;
88
- }
89
-
90
- function main() {
91
- // Skip if bb already installed via pip
92
- if (isPipBbInstalled()) {
93
- log("'bb' command found on PATH (pip) — skipping Python setup.");
94
- return;
95
- }
96
-
97
- // Find suitable Python
98
- const python = findPython();
99
- if (!python) {
100
- warn(
101
- "Python 3.12+ not found. The 'bb' command won't work until you:\n" +
102
- " 1. Install Python 3.12+ (https://python.org)\n" +
103
- " 2. Run: pip install bumblebee-cli"
104
- );
105
- return;
106
- }
107
-
108
- log(`Found ${python.version} (${python.cmd})`);
109
-
110
- // Create .venv and install
111
- const venvDir = join(pkgRoot, ".venv");
112
- const isWin = process.platform === "win32";
113
- const pip = isWin
114
- ? join(venvDir, "Scripts", "pip.exe")
115
- : join(venvDir, "bin", "pip");
116
-
117
- try {
118
- if (!existsSync(venvDir)) {
119
- log("Creating virtual environment...");
120
- execSync(`${python.cmd} -m venv "${venvDir}"`, { stdio: "pipe" });
121
- }
122
-
123
- // Install from bundled python/ dir if available, otherwise from PyPI
124
- if (existsSync(pythonDir)) {
125
- log("Installing Bumblebee CLI from bundled source...");
126
- execSync(`"${pip}" install "${pythonDir}"`, { stdio: "pipe" });
127
- } else {
128
- log("Installing Bumblebee CLI from PyPI...");
129
- execSync(`"${pip}" install bumblebee-cli`, { stdio: "pipe" });
130
- }
131
-
132
- log("Setup complete! Run 'bb --help' to get started.");
133
- } catch (e) {
134
- warn(
135
- `Python setup failed: ${e.message}\n` +
136
- "You can still install manually: pip install bumblebee-cli"
137
- );
138
- }
139
- }
140
-
141
- try {
142
- main();
143
- } catch {
144
- // Never fail npm install
145
- warn("Postinstall encountered an error, but npm install will continue.");
146
- }