@xmoon76/dsh-pi-tui 0.1.1 → 0.1.3
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 +59 -0
- package/dist/index.d.mts +29 -1
- package/dist/index.mjs +4849 -789
- package/package.json +25 -21
- package/scripts/bench.mts +261 -0
- package/scripts/naming-gate.mjs +102 -0
- package/scripts/repair-core.mjs +638 -0
- package/scripts/repair-session.mjs +474 -0
- package/scripts/tarball-smoke.mjs +325 -0
package/README.md
CHANGED
|
@@ -30,6 +30,65 @@ dsh plugin --profile pi-tui -- remove @xmoon76/dsh-pi-tui
|
|
|
30
30
|
- `/title [title]` — show or set the current session's title
|
|
31
31
|
- `/preset`, `/model`, `/settings`, `/export`, `/fork`, `/subagents` — see the command autocomplete (`/` + Tab)
|
|
32
32
|
|
|
33
|
+
## ⚠️ One surface per session
|
|
34
|
+
|
|
35
|
+
**Upstream limitation (a known dsh issue this TUI cannot fix):** dsh's session persistence has no cross-process coordination — each process numbers events from its own in-memory log length (`seq = log.length`) and appends to the same session file. When two processes hold the **same active session** at the same time (TUI + web GUI, two TUIs, TUI + any third-party plugin), one side's resume writes a `session/end-seed` marker and the other side's next append collides on the same seq — **the log corrupts and the session becomes unreadable** (`corrupt session log: seq gap in committed region`).
|
|
36
|
+
|
|
37
|
+
Therefore:
|
|
38
|
+
|
|
39
|
+
- **Do not open the same active session in two surfaces at once** (TUI, web GUI, or any other plugin);
|
|
40
|
+
- To switch surfaces, close the session in the current one first, then open it in the other;
|
|
41
|
+
- This TUI ships a **divergence guard**: before each message send it checks whether another process has written the session file, and **blocks the send with a warning** when it has (pressing Enter again force-sends at your own risk — it may corrupt the log);
|
|
42
|
+
- If a session is already corrupted, fix it with the [session repair script](#session-repair) below (close every process holding the session first).
|
|
43
|
+
|
|
44
|
+
## Diagnostic log
|
|
45
|
+
|
|
46
|
+
The TUI writes its own diagnostics to stderr and a log file (`ctx.logger` is invisible in this process — no exporter):
|
|
47
|
+
|
|
48
|
+
- Default file: `$DSH_HOME/logs/pi-tui-<pid>.log` (default `~/.dsh/logs/`);
|
|
49
|
+
- Line format: `[tui] <ISO time> <level> <message> k=v ...`;
|
|
50
|
+
- Default level `info`: key lifecycle events only (boot/resume/switch/exit, divergence-guard warnings, errors); `debug` additionally logs every guard check before a send.
|
|
51
|
+
|
|
52
|
+
Configuration (environment variables):
|
|
53
|
+
|
|
54
|
+
| Variable | Meaning | Default |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `DSH_PI_TUI_LOG` | Log file path; `off` disables file logging | `$DSH_HOME/logs/pi-tui-<pid>.log` |
|
|
57
|
+
| `DSH_PI_TUI_LOG_LEVEL` | `debug` / `info` / `warn` / `error` | `info` |
|
|
58
|
+
|
|
59
|
+
Troubleshooting example:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
DSH_PI_TUI_LOG_LEVEL=debug dsh --profile pi-tui
|
|
63
|
+
tail -f ~/.dsh/logs/pi-tui-*.log
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Session repair
|
|
67
|
+
|
|
68
|
+
**Background:** when a session log is corrupted (duplicate or missing seqs) dsh can no longer read that session. This repository ships a standalone repair script, `scripts/repair-session.mjs`: it locates the session file, diagnoses the damage, and repairs it — renumbering seqs (duplicates), truncating at the first missing/unparsable event (which cannot be recreated), or re-framing the log when the frame layout is wrong (dsh requires the first zstd frame to be exactly the header line; a whole-log single frame is structurally valid zstd but rejected by every dsh reader). It **always backs up the original before writing** and verifies the result with the same scans the reader performs (frame layout + event contiguity).
|
|
69
|
+
|
|
70
|
+
**Dependency:** resolves `@deepseek-ai/dsh-session` from the dsh installation (auto-detected through the `dsh` launcher on PATH, or `--dsh-dir <path>`).
|
|
71
|
+
|
|
72
|
+
**Repair one session (dry run by default; `--yes` writes):**
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
# Close every process holding the session first (TUI / web / plugins)!
|
|
76
|
+
node scripts/repair-session.mjs session-ab79200b-0e36-4a62-a7a6-3ac620c05f1d # diagnose + repair plan (no write)
|
|
77
|
+
node scripts/repair-session.mjs session-ab79200b-0e36-4a62-a7a6-3ac620c05f1d --yes # apply the repair
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The original file is backed up to `session.jsonl.zstd.bak-<timestamp>` before writing (a failed backup aborts the write); the report prints the backup path.
|
|
81
|
+
|
|
82
|
+
**Read-only scan of all sessions, listing damaged ids:**
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
node scripts/repair-session.mjs --scan
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Prints one `CORRUPT <id>: <reason>` per damaged session; `no damaged sessions found` when everything is healthy.
|
|
89
|
+
|
|
90
|
+
**Other options:** `--dsh-home <path>` sets the sessions root (default `$DSH_HOME` or `~/.dsh`); `--help` shows usage.
|
|
91
|
+
|
|
33
92
|
## Development
|
|
34
93
|
|
|
35
94
|
Source and tests live in the [dsh-pi-tui repository](https://github.com/XMoon/dsh-pi-tui) (`packages/dsh-pi-tui/`); headless tests drive the UI through `@xterm/headless` with no TTY or model connection.
|
package/dist/index.d.mts
CHANGED
|
@@ -22,12 +22,40 @@ interface Config {
|
|
|
22
22
|
sessionId?: string;
|
|
23
23
|
}
|
|
24
24
|
declare const Config: z<Config>;
|
|
25
|
+
/**
|
|
26
|
+
* Read an explicit child-session reference from a future/extended job record.
|
|
27
|
+
* Current dsh JobSnapshot records do not expose one, so this normally returns
|
|
28
|
+
* undefined. Crucially, label, registration order and timestamps are never
|
|
29
|
+
* accepted as identity signals.
|
|
30
|
+
*/
|
|
31
|
+
declare function subagentJobTranscriptId(snapshot: unknown): string | undefined;
|
|
32
|
+
/** Viewer body for a subagent job with no uniquely matched child. */
|
|
33
|
+
declare function subagentJobViewHint(status: string, detail: string | undefined): string;
|
|
25
34
|
/**
|
|
26
35
|
* Whether a shell command matches a destructive pattern. `rm` is treated
|
|
27
36
|
* specially: any spelling of recursive + force flags (`rm -rf`, `rm -r -f`,
|
|
28
37
|
* `rm -rf /`) is dangerous; the remaining patterns are verbatim matches.
|
|
29
38
|
*/
|
|
30
39
|
declare function dangerCommand(command: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* The dsh profile this process was launched with (the `--profile` flag),
|
|
42
|
+
* so the exit-time resume hint names the profile the TUI actually runs
|
|
43
|
+
* under. Falls back to `pi-tui` when the flag is absent (the TUI bundle
|
|
44
|
+
* cannot load without a profile, so this is defensive only).
|
|
45
|
+
* @param argv - the process argument vector.
|
|
46
|
+
* @param fallback - the default profile.
|
|
47
|
+
*/
|
|
48
|
+
declare function runningProfile(argv?: readonly string[], fallback?: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* The interactive-quit resume hint (pi parity): `dsh --profile <p>
|
|
51
|
+
* --session <id>`, printed after the terminal restores so the user can
|
|
52
|
+
* re-enter the session later. Returns undefined when there is no session
|
|
53
|
+
* to resume (deferred start never created one).
|
|
54
|
+
* @param profile - the running profile ({@link runningProfile}).
|
|
55
|
+
* @param sessionId - the live session id.
|
|
56
|
+
* @returns the resume command line, or undefined without a session.
|
|
57
|
+
*/
|
|
58
|
+
declare function resumeCommand(profile: string, sessionId: string): string | undefined;
|
|
31
59
|
/** One agent's preset composition: the id to record and the setup that installs it. */
|
|
32
60
|
interface AgentComposition {
|
|
33
61
|
/** Preset id for the session header, absent when the deployment composes no roster. */
|
|
@@ -103,4 +131,4 @@ declare function recomposeBlank(ctx: Context, agent: {
|
|
|
103
131
|
*/
|
|
104
132
|
declare function apply(ctx: Context, config: Config): void;
|
|
105
133
|
//#endregion
|
|
106
|
-
export { AgentComposition, Config, RecomposableSession, RecomposeOutcome, apply, composeAgent, dangerCommand, forkSeed, inject, name, recomposeBlank, recordedPreset };
|
|
134
|
+
export { AgentComposition, Config, RecomposableSession, RecomposeOutcome, apply, composeAgent, dangerCommand, forkSeed, inject, name, recomposeBlank, recordedPreset, resumeCommand, runningProfile, subagentJobTranscriptId, subagentJobViewHint };
|