@xmoon76/dsh-pi-tui 0.3.4 → 0.3.6
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.en.md +655 -0
- package/README.md +563 -466
- package/dist/builtins.mjs +1 -13
- package/dist/extension/advanced.d.mts +1 -1
- package/dist/extension/unstable.d.mts +1 -1
- package/dist/extensions.d.mts +9 -6
- package/dist/extensions.mjs +1 -1
- package/dist/index.d.mts +2 -12
- package/dist/index.mjs +2 -2
- package/dist/{public-types-CZz5_arj.d.mts → public-types-_pe9ZH00.d.mts} +74 -8
- package/dist/{src-B1uP5j0d.mjs → src-Bk66X6NR.mjs} +16568 -2976
- package/package.json +14 -6
- package/README.zh-CN.md +0 -469
- package/scripts/advanced-plugin-smoke.mjs +0 -314
- package/scripts/bench.mts +0 -302
- package/scripts/client-boundary-baseline.json +0 -82
- package/scripts/client-boundary-gate.mjs +0 -165
- package/scripts/e2e-session-lease.sh +0 -388
- package/scripts/examples-plugin-smoke.mjs +0 -320
- package/scripts/extension-fixture-smoke.mjs +0 -219
- package/scripts/naming-gate.mjs +0 -158
- package/scripts/phase4-plugin-smoke.mjs +0 -318
- package/scripts/pre-push-stages.mjs +0 -116
- package/scripts/preview-prompt.mts +0 -62
- package/scripts/preview-role-styles.mts +0 -97
- package/scripts/tarball-smoke.mjs +0 -393
- package/scripts/unstable-plugin-smoke.mjs +0 -300
- package/scripts/vim-plugin-smoke.mjs +0 -315
- /package/dist/{theme-registry-CjbtRmhd.d.mts → keybinding-registry-CjbtRmhd.d.mts} +0 -0
package/README.en.md
ADDED
|
@@ -0,0 +1,655 @@
|
|
|
1
|
+
# dsh-pi-tui
|
|
2
|
+
|
|
3
|
+
[简体中文](README.md) | English
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@xmoon76/dsh-pi-tui)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
A Pi-style terminal frontend for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness).
|
|
9
|
+
|
|
10
|
+
`dsh-pi-tui` is installed as an independent dsh bundle inside a profile. It provides terminal interaction for streaming conversations, tool calls, session management, subagents, history search, shell commands, approvals, and settings. Models, tools, Sessions, permissions, Skills, Plan, Goal, and Subagent runtime behavior are still provided by DeepSeek Harness.
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
dsh plugin --profile pi-tui -- add @xmoon76/dsh-pi-tui
|
|
14
|
+
dsh --profile pi-tui
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
### Conversation and tools
|
|
22
|
+
|
|
23
|
+
* Streaming Markdown output
|
|
24
|
+
* Collapsible Thinking blocks
|
|
25
|
+
* Tool Call cards with running / success / failure state
|
|
26
|
+
* Collapsible Tool / System details
|
|
27
|
+
* Full-text Transcript search
|
|
28
|
+
* Folding for long Session history
|
|
29
|
+
* Context, token, model, and runtime status
|
|
30
|
+
* Approval and `ask_user_question` dialogs
|
|
31
|
+
* Plan Review
|
|
32
|
+
* Todo / Goal status
|
|
33
|
+
* Human-readable terminal window titles
|
|
34
|
+
* Bounded long-session windows with stable paging and live-follow position
|
|
35
|
+
* No duplicate ghost Tool Cards after compaction / pruning
|
|
36
|
+
|
|
37
|
+
`Ctrl+O` controls Tool and System details — and in fullscreen Focus it bulk-expands the recent Thought roots or collapses them all. `Alt+T` controls Thinking separately.
|
|
38
|
+
|
|
39
|
+
### Focus Mode
|
|
40
|
+
|
|
41
|
+
`/focus` groups the current turn's Thinking, Tool Calls, and intermediate replies into a live Thought block.
|
|
42
|
+
|
|
43
|
+
The full process can still be expanded when needed. In fullscreen Focus, Thought roots can be expanded/collapsed in bulk or opened with an individual card click, and the viewport survives switches and resizes. Disabling Focus restores the normal Transcript projection. Focus only changes presentation; it does not modify Session events.
|
|
44
|
+
|
|
45
|
+
### Sessions
|
|
46
|
+
|
|
47
|
+
Supports persisted DSH Sessions, including:
|
|
48
|
+
|
|
49
|
+
* Creating and resuming Sessions
|
|
50
|
+
* Session switching
|
|
51
|
+
* Renaming
|
|
52
|
+
* Forking
|
|
53
|
+
* Rewind
|
|
54
|
+
* Session lineage
|
|
55
|
+
* Transcript export
|
|
56
|
+
|
|
57
|
+
Use:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
/sessions
|
|
61
|
+
/fork
|
|
62
|
+
/rewind
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
When the Agent is idle and the editor is empty, pressing `Esc` twice quickly also opens Rewind.
|
|
66
|
+
|
|
67
|
+
Rewind creates a new Child Session from a selected historical User Turn and restores that Prompt into the editor. The original Session is left unchanged.
|
|
68
|
+
|
|
69
|
+
### Input history
|
|
70
|
+
|
|
71
|
+
`Ctrl+R` opens input history search.
|
|
72
|
+
|
|
73
|
+
Three scopes are available:
|
|
74
|
+
|
|
75
|
+
* Current session
|
|
76
|
+
* Current directory
|
|
77
|
+
* All directories
|
|
78
|
+
|
|
79
|
+
History results include the Prompt, working directory, timestamp, and Session information. Selecting an entry restores it to the editor without submitting it.
|
|
80
|
+
|
|
81
|
+
Regular `↑` / `↓` history recall is still available for recent input.
|
|
82
|
+
|
|
83
|
+
### Subagents and background tasks
|
|
84
|
+
|
|
85
|
+
`/tasks` opens the task browser for the current Session.
|
|
86
|
+
|
|
87
|
+
Subagents are shown using their complete lineage, including nested descendants:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
main
|
|
91
|
+
├─ subagent A
|
|
92
|
+
│ └─ subagent B
|
|
93
|
+
└─ subagent C
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The browser distinguishes:
|
|
97
|
+
|
|
98
|
+
* `continuable`
|
|
99
|
+
* `one-shot`
|
|
100
|
+
* running / inactive
|
|
101
|
+
* nested descendants
|
|
102
|
+
* background Jobs
|
|
103
|
+
|
|
104
|
+
Completed one-shot Subagents remain available for persisted Transcript inspection.
|
|
105
|
+
|
|
106
|
+
A direct `continuable` Child can be opened in an interactive viewer and sent follow-up messages directly. The Child has its own Transcript, Draft, and runtime state, without modifying the main Session input.
|
|
107
|
+
|
|
108
|
+
Deeper nested Subagents are read-only by default.
|
|
109
|
+
|
|
110
|
+
### Shell
|
|
111
|
+
|
|
112
|
+
The editor supports two Shell modes:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
! git status
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Runs a local command and submits its output into the current Session.
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
!! git status
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Runs the command locally only. Its output is not added to model context.
|
|
125
|
+
|
|
126
|
+
`!` / `!!` are editor modes rather than plain text prefixes. The prompt and completion behavior switch together with the active mode.
|
|
127
|
+
|
|
128
|
+
Shell cards show a bounded output preview by default. `Ctrl+O` expands the retained output — except in fullscreen Focus, where Ctrl+O owns the Thought roots and the shell cards keep their folded state.
|
|
129
|
+
|
|
130
|
+
### File references and images
|
|
131
|
+
|
|
132
|
+
Typing `@` opens workspace file search and completion:
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
@src/index.ts
|
|
136
|
+
@"path with spaces/file.ts"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`/image <path>` also completes files and directories; paths with spaces, quotes, or Windows separators preserve the input dialect, and directories can be expanded further.
|
|
140
|
+
|
|
141
|
+
Resolvable relative paths are canonicalized before submission.
|
|
142
|
+
|
|
143
|
+
Clipboard images can be added with `Ctrl+V` and persisted through the DSH Attachment service.
|
|
144
|
+
|
|
145
|
+
### Models and runtime settings
|
|
146
|
+
|
|
147
|
+
The TUI uses DSH model and settings services.
|
|
148
|
+
|
|
149
|
+
Common entry points:
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
/model
|
|
153
|
+
/settings
|
|
154
|
+
/login
|
|
155
|
+
/permission
|
|
156
|
+
/plan
|
|
157
|
+
/goal
|
|
158
|
+
/compact
|
|
159
|
+
/footer
|
|
160
|
+
/statusline
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Model selection, Reasoning Effort, permission presets, Plan, and Goal all keep the corresponding DSH runtime semantics.
|
|
164
|
+
|
|
165
|
+
The `Icon style` option in `/settings` switches the TUI's structural icons:
|
|
166
|
+
`Emoji` (default, colorful), `Symbols` (compact single-cell terminal
|
|
167
|
+
symbols), or `Minimal` (decorative icons hidden; only status/interaction
|
|
168
|
+
markers remain). Switching applies immediately and persists.
|
|
169
|
+
|
|
170
|
+
Slash Commands registered by other plugins through `ctx.commands` are discovered automatically.
|
|
171
|
+
|
|
172
|
+
### Footer customization
|
|
173
|
+
|
|
174
|
+
The status line is a **composable surface** — no plugin or shell needed
|
|
175
|
+
for the common cases.
|
|
176
|
+
|
|
177
|
+
`/settings` → Status line (or the `footer` key in the `dsh-pi-tui`
|
|
178
|
+
settings document) selects the preset:
|
|
179
|
+
|
|
180
|
+
| Value | Meaning |
|
|
181
|
+
|---|---|
|
|
182
|
+
| `default` (legacy `full`) | the classic two-row footer (status + stats) |
|
|
183
|
+
| `compact` | the status row only (stats line hidden) |
|
|
184
|
+
| `custom` | a versioned `footerLayout` (see below) |
|
|
185
|
+
| `command` | a user-configured command renders the status surface (see below) |
|
|
186
|
+
|
|
187
|
+
The first three values are selectable in the `/settings` panel; `command`
|
|
188
|
+
is NOT in the panel — it can only be enabled through the USER-layer
|
|
189
|
+
settings document (`footer: "command"` + `footerCommand`). The `/settings`
|
|
190
|
+
Status line row offers exactly `default / compact / custom`.
|
|
191
|
+
|
|
192
|
+
`/footer` is a hierarchical interactive configurator: pick a row first
|
|
193
|
+
(Row Selector), then edit that row's items — `↑/↓` walks every item of
|
|
194
|
+
the row in order (Left/Right are visual grouping only), `←/→` moves an
|
|
195
|
+
item across sides, `Space` removes it, `A` opens a searchable Add Picker
|
|
196
|
+
(filtered by label / id / description, with the highlighted item's
|
|
197
|
+
description below), `M` enters Move Mode to reorder, and `Enter` opens
|
|
198
|
+
the Item Editor (Style candidates previewed with the item's real render;
|
|
199
|
+
semantic tones; Advanced edits prefix / suffix / importance with a
|
|
200
|
+
one-keystroke Reset). The preview is composed by the real footer engine
|
|
201
|
+
and — with the contextual help — pinned to the top of the panel; it never
|
|
202
|
+
scrolls away at any terminal size. `S` on the Row Selector saves
|
|
203
|
+
(persisted); `Esc` walks back page by page and closes on the first page
|
|
204
|
+
without touching the active layout. With dirty changes, `Esc` first offers
|
|
205
|
+
Save & Exit, Discard & Exit, or Keep Editing; saving waits for the settings
|
|
206
|
+
write to succeed. Usable before any session exists.
|
|
207
|
+
|
|
208
|
+
The Add Picker also offers `+ Create Custom Text` for user-defined static text items. Their text, default semantic tone, display name, and deletion are editable; definitions are read and persisted only from the USER layer. The definition tone is separate from the placement Tone, and the item can otherwise be shown/hidden, moved, and reordered like any other footer item.
|
|
209
|
+
|
|
210
|
+
`footerLayout` is a nested settings object (schemaVersion 1, 1–2 rows,
|
|
211
|
+
left/right zones, a separator, finite formatters, semantic tones,
|
|
212
|
+
prefix/suffix, importance). The `/footer` configurator builds it
|
|
213
|
+
interactively; the YAML shape is:
|
|
214
|
+
|
|
215
|
+
```yaml
|
|
216
|
+
footer: custom
|
|
217
|
+
footerLayout:
|
|
218
|
+
schemaVersion: 1
|
|
219
|
+
rows:
|
|
220
|
+
- left:
|
|
221
|
+
- id: agent-preset
|
|
222
|
+
format: compact
|
|
223
|
+
- id: model
|
|
224
|
+
- id: project
|
|
225
|
+
- id: context
|
|
226
|
+
format: full
|
|
227
|
+
- id: cache-hit
|
|
228
|
+
- id: token-usage
|
|
229
|
+
format: io
|
|
230
|
+
- id: performance
|
|
231
|
+
format: speed
|
|
232
|
+
- id: version
|
|
233
|
+
format: tui
|
|
234
|
+
right:
|
|
235
|
+
- id: focus-mode
|
|
236
|
+
separator:
|
|
237
|
+
text: " │ "
|
|
238
|
+
tone: textDim
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Builtin format choices are finite and use the existing `format` field (no
|
|
242
|
+
second style schema): Model `badge` / `plain` / `compact`; Permission preset
|
|
243
|
+
`badge` / `plain` / `compact`; Plan state `badge` / `plain`; Working directory
|
|
244
|
+
`short` / `basename` / `full`; Git branch `plain` / `label`; Context `bar` /
|
|
245
|
+
`percent` / `full`; Token usage `io` / `total` / `compact`; Cache hit `full` /
|
|
246
|
+
`compact`; Performance `full` / `speed` / `latency` measures average time
|
|
247
|
+
to first token; Turns/steps `both` / `turns` / `steps`; Version keeps `tui` / `dsh` /
|
|
248
|
+
`both`. Omitting `format` continues to use each item's legacy default.
|
|
249
|
+
|
|
250
|
+
Builtin item ids: `agent-preset`, `model`, `reasoning`,
|
|
251
|
+
`permission-preset`, `sandbox-mode`, `approval-policy`, `plan-state`,
|
|
252
|
+
`focus-mode`, `focused-seat`, `view-scope`, `cwd`, `project`,
|
|
253
|
+
`git-branch`, `run-state`, `queue`, `tasks`, `agents`, `todo`,
|
|
254
|
+
`context`, `cache-hit`, `token-usage`, `performance`, `turns-steps`,
|
|
255
|
+
`stats-line`, `version`, `ext:*` (the legacy extension segments).
|
|
256
|
+
An invalid `footerLayout` warns once and falls back to the default — the
|
|
257
|
+
TUI always starts.
|
|
258
|
+
|
|
259
|
+
`footer: command` hands the Status Surface to a user-configured command
|
|
260
|
+
(Claude/Kimi style): the current status snapshot is serialized to JSON on
|
|
261
|
+
the command's stdin (schemaVersion 1 — no secrets, no credentials, no
|
|
262
|
+
prompts), and the command's stdout (sanitized: SGR colors and OSC 8
|
|
263
|
+
hyperlinks only) renders the status surface. The Host's instruction
|
|
264
|
+
surface (e.g. the Ctrl+C exit hint) always survives on top.
|
|
265
|
+
|
|
266
|
+
```yaml
|
|
267
|
+
footer: command
|
|
268
|
+
footerCommand:
|
|
269
|
+
schemaVersion: 1
|
|
270
|
+
command: "~/.config/dsh/statusline.sh"
|
|
271
|
+
timeoutMs: 300 # default 300, max 1000
|
|
272
|
+
refreshIntervalMs: 1000 # min 1000
|
|
273
|
+
maxRows: 1 # 1..2
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Security:** the command is executed ONLY when it lives in the USER
|
|
277
|
+
layer of your settings document. A repository/project-supplied
|
|
278
|
+
`footerCommand` is never executed — command mode is disabled and the
|
|
279
|
+
native layout applies. The command refreshes periodically according to
|
|
280
|
+
`refreshIntervalMs` and renders at most two rows; failures (empty output,
|
|
281
|
+
non-zero exit, timeout) fall back to the native layout automatically.
|
|
282
|
+
|
|
283
|
+
### Extension footer items
|
|
284
|
+
|
|
285
|
+
Plugins can contribute **configurable footer items** through the Stable
|
|
286
|
+
extension API (`@xmoon76/dsh-pi-tui/extensions`): register a
|
|
287
|
+
`FooterItemContribution` on the `chrome.footer.item` slot — a label and a
|
|
288
|
+
plain-data `segment` (styled spans; the host strips any terminal control
|
|
289
|
+
sequence, plugins never style the terminal). Users show/hide, reorder and
|
|
290
|
+
zone-place the item in `/footer` exactly like a builtin item. Feature-detect
|
|
291
|
+
the `slot.chrome.footer.item` capability before registering (it is
|
|
292
|
+
advertised before any surface exists). The item's config identity is the
|
|
293
|
+
canonical key `ext:<owner>/<id>` where the owner is the plugin's stable
|
|
294
|
+
name — **stable across HMR**: a layout referencing an unloaded plugin's
|
|
295
|
+
item keeps the reference and recovers automatically when the plugin
|
|
296
|
+
reloads. An npm-scoped plugin name (`@scope/name`) is legal: its `/` is
|
|
297
|
+
percent-encoded via `encodeURIComponent` in the key
|
|
298
|
+
(`ext:%40scope%2Fname/<id>`); the id itself must
|
|
299
|
+
not contain `/`. The legacy `chrome.footer.status` slot is unchanged: its
|
|
300
|
+
segments aggregate into the single `ext:*` item. Full author guide:
|
|
301
|
+
[docs/extension-api.md](docs/extension-api.md).
|
|
302
|
+
|
|
303
|
+
## Common keys
|
|
304
|
+
|
|
305
|
+
| Key | Action |
|
|
306
|
+
| ------------- | --------------------------------------------------- |
|
|
307
|
+
| `Enter` | Submit input |
|
|
308
|
+
| `Ctrl+Enter` | Queue the draft while the agent is busy (the opposite of Enter while busy) |
|
|
309
|
+
| `Shift+Enter` | Insert newline |
|
|
310
|
+
| `Esc` | Cancel current interaction / interrupt running work |
|
|
311
|
+
| `Esc Esc` | Open Rewind while idle |
|
|
312
|
+
| `Ctrl+C` | Interrupt / clear current input |
|
|
313
|
+
| `Ctrl+D` | Quit the TUI (like `/exit`) |
|
|
314
|
+
| `Ctrl+S` | Steer queued messages and the draft into the running turn |
|
|
315
|
+
| `Ctrl+T` | Toggle the todo panel |
|
|
316
|
+
| `Ctrl+R` | Search input history |
|
|
317
|
+
| `Ctrl+F` | Search Transcript |
|
|
318
|
+
| `Ctrl+End` | Jump to the latest Transcript output in fullscreen |
|
|
319
|
+
| `Ctrl+O` | Expand / collapse Tool and System details; in fullscreen Focus, bulk-toggle the Thought roots |
|
|
320
|
+
| `Alt+T` | Expand / collapse Thinking |
|
|
321
|
+
| `Ctrl+G` | Edit current input in `$VISUAL`/`$EDITOR` |
|
|
322
|
+
| `Ctrl+V` | Paste image |
|
|
323
|
+
| `Tab` | Autocomplete slash commands and file paths |
|
|
324
|
+
| `@` | File completion |
|
|
325
|
+
| `!` | Enter Shell mode |
|
|
326
|
+
| `!!` | Enter local-only Shell mode |
|
|
327
|
+
|
|
328
|
+
Use `/help` inside the TUI for the current command and keybinding list. The table above shows the defaults; after customization, `/help` and `/keybindings` show the effective keys.
|
|
329
|
+
|
|
330
|
+
### Customizing keybindings
|
|
331
|
+
|
|
332
|
+
Host shortcuts are semantic actions (`app.*`) resolved through a
|
|
333
|
+
context-aware keymap — the UI (footer hints, `/help`, `/keybindings`)
|
|
334
|
+
always shows the EFFECTIVE keys, so a remap updates every hint. Configure
|
|
335
|
+
them in the `dsh-pi-tui` settings namespace; apply with `/keybindings
|
|
336
|
+
reload` (explicit — a settings edit takes effect after the reload, no
|
|
337
|
+
restart):
|
|
338
|
+
|
|
339
|
+
```yaml
|
|
340
|
+
dsh-pi-tui:
|
|
341
|
+
keybindings:
|
|
342
|
+
app.input.steer: ctrl+s # one key
|
|
343
|
+
app.permission.cycle: [shift+tab, ctrl+shift+p] # several keys
|
|
344
|
+
app.history.search: ctrl+r
|
|
345
|
+
app.transcript.toggleThinking: false # disable the action's keys
|
|
346
|
+
leader: ctrl+x # M6: leader sequences
|
|
347
|
+
bindings:
|
|
348
|
+
app.tasks.open: <leader>t
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
- A plain printable key can never be bound to a Host action (it would
|
|
352
|
+
swallow typing); a bad entry is a warning, never a startup failure
|
|
353
|
+
(fail-soft).
|
|
354
|
+
- Any user declaration REPLACES the action's builtin default keys:
|
|
355
|
+
`app.input.steer: ctrl+x` makes Ctrl+X steer and Ctrl+S stop steering;
|
|
356
|
+
a leader-only `app.todo.toggle: <leader>t` makes Leader T the only
|
|
357
|
+
toggle trigger (Ctrl+T stops); `['ctrl+z', '<leader>s']` keeps both
|
|
358
|
+
USER triggers; `false` removes every trigger of the action. Leader
|
|
359
|
+
completions that the effective editor-owned submit key would consume (for
|
|
360
|
+
example, `<leader>enter`) are rejected instead of being advertised as dead
|
|
361
|
+
sequences.
|
|
362
|
+
- `DSH_PI_TUI_SAFE_KEYBINDINGS=1` ignores all user overrides (builtin
|
|
363
|
+
defaults only). The whole `/keybindings` editor is read-only while safe mode
|
|
364
|
+
is active, so it cannot save a configuration that is only checked after safe
|
|
365
|
+
mode is disabled.
|
|
366
|
+
- In the editor, untouched default bindings that are still effective are
|
|
367
|
+
selectable. `Add shortcut` materializes those surviving defaults plus the new
|
|
368
|
+
key; shadowed definition defaults remain reference-only, and replacing or
|
|
369
|
+
removing one surviving default preserves its siblings. Once an action has a
|
|
370
|
+
user declaration, that declaration still replaces the builtin set as
|
|
371
|
+
described above.
|
|
372
|
+
- `/help` remains the key-first, read-only help surface; `/keybindings` is the
|
|
373
|
+
action-first, editable Keyboard Shortcuts Editor: it groups actions by
|
|
374
|
+
category, searches action IDs/descriptions/current keys/default keys, and
|
|
375
|
+
marks customized, conflict, Unbound, Disabled, and fixed states. A standalone Leader key row also configures the global leader key.
|
|
376
|
+
- `/settings` has one `Keyboard shortcuts` launcher that opens the same editor
|
|
377
|
+
and persistence controller as `/keybindings`.
|
|
378
|
+
- The recorder reads a real terminal key, parses it with `parseKey`, and stores
|
|
379
|
+
the canonical `KeyId`; known dead, typing-swallowing, terminal-ambiguous, and
|
|
380
|
+
conflicting shortcuts are rejected before saving. Ordinary recording cancels
|
|
381
|
+
on `Esc`; the direct Host interrupt recorder uses a short double-press window:
|
|
382
|
+
one `Esc` cancels and two `Esc` press events assign physical Escape. Key
|
|
383
|
+
repeats/releases do not count, and there is no single-letter shortcut;
|
|
384
|
+
physical Escape remains reserved for Host lifecycle paths.
|
|
385
|
+
- Conditional affordances are labeled separately in the editor (for example,
|
|
386
|
+
`Down (conditional)` for the empty-editor task browser) instead of appearing
|
|
387
|
+
as ordinary configured shortcuts.
|
|
388
|
+
- `/keybindings conflicts` lists conflicts (same key + overlapping scope + same
|
|
389
|
+
priority — never silent last-write-wins); `/keybindings reload` re-reads the
|
|
390
|
+
settings (fail-soft: a bad entry is diagnosed and skipped, a throwing read
|
|
391
|
+
is an error notice — never a crash; the keymap keeps the last-known-good
|
|
392
|
+
configuration); `/keybindings reset` clears the overrides through the
|
|
393
|
+
settings service and rebuilds the running keymap immediately.
|
|
394
|
+
- The subagent viewer blocks PARENT actions by action id, so a remapped
|
|
395
|
+
parent shortcut stays blocked inside the viewer.
|
|
396
|
+
- Conditional affordances are ADDITIVE: binding `app.tasks.open: ctrl+x`
|
|
397
|
+
ADDS a trigger — the empty-editor `↓` task-browser affordance still
|
|
398
|
+
works; only `false` removes every trigger of an action.
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
## Installation
|
|
402
|
+
|
|
403
|
+
### Requirements
|
|
404
|
+
|
|
405
|
+
* DeepSeek Harness
|
|
406
|
+
* Node.js `^22.19.0 || >=24`
|
|
407
|
+
|
|
408
|
+
The project currently follows the DeepSeek Harness `0.1.1-rc.x` release line.
|
|
409
|
+
|
|
410
|
+
### npm
|
|
411
|
+
|
|
412
|
+
Using a dedicated `pi-tui` profile is recommended:
|
|
413
|
+
|
|
414
|
+
```sh
|
|
415
|
+
dsh plugin --profile pi-tui -- add @xmoon76/dsh-pi-tui
|
|
416
|
+
dsh --profile pi-tui
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Resume an existing Session:
|
|
420
|
+
|
|
421
|
+
```sh
|
|
422
|
+
dsh --profile pi-tui --session <session-id>
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
The published package already contains the Pi TUI fork required at runtime. No separate internal TUI package needs to be installed.
|
|
426
|
+
|
|
427
|
+
### Update
|
|
428
|
+
|
|
429
|
+
```sh
|
|
430
|
+
dsh plugin --profile pi-tui -- update @xmoon76/dsh-pi-tui
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
List installed plugins:
|
|
434
|
+
|
|
435
|
+
```sh
|
|
436
|
+
dsh plugin --profile pi-tui -- list
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Remove:
|
|
440
|
+
|
|
441
|
+
```sh
|
|
442
|
+
dsh plugin --profile pi-tui -- remove @xmoon76/dsh-pi-tui
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## Running from source
|
|
446
|
+
|
|
447
|
+
```sh
|
|
448
|
+
git clone https://github.com/XMoon/dsh-pi-tui
|
|
449
|
+
cd dsh-pi-tui
|
|
450
|
+
|
|
451
|
+
pnpm install
|
|
452
|
+
pnpm build
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Install using `file:`:
|
|
456
|
+
|
|
457
|
+
```sh
|
|
458
|
+
dsh plugin --profile pi-tui -- add @xmoon76/dsh-pi-tui@file:$PWD
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
`file:` copies the current build output at install time. After changing source, rebuild and add the package again.
|
|
462
|
+
|
|
463
|
+
For continuous development, use `link:`:
|
|
464
|
+
|
|
465
|
+
```sh
|
|
466
|
+
dsh plugin --profile pi-tui-dev -- add @xmoon76/dsh-pi-tui@link:$PWD
|
|
467
|
+
dsh --profile pi-tui-dev
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
After that, rebuilding is enough:
|
|
471
|
+
|
|
472
|
+
```sh
|
|
473
|
+
pnpm build
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
The development profile continues to point at the working tree.
|
|
477
|
+
|
|
478
|
+
## DeepSeek Harness integration
|
|
479
|
+
|
|
480
|
+
`dsh-pi-tui` implements the terminal interaction layer only.
|
|
481
|
+
|
|
482
|
+
The following capabilities are provided by DeepSeek Harness:
|
|
483
|
+
|
|
484
|
+
* Agent Loop
|
|
485
|
+
* LLM / Provider
|
|
486
|
+
* Session Persistence
|
|
487
|
+
* Tools
|
|
488
|
+
* Skills
|
|
489
|
+
* Approval
|
|
490
|
+
* Permission Presets
|
|
491
|
+
* Plan Mode
|
|
492
|
+
* Goal
|
|
493
|
+
* Jobs
|
|
494
|
+
* Subagents
|
|
495
|
+
* Credentials
|
|
496
|
+
* Settings
|
|
497
|
+
|
|
498
|
+
The TUI therefore does not maintain a separate model configuration, Session format, or Agent Runtime.
|
|
499
|
+
|
|
500
|
+
It can coexist with other DSH surfaces using the same runtime data:
|
|
501
|
+
|
|
502
|
+
```sh
|
|
503
|
+
dsh --profile web
|
|
504
|
+
dsh --profile headless
|
|
505
|
+
dsh --profile pi-tui
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
## Extension API
|
|
509
|
+
|
|
510
|
+
In addition to being used as a TUI, `dsh-pi-tui` exposes versioned Extension APIs for other Cordis / DSH plugins that need to extend terminal interaction.
|
|
511
|
+
|
|
512
|
+
Three public entries are currently available:
|
|
513
|
+
|
|
514
|
+
| Entry | Use | Stability |
|
|
515
|
+
| ----------------------------------------- | ------------------------------- | --------- |
|
|
516
|
+
| `@xmoon76/dsh-pi-tui/extensions` | General extensions | Stable |
|
|
517
|
+
| `@xmoon76/dsh-pi-tui/extensions/advanced` | Deeper interaction capabilities | Advanced |
|
|
518
|
+
| `@xmoon76/dsh-pi-tui/extensions/unstable` | Low-level capabilities | Unstable |
|
|
519
|
+
|
|
520
|
+
Extension points include:
|
|
521
|
+
|
|
522
|
+
* Header / Footer
|
|
523
|
+
* Input Widget
|
|
524
|
+
* Slash Command
|
|
525
|
+
* Theme
|
|
526
|
+
* Setting
|
|
527
|
+
* Autocomplete
|
|
528
|
+
* Keybinding
|
|
529
|
+
* Message Renderer
|
|
530
|
+
* Tool Renderer
|
|
531
|
+
* Overlay
|
|
532
|
+
* Interactive UI
|
|
533
|
+
* Editor Control
|
|
534
|
+
* Replacement Editor
|
|
535
|
+
|
|
536
|
+
Plugins depend only on public entries and do not need to import internal types such as `TuiApp` or `TuiMainScreen`.
|
|
537
|
+
|
|
538
|
+
Minimal example:
|
|
539
|
+
|
|
540
|
+
```ts
|
|
541
|
+
import {
|
|
542
|
+
PI_TUI_EXTENSIONS_SERVICE,
|
|
543
|
+
type PiTuiExtensionService,
|
|
544
|
+
} from '@xmoon76/dsh-pi-tui/extensions'
|
|
545
|
+
|
|
546
|
+
export const name = 'my-plugin'
|
|
547
|
+
export const inject = ['tuiStartup', PI_TUI_EXTENSIONS_SERVICE]
|
|
548
|
+
|
|
549
|
+
export function apply(ctx: Context): void {
|
|
550
|
+
const service = ctx.get(
|
|
551
|
+
PI_TUI_EXTENSIONS_SERVICE,
|
|
552
|
+
) as PiTuiExtensionService
|
|
553
|
+
|
|
554
|
+
if (!service.api().capabilities.has('slot.chrome.header.badge')) {
|
|
555
|
+
return
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
service.register(
|
|
559
|
+
'chrome.header.badge',
|
|
560
|
+
{
|
|
561
|
+
id: 'my-badge',
|
|
562
|
+
order: 100,
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
text: 'my-plugin',
|
|
566
|
+
tone: 'info',
|
|
567
|
+
},
|
|
568
|
+
)
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
Documentation:
|
|
573
|
+
|
|
574
|
+
* [Extension API](docs/extension-api.md)
|
|
575
|
+
* [Extension tiers](docs/extension-tiers.md)
|
|
576
|
+
* [Advanced API](docs/extension-advanced.md)
|
|
577
|
+
* [Unstable API](docs/extension-unstable.md)
|
|
578
|
+
* [Plugin authoring](docs/plugin-authoring.md)
|
|
579
|
+
* [Capability matrix](docs/extension-capability-matrix.md)
|
|
580
|
+
|
|
581
|
+
## Development
|
|
582
|
+
|
|
583
|
+
```sh
|
|
584
|
+
pnpm install
|
|
585
|
+
pnpm build
|
|
586
|
+
pnpm typecheck
|
|
587
|
+
pnpm test
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
The test suite covers the Pi TUI fork, host / surface behavior, and Extension API fixtures and smoke tests.
|
|
591
|
+
|
|
592
|
+
Terminal rendering and input routing are tested extensively with `@xterm/headless`, so most UI tests do not require a real TTY or a live model connection.
|
|
593
|
+
|
|
594
|
+
Performance baseline:
|
|
595
|
+
|
|
596
|
+
```sh
|
|
597
|
+
node --expose-gc scripts/bench.mts
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
The project is also developed against a dedicated `pi-tui-dev` profile:
|
|
601
|
+
|
|
602
|
+
```sh
|
|
603
|
+
dsh plugin --profile pi-tui-dev -- add @xmoon76/dsh-pi-tui@link:$PWD
|
|
604
|
+
dsh --profile pi-tui-dev
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
## Repository layout
|
|
608
|
+
|
|
609
|
+
The repository root is the npm package published as `@xmoon76/dsh-pi-tui`.
|
|
610
|
+
|
|
611
|
+
The Pi TUI fork lives under:
|
|
612
|
+
|
|
613
|
+
```text
|
|
614
|
+
packages/pi-tui/
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
It is an internal build dependency bundled with the root package and does not need to be installed separately by users.
|
|
618
|
+
|
|
619
|
+
Upstream provenance, version information, and local divergence are tracked in:
|
|
620
|
+
|
|
621
|
+
```text
|
|
622
|
+
packages/pi-tui/package.json
|
|
623
|
+
packages/pi-tui/AGENTS.md
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
Contributor-oriented repository structure and development rules are documented in [AGENTS.md](AGENTS.md).
|
|
627
|
+
|
|
628
|
+
## Documentation
|
|
629
|
+
|
|
630
|
+
| Document | Content |
|
|
631
|
+
| ------------------------------------------------------ | --------------------------------- |
|
|
632
|
+
| [docs/README.md](docs/README.md) | Documentation index |
|
|
633
|
+
| [docs/architecture.md](docs/architecture.md) | Architecture and module ownership |
|
|
634
|
+
| [docs/input-history.md](docs/input-history.md) | Input history |
|
|
635
|
+
| [docs/surface-decisions.md](docs/surface-decisions.md) | TUI interaction decisions |
|
|
636
|
+
| [docs/concurrency.md](docs/concurrency.md) | Session concurrency |
|
|
637
|
+
| [docs/failure-model.md](docs/failure-model.md) | Async failure / cancellation |
|
|
638
|
+
| [docs/perf-baseline.md](docs/perf-baseline.md) | Performance baseline |
|
|
639
|
+
| [docs/local-development.md](docs/local-development.md) | Local development and worktree policy |
|
|
640
|
+
| [docs/extension-api.md](docs/extension-api.md) | Extension API |
|
|
641
|
+
| [AGENTS.md](AGENTS.md) | Contributor operating manual |
|
|
642
|
+
|
|
643
|
+
## Changelog
|
|
644
|
+
|
|
645
|
+
简体中文:
|
|
646
|
+
|
|
647
|
+
[CHANGELOG.md](CHANGELOG.md)
|
|
648
|
+
|
|
649
|
+
English:
|
|
650
|
+
|
|
651
|
+
[CHANGELOG.en.md](CHANGELOG.en.md)
|
|
652
|
+
|
|
653
|
+
## License
|
|
654
|
+
|
|
655
|
+
[MIT](LICENSE)
|