@aiwayds/dsh-tui-pi 1.0.0 → 1.0.2
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 +106 -429
- package/README.zh-CN.md +105 -409
- package/cordis.patch.yml +11 -0
- package/lib/index.js +0 -22
- package/lib/index.js.map +1 -1
- package/package.json +2 -1
- package/lib/model-sync.d.ts +0 -122
- package/lib/model-sync.js +0 -256
- package/lib/model-sync.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,223 +2,108 @@
|
|
|
2
2
|
|
|
3
3
|
# dsh-tui-pi
|
|
4
4
|
|
|
5
|
-
pi-style terminal UI for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) — a plugin suite that turns dsh into a pi-like coding
|
|
5
|
+
pi-style terminal UI for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) — a plugin suite that turns dsh into a pi-like coding-agent experience: pi-tui look & feel, dsh slash commands, GitHub light/dark themes and a powerline footer.
|
|
6
6
|
|
|
7
|
-
**Compatibility:** tested against dsh `0.1.1-rc.2
|
|
8
|
-
through an `executeCommand()` compat shim (`src/commands.ts`) that probes the
|
|
9
|
-
arity of `dsh-commands`' `execute()` at runtime — supporting both the pre-rc.8
|
|
10
|
-
3-arg form `(agent, line, signal)` and the current 4-arg form
|
|
11
|
-
`(agent, line, images, signal)`, unchanged since `0.1.0-rc.8`. Verified by unit
|
|
12
|
-
tests plus a live tmux e2e smoke.
|
|
13
|
-
|
|
14
|
-
> 中文说明: [README.zh.md](README.zh.md)
|
|
15
|
-
|
|
16
|
-
## Screenshot
|
|
7
|
+
**Compatibility:** tested against dsh `0.1.1-rc.2`; slash commands keep working across dsh-commands' `execute()` signature change (pre-rc.8 3-arg → current 4-arg).
|
|
17
8
|
|
|
18
9
|
https://github.com/user-attachments/assets/6a7e00bb-1fd0-4bc5-9070-457f1e9fa54d
|
|
19
10
|
|
|
20
|
-
A live
|
|
21
|
-
subagents, think/tool panels and the powerline footer in action.
|
|
22
|
-
([Interactive playback on asciinema](https://asciinema.org/a/BE212ZO8x1zEZyZn))
|
|
11
|
+
*A live recording of a session (MP4, 1.5× speed) — todos, running subagents, think/tool panels and the powerline footer in action.*
|
|
23
12
|
|
|
24
|
-
|
|
13
|
+
## ✨ Features
|
|
25
14
|
|
|
26
|
-
|
|
27
|
-
┌─────────────────────────────────────────────────────────────────────┐
|
|
28
|
-
│ Transcript (scrollable) │
|
|
29
|
-
│ ┌─────────────────────────────────────────────────────────────┐ │
|
|
30
|
-
│ │ 💭 thinking — reasoning in progress │ │
|
|
31
|
-
│ └─────────────────────────────────────────────────────────────┘ │
|
|
32
|
-
│ ⚙ bash python scripts/demo.py … ✔ bash │
|
|
33
|
-
│ ↳ 生成 2 个 todo, 每个 todo 起一个 10s 的 subagent │
|
|
34
|
-
│ ↳ ⠼ Workhorse 10s 任务 · 1.2k token · 19.0s │
|
|
35
|
-
└─────────────────────────────────────────────────────────────────────┘
|
|
36
|
-
┌─ ● Todos (0/8) ────────────────────────────────────────────────────┐
|
|
37
|
-
│ ├─ ☑ 调研 dsh-tui-pi 斜杠命令/补全机制 │
|
|
38
|
-
│ ├─ ◐ 调研 harness ctx.skills API │
|
|
39
|
-
│ └─ ☐ 实现 /skill:<name> 补全并触发 skill │
|
|
40
|
-
└─────────────────────────────────────────────────────────────────────┘
|
|
41
|
-
∴ working… │
|
|
42
|
-
~/github (Full access) │ ⎇ main │
|
|
43
|
-
[ 请输入指令… ] │
|
|
44
|
-
↳ 第一 打slash 命令的时候 显示 /skill:<skill name> 选择后使用 │
|
|
45
|
-
↳ ⠼ 牛马狗 · 1.5m/1m · 635.7s │
|
|
46
|
-
dsh ▸ volc-ark-plan ▸ deepseek-v4-flash ▸ high ▸ 48.7k/1.0M(4.6%) │
|
|
47
|
-
▸ ⚡ CH85.4% ▸ 15 msgs ▸ 11 tools 00:02:13 │
|
|
48
|
-
Esc ×2: stop · Ctrl+C ×2: quit · Ctrl+G: subagents · ↑↓: history │
|
|
49
|
-
└─────────────────────────────────────────────────────────────────────┘
|
|
50
|
-
│ │ │
|
|
51
|
-
│ │ └─ Footer (powerline)
|
|
52
|
-
│ └─ Running subagents (last-request area)
|
|
53
|
-
└─ Todos panel (bordered, above editor)
|
|
54
|
-
```
|
|
15
|
+
> Each item links to its section below — one line for what it gives you.
|
|
55
16
|
|
|
56
|
-
|
|
17
|
+
- [**Footer — live session overview**](#footer) — provider/model, context pressure and the session cache-hit rate at a glance, always in view.
|
|
18
|
+
- [**Think & tool panels**](#think-and-tool-panels) — reasoning and tool activity stay out of the transcript, so the conversation reads clean.
|
|
19
|
+
- [**Subagents**](#subagents) — every running subagent gets a status line; watch and steer it live.
|
|
20
|
+
- [**Ask User Question**](#ask-user-question) — the model can pause and ask you structured questions, answered without leaving the TUI.
|
|
21
|
+
- [**Feishu integration demo**](#feishu-integration-demo) — dsh-tui-pi on the desktop and Feishu/Lark on the phone driving (and answering for) the same dsh session.
|
|
22
|
+
- [**Dynamic context pruning (DCP)**](#dynamic-context-pruning-dcp) — context stays within limits automatically, with zero LLM calls.
|
|
23
|
+
- [**Persistent context**](#persistent-context) — your ground rules ride along on every request, hot-applied with no restart.
|
|
24
|
+
- [**Model profiles & favorites**](#model-profiles-and-favorites) — switch a whole model setup per project and keep the picker small.
|
|
25
|
+
- [**Sessions & resume**](#sessions-and-resume) — sessions stay tidy automatically and resume in a few keystrokes.
|
|
26
|
+
- [**Themes**](#themes) — GitHub light/dark palettes, hot-switchable; `auto` follows your terminal.
|
|
57
27
|
|
|
58
|
-
|
|
28
|
+
---
|
|
59
29
|
|
|
60
|
-
|
|
30
|
+
## Footer
|
|
61
31
|
|
|
62
|
-
|
|
32
|
+
Every number that matters for a session — provider/model route, thinking level, context use, message and tool counts, plus a live clock — sits in one powerline bar pinned at the bottom, with the editor's top border showing your cwd and git branch. You see cost pressure (context %, cache-hit %) and activity without ever leaving the terminal.
|
|
63
33
|
|
|
64
34
|
```
|
|
65
35
|
dsh ▸ volc-ark-plan ▸ deepseek-v4-flash ▸ high ▸ 48.7k/1.0M(4.6%) ▸ ⚡ CH85.4% ▸ 15 msgs ▸ 11 tools 00:02:13
|
|
66
36
|
```
|
|
67
37
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
| Segment | Content |
|
|
71
|
-
|---|---|
|
|
72
|
-
| **Provider** | current `provider/model` route |
|
|
73
|
-
| **Model** | model short-name |
|
|
74
|
-
| **Thinking** | reasoning effort level (`off` / `high` / `max`) |
|
|
75
|
-
| **Context** | `used / max (percent%)` |
|
|
76
|
-
| **Cache-hit** | `CHxx%` — prompt-cache hit rate |
|
|
77
|
-
| **Messages** | total user + assistant messages |
|
|
78
|
-
| **Tools** | total tool invocations |
|
|
79
|
-
| **Clock** | live right-aligned HH:MM:SS (tick every second) |
|
|
80
|
-
|
|
81
|
-
Segments are rendered with [U+E0B0](https://www.nerdfonts.com/cheat-sheet) powerline arrows; the palette is hot-swappable with the current theme.
|
|
82
|
-
|
|
83
|
-
The editor's top border shows the working directory and git branch:
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
~/github (Full access) │ ⎇ main
|
|
87
|
-
```
|
|
38
|
+
**Cache-hit (`CHxx%`)** is the session's cache-hit rate — the share of the session's total billed input traffic that was served from the prompt cache. It is cumulative over the whole session (a provider/model switch does not reset it) and appears only once the session has actually billed any cached tokens. (Layout: [ARCHITECTURE.md](ARCHITECTURE.md).)
|
|
88
39
|
|
|
89
40
|
---
|
|
90
41
|
|
|
91
|
-
|
|
42
|
+
## Think and tool panels
|
|
92
43
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
┌─ 💭 thinking ──────────────────────────────────────────────┐
|
|
97
|
-
│ Actually, I can check list_agents or wait… │
|
|
98
|
-
└────────────────────────────────────────────────────────────┘
|
|
99
|
-
⚙ bash python scripts/demo.py … ✔ bash
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
Key behavior:
|
|
103
|
-
|
|
104
|
-
- **One panel per type** — a single `ThinkPanel` and a single `ToolPanel` exist for the whole run; each event refreshes the panel in place, so there's no transcript churn.
|
|
105
|
-
- **Empty = hidden** — when nothing is active, the panel renders zero rows and disappears.
|
|
106
|
-
- **`dsh-tui.panelHeight`** (default `1`): one borderless row (block id + elapsed + last content line, right-truncated); `5`/`7`/`10` renders a boxed panel; `all` prints the full body.
|
|
107
|
-
- **Delegation tools** (`use_agent`, `subagent`, `workflow`, `ralph`) never open a tool block — their children appear as running-agent lines (see Subagents).
|
|
44
|
+
Live reasoning and tool calls render as fixed panels pinned **above the chat input** instead of scrolling into the transcript, so the conversation thread stays readable. Panels appear only while something is active, and their height is configurable (`dsh-tui.panelHeight`: `1` line, `5`/`7`/`10` boxed rows, or `all`).
|
|
108
45
|
|
|
109
46
|
---
|
|
110
47
|
|
|
111
|
-
|
|
48
|
+
## Subagents
|
|
112
49
|
|
|
113
|
-
Running
|
|
114
|
-
|
|
115
|
-
```
|
|
116
|
-
↳ 创建 2 个 todo, 每个 todo 起一个 10s 的 subagent
|
|
117
|
-
↳ ⠼ Subagent A 10s 任务 · 1.2k token · 19.0s
|
|
118
|
-
↳ ⠼ Subagent B 10s 任务 · 562 token · 6.0s
|
|
119
|
-
```
|
|
50
|
+
Running subagents show as compact one-line status rows below the editor — name, context use, rounds, elapsed — so delegation is visible without opening anything. `Ctrl+G` (or `/subagents`) opens a live transcript viewer; press `Enter` inside it to steer a child with a message. The `● Todos` panel keeps your task tree pinned above the input. Caps (`maxAgents`, `maxRounds`, configured via `/agents` → `l`) keep runaway delegation in check.
|
|
120
51
|
|
|
121
|
-
|
|
52
|
+
---
|
|
122
53
|
|
|
123
|
-
|
|
54
|
+
## Ask User Question
|
|
124
55
|
|
|
125
|
-
|
|
56
|
+
While mid-turn, the model can pause and ask you structured questions via the `ask_user_question` tool; the answering side is a docked panel above the input — no window juggling. One question at a time with tabs for the rest, `Ctrl+T` folds the panel away, double-`Esc` declines. Free text, multi-select, a multi-question review page, bracketed-paste and right-click / `Ctrl+Shift+C` system-clipboard paste are all supported.
|
|
126
57
|
|
|
127
|
-
|
|
58
|
+
See the ask-question flow in action:
|
|
128
59
|
|
|
129
|
-
|
|
130
|
-
┌─ ● Todos (0/8) ──────────────────────────────────────────┐
|
|
131
|
-
│ ├─ ☑ Todo 1: research subagent spawn API │
|
|
132
|
-
│ ├─ ◐ Todo 2: implement /skill:<name> autocomplete │
|
|
133
|
-
│ └─ ☐ Todo 3: add settings panel skills branch │
|
|
134
|
-
└───────────────────────────────────────────────────────────┘
|
|
135
|
-
```
|
|
60
|
+
https://github.com/user-attachments/assets/aa36be36-a508-4f53-ba85-efe0394dab11
|
|
136
61
|
|
|
137
|
-
|
|
62
|
+
---
|
|
138
63
|
|
|
139
|
-
|
|
64
|
+
## Feishu integration demo
|
|
140
65
|
|
|
141
|
-
|
|
66
|
+
dsh-tui-pi on the desktop and Feishu/Lark on the phone driving (and answering for) the same dsh session:
|
|
142
67
|
|
|
143
|
-
|
|
68
|
+
https://github.com/user-attachments/assets/177e8839-523b-487e-b3d1-6d725cd8aba5
|
|
144
69
|
|
|
145
|
-
|
|
70
|
+
https://github.com/user-attachments/assets/c0d7092f-deda-4443-b75a-2bc93bd30d86
|
|
146
71
|
|
|
147
|
-
|
|
148
|
-
- **`maxRounds`** (default 75, `0` = unlimited) — after a child's assistant messages (one per LLM round-trip — the "rounds") reach the cap, the TUI injects one wrap-up directive and never force-stops: a running child receives it at its next step boundary (`steer` — the very next LLM round-trip), an idle child as its own next turn. The injection is visible: the compact line, the Ctrl+G picker row and the viewer header show a `⚡` marker, and the transcript renders the injected message as `⚡ <text>` — so a wrap-up the child LLM ignored can be told apart from one that never fired.
|
|
72
|
+
Demos courtesy of the [dsh-feishu Demos issue](https://github.com/fan56/dsh-feishu/issues/1).
|
|
149
73
|
|
|
150
74
|
---
|
|
151
75
|
|
|
152
|
-
|
|
76
|
+
## Dynamic context pruning (DCP)
|
|
153
77
|
|
|
154
|
-
[
|
|
155
|
-
|
|
156
|
-
`dsh-tui-pi` lists `@aiwayds/dsh-dcp` as a dependency, but **does not mount it** — dsh-dcp ships its own `cordis.patch.yml` (since `@aiwayds/dsh-dcp@0.2.0`). To activate:
|
|
78
|
+
Context stays within the model window automatically: [dsh-dcp](https://github.com/fan56/dsh-dcp) compacts the session **without calling an LLM to summarize**. Mount it once and it runs transparently — the footer's context segment follows the shrink, and inside a subagent each committed compaction shows as a `🧹` notice in the viewer.
|
|
157
79
|
|
|
158
80
|
```sh
|
|
159
81
|
dsh plugin --profile tui add @aiwayds/dsh-dcp
|
|
160
82
|
```
|
|
161
83
|
|
|
162
|
-
Once mounted, DCP runs transparently in the background. The footer's **context** segment prices the current occupancy — the latest request's billed context plus a CJK estimate of messages after it — so after a compaction the next request lands smaller and the display follows it down (the percent is capped at 100, the window being a hard ceiling). The **cache-hit** segment reflects the current provider/model route's cache reuse — the rate is computed per route segment and restarts (hiding until the next billed message) when the provider or model changes.
|
|
163
|
-
|
|
164
|
-
Inside a subagent, a committed compaction is visible too: DCP appends one `user/message` **notice** row per compaction on the child's own log, and the Ctrl+G transcript renders it with a `🧹` marker (distinct from the generic `ⓘ`), with the picker rows carrying the per-child compaction count (`🧹 N×` in the description). Both DCP's `roundInterval` and the TUI's `maxRounds` count the **same** thing — `assistant/message` events, one per LLM round-trip — but act differently: the TUI queues one wrap-up request once a child's count reaches `maxRounds`, while DCP compacts (prunes context) at the next idle boundary once a session's count reaches `roundInterval`. One triggers work, the other frees context.
|
|
165
|
-
|
|
166
84
|
---
|
|
167
85
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
A user-editable markdown file whose content is appended to the **system prompt of the main agent this TUI creates** — borrows pi's `~/.pi/agent/APPEND_SYSTEM.md` convention, dsh side: `$DSH_HOME/APPEND_SYSTEM.md` (default `~/.dsh/APPEND_SYSTEM.md`, honors the same `$DSH_HOME` override as the rest of dsh).
|
|
171
|
-
|
|
172
|
-
- **Hot-applied** — the section provider reads the file at every prompt assembly, so editing the file picks up on the **next request**: no restart, no watcher, no `/reload`.
|
|
173
|
-
- **Auto-seeded on first run** — when the file is missing, the TUI seeds it once at startup from the shipped template `templates/APPEND_SYSTEM.md` (the English orchestrator-identity template: identity, core rules, execution workflow — including the registered-subagents vocabulary rule: "subagent" means the registered subagents only). An existing file is yours — the TUI never overwrites user content; it only appends the marked todo-lifecycle section and (idempotently, by phrase match) the subagents rule when a file does not phrase them yet.
|
|
174
|
-
- **TUI-owned section** — a marked block (`<!-- dsh-tui-pi:todo-lifecycle -->`) is appended once and then maintained idempotently so the model clears its `todo/write` list when every item is done. A marked file is left byte-identical on later startups.
|
|
175
|
-
- **Legacy migration** — the same todo block used to be delivered through `~/.dsh/AGENTS.md`. On startup the TUI strips that block once (no-op when absent), so the guidance is never duplicated.
|
|
176
|
-
- **Empty / unreadable = no section** — if the file is missing or can't be read, the section is silently dropped. No error, no TUI startup failure.
|
|
86
|
+
## Persistent context
|
|
177
87
|
|
|
178
|
-
|
|
88
|
+
`$DSH_HOME/APPEND_SYSTEM.md` (default `~/.dsh/APPEND_SYSTEM.md`, pi convention) is appended to the **main agent's** system prompt and hot-applied — edit the file and the next request sees it, no restart. The TUI seeds it from a template on first run, keeps its marked todo-lifecycle section idempotent, and never overwrites your content. Subagents are deliberately left untouched.
|
|
179
89
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
#### Example
|
|
183
|
-
|
|
184
|
-
```sh
|
|
185
|
-
# Auto-seeded on first run from templates/APPEND_SYSTEM.md — open and edit.
|
|
186
|
-
$EDITOR ~/.dsh/APPEND_SYSTEM.md
|
|
187
|
-
|
|
188
|
-
# Or replace with your own from scratch (the TUI still keeps its marked
|
|
189
|
-
# todo-lifecycle section — it gets re-appended when missing).
|
|
190
|
-
cat > ~/.dsh/APPEND_SYSTEM.md <<'EOF'
|
|
191
|
-
# Project ground rules
|
|
90
|
+
---
|
|
192
91
|
|
|
193
|
-
|
|
194
|
-
- Prefer dispatching `workhorse` for multi-step investigations.
|
|
195
|
-
EOF
|
|
196
|
-
```
|
|
92
|
+
## Model profiles and favorites
|
|
197
93
|
|
|
198
|
-
|
|
94
|
+
`/profile-switch` swaps a whole setup — default model, thinking level and every subagent's model — in one pick; `p` pins a profile to the current directory so every new session in that tree loads it. `/model` favorites and hidden lists keep the picker small. Manage profiles with `/profile-cfg` (roster, edit, save-current, rename, delete).
|
|
199
95
|
|
|
200
96
|
---
|
|
201
97
|
|
|
202
|
-
|
|
98
|
+
## Sessions and resume
|
|
203
99
|
|
|
204
|
-
|
|
100
|
+
`/resume` restores any recent session in a few keystrokes (ordered by last update), `/new` starts fresh, `/export` writes the session log as JSONL (`~/Downloads/dsh-session-<id>.jsonl`). A startup janitor (`dsh-tui.retention.*`) prunes old session logs so the store never grows without bound; the resume picker shows only the working set (`dsh-tui.resume.*`). Both are configurable in `~/.dsh/settings.yaml` with env overrides.
|
|
205
101
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
https://github.com/user-attachments/assets/aa36be36-a508-4f53-ba85-efe0394dab11
|
|
102
|
+
---
|
|
209
103
|
|
|
210
|
-
|
|
211
|
-
- **Ctrl+T folds the panel to a 3-line strip** — the questions panel can block the transcript it stacks on while you think; Ctrl+T collapses it to borders + one summary line (phase, tab position, answered count, how to expand) and the same key unfolds it. While folded only the toggle and the Esc chain act; folding mid-edit commits the buffer like the ↑↓ arrow-exit does.
|
|
212
|
-
- **Single-question fast path** — a lone single-select question submits immediately on Enter: picking an option or committing typed free text both submit right away (a question without options is answered by typing alone). A lone multiSelect question instead gets a `⏎ Confirm answers` row so you can pick several options before submitting.
|
|
213
|
-
- **Multi-question review page** — with ≥ 2 questions a `⏎ Confirm answers` row hops to a review listing every answer, each row editable in place (jumping back re-focuses that question's tab); `Submit answers` commits (Enter on it while an answer is missing flashes a hint instead of failing silently).
|
|
214
|
-
- **Double-Esc declines** — two Esc presses within 200 ms return a declined envelope (the model reads it as a normal reply that no answer was given); holding Esc does not accidentally fire (key auto-repeat below a minimum gap is ignored), and the tool call being aborted settles as declined too. While the panel is open it owns the keyboard exactly like an open overlay: Esc never arms the running-task stop, and app keys (Ctrl+L/G/O, Tab) yield to the panel.
|
|
215
|
-
- **Conservative-use guidance** — a system-prompt section nudges the model to ask only when it genuinely needs you (1–3 questions, 2–4 options each), so the TUI doesn't turn into a questionnaire.
|
|
216
|
-
- **Keyboard** — `←→` switch question tabs · `↑↓` navigate · `Enter` select/toggle/confirm · type into the sentinel for free text · `Ctrl+T` fold/unfold the panel · `Esc` twice to decline.
|
|
217
|
-
- **Paste (bracketed-paste) into the free-text sentinel** — terminals that advertise `?2004` deliver multi-line clipboard content as one bracketed-paste chunk; the sentinel collapses every run of `CR`/`LF`/`CRLF` into a single space, drops C0/C1 control bytes, expands tabs to four spaces, and caps the buffer at 16 KiB — so a pasted paragraph lands as one space-separated run, never a stack of newlines.
|
|
218
|
-
- **Right-click while editing = direct paste from the system clipboard** — the TUI short-circuits SGR right-click presses *before* they reach pi-tui (which would otherwise start a selection drag) and, on `wl-paste`/`xclip`/`xsel`/`pbpaste`/PowerShell, copies the system clipboard into the sentinel's buffer; the helper is fire-and-forget, a missing clipboard tool degrades to a silent no-op, and the OSC 52 write-back runs in parallel so the host terminal's own paste works without the local tool.
|
|
219
|
-
- **`Ctrl+Shift+C` copies the sentinel buffer to the system clipboard** — the kitty-CSI-u encoding `\x1b[<codepoint>;<modifier>u` (modifier 6 = ctrl+shift+1) writes the buffer through OSC 52 *and* `pbcopy`/`wl-copy`/`xclip`/`xsel`/`clip` in parallel; a small `Copied` hint appears under the panel for confirmation, an empty buffer is a silent no-op. *Known limitation:* Apple Terminal maps `Ctrl+Shift+C` to its own copy action before the kitty sequence reaches us, so the in-app copy fires as plain `Ctrl+C` = exit-edit; in tmux, run `set-clipboard on` (and the matching `set-option` for the pane) so the OSC 52 sequence passes through to the host terminal.
|
|
104
|
+
## Themes
|
|
220
105
|
|
|
221
|
-
|
|
106
|
+
GitHub light/dark palettes, hot-switched with `/theme`; `auto` detects your terminal and follows live light/dark switches. `DSH_TUI_THEME=light|dark` pins a scheme, `DSH_TUI_TRANSPARENT=1` makes the canvas see-through, `DSH_TUI_MOUSE=buttons|all|off` tunes mouse tracking.
|
|
222
107
|
|
|
223
108
|
---
|
|
224
109
|
|
|
@@ -226,26 +111,32 @@ Inspired by [juicesharp/rpiv-ask-user-question](https://github.com/juicesharp/rp
|
|
|
226
111
|
|
|
227
112
|
| Command | What it does |
|
|
228
113
|
|---|---|
|
|
229
|
-
| `/model` | Two-stage provider/model picker
|
|
230
|
-
| `/think` | Reasoning-effort picker
|
|
231
|
-
| `/session` | Read-only info
|
|
232
|
-
| `/resume` | Pick a persisted session, validate its log,
|
|
114
|
+
| `/model` | Two-stage provider/model picker + thinking level; `f` favorite, `h` hide, `/` filter (persisted). |
|
|
115
|
+
| `/think` | Reasoning-effort picker (`Off`/`High`/`Max`). |
|
|
116
|
+
| `/session` | Read-only info: id, cwd, model, token usage, event count. |
|
|
117
|
+
| `/resume` | Pick a persisted session (newest first), validate its log, restore it. |
|
|
233
118
|
| `/new` | Detach the current session; the next prompt opens a fresh one. |
|
|
234
|
-
| `/settings` | Text-based settings browser (namespaces, schema walk,
|
|
235
|
-
| `/export` | Write the current session log as JSONL
|
|
119
|
+
| `/settings` | Text-based settings browser (namespaces, schema walk, secrets masked). |
|
|
120
|
+
| `/export` | Write the current session log as JSONL. |
|
|
236
121
|
| `/permission` | Permission-preset picker (read-only / workspace-write / danger-full-access). |
|
|
237
|
-
| `/theme` | Color-scheme picker (`auto
|
|
238
|
-
| `/preset` | Agent-preset picker; `<name>` switches directly, `next` cycles
|
|
239
|
-
| `/profile-switch` |
|
|
240
|
-
| `/profile-cfg` |
|
|
122
|
+
| `/theme` | Color-scheme picker (`auto`/`light`/`dark`), applies immediately. |
|
|
123
|
+
| `/preset` | Agent-preset picker; `<name>` switches directly, `next` cycles (same as `Tab`). |
|
|
124
|
+
| `/profile-switch` | Apply a model profile to the live selection, the persisted default and the agent files; `p` pins the cwd. |
|
|
125
|
+
| `/profile-cfg` | Manage profiles: edit default model / think / per-agent models, `s` save current, `n` new, `r` rename, `d` delete. |
|
|
241
126
|
| `/agents` | Manage agent markdown files + subagent limits (`maxAgents`, `maxRounds`). |
|
|
242
|
-
| `/subagents` | Pick a running/recent subagent and watch its live transcript; `Enter`
|
|
243
|
-
| `/
|
|
244
|
-
| `/
|
|
245
|
-
| `/
|
|
127
|
+
| `/subagents` | Pick a running/recent subagent and watch its live transcript; `Enter` steers it. |
|
|
128
|
+
| `/skills` | Manage user skills (installed and available). |
|
|
129
|
+
| `/reload` | Hot-reload the plugin from source after `pnpm build`. |
|
|
130
|
+
| `/login` | Log in to a provider (or `/login openai`); **Custom provider…** adds any OpenAI/Anthropic-compatible gateway. |
|
|
131
|
+
| `/logout` | Remove a provider's stored key and profile. |
|
|
246
132
|
| `/hotkeys` | Keybinding browser and live editor. |
|
|
247
133
|
|
|
248
|
-
|
|
134
|
+
Model-list auto-sync for hand-declared (baseURL) providers is no longer a
|
|
135
|
+
built-in command: the separate `@aiwayds/dsh-model-sync` plugin (a default
|
|
136
|
+
dependency of this package) keeps those routes' model lists up to date on its
|
|
137
|
+
own schedule.
|
|
138
|
+
|
|
139
|
+
Anything else falls through to the model as an ordinary prompt; dsh-native commands (`plan`, `compact`, `feedback`, `goal`, …) work unchanged.
|
|
249
140
|
|
|
250
141
|
---
|
|
251
142
|
|
|
@@ -254,299 +145,85 @@ Anything that is not a resolvable command falls through to the model as an ordin
|
|
|
254
145
|
| Key | Action |
|
|
255
146
|
|---|---|
|
|
256
147
|
| `Enter` | Send the prompt |
|
|
257
|
-
| `Esc` | **Double-press to stop**
|
|
258
|
-
| `Ctrl+C` | Mid-turn: first press cancels
|
|
259
|
-
| `Ctrl+D` | Quit (only when editor is empty) |
|
|
260
|
-
| `Ctrl+L` | Open model/think picker |
|
|
261
|
-
| `Ctrl+G` | Open subagent picker (
|
|
262
|
-
| `
|
|
263
|
-
|
|
|
264
|
-
|
|
265
|
-
### Custom keybindings
|
|
266
|
-
|
|
267
|
-
Remap any app key through `~/.dsh/keybindings.json` — a partial JSON map of app keys to key ids (`ctrl+letter`, `alt+letter`, named keys). Edit by hand or use `/hotkeys` to change interactively (live-applied, no restart).
|
|
268
|
-
|
|
269
|
-
---
|
|
270
|
-
|
|
271
|
-
## Agent presets
|
|
272
|
-
|
|
273
|
-
The TUI starts with the `standard` agent preset selected when the deployment supplies one; otherwise the first-scanned entry is selected. This is a local selection only: before you interact with `/preset` or press `Tab`, no `meta.agentPreset` is sent at session create, so the server-side default (`agent-presets.default`) governs. The footer brand segment reflects the local selection (`dsh(<name>)`); a switch applies to the next blank session.
|
|
274
|
-
|
|
275
|
-
---
|
|
148
|
+
| `Esc` | **Double-press to stop** (single press arms; a popup open closes it instead) |
|
|
149
|
+
| `Ctrl+C` | Mid-turn: first press cancels, second quits; idle: clears editor / quits. Held-key auto-repeat never quits. |
|
|
150
|
+
| `Ctrl+D` | Quit (only when the editor is empty) |
|
|
151
|
+
| `Ctrl+L` | Open the model/think picker |
|
|
152
|
+
| `Ctrl+G` | Open the subagent picker (viewer `Enter` opens steer) |
|
|
153
|
+
| `Ctrl+O` | Pending-message queue (s steer now · d remove) |
|
|
154
|
+
| `Tab` | Cycle agent presets |
|
|
155
|
+
| `↑` / `↓` | Browse submitted-message history |
|
|
276
156
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
GitHub light / GitHub dark palettes, hot-switchable at runtime:
|
|
280
|
-
|
|
281
|
-
- `/theme` — live picker; the whole screen repaints including background.
|
|
282
|
-
- `DSH_TUI_THEME=light|dark` — env pin that wins over preference.
|
|
283
|
-
- `DSH_TUI_TRANSPARENT=1` — see-through canvas (terminal background shows through).
|
|
284
|
-
- `DSH_TUI_MOUSE=buttons|all|off` — terminal mouse tracking mode (default `buttons`: clicks/wheel/drag keep working, idle pointer movement reports nothing; `all` = pi-tui's all-motion tracking, whose bursts can leak into the editor under cmux; `off` = no mouse).
|
|
285
|
-
- `auto` mode detects the terminal and follows live light/dark switches.
|
|
286
|
-
|
|
287
|
-
The full-screen canvas background ships inside the package — a write-stream
|
|
288
|
-
decorator (`src/canvas-terminal.ts`) paints every erase sequence with the
|
|
289
|
-
theme color via BCE, no patched dependencies.
|
|
157
|
+
Remap any app key through `~/.dsh/keybindings.json` (a partial JSON map, live-applied) or interactively with `/hotkeys`.
|
|
290
158
|
|
|
291
159
|
---
|
|
292
160
|
|
|
293
|
-
##
|
|
294
|
-
|
|
295
|
-
Two knobs clusters govern the session store, both living under the
|
|
296
|
-
`dsh-tui` settings namespace (`~/.dsh/settings.yaml`) with an environment
|
|
297
|
-
escape hatch each:
|
|
298
|
-
|
|
299
|
-
```yaml
|
|
300
|
-
dsh-tui:
|
|
301
|
-
# Startup janitor for ~/.dsh/sessions — DELETES whole session log
|
|
302
|
-
# directories outside the window. Runs once per process at startup.
|
|
303
|
-
retention:
|
|
304
|
-
maxCount: 100 # keep at most this many sessions; <= 0 DISABLES the janitor
|
|
305
|
-
maxAgeDays: 7 # delete logs untouched for more than this many days (> 0)
|
|
306
|
-
minIdleHours: 24 # count-rule-only idle guard in hours (>= 0)
|
|
307
|
-
|
|
308
|
-
# /resume display filter — only HIDES picker rows, never deletes.
|
|
309
|
-
# Resolved fresh at every picker open (a settings change applies to
|
|
310
|
-
# the next /resume, no restart).
|
|
311
|
-
resume:
|
|
312
|
-
maxAgeDays: 7 # only sessions with log activity inside this window (> 0)
|
|
313
|
-
minBytes: 20480 # minimum compressed on-disk log size for a row (>= 0)
|
|
314
|
-
```
|
|
161
|
+
## Configuration
|
|
315
162
|
|
|
316
|
-
|
|
317
|
-
`DSH_TUI_RETENTION_MAX_COUNT` / `DSH_TUI_RETENTION_MAX_AGE_DAYS` /
|
|
318
|
-
`DSH_TUI_RETENTION_MIN_IDLE_HOURS` and `DSH_TUI_RESUME_MAX_AGE_DAYS` /
|
|
319
|
-
`DSH_TUI_RESUME_MIN_BYTES` environment variables > the defaults above.
|
|
320
|
-
An invalid settings value surfaces a transient notice via the shared
|
|
321
|
-
notice bridge (silently dropped when no TUI sink is registered — headless
|
|
322
|
-
runs never print it) and falls to the next level; an invalid env value — a typo
|
|
323
|
-
never widens or guts the policy. `maxCount` and `minBytes` must be
|
|
324
|
-
integers at every layer (a fractional cap or byte floor is garbage, not a
|
|
325
|
-
window).
|
|
326
|
-
|
|
327
|
-
**Disabling retention entirely** — for a long-lived process (a remote
|
|
328
|
-
bridge, a headless cron run) that read-attaches old sessions the default
|
|
329
|
-
window would prune:
|
|
163
|
+
Session-store knobs under the `dsh-tui` settings namespace in `~/.dsh/settings.yaml` (each also has an env override, `DSH_TUI_RETENTION_*` / `DSH_TUI_RESUME_*`; precedence: settings.yaml > env > default):
|
|
330
164
|
|
|
331
165
|
```yaml
|
|
332
166
|
dsh-tui:
|
|
333
|
-
retention:
|
|
334
|
-
maxCount:
|
|
167
|
+
retention: # startup janitor for ~/.dsh/sessions — DELETES old logs. Once per startup.
|
|
168
|
+
maxCount: 100 # <= 0 disables the janitor
|
|
169
|
+
maxAgeDays: 7
|
|
170
|
+
minIdleHours: 24
|
|
171
|
+
resume: # /resume display filter — only HIDES picker rows, never deletes.
|
|
172
|
+
maxAgeDays: 7
|
|
173
|
+
minBytes: 20480
|
|
335
174
|
```
|
|
336
175
|
|
|
337
|
-
|
|
338
|
-
`/reload` does not re-run it — the next cold start does), while the
|
|
339
|
-
**resume filter applies at every `/resume` open**. The two `7`s default
|
|
340
|
-
to the same "one week is the working set" decision but serve different
|
|
341
|
-
masters — retention deletes logs, the resume filter only hides rows.
|
|
176
|
+
Other knobs: `dsh-tui.panelHeight` (think/tool panel height), `dsh-tui.iconSet` (`auto`/`nerdfont`/`plain` — powerline glyphs adapt to your font; install a Nerd Font with `node scripts/install-font.mjs`), `~/.dsh/keybindings.json` (key remaps).
|
|
342
177
|
|
|
343
178
|
---
|
|
344
179
|
|
|
345
|
-
##
|
|
346
|
-
|
|
347
|
-
The TUI's only Private-Use-Area glyph is the powerline segment separator
|
|
348
|
-
(U+E0B0) in the footer — no default terminal font ships it, so a terminal
|
|
349
|
-
without a Nerd/Powerline font shows a tofu box. The `dsh-tui.iconSet`
|
|
350
|
-
setting (`auto` | `nerdfont` | `plain`, default `auto`) adapts the risky
|
|
351
|
-
glyphs (U+E0B0, ⏹, ⭘) to the terminal:
|
|
352
|
-
|
|
353
|
-
- `auto` — powerline glyphs when a Nerd/Powerline font is detected at
|
|
354
|
-
startup, safe Unicode stand-ins (`▸ ■ ●`) otherwise.
|
|
355
|
-
- `nerdfont` — always the powerline glyphs (you already set the font).
|
|
356
|
-
- `plain` — always the safe stand-ins, no font required.
|
|
357
|
-
|
|
358
|
-
**Install the bundled font in one shot** (install + point the terminal at
|
|
359
|
-
it, preserving your font size):
|
|
360
|
-
|
|
361
|
-
```sh
|
|
362
|
-
node scripts/install-font.mjs
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
It copies `assets/fonts/dsh-tui-pi-nerd.ttf` (a ~170KB subset: ASCII +
|
|
366
|
-
U+E0B0 + every symbol the TUI renders) into the user font directory and
|
|
367
|
-
best-effort flips the terminal: macOS iTerm2 (PlistBuddy, default bookmark),
|
|
368
|
-
Linux GNOME Terminal (`gsettings`) and kitty/alacritty/wezterm (config
|
|
369
|
-
file, backed up first). Terminal.app is intentionally skipped (its font is
|
|
370
|
-
a binary blob) — set it by hand. Every step is wrapped: a failure logs a
|
|
371
|
-
warning and moves on, never touching your config destructively.
|
|
372
|
-
|
|
373
|
-
**Or set the font by hand** — any Nerd Font family as the terminal's main
|
|
374
|
-
font (e.g. JetBrainsMono Nerd Font, Hack Nerd Font, or the bundled `DSH TUI
|
|
375
|
-
Nerd` after installing it): iTerm2 → Settings → Profiles → Text → Font;
|
|
376
|
-
Terminal.app → Settings → Profiles → Text; kitty → `font_family`; alacritty
|
|
377
|
-
→ `[font] family`; wezterm → `wezterm.font("…")`. Then `auto` resolves to
|
|
378
|
-
the powerline glyphs on the next start.
|
|
379
|
-
|
|
380
|
-
---
|
|
381
|
-
|
|
382
|
-
## Install (local)
|
|
383
|
-
|
|
384
|
-
The `tui` profile installs this plugin from the npm registry — its
|
|
385
|
-
`package.json` pins `"@aiwayds/dsh-tui-pi": "<version>"`, resolved by pnpm
|
|
386
|
-
like any other dependency. After a release, upgrade the profile with:
|
|
387
|
-
|
|
388
|
-
```sh
|
|
389
|
-
node scripts/dev-upgrade.mjs # latest
|
|
390
|
-
node scripts/dev-upgrade.mjs 0.15.1 --dry-run # preview the plan first
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
The script verifies the version exists on the registry, updates ONLY the
|
|
394
|
-
`"@aiwayds/dsh-tui-pi"` key in `~/.dsh/profiles/tui/package.json`
|
|
395
|
-
(formatting-preserving read-modify-write), runs `pnpm install` there, then
|
|
396
|
-
checks the installed copy reports the target version. It never touches
|
|
397
|
-
`~/.dsh/settings.yaml` or `.credentials.yaml`. Restart dsh (or `/reload`
|
|
398
|
-
inside the TUI) to load the new copy.
|
|
399
|
-
|
|
400
|
-
## Install (npm)
|
|
401
|
-
|
|
402
|
-
Install the full dsh plugin suite into a fresh profile:
|
|
180
|
+
## Install and launch
|
|
403
181
|
|
|
404
182
|
```sh
|
|
405
183
|
dsh plugin --profile tui add @aiwayds/dsh-tui-pi
|
|
406
|
-
dsh plugin --profile tui add @aiwayds/dsh-subagent-registry
|
|
407
|
-
dsh plugin --profile tui add @aiwayds/dsh-dcp
|
|
184
|
+
dsh plugin --profile tui add @aiwayds/dsh-subagent-registry # optional
|
|
185
|
+
dsh plugin --profile tui add @aiwayds/dsh-dcp # optional
|
|
186
|
+
dsh --profile tui # launch (or: dsh-tui-pi)
|
|
408
187
|
```
|
|
409
188
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
```sh
|
|
413
|
-
dsh --profile tui
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
**What happens automatically:**
|
|
417
|
-
|
|
418
|
-
- dsh registers all three plugins in `dsh.profile.bundles` (via `reconcilePlugins`).
|
|
419
|
-
- dsh sets `autoInstallPeers: false` in the profile's `pnpm-workspace.yaml`.
|
|
420
|
-
- On first boot, dsh calls `healProfilesModuleFallback` to create symlinks
|
|
421
|
-
under `~/.dsh/profiles/node_modules/@deepseek-ai/*` → the global dsh
|
|
422
|
-
closure (`$(which dsh)/../../node_modules/@deepseek-ai`). This gives all
|
|
423
|
-
plugins a single `@deepseek-ai/cordis` instance — no manual closure setup
|
|
424
|
-
is needed.
|
|
425
|
-
- `compaction-basic` is disabled by `@aiwayds/dsh-dcp`'s patch; dsh-dcp
|
|
426
|
-
takes over as the compaction backend.
|
|
427
|
-
|
|
428
|
-
**What does NOT happen automatically:**
|
|
429
|
-
|
|
430
|
-
- Nothing patch-related anymore: since 0.8.0 the repo and the npm package
|
|
431
|
-
run the same pristine `@earendil-works/pi-tui` — the canvas background is
|
|
432
|
-
painted by our own write-stream decorator (BCE), which ships in the
|
|
433
|
-
package and needs no `pnpm-workspace.yaml` entries in consumer profiles.
|
|
434
|
-
|
|
435
|
-
### Troubleshooting
|
|
436
|
-
|
|
437
|
-
| Symptom | Cause | Fix |
|
|
438
|
-
|---|---|---|
|
|
439
|
-
| `Cannot find package '<name>' imported from ~/.dsh/profiles/...` | A bundle's `cordis.patch.yml` `name` field doesn't match the scoped package name. | Update the plugin; all `@aiwayds/*` plugins now use `name: '@aiwayds/<pkg>'` in their patch. |
|
|
440
|
-
| `Cannot find package '@deepseek-ai/dsh-client-schema-form'` on npm-installed dsh | The npm-distributed dsh closure is missing that package (upstream packaging gap — [deepseek-harness discussion #3471](https://github.com/deepseek-ai/deepseek-harness/discussions/3471)). | Fixed for this plugin since 0.8.1 (helpers vendored, no import of the missing package). Other plugins needing it: `cd ~/.dsh/profiles/<profile> && pnpm add @deepseek-ai/dsh-client-schema-form@next`. |
|
|
441
|
-
| `Cannot read properties of undefined (reading 'prepare')` | Duplicate `@deepseek-ai/cordis` module instances (two physical copies in the profile tree). | See iron rule 8 in AGENTS.md. Delete physical `~/.dsh/profiles/tui/node_modules/@deepseek-ai` copies and let dsh heal the fallback: `rm -rf ~/.dsh/profiles/tui/node_modules/@deepseek-ai && dsh --profile tui` (the heal recreates them as symlinks). |
|
|
442
|
-
| pnpm `Peer dependencies that should be installed: @deepseek-ai/...` warning | A plugin declares `@deepseek-ai/*` as regular `dependencies` instead of `peerDependencies`. | Update the plugin (all `@aiwayds/*` dsh plugins use optional peerDeps). The warning is harmless — pnpm doesn't auto-install optional peers. |
|
|
443
|
-
| pnpm `Ignored build scripts: @aiwayds/dsh-tui-pi@...` warning | pnpm 10 blocks build scripts by default; the tui-pi postinstall (`link-dsh-closure.mjs`) was skipped. | This is expected and **harmless** — the postinstall only matters for the repo dev flow, not npm consumers. dsh handles closure linking via `healProfilesModuleFallback`. |
|
|
444
|
-
|
|
445
|
-
---
|
|
446
|
-
|
|
447
|
-
## Use
|
|
189
|
+
Everything that used to need manual patching — the canvas background, the `@deepseek-ai` module closure, the compaction backend — now happens automatically. Upgrade an existing profile after a release:
|
|
448
190
|
|
|
449
191
|
```sh
|
|
450
|
-
|
|
192
|
+
node scripts/dev-upgrade.mjs # latest
|
|
193
|
+
node scripts/dev-upgrade.mjs 1.0.2 --dry-run # preview the plan first
|
|
451
194
|
```
|
|
452
195
|
|
|
453
196
|
---
|
|
454
197
|
|
|
455
|
-
## Companion plugins
|
|
456
|
-
|
|
457
|
-
- **[@aiwayds/dsh-ask-router](https://www.npmjs.com/package/@aiwayds/dsh-ask-router)**
|
|
458
|
-
(ships as a default dependency). Owns the single `ctx.userQuestions`
|
|
459
|
-
provider slot and fans every `ask_user_question` out to the interaction
|
|
460
|
-
surfaces bound to the asking session — first answer wins, losing surfaces
|
|
461
|
-
dismiss automatically. Activate it by listing `@aiwayds/dsh-ask-router`
|
|
462
|
-
in the profile's `bundles` **before any UI bundle**; without it the TUI
|
|
463
|
-
panel simply owns questions by itself.
|
|
464
|
-
- **[@aiwayds/dsh-feishu](https://github.com/fan56/dsh-feishu)** (optional).
|
|
465
|
-
Drives an existing dsh session from Feishu/Lark on the phone: round cards,
|
|
466
|
-
interactive `/resume` picker, and an ask-user **card surface** that joins
|
|
467
|
-
the router's fan-out — ask on the desktop, answer on the phone, or both
|
|
468
|
-
render and the first answer wins. Install into the same profile when you
|
|
469
|
-
want phone-side participation; skip it for desktop-only setups. Never
|
|
470
|
-
install the router into a **web** profile (the upstream web apiproxy
|
|
471
|
-
registers its own provider and does not tolerate duplicates).
|
|
472
|
-
|
|
473
|
-
### Feishu integration demo
|
|
474
|
-
|
|
475
|
-
The dsh-feishu companion in action — dsh-tui-pi on the desktop and
|
|
476
|
-
Feishu/Lark on the phone driving (and answering for) the same dsh session:
|
|
477
|
-
|
|
478
|
-
https://github.com/user-attachments/assets/177e8839-523b-487e-b3d1-6d725cd8aba5
|
|
198
|
+
## Companion plugins
|
|
479
199
|
|
|
480
|
-
https://
|
|
481
|
-
|
|
482
|
-
Demos courtesy of the [dsh-feishu Demos issue](https://github.com/fan56/dsh-feishu/issues/1).
|
|
200
|
+
- [@aiwayds/dsh-ask-router](https://www.npmjs.com/package/@aiwayds/dsh-ask-router) — ships as a default dependency; fans every `ask_user_question` out to all answering surfaces (TUI panel, Feishu card) and the first answer wins. List it in the profile's `bundles` before the UI bundles to activate.
|
|
201
|
+
- [@aiwayds/dsh-feishu](https://github.com/fan56/dsh-feishu) — optional; drives the same dsh session from Feishu/Lark on your phone, including an ask-user card surface. Install into the same profile for phone-side participation.
|
|
483
202
|
|
|
484
203
|
---
|
|
485
204
|
|
|
486
|
-
##
|
|
205
|
+
## Development
|
|
487
206
|
|
|
488
207
|
```sh
|
|
489
208
|
pnpm check # tsc --noEmit
|
|
490
209
|
pnpm build # emit lib/
|
|
491
|
-
pnpm test # unit tests, node --test against lib/ (
|
|
210
|
+
pnpm test # unit tests, node --test against lib/ (pretest builds; 1020 tests across 55 files)
|
|
492
211
|
```
|
|
493
212
|
|
|
494
|
-
|
|
495
|
-
dsh closure (`/opt/homebrew/lib/node_modules/@deepseek-ai/dsh/node_modules`);
|
|
496
|
-
those symlinks stay out of any tarball. `scripts/link-dsh-closure.mjs` (the
|
|
497
|
-
package's `postinstall`) re-creates every link after each `pnpm install`.
|
|
498
|
-
|
|
499
|
-
**pi-tui**: pristine `@earendil-works/pi-tui` 0.84.2 from npm — no patches,
|
|
500
|
-
no fork. The full-screen canvas background is our own write-stream decorator
|
|
501
|
-
(`src/canvas-terminal.ts`, BCE).
|
|
502
|
-
|
|
503
|
-
---
|
|
504
|
-
|
|
505
|
-
## Layout
|
|
506
|
-
|
|
507
|
-
```
|
|
508
|
-
bin/dsh-tui-pi launcher shim (exec dsh --profile tui)
|
|
509
|
-
cordis.patch.yml bundle patch: mounts the plugin as `tui-pi`
|
|
510
|
-
src/
|
|
511
|
-
index.ts cordis plugin entry: command registration, footer,
|
|
512
|
-
git watcher, clock, bridge, theme hot-swap, shutdown
|
|
513
|
-
tui.ts alt-screen tree, transcript ScrollView, dock, canvas bg
|
|
514
|
-
session.ts DshSessionBridge: agent create, followup, resume,
|
|
515
|
-
O(1) incremental stats, subagent tracker
|
|
516
|
-
live-widgets.ts Todos panel + running-agent activity lines
|
|
517
|
-
messages.ts TranscriptRenderer: session events → pi-tui components,
|
|
518
|
-
streaming setText, height-configurable panels
|
|
519
|
-
footer.ts PowerlineFooter (7 segments + clock)
|
|
520
|
-
editor.ts CwdBorderEditor (top border: cwd + git branch)
|
|
521
|
-
subagent-policy.ts maxAgents guard + maxRounds wrap-up injection
|
|
522
|
-
(steer-when-running; ⚡-marked, visible in the viewer)
|
|
523
|
-
subagent-viewer.ts Ctrl+G picker + live transcript panel + Enter steer injection
|
|
524
|
-
ask-user.ts Ask User Question docked panel: pure state reducers +
|
|
525
|
-
framed overlay UI + ctx.userQuestions provider
|
|
526
|
-
steer-flow.ts Steer / follow-up decision layer: routed delivery with
|
|
527
|
-
race fallback, queue actions (remove / promote), notices
|
|
528
|
-
route-dialog.ts Submit routing dialog (queue as follow-up vs steer now):
|
|
529
|
-
pure key reducer + framed overlay
|
|
530
|
-
queue-panel.ts Ctrl+O pending-message queue: d remove · s steer now,
|
|
531
|
-
live-refreshed overlay
|
|
532
|
-
theme/ GitHub light/dark palettes + terminal detection
|
|
533
|
-
test/*.test.mjs unit tests (757 across 44 files)
|
|
534
|
-
```
|
|
213
|
+
`pi-tui` runs pristine from npm — no patches, no fork. See [AGENTS.md](AGENTS.md) for the iron rules and quality gates.
|
|
535
214
|
|
|
536
215
|
---
|
|
537
216
|
|
|
538
|
-
##
|
|
217
|
+
## Documentation
|
|
539
218
|
|
|
540
|
-
|
|
219
|
+
- [ARCHITECTURE.md](ARCHITECTURE.md) — full design: process model, layers, data flow.
|
|
220
|
+
- [HANDOFF.md](HANDOFF.md) — session history and current state (Chinese).
|
|
221
|
+
- [CHANGELOG.md](CHANGELOG.md) — release history.
|
|
222
|
+
- [AGENTS.md](AGENTS.md) — working conventions and quality gates for contributors.
|
|
223
|
+
- [docs/](docs/) — design notes (steer/follow-up flow, showcase drafts, …).
|
|
541
224
|
|
|
542
225
|
---
|
|
543
226
|
|
|
544
227
|
## Credits
|
|
545
228
|
|
|
546
|
-
|
|
547
|
-
[juicesharp/rpiv-ask-user-question](https://github.com/juicesharp/rpiv-ask-user-question) —
|
|
548
|
-
the interaction design (numbered option list with a free-text sentinel,
|
|
549
|
-
multi-question review page, decline gesture; since reworked into a
|
|
550
|
-
one-question-at-a-time tab view with a fold-away strip) was adapted to this
|
|
551
|
-
TUI's docked-panel and dsh `userQuestions` provider architecture. All code
|
|
552
|
-
here is original.
|
|
229
|
+
The [Ask User Question](#ask-user-question) interaction is inspired by [juicesharp/rpiv-ask-user-question](https://github.com/juicesharp/rpiv-ask-user-question) (adapted to this TUI's docked-panel and dsh `userQuestions` provider architecture; all code here is original).
|