@aiwayds/dsh-tui-pi 0.8.2 → 0.9.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 +44 -3
- package/README.zh.md +36 -3
- package/assets/fonts/LICENSE-Hack.txt +45 -0
- package/assets/fonts/LICENSE-NerdFonts.txt +126 -0
- package/assets/fonts/LICENSE-NotoSansSymbols.txt +93 -0
- package/assets/fonts/LICENSE-NotoSansSymbols2.txt +93 -0
- package/assets/fonts/dsh-tui-pi-nerd.ttf +0 -0
- package/assets/fonts-gen.mjs +219 -0
- package/assets/whale-gen.mjs +169 -0
- package/assets/whale-source.png +0 -0
- package/lib/agents.js +1 -1
- package/lib/agents.js.map +1 -1
- package/lib/canvas-terminal.d.ts +17 -11
- package/lib/canvas-terminal.js +62 -24
- package/lib/canvas-terminal.js.map +1 -1
- package/lib/dsh-events.d.ts +32 -3
- package/lib/dsh-events.js +14 -0
- package/lib/dsh-events.js.map +1 -1
- package/lib/font-detect.d.ts +66 -0
- package/lib/font-detect.js +124 -0
- package/lib/font-detect.js.map +1 -0
- package/lib/footer.d.ts +3 -2
- package/lib/footer.js +16 -8
- package/lib/footer.js.map +1 -1
- package/lib/icons.d.ts +53 -0
- package/lib/icons.js +78 -0
- package/lib/icons.js.map +1 -0
- package/lib/index.js +44 -13
- package/lib/index.js.map +1 -1
- package/lib/live-widgets.d.ts +16 -5
- package/lib/live-widgets.js +29 -8
- package/lib/live-widgets.js.map +1 -1
- package/lib/messages.js +2 -1
- package/lib/messages.js.map +1 -1
- package/lib/session.d.ts +99 -16
- package/lib/session.js +322 -64
- package/lib/session.js.map +1 -1
- package/lib/sessions.d.ts +15 -0
- package/lib/sessions.js +18 -3
- package/lib/sessions.js.map +1 -1
- package/lib/settings.js +2 -2
- package/lib/skills.d.ts +19 -3
- package/lib/skills.js +43 -10
- package/lib/skills.js.map +1 -1
- package/lib/subagent-policy.d.ts +11 -11
- package/lib/subagent-policy.js +17 -15
- package/lib/subagent-policy.js.map +1 -1
- package/lib/subagent-viewer.d.ts +20 -5
- package/lib/subagent-viewer.js +29 -15
- package/lib/subagent-viewer.js.map +1 -1
- package/lib/theme-settings.d.ts +25 -10
- package/lib/theme-settings.js +40 -14
- package/lib/theme-settings.js.map +1 -1
- package/lib/tokens.d.ts +38 -0
- package/lib/tokens.js +68 -0
- package/lib/tokens.js.map +1 -0
- package/lib/tui.js +15 -6
- package/lib/tui.js.map +1 -1
- package/package.json +2 -1
- package/scripts/install-font.mjs +329 -0
package/lib/canvas-terminal.js
CHANGED
|
@@ -2,41 +2,71 @@
|
|
|
2
2
|
* Terminal write-stream decorator painting the canvas via BCE.
|
|
3
3
|
*
|
|
4
4
|
* pi-tui renders rows as `\x1b[{row};1H\x1b[2K{line}` and full redraws as
|
|
5
|
-
* `\x1b[2J` — no background of their own.
|
|
6
|
-
*
|
|
5
|
+
* `\x1b[2J` — no background of their own. Injections make the whole screen
|
|
6
|
+
* carry the theme colors without touching pi-tui:
|
|
7
7
|
*
|
|
8
8
|
* 1. Before every erase sequence (`\x1b[2K`/`\x1b[2J`): terminals with BCE
|
|
9
9
|
* (back color erase) fill the erased region with the current SGR
|
|
10
10
|
* background, painting row tails the erase never reaches.
|
|
11
|
-
* 2. After every
|
|
12
|
-
* `\x1b[0;…m`, `\x1b[49m`): content following a reset would
|
|
13
|
-
* print with the terminal default
|
|
14
|
-
* canvas
|
|
15
|
-
*
|
|
16
|
-
*
|
|
11
|
+
* 2. After every color-clearing SGR reset (`\x1b[0m`, `\x1b[m`,
|
|
12
|
+
* `\x1b[0;…m`, `\x1b[39m`, `\x1b[49m`): content following a reset would
|
|
13
|
+
* otherwise print with the terminal default colors, punching holes into
|
|
14
|
+
* the canvas — most visibly the editor input and unselected picker rows
|
|
15
|
+
* falling back to the terminal's default FOREGROUND, which is dark text
|
|
16
|
+
* when the host terminal is light-themed (pi itself never paints a
|
|
17
|
+
* canvas, so its unstyled text always matches; we paint, so we must own
|
|
18
|
+
* both channels). Re-injecting restores the canvas; spans that set their
|
|
19
|
+
* own colors still override it.
|
|
17
20
|
*
|
|
18
|
-
* Rows the diff renderer skips keep the
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
+
* Rows the diff renderer skips keep the colors of their last paint, which
|
|
22
|
+
* is correct until the canvas changes — the caller must then force a full
|
|
23
|
+
* redraw (requestRender(true)).
|
|
21
24
|
*/
|
|
22
25
|
const ENTER_ALT_SCREEN = '\x1b[?1049h';
|
|
23
26
|
const EXIT_ALT_SCREEN = '\x1b[?1049l';
|
|
24
27
|
const SGR = /\x1b\[([0-9;]*)m/g;
|
|
25
28
|
/**
|
|
26
|
-
*
|
|
27
|
-
* (`\x1b[0m`, `\x1b[m`, `\x1b[0;…m`
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
29
|
+
* Which color channels an SGR parameter list resets to the terminal
|
|
30
|
+
* default: full resets (`\x1b[0m`, `\x1b[m`, `\x1b[0;…m`) clear both,
|
|
31
|
+
* `\x1b[39m`/`\x1b[49m` clear one each. Color-set parameters are skipped
|
|
32
|
+
* so a 0 channel (`\x1b[48;2;0;121;107m`, `\x1b[38;5;0m`) never reads as
|
|
33
|
+
* a reset — treating those as clears would paint over intentional
|
|
34
|
+
* surfaces.
|
|
31
35
|
*/
|
|
32
|
-
function
|
|
33
|
-
if (params === ''
|
|
34
|
-
return true;
|
|
35
|
-
|
|
36
|
+
function sgrClears(params) {
|
|
37
|
+
if (params === '')
|
|
38
|
+
return { bg: true, fg: true };
|
|
39
|
+
const p = params.split(';');
|
|
40
|
+
let bg = false;
|
|
41
|
+
let fg = false;
|
|
42
|
+
for (let i = 0; i < p.length; i++) {
|
|
43
|
+
const token = p[i];
|
|
44
|
+
if (token === '0' || token === '') {
|
|
45
|
+
bg = true;
|
|
46
|
+
fg = true;
|
|
47
|
+
}
|
|
48
|
+
else if (token === '39') {
|
|
49
|
+
fg = true;
|
|
50
|
+
}
|
|
51
|
+
else if (token === '49') {
|
|
52
|
+
bg = true;
|
|
53
|
+
}
|
|
54
|
+
else if (token === '38' || token === '48') {
|
|
55
|
+
// Skip the color spec (5;n or 2;r;g;b, plus legacy 3;/4; forms).
|
|
56
|
+
if (p[i + 1] === '5')
|
|
57
|
+
i += 2;
|
|
58
|
+
else if (p[i + 1] === '2')
|
|
59
|
+
i += 4;
|
|
60
|
+
else if (p[i + 1] === '3' || p[i + 1] === '4')
|
|
61
|
+
i += 1;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return { bg, fg };
|
|
36
65
|
}
|
|
37
66
|
export class CanvasTerminal {
|
|
38
67
|
/** '' = transparent passthrough (DSH_TUI_TRANSPARENT). */
|
|
39
68
|
background = '';
|
|
69
|
+
foreground = '';
|
|
40
70
|
/** False once the alt-screen exit sequence is seen — the main-screen document dump that follows stays unpainted. */
|
|
41
71
|
active = true;
|
|
42
72
|
inner;
|
|
@@ -47,6 +77,10 @@ export class CanvasTerminal {
|
|
|
47
77
|
setCanvasBackground(bg) {
|
|
48
78
|
this.background = bg ?? '';
|
|
49
79
|
}
|
|
80
|
+
/** Set the canvas foreground SGR (the app's default text color); undefined disables. */
|
|
81
|
+
setCanvasForeground(fg) {
|
|
82
|
+
this.foreground = fg ?? '';
|
|
83
|
+
}
|
|
50
84
|
write(data) {
|
|
51
85
|
if (data.includes(EXIT_ALT_SCREEN)) {
|
|
52
86
|
// The exit buffer starts with EXIT_ALT_SCREEN; write it (and anything
|
|
@@ -58,18 +92,22 @@ export class CanvasTerminal {
|
|
|
58
92
|
}
|
|
59
93
|
if (data.includes(ENTER_ALT_SCREEN))
|
|
60
94
|
this.active = true;
|
|
61
|
-
if (this.background === '' || !this.active) {
|
|
95
|
+
if ((this.background === '' && this.foreground === '') || !this.active) {
|
|
62
96
|
this.inner.write(data);
|
|
63
97
|
return;
|
|
64
98
|
}
|
|
65
99
|
// Injection happens only at erase-sequence boundaries and after
|
|
66
|
-
//
|
|
67
|
-
//
|
|
100
|
+
// color-clearing resets; kitty image payloads are APC base64/hex and
|
|
101
|
+
// never contain ESC bytes.
|
|
68
102
|
const bg = this.background;
|
|
103
|
+
const fg = this.foreground;
|
|
69
104
|
this.inner.write(data
|
|
70
105
|
.replaceAll('\x1b[2K', `${bg}\x1b[2K`)
|
|
71
106
|
.replaceAll('\x1b[2J', `${bg}\x1b[2J`)
|
|
72
|
-
.replace(SGR, (seq, params) =>
|
|
107
|
+
.replace(SGR, (seq, params) => {
|
|
108
|
+
const clears = sgrClears(params);
|
|
109
|
+
return seq + (clears.bg ? bg : '') + (clears.fg ? fg : '');
|
|
110
|
+
}));
|
|
73
111
|
}
|
|
74
112
|
start(onInput, onResize) {
|
|
75
113
|
this.inner.start(onInput, onResize);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvas-terminal.js","sourceRoot":"","sources":["../src/canvas-terminal.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"canvas-terminal.js","sourceRoot":"","sources":["../src/canvas-terminal.ts"],"names":[],"mappings":"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"}
|
package/lib/dsh-events.d.ts
CHANGED
|
@@ -67,14 +67,25 @@ export declare function isLlmRetry(event: SessionEvent): event is SessionEvent &
|
|
|
67
67
|
type: 'llm/retry';
|
|
68
68
|
data: LlmRetryData;
|
|
69
69
|
};
|
|
70
|
+
/**
|
|
71
|
+
* Type guard for a dsh-dcp compaction notice. DCP appends ONE `user/message`
|
|
72
|
+
* row per committed compaction with
|
|
73
|
+
* `source: { kind: 'plugin', plugin: 'dsh-dcp', form: 'notice', summary }`
|
|
74
|
+
* (the summary reads like `dcp: compacted N history items (~X tokens, …)`).
|
|
75
|
+
* Recognized on the child's own log so the viewer can render a compaction-
|
|
76
|
+
* specific marker row and the bridge can tally a per-child count.
|
|
77
|
+
*/
|
|
78
|
+
export declare function isDcpCompactionNotice(event: SessionEvent): boolean;
|
|
70
79
|
/**
|
|
71
80
|
* One live subagent row the TUI renders: the bridge's per-child fold of
|
|
72
81
|
* workflow events (parent log) and the child's own session events. Children
|
|
73
82
|
* are keyed by their session id — discovered either from
|
|
74
83
|
* `tool-workflow/agent-start` or, when the deployment never emits workflow
|
|
75
|
-
* events, from the child session's header (`
|
|
76
|
-
*
|
|
77
|
-
*
|
|
84
|
+
* events, from the child session's header (`parentSession` pointing at a
|
|
85
|
+
* tracked session + the delegation markers `origin: 'subagent'` or
|
|
86
|
+
* `delegationDepth > 0`; dsh's childSessionMeta writes both for spawn and
|
|
87
|
+
* in-process fork children alike). All fields are O(1)-maintained — never a
|
|
88
|
+
* session-log scan on the render path.
|
|
78
89
|
*/
|
|
79
90
|
export interface AgentView {
|
|
80
91
|
/** The child session id (raw string) — the stable identity key. */
|
|
@@ -99,6 +110,24 @@ export interface AgentView {
|
|
|
99
110
|
readonly endedAt?: number;
|
|
100
111
|
/** Cumulative tokens: input + output + cacheRead + cacheWrite. */
|
|
101
112
|
readonly tokens: number;
|
|
113
|
+
/**
|
|
114
|
+
* Current context occupancy estimate — the `X` in the compact line's
|
|
115
|
+
* `X/Y`: the child's latest assistant/message billed input + output plus a
|
|
116
|
+
* CJK estimate of messages appended after it. NOT the cumulative `tokens`
|
|
117
|
+
* (that total only grows and stays the viewer/session-panel spend): this
|
|
118
|
+
* tracks the child's current context so the display follows the latest
|
|
119
|
+
* request and drops after a compaction. Before the first assistant/message
|
|
120
|
+
* it is the pending estimate alone.
|
|
121
|
+
*/
|
|
122
|
+
readonly contextTokens: number;
|
|
123
|
+
/**
|
|
124
|
+
* Assistant-message count — one per LLM round-trip, i.e. the child's
|
|
125
|
+
* "rounds" the compact line shows against the policy cap. Maintained O(1)
|
|
126
|
+
* on the child's own `assistant/message` events (NOT `turn/end`): a
|
|
127
|
+
* one-shot child spends its whole life in a single turn, so turns never
|
|
128
|
+
* progress while the child works — messages do.
|
|
129
|
+
*/
|
|
130
|
+
readonly rounds: number;
|
|
102
131
|
/** Latest `llm/retry` attempt number (0 = none retried). */
|
|
103
132
|
readonly retries: number;
|
|
104
133
|
/** Latest `llm/retry` maxRetries, when the policy reported one. */
|
package/lib/dsh-events.js
CHANGED
|
@@ -27,4 +27,18 @@ export function isSubagentDescriptor(event) {
|
|
|
27
27
|
export function isLlmRetry(event) {
|
|
28
28
|
return event.type === 'llm/retry';
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Type guard for a dsh-dcp compaction notice. DCP appends ONE `user/message`
|
|
32
|
+
* row per committed compaction with
|
|
33
|
+
* `source: { kind: 'plugin', plugin: 'dsh-dcp', form: 'notice', summary }`
|
|
34
|
+
* (the summary reads like `dcp: compacted N history items (~X tokens, …)`).
|
|
35
|
+
* Recognized on the child's own log so the viewer can render a compaction-
|
|
36
|
+
* specific marker row and the bridge can tally a per-child count.
|
|
37
|
+
*/
|
|
38
|
+
export function isDcpCompactionNotice(event) {
|
|
39
|
+
if (event.type !== 'user/message')
|
|
40
|
+
return false;
|
|
41
|
+
const source = event.data.source;
|
|
42
|
+
return source?.kind === 'plugin' && source?.plugin === 'dsh-dcp' && source?.form === 'notice';
|
|
43
|
+
}
|
|
30
44
|
//# sourceMappingURL=dsh-events.js.map
|
package/lib/dsh-events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dsh-events.js","sourceRoot":"","sources":["../src/dsh-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAqDH,yDAAyD;AACzD,MAAM,UAAU,YAAY,CAAC,KAAmB;IAC9C,OAAO,KAAK,CAAC,IAAI,KAAK,2BAA2B,CAAA;AACnD,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,UAAU,CAAC,KAAmB;IAC5C,OAAO,KAAK,CAAC,IAAI,KAAK,yBAAyB,CAAA;AACjD,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,oBAAoB,CAAC,KAAmB;IACtD,OAAO,KAAK,CAAC,IAAI,KAAK,qBAAqB,CAAA;AAC7C,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,UAAU,CAAC,KAAmB;IAC5C,OAAO,KAAK,CAAC,IAAI,KAAK,WAAW,CAAA;AACnC,CAAC"}
|
|
1
|
+
{"version":3,"file":"dsh-events.js","sourceRoot":"","sources":["../src/dsh-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAqDH,yDAAyD;AACzD,MAAM,UAAU,YAAY,CAAC,KAAmB;IAC9C,OAAO,KAAK,CAAC,IAAI,KAAK,2BAA2B,CAAA;AACnD,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,UAAU,CAAC,KAAmB;IAC5C,OAAO,KAAK,CAAC,IAAI,KAAK,yBAAyB,CAAA;AACjD,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,oBAAoB,CAAC,KAAmB;IACtD,OAAO,KAAK,CAAC,IAAI,KAAK,qBAAqB,CAAA;AAC7C,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,UAAU,CAAC,KAAmB;IAC5C,OAAO,KAAK,CAAC,IAAI,KAAK,WAAW,CAAA;AACnC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAmB;IACvD,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc;QAAE,OAAO,KAAK,CAAA;IAC/C,MAAM,MAAM,GAAI,KAAK,CAAC,IAAuE,CAAC,MAAM,CAAA;IACpG,OAAO,MAAM,EAAE,IAAI,KAAK,QAAQ,IAAI,MAAM,EAAE,MAAM,KAAK,SAAS,IAAI,MAAM,EAAE,IAAI,KAAK,QAAQ,CAAA;AAC/F,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nerd Font detection for the icon-set self-adaptation — a
|
|
3
|
+
* zero-dependency probe that tells `src/icons.ts` whether the terminal can
|
|
4
|
+
* render the powerline PUA glyph U+E0B0 (and the other weak-terminal glyphs)
|
|
5
|
+
* before the `auto` icon-set mode picks between 'nerdfont' and 'plain'.
|
|
6
|
+
*
|
|
7
|
+
* Detection is per-platform and deliberately approximate:
|
|
8
|
+
*
|
|
9
|
+
* - Linux: `fc-list -q <name>` for each candidate family. fc-list exits 0
|
|
10
|
+
* when the family is installed (quiet mode prints nothing either way).
|
|
11
|
+
* When `fc-list` itself is missing (ENOENT — a fontconfig-less system),
|
|
12
|
+
* every probe fails and the probe reports "no Nerd Font".
|
|
13
|
+
* - macOS: scan `~/Library/Fonts` and `/Library/Fonts` and match file names
|
|
14
|
+
* against a Nerd/Powerline heuristic (the real Core Text registry is not
|
|
15
|
+
* reachable without Objective-C bindings — a file-name scan is the
|
|
16
|
+
* reasonable zero-dependency approximation; it also recognises the TUI's
|
|
17
|
+
* own bundled font `dsh-tui-pi-nerd.ttf`, so `node scripts/install-font.mjs`
|
|
18
|
+
* flipping the terminal to it is enough to flip `auto` → nerdfont).
|
|
19
|
+
* - Windows / anything else: false (no free probe; the conservative answer
|
|
20
|
+
* is the plain glyphs).
|
|
21
|
+
*
|
|
22
|
+
* The result is memoised at module level — the TUI probes once at startup and
|
|
23
|
+
* hot-applied 'auto' settings changes resolve against that same snapshot. All
|
|
24
|
+
* failure paths return `false`; the probe never throws.
|
|
25
|
+
*/
|
|
26
|
+
/** Candidate font families probed with `fc-list -q` on Linux. */
|
|
27
|
+
export declare const NERD_FONT_CANDIDATES: readonly string[];
|
|
28
|
+
/**
|
|
29
|
+
* macOS font-file-name heuristic for a Nerd/Powerline-capable font, incl. the
|
|
30
|
+
* TUI's own bundled subset (`dsh-tui-pi-nerd.ttf`). `MesloLGS` mirrors the
|
|
31
|
+
* Linux candidate list (MesloLGS NF ships as `MesloLGS NF Regular.ttf`).
|
|
32
|
+
*/
|
|
33
|
+
export declare const NERD_FONT_FILE_RE: RegExp;
|
|
34
|
+
/**
|
|
35
|
+
* The environment the probe reads — injected for tests (see
|
|
36
|
+
* test/font-detect.test.mjs), defaulting to the real platform/fs.
|
|
37
|
+
*/
|
|
38
|
+
export interface FontDetectEnv {
|
|
39
|
+
platform: NodeJS.Platform;
|
|
40
|
+
/** `os.homedir()` — `~/Library/Fonts` is derived from it. */
|
|
41
|
+
home: string;
|
|
42
|
+
/** Resolves with the directory's entry names, rejects when unreadable. */
|
|
43
|
+
readdir: (dir: string) => Promise<string[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Resolves when the command exits 0, rejects on a missing/nonzero exit or
|
|
46
|
+
* on timeout — a stale fontconfig / hung fc-list must not block startup.
|
|
47
|
+
*/
|
|
48
|
+
execFile: (file: string, args: readonly string[], options?: {
|
|
49
|
+
timeout?: number;
|
|
50
|
+
}) => Promise<unknown>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The full probe against an injected environment: Linux uses fc-list, macOS
|
|
54
|
+
* uses the font-directory scan, every other platform reports `false`. Never
|
|
55
|
+
* throws — every platform path is wrapped or falls through to `false`.
|
|
56
|
+
*/
|
|
57
|
+
export declare function probeNerdFont(env: FontDetectEnv): Promise<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* Detect whether a Nerd/Powerline font is available, memoised. The first call
|
|
60
|
+
* (TUI startup, src/index.ts) runs the platform probe and caches the result;
|
|
61
|
+
* every later call — including a hot-applied 'auto' iconSet change — resolves
|
|
62
|
+
* against the same startup snapshot. Never throws.
|
|
63
|
+
*/
|
|
64
|
+
export declare function detectNerdFontAvailable(env?: FontDetectEnv): Promise<boolean>;
|
|
65
|
+
/** Drop the memoised result — a test seam (deterministic probe tests). */
|
|
66
|
+
export declare function resetNerdFontCache(): void;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nerd Font detection for the icon-set self-adaptation — a
|
|
3
|
+
* zero-dependency probe that tells `src/icons.ts` whether the terminal can
|
|
4
|
+
* render the powerline PUA glyph U+E0B0 (and the other weak-terminal glyphs)
|
|
5
|
+
* before the `auto` icon-set mode picks between 'nerdfont' and 'plain'.
|
|
6
|
+
*
|
|
7
|
+
* Detection is per-platform and deliberately approximate:
|
|
8
|
+
*
|
|
9
|
+
* - Linux: `fc-list -q <name>` for each candidate family. fc-list exits 0
|
|
10
|
+
* when the family is installed (quiet mode prints nothing either way).
|
|
11
|
+
* When `fc-list` itself is missing (ENOENT — a fontconfig-less system),
|
|
12
|
+
* every probe fails and the probe reports "no Nerd Font".
|
|
13
|
+
* - macOS: scan `~/Library/Fonts` and `/Library/Fonts` and match file names
|
|
14
|
+
* against a Nerd/Powerline heuristic (the real Core Text registry is not
|
|
15
|
+
* reachable without Objective-C bindings — a file-name scan is the
|
|
16
|
+
* reasonable zero-dependency approximation; it also recognises the TUI's
|
|
17
|
+
* own bundled font `dsh-tui-pi-nerd.ttf`, so `node scripts/install-font.mjs`
|
|
18
|
+
* flipping the terminal to it is enough to flip `auto` → nerdfont).
|
|
19
|
+
* - Windows / anything else: false (no free probe; the conservative answer
|
|
20
|
+
* is the plain glyphs).
|
|
21
|
+
*
|
|
22
|
+
* The result is memoised at module level — the TUI probes once at startup and
|
|
23
|
+
* hot-applied 'auto' settings changes resolve against that same snapshot. All
|
|
24
|
+
* failure paths return `false`; the probe never throws.
|
|
25
|
+
*/
|
|
26
|
+
import { execFile as execFileCb } from 'node:child_process';
|
|
27
|
+
import { readdir as readdirCb } from 'node:fs';
|
|
28
|
+
import { homedir } from 'node:os';
|
|
29
|
+
import { join } from 'node:path';
|
|
30
|
+
import { promisify } from 'node:util';
|
|
31
|
+
const execFile = promisify(execFileCb);
|
|
32
|
+
const readdir = promisify(readdirCb);
|
|
33
|
+
/** Candidate font families probed with `fc-list -q` on Linux. */
|
|
34
|
+
export const NERD_FONT_CANDIDATES = [
|
|
35
|
+
'JetBrainsMono Nerd Font',
|
|
36
|
+
'Hack Nerd Font',
|
|
37
|
+
'MesloLGS NF',
|
|
38
|
+
'Cascadia Mono PL',
|
|
39
|
+
'PowerlineSymbols',
|
|
40
|
+
'0xProto Nerd Font',
|
|
41
|
+
];
|
|
42
|
+
/**
|
|
43
|
+
* macOS font-file-name heuristic for a Nerd/Powerline-capable font, incl. the
|
|
44
|
+
* TUI's own bundled subset (`dsh-tui-pi-nerd.ttf`). `MesloLGS` mirrors the
|
|
45
|
+
* Linux candidate list (MesloLGS NF ships as `MesloLGS NF Regular.ttf`).
|
|
46
|
+
*/
|
|
47
|
+
export const NERD_FONT_FILE_RE = /Nerd|Powerline|Cascadia.*PL|MesloLGS|dsh-tui-pi-nerd/i;
|
|
48
|
+
/** The real environment: this process's platform, home and filesystem. */
|
|
49
|
+
const realEnv = {
|
|
50
|
+
platform: process.platform,
|
|
51
|
+
home: homedir(),
|
|
52
|
+
readdir: (dir) => readdir(dir),
|
|
53
|
+
execFile: (file, args, options) => execFile(file, args, options),
|
|
54
|
+
};
|
|
55
|
+
/** Probe one platform with `fc-list -q`; `false` when fc-list is absent. */
|
|
56
|
+
async function probeLinux(env) {
|
|
57
|
+
for (const candidate of NERD_FONT_CANDIDATES) {
|
|
58
|
+
try {
|
|
59
|
+
// 2s cap: a broken fontconfig / stale NFS font dir must fall through to
|
|
60
|
+
// the plain glyphs instead of hanging the TUI startup.
|
|
61
|
+
await env.execFile('fc-list', ['-q', candidate], { timeout: 2000 });
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// fc-list missing (ENOENT), timed out, or the family not installed —
|
|
66
|
+
// try the next.
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
/** Probe macOS by scanning the two font directories for matching file names. */
|
|
72
|
+
async function probeDarwin(env) {
|
|
73
|
+
for (const dir of [join(env.home, 'Library', 'Fonts'), '/Library/Fonts']) {
|
|
74
|
+
let names;
|
|
75
|
+
try {
|
|
76
|
+
names = await env.readdir(dir);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
continue; // missing/unreadable directory — try the next
|
|
80
|
+
}
|
|
81
|
+
for (const name of names) {
|
|
82
|
+
if (NERD_FONT_FILE_RE.test(name))
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The full probe against an injected environment: Linux uses fc-list, macOS
|
|
90
|
+
* uses the font-directory scan, every other platform reports `false`. Never
|
|
91
|
+
* throws — every platform path is wrapped or falls through to `false`.
|
|
92
|
+
*/
|
|
93
|
+
export async function probeNerdFont(env) {
|
|
94
|
+
switch (env.platform) {
|
|
95
|
+
case 'linux':
|
|
96
|
+
return probeLinux(env);
|
|
97
|
+
case 'darwin':
|
|
98
|
+
return probeDarwin(env);
|
|
99
|
+
default:
|
|
100
|
+
// Windows and the rest: no free probe, conservative plain answer.
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/** Module-level memo: the TUI probes once per process, never again. */
|
|
105
|
+
let cachedNerdFont;
|
|
106
|
+
/**
|
|
107
|
+
* Detect whether a Nerd/Powerline font is available, memoised. The first call
|
|
108
|
+
* (TUI startup, src/index.ts) runs the platform probe and caches the result;
|
|
109
|
+
* every later call — including a hot-applied 'auto' iconSet change — resolves
|
|
110
|
+
* against the same startup snapshot. Never throws.
|
|
111
|
+
*/
|
|
112
|
+
export function detectNerdFontAvailable(env = realEnv) {
|
|
113
|
+
if (cachedNerdFont !== undefined)
|
|
114
|
+
return Promise.resolve(cachedNerdFont);
|
|
115
|
+
return probeNerdFont(env).then((value) => {
|
|
116
|
+
cachedNerdFont = value;
|
|
117
|
+
return value;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/** Drop the memoised result — a test seam (deterministic probe tests). */
|
|
121
|
+
export function resetNerdFontCache() {
|
|
122
|
+
cachedNerdFont = undefined;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=font-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"font-detect.js","sourceRoot":"","sources":["../src/font-detect.ts"],"names":[],"mappings":"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"}
|
package/lib/footer.d.ts
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Segments (left → right): fixed brand "dsh" · provider · model+thinking ·
|
|
5
5
|
* context usage · cache-hit rate · message count · tool count, then a
|
|
6
6
|
* right-aligned 24h clock. Segment backgrounds are the pi-powerline-footer
|
|
7
|
-
* palette; separators are
|
|
8
|
-
*
|
|
7
|
+
* palette; separators are the powerline arrow from src/icons.ts (U+E0B0 in
|
|
8
|
+
* nerdfont/auto-with-font, ▸ in the plain icon set), tinted by the
|
|
9
|
+
* neighbouring segment colours.
|
|
9
10
|
*
|
|
10
11
|
* Render cost is O(segments): every statistic is read from the bridge's
|
|
11
12
|
* incrementally maintained counters (never a session-log scan). The 1s clock
|
package/lib/footer.js
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Segments (left → right): fixed brand "dsh" · provider · model+thinking ·
|
|
5
5
|
* context usage · cache-hit rate · message count · tool count, then a
|
|
6
6
|
* right-aligned 24h clock. Segment backgrounds are the pi-powerline-footer
|
|
7
|
-
* palette; separators are
|
|
8
|
-
*
|
|
7
|
+
* palette; separators are the powerline arrow from src/icons.ts (U+E0B0 in
|
|
8
|
+
* nerdfont/auto-with-font, ▸ in the plain icon set), tinted by the
|
|
9
|
+
* neighbouring segment colours.
|
|
9
10
|
*
|
|
10
11
|
* Render cost is O(segments): every statistic is read from the bridge's
|
|
11
12
|
* incrementally maintained counters (never a session-log scan). The 1s clock
|
|
@@ -15,6 +16,7 @@ import { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
|
|
|
15
16
|
import { ansiBg, ansiFg, BOLD, POWERLINE, RESET } from "./theme/index.js";
|
|
16
17
|
import { hexIsLight } from "./theme/palette.js";
|
|
17
18
|
import { clipToWidth } from "./text.js";
|
|
19
|
+
import { arrowRight } from "./icons.js";
|
|
18
20
|
/**
|
|
19
21
|
* The footer keybinding hint, assembled from the user's `dsh-tui.footerHints`
|
|
20
22
|
* selection (see buildFooterHint) - the pre-feature full string is what the
|
|
@@ -80,7 +82,6 @@ export class FooterHint {
|
|
|
80
82
|
return [` ${styled}${pad} `];
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
|
-
const ARROW_RIGHT = '\uE0B0';
|
|
84
85
|
const WHITE = ansiFg('#FFFFFF');
|
|
85
86
|
/** Segment text on bright fills (e.g. amber #FFC107): white is unreadable there. */
|
|
86
87
|
const DARK_TEXT = ansiFg('#1f2328');
|
|
@@ -103,10 +104,10 @@ function buildSegments(segs) {
|
|
|
103
104
|
const s = segs[i];
|
|
104
105
|
out += `${ansiBg(s.bgHex)}${BOLD}${segmentText(s.bgHex)} ${s.label} `;
|
|
105
106
|
if (i + 1 < segs.length) {
|
|
106
|
-
out += `${ansiBg(segs[i + 1].bgHex)}${ansiFg(s.bgHex)}${
|
|
107
|
+
out += `${ansiBg(segs[i + 1].bgHex)}${ansiFg(s.bgHex)}${arrowRight()}`;
|
|
107
108
|
}
|
|
108
109
|
else {
|
|
109
|
-
out += RESET + ansiFg(s.bgHex) +
|
|
110
|
+
out += RESET + ansiFg(s.bgHex) + arrowRight() + RESET;
|
|
110
111
|
}
|
|
111
112
|
}
|
|
112
113
|
return out;
|
|
@@ -157,11 +158,18 @@ export class PowerlineFooter {
|
|
|
157
158
|
bgHex: thinkingBg(effort),
|
|
158
159
|
});
|
|
159
160
|
}
|
|
160
|
-
// Context usage:
|
|
161
|
+
// Context usage: the current occupancy estimate (latest request's billed
|
|
162
|
+
// input + output + a CJK estimate of messages after it) vs. the model's
|
|
163
|
+
// window — NOT the cumulative inputTokens, which only grows. Percent is
|
|
164
|
+
// capped at 100 (the window is a hard ceiling; the estimate can overshoot
|
|
165
|
+
// while it prices pending messages that a compaction will drop).
|
|
161
166
|
const window = this.source.getContextWindow();
|
|
162
|
-
|
|
167
|
+
// Defensive `?? 0`: a stats source without the field (any object missing
|
|
168
|
+
// contextTokens) degrades to an empty context instead of rendering
|
|
169
|
+
// `undefined`/`NaN` in the segment.
|
|
170
|
+
const used = stats.contextTokens ?? 0;
|
|
163
171
|
if (window !== undefined && window > 0) {
|
|
164
|
-
const percent = (used / window) * 100;
|
|
172
|
+
const percent = Math.min(100, (used / window) * 100);
|
|
165
173
|
segs.push({
|
|
166
174
|
label: `🧠 ${fmtNum(used)}/${fmtNum(window)}(${percent.toFixed(1)}%)`,
|
|
167
175
|
bgHex: contextBg(percent),
|
package/lib/footer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"footer.js","sourceRoot":"","sources":["../src/footer.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"footer.js","sourceRoot":"","sources":["../src/footer.ts"],"names":[],"mappings":"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"}
|
package/lib/icons.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Icon handling for dsh-tui-pi (icon-set self-adaptation).
|
|
3
|
+
*
|
|
4
|
+
* Glyph-risk classification for every symbol this TUI renders:
|
|
5
|
+
*
|
|
6
|
+
* - PUA, must fall back — the ONLY Private Use Area codepoint in the whole
|
|
7
|
+
* project is the powerline separator U+E0B0 (footer's arrow between
|
|
8
|
+
* segments). No default terminal font ships it, so a terminal without a
|
|
9
|
+
* Nerd Font shows a tofu box. `auto`/`plain` swap it for `▸` U+25B8.
|
|
10
|
+
*
|
|
11
|
+
* - Standard Unicode, weak-terminal-risky — U+23F9 `⏹` (stop) and U+2B58
|
|
12
|
+
* `⭘` (heavy circle) are standard codepoints, but weak terminals /
|
|
13
|
+
* emoji-less fonts still render them as boxes. `auto`/`plain` swap them
|
|
14
|
+
* for `■` U+25A0 and `●` U+25CF.
|
|
15
|
+
*
|
|
16
|
+
* - Standard Unicode, rely on system fallback — everything else
|
|
17
|
+
* (⚙ ⚠ ⚡ ✓ ✔ ✗ ✘ ⌘ ⎇ ⓘ ◐ ☑ ☐ ◔ ◑ ◕ ◉ ○ ★ ☁ 🤖 🧠 💬 🔧 ● …). Modern
|
|
18
|
+
* terminals resolve these via font fallback and they are left untouched
|
|
19
|
+
* in every mode.
|
|
20
|
+
*
|
|
21
|
+
* Modes (`dsh-tui.iconSet`, persisted in the settings namespace):
|
|
22
|
+
* - 'nerdfont': use the PUA powerline glyph (assumes a Nerd Font is the
|
|
23
|
+
* terminal's font).
|
|
24
|
+
* - 'plain': use the safe standard-Unicode stand-ins for every risky glyph.
|
|
25
|
+
* - 'auto' (default): nerdfont when a Nerd Font is detected at startup,
|
|
26
|
+
* plain otherwise (see src/font-detect.ts).
|
|
27
|
+
*
|
|
28
|
+
* The resolved mode lives in module state: `applyIconSet` is called once at
|
|
29
|
+
* TUI startup and again on every hot-applied `iconSet` settings change, so
|
|
30
|
+
* footer/notice/panel accessors return the right glyph at render time. The
|
|
31
|
+
* module defaults to 'nerdfont' — the pre-feature output (`\uE0B0`) is
|
|
32
|
+
* preserved unless the resolution lands on 'plain'.
|
|
33
|
+
*/
|
|
34
|
+
/** The persisted/`auto` icon-set mode; 'auto' resolves at startup. */
|
|
35
|
+
export type IconSet = 'auto' | 'nerdfont' | 'plain';
|
|
36
|
+
/** A resolved (non-auto) icon set — the value that drives glyph selection. */
|
|
37
|
+
export type ResolvedIconSet = Exclude<IconSet, 'auto'>;
|
|
38
|
+
/**
|
|
39
|
+
* Resolve an icon-set mode against the startup font detection: `auto` picks
|
|
40
|
+
* the nerdfont glyphs when a Nerd Font is available and the plain fallbacks
|
|
41
|
+
* otherwise; an explicit `nerdfont`/`plain` pin returns itself unchanged.
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolveIconSet(mode: IconSet, nerdfontAvailable: boolean): IconSet;
|
|
44
|
+
/** Set the live resolved icon set (startup + hot-apply, src/index.ts). */
|
|
45
|
+
export declare function applyIconSet(set: IconSet): void;
|
|
46
|
+
/** The live resolved icon set (exposed for tests and the /settings UI). */
|
|
47
|
+
export declare function getResolvedIconSet(): ResolvedIconSet;
|
|
48
|
+
/** The powerline segment separator: `\uE0B0` (nerdfont) / `▸` (plain). */
|
|
49
|
+
export declare function arrowRight(set?: IconSet): string;
|
|
50
|
+
/** The stop glyph: `⏹` (nerdfont) / `■` (plain). */
|
|
51
|
+
export declare function stopIcon(set?: IconSet): string;
|
|
52
|
+
/** The subagent glyph: `⭘` (nerdfont) / `●` (plain). */
|
|
53
|
+
export declare function sunglassesIcon(set?: IconSet): string;
|