@cam5/baby-bird 0.1.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 ADDED
@@ -0,0 +1,205 @@
1
+ # baby-bird 🐣
2
+
3
+ Guided **code tours** for git changes, on the command line.
4
+
5
+ `bb` looks at a change (a branch, a range, or your working tree), asks an LLM to organize it into an ordered set of sections, and renders the result in your terminal: each section has a title, a description of *why* and *what*, the files it touches with `+/-` counts, and excerpts pulled from the real diff. Tours are cached by content, so the model runs once per change.
6
+
7
+ ```
8
+ 🐣 Add a shell-command LLM provider with presets
9
+ feat/llm-presets vs main (merge-base 4e2a1c9) · base from pull request
10
+ PR #12: Add LLM presets https://github.com/you/repo/pull/12
11
+ 6 files · +412 -18 · 4 sections · claude-sonnet, generated just now
12
+
13
+ Presets let people pick a model and effort level without hand-writing a
14
+ command line, while still allowing a fully custom invocation ...
15
+
16
+ Contents
17
+ 1. The preset table and how it resolves 2 files · +96 -4
18
+ 2. Running any CLI as the model 1 file · +93 -0
19
+ 3. Config cascade: user, project, env, flags 2 files · +120 -14
20
+ 4. Tests 1 file · +103 -0
21
+
22
+ ────────────────────────────────────────────────────────────────────
23
+ 1. The preset table and how it resolves (1/4)
24
+ 2 files · +96 -4
25
+
26
+ Presets are named argv templates. Resolution is: an explicit
27
+ `llm.command` wins, otherwise the named preset (user-defined
28
+ presets shadow built-ins), then `llm.args` are appended ...
29
+
30
+ src/core/config.ts
31
+ src/index.ts
32
+
33
+ src/core/config.ts:24 The built-in presets, all targeting the Claude Code CLI
34
+ 22 24 │ const CLAUDE_BASE = ['claude', '-p', '--bare', ...
35
+ 25 │+export const BUILTIN_PRESETS = Object.freeze({
36
+ ...
37
+ ```
38
+
39
+ ## Install
40
+
41
+ ```sh
42
+ pnpm add -g @cam5/baby-bird # or: npm i -g @cam5/baby-bird
43
+ bb --help
44
+ ```
45
+
46
+ Requirements: Node 22+, git, and some CLI that can answer a prompt (by default the [Claude Code](https://claude.com/claude-code) CLI, `claude`).
47
+
48
+ ## Usage
49
+
50
+ ```
51
+ bb tour the current branch
52
+ bb main..feature tour an explicit range
53
+ bb main...feature same, from the merge-base
54
+ bb HEAD~3 tour the last three commits
55
+ bb release/2.0 what HEAD adds on top of release/2.0 (merge-base semantics)
56
+ bb --working uncommitted changes (tracked + untracked)
57
+ bb --staged what you are about to commit
58
+ bb --section 2 render only the second section
59
+ bb --json | jq machine-readable tour
60
+ bb --dump-prompt print the prompt instead of calling the model
61
+ bb --refresh regenerate even if a cached tour exists
62
+ bb --preset claude-sonnet
63
+ ```
64
+
65
+ ### What does bare `bb` tour?
66
+
67
+ 1. If the working tree has uncommitted changes: those.
68
+ 2. Else, if the code host knows a pull request for this branch (`gh pr view`): the branch against the PR's base, and the PR title/body are fed to the model.
69
+ 3. Else, the branch against its nearest ancestor branch (the local branch whose merge-base is closest to `HEAD`).
70
+ 4. Else, the branch against the default branch (`origin/HEAD`, or `main`/`master`/`trunk`).
71
+
72
+ The header of every tour says which one was used.
73
+
74
+ ## Configuration
75
+
76
+ Config is JSON, merged in this order (later wins; objects merge, arrays replace):
77
+
78
+ 1. built-in defaults
79
+ 2. `$XDG_CONFIG_HOME/baby-bird/config.json` (default `~/.config/baby-bird/config.json`)
80
+ 3. `<repo>/.baby-bird/config.json` (create one with `bb init`)
81
+ 4. environment: `BB_PRESET`, `BB_LLM_COMMAND`, `BB_CODEHOST`, `BB_CACHE_DIR`, `BB_NO_CACHE`, `NO_COLOR`
82
+ 5. flags: `--preset`, `--color/--no-color`, `--no-cache`, `--no-pager`
83
+
84
+ `bb config` shows every layer, what it contributed, the resolved LLM command, and all presets.
85
+
86
+ All keys, with defaults:
87
+
88
+ ```jsonc
89
+ {
90
+ "llm": {
91
+ "preset": "claude", // which preset to run (built-in or from "presets")
92
+ "presets": {}, // your own presets; same names shadow built-ins
93
+ "args": [], // extra argv appended to the preset's command
94
+ "command": null, // a whole custom invocation; when set, "preset" is ignored
95
+ "promptVia": null, // "stdin" (default) or "arg" (replace {prompt} in argv)
96
+ "timeoutMs": 180000,
97
+ "maxPromptBytes": 200000, // larger diffs are truncated, biggest files first
98
+ "env": {} // extra environment for the command
99
+ },
100
+ "codehost": { "provider": "gh" }, // "gh" or "none"
101
+ "git": {
102
+ "defaultBranch": null, // auto-detect
103
+ "exclude": ["**/pnpm-lock.yaml", "**/package-lock.json", "**/yarn.lock", "**/Cargo.lock",
104
+ "**/*.min.*", "**/dist/**", "**/*.snap", "**/*.map"]
105
+ },
106
+ "render": { "color": "auto", "pager": "auto", "maxExcerptLines": 60, "width": null },
107
+ "cache": { "enabled": true, "dir": null } // default $XDG_CACHE_HOME/baby-bird
108
+ }
109
+ ```
110
+
111
+ ### LLM presets
112
+
113
+ The model is just a command: the prompt goes in on stdin, the answer comes out on stdout. Built-in presets:
114
+
115
+ | preset | runs |
116
+ |---|---|
117
+ | `claude` (default) | `claude -p --no-session-persistence --setting-sources "" --tools ""` |
118
+ | `claude-sonnet` | the above plus `--model sonnet --effort high` |
119
+ | `claude-opus` | the above plus `--model opus --effort high` |
120
+ | `claude-fable` | the above plus `--model fable --effort high` |
121
+ | `claude-haiku` | the above plus `--model haiku` |
122
+ | `llm` | `llm` ([Simon Willison's CLI](https://llm.datasette.io/)) |
123
+
124
+ Add flags to a preset, define your own, or replace the command entirely:
125
+
126
+ ```jsonc
127
+ {
128
+ "llm": {
129
+ "preset": "claude-sonnet",
130
+ "args": ["--fallback-model", "haiku"],
131
+ "presets": {
132
+ "local": { "command": ["ollama", "run", "qwen2.5-coder:14b"] },
133
+ "gemini": { "command": ["gemini", "-p", "{prompt}"], "promptVia": "arg" }
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ ```sh
140
+ bb --preset local
141
+ BB_LLM_COMMAND='llm -m gpt-4.1' bb
142
+ ```
143
+
144
+ The effective command is part of the cache key, so switching presets regenerates the tour instead of reusing another model's.
145
+
146
+ ### Code host
147
+
148
+ With `codehost.provider` set to `gh` (the default), `bb` uses the `gh` CLI to find the current branch's pull request. Its base branch decides what to compare against and its title and body are included in the prompt. Nothing else is read, and no tokens are handled by `bb`. If `gh` is missing or not logged in, the lookup is silently skipped. Set the provider to `none` to turn it off.
149
+
150
+ ### Cache
151
+
152
+ Tours are stored as JSON under `$XDG_CACHE_HOME/baby-bird/tours/` (default `~/.cache/baby-bird/tours/`), keyed by a hash of the exact prompt (which encodes the diff content, PR text, commit subjects, and prompt version) plus the LLM command.
153
+
154
+ ```
155
+ bb cache ls # what is cached
156
+ bb cache clear
157
+ bb cache path
158
+ ```
159
+
160
+ ## How a tour is built
161
+
162
+ 1. Resolve what to compare (see above) and collect the unified diff, commit subjects, and PR text.
163
+ 2. Assemble the prompt: rules, the output contract, a file table, and the diff with every hunk labeled `[F3.H2]`. Over-budget prompts are shortened biggest-file-first.
164
+ 3. Run the LLM command. The model returns sections that *reference* hunks by id; it never reproduces code. If the reply isn't valid JSON for the schema, one repair round-trip is attempted.
165
+ 4. Materialize: excerpts are sliced from the real diff, counts are computed locally, and any file the model did not mention lands in a final "Other changes" section.
166
+ 5. Cache and render.
167
+
168
+ `bb --dump-prompt` prints step 2's output, which is the fastest way to iterate on the prompt (`src/core/prompt/template.ts`).
169
+
170
+ ## Using it as a library
171
+
172
+ The CLI is one consumer of a small core. `import { generateTour, CliRenderer, type Tour } from '@cam5/baby-bird'` gives you the same pipeline for a TUI, a web view, or a bot; a `Tour` is plain JSON (sections, stats, excerpts) with no git or LLM dependencies.
173
+
174
+ ## Development
175
+
176
+ ```sh
177
+ pnpm install
178
+ pnpm dev -- --help # run from source
179
+ pnpm test # vitest: unit + integration (uses temp git repos and a fake LLM)
180
+ pnpm typecheck
181
+ pnpm build # dist/ via tsup
182
+ ```
183
+
184
+ ## Releasing
185
+
186
+ Releases are cut by pushing a version tag. The `release` workflow checks that the tag matches `package.json`, runs typecheck, tests and build, publishes to npm with provenance (via npm trusted publishing, so no token is stored), and creates a GitHub Release with generated notes.
187
+
188
+ ```sh
189
+ npm version patch # or minor / major: bumps package.json, commits, tags vX.Y.Z
190
+ git push --follow-tags
191
+ ```
192
+
193
+ ## Exit codes
194
+
195
+ | code | meaning |
196
+ |---|---|
197
+ | 0 | ok |
198
+ | 2 | usage or configuration error |
199
+ | 3 | not a git repository, or nothing to tour |
200
+ | 4 | the LLM command failed to run |
201
+ | 5 | the model's output was unusable even after a repair attempt |
202
+
203
+ ## License
204
+
205
+ MIT