devstuff 1.16.0__tar.gz → 1.17.0__tar.gz
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.
- {devstuff-1.16.0 → devstuff-1.17.0}/.github/workflows/test-installs.yml +1 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/CHANGELOG.md +7 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/CLAUDE.md +88 -2
- {devstuff-1.16.0 → devstuff-1.17.0}/PKG-INFO +109 -2
- {devstuff-1.16.0 → devstuff-1.17.0}/README.md +108 -1
- {devstuff-1.16.0 → devstuff-1.17.0}/docs/specs/README.md +1 -0
- devstuff-1.17.0/docs/specs/starship-config/development-plan.md +74 -0
- devstuff-1.17.0/docs/specs/starship-config/specifications.md +164 -0
- devstuff-1.17.0/docs/specs/starship-config/stack-decisions.md +187 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/pyproject.toml +1 -1
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/cli.py +3 -0
- devstuff-1.17.0/src/dev_setup/commands/configure_cmd.py +123 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/help_cmd.py +2 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/install_cmd.py +19 -1
- devstuff-1.17.0/src/dev_setup/configure/__init__.py +56 -0
- devstuff-1.17.0/src/dev_setup/configure/starship/__init__.py +1 -0
- devstuff-1.17.0/src/dev_setup/configure/starship/fonts.py +47 -0
- devstuff-1.17.0/src/dev_setup/configure/starship/model.py +850 -0
- devstuff-1.17.0/src/dev_setup/configure/starship/preview.py +157 -0
- devstuff-1.17.0/src/dev_setup/configure/starship/render.py +268 -0
- devstuff-1.17.0/src/dev_setup/configure/starship/wizard.py +396 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/tools.yaml +48 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/ui.py +4 -2
- devstuff-1.17.0/tests/test_configure_starship.py +682 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/uv.lock +1 -1
- {devstuff-1.16.0 → devstuff-1.17.0}/.claude/skills/run-stuff/SKILL.md +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/.claude/skills/run-stuff/smoke.sh +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/.github/workflows/bump.yml +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/.github/workflows/ci.yml +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/.github/workflows/publish.yml +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/.gitignore +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/dev/Dockerfile +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/dev/Dockerfile.ci +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/dev/Makefile +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/dev/docker-compose.yml +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/dev-setup +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/docs/specs/agent/development-plan.md +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/docs/specs/agent/specifications.md +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/docs/specs/agent/stack-decisions.md +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/install.sh +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/__init__.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/__main__.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/__init__.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/approval.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/bridges.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/catalog.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/completion.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/config.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/loop.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/ollama.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/preflight.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/primitives.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/registry.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/sandbox.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/session.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/transcript.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent/wizard.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent_tools.schema.json +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/agent_tools.yaml +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/base.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/catalog.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/__init__.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/add_cmd.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/agent_cmd.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/catalog_cmd.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/delete_cmd.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/docs_cmd.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/functions_cmd.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/list_cmd.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/remove_cmd.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/run_cmd.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/skills_cmd.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/commands/update_cmd.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/function_runner.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/functions.schema.json +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/functions.yaml +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/functions_catalog.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/functions_registry.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/generic.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/src/dev_setup/registry.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/__init__.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/integration/__init__.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/integration/conftest.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/integration/test_agent_smoke.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/integration/test_agent_tui.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/integration/test_tools.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/test_agent.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/test_agent_completion.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/test_agent_loop.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/test_agent_sandbox.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/test_agent_tools.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/test_agent_wizard.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/test_catalog.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/test_functions.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/test_generic.py +0 -0
- {devstuff-1.16.0 → devstuff-1.17.0}/tests/test_registry.py +0 -0
|
@@ -21,8 +21,10 @@ uv run pytest tests/test_catalog.py::test_user_catalog_overrides_bundled_tool_in
|
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
`pip` is not available in this dev environment — `uv pip install -e .` / `uv run` are the way in.
|
|
24
|
-
Interactive commands (`install`, `add`, `remove`, `delete`) open questionary/click
|
|
25
|
-
hang in non-TTY shells; don't try to drive them from a piped/non-interactive shell.
|
|
24
|
+
Interactive commands (`install`, `add`, `remove`, `delete`, `configure`) open questionary/click
|
|
25
|
+
prompts and hang in non-TTY shells; don't try to drive them from a piped/non-interactive shell.
|
|
26
|
+
To exercise one end-to-end anyway, fork a pty (`pty.fork()`) and write keystrokes to the fd —
|
|
27
|
+
that is how the starship wizard's full flow was verified.
|
|
26
28
|
|
|
27
29
|
### Integration tests (real installs, Docker-isolated)
|
|
28
30
|
|
|
@@ -60,6 +62,7 @@ src/dev_setup/
|
|
|
60
62
|
├── generic.py # GenericTool — the ONE engine that implements every install type
|
|
61
63
|
├── tools.yaml # Bundled built-in catalog (core/tools/languages categories)
|
|
62
64
|
├── ui.py # Rich console + questionary wrappers (spinners, prompts, styled output)
|
|
65
|
+
├── configure/ # Per-tool setup wizards (see "Configurators" below)
|
|
63
66
|
└── commands/ # One Click command per file: list, install, remove, add, delete, docs, catalog
|
|
64
67
|
```
|
|
65
68
|
|
|
@@ -167,6 +170,83 @@ non-interactive `bash <tmpfile>`, so `~/.bashrc`/nvm's shell init never runs on
|
|
|
167
170
|
Not yet built: an `add` wizard and `catalog import`/`export` for functions, analogous to the
|
|
168
171
|
ones tools already have.
|
|
169
172
|
|
|
173
|
+
## Configurators (`configure/`) — tool-specific wizards, deliberately *not* catalog-driven
|
|
174
|
+
|
|
175
|
+
`src/dev_setup/configure/` holds per-tool setup wizards (`devstuff configure <tool>`), registered
|
|
176
|
+
in a `CONFIGURATORS` dict keyed by catalog tool key. `starship` is the first one:
|
|
177
|
+
`configure/starship/{model,render,preview,wizard}.py`.
|
|
178
|
+
|
|
179
|
+
**Why this one breaks the YAML-catalog rule.** Installation generalises into ~7 mechanisms, which
|
|
180
|
+
is what makes `GenericTool` possible. Configuration does not: starship's config is a TOML file of
|
|
181
|
+
format strings, palette tables and powerline transition glyphs; another tool's would be shell
|
|
182
|
+
exports or `git config` calls. Expressing this wizard in YAML would need conditional questions, an
|
|
183
|
+
ordered section model with colour roles, and a template language — a programming language spelled
|
|
184
|
+
in YAML. So configurators are Python, dispatched from a dict, the same shape as `_INSTALLERS` in
|
|
185
|
+
`generic.py`. Full reasoning in `docs/specs/starship-config/stack-decisions.md` (SD-1).
|
|
186
|
+
|
|
187
|
+
A configurator that finds a missing *prerequisite* should offer to install it through
|
|
188
|
+
`install_cmd.install_by_key(key)` rather than telling the user to run a second command — that is
|
|
189
|
+
what the starship wizard does for `nerd-font`.
|
|
190
|
+
|
|
191
|
+
**Adding a configurator** — a new module plus one dict entry. The module must expose
|
|
192
|
+
`run(*, target: Path | None = None)` (returns `None` if the user cancelled; writes nothing until
|
|
193
|
+
they confirm) and `config_path() -> Path`. Everything generic — the picker, install-state check,
|
|
194
|
+
`--list`/`--path`/`--output`, and the post-install offer in `install_cmd.py` — reads the registry,
|
|
195
|
+
so none of it needs touching. There is deliberately **no `configure:` field in `tools.yaml`**: user
|
|
196
|
+
catalogs are strictly validated, so a catalog naming a nonexistent configurator would add a
|
|
197
|
+
load-time failure mode for nothing.
|
|
198
|
+
|
|
199
|
+
**Within the starship configurator, `model.py` is the data and everything else reads it.**
|
|
200
|
+
`SECTIONS` (ordered — declaration order *is* prompt order), `PALETTES` and `PRESETS` drive both the
|
|
201
|
+
TOML emitter and the offline preview, which is what stops those two from drifting. Adding a section
|
|
202
|
+
or palette is one entry; no other file changes.
|
|
203
|
+
|
|
204
|
+
**Things learned from the real binary — don't "simplify" these away:**
|
|
205
|
+
- `symbol` is emitted for every section whose body contains `$symbol`, *including as an empty
|
|
206
|
+
string*. Omit it and starship's built-in Nerd Font glyph leaks into the `plain` preset. The
|
|
207
|
+
converse is unit-tested: a section carrying an icon its body can't render is a bug (that's why
|
|
208
|
+
`directory`, which has no `symbol` key at all, has no icon).
|
|
209
|
+
- Not every module spells the colour key `style` — hence `Section.style_key` (`username` wants
|
|
210
|
+
`style_user`). `battery` is deliberately absent: it accepts neither `style` nor `symbol` (both
|
|
211
|
+
live in its `[[battery.display]]` array), so it would cost three quirk fields for one section.
|
|
212
|
+
- `kubernetes`, `time`, `azure`, `status` and `shlvl` ship *disabled*; listing them in `format`
|
|
213
|
+
isn't enough, they need `disabled = false`. `os` and `git_metrics` are absent for the same
|
|
214
|
+
reason `battery` is: `os` takes its symbol from an `[os.symbols]` distro table, `git_metrics`
|
|
215
|
+
has `added_style`/`deleted_style` instead of `style`.
|
|
216
|
+
- Format strings are emitted as TOML **literal** strings (`'…'`) so starship's `$`, `[`, and `\[`
|
|
217
|
+
grammar needs no escaping. The multi-line top-level `format` is the one basic string, and it
|
|
218
|
+
contains no backslashes of its own beyond the line continuations.
|
|
219
|
+
- Powerline transitions are emitted per **run of consecutive sections sharing a palette role**, not
|
|
220
|
+
per section — otherwise two adjacent language segments draw an arrow between two identical
|
|
221
|
+
backgrounds. The three powerline presets differ *only* in the four glyphs in their `Powerline`
|
|
222
|
+
record (`POWERLINES` in `model.py`); nothing in the emitter knows which variant it is drawing.
|
|
223
|
+
- Any literal text the emitter writes into a format string is escaped with `_escape_format()`.
|
|
224
|
+
This is not theoretical: `success_symbol = '[$](bold fg:ok)'` made starship read `$` as the start
|
|
225
|
+
of a variable name, so the `plain` preset shipped with *no prompt symbol at all* until it was
|
|
226
|
+
caught by sweeping every combination and asserting empty stderr.
|
|
227
|
+
- A custom module (`custom.compose`) is a normal `Section`, but its dotted key has to be written
|
|
228
|
+
`${custom.compose}` in `format` — hence `Section.ref`. It also runs a shell command on **every**
|
|
229
|
+
prompt, so it carries a `when` guard, and anything needing the network is disqualified.
|
|
230
|
+
- Symbols for new sections come from `starship print-config --default` — the module's own shipped
|
|
231
|
+
glyph — rather than being picked from a Nerd Font chart that can't be verified without the font.
|
|
232
|
+
- The sample project must never gain a `bun.lock`: starship's `nodejs` module lists it as a
|
|
233
|
+
*negative* detector, so it silently switches the Node section off in previews.
|
|
234
|
+
- The live preview runs `starship prompt` with `STARSHIP_SHELL=nu`, not `bash`: for bash, starship
|
|
235
|
+
wraps escapes in readline's `\[`/`\]` markers, which are invisible inside a `PS1` and print
|
|
236
|
+
literally anywhere else. It also overrides `PWD` (starship prefers it over the real cwd) and
|
|
237
|
+
makes a second `--right` call, since `right_format` is not part of the left prompt.
|
|
238
|
+
- Every preview failure path returns `None` and degrades to the offline renderer. A preview must
|
|
239
|
+
never be able to end the wizard.
|
|
240
|
+
- The Nerd Font gate (`configure/starship/fonts.py`) is allowed to answer "don't know": without
|
|
241
|
+
fontconfig there is nothing to enumerate, and `None` means *stay silent* rather than warn. It
|
|
242
|
+
also refuses to install over SSH — the glyphs are drawn by the client's terminal — and always
|
|
243
|
+
says that installing a font does not repoint the terminal at it. The install itself goes through
|
|
244
|
+
the ordinary catalog path (`nerd-font` in `tools.yaml` → `install_cmd.install_by_key`), never a
|
|
245
|
+
private download (SD-10).
|
|
246
|
+
|
|
247
|
+
Not yet built: configurators for anything other than starship, and round-tripping an existing
|
|
248
|
+
hand-edited config back into wizard state (the timestamped backup is the safety net instead).
|
|
249
|
+
|
|
170
250
|
## Specs (`docs/specs/`)
|
|
171
251
|
|
|
172
252
|
Design documents live in `docs/specs/<feature>/` — `specifications.md` (numbered, testable
|
|
@@ -258,6 +338,12 @@ Not yet built: an `add` wizard for agent tools, and `catalog import`/`export` fo
|
|
|
258
338
|
- **No new runtime dependencies for the agent.** The Ollama transport is stdlib `urllib` against
|
|
259
339
|
`/api/chat`; the REPL uses `prompt_toolkit`, already vendored via questionary. devstuff is a
|
|
260
340
|
globally installed CLI, so every dependency is a cost paid by users who never run `agent`.
|
|
341
|
+
- **Configuration is Python, installation is YAML.** The no-per-tool-code rule covers *install
|
|
342
|
+
mechanisms*, which generalise; per-tool config formats don't. `configure/` is a registry of
|
|
343
|
+
Python wizards on purpose — see the section above before trying to fold it into `tools.yaml`.
|
|
344
|
+
- **A config wizard previews with the real binary, not an approximation.** `starship prompt`
|
|
345
|
+
against a temp config in a throwaway project is the source of truth; the offline renderer is a
|
|
346
|
+
labelled fallback for when the tool isn't installed (and is what unit tests exercise).
|
|
261
347
|
- **Functions get a parallel catalog/registry instead of extending `GenericTool`.** The
|
|
262
348
|
schemas diverge enough (no `requires` inference, a `params` list, no install/remove
|
|
263
349
|
lifecycle) that folding them into the tool catalog would be lossy; some duplication with
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devstuff
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.17.0
|
|
4
4
|
Summary: Development environment setup CLI for Linux
|
|
5
5
|
Project-URL: Repository, https://github.com/thesawdawg/dev-setup-py
|
|
6
6
|
Author-email: Sawyer <sawyerksu@gmail.com>
|
|
@@ -188,6 +188,105 @@ for confirmation before doing this.
|
|
|
188
188
|
|
|
189
189
|
---
|
|
190
190
|
|
|
191
|
+
### `configure`
|
|
192
|
+
|
|
193
|
+
Set up an installed tool through a guided wizard, previewing the result before anything is
|
|
194
|
+
written. Installing a tool that has a wizard also offers to run it there and then.
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
devstuff configure # pick from the tools that have a wizard
|
|
198
|
+
devstuff configure starship # run starship's prompt wizard
|
|
199
|
+
devstuff configure --list # which tools have a wizard
|
|
200
|
+
devstuff configure starship --path # print the config file path
|
|
201
|
+
devstuff configure starship --output /tmp/try.toml # write elsewhere, leave the live config alone
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
| Tool | What it configures |
|
|
205
|
+
|------|-------------------|
|
|
206
|
+
| `starship` | Prompt style, colour palette, which sections appear, and layout |
|
|
207
|
+
|
|
208
|
+
#### Starship prompt wizard
|
|
209
|
+
|
|
210
|
+
Four questions, with the prompt re-rendered after each one:
|
|
211
|
+
|
|
212
|
+
| Step | Options |
|
|
213
|
+
|------|---------|
|
|
214
|
+
| **Style** | `Plain text` · `Bracketed segments` (both ASCII, any font) · `Icons` · `Icons, bracketed` (Nerd Font glyphs) · `Powerline`, `Powerline, rounded`, `Powerline, slanted` (solid colour bars) |
|
|
215
|
+
| **Palette** | `Terminal colours` (inherits your terminal theme) · Catppuccin Mocha · Nord · Gruvbox Dark · Tokyo Night · Dracula · Rosé Pine · Catppuccin Latte (light) |
|
|
216
|
+
| **Sections** | Grouped checkbox over ~35 modules — see the table below |
|
|
217
|
+
| **Layout** | Single line · Two lines · Two lines with shell info right-aligned (needs zsh/fish/nushell — bash has no right prompt) |
|
|
218
|
+
|
|
219
|
+
| Group | Sections |
|
|
220
|
+
|-------|----------|
|
|
221
|
+
| **Context** | username, hostname (over SSH), container (Docker/toolbox/distrobox) |
|
|
222
|
+
| **Location** | current directory |
|
|
223
|
+
| **Git** | branch, commit hash (when detached), status (dirty/ahead/behind), operation in progress |
|
|
224
|
+
| **Languages** | Node.js, Deno, Bun, Python, Rust, Go, Java, PHP, Ruby, Elixir, .NET, package version |
|
|
225
|
+
| **Infrastructure** | Docker context, **Docker Compose project**, Kubernetes context, AWS profile, Google Cloud project, Azure subscription, Terraform workspace, Nix shell |
|
|
226
|
+
| **Shell** | command duration, exit code of the last command, background jobs, nested shell depth, clock |
|
|
227
|
+
|
|
228
|
+
The review menu adds two content toggles: the blank line between prompts, and whether language
|
|
229
|
+
sections show **version numbers** or just the runtime's symbol.
|
|
230
|
+
|
|
231
|
+
If you pick a style that needs a Nerd Font and there isn't one on the machine, the wizard says
|
|
232
|
+
so in the style list itself (`Needs a Nerd Font — none installed here.`) and offers to install
|
|
233
|
+
`nerd-font` right there — once per run, whether you say yes or no. Two cases it handles rather
|
|
234
|
+
than pretending otherwise: over SSH it points you at [nerdfonts.com](https://www.nerdfonts.com/)
|
|
235
|
+
instead, because the glyphs are drawn by the terminal on *your* machine, not the one you're
|
|
236
|
+
configuring; and after installing it reminds you to actually select the font in your terminal's
|
|
237
|
+
settings, which is a preference no shell can change for you. Without `fontconfig` there is no way
|
|
238
|
+
to enumerate fonts, so the wizard says nothing rather than guessing.
|
|
239
|
+
|
|
240
|
+
The Compose section is a starship [custom module](https://starship.rs/config/#custom-commands)
|
|
241
|
+
rather than a built-in one — it reports the project name `docker compose` in that directory would
|
|
242
|
+
actually use (`$COMPOSE_PROJECT_NAME`, else a top-level `name:` in the compose file, else the
|
|
243
|
+
lowercased directory name), and it only runs at all when there is a compose file next to you.
|
|
244
|
+
|
|
245
|
+
The preview is the real thing: the candidate config is written to a temp file and rendered by
|
|
246
|
+
your installed `starship` binary inside a throwaway sample project (a git repo with language
|
|
247
|
+
marker files), so what you see is the bytes your prompt will produce. Without starship installed
|
|
248
|
+
the wizard still works and falls back to a labelled approximation.
|
|
249
|
+
|
|
250
|
+
A review menu then lets you revisit any answer, dump the generated TOML, or save. On save:
|
|
251
|
+
|
|
252
|
+
- Written to `$STARSHIP_CONFIG`, or `~/.config/starship.toml`.
|
|
253
|
+
- Any existing file is copied to `starship.toml.bak.<timestamp>` first — and if it wasn't written
|
|
254
|
+
by this wizard, you're asked before it's replaced.
|
|
255
|
+
- If `~/.bashrc` has no starship hook, you're offered one (using the same marker
|
|
256
|
+
`devstuff install starship` uses, so `devstuff remove starship` still cleans up).
|
|
257
|
+
|
|
258
|
+
The output is meant to be hand-edited afterwards: it's commented, ordered, and colours are
|
|
259
|
+
referenced through nine semantic palette roles (`dir`, `git`, `lang`, `infra`, `shell`, `ok`,
|
|
260
|
+
`err`, `muted`, `bar_text`), so retheming everything is nine edits in one table.
|
|
261
|
+
|
|
262
|
+
```toml
|
|
263
|
+
# Starship prompt configuration
|
|
264
|
+
# Generated by `devstuff configure starship` — edit freely, or re-run the wizard.
|
|
265
|
+
# Style: Powerline · Palette: Nord · Layout: Two lines
|
|
266
|
+
# Module reference: https://starship.rs/config/
|
|
267
|
+
"$schema" = 'https://starship.rs/config-schema.json'
|
|
268
|
+
|
|
269
|
+
add_newline = true
|
|
270
|
+
palette = 'nord'
|
|
271
|
+
|
|
272
|
+
format = """
|
|
273
|
+
[](fg:dir)\
|
|
274
|
+
$directory\
|
|
275
|
+
[](fg:dir bg:git)\
|
|
276
|
+
$git_branch\
|
|
277
|
+
[](fg:git)\
|
|
278
|
+
$line_break\
|
|
279
|
+
$character"""
|
|
280
|
+
|
|
281
|
+
# Semantic colour roles — swap these to retheme every section at once.
|
|
282
|
+
[palettes.nord]
|
|
283
|
+
dir = '#81a1c1'
|
|
284
|
+
git = '#a3be8c'
|
|
285
|
+
# …
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
191
290
|
### `add`
|
|
192
291
|
|
|
193
292
|
Guided wizard to register a new custom package. Supports six install types:
|
|
@@ -590,12 +689,13 @@ Optional utilities you may want on some machines.
|
|
|
590
689
|
| `gh` | GitHub CLI | GitHub's official CLI | `gh --help` |
|
|
591
690
|
| `htop` | htop | Interactive process and resource monitor | `man htop` |
|
|
592
691
|
| `mkcert` | mkcert | Zero-config local HTTPS certificates | `mkcert --help` |
|
|
692
|
+
| `nerd-font` | JetBrainsMono Nerd Font | Patched font supplying the icons Starship and other CLI tools draw | `fc-list \| grep -i "nerd font"` |
|
|
593
693
|
| `ollama` | Ollama | Run large language models locally | `ollama --help` |
|
|
594
694
|
| `php` | PHP 8.4 | PHP 8.4 + common extensions via ondrej/php PPA | `php --help` |
|
|
595
695
|
| `pi` | Pi Coding Agent | AI coding agent npm package | `pi --help` |
|
|
596
696
|
| `pre-commit` | pre-commit | Git hook manager for automated code quality checks | `pre-commit --help` |
|
|
597
697
|
| `saml2aws` | saml2aws | SAML → AWS STS credentials CLI (Versent) | `saml2aws --help` |
|
|
598
|
-
| `starship` | Starship | Fast, cross-shell customizable prompt | `starship --help` |
|
|
698
|
+
| `starship` | Starship | Fast, cross-shell customizable prompt (`devstuff configure starship`) | `starship --help` |
|
|
599
699
|
| `yq` | yq | Portable command-line YAML/JSON/XML processor | `yq --help` |
|
|
600
700
|
|
|
601
701
|
### Languages
|
|
@@ -740,6 +840,13 @@ dev-setup-py/
|
|
|
740
840
|
├── functions_registry.py # Loads bundled + user YAML into the live function registry
|
|
741
841
|
├── function_runner.py # Param resolution + script/eval/bashrc rendering & execution
|
|
742
842
|
├── functions.yaml # Bundled built-in function catalog
|
|
843
|
+
├── configure/ # Per-tool setup wizards (see "configure" above)
|
|
844
|
+
│ ├── __init__.py # CONFIGURATORS registry: tool key -> wizard module
|
|
845
|
+
│ └── starship/
|
|
846
|
+
│ ├── model.py # presets, palettes, sections, StarshipConfig
|
|
847
|
+
│ ├── render.py # starship.toml emitter + offline preview renderer
|
|
848
|
+
│ ├── preview.py # live preview via `starship prompt` in a sample project
|
|
849
|
+
│ └── wizard.py # the interactive flow, backup + save
|
|
743
850
|
├── agent_tools.yaml # Bundled agent tool catalog
|
|
744
851
|
├── agent/ # Local-model agent (see "Agent" above)
|
|
745
852
|
│ ├── config.py # agent.yaml load/validate/save
|
|
@@ -161,6 +161,105 @@ for confirmation before doing this.
|
|
|
161
161
|
|
|
162
162
|
---
|
|
163
163
|
|
|
164
|
+
### `configure`
|
|
165
|
+
|
|
166
|
+
Set up an installed tool through a guided wizard, previewing the result before anything is
|
|
167
|
+
written. Installing a tool that has a wizard also offers to run it there and then.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
devstuff configure # pick from the tools that have a wizard
|
|
171
|
+
devstuff configure starship # run starship's prompt wizard
|
|
172
|
+
devstuff configure --list # which tools have a wizard
|
|
173
|
+
devstuff configure starship --path # print the config file path
|
|
174
|
+
devstuff configure starship --output /tmp/try.toml # write elsewhere, leave the live config alone
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
| Tool | What it configures |
|
|
178
|
+
|------|-------------------|
|
|
179
|
+
| `starship` | Prompt style, colour palette, which sections appear, and layout |
|
|
180
|
+
|
|
181
|
+
#### Starship prompt wizard
|
|
182
|
+
|
|
183
|
+
Four questions, with the prompt re-rendered after each one:
|
|
184
|
+
|
|
185
|
+
| Step | Options |
|
|
186
|
+
|------|---------|
|
|
187
|
+
| **Style** | `Plain text` · `Bracketed segments` (both ASCII, any font) · `Icons` · `Icons, bracketed` (Nerd Font glyphs) · `Powerline`, `Powerline, rounded`, `Powerline, slanted` (solid colour bars) |
|
|
188
|
+
| **Palette** | `Terminal colours` (inherits your terminal theme) · Catppuccin Mocha · Nord · Gruvbox Dark · Tokyo Night · Dracula · Rosé Pine · Catppuccin Latte (light) |
|
|
189
|
+
| **Sections** | Grouped checkbox over ~35 modules — see the table below |
|
|
190
|
+
| **Layout** | Single line · Two lines · Two lines with shell info right-aligned (needs zsh/fish/nushell — bash has no right prompt) |
|
|
191
|
+
|
|
192
|
+
| Group | Sections |
|
|
193
|
+
|-------|----------|
|
|
194
|
+
| **Context** | username, hostname (over SSH), container (Docker/toolbox/distrobox) |
|
|
195
|
+
| **Location** | current directory |
|
|
196
|
+
| **Git** | branch, commit hash (when detached), status (dirty/ahead/behind), operation in progress |
|
|
197
|
+
| **Languages** | Node.js, Deno, Bun, Python, Rust, Go, Java, PHP, Ruby, Elixir, .NET, package version |
|
|
198
|
+
| **Infrastructure** | Docker context, **Docker Compose project**, Kubernetes context, AWS profile, Google Cloud project, Azure subscription, Terraform workspace, Nix shell |
|
|
199
|
+
| **Shell** | command duration, exit code of the last command, background jobs, nested shell depth, clock |
|
|
200
|
+
|
|
201
|
+
The review menu adds two content toggles: the blank line between prompts, and whether language
|
|
202
|
+
sections show **version numbers** or just the runtime's symbol.
|
|
203
|
+
|
|
204
|
+
If you pick a style that needs a Nerd Font and there isn't one on the machine, the wizard says
|
|
205
|
+
so in the style list itself (`Needs a Nerd Font — none installed here.`) and offers to install
|
|
206
|
+
`nerd-font` right there — once per run, whether you say yes or no. Two cases it handles rather
|
|
207
|
+
than pretending otherwise: over SSH it points you at [nerdfonts.com](https://www.nerdfonts.com/)
|
|
208
|
+
instead, because the glyphs are drawn by the terminal on *your* machine, not the one you're
|
|
209
|
+
configuring; and after installing it reminds you to actually select the font in your terminal's
|
|
210
|
+
settings, which is a preference no shell can change for you. Without `fontconfig` there is no way
|
|
211
|
+
to enumerate fonts, so the wizard says nothing rather than guessing.
|
|
212
|
+
|
|
213
|
+
The Compose section is a starship [custom module](https://starship.rs/config/#custom-commands)
|
|
214
|
+
rather than a built-in one — it reports the project name `docker compose` in that directory would
|
|
215
|
+
actually use (`$COMPOSE_PROJECT_NAME`, else a top-level `name:` in the compose file, else the
|
|
216
|
+
lowercased directory name), and it only runs at all when there is a compose file next to you.
|
|
217
|
+
|
|
218
|
+
The preview is the real thing: the candidate config is written to a temp file and rendered by
|
|
219
|
+
your installed `starship` binary inside a throwaway sample project (a git repo with language
|
|
220
|
+
marker files), so what you see is the bytes your prompt will produce. Without starship installed
|
|
221
|
+
the wizard still works and falls back to a labelled approximation.
|
|
222
|
+
|
|
223
|
+
A review menu then lets you revisit any answer, dump the generated TOML, or save. On save:
|
|
224
|
+
|
|
225
|
+
- Written to `$STARSHIP_CONFIG`, or `~/.config/starship.toml`.
|
|
226
|
+
- Any existing file is copied to `starship.toml.bak.<timestamp>` first — and if it wasn't written
|
|
227
|
+
by this wizard, you're asked before it's replaced.
|
|
228
|
+
- If `~/.bashrc` has no starship hook, you're offered one (using the same marker
|
|
229
|
+
`devstuff install starship` uses, so `devstuff remove starship` still cleans up).
|
|
230
|
+
|
|
231
|
+
The output is meant to be hand-edited afterwards: it's commented, ordered, and colours are
|
|
232
|
+
referenced through nine semantic palette roles (`dir`, `git`, `lang`, `infra`, `shell`, `ok`,
|
|
233
|
+
`err`, `muted`, `bar_text`), so retheming everything is nine edits in one table.
|
|
234
|
+
|
|
235
|
+
```toml
|
|
236
|
+
# Starship prompt configuration
|
|
237
|
+
# Generated by `devstuff configure starship` — edit freely, or re-run the wizard.
|
|
238
|
+
# Style: Powerline · Palette: Nord · Layout: Two lines
|
|
239
|
+
# Module reference: https://starship.rs/config/
|
|
240
|
+
"$schema" = 'https://starship.rs/config-schema.json'
|
|
241
|
+
|
|
242
|
+
add_newline = true
|
|
243
|
+
palette = 'nord'
|
|
244
|
+
|
|
245
|
+
format = """
|
|
246
|
+
[](fg:dir)\
|
|
247
|
+
$directory\
|
|
248
|
+
[](fg:dir bg:git)\
|
|
249
|
+
$git_branch\
|
|
250
|
+
[](fg:git)\
|
|
251
|
+
$line_break\
|
|
252
|
+
$character"""
|
|
253
|
+
|
|
254
|
+
# Semantic colour roles — swap these to retheme every section at once.
|
|
255
|
+
[palettes.nord]
|
|
256
|
+
dir = '#81a1c1'
|
|
257
|
+
git = '#a3be8c'
|
|
258
|
+
# …
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
164
263
|
### `add`
|
|
165
264
|
|
|
166
265
|
Guided wizard to register a new custom package. Supports six install types:
|
|
@@ -563,12 +662,13 @@ Optional utilities you may want on some machines.
|
|
|
563
662
|
| `gh` | GitHub CLI | GitHub's official CLI | `gh --help` |
|
|
564
663
|
| `htop` | htop | Interactive process and resource monitor | `man htop` |
|
|
565
664
|
| `mkcert` | mkcert | Zero-config local HTTPS certificates | `mkcert --help` |
|
|
665
|
+
| `nerd-font` | JetBrainsMono Nerd Font | Patched font supplying the icons Starship and other CLI tools draw | `fc-list \| grep -i "nerd font"` |
|
|
566
666
|
| `ollama` | Ollama | Run large language models locally | `ollama --help` |
|
|
567
667
|
| `php` | PHP 8.4 | PHP 8.4 + common extensions via ondrej/php PPA | `php --help` |
|
|
568
668
|
| `pi` | Pi Coding Agent | AI coding agent npm package | `pi --help` |
|
|
569
669
|
| `pre-commit` | pre-commit | Git hook manager for automated code quality checks | `pre-commit --help` |
|
|
570
670
|
| `saml2aws` | saml2aws | SAML → AWS STS credentials CLI (Versent) | `saml2aws --help` |
|
|
571
|
-
| `starship` | Starship | Fast, cross-shell customizable prompt | `starship --help` |
|
|
671
|
+
| `starship` | Starship | Fast, cross-shell customizable prompt (`devstuff configure starship`) | `starship --help` |
|
|
572
672
|
| `yq` | yq | Portable command-line YAML/JSON/XML processor | `yq --help` |
|
|
573
673
|
|
|
574
674
|
### Languages
|
|
@@ -713,6 +813,13 @@ dev-setup-py/
|
|
|
713
813
|
├── functions_registry.py # Loads bundled + user YAML into the live function registry
|
|
714
814
|
├── function_runner.py # Param resolution + script/eval/bashrc rendering & execution
|
|
715
815
|
├── functions.yaml # Bundled built-in function catalog
|
|
816
|
+
├── configure/ # Per-tool setup wizards (see "configure" above)
|
|
817
|
+
│ ├── __init__.py # CONFIGURATORS registry: tool key -> wizard module
|
|
818
|
+
│ └── starship/
|
|
819
|
+
│ ├── model.py # presets, palettes, sections, StarshipConfig
|
|
820
|
+
│ ├── render.py # starship.toml emitter + offline preview renderer
|
|
821
|
+
│ ├── preview.py # live preview via `starship prompt` in a sample project
|
|
822
|
+
│ └── wizard.py # the interactive flow, backup + save
|
|
716
823
|
├── agent_tools.yaml # Bundled agent tool catalog
|
|
717
824
|
├── agent/ # Local-model agent (see "Agent" above)
|
|
718
825
|
│ ├── config.py # agent.yaml load/validate/save
|
|
@@ -39,3 +39,4 @@ They are most useful when they capture:
|
|
|
39
39
|
| Feature | Status |
|
|
40
40
|
|---------|--------|
|
|
41
41
|
| [`agent/`](agent/) — `devstuff agent`, the local-model agent | Complete (v1) |
|
|
42
|
+
| [`starship-config/`](starship-config/) — `devstuff configure starship`, the prompt wizard | Complete (v1) |
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Development Plan: `devstuff configure starship`
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-07-30
|
|
4
|
+
**Status:** Milestones 1–6 complete
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Milestones
|
|
9
|
+
|
|
10
|
+
| # | Milestone | Deliverable | Done when |
|
|
11
|
+
|---|-----------|-------------|-----------|
|
|
12
|
+
| 1 | Data model | `configure/starship/model.py` — `Preset`, `Palette`, `Section`, `StarshipConfig`, the ordered `SECTIONS` tuple | Defaults produce a coherent config with no I/O |
|
|
13
|
+
| 2 | TOML emitter | `configure/starship/render.py` `to_toml()` | Output parses under `tomllib` for every preset × palette × layout combination, and `starship print-config` accepts it |
|
|
14
|
+
| 3 | Preview | `configure/starship/preview.py` (live, via `starship prompt` in a sample project) + `render.sample_markup()` (offline fallback) | Live path prints ANSI for a real config; offline path renders every selected section with starship absent |
|
|
15
|
+
| 4 | Wizard + command | `configure/starship/wizard.py`, `commands/configure_cmd.py`, registry in `configure/__init__.py`, CLI wiring | `devstuff configure starship` walks the steps, previews after each, saves with a backup |
|
|
16
|
+
| 5 | Integration + docs | post-install offer in `install_cmd.py`, help text, README, CLAUDE.md, this spec | `devstuff install starship` offers the wizard; docs describe how to add a configurator |
|
|
17
|
+
| 6 | Preset + section expansion (v2) | `POWERLINES` glyph sets, bracketed presets, three more palettes, `show_versions`, custom modules (`custom.compose`) and 10 further sections | Every preset × palette × layout × versions combination is accepted by the real binary with **no stderr output**, and the compose command resolves the same name Compose would |
|
|
18
|
+
|
|
19
|
+
## Testing Strategy
|
|
20
|
+
|
|
21
|
+
`tests/test_configure_starship.py` — unit only, no starship required (NFR-5):
|
|
22
|
+
|
|
23
|
+
- **Emitter validity:** every `preset × palette × layout` combination parses under `tomllib`;
|
|
24
|
+
spot-check that `format`, `palette`, `add_newline` and the expected module tables exist.
|
|
25
|
+
- **Section selection:** unselected modules get no table and never appear in `format`; selected
|
|
26
|
+
ones appear in canonical order regardless of the order the checkbox returned them in.
|
|
27
|
+
- **Symbol handling:** `plain` preset emits `symbol = ''` for icon-bearing sections (regression
|
|
28
|
+
guard for starship's default glyph leaking through); `icons`/`powerline` emit the Nerd Font one.
|
|
29
|
+
- **Powerline runs:** consecutive same-role sections produce one bar run — the transition count
|
|
30
|
+
equals the number of role changes, not the number of sections.
|
|
31
|
+
- **Defaults on by default:** `disabled = false` is emitted for `kubernetes`/`time` when selected
|
|
32
|
+
(FR-16) and never for modules starship already enables.
|
|
33
|
+
- **Layout:** `two_line`/`two_line_right` place `$line_break` before `$character`; `single` does
|
|
34
|
+
not; `two_line_right` moves Shell-group sections into `right_format` and out of `format`.
|
|
35
|
+
- **Offline renderer:** `sample_markup()` mentions every selected section's sample value and is
|
|
36
|
+
valid Rich markup (rendered through a `Console` without raising).
|
|
37
|
+
- **Save path:** `save()` honours `STARSHIP_CONFIG`, backs an existing file up to a timestamped
|
|
38
|
+
name, and leaves the backup byte-identical to the original.
|
|
39
|
+
- **Wizard flow:** scripted `ui.*` prompts (the `FakePrompts` pattern from `test_agent_wizard.py`)
|
|
40
|
+
drive a full run and assert the written file reflects every choice; a cancel writes nothing.
|
|
41
|
+
- **Registry:** `configure.get()` / `keys()` resolve starship and reject unknown keys.
|
|
42
|
+
|
|
43
|
+
- **Presets as data:** every preset's `powerline` is one of the declared glyph sets; a preset with
|
|
44
|
+
no bars emits none of those glyphs anywhere in the file; each powerline preset's own four glyphs
|
|
45
|
+
appear in the expected counts (one cap, one transition per role change, one closing separator).
|
|
46
|
+
- **Brackets / versions:** bracketed presets wrap every body except the one that brackets itself;
|
|
47
|
+
hiding versions drops `$version` and the symbol's trailing space, and is recorded in the header.
|
|
48
|
+
- **Custom modules:** `${custom.compose}` is braced in `format`, the table is nested under
|
|
49
|
+
`custom`, and the shell script round-trips byte for byte through the multi-line literal string.
|
|
50
|
+
- **Prompt symbol escaping:** the plain presets emit `[\$]`, not `[$]` (FR-20).
|
|
51
|
+
|
|
52
|
+
Verification against the real binary (not in CI, which has no starship — run from the repo when
|
|
53
|
+
touching the emitter):
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
# for every preset × palette × layout × show_versions, with every section selected:
|
|
57
|
+
# starship print-config, starship prompt, starship prompt --right
|
|
58
|
+
# assert returncode == 0 and stderr == "" # a *warning* is a failure here
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
That sweep is 1008 invocations and is how the `character`-module bug in §6a was found; a config
|
|
62
|
+
that merely parses is not enough, since starship degrades unknown keys and bad format strings to
|
|
63
|
+
a stderr warning and an empty render. Plus a visual check of the live preview per preset.
|
|
64
|
+
|
|
65
|
+
## Risks
|
|
66
|
+
|
|
67
|
+
| Risk | Mitigation |
|
|
68
|
+
|------|------------|
|
|
69
|
+
| `starship prompt` flags differ across versions (`--terminal-width`, `--jobs`) | Try the full flag set, retry with a minimal one, then give up to the offline renderer. Never fatal (NFR-4). |
|
|
70
|
+
| Nerd Font glyphs wrong or absent in the user's terminal | Glyphs are defined as explicit `\uXXXX` escapes with the Nerd Font name in a comment, so they are reviewable; the `plain` preset is the escape hatch and the two Nerd Font presets say so at the point of choosing. |
|
|
71
|
+
| Preview subprocess hangs | 5 s timeout; timeout is treated as a failed render. |
|
|
72
|
+
| Overwriting a hand-tuned `starship.toml` | Timestamped backup before write, path reported; the wizard warns when replacing a file it did not generate (no devstuff header). |
|
|
73
|
+
| Sample project creation fails (no `git`) | Wrapped in try/except; git sections then simply do not render in the live preview, which is the same degradation as running outside a repo. |
|
|
74
|
+
| Emitter and offline renderer drifting apart | Both consume the same `SECTIONS`/`PALETTES` tables; neither hard-codes a module list. |
|