@groeponline/pi-wishcraft 1.13.0 → 1.14.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 (65) hide show
  1. package/AGENTS.md +2 -2
  2. package/CHANGELOG.md +60 -0
  3. package/README.md +30 -129
  4. package/build-stamp.json +1 -1
  5. package/docs/commands.md +11 -5
  6. package/docs/configuration.md +153 -5
  7. package/docs/index.md +2 -2
  8. package/docs/segments.md +18 -4
  9. package/package.json +15 -4
  10. package/src/config/parse.ts +2 -2
  11. package/src/config/segment-options.ts +27 -0
  12. package/src/config/settings-registry.ts +181 -8
  13. package/src/extension/commands/commands.ts +13 -35
  14. package/src/extension/session/activate.ts +5 -0
  15. package/src/extension/settings/config-cli.ts +718 -0
  16. package/src/extension/settings/config-diagnostics.ts +512 -0
  17. package/src/extension/settings/config-doctor.ts +56 -0
  18. package/src/extension/settings/config-paths.ts +180 -0
  19. package/src/extension/settings/setup-wizard.ts +375 -0
  20. package/src/extension/settings/wishcraft-config-items.ts +7 -2
  21. package/src/extension/settings/wishcraft-config.ts +185 -136
  22. package/src/extension/shortcuts/shortcuts-router.ts +1 -1
  23. package/src/extension/ui/custom-editor.ts +15 -0
  24. package/src/extension/ui/deck/component.ts +86 -8
  25. package/src/extension/ui/deck/config-diagnostic-lines.ts +156 -0
  26. package/src/extension/ui/deck/render.ts +260 -46
  27. package/src/extension/ui/deck/route-bodies.ts +163 -11
  28. package/src/extension/ui/deck/routes.ts +24 -0
  29. package/src/extension/ui/deck/session-snapshot.ts +1 -0
  30. package/src/extension/ui/deck/types.ts +4 -0
  31. package/src/extension/ui/menu-views.ts +28 -56
  32. package/src/extension/ui/ports-panel.ts +240 -0
  33. package/src/extension/welcome/welcome-integration.ts +72 -8
  34. package/src/i18n/index.ts +19 -0
  35. package/src/i18n/locale.ts +99 -0
  36. package/src/i18n/nl.ts +355 -0
  37. package/src/i18n/types.ts +16 -0
  38. package/src/motion/frames.ts +156 -3
  39. package/src/motion/gallery.ts +22 -8
  40. package/src/motion/index.ts +13 -1
  41. package/src/motion/scheduler.ts +11 -3
  42. package/src/motion/sweep-cells.ts +53 -0
  43. package/src/render/motion-rail.ts +151 -38
  44. package/src/segments/custom.ts +111 -22
  45. package/src/segments/index.ts +22 -0
  46. package/src/segments/ports-parse.ts +309 -0
  47. package/src/segments/ports-proc.ts +154 -0
  48. package/src/segments/ports.ts +249 -0
  49. package/src/segments/probe-shell.ts +38 -0
  50. package/src/segments/system.ts +64 -215
  51. package/src/signal/controller.ts +9 -2
  52. package/src/theme/colors.ts +204 -3
  53. package/src/theme/icons.ts +18 -3
  54. package/src/theme/theme.ts +19 -3
  55. package/src/welcome/banner.ts +112 -6
  56. package/src/welcome/index.ts +5 -1
  57. package/src/welcome/overlay.ts +40 -2
  58. package/src/welcome/renderer.ts +13 -6
  59. package/src/welcome/types.ts +6 -0
  60. package/src/welcome/whats-new.ts +18 -0
  61. package/src/welcome/widgets/queue-widget.ts +18 -8
  62. package/src/welcome/widgets/sessions-widget.ts +4 -3
  63. package/src/welcome/widgets/shortcuts-widget.ts +9 -8
  64. package/src/welcome/widgets/system-widget.ts +15 -10
  65. package/src/welcome/widgets/whats-new-widget.ts +6 -1
package/AGENTS.md CHANGED
@@ -52,7 +52,7 @@ npm run circular
52
52
 
53
53
  | Directory | Purpose |
54
54
  |---|---|
55
- | `src/` | Extension runtime, organized by domain (core, config, segments, render, signal, motion, theme, welcome, working-vibes, usage, studio, skills, hooks, settings, shortcuts, history, queue, contrib) |
55
+ | `src/` | Extension runtime, organized by domain (core, config, segments, render, signal, motion, theme, welcome, working-vibes, usage, studio, skills, hooks, settings, shortcuts, history, queue, contrib, editor, paths, shell, tools, i18n) |
56
56
  | `src/extension/` | Pi extension runtime: `core/` (hub, types, constants), `session/` (activation, lifecycle), `ui/` (deck, layout), `commands/`, `shortcuts/`, `queue/`, `welcome/`, `skills/`, `hooks/`, `settings/`, `history/`, `contrib/` |
57
57
  | `src/config/` | Powerline config parsing, presets, settings registry, tokens |
58
58
  | `src/segments/` | Segment registry and builtin renderers (core, system, usage, custom) |
@@ -245,7 +245,7 @@ function createRuntimeState(hooks: {
245
245
 
246
246
  | Requirement | Detail |
247
247
  |---|---|
248
- | **Node** | v22.14 system default; Node 24 via nvm for CI and pi CLI (pi requires ≥22.19) |
248
+ | **Node** | ≥22.19 required (pi CLI floor, pinned via `engines`); Node 24 via nvm for CI and pi CLI |
249
249
  | **Package manager** | npm (lockfile v3) |
250
250
  | **TypeScript** | 5.9.3, strict mode, `NodeNext` module/resolution, `allowImportingTsExtensions`, no build step |
251
251
  | **Test runner** | Node built-in `node:test` with `--experimental-strip-types` type stripping |
package/CHANGELOG.md CHANGED
@@ -2,6 +2,66 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.14.0] - 2026-10-01
6
+
7
+ ### Added
8
+ - **Configure from the prompt**: `/wishcraft get|set|unset <setting>` — every registered setting is readable and writable from the pi CLI, no editor involved. `get` reports stored value → owning file (project/global/default) → effective value, with a ⚠ explanation when validation discards it. `set` validates against the same registry the settings TUI and wizard use (unique choice prefixes: `set motion.level red` → `reduced`; toggles take `on`/`off`; numbers checked against declared `min`/`max`), applies immediately (status line repaints; shortcuts/bash settings after `/reload`), and writes to the file that already owns the key. `unset` (alias `reset`) returns to the default. Tab completes subcommands, all registered paths, and each setting's values. Structured values (layout, segments, policy) are refused with a pointer to settings.json rather than written in a broken shape; `get` works even with Signal disabled.
9
+ - Settings registry +19 entries and a new **Shell & bash mode** group: the whole `bashMode.*` surface (toggle shortcut, transcript max lines/bytes, init script), the four missing `powerlineShortcuts` bindings (`copyEditor`, `cutEditor`, `editorStart`, `editorEnd`), `powerline.costAlert`, `powerline.stashSharpSShortcut`, `powerline.customItemsAuto`, `powerline.queue.retentionHours`, `wishcraft.policyEnabled`, git segment toggles (branch/staged/unstaged/untracked/polling/commit length), model segment options (thinking level, name style), and the fleet `openPorts.host`. All of them are now editable in `/wishcraft settings`, validated by the doctor, and covered by NL translations.
10
+ - **Deck → Ports route** (`g p`, twelfth route): the same open-ports table `alt+i` shows, probed asynchronously off the render path and read from a shared 5s cache, so the route never spawns a process during a frame.
11
+ - **Open-ports panel rebuild** (`alt+i`): leads with a summary (`21 tcp · 12 exposed · 9 loopback · local`), renders aligned `PROTO PORT ADDRESS OWNER` rows instead of raw `ss` output, filters as you type on port/address/owner, `r` re-probes, Enter copies the selected row, and fails soft with a readable reason instead of an error toast. Used by `alt+i`, the classic menu and the new Deck route.
12
+ - Shared listening-ports parser (`src/segments/ports.ts`): one parse of `ss`/`netstat` output feeds the segment count, the segment detail, the panel and the Deck route, so they can no longer disagree. Dual-stack binds collapse to one row, IPv6 brackets are stripped (an `[::1]` bind previously would have been reported as *exposed*), and `ss`/`netstat`/macOS dotted-address variants are all handled. The pure parsing half (`ports-parse.ts`) and the `/proc/net` fallback (`ports-proc.ts`) are separate modules, so the render path has no synchronous filesystem or process access at all.
13
+ - **Deck idea actions**: `enter` cycles the review status (idea → in-progress → done) and `d` removes the idea, straight from the Ideas route — the same states the `/ideas` overlay offers.
14
+ - `/` now filters the Ideas list in place (it already filtered skills, appearance and motion).
15
+ - Interface language: a new `Language` setting (`wishcraft.locale`, `en` | `nl`) localises the operator UI — Deck routes and chrome, the settings registry's labels/hints/group titles, the configuration overlay, the welcome overlay and its widgets, the setup wizard, and the diagnostics copy. English is compiled in at each call site (`tr(key, "English")`), so a missing or unknown locale can only ever fall back to English, never blank a surface; the default stays `en` and no existing golden output changes.
16
+ - `/wishcraft setup` — first-run wizard: four questions (language, status preset, motion level, welcome overlay), a review screen, then one write to `settings.json`. The step model is pure and separately tested.
17
+ - `/wishcraft doctor` — configuration diagnosis as a one-screen list, also rendered as a section of the Deck's Diagnostics route: which settings file is winning, values shadowed between global and project, near-miss keys with a "did you mean" suggestion, and every stored value that validation throws away — with an explanation of why and which default applies.
18
+ - Live status-line preview inside the configuration overlay: every toggle/cycle/edit repaints the real status line under the list, so a setting's effect is visible instead of inferred.
19
+ - Per-setting inline warning markers and contextual hints in the configuration overlay: an invalid stored value is flagged in place rather than silently replaced by its default.
20
+ - Settings validation now reports *why* a value is rejected (`explainSettingValue`, `validationProblem`) with localised, actionable copy — including the valid choices and the default that is applied — instead of a bare boolean. Numeric settings gained declared `min`/`max` bounds.
21
+ - First-run welcome: an operator who has never run Wishcraft sees three short next steps under a "Getting started" heading instead of a wall of changelog bullets; later sessions keep the changelog delta under its own heading.
22
+ - **Hot-path regression guard** (`tests/hot-path-contract.test.ts`): the suite now walks the import graph from `src/render/v2-entry.ts` and fails if any reachable module makes a synchronous process spawn (`execSync`/`spawnSync`/`execFileSync`), plus a stricter sweep of all of `src/segments/` and `src/extension/ui/`. Synchronous filesystem reads on the paint path are allowed only via a named allowlist carrying a justification, so a new one has to be argued for rather than slipped in. The assertions are structural, so a blocking call hidden three layers behind helper modules still fails.
23
+ - Coverage gate in CI and local `npm test`: the suite fails below 70% line / 60% function coverage (current baseline 84.7% / 82.6%), so coverage can no longer silently regress.
24
+ - Release-path contract tests: `scripts/release.mjs` (semver bump, `[skip release]` guard, org bump policy, tag parsing/collisions, CHANGELOG roll and note extraction, lockfile rewrite, release-candidate metadata validation incl. every rejection path) and `scripts/verify-release-tag.mjs` (version sources, tag equality, argument parsing) — previously the least-covered, most operationally critical files in the repo.
25
+ - Extension-layer tests: prompt-history (trim/dedupe/cap, snapshot/restore, tracker idempotence, session-JSONL parsing via `PI_CODING_AGENT_DIR` fixture), stash-history (normalize/push/preview semantics), shortcuts router (per-binding action resolution incl. kitty CSI-u forms and release filtering), bash-mode actions (shell path/cwd/history-merge), and stash shortcuts.
26
+ - OMP-style boot reveal: the welcome header and startup overlay fade their art up from a faint ember over the first ~1.5s after mount (logarithmic ramp on a 90ms heartbeat, ember-noise flicker while catching), then settle into the steady layout — a bounded one-shot, zero timers afterwards. `WelcomeHeader`/`WelcomeComponent` arm it via `armBootReveal()`; pure frames via `renderWelcomeArtWithReveal`.
27
+ - Settings appearance preview: the Deck's Appearance route now renders a live signal-rail preview of the structural preset under the cursor (the preset's own signal spec and animation, one row, deterministic per tick), so you see each base before Enter applies it.
28
+
29
+ ### Fixed
30
+ - **CI and the release pipeline were silently dead.** A step name edited to `- name: Unit tests (coverage threshold: 70% lines / 60% functions)` contains an unquoted `: ` inside a plain YAML scalar, which YAML reads as a nested mapping — `.github/workflows/test.yml` became unparseable. GitHub's only signal is a run that fails in 0s with zero jobs and no logs, and because `release.yml` calls `test.yml` via `workflow_call`, the whole release pipeline failed the same way. The scalar is now quoted, all five workflows parse, and `tests/workflow-yaml.test.ts` fails locally — with a file:line reference — on any unquoted colon-space in a step scalar.
31
+ - **Icon and colour resolution did synchronous filesystem work ~19x per paint.** `getIcons()` is called once per segment that renders an icon, and every call re-walked up to six parent directories looking for a `package.json` and then `statSync`'d each candidate `theme.json` — on the order of 170 blocking syscalls per frame while streaming. The package root is now resolved once per process and the icon set is memoised on the config object identity, cutting a paint's theme work by ~28% (61µs → 44µs per `getIcons()` call). The mtime identity check is deliberately kept *before* the TTL, so editing `theme.json` still lands on the very next paint rather than after the cache window.
32
+ - **The status line could still spawn `ss` from a paint.** `open_ports` and its detail view each ran their own `execSync` with a 3s timeout, duplicating a ladder `src/segments/ports.ts` already owned — a violation of the package's own hot-path contract. Both now read the shared async probe cache (`readPorts()`), serve the last known value, schedule a background refresh, and repaint through a new `subscribePortsUpdates` listener. A stale-but-known count no longer flickers to `?`, and the status line has no blocking process spawn left on it at all. The `/proc/net` fallback moved into the async ladder too (with kernel hex addresses decoded, so an IPv6 loopback bind no longer reads as externally reachable).
33
+ - **User-defined command segments ran `execSync` on every paint** — a custom `{"type": "command"}` segment without `cacheMs` respawned a shell every ~33ms, and one that hung blocked the event loop for up to 5s per paint. Command output now runs in the background behind a defaulted (1000ms) and clamped (100ms–300000ms) cache window, output is capped at 512 characters, the segment serves its last value while a refresh runs, and a repaint is requested when new output arrives. A failing command still surfaces as `!custom:<id>`, one frame later.
34
+ - **`/open-ports` ran `execSync("ss")` with no timeout** — the last remaining copy of the old ports implementation — so a wedged `ss` could still freeze the whole TUI from the command line while the `alt+i` panel was already async. The command now opens the shared panel (bounded probe, parsed table, filter, `r` refresh).
35
+ - **Toggling the ports UDP flag published a stale count**: the toggle changed the probe key, so the synchronous read had nothing cached and exported `?` until an unrelated render happened to refresh. It now awaits the probe before publishing.
36
+ - **Configuration diagnosed as typos**: `wishcraft.hooks`, `wishcraft.policy` and the four editor shortcuts (`powerlineShortcuts.copyEditor`/`cutEditor`/`editorStart`/`editorEnd`) were reported by `/wishcraft doctor` as "no reader consumes this key" although every one of them has a live reader — the registry is the known-set, and they had no entry. The doctor now reads structured roots (`hooks`, `policy`) as known, and the shortcut entries come from the registry itself.
37
+ - **`bashMode` conflicts were invisible**: the root was not managed, so global-vs-project divergence (e.g. different `transcriptMaxLines`) was never reported and typos under it never flagged. `bashMode` is now a managed root with its four known keys.
38
+ - **Ports panel ignored its own segment config**: `alt+i` and `/open-ports` always probed TCP-local even when `powerline.segmentOptions.openPorts` set `includeUdp`/`host`, so the panel and the status segment could disagree about what they were counting. Options now default from the config with explicit overrides still winning.
39
+ - **Settings edited from `/wishcraft settings` did nothing.** Every `status.*` setting writes to `powerline.segmentOptions.<segment>.<option>`, but `parsePowerlineConfig` only ever read the hand-edited top-level buckets (`powerline.tps.*`, `powerline.path.*`, …). A dozen settings — path mode and max length, time format/seconds, git host icons/ahead-behind/latest commit, context format, cache-read format, cost display/currency, UDP ports, TPS window/mode/label — were persisted and then silently ignored. The parser now merges both shapes per segment (nested wins), so the settings UI, hand-edited configs, and the menu's `openPorts` toggle all agree.
40
+ - The coverage gate was not actually enforcing anything: `--test-coverage-lines`/`--test-coverage-functions` do nothing without `--experimental-test-coverage`, so `npm test` printed thresholds while collecting no coverage. The flag is now part of the script and a deliberately impossible threshold demonstrably fails the run.
41
+ - `tr()` did not interpolate its English fallback, so the default locale printed raw `{route}` placeholders in Deck headings.
42
+ - Dutch catalog drift: two message keys referenced from the configuration overlay had differently-named entries, and several entries had no caller.
43
+ - Shortcuts router: a missing `ctx.ui` crashed `getCurrentEditorText` with a TypeError; the accessor now falls through safely to the editor text or an empty string.
44
+
45
+ ### Changed
46
+ - The configuration overlay's three duplicated persist-and-notify blocks (typed edit, choice cycle, toggle) collapsed into one `persist` path, so locale sync, powerline reload and the save/failure toast can no longer drift apart between edit modes.
47
+ - Motion engine (Mijlpaal B1): sub-tick interpolation — repaints between scheduler heartbeats move the travelling head smoothly instead of stepping one cell per tick. `SignalRuntime` records the heartbeat clock (`lastTickAt`) and `renderActivity` interpolates strictly within one interval, so hand-driven ticks (tests) and stale clocks keep exact integer rendering. Glyph frames stay tick-aligned via a fractional-safe `frameAt`.
48
+ - Shared sweep geometry (`src/motion/sweep-cells.ts`): the status rail, gallery preview strip and composer preview now resolve head/trail/track cells through one `buildSweepCells` builder, so the gallery previews exactly what the rail paints. Rendered output is byte-identical to the previous inline loops (pinned by goldens).
49
+ - Compact rail heads round to whole cells under fractional ticks; lab rails (fat-band) floor fractional ticks before painting.
50
+ - Motion craft (Mijlpaal B2) — same surfaces, richer rendering, no new features or catalog entries:
51
+ - The travelling wake now rides a perceptual multi-stop ramp (hot → warm → cool → track) mixed in **Oklab** space, instead of a naive two-stop sRGB lerp that rendered muddy midpoints. The cool stop is derived by rotating the warm hue and dipping lightness, so every palette cools credibly without hardcoding a blue; a test pins that wake lightness falls strictly monotonically. Trail brightness decays with an ease-out glow falloff, so the wake cools like embers instead of stepping through tiers.
52
+ - wave/heat/liquid generator geometries render their wake as a rippling braille sub-cell curve (2×4 dot matrix per cell, still exactly one column) instead of four flat glyph steps; the gallery previews the same curve.
53
+ - Terminal events (success/warning/error) play a one-shot expanding ripple — two fading rings from the rail center — instead of a plain sweep; finite loop, zero frames once settled.
54
+ - Every event switch lands with an ignition punch (fast exponential brightness decay from `startedAt`).
55
+ - Ember/heat heads flicker with layered deterministic value noise (slow breathe + fast crackle, never repeats exactly) instead of two fixed sines.
56
+ - **The Deck frame is bounded**: the center pane and right rail clip at a fixed row budget with an overflow count, and Ideas/Guardrails window around the cursor. A long queue or a large policy list previously grew the box past the bottom of the terminal.
57
+ - **Right rail is now a decision aid**: leads with the latest activity, shows workload (ideas/queue, bash) and only spends space on an **ATTENTION** block when something is actually wrong (skill warnings, guardrails off, context ≥ 90%).
58
+ - Deck home route body reworked into four scannable blocks — session (activity, context bar, look), right now (ideas/queue, bash and policy state, shell), next intent, and quick keys — instead of a thin session stub.
59
+ - Welcome startup: skill/extension/session discovery now happens inside the overlay's delay instead of on the session-start critical path, and the panel heading/bullets resolve through one helper.
60
+ - Deck copy is localised: route descriptions, body headings, list headers, alerts and the per-route footer hints now resolve through `tr()`, keeping their English wording as the fallback.
61
+ - `sanitizeSshHost`/`sshCommand` moved to `src/segments/probe-shell.ts` (re-exported from `segments/system.ts`) so the ports parser and the segments can share them without an import cycle.
62
+ - Dotted setting-path helpers moved to `src/extension/settings/config-paths.ts` so the wizard and diagnostics can share them without importing the overlay (keeps the dependency graph acyclic).
63
+ - Housekeeping: removed the stray `bun.lock` (npm is the package manager of record), added `engines: node >=22.19` to `package.json`, untracked the local harness log `.auto/log.jsonl`, and corrected the Node-version line and `src/` directory list in AGENTS.md.
64
+
5
65
  ## [1.13.0] - 2026-09-25
6
66
 
7
67
  ### Added
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  <p align="center">
2
- <img src="https://raw.githubusercontent.com/GroepOnline/pi-wishcraft/main/banner.png" alt="Pi Wishcraft" width="100%">
2
+ <img src="https://raw.githubusercontent.com/GroepOnline/pi-wishcraft/main/banner.png" alt="Pi Wishcraft — operator cockpit for the Pi coding agent" width="100%">
3
3
  </p>
4
4
 
5
5
  <h1 align="center">Pi Wishcraft</h1>
6
6
 
7
- <p align="center"><strong>Your operator cockpit for Pi.</strong><br>See what the session is doing, park ideas without interrupting it, search skills, switch into Bash, and keep the important controls one keypress away.</p>
7
+ <p align="center"><strong>Your operator cockpit for Pi.</strong><br>A live powerline status bar, idea queue, skill search, sticky Bash, hooks, policy controls and session UX — one keypress away, without leaving the terminal.</p>
8
8
 
9
9
  <p align="center">
10
10
  <a href="https://www.npmjs.com/package/@groeponline/pi-wishcraft"><img src="https://img.shields.io/npm/v/@groeponline/pi-wishcraft.svg" alt="npm version"></a>
@@ -13,7 +13,7 @@
13
13
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-555.svg" alt="MIT license"></a>
14
14
  </p>
15
15
 
16
- <p align="center"><img src="https://raw.githubusercontent.com/GroepOnline/pi-wishcraft/main/docs/images/wishcraft-cockpit-map.svg" alt="Wishcraft cockpit map showing Signal, Deck, idea capture, skills, managed shell and local guardrails around Pi" width="100%"><br><sub>A map of the shipped operator surfaces. Pi remains the agent runtime.</sub></p>
16
+ <p align="center"><img src="https://raw.githubusercontent.com/GroepOnline/pi-wishcraft/main/docs/images/wishcraft-cockpit-map.svg" alt="Wishcraft cockpit map showing Signal, Deck, idea capture, skills, managed shell and local guardrails around Pi" width="100%"><br><sub>The shipped operator surfaces. Pi remains the agent runtime.</sub></p>
17
17
 
18
18
  ## Start in 10 seconds
19
19
 
@@ -21,24 +21,14 @@
21
21
  pi install npm:@groeponline/pi-wishcraft
22
22
  ```
23
23
 
24
- Reload Pi, then press `alt+p` to open the Deck.
25
-
26
- Try the two flows that make Wishcraft click fastest:
24
+ Reload Pi, then press `alt+p` to open the Deck. Two flows make Wishcraft click fastest:
27
25
 
28
26
  ```text
29
27
  # remember to benchmark the new provider path
30
28
  /ideas
31
29
  ```
32
30
 
33
- The `#` line is captured as an idea instead of being sent as a prompt. Your active run keeps going.
34
-
35
- Then open the skill picker:
36
-
37
- ```text
38
- /skills
39
- ```
40
-
41
- Search, inspect and insert a skill without leaving the session.
31
+ The `#` line is captured as an idea instead of being sent as a prompt — your active run keeps going. Then `/skills` opens the picker: search, inspect and insert a skill without leaving the session.
42
32
 
43
33
  ## Why Wishcraft
44
34
 
@@ -48,14 +38,12 @@ Kongming lanterns started as battlefield signals and later carried wishes. Wishc
48
38
 
49
39
  **Portfolio boundary:** Wishcraft owns the operator cockpit and lightweight idea capture. Promote durable work to [`pi-missions`](https://github.com/GroepOnline/pi-missions), then use [`pi-agent-orchestrator`](https://github.com/GroepOnline/pi-agent-orchestrator) when parallel or isolated execution adds value: `idea -> mission -> orchestration run`.
50
40
 
51
- Guides live in [`docs/`](docs/index.md).
52
-
53
41
  ## What you get
54
42
 
55
43
  | Surface | What it does |
56
44
  | --- | --- |
57
45
  | Signal | Motion-aware three-lane operator status: model/Git, live activity/tool state, and context/queue. Default placement is the editor top border; `/signal placement below` moves it. |
58
- | `alt+p` | Wishcraft Deck: session, Signal, skills, ideas, guardrails, appearance. `g` + jump. `/wishcraft settings` is the flat list. `/signal menu` is Navigate / Configure / Status. |
46
+ | `alt+p` | Wishcraft Deck: session, Signal, skills, ideas, guardrails, shell, **ports**, usage, appearance, motion, shortcuts, diagnostics. `g` + jump key. `/wishcraft settings` is the flat list; `/signal menu` is Navigate / Configure / Status. |
59
47
  | `# <idea>` | File-backed inbox. Does not send the prompt. `/ideas` reviews status, tags, and skill insert. `/ideas next` feeds the oldest active idea into the session. |
60
48
  | `alt+s` | Stash the draft, ask something else, get it back when the run finishes. |
61
49
  | `/skills` | Overlay search on name, description, and path. Enter inserts. `/skills doctor` is the health table. `/skills new` writes a SKILL.md from a template. |
@@ -70,27 +58,29 @@ Pi owns the footer chrome, feed scrolling, and input. Wishcraft supplies widgets
70
58
 
71
59
  ## Daily commands
72
60
 
73
- Activates on load. `/signal` toggles it. `/signal <preset>` switches the information layout. `/signal menu` opens Navigate / Configure / Status. `/wishcraft` opens the Deck. Tab completes presets and `placement above|below|toggle`. `/powerline` remains a compatibility alias.
61
+ Activates on load. `/signal` toggles it. `/signal <preset>` switches the information layout. `/wishcraft` opens the Deck. Tab completes presets, `placement above|below|toggle`, and every `/wishcraft` subcommand and setting path. `/powerline` remains a compatibility alias.
74
62
 
75
63
  ```text
76
64
  /signal doctor settings, queue, git, bash, fonts
77
65
  /signal export current preset + layout as JSON
78
66
  /tps live in/out overlay (same ring as the segment)
79
- /tps 40 override POWERLINE_TPS
80
- /usage session / today / week from ~/.pi/agent/wishcraft-usage.json
67
+ /usage session / today / week token ledger
81
68
  /repairs tool-input repair counters
82
- /skills skill manager
83
- /skills doctor health table (broken frontmatter, dupes, unused, budget)
84
- /skills new [name] write a SKILL.md from a template
69
+ /skills skill manager · /skills doctor · /skills new [name]
85
70
  /ideas idea review overlay (status, tags, skill insert)
86
71
  /wishcraft Deck overlay (operator surface)
87
- /wishcraft settings flat settings TUI
88
- /open-ports listening sockets
72
+ /wishcraft get <key> one setting: stored → source → effective
73
+ /wishcraft set <k> <v> validated write (Tab completes paths + values)
74
+ /wishcraft unset <k> remove a stored value, back to default
75
+ /wishcraft settings flat settings TUI · setup · doctor
76
+ /open-ports listening sockets (filter, r refresh, enter copy)
89
77
  /cd <path> continue this conversation in another directory
90
78
  /bash-mode sticky shell (also ctrl+shift+b)
91
79
  /vibe star trek themed working messages
92
80
  ```
93
81
 
82
+ Configuration never needs an editor: `set` validates against the same registry the settings TUI and wizard use, applies immediately, and writes to the file that already owns the key. Structured values (layout, custom segments, policy) stay in `settings.json`. See [Configure from the prompt](docs/configuration.md#configure-from-the-prompt).
83
+
94
84
  Keybinds (`powerlineShortcuts`, applied after `/reload`; `null` disables):
95
85
 
96
86
  ```json
@@ -117,112 +107,22 @@ Keybinds (`powerlineShortcuts`, applied after `/reload`; `null` disables):
117
107
  }
118
108
  ```
119
109
 
120
- `chef` is muted colors, slash separators, live TPS in/out, and TCP port count. Built-in presets: `default`, `minimal`, `compact`, `full`, `nerd`, `ascii`, `chef`. Custom segments, labels, layout, and presets are documented in [docs/configuration.md](docs/configuration.md). For every setting at its default, see [`examples/settings.example.json`](examples/settings.example.json).
110
+ `chef` is muted colors, slash separators, live TPS in/out, and TCP port count. Built-in presets: `default`, `minimal`, `compact`, `full`, `nerd`, `ascii`, `chef`. For every setting at its default, see [`examples/settings.example.json`](examples/settings.example.json).
121
111
 
122
112
  Daily token budget (never blocks a turn):
123
113
 
124
114
  ```json
125
- {
126
- "wishcraft": {
127
- "tokenBudget": { "daily": 500000 }
128
- }
129
- }
115
+ { "wishcraft": { "tokenBudget": { "daily": 500000 } } }
130
116
  ```
131
117
 
132
118
  At 80% the cost segment warns; at 100% it goes red and welcome notifies. `/usage` shows the ledger.
133
119
 
134
- ## Hooks
135
-
136
- Hooks are commands that read JSON on stdin. See [docs/configuration.md](docs/configuration.md) for examples.
137
-
138
- Definitions come from the **global** agent settings file only. Project `.pi/settings.json` cannot install new hook commands. `wishcraft.hooksEnabled: false` disables every hook without deleting the config.
139
-
140
- ```json
141
- {
142
- "wishcraft": {
143
- "hooksEnabled": true,
144
- "hooks": {
145
- "preToolUse": [
146
- { "matcher": "bash", "hooks": [{ "command": "~/.pi/agent/hooks/bash-guard.sh", "timeout": 5 }] }
147
- ],
148
- "postToolUse": [
149
- { "matcher": "write", "hooks": [{ "command": "~/.pi/agent/hooks/write-audit.sh", "timeout": 5 }] }
150
- ],
151
- "sessionStart": [
152
- { "hooks": [{ "command": "~/.pi/agent/hooks/session-git-status.sh", "timeout": 10 }] }
153
- ]
154
- }
155
- }
156
- }
157
- ```
158
-
159
- **Example hook** (exit 2 = deny):
160
-
161
- ```bash
162
- #!/usr/bin/env bash
163
- payload=$(cat)
164
- cmd=$(printf '%s' "$payload" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("tool_input",{}).get("command",""))')
165
- if printf '%s' "$cmd" | grep -Eq '(^|[[:space:]])rm[[:space:]]+(-[a-zA-Z]*[[:space:]]+)*-r[a-zA-Z]*f|-fr[a-zA-Z]*|[[:space:]]/[[:space:]]*$'; then
166
- printf '%s\n' '{"hookSpecificOutput":{"permissionDecision":"deny","permissionDecisionReason":"blocked destructive rm"}}'
167
- echo "blocked destructive rm" >&2
168
- exit 2
169
- fi
170
- exit 0
171
- ```
172
-
173
- **Another example** (append-only, never blocks):
174
-
175
- ```bash
176
- #!/usr/bin/env bash
177
- mkdir -p "$HOME/.pi/agent/logs"
178
- cat >> "$HOME/.pi/agent/logs/write-audit.jsonl"
179
- ```
180
-
181
- **SessionStart example** (extra context, never blocks):
182
-
183
- ```bash
184
- #!/usr/bin/env bash
185
- status=$(git status --short 2>/dev/null | head -n 40)
186
- CTX="$status" python3 - <<'PY'
187
- import json, os
188
- print(json.dumps({
189
- "hookSpecificOutput": {
190
- "additionalContext": "git status:\n" + os.environ.get("CTX", "")
191
- }
192
- }))
193
- PY
194
- ```
195
-
196
- Repairs run on custom/extension tools only, before hooks: drop null optionals, parse JSON-string arrays before wrapping, turn `{}` into `[]` on array keys, wrap bare strings, alias `filePath` / `absolutePath` / `target_file` to `path`, unwrap degenerate markdown auto-links. Core tools (`bash`, `read`, `edit`, `write`, `grep`, `find`, `ls`) are never rewritten. `/repairs` prints the counters.
197
-
198
- ## Policy
199
-
200
- Declarative deny/inject rules live in the global settings file; see [docs/configuration.md](docs/configuration.md).
201
- No shell commands — pure in-process regex. Evaluated before command hooks. `wishcraft.policyEnabled: false` disables policy without deleting rules.
202
-
203
- ```json
204
- {
205
- "wishcraft": {
206
- "policy": [
207
- {
208
- "action": "deny",
209
- "tool": "bash",
210
- "match": "sudo\\s+rm",
211
- "reason": "destructive sudo rm"
212
- },
213
- {
214
- "action": "inject",
215
- "tool": "read",
216
- "pathMatch": "\\.env",
217
- "context": "Do not leak secrets from .env files into the conversation."
218
- }
219
- ]
220
- }
221
- }
222
- ```
120
+ ## Hooks, policy, and guardrails
223
121
 
122
+ Hooks are commands that read JSON on stdin; policy is in-process regex evaluated before them. Definitions live in the **global** settings file only, and `wishcraft.hooksEnabled: false` / `wishcraft.policyEnabled: false` are the kill-switches. Full copy-paste examples — a destructive-`rm` deny hook, an append-only audit hook, a SessionStart git-status hook, and two policy rules — are in [docs/configuration.md](docs/configuration.md#hooks-and-repairs).
224
123
 
225
124
  Privacy/network boundary: ideas, settings, usage ledgers, and normal cockpit state stay local; there is no package-owned telemetry backend. Optional exchange-rate/DeepWiki features and operator-defined hooks cross the network/process boundary only when used.
125
+
226
126
  ## Limits
227
127
 
228
128
  - No mouse on the live footer. Pi core owns that surface.
@@ -231,18 +131,19 @@ Privacy/network boundary: ideas, settings, usage ledgers, and normal cockpit sta
231
131
  - The legacy `@groeponline/pi-powerline-footer` package is deprecated in favor of `@groeponline/pi-wishcraft`.
232
132
  - Tags are not rewritten. 0.19.x through current stay on the timeline.
233
133
 
234
- ## vNext Direction
134
+ ## vNext direction
235
135
 
236
136
  Wishcraft is Pi's animated operator layer. See the [release plan](docs/design/vnext-release-plan.md) and [design corpus](docs/index.md#design-system--vnext-specifications).
137
+
237
138
  ## Docs
238
139
 
239
- - [Commands](docs/commands.md)
240
- - [Configuration](docs/configuration.md)
241
- - [Bash mode](docs/bash-mode.md)
242
- - [Stash and shortcuts](docs/stash-and-shortcuts.md)
243
- - [Skill manager](docs/skill-manager.md)
244
- - [Working vibes](docs/working-vibes.md)
245
- - [Segments and theming](docs/segments.md)
140
+ - [Commands](docs/commands.md) — every slash command and keybind
141
+ - [Configuration](docs/configuration.md) — settings, hooks, policy, custom segments
142
+ - [Segments and theming](docs/segments.md) — presets, colors, separators
143
+ - [Bash mode](docs/bash-mode.md) · [Stash and shortcuts](docs/stash-and-shortcuts.md)
144
+ - [Skill manager](docs/skill-manager.md) · [Working vibes](docs/working-vibes.md)
246
145
  - [ROADMAP](ROADMAP.md)
247
146
 
147
+ Guides live in [`docs/`](docs/index.md).
148
+
248
149
  MIT. Issues: [GroepOnline/pi-wishcraft](https://github.com/GroepOnline/pi-wishcraft/issues).
package/build-stamp.json CHANGED
@@ -1 +1 @@
1
- {"source_sha":"394402d958799308f24ffc284a240b878588a931"}
1
+ {"source_sha":"a7570d9c73e85d4553e6bfbba32e1c76c7d857b9"}
package/docs/commands.md CHANGED
@@ -98,14 +98,20 @@ Pi core renders the footer as static text, so live click is not possible; action
98
98
 
99
99
  - `/tps`: overlay of the live 1s window (same ring as the segment). `/tps <value>` sets `POWERLINE_TPS`
100
100
  - `/usage`: session / today / week overlay from `~/.pi/agent/wishcraft-usage.json`
101
- - `/open-ports`: list listening ports and pick one
101
+ - `/open-ports`: listening sockets in a parsed table — async probe with a bounded timeout, summary line, type to filter, `r` re-probe, Enter copies. Honours `powerline.segmentOptions.openPorts` (UDP + fleet host), so the command, `alt+i`, the classic menu and the Deck all probe the same target. `--udp` forces UDP on for one call
102
102
  - `/powerline doctor`: diagnostics overlay — settings file validity, unknown presets, Nerd Font detection, git polling, bash-mode status, queue file health, and `package.identity`
103
103
  - `/powerline version`: `{ version, source_sha }` from `package.json` (SHA only when release-stamped). See [release.md](./release.md).
104
104
  - `/powerline export`: export the current preset + effective layout + labels as a JSON snippet (Enter copies it to the clipboard)
105
- - `alt+p`: **Wishcraft Deck** — operator overlay (Home, Signal, Skills, Ideas, Guardrails, Appearance, …). `g` then a jump key (`h` home, `s` signal, `a` appearance). Escape closes. `/signal menu` still opens Navigate / Configure / Status.
106
- - `alt+i`: **powerline info**: full open-ports list
107
- - `/wishcraft [route]`: open the Deck at a named route (`appearance`, `skills`, …)
108
- - `/wishcraft settings`: flat settings TUI, including `powerline.appearance.base` and `powerline.motionLevel`
105
+ - `alt+p`: **Wishcraft Deck** — operator overlay (Home, Signal, Skills, Ideas, Guardrails, Shell, Ports, Usage, Appearance, Motion, Shortcuts, Diagnostics). `g` then a jump key (`h` home, `s` signal, `a` appearance, `p` ports). Long lists window around the cursor (↑↓ scrolls, the frame never grows past the screen). On **Ideas**: `enter` cycles idea → in-progress → done, `d` removes, `/` filters. Escape closes. `/signal menu` still opens Navigate / Configure / Status.
106
+ - `alt+i`: **powerline info** — the open-ports panel: async probe (bounded timeout, never blocks the UI), summary line, aligned `PROTO PORT ADDRESS OWNER` table, type to filter, `r` re-probe, Enter copies
107
+ - `/wishcraft [route]`: open the Deck at a named route (`appearance`, `skills`, `ports`, …)
108
+ - `/wishcraft get <setting>`: one line — stored value, which file owns it (project / global / default), the effective value, and a ⚠ explanation when the stored value fails validation. Accepts the dotted path (`powerline.preset`) or the setting id (`status.preset`)
109
+ - `/wishcraft set <setting> <value>`: validated write from the prompt — choices accept a unique prefix (`set motion.level red` → `reduced`), toggles take `on`/`off` (not `true`/`false`), numbers are checked against the registry's bounds, and an empty value on a text setting clears the key. Tab completes subcommands, every registered path, and the values each setting accepts. Changes apply immediately (status line repaints; shortcuts and bash settings after `/reload`)
110
+ - `/wishcraft unset <setting>`: remove the stored key so the default applies again (alias: `reset`)
111
+ - `/wishcraft help`: the one-line grammar. Structured values (`powerline.layout`, `powerline.segments`, `wishcraft.policy`…) stay in settings.json — the CLI refuses them with a pointer instead of writing a broken shape
112
+ - `/wishcraft settings`: flat settings TUI, including `powerline.appearance.base` and `powerline.motionLevel` — shows a live status-line preview, the current setting's hint, and a ⚠ marker on any stored value that fails validation
113
+ - `/wishcraft setup`: first-run wizard — language, status preset, motion level, welcome overlay, then one write to `settings.json`
114
+ - `/wishcraft doctor`: configuration diagnosis on one screen — which settings file wins, shadowed values, near-miss keys, and every value validation discarded (also a section of the Deck's Diagnostics route)
109
115
  - Deck **Motion**: gallery + composer. `t` picks the event, Enter applies, `e` opens the composer
110
116
  - Deck **Skills**: workbench list with health; Enter inserts the skill body
111
117
 
@@ -92,14 +92,16 @@ Segment fields:
92
92
 
93
93
  - `type` (required): `command` | `env` | `static`
94
94
  - `command` (command type): shell command to run; output is trimmed
95
- - `cacheMs` (command type, optional): cache output for N ms to avoid re-spawning a shell every paint
95
+ - `cacheMs` (command type, optional): how long to reuse the previous output before re-running. Defaults to `1000`ms; clamped to `100`–`300000`ms
96
96
  - `env` (env type): environment variable to read
97
97
  - `fallback` (env type, optional): text shown when the variable is unset (omit to hide the segment)
98
98
  - `text` (static type): fixed text
99
99
  - `prefix` (optional): text shown before the value
100
100
  - `color` (optional): Pi theme color (`warning`, `accent`, ...) or hex (`#RRGGBB`)
101
101
 
102
- If a command fails or an env var is unset without a fallback, the segment renders nothing.
102
+ Command segments run **in the background**, never inside a paint: the status line shows the previous output (or nothing on the very first frame) and repaints when the command finishes. A hung command is capped at 5s and its output at 512 characters.
103
+
104
+ If a command fails or an env var is unset without a fallback, the segment renders nothing. A failed command is reported as a fault marker (`!custom:<id>`) on the next paint rather than being silently hidden.
103
105
 
104
106
  ## Custom presets
105
107
 
@@ -281,11 +283,88 @@ Set `powerline.costAlert` to a USD threshold to get a single warning notificatio
281
283
 
282
284
  ## Hooks and repairs
283
285
 
284
- Command hooks live under `wishcraft.hooks` in the **global** agent settings file. `wishcraft.hooksEnabled: false` is the kill-switch. See the README Hooks section for three copy-paste examples (bash-guard, write-audit, SessionStart git-status).
286
+ Command hooks live under `wishcraft.hooks` in the **global** agent settings file. `wishcraft.hooksEnabled: false` is the kill-switch. A hook is any command that reads JSON on stdin; exit code 2 denies the tool call, stdout may return a `hookSpecificOutput` payload. Definitions come from the global file only — project `.pi/settings.json` cannot install new hook commands.
287
+
288
+ ```json
289
+ {
290
+ "wishcraft": {
291
+ "hooksEnabled": true,
292
+ "hooks": {
293
+ "preToolUse": [
294
+ { "matcher": "bash", "hooks": [{ "command": "~/.pi/agent/hooks/bash-guard.sh", "timeout": 5 }] }
295
+ ],
296
+ "postToolUse": [
297
+ { "matcher": "write", "hooks": [{ "command": "~/.pi/agent/hooks/write-audit.sh", "timeout": 5 }] }
298
+ ],
299
+ "sessionStart": [
300
+ { "hooks": [{ "command": "~/.pi/agent/hooks/session-git-status.sh", "timeout": 10 }] }
301
+ ]
302
+ }
303
+ }
304
+ }
305
+ ```
306
+
307
+ **Example hook** (exit 2 = deny):
308
+
309
+ ```bash
310
+ #!/usr/bin/env bash
311
+ payload=$(cat)
312
+ cmd=$(printf '%s' "$payload" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("tool_input",{}).get("command",""))')
313
+ if printf '%s' "$cmd" | grep -Eq '(^|[[:space:]])rm[[:space:]]+(-[a-zA-Z]*[[:space:]]+)*-r[a-zA-Z]*f|-fr[a-zA-Z]*|[[:space:]]/[[:space:]]*$'; then
314
+ printf '%s\n' '{"hookSpecificOutput":{"permissionDecision":"deny","permissionDecisionReason":"blocked destructive rm"}}'
315
+ echo "blocked destructive rm" >&2
316
+ exit 2
317
+ fi
318
+ exit 0
319
+ ```
320
+
321
+ **Another example** (append-only, never blocks):
322
+
323
+ ```bash
324
+ #!/usr/bin/env bash
325
+ mkdir -p "$HOME/.pi/agent/logs"
326
+ cat >> "$HOME/.pi/agent/logs/write-audit.jsonl"
327
+ ```
328
+
329
+ **SessionStart example** (extra context, never blocks):
330
+
331
+ ```bash
332
+ #!/usr/bin/env bash
333
+ status=$(git status --short 2>/dev/null | head -n 40)
334
+ CTX="$status" python3 - <<'PY'
335
+ import json, os
336
+ print(json.dumps({
337
+ "hookSpecificOutput": {
338
+ "additionalContext": "git status:\n" + os.environ.get("CTX", "")
339
+ }
340
+ }))
341
+ PY
342
+ ```
285
343
 
286
- Declarative policy rules (`wishcraft.policy`) live in the same global file. They run in-process before command hooks: **deny** blocks a tool call when input matches a regex; **inject** appends context after a matching read/write path. `wishcraft.policyEnabled: false` disables policy without deleting rules. See the README Policy section for two copy-paste examples.
344
+ Repairs run on custom/extension tools only, before hooks: drop null optionals, parse JSON-string arrays before wrapping, turn `{}` into `[]` on array keys, wrap bare strings, alias `filePath` / `absolutePath` / `target_file` to `path`, unwrap degenerate markdown auto-links. Core tools (`bash`, `read`, `edit`, `write`, `grep`, `find`, `ls`) are never rewritten. `/repairs` prints the counters.
287
345
 
288
- Tool-input repairs apply to custom/extension tools only (`wishcraft.repairsEnabled`, default on). `/repairs` prints the counters.
346
+ Declarative policy rules (`wishcraft.policy`) live in the same global file. They run in-process before command hooks: **deny** blocks a tool call when input matches a regex; **inject** appends context after a matching read/write path. `wishcraft.policyEnabled: false` disables policy without deleting rules. No shell commands — pure in-process regex.
347
+
348
+ ```json
349
+ {
350
+ "wishcraft": {
351
+ "policy": [
352
+ {
353
+ "action": "deny",
354
+ "tool": "bash",
355
+ "match": "sudo\\s+rm",
356
+ "reason": "destructive sudo rm"
357
+ },
358
+ {
359
+ "action": "inject",
360
+ "tool": "read",
361
+ "pathMatch": "\\.env",
362
+ "context": "Do not leak secrets from .env files into the conversation."
363
+ }
364
+ ]
365
+ }
366
+ }
367
+ ```
289
368
 
290
369
  ## Token budget
291
370
 
@@ -372,3 +451,72 @@ Opt-in; defaults match the historical rendering.
372
451
  }
373
452
  }
374
453
  ```
454
+
455
+ ## Where settings live
456
+
457
+ Pi merges two files; the **project** file wins on any key it also defines in the global file.
458
+
459
+ | Scope | Path | Wins over |
460
+ |---|---|---|
461
+ | Global | `~/.pi/agent/settings.json` | — |
462
+ | Project | `<cwd>/.pi/settings.json` | global |
463
+
464
+ `/wishcraft doctor` shows this on one screen: both files' health, every value shadowed by the other file, near-miss keys with a "did you mean" suggestion, and every stored value that validation discards (with the reason and the default that applies instead). The same report is rendered as a section of the Deck's **Diagnostics** route.
465
+
466
+ ## Configure from the prompt
467
+
468
+ Every registered setting is readable and writable without leaving pi — no editor, no `settings.json` detour:
469
+
470
+ ```text
471
+ /wishcraft get powerline.preset # stored · global/project/default → effective
472
+ /wishcraft set powerline.preset chef # validated write, applies immediately
473
+ /wishcraft set motion.level red # unique prefix → reduced
474
+ /wishcraft set powerline.welcome off # toggles take on/off
475
+ /wishcraft unset powerline.preset # back to the default (alias: reset)
476
+ /wishcraft help # the grammar, one line
477
+ ```
478
+
479
+ Tab completes subcommands, every registered path, and the values a setting accepts (`choices` for selects, `on · off` for toggles). The same validation runs everywhere — the CLI, `/wishcraft settings`, the setup wizard and the doctor all read one registry, so a value the CLI accepts is a value the overlay accepts.
480
+
481
+ Deliberate boundaries:
482
+
483
+ - **Scalars only.** Structured values (`powerline.layout`, `powerline.segments`, `wishcraft.policy`, `powerline.presets`) stay in `settings.json`; the CLI refuses them with a pointer instead of writing a broken shape.
484
+ - **Writes land where the key already exists** (project file if it defines the root, otherwise global) — the same precedence `readSettings` uses.
485
+ - **`get` works even when Signal is disabled**; configuration never depends on the status line.
486
+
487
+ Settings the CLI and overlay expose, beyond the presets and segment options: the whole `bashMode.*` group (toggle shortcut, transcript limits, init script), all nine `powerlineShortcuts` bindings, `powerline.costAlert`, `powerline.stashSharpSShortcut`, `powerline.customItemsAuto`, `powerline.queue.retentionHours`, `wishcraft.policyEnabled`, and the git/model/ports segment toggles. `examples/settings.example.json` remains the reference for every key at its default.
488
+
489
+ ## Interface language
490
+
491
+ ```json
492
+ { "wishcraft": { "locale": "nl" } }
493
+ ```
494
+
495
+ `en` (default) or `nl`. The setting appears as **Language** under *Interface* in `/wishcraft settings`, and applies immediately — no restart. Anything unknown, malformed, or region-tagged (`nl-NL`, `en_US`) resolves safely, and a message with no translation falls back to its built-in English string, so switching locale can never blank a surface. Set `PI_WISHCRAFT_LOCALE` to pick a language before settings are read.
496
+
497
+ Localised surfaces: Deck route names and chrome, settings labels/hints/group titles, the configuration overlay, the welcome overlay and its widgets, the setup wizard, and the diagnostics copy. Segment values, model names, branch names and other data are data — they stay as-is.
498
+
499
+ ## First-run setup
500
+
501
+ ```text
502
+ /wishcraft setup
503
+ ```
504
+
505
+ Four questions — language, status preset, motion level, welcome overlay — then a review screen and one write to `settings.json`. Every step is also editable later from `/wishcraft settings`.
506
+
507
+ On the very first launch the welcome panel shows three next steps under **Getting started** instead of a changelog wall. Later launches show the usual changelog delta under **What's new**.
508
+
509
+ ## Segment options: two accepted shapes
510
+
511
+ Segment options may be written either hand-edited at the top level of `powerline`, or nested under `powerline.segmentOptions` (the shape the settings UI writes):
512
+
513
+ ```json
514
+ {
515
+ "powerline": {
516
+ "tps": { "windowMs": 2000 },
517
+ "segmentOptions": { "path": { "mode": "abbreviated" } }
518
+ }
519
+ }
520
+ ```
521
+
522
+ Both are read; when a segment appears in both places the nested `segmentOptions` copy wins for the keys it defines.
package/docs/index.md CHANGED
@@ -4,8 +4,8 @@ This package is a Pi.dev extension, not a standalone website. The README is the
4
4
 
5
5
  ## Guides
6
6
 
7
- - [Commands & interactivity](./commands.md) — `/powerline`, `/tps`, `/usage`, `/queue`, `/idea`, placement, presets, keybinds, and the navigable overlay.
8
- - [Configuration](./configuration.md) — custom items, hooks, repairs, token budget, labels, templates, layout, cost alert, and display formats.
7
+ - [Commands & interactivity](./commands.md) — `/powerline`, `/tps`, `/usage`, `/queue`, `/idea`, `/wishcraft` (get/set/unset, settings, setup, doctor), placement, presets, keybinds, and the navigable overlay.
8
+ - [Configuration](./configuration.md) — configure from the prompt, where settings live, interface language, first-run setup, custom items, hooks, repairs, token budget, labels, templates, layout, cost alert, and display formats.
9
9
  - [Bash mode](./bash-mode.md) — sticky shell, ghost suggestions, and shell config.
10
10
  - [Stash & shortcuts](./stash-and-shortcuts.md) — editor stash, prompt history, clipboard/navigation shortcuts, and shortcut config.
11
11
  - [Skill manager](./skill-manager.md) — browsing, inserting, `/skills doctor`, and `/skills new` templates.