@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.
Files changed (60) hide show
  1. package/README.md +44 -3
  2. package/README.zh.md +36 -3
  3. package/assets/fonts/LICENSE-Hack.txt +45 -0
  4. package/assets/fonts/LICENSE-NerdFonts.txt +126 -0
  5. package/assets/fonts/LICENSE-NotoSansSymbols.txt +93 -0
  6. package/assets/fonts/LICENSE-NotoSansSymbols2.txt +93 -0
  7. package/assets/fonts/dsh-tui-pi-nerd.ttf +0 -0
  8. package/assets/fonts-gen.mjs +219 -0
  9. package/assets/whale-gen.mjs +169 -0
  10. package/assets/whale-source.png +0 -0
  11. package/lib/agents.js +1 -1
  12. package/lib/agents.js.map +1 -1
  13. package/lib/canvas-terminal.d.ts +17 -11
  14. package/lib/canvas-terminal.js +62 -24
  15. package/lib/canvas-terminal.js.map +1 -1
  16. package/lib/dsh-events.d.ts +32 -3
  17. package/lib/dsh-events.js +14 -0
  18. package/lib/dsh-events.js.map +1 -1
  19. package/lib/font-detect.d.ts +66 -0
  20. package/lib/font-detect.js +124 -0
  21. package/lib/font-detect.js.map +1 -0
  22. package/lib/footer.d.ts +3 -2
  23. package/lib/footer.js +16 -8
  24. package/lib/footer.js.map +1 -1
  25. package/lib/icons.d.ts +53 -0
  26. package/lib/icons.js +78 -0
  27. package/lib/icons.js.map +1 -0
  28. package/lib/index.js +44 -13
  29. package/lib/index.js.map +1 -1
  30. package/lib/live-widgets.d.ts +16 -5
  31. package/lib/live-widgets.js +29 -8
  32. package/lib/live-widgets.js.map +1 -1
  33. package/lib/messages.js +2 -1
  34. package/lib/messages.js.map +1 -1
  35. package/lib/session.d.ts +99 -16
  36. package/lib/session.js +322 -64
  37. package/lib/session.js.map +1 -1
  38. package/lib/sessions.d.ts +15 -0
  39. package/lib/sessions.js +18 -3
  40. package/lib/sessions.js.map +1 -1
  41. package/lib/settings.js +2 -2
  42. package/lib/skills.d.ts +19 -3
  43. package/lib/skills.js +43 -10
  44. package/lib/skills.js.map +1 -1
  45. package/lib/subagent-policy.d.ts +11 -11
  46. package/lib/subagent-policy.js +17 -15
  47. package/lib/subagent-policy.js.map +1 -1
  48. package/lib/subagent-viewer.d.ts +20 -5
  49. package/lib/subagent-viewer.js +29 -15
  50. package/lib/subagent-viewer.js.map +1 -1
  51. package/lib/theme-settings.d.ts +25 -10
  52. package/lib/theme-settings.js +40 -14
  53. package/lib/theme-settings.js.map +1 -1
  54. package/lib/tokens.d.ts +38 -0
  55. package/lib/tokens.js +68 -0
  56. package/lib/tokens.js.map +1 -0
  57. package/lib/tui.js +15 -6
  58. package/lib/tui.js.map +1 -1
  59. package/package.json +2 -1
  60. package/scripts/install-font.mjs +329 -0
@@ -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. Two injections make the whole
6
- * screen carry the theme canvas color without touching pi-tui:
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 background-clearing SGR reset (`\x1b[0m`, `\x1b[m`,
12
- * `\x1b[0;…m`, `\x1b[49m`): content following a reset would otherwise
13
- * print with the terminal default background, punching holes into the
14
- * canvas (invisible with a dark theme on a dark terminal, glaring after
15
- * a switch to light). Re-injecting restores the canvas so every printed
16
- * cell keeps it; spans that set their own background still override it.
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 background of their last paint,
19
- * which is correct until the canvas color changes — the caller must then
20
- * force a full redraw (requestRender(true)).
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
- * Whether an SGR sequence clears the background: the full reset forms
27
- * (`\x1b[0m`, `\x1b[m`, `\x1b[0;…m` combined resets) and the explicit
28
- * background-default (`\x1b[49m`). Color-set sequences whose parameter list
29
- * merely contains a 0 channel (`\x1b[38;5;0m`, `\x1b[48;2;0;121;107m`) do
30
- * NOT clear — treating them as resets paints over intentional surfaces.
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 clearsBackground(params) {
33
- if (params === '' || params === '49')
34
- return true;
35
- return params.split(';', 1)[0] === '0';
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
- // background-clearing resets; kitty image payloads are APC base64/hex
67
- // and never contain ESC bytes.
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) => (clearsBackground(params) ? seq + bg : seq)));
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":"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"}
1
+ {"version":3,"file":"canvas-terminal.js","sourceRoot":"","sources":["../src/canvas-terminal.ts"],"names":[],"mappings":"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"}
@@ -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 (`origin: 'subagent'` +
76
- * `parentSession`). All fields are O(1)-maintained — never a session-log
77
- * scan on the render path.
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
@@ -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 U+E0B0 powerline arrows tinted by the neighbouring
8
- * segment colours.
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 U+E0B0 powerline arrows tinted by the neighbouring
8
- * segment colours.
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)}${ARROW_RIGHT}`;
107
+ out += `${ansiBg(segs[i + 1].bgHex)}${ansiFg(s.bgHex)}${arrowRight()}`;
107
108
  }
108
109
  else {
109
- out += RESET + ansiFg(s.bgHex) + ARROW_RIGHT + RESET;
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: latest request's input tokens vs. the model's window.
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
- const used = stats.inputTokens;
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":"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"}
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;