Skip to content

Commit 5297d6e

Browse files
authored
feat: add install and update commands to CLI and enhance documentation (#157)
Signed-off-by: Frost Ming <me@frostming.com>
1 parent 1eb016a commit 5297d6e

5 files changed

Lines changed: 61 additions & 6 deletions

File tree

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,14 @@ See the [Extension Guide](https://bub.build/extension-guide/) for hook semantics
9696
| `bub chat` | Interactive REPL |
9797
| `bub run MESSAGE` | One-shot turn |
9898
| `bub gateway` | Channel listener (Telegram, etc.) |
99+
| `bub install` | Install or sync Bub plugin deps |
100+
| `bub update` | Upgrade Bub plugin deps |
99101
| `bub login openai` | OpenAI Codex OAuth |
100-
| `bub hooks` | Print hook-to-plugin bindings |
101102

102103
Lines starting with `,` enter internal command mode (`,help`, `,skill name=my-skill`, `,fs.read path=README.md`).
103104

105+
`bub hooks` still exists for diagnostics, but it is hidden from top-level help. `bub install` and `bub update` manage a separate uv project for Bub plugins, defaulting to `~/.bub/bub-project` or `BUB_PROJECT`.
106+
104107
## Configuration
105108

106109
| Variable | Default | Description |

docs/channels/cli.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# CLI
22

3-
`bub` exposes four main commands (`run`, `gateway`, `chat`, `login`) plus one hidden one (`hooks` for diagnostics).
3+
`bub` exposes six public command groups: `run`, `gateway`, `chat`, `install`, `update`, and `login`. It also keeps one hidden diagnostic command: `hooks`.
44

55
## `bub run`
66

@@ -65,6 +65,52 @@ uv run bub chat
6565
uv run bub chat --chat-id local --session-id cli:local
6666
```
6767

68+
`chat` reuses the top-level `--workspace/-w` option. By default it sets `chat_id=local`, keeps the channel as `cli`, and leaves the underlying CLI channel session id at `cli_session` unless you pass `--session-id`.
69+
70+
## `bub install`
71+
72+
Install packages into Bub's managed plugin project, or sync that project if no package spec is given.
73+
74+
```bash
75+
uv run bub install
76+
uv run bub install my-plugin
77+
uv run bub install example-owner/example-bub-plugin@main
78+
uv run bub install https://github.com/example/bub-plugin.git
79+
```
80+
81+
Options and behavior:
82+
83+
- `--project`: path to the uv project used for Bub-managed plugins
84+
- `BUB_PROJECT`: environment variable equivalent of `--project`
85+
- default project path: `~/.bub/bub-project`
86+
- if the project does not exist yet, Bub creates a bare uv app project automatically
87+
- Bub must be installed inside a virtual environment before `install` or `update` can run
88+
89+
Accepted spec forms:
90+
91+
- `https://...` or `git@...`: installed as a Git requirement
92+
- `owner/repo` or `owner/repo@ref`: expanded to a GitHub repository URL
93+
- `name`: passed through as a normal package requirement
94+
- `name@ref`: resolved from `bub-contrib` as `packages/<name>` at the given Git ref
95+
96+
If no package specs are provided, `install` runs a project sync instead of adding anything new.
97+
98+
## `bub update`
99+
100+
Update dependencies inside Bub's managed plugin project.
101+
102+
```bash
103+
uv run bub update
104+
uv run bub update my-plugin another-plugin
105+
```
106+
107+
Behavior:
108+
109+
- with no package names, upgrades the whole project
110+
- with package names, upgrades only the selected dependencies
111+
- uses the same `--project` / `BUB_PROJECT` location as `install`
112+
- creates the managed project first if it does not exist yet
113+
68114
## `bub login`
69115

70116
Authenticate with OpenAI Codex OAuth and persist the resulting credentials under `CODEX_HOME` (default `~/.codex`).
@@ -98,6 +144,8 @@ BUB_MODEL=openai:gpt-5-codex BUB_API_FORMAT=responses uv run bub chat
98144
## Notes
99145

100146
- `--workspace` is parsed before the subcommand, for example `uv run bub --workspace /repo chat`.
147+
- `install` and `update` operate on Bub's managed plugin project, not on the current workspace.
148+
- `uninstall()` exists in the builtin module but is not currently exposed as a public CLI command.
101149
- `run` prints each outbound as:
102150

103151
```text

docs/channels/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ uv run bub gateway --enable-channel telegram
3232
- `run` command default session id: `<channel>:<chat_id>`
3333
- Telegram channel session id: `telegram:<chat_id>`
3434
- `chat` command default session id: `cli_session` (override with `--session-id`)
35+
- `chat` command default chat id: `local`
3536

3637
## Outbound Delivery Surfaces
3738

docs/features.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Context is reconstructed from tape records, not accumulated in session state.
1717

1818
## Builtin Batteries
1919

20-
- **CLI**: `run`, `chat`, `gateway`, `login`, `hooks` via Typer.
20+
- **CLI**: `run`, `chat`, `gateway`, `install`, `update`, and `login` via Typer; hidden `hooks` remains available for diagnostics.
2121
- **Model runtime**: agent loop with tool use, backed by [Republic](https://github.com/bubbuild/republic).
2222
- **Comma commands**: `,help`, `,skill`, `,fs.read`, etc. Unknown commands fall back to shell.
2323
- **Channels**: `cli` and `telegram` ship as defaults.

src/bub/builtin/cli.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,12 @@ def _build_requirement(spec: str) -> str:
148148
return f"git+https://github.com/{repo}.git{ref}"
149149
else:
150150
# Assume it's a package name in bub-contrib
151-
name, *rest = spec.partition("@")
152-
ref = "".join(rest)
153-
return f"git+{BUB_CONTRIB_REPO}{ref}#subdirectory=packages/{name}"
151+
name, has_ref, ref = spec.partition("@")
152+
if has_ref:
153+
ref = f"@{ref}"
154+
return f"git+{BUB_CONTRIB_REPO}{ref}#subdirectory=packages/{name}"
155+
else: # PyPI package name
156+
return name
154157

155158

156159
def _ensure_project(project: Path) -> None:

0 commit comments

Comments
 (0)