pi-cockpit 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +193 -193
- package/node_modules/pi-maestro-settings-core/package.json +32 -0
- package/node_modules/pi-maestro-settings-core/src/index.ts +1 -0
- package/node_modules/pi-maestro-settings-core/src/public/v1/events.ts +50 -0
- package/node_modules/pi-maestro-settings-core/src/public/v1/i18n.ts +195 -0
- package/node_modules/pi-maestro-settings-core/src/public/v1/index.ts +4 -0
- package/node_modules/pi-maestro-settings-core/src/public/v1/provider.ts +157 -0
- package/node_modules/pi-maestro-settings-core/src/public/v1/schema.ts +219 -0
- package/package.json +10 -5
- package/src/agent-bar.ts +330 -0
- package/src/agent-overlay.ts +344 -337
- package/src/agents-store.ts +22 -3
- package/src/ambient.ts +6 -3
- package/src/bash-bg-overlay.ts +38 -28
- package/src/bash-bg-widget.ts +8 -3
- package/src/capturing-overlay.ts +77 -77
- package/src/claude-editor.ts +17 -1
- package/src/config.ts +12 -1
- package/src/edit-guard.ts +306 -18
- package/src/editor-bottom.ts +14 -12
- package/src/endpoint-store.ts +459 -0
- package/src/footer.ts +33 -10
- package/src/fullscreen-controller.ts +23 -19
- package/src/index.ts +577 -187
- package/src/input-routing.ts +41 -8
- package/src/model-picker.ts +7 -6
- package/src/public/v1/events.ts +11 -0
- package/src/render.ts +43 -23
- package/src/session-bar.ts +7 -170
- package/src/session-detail.ts +32 -7
- package/src/session-tabs.ts +93 -0
- package/src/session-ui-state.ts +185 -0
- package/src/settings/cockpit-provider.ts +160 -13
- package/src/settings/i18n.ts +18 -8
- package/src/settings/locale-state.ts +182 -138
- package/src/settings/native-pi-provider.ts +926 -0
- package/src/settings/settings-shell.ts +330 -202
- package/src/settings-view.ts +29 -1
- package/src/sidebar-controller.ts +6 -5
- package/src/sidebar-render.ts +61 -38
- package/src/split-pane.ts +26 -5
- package/src/stable-reference.ts +5 -0
- package/src/stack-widget.ts +38 -30
- package/src/theme-picker.ts +13 -12
- package/src/thinking-timer.ts +5 -4
- package/src/title-llm.ts +25 -3
- package/src/transcript-selection.ts +4 -3
- package/src/tui-i18n.ts +609 -0
- package/src/types.ts +272 -265
- package/src/viewport-stability.ts +6 -5
- package/src/viewport.ts +8 -3
- package/src/window-bar.ts +94 -0
- package/src/window-thread-view.ts +111 -0
package/README.md
CHANGED
|
@@ -1,193 +1,193 @@
|
|
|
1
|
-
# pi-cockpit
|
|
2
|
-
|
|
3
|
-
A responsive **agent cockpit** for [Pi](https://pi.dev): wide terminals get a docked Maestro operations sidebar, narrow terminals automatically fall back to the existing Todo and Agent widgets, and every layout keeps the Starship-style footer.
|
|
4
|
-
|
|
5
|
-
It is the third plugin of the `pi-maestro-flow` project (alongside `pi-maestro-flow` and `pi-maestro-teammate`). It is installed and registered with `pi-maestro-flow`, but it also runs standalone. Current version: **0.9.1**.
|
|
6
|
-
|
|
7
|
-
The dock is a non-capturing top-right overlay. Cockpit reserves its columns by wrapping the active TUI renderer at runtime, so the Pi workspace reflows instead of rendering underneath it. No Pi source files are modified.
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
┌─ AGENTS · 2 running ─────────────────────────────┐ ← setWidget(aboveEditor)
|
|
11
|
-
│ ⠋ explorer #a1f3c2 map auth read routes.ts │
|
|
12
|
-
│ ⠋ explorer #b9e014 trace jwt read jwt.ts │
|
|
13
|
-
├─ TODO · 1/4 ─────────────────────────────────────┤
|
|
14
|
-
│ 01 ✓ map auth entrypoints │
|
|
15
|
-
│ 02 ⠋ trace jwt verify │
|
|
16
|
-
│ 03 · implement refresh │
|
|
17
|
-
│ 04 · add tests │
|
|
18
|
-
└──────────────────────────────────────────────────┘
|
|
19
|
-
> dispatch a goal… ← editor (Pi native)
|
|
20
|
-
pi/stream-70b · ctx [████░░░░] 42% · $0.52 · 01:23 ← setFooter
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Install
|
|
24
|
-
|
|
25
|
-
`pi-cockpit` comes automatically with the orchestration layer — installing `pi-maestro-flow` pulls `pi-cockpit` and registers it into `settings.packages` on postinstall, no manual setup required. To use it on its own:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
pi install npm:pi-cockpit@0.9.1 # standalone from npm
|
|
29
|
-
# or, for one run:
|
|
30
|
-
pi -e ./packages/pi-cockpit
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## What it shows
|
|
34
|
-
|
|
35
|
-
- **SIDEBAR** — Workflow Session/Run progress, Goal state and budget, Todo tasks, Teammate roster, background jobs, and read-only Team Swarm progress. Empty sections disappear and constrained heights retain current or failed work before secondary detail.
|
|
36
|
-
- **AGENTS** — every running teammate as a table row (status spinner · role · id · label · live tail), sorted running-first. Completed/failed agents show their total duration. On narrow terminals this returns to the below-editor widget.
|
|
37
|
-
- **TODO** — the active plan as numbered rows with four states (done ✓ / in-progress spinner / blocked ! / pending ·). On narrow terminals this returns to the above-editor widget.
|
|
38
|
-
- **Footer** — `provider/model · context gauge · ↑in ↓out · $cost · elapsed · git branch`. `bash_bg` background-job state lives on a **dedicated second footer row** so it no longer competes with the primary line.
|
|
39
|
-
- **Thinking timer** — while the model is thinking, the folded thinking row shows a spinner and running elapsed time; when the run ends, it settles to the actual duration (e.g. `thoughts · 8.4s`).
|
|
40
|
-
- **Quiet mode** — compresses the seven built-in tool calls (read/bash/edit/write/grep/find/ls) into single-line ✓/✗/⋯ summaries and folds thinking blocks. Two glyph sets available: `check` (✓/✗/⋯) and `dot` (●/○/◌). Toggle with `/cockpit quiet`; turning off requires `/reload` to restore native tool renderers.
|
|
41
|
-
|
|
42
|
-
Toggle each block between list and compact with `/cockpit`.
|
|
43
|
-
|
|
44
|
-
## Data sources (and the dependency this implies)
|
|
45
|
-
|
|
46
|
-
| Block | Source | Available on bare Pi? |
|
|
47
|
-
|-------|--------|------------------------|
|
|
48
|
-
| MAESTRO | Versioned `cockpit:maestro-query` / `maestro:ui-snapshot` full snapshots from **pi-maestro-flow** | **No** — Workflow, Goal, and Swarm sections stay hidden |
|
|
49
|
-
| AGENTS | `pi.events` channels `teammate:started` / `teammate:message` / `teammate:complete`, broadcast by **pi-maestro-teammate** | **No** — without that extension no events fire, the block stays hidden |
|
|
50
|
-
| TODO | the `todo-state` snapshot the **pi-maestro-flow** `todo` tool persists after every mutation (re-read on each `tool_execution_end` and on `session_start`) | **No** — without the `todo` tool the block stays hidden |
|
|
51
|
-
| Footer | `ctx.model`, `ctx.getContextUsage()`, session usage totals, `footerData.getGitBranch()` | **Yes** |
|
|
52
|
-
|
|
53
|
-
So on a stock Pi the extension loads without error, the Maestro sections stay empty, and the footer remains available. The roster is **self-accumulated from event deltas**; Todo is back-filled from the latest durable `todo-state`. Workflow, Goal, and Swarm use a versioned full-replacement snapshot with generation fencing and a query path for cold-start recovery.
|
|
54
|
-
|
|
55
|
-
Cockpit has no package dependency on `pi-maestro-flow`. It observes optional producers through public event contracts; removing a producer hides only the matching section.
|
|
56
|
-
|
|
57
|
-
## Configuration
|
|
58
|
-
|
|
59
|
-
`~/.pi/agent/cockpit.json` (created on first run):
|
|
60
|
-
|
|
61
|
-
```json
|
|
62
|
-
{
|
|
63
|
-
"enabled": true,
|
|
64
|
-
"quietMode": false,
|
|
65
|
-
"quietSymbols": "check",
|
|
66
|
-
"agentsMode": "list",
|
|
67
|
-
"todoMode": "list",
|
|
68
|
-
"todoExpanded": false,
|
|
69
|
-
"hideNativeAgents": true,
|
|
70
|
-
"icons": { "mode": "auto" },
|
|
71
|
-
"sidebar": {
|
|
72
|
-
"mode": "auto",
|
|
73
|
-
"width": 40,
|
|
74
|
-
"density": "comfortable"
|
|
75
|
-
},
|
|
76
|
-
"title": {
|
|
77
|
-
"enabled": true,
|
|
78
|
-
"showSession": true,
|
|
79
|
-
"showCwd": false,
|
|
80
|
-
"showModel": false,
|
|
81
|
-
"showThinking": false,
|
|
82
|
-
"showGit": false,
|
|
83
|
-
"showMaestro": false,
|
|
84
|
-
"maxLength": 80
|
|
85
|
-
},
|
|
86
|
-
"theme": ""
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
- `quietMode`: when `true`, compresses built-in tool rendering and folds thinking blocks.
|
|
91
|
-
- `quietSymbols`: `"check"` (✓/✗/⋯) or `"dot"` (●/○/◌) lifecycle glyphs for quiet tool rows.
|
|
92
|
-
- `agentsMode` / `todoMode`: `"list"` or `"compact"`.
|
|
93
|
-
- `todoExpanded`: when `true`, expands the todo widget by default.
|
|
94
|
-
- `hideNativeAgents`: when `true`, clears the teammate extension's own `teammate-agents` widget (it draws a similar list *below* the editor) so the two don't duplicate. On by default.
|
|
95
|
-
- `sidebar.mode`: `"auto"` or `"on"` enables the dock when at least 72 main columns plus 32 sidebar columns fit; `"off"` always uses widgets.
|
|
96
|
-
- `sidebar.width`: persisted dock width, rounded and clamped to `32..56`; default `40`.
|
|
97
|
-
- `sidebar.density`: `"comfortable"` or `"compact"`.
|
|
98
|
-
- `icons.mode`: `"auto"` (detect Nerd Font), `"nerd"`, or `"ascii"`.
|
|
99
|
-
- `title.enabled`: master switch for the terminal tab title (session summary + working state + opt-in tags). On by default.
|
|
100
|
-
- `title.showSession`: include the session summary (the `session_info` name, else a short session id) right after `pi`. On by default.
|
|
101
|
-
- `title.showCwd`: include the working directory after the session. Off by default — the title stays short, since the tab strip has no room for a wall of tags.
|
|
102
|
-
- `title.showModel`: include the active model tag (`m:gpt-5.6-sol`). Off by default.
|
|
103
|
-
- `title.showThinking`: include the thinking level tag (`t:high`); skipped while off. Off by default.
|
|
104
|
-
- `title.showGit`: include the git branch tag (`git:main`, `git:detached`); read synchronously from `.git/HEAD`, so it costs no process spawn. Off by default.
|
|
105
|
-
- `title.showMaestro`: include the Maestro workflow status tag (`wf:running`, `wf:done`). Off by default.
|
|
106
|
-
- `title.maxLength`: hard cap on the composed title; the middle is ellided to keep the head and the working-state tail. Clamped to `20..200`; default `80`.
|
|
107
|
-
- `title.generationModel`: `"provider/model"` (e.g. `"maestro-qwen/qwen3.8-max
|
|
108
|
-
|
|
109
|
-
The tab title is `frame + pi - <session> - <working state>`. The session part follows Claude Code's chain (`sessionTitle ?? agentTitle ?? haikuTitle ?? default`): the `/session name` title wins, otherwise the generated title, otherwise a short session id. The frame is Claude Code's title chrome: `⠂`/`⠐` braille spinner while a turn runs, static `✳` when idle; failure replaces it with `✗`. On quit, Cockpit clears the title so no stale tab label lingers (Claude Code's `CLEAR_TERMINAL_TITLE`).
|
|
110
|
-
- `theme`: named theme override; empty string follows the Pi session theme.
|
|
111
|
-
|
|
112
|
-
## Commands
|
|
113
|
-
|
|
114
|
-
- `/cockpit` — opens the settings overlay.
|
|
115
|
-
- `/maestro-settings` — opens the unified settings shell (Cockpit, Flow, Teammate and integrations).
|
|
116
|
-
- `Alt+J` — opens the background Bash jobs overlay (live status, command, cwd, duration, output tail).
|
|
117
|
-
- `/cockpit sidebar` — reports the current sidebar mode, width, and density.
|
|
118
|
-
- `/cockpit sidebar auto|on|off` — selects dock behavior.
|
|
119
|
-
- `/cockpit sidebar resize` or `Ctrl+Shift+R` — enters temporary Resize mode. Left/Right adjusts one column, Shift+Left/Shift+Right adjusts four, Enter accepts, and Escape rolls back. Mouse reporting is active only during Resize mode.
|
|
120
|
-
- `/cockpit quiet` — toggles quiet mode; `/cockpit bg` shows background jobs.
|
|
121
|
-
- `/theme` — switch theme with live preview; `/theme <name>` applies directly. Pi ships no standalone theme command; cockpit provides one.
|
|
122
|
-
|
|
123
|
-
## Sidebar compatibility
|
|
124
|
-
|
|
125
|
-
The split-pane wrapper depends on Pi's current TUI renderer shape and is verified against Pi `0.83.0`. A render integration failure disables the split and retries the original renderer at full width.
|
|
126
|
-
|
|
127
|
-
Do not enable `pi-cockpit`'s dock and `pi-atelier@0.7.0`'s sidebar together. Both reserve columns by wrapping the same renderer, and `pi-atelier@0.7.0` does not participate in Cockpit's split-owner marker protocol. Use `"sidebar": { "mode": "off" }` when running Atelier.
|
|
128
|
-
|
|
129
|
-
## Terminal feasibility — what this design deliberately does NOT do
|
|
130
|
-
|
|
131
|
-
The original mockup was a browser page; a terminal is an ANSI stream with no DOM, no CSS, no focus, no hover. Four mockup effects are **out of scope** here, with replacements:
|
|
132
|
-
|
|
133
|
-
| Mockup effect | Why it can't work in a TUI | Replacement |
|
|
134
|
-
|---------------|----------------------------|-------------|
|
|
135
|
-
| Input-focus "power-up" glow (`:has(:focus)`) | no focus pseudo-class; `render(width)` can't see focus | the stack's header dot turns accent-green while an agent is running |
|
|
136
|
-
| Hover-to-expand chips/rows | no hover in a terminal | list mode shows everything; compact mode is one line; `/cockpit` toggles |
|
|
137
|
-
| Scanlines / logo light-up animation | no overlay/animation layer | a braille spinner frame, advanced on each redraw |
|
|
138
|
-
| In-stream thinking-collapse / edit progress bar / colored bash stdout | built-in message & built-in tool rendering is **not** replaceable by extensions (`renderCall`/`renderResult` only apply to tools *you* register) | the conversation stream is left to Pi's native renderer — it is context, not a cockpit deliverable |
|
|
139
|
-
|
|
140
|
-
## Claude Code-style interactions (all opt-in, all default off)
|
|
141
|
-
|
|
142
|
-
Three independent settings, each stored in `cockpit.json` and exposed bilingually in `/cockpit` and `/maestro-settings`:
|
|
143
|
-
|
|
144
|
-
| Setting | Default | Applies | What it does |
|
|
145
|
-
|---|---|---|---|
|
|
146
|
-
| `doubleEscapeClearInput` | off | after `/reload` | Press Escape twice quickly to clear a non-empty input draft. The first Escape keeps its native meaning; an empty-draft double-Escape stays pi's rewind/tree action. Requires the Cockpit custom editor (`/reload`). |
|
|
147
|
-
| `fullscreenInput` | off | after `/reload` | Alternate screen with the editor fixed at the bottom and an application-scrolled transcript. Wheel scrolls history while the editor stays put; `↑ n new · click to bottom` appears when new output arrives while you are scrolled up. Replaces terminal-native scrollback/search inside fullscreen. Requires the Cockpit custom editor (`/reload`). |
|
|
148
|
-
| `copyOnSelect` | off | live | Drag inside the fullscreen transcript to select; the visible text is copied to the clipboard on release. Effective only while `fullscreenInput` is active. |
|
|
149
|
-
|
|
150
|
-
Interaction rules:
|
|
151
|
-
|
|
152
|
-
- The three settings are independent; `copyOnSelect` is inert without `fullscreenInput`.
|
|
153
|
-
- The legacy `pinEditorBottom` keeps working in normal mode and is ignored inside fullscreen.
|
|
154
|
-
- If another extension already owns a custom editor, `doubleEscapeClearInput` and `fullscreenInput` fail closed with one warning (they share the Cockpit custom editor) and never overwrite it.
|
|
155
|
-
- A clipboard failure shows a warning and keeps the selection so you can retry.
|
|
156
|
-
|
|
157
|
-
### Terminal capability matrix
|
|
158
|
-
|
|
159
|
-
Fullscreen needs an alternate screen (`?1049`) and SGR mouse reporting (`1006`/`1002`); copy-on-select additionally needs drag selection to be application-owned. No universal support is claimed — this is best effort, opt-in, and `TERM=dumb`/unset is refused with a warning.
|
|
160
|
-
|
|
161
|
-
| Terminal | Alternate screen | SGR mouse | Copy-on-select | Verified |
|
|
162
|
-
|---|---|---|---|---|
|
|
163
|
-
| iTerm2 | ✓ | ✓ | ✓ | expected |
|
|
164
|
-
| Ghostty | ✓ | ✓ | ✓ | expected |
|
|
165
|
-
| WezTerm | ✓ | ✓ | ✓ | expected |
|
|
166
|
-
| kitty | ✓ | ✓ | ✓ | expected |
|
|
167
|
-
| Windows Terminal | ✓ | ✓ | ✓ | expected |
|
|
168
|
-
| VS Code integrated terminal | ✓ | ✓ | ✓ | expected |
|
|
169
|
-
| tmux (no `-T` config) | depends | depends | depends | not claimed |
|
|
170
|
-
| `TERM=dumb` | ✗ | ✗ | ✗ | refused with a warning |
|
|
171
|
-
|
|
172
|
-
### Manual smoke checklist
|
|
173
|
-
|
|
174
|
-
1. `/maestro-settings` → Cockpit → enable `doubleEscapeClearInput`, then `/reload`; type a draft and press Escape twice — the draft clears; a single Escape does nothing; with an empty draft two Escapes still open the tree selector.
|
|
175
|
-
2. Enable `fullscreenInput`, `/reload`; scroll the transcript with the mouse wheel — the editor stays fixed at the bottom; while scrolled up, new output shows the `↑ n new` hint; clicking it returns to the bottom.
|
|
176
|
-
3. Enable `copyOnSelect` (live, no reload); drag across transcript lines — the visible text lands on the clipboard (verify with `pbpaste` on macOS); a plain click does not copy; a copy failure (e.g. headless) shows a warning and keeps the selection.
|
|
177
|
-
4. Toggle everything off and `/reload` — behavior returns to stock pi.
|
|
178
|
-
5. If a terminal ever gets stuck in a blank alternate screen (crash while fullscreen), run `reset` to restore the normal screen.
|
|
179
|
-
|
|
180
|
-
## Local development
|
|
181
|
-
|
|
182
|
-
```bash
|
|
183
|
-
cd packages/pi-cockpit
|
|
184
|
-
npm test
|
|
185
|
-
npm run typecheck
|
|
186
|
-
npm pack --dry-run
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
The package lives inside the `pi-maestro-flow` monorepo under `packages/` so it resolves `@earendil-works/*` types from the root `node_modules`. It is also an exact-pinned dependency of `pi-maestro-flow` and ships as its own npm package (`pi-cockpit`).
|
|
190
|
-
|
|
191
|
-
## License
|
|
192
|
-
|
|
193
|
-
MIT. The split-pane behavior is adapted from `pi-atelier` under its MIT license; attribution is retained in `src/split-pane.ts`.
|
|
1
|
+
# pi-cockpit
|
|
2
|
+
|
|
3
|
+
A responsive **agent cockpit** for [Pi](https://pi.dev): wide terminals get a docked Maestro operations sidebar, narrow terminals automatically fall back to the existing Todo and Agent widgets, and every layout keeps the Starship-style footer.
|
|
4
|
+
|
|
5
|
+
It is the third plugin of the `pi-maestro-flow` project (alongside `pi-maestro-flow` and `pi-maestro-teammate`). It is installed and registered with `pi-maestro-flow`, but it also runs standalone. Current version: **0.9.1**.
|
|
6
|
+
|
|
7
|
+
The dock is a non-capturing top-right overlay. Cockpit reserves its columns by wrapping the active TUI renderer at runtime, so the Pi workspace reflows instead of rendering underneath it. No Pi source files are modified.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─ AGENTS · 2 running ─────────────────────────────┐ ← setWidget(aboveEditor)
|
|
11
|
+
│ ⠋ explorer #a1f3c2 map auth read routes.ts │
|
|
12
|
+
│ ⠋ explorer #b9e014 trace jwt read jwt.ts │
|
|
13
|
+
├─ TODO · 1/4 ─────────────────────────────────────┤
|
|
14
|
+
│ 01 ✓ map auth entrypoints │
|
|
15
|
+
│ 02 ⠋ trace jwt verify │
|
|
16
|
+
│ 03 · implement refresh │
|
|
17
|
+
│ 04 · add tests │
|
|
18
|
+
└──────────────────────────────────────────────────┘
|
|
19
|
+
> dispatch a goal… ← editor (Pi native)
|
|
20
|
+
pi/stream-70b · ctx [████░░░░] 42% · $0.52 · 01:23 ← setFooter
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
`pi-cockpit` comes automatically with the orchestration layer — installing `pi-maestro-flow` pulls `pi-cockpit` and registers it into `settings.packages` on postinstall, no manual setup required. To use it on its own:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pi install npm:pi-cockpit@0.9.1 # standalone from npm
|
|
29
|
+
# or, for one run:
|
|
30
|
+
pi -e ./packages/pi-cockpit
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## What it shows
|
|
34
|
+
|
|
35
|
+
- **SIDEBAR** — Workflow Session/Run progress, Goal state and budget, Todo tasks, Teammate roster, background jobs, and read-only Team Swarm progress. Empty sections disappear and constrained heights retain current or failed work before secondary detail.
|
|
36
|
+
- **AGENTS** — every running teammate as a table row (status spinner · role · id · label · live tail), sorted running-first. Completed/failed agents show their total duration. On narrow terminals this returns to the below-editor widget.
|
|
37
|
+
- **TODO** — the active plan as numbered rows with four states (done ✓ / in-progress spinner / blocked ! / pending ·). On narrow terminals this returns to the above-editor widget.
|
|
38
|
+
- **Footer** — `provider/model · context gauge · ↑in ↓out · $cost · elapsed · git branch`. `bash_bg` background-job state lives on a **dedicated second footer row** so it no longer competes with the primary line.
|
|
39
|
+
- **Thinking timer** — while the model is thinking, the folded thinking row shows a spinner and running elapsed time; when the run ends, it settles to the actual duration (e.g. `thoughts · 8.4s`).
|
|
40
|
+
- **Quiet mode** — compresses the seven built-in tool calls (read/bash/edit/write/grep/find/ls) into single-line ✓/✗/⋯ summaries and folds thinking blocks. Two glyph sets available: `check` (✓/✗/⋯) and `dot` (●/○/◌). Toggle with `/cockpit quiet`; turning off requires `/reload` to restore native tool renderers.
|
|
41
|
+
|
|
42
|
+
Toggle each block between list and compact with `/cockpit`.
|
|
43
|
+
|
|
44
|
+
## Data sources (and the dependency this implies)
|
|
45
|
+
|
|
46
|
+
| Block | Source | Available on bare Pi? |
|
|
47
|
+
|-------|--------|------------------------|
|
|
48
|
+
| MAESTRO | Versioned `cockpit:maestro-query` / `maestro:ui-snapshot` full snapshots from **pi-maestro-flow** | **No** — Workflow, Goal, and Swarm sections stay hidden |
|
|
49
|
+
| AGENTS | `pi.events` channels `teammate:started` / `teammate:message` / `teammate:complete`, broadcast by **pi-maestro-teammate** | **No** — without that extension no events fire, the block stays hidden |
|
|
50
|
+
| TODO | the `todo-state` snapshot the **pi-maestro-flow** `todo` tool persists after every mutation (re-read on each `tool_execution_end` and on `session_start`) | **No** — without the `todo` tool the block stays hidden |
|
|
51
|
+
| Footer | `ctx.model`, `ctx.getContextUsage()`, session usage totals, `footerData.getGitBranch()` | **Yes** |
|
|
52
|
+
|
|
53
|
+
So on a stock Pi the extension loads without error, the Maestro sections stay empty, and the footer remains available. The roster is **self-accumulated from event deltas**; Todo is back-filled from the latest durable `todo-state`. Workflow, Goal, and Swarm use a versioned full-replacement snapshot with generation fencing and a query path for cold-start recovery.
|
|
54
|
+
|
|
55
|
+
Cockpit has no package dependency on `pi-maestro-flow`. It observes optional producers through public event contracts; removing a producer hides only the matching section.
|
|
56
|
+
|
|
57
|
+
## Configuration
|
|
58
|
+
|
|
59
|
+
`~/.pi/agent/cockpit.json` (created on first run):
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"enabled": true,
|
|
64
|
+
"quietMode": false,
|
|
65
|
+
"quietSymbols": "check",
|
|
66
|
+
"agentsMode": "list",
|
|
67
|
+
"todoMode": "list",
|
|
68
|
+
"todoExpanded": false,
|
|
69
|
+
"hideNativeAgents": true,
|
|
70
|
+
"icons": { "mode": "auto" },
|
|
71
|
+
"sidebar": {
|
|
72
|
+
"mode": "auto",
|
|
73
|
+
"width": 40,
|
|
74
|
+
"density": "comfortable"
|
|
75
|
+
},
|
|
76
|
+
"title": {
|
|
77
|
+
"enabled": true,
|
|
78
|
+
"showSession": true,
|
|
79
|
+
"showCwd": false,
|
|
80
|
+
"showModel": false,
|
|
81
|
+
"showThinking": false,
|
|
82
|
+
"showGit": false,
|
|
83
|
+
"showMaestro": false,
|
|
84
|
+
"maxLength": 80
|
|
85
|
+
},
|
|
86
|
+
"theme": ""
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- `quietMode`: when `true`, compresses built-in tool rendering and folds thinking blocks.
|
|
91
|
+
- `quietSymbols`: `"check"` (✓/✗/⋯) or `"dot"` (●/○/◌) lifecycle glyphs for quiet tool rows.
|
|
92
|
+
- `agentsMode` / `todoMode`: `"list"` or `"compact"`.
|
|
93
|
+
- `todoExpanded`: when `true`, expands the todo widget by default.
|
|
94
|
+
- `hideNativeAgents`: when `true`, clears the teammate extension's own `teammate-agents` widget (it draws a similar list *below* the editor) so the two don't duplicate. On by default.
|
|
95
|
+
- `sidebar.mode`: `"auto"` or `"on"` enables the dock when at least 72 main columns plus 32 sidebar columns fit; `"off"` always uses widgets.
|
|
96
|
+
- `sidebar.width`: persisted dock width, rounded and clamped to `32..56`; default `40`.
|
|
97
|
+
- `sidebar.density`: `"comfortable"` or `"compact"`.
|
|
98
|
+
- `icons.mode`: `"auto"` (detect Nerd Font), `"nerd"`, or `"ascii"`.
|
|
99
|
+
- `title.enabled`: master switch for the terminal tab title (session summary + working state + opt-in tags). On by default.
|
|
100
|
+
- `title.showSession`: include the session summary (the `session_info` name, else a short session id) right after `pi`. On by default.
|
|
101
|
+
- `title.showCwd`: include the working directory after the session. Off by default — the title stays short, since the tab strip has no room for a wall of tags.
|
|
102
|
+
- `title.showModel`: include the active model tag (`m:gpt-5.6-sol`). Off by default.
|
|
103
|
+
- `title.showThinking`: include the thinking level tag (`t:high`); skipped while off. Off by default.
|
|
104
|
+
- `title.showGit`: include the git branch tag (`git:main`, `git:detached`); read synchronously from `.git/HEAD`, so it costs no process spawn. Off by default.
|
|
105
|
+
- `title.showMaestro`: include the Maestro workflow status tag (`wf:running`, `wf:done`). Off by default.
|
|
106
|
+
- `title.maxLength`: hard cap on the composed title; the middle is ellided to keep the head and the working-state tail. Clamped to `20..200`; default `80`.
|
|
107
|
+
- `title.generationModel`: `"provider/model"` (e.g. `"maestro-qwen/qwen3.8-max"`) of a model registered with the `/api-manager` command (or any other provider pi resolves). When set, the session title is generated by that model over the first completed turn (user prompt + assistant reply) through its OpenAI-compatible endpoint, with a 10s timeout. Empty (default) uses the offline rule-based extractor instead. Generation is best-effort — on any failure the title silently falls back to the rule-based one. Editable from the `/cockpit` settings overlay (`z` or cursor to the `title gen model` row, Enter, type, Enter to save; empty clears back to rule-based).
|
|
108
|
+
|
|
109
|
+
The tab title is `frame + pi - <session> - <working state>`. The session part follows Claude Code's chain (`sessionTitle ?? agentTitle ?? haikuTitle ?? default`): the `/session name` title wins, otherwise the generated title, otherwise a short session id. The frame is Claude Code's title chrome: `⠂`/`⠐` braille spinner while a turn runs, static `✳` when idle; failure replaces it with `✗`. On quit, Cockpit clears the title so no stale tab label lingers (Claude Code's `CLEAR_TERMINAL_TITLE`).
|
|
110
|
+
- `theme`: named theme override; empty string follows the Pi session theme.
|
|
111
|
+
|
|
112
|
+
## Commands
|
|
113
|
+
|
|
114
|
+
- `/cockpit` — opens the settings overlay.
|
|
115
|
+
- `/maestro-settings` — opens the unified settings shell (Cockpit, Flow, Teammate and integrations).
|
|
116
|
+
- `Alt+J` — opens the background Bash jobs overlay (live status, command, cwd, duration, output tail).
|
|
117
|
+
- `/cockpit sidebar` — reports the current sidebar mode, width, and density.
|
|
118
|
+
- `/cockpit sidebar auto|on|off` — selects dock behavior.
|
|
119
|
+
- `/cockpit sidebar resize` or `Ctrl+Shift+R` — enters temporary Resize mode. Left/Right adjusts one column, Shift+Left/Shift+Right adjusts four, Enter accepts, and Escape rolls back. Mouse reporting is active only during Resize mode.
|
|
120
|
+
- `/cockpit quiet` — toggles quiet mode; `/cockpit bg` shows background jobs.
|
|
121
|
+
- `/theme` — switch theme with live preview; `/theme <name>` applies directly. Pi ships no standalone theme command; cockpit provides one.
|
|
122
|
+
|
|
123
|
+
## Sidebar compatibility
|
|
124
|
+
|
|
125
|
+
The split-pane wrapper depends on Pi's current TUI renderer shape and is verified against Pi `0.83.0`. A render integration failure disables the split and retries the original renderer at full width.
|
|
126
|
+
|
|
127
|
+
Do not enable `pi-cockpit`'s dock and `pi-atelier@0.7.0`'s sidebar together. Both reserve columns by wrapping the same renderer, and `pi-atelier@0.7.0` does not participate in Cockpit's split-owner marker protocol. Use `"sidebar": { "mode": "off" }` when running Atelier.
|
|
128
|
+
|
|
129
|
+
## Terminal feasibility — what this design deliberately does NOT do
|
|
130
|
+
|
|
131
|
+
The original mockup was a browser page; a terminal is an ANSI stream with no DOM, no CSS, no focus, no hover. Four mockup effects are **out of scope** here, with replacements:
|
|
132
|
+
|
|
133
|
+
| Mockup effect | Why it can't work in a TUI | Replacement |
|
|
134
|
+
|---------------|----------------------------|-------------|
|
|
135
|
+
| Input-focus "power-up" glow (`:has(:focus)`) | no focus pseudo-class; `render(width)` can't see focus | the stack's header dot turns accent-green while an agent is running |
|
|
136
|
+
| Hover-to-expand chips/rows | no hover in a terminal | list mode shows everything; compact mode is one line; `/cockpit` toggles |
|
|
137
|
+
| Scanlines / logo light-up animation | no overlay/animation layer | a braille spinner frame, advanced on each redraw |
|
|
138
|
+
| In-stream thinking-collapse / edit progress bar / colored bash stdout | built-in message & built-in tool rendering is **not** replaceable by extensions (`renderCall`/`renderResult` only apply to tools *you* register) | the conversation stream is left to Pi's native renderer — it is context, not a cockpit deliverable |
|
|
139
|
+
|
|
140
|
+
## Claude Code-style interactions (all opt-in, all default off)
|
|
141
|
+
|
|
142
|
+
Three independent settings, each stored in `cockpit.json` and exposed bilingually in `/cockpit` and `/maestro-settings`:
|
|
143
|
+
|
|
144
|
+
| Setting | Default | Applies | What it does |
|
|
145
|
+
|---|---|---|---|
|
|
146
|
+
| `doubleEscapeClearInput` | off | after `/reload` | Press Escape twice quickly to clear a non-empty input draft. The first Escape keeps its native meaning; an empty-draft double-Escape stays pi's rewind/tree action. Requires the Cockpit custom editor (`/reload`). |
|
|
147
|
+
| `fullscreenInput` | off | after `/reload` | Alternate screen with the editor fixed at the bottom and an application-scrolled transcript. Wheel scrolls history while the editor stays put; `↑ n new · click to bottom` appears when new output arrives while you are scrolled up. Replaces terminal-native scrollback/search inside fullscreen. Requires the Cockpit custom editor (`/reload`). |
|
|
148
|
+
| `copyOnSelect` | off | live | Drag inside the fullscreen transcript to select; the visible text is copied to the clipboard on release. Effective only while `fullscreenInput` is active. |
|
|
149
|
+
|
|
150
|
+
Interaction rules:
|
|
151
|
+
|
|
152
|
+
- The three settings are independent; `copyOnSelect` is inert without `fullscreenInput`.
|
|
153
|
+
- The legacy `pinEditorBottom` keeps working in normal mode and is ignored inside fullscreen.
|
|
154
|
+
- If another extension already owns a custom editor, `doubleEscapeClearInput` and `fullscreenInput` fail closed with one warning (they share the Cockpit custom editor) and never overwrite it.
|
|
155
|
+
- A clipboard failure shows a warning and keeps the selection so you can retry.
|
|
156
|
+
|
|
157
|
+
### Terminal capability matrix
|
|
158
|
+
|
|
159
|
+
Fullscreen needs an alternate screen (`?1049`) and SGR mouse reporting (`1006`/`1002`); copy-on-select additionally needs drag selection to be application-owned. No universal support is claimed — this is best effort, opt-in, and `TERM=dumb`/unset is refused with a warning.
|
|
160
|
+
|
|
161
|
+
| Terminal | Alternate screen | SGR mouse | Copy-on-select | Verified |
|
|
162
|
+
|---|---|---|---|---|
|
|
163
|
+
| iTerm2 | ✓ | ✓ | ✓ | expected |
|
|
164
|
+
| Ghostty | ✓ | ✓ | ✓ | expected |
|
|
165
|
+
| WezTerm | ✓ | ✓ | ✓ | expected |
|
|
166
|
+
| kitty | ✓ | ✓ | ✓ | expected |
|
|
167
|
+
| Windows Terminal | ✓ | ✓ | ✓ | expected |
|
|
168
|
+
| VS Code integrated terminal | ✓ | ✓ | ✓ | expected |
|
|
169
|
+
| tmux (no `-T` config) | depends | depends | depends | not claimed |
|
|
170
|
+
| `TERM=dumb` | ✗ | ✗ | ✗ | refused with a warning |
|
|
171
|
+
|
|
172
|
+
### Manual smoke checklist
|
|
173
|
+
|
|
174
|
+
1. `/maestro-settings` → Cockpit → enable `doubleEscapeClearInput`, then `/reload`; type a draft and press Escape twice — the draft clears; a single Escape does nothing; with an empty draft two Escapes still open the tree selector.
|
|
175
|
+
2. Enable `fullscreenInput`, `/reload`; scroll the transcript with the mouse wheel — the editor stays fixed at the bottom; while scrolled up, new output shows the `↑ n new` hint; clicking it returns to the bottom.
|
|
176
|
+
3. Enable `copyOnSelect` (live, no reload); drag across transcript lines — the visible text lands on the clipboard (verify with `pbpaste` on macOS); a plain click does not copy; a copy failure (e.g. headless) shows a warning and keeps the selection.
|
|
177
|
+
4. Toggle everything off and `/reload` — behavior returns to stock pi.
|
|
178
|
+
5. If a terminal ever gets stuck in a blank alternate screen (crash while fullscreen), run `reset` to restore the normal screen.
|
|
179
|
+
|
|
180
|
+
## Local development
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
cd packages/pi-cockpit
|
|
184
|
+
npm test
|
|
185
|
+
npm run typecheck
|
|
186
|
+
npm pack --dry-run
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The package lives inside the `pi-maestro-flow` monorepo under `packages/` so it resolves `@earendil-works/*` types from the root `node_modules`. It is also an exact-pinned dependency of `pi-maestro-flow` and ships as its own npm package (`pi-cockpit`).
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
MIT. The split-pane behavior is adapted from `pi-atelier` under its MIT license; attribution is retained in `src/split-pane.ts`.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-maestro-settings-core",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Versioned Settings and i18n contracts shared by Pi Maestro plugins.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22.19.0"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "node --experimental-transform-types --test \"test/*.test.ts\"",
|
|
11
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
12
|
+
},
|
|
13
|
+
"main": "./src/index.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": "./src/index.ts",
|
|
16
|
+
"./v1": "./src/public/v1/index.ts",
|
|
17
|
+
"./v1/events": "./src/public/v1/events.ts",
|
|
18
|
+
"./v1/provider": "./src/public/v1/provider.ts",
|
|
19
|
+
"./v1/schema": "./src/public/v1/schema.ts",
|
|
20
|
+
"./v1/i18n": "./src/public/v1/i18n.ts"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"src/**/*.ts"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [
|
|
26
|
+
"pi",
|
|
27
|
+
"maestro",
|
|
28
|
+
"settings",
|
|
29
|
+
"i18n"
|
|
30
|
+
],
|
|
31
|
+
"license": "ISC"
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./public/v1/index.ts";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { SupportedSettingsLocale } from "./i18n.ts";
|
|
2
|
+
import type { SettingsContextV1, SettingsProviderV1 } from "./provider.ts";
|
|
3
|
+
import type { SettingsActivationPlan, SettingsResourceRevision, SettingsSnapshot } from "./schema.ts";
|
|
4
|
+
|
|
5
|
+
export const SETTINGS_PROTOCOL_VERSION = 1 as const;
|
|
6
|
+
|
|
7
|
+
export const SETTINGS_DISCOVER_EVENT = "maestro:settings:discover" as const;
|
|
8
|
+
export const SETTINGS_ANNOUNCE_EVENT = "maestro:settings:announce" as const;
|
|
9
|
+
export const SETTINGS_CHANGED_EVENT = "maestro:settings:changed" as const;
|
|
10
|
+
export const SETTINGS_LOCALE_EVENT = "maestro:settings:locale" as const;
|
|
11
|
+
|
|
12
|
+
export interface SettingsDiscoverEventV1 {
|
|
13
|
+
version: typeof SETTINGS_PROTOCOL_VERSION;
|
|
14
|
+
/** Correlates provider announcements with one discovery broadcast. */
|
|
15
|
+
requestId: string;
|
|
16
|
+
context: SettingsContextV1;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface SettingsAnnounceEventV1 {
|
|
20
|
+
version: typeof SETTINGS_PROTOCOL_VERSION;
|
|
21
|
+
requestId?: string;
|
|
22
|
+
providerId: string;
|
|
23
|
+
instanceId: string;
|
|
24
|
+
/** Same-process event buses may carry the provider methods directly. */
|
|
25
|
+
provider: SettingsProviderV1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface SettingsChangedEventV1 {
|
|
29
|
+
version: typeof SETTINGS_PROTOCOL_VERSION;
|
|
30
|
+
providerId: string;
|
|
31
|
+
providerInstanceId: string;
|
|
32
|
+
transactionId?: string;
|
|
33
|
+
changedKeys: readonly string[];
|
|
34
|
+
snapshot?: SettingsSnapshot;
|
|
35
|
+
revisions?: readonly SettingsResourceRevision[];
|
|
36
|
+
activation?: readonly SettingsActivationPlan[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SettingsLocaleEventV1 {
|
|
40
|
+
version: typeof SETTINGS_PROTOCOL_VERSION;
|
|
41
|
+
locale: SupportedSettingsLocale;
|
|
42
|
+
generation: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface SettingsEventMapV1 {
|
|
46
|
+
"maestro:settings:discover": SettingsDiscoverEventV1;
|
|
47
|
+
"maestro:settings:announce": SettingsAnnounceEventV1;
|
|
48
|
+
"maestro:settings:changed": SettingsChangedEventV1;
|
|
49
|
+
"maestro:settings:locale": SettingsLocaleEventV1;
|
|
50
|
+
}
|