@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
package/lib/tui.js CHANGED
@@ -30,17 +30,24 @@ export function startTui(options = {}) {
30
30
  // getter, baked closures below) observes the new bundle on the next call.
31
31
  let themeRef = resolveTheme(process.env, options.themePreference ?? 'auto');
32
32
  // App-owned canvas: the write-stream decorator injects the palette's
33
- // canvas background before every erase sequence (BCE — see
34
- // canvas-terminal.ts), so a theme switch recolors the WHOLE screen, not
35
- // only the surfaces that paint their own bg. Without it the terminal
36
- // default background shows through the unpainted rows and "freezes" on
33
+ // canvas colors around every erase sequence and after every color reset
34
+ // (BCE + re-injection — see canvas-terminal.ts), so a theme switch
35
+ // recolors the WHOLE screen, not only the surfaces that paint their own
36
+ // colors. The foreground matters as much as the background: unstyled
37
+ // content (editor input, unselected picker rows) would otherwise fall
38
+ // back to the terminal's default foreground — dark text when the host
39
+ // terminal is light-themed (pi never paints a canvas so its unstyled
40
+ // text always matches; we paint, so we own both channels). Without the
41
+ // canvas the terminal default background shows through and "freezes" on
37
42
  // switch — most visible inside cmux/gostty, where the pane background
38
43
  // belongs to the multiplexer. DSH_TUI_TRANSPARENT=1 opts back into the
39
44
  // old see-through canvas for users who want their terminal theme to stay
40
45
  // visible.
41
46
  const paintCanvas = process.env.DSH_TUI_TRANSPARENT !== '1';
42
- if (paintCanvas)
47
+ if (paintCanvas) {
43
48
  terminal.setCanvasBackground(ansiBg(themeRef.palette.canvas));
49
+ terminal.setCanvasForeground(ansiFg(themeRef.palette.fgDefault));
50
+ }
44
51
  // ------------------------------------------------------------- component tree --
45
52
  // Live Todos widget, pinned ABOVE the chat input: a plain Container with
46
53
  // auto height — it renders zero rows while empty and grows to its
@@ -172,8 +179,10 @@ export function startTui(options = {}) {
172
179
  if (theme === themeRef)
173
180
  return;
174
181
  themeRef = theme;
175
- if (paintCanvas)
182
+ if (paintCanvas) {
176
183
  terminal.setCanvasBackground(ansiBg(theme.palette.canvas));
184
+ terminal.setCanvasForeground(ansiFg(theme.palette.fgDefault));
185
+ }
177
186
  rebuildEditor();
178
187
  // Forced full redraw: the diff renderer skips content-unchanged rows
179
188
  // (blank fillers render as '' under both themes), which would leave
package/lib/tui.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EACL,SAAS,EACT,UAAU,EACV,eAAe,EACf,UAAU,EACV,MAAM,EACN,IAAI,EACJ,YAAY,EACZ,MAAM,GAGP,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAoC,MAAM,aAAa,CAAA;AAClG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAuC,MAAM,kBAAkB,CAAA;AAqE3G,MAAM,UAAU,QAAQ,CAAC,UAA2B,EAAE;IACpD,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,IAAI,eAAe,EAAE,CAAC,CAAA;IAC1D,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IAC5C,wEAAwE;IACxE,0EAA0E;IAC1E,IAAI,QAAQ,GAAa,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,eAAe,IAAI,MAAM,CAAC,CAAA;IACrF,qEAAqE;IACrE,2DAA2D;IAC3D,wEAAwE;IACxE,qEAAqE;IACrE,uEAAuE;IACvE,sEAAsE;IACtE,uEAAuE;IACvE,yEAAyE;IACzE,WAAW;IACX,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,GAAG,CAAA;IAC3D,IAAI,WAAW;QAAE,QAAQ,CAAC,mBAAmB,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;IAE9E,kFAAkF;IAClF,yEAAyE;IACzE,kEAAkE;IAClE,sDAAsD;IACtD,MAAM,OAAO,GAAG,IAAI,SAAS,EAAE,CAAA;IAC/B,MAAM,UAAU,GAAG,IAAI,SAAS,EAAE,CAAA;IAClC,MAAM,cAAc,GAAG,IAAI,UAAU,CAAC,UAAU,EAAE;QAChD,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,OAAO;KACpB,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,IAAI,SAAS,EAAE,CAAA;IAC9B,uEAAuE;IACvE,uEAAuE;IACvE,kCAAkC;IAClC,IAAI,MAAM,GAAG,IAAI,eAAe,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE;QACpE,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,KAAK;KACnE,CAAC,CAAA;IACF,sEAAsE;IACtE,2DAA2D;IAC3D,IAAI,cAAc,GAAqC,OAAO,CAAC,WAAW,CAAA;IAC1E,qDAAqD;IACrD,IAAI,oBAAsD,CAAA;IAC1D,IAAI,cAAsD,CAAA;IAC1D,IAAI,kBAA0D,CAAA;IAC9D,2EAA2E;IAC3E,4EAA4E;IAC5E,wEAAwE;IACxE,qDAAqD;IACrD,MAAM,WAAW,GAAG,IAAI,SAAS,EAAE,CAAA;IACnC,MAAM,MAAM,GAAG,IAAI,SAAS,EAAE,CAAA;IAE9B,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC;QACtB,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QAC7C,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QACjD,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;KAC7C,CAAC,CAAA;IAEF,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC;QACtB,EAAE,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QACvE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;KACnE,CAAC,CAAA;IAEF,mFAAmF;IACnF,MAAM,WAAW,GAAG,gDAAgD,CAAA;IACpE,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,WAAW,GAAG,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAC5F,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;IAChC,UAAU,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IAElC,MAAM,CAAC,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAE;QACjC,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAM;QAC9B,uEAAuE;QACvE,uEAAuE;QACvE,4EAA4E;QAC5E,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;QACzB,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;YACtB,OAAM;QACR,CAAC;QACD,wCAAwC;QACxC,UAAU,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAC9E,UAAU,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QAClC,GAAG,CAAC,aAAa,EAAE,CAAA;IACrB,CAAC,CAAA;IAED;;;;;;;;OAQG;IACH,SAAS,aAAa;QACpB,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAA;QAC7B,sEAAsE;QACtE,0EAA0E;QAC1E,4EAA4E;QAC5E,yEAAyE;QACzE,gEAAgE;QAChE,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAA;QACnC,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,EAAE,CAAA;QACtC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAA;QAC/B,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE;YACpE,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,KAAK;SACnE,CAAC,CAAA;QACF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAClB,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAA;QAC/B,uEAAuE;QACvE,mEAAmE;QACnE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;QAC3B,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAA;QAC/B,IAAI,oBAAoB,KAAK,SAAS;YAAE,IAAI,CAAC,uBAAuB,CAAC,oBAAoB,CAAC,CAAA;QAC1F,IAAI,cAAc,KAAK,SAAS;YAAE,IAAI,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAA;QACxE,IAAI,kBAAkB,KAAK,SAAS;YAAE,IAAI,CAAC,qBAAqB,CAAC,kBAAkB,CAAC,CAAA;QACpF,IAAI,CAAC,KAAK,EAAE,CAAA;QACZ,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;QAChD,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;QACjD,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;QAC9C,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;QACrD,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;QAChD,MAAM,GAAG,IAAI,CAAA;QACb,IAAI,QAAQ;YAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACpC,CAAC;IAED,iFAAiF;IACjF,MAAM,MAAM,GAAc;QACxB,OAAO;YACL,GAAG,CAAC,IAAI,EAAE,CAAA;QACZ,CAAC;QACD,GAAG;QACH,UAAU;QACV,OAAO;QACP,WAAW;QACX,MAAM;QACN,IAAI,MAAM;YACR,OAAO,MAAM,CAAA;QACf,CAAC;QACD,MAAM;QACN,aAAa;YACX,GAAG,CAAC,aAAa,EAAE,CAAA;QACrB,CAAC;QACD,IAAI,KAAK;YACP,OAAO,QAAQ,CAAA;QACjB,CAAC;QACD,UAAU,CAAC,KAAe;YACxB,IAAI,KAAK,KAAK,QAAQ;gBAAE,OAAM;YAC9B,QAAQ,GAAG,KAAK,CAAA;YAChB,IAAI,WAAW;gBAAE,QAAQ,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;YAC3E,aAAa,EAAE,CAAA;YACf,qEAAqE;YACrE,oEAAoE;YACpE,+CAA+C;YAC/C,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;QACzB,CAAC;QACD,6BAA6B,CAAC,QAA8B;YAC1D,oBAAoB,GAAG,QAAQ,CAAA;YAC/B,MAAM,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAA;QAC1C,CAAC;QACD,uBAAuB,CAAC,QAAkC;YACxD,cAAc,GAAG,QAAQ,CAAA;YACzB,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAA;QACpC,CAAC;QACD,2BAA2B,CAAC,QAAkC;YAC5D,kBAAkB,GAAG,QAAQ,CAAA;YAC7B,MAAM,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAA;QACxC,CAAC;QACD,cAAc,CAAC,QAA8B;YAC3C,cAAc,GAAG,QAAQ,CAAA;QAC3B,CAAC;KACF,CAAA;IAED,iFAAiF;IACjF,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IAEpB;;;;;;;;;;;;OAYG;IACH,IAAI,YAAY,GAAG,CAAC,CAAA;IACpB,IAAI,mBAAmB,GAAG,CAAC,CAAA;IAC3B,IAAI,cAAc,GAAG,CAAC,CAAA;IACtB,IAAI,mBAAmB,GAAG,CAAC,CAAA;IAC3B,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAA;IACpD,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAA;IAE9D,GAAG,CAAC,gBAAgB,CAAC,CAAC,IAAY,EAAE,EAAE;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE;YACpC,OAAO,EAAE,SAAS,EAAE;YACpB,WAAW,EAAE,GAAG,CAAC,UAAU,EAAE;YAC7B,aAAa,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE;YACtC,gBAAgB,EAAE,MAAM,CAAC,qBAAqB,EAAE;YAChD,aAAa,EAAE,gBAAgB,EAAE;YACjC,YAAY;YACZ,mBAAmB;YACnB,cAAc;YACd,mBAAmB;SACpB,EAAE,GAAG,EAAE,cAAc,CAAC,CAAA;QACvB,qEAAqE;QACrE,mEAAmE;QACnE,uEAAuE;QACvE,uEAAuE;QACvE,wEAAwE;QACxE,yEAAyE;QACzE,0EAA0E;QAC1E,mEAAmE;QACnE,yEAAyE;QACzE,uEAAuE;QACvE,iEAAiE;QACjE,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,IAAI,MAAM,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAC1E,YAAY,GAAG,GAAG,CAAA;QACpB,CAAC;aAAM,IAAI,MAAM,CAAC,IAAI,KAAK,oBAAoB,IAAI,MAAM,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YACtF,mBAAmB,GAAG,GAAG,CAAA;QAC3B,CAAC;aAAM,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACzC,mBAAmB,GAAG,GAAG,CAAA;QAC3B,CAAC;QACD,uEAAuE;QACvE,qEAAqE;QACrE,0EAA0E;QAC1E,yEAAyE;QACzE,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,UAAU,CAAC,IAAI,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9F,cAAc,GAAG,GAAG,CAAA;QACtB,CAAC;QACD,oEAAoE;QACpE,iEAAiE;QACjE,8DAA8D;QAC9D,iEAAiE;QACjE,wCAAwC;QACxC,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,KAAK,oBAAoB,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM;eAC1F,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,MAAM,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;YAC3G,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;gBACtC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;YAC7B,CAAC;iBAAM,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,IAAI,MAAM,CAAC,IAAI,KAAK,cAAc;mBACvE,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;gBACpE,mEAAmE;gBACnE,wEAAwE;gBACxE,sEAAsE;gBACtE,gDAAgD;gBAChD,MAAM,CAAC,OAAO,EAAE,CAAA;gBAChB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACnB,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IACxD,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;IAEvB,IAAI,CAAC;QACH,GAAG,CAAC,KAAK,EAAE,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,gEAAgE;QAChE,IAAI,CAAC;YAAC,GAAG,CAAC,IAAI,EAAE,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,iBAAiB,CAAC,CAAC;QAC9C,MAAM,KAAK,CAAA;IACb,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
1
+ {"version":3,"file":"tui.js","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiwayds/dsh-tui-pi",
3
- "version": "0.8.2",
3
+ "version": "0.9.0",
4
4
  "description": "pi-style terminal UI for DeepSeek Harness (dsh) — pi-tui look & feel, dsh slash commands, GitHub light/dark themes, powerline footer",
5
5
  "repository": {
6
6
  "type": "git",
@@ -32,6 +32,7 @@
32
32
  "cordis.patch.yml",
33
33
  "scripts",
34
34
  "templates",
35
+ "assets",
35
36
  "README.md",
36
37
  "LICENSE"
37
38
  ],
@@ -0,0 +1,329 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Install the bundled terminal font and point the user's terminal at it.
4
+ *
5
+ * The TUI's icon-set self-adaptation (src/icons.ts) resolves 'auto' to the
6
+ * powerline glyphs only when a Nerd/Powerline-capable font is the terminal's
7
+ * MAIN font — no default terminal font ships the powerline separator U+E0B0,
8
+ * so without one 'auto' falls back to the plain Unicode stand-ins. This
9
+ * script installs the tiny bundled subset (assets/fonts/dsh-tui-pi-nerd.ttf,
10
+ * ASCII + U+E0B0 + the whole project glyph set, ~170KB) and flips the
11
+ * terminal to it, preserving the current font size where the terminal
12
+ * expresses one.
13
+ *
14
+ * Zero dependencies and fully best-effort: every step is wrapped in
15
+ * try/catch — a failure logs a warning and the script moves on. It never
16
+ * aborts mid-way and never corrupts user configuration (config files are
17
+ * backed up before editing and restored on failure; preferences are only
18
+ * written through PlistBuddy/gsettings/defaults with the original value
19
+ * read first).
20
+ *
21
+ * - Font install
22
+ * macOS → cp → ~/Library/Fonts/ (physical copy, never a symlink)
23
+ * Linux → cp → ~/.local/share/fonts/ + fc-cache -f
24
+ * other → skipped (no free font directory)
25
+ *
26
+ * - Terminal config (best-effort, per platform/terminal)
27
+ * macOS iTerm2 → PlistBuddy against the Default Bookmark's
28
+ * "Normal Font" (PostScript name DSHTUINerd,
29
+ * keeping the current size); `defaults write
30
+ * com.googlecode.iterm2 "Normal Font"` as an
31
+ * extra best-effort key.
32
+ * macOS Terminal.app → skipped — its font is a binary blob in the
33
+ * plist; set it by hand (Settings → Profiles →
34
+ * Text → Font).
35
+ * Linux GNOME Terminal → gsettings set use-system-font=false + font on
36
+ * the default profile.
37
+ * Linux kitty / alacritty / wezterm → edit the config file
38
+ * (font_family / [font] family / wezterm.font),
39
+ * backing the file up first and restoring on
40
+ * failure.
41
+ * SSH / xterm / urxvt / unknown / Windows → skipped (no safe write).
42
+ *
43
+ * Usage: node scripts/install-font.mjs
44
+ */
45
+
46
+ import { execFileSync } from 'node:child_process'
47
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
48
+ import { homedir } from 'node:os'
49
+ import { dirname, join } from 'node:path'
50
+ import { fileURLToPath } from 'node:url'
51
+
52
+ const repoRoot = dirname(dirname(fileURLToPath(import.meta.url)))
53
+ const FONT_SRC = join(repoRoot, 'assets', 'fonts', 'dsh-tui-pi-nerd.ttf')
54
+ const FONT_FILE = 'dsh-tui-pi-nerd.ttf'
55
+ /** Family name (font nameID 1) — GNOME/kitty/alacritty/wezterm use this. */
56
+ const FONT_FAMILY = 'DSH TUI Nerd'
57
+ /** PostScript name (font nameID 6) — iTerm2's "Normal Font" key uses this. */
58
+ const FONT_POSTSCRIPT = 'DSHTUINerd'
59
+
60
+ /**
61
+ * The install environment — the real platform/home by default, injected by
62
+ * tests (test scripts point it at a sandbox home / a fake platform to drive
63
+ * the copy + config paths without touching the real home).
64
+ */
65
+ export const env = {
66
+ platform: process.platform,
67
+ home: homedir(),
68
+ }
69
+
70
+ const PLISTBUDDY = '/usr/libexec/PlistBuddy'
71
+
72
+ const log = {
73
+ info: (msg) => console.log(`[install-font] ${msg}`),
74
+ ok: (msg) => console.log(`[install-font] ✓ ${msg}`),
75
+ warn: (msg) => console.warn(`[install-font] ! ${msg}`),
76
+ }
77
+
78
+ /** Run a command; `null` on failure (missing binary, nonzero exit). */
79
+ export function sh(cmd, args) {
80
+ try {
81
+ return execFileSync(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf8' }).trim()
82
+ } catch {
83
+ return null
84
+ }
85
+ }
86
+
87
+ /** True when the script runs inside an SSH session (terminal config would hit the remote). */
88
+ function isSsh() {
89
+ return Boolean(process.env.SSH_CONNECTION || process.env.SSH_TTY)
90
+ }
91
+
92
+ // ------------------------------------------------------------- font install --
93
+
94
+ /** Copy the bundled font into the platform font directory; false when skipped. */
95
+ export function installFont() {
96
+ if (env.platform === 'darwin') {
97
+ const dir = join(env.home, 'Library', 'Fonts')
98
+ mkdirSync(dir, { recursive: true })
99
+ copyFileSync(FONT_SRC, join(dir, FONT_FILE))
100
+ return dir
101
+ }
102
+ if (env.platform === 'linux') {
103
+ const dir = join(env.home, '.local', 'share', 'fonts')
104
+ mkdirSync(dir, { recursive: true })
105
+ copyFileSync(FONT_SRC, join(dir, FONT_FILE))
106
+ // Refresh the fontconfig cache so the family resolves immediately.
107
+ const refreshed = sh('fc-cache', ['-f', dir])
108
+ if (refreshed === null) log.warn('fc-cache refresh skipped (fc-cache not found)')
109
+ return dir
110
+ }
111
+ log.warn(`font install skipped on ${env.platform} (no free font directory; copy ${FONT_FILE} by hand)`)
112
+ return null
113
+ }
114
+
115
+ // --------------------------------------------------------- config file edit --
116
+
117
+ /** Edit a text config file under a backup; restore on failure. Returns true when changed. */
118
+ function editConfigWithBackup(path, transform) {
119
+ if (!existsSync(path)) return false
120
+ const backup = `${path}.dsh-tui.bak`
121
+ try {
122
+ if (!existsSync(backup)) copyFileSync(path, backup)
123
+ const changed = transform(readFileSync(path, 'utf8'))
124
+ if (changed === null) return false
125
+ writeFileSync(path, changed)
126
+ return true
127
+ } catch (error) {
128
+ // Restore the original so a botched edit never leaves a broken config.
129
+ try { copyFileSync(backup, path) } catch { /* best effort */ }
130
+ throw error
131
+ }
132
+ }
133
+
134
+ /** kitty: `font_family` (replace the existing line, or append one). */
135
+ export function kittyTransform(text) {
136
+ const line = `font_family ${FONT_FAMILY}`
137
+ if (/^\s*font_family\b/m.test(text)) return text.replace(/^\s*font_family\s+.*$/m, line)
138
+ return `${text.replace(/\s*$/, '')}\n${line}\n`
139
+ }
140
+
141
+ /** alacritty (TOML): `family = "…"` under `[font]`; append a `[font.normal]` block when absent. */
142
+ export function alacrittyTomlTransform(text) {
143
+ if (text.includes('[font')) {
144
+ if (/^\s*family\s*=/m.test(text)) return text.replace(/^(\s*family\s*=\s*")[^"]*(".*)$/m, `$1${FONT_FAMILY}$2`)
145
+ return `${text.replace(/\s*$/, '')}\n[font.normal]\nfamily = "${FONT_FAMILY}"\n`
146
+ }
147
+ return `${text.replace(/\s*$/, '')}\n[font.normal]\nfamily = "${FONT_FAMILY}"\n`
148
+ }
149
+
150
+ /** alacritty (legacy YAML): `family: "…"` under `font: normal:`; append otherwise. */
151
+ export function alacrittyYmlTransform(text) {
152
+ if (/^font:\s*\n(\s*)normal:\s*\n\s*family:/m.test(text)) {
153
+ return text.replace(/^(font:\s*\n\s*normal:\s*\n\s*family:).*$/m, `$1 "${FONT_FAMILY}"`)
154
+ }
155
+ return `${text.replace(/\s*$/, '')}\nfont:\n normal:\n family: "${FONT_FAMILY}"\n`
156
+ }
157
+
158
+ /** wezterm: replace `wezterm.font("…")` calls / `config.font`, or append a font line. */
159
+ export function weztermTransform(text) {
160
+ // wezterm.font_with_fallback("Primary", "Fallback", …) — replace only the
161
+ // primary font so the user's fallback list survives.
162
+ if (/wezterm\.font_with_fallback\(\s*"[^"]*"/.test(text)) {
163
+ return text.replace(/wezterm\.font_with_fallback\(\s*"[^"]*"/g, `wezterm.font_with_fallback("${FONT_FAMILY}"`)
164
+ }
165
+ if (/wezterm\.font\(\s*"[^"]*"\s*\)/.test(text)) {
166
+ return text.replace(/wezterm\.font\(\s*"[^"]*"\s*\)/g, `wezterm.font("${FONT_FAMILY}")`)
167
+ }
168
+ const append = `config.font = wezterm.font("${FONT_FAMILY}")`
169
+ if (/^\s*config\.font\s*=/m.test(text)) return text.replace(/^\s*config\.font\s*=.*$/m, append)
170
+ return `${text.replace(/\s*$/, '')}\n${append}\n`
171
+ }
172
+
173
+ // ------------------------------------------------------------- iTerm2 (mac) --
174
+
175
+ /** PlistBuddy read of one key; `null` when the key/file is absent. */
176
+ function pbGet(plist, key) {
177
+ return sh(PLISTBUDDY, ['-c', `Print :${key}`, plist])
178
+ }
179
+
180
+ /** The trailing font-size number of an iTerm2 "Normal Font" value ("Menlo-Regular 13" → "13"). */
181
+ export function parseFontSize(value) {
182
+ const match = value === null ? null : value.match(/(\d+(?:\.\d+)?)\s*$/)
183
+ return match === null ? '12' : match[1]
184
+ }
185
+
186
+ /** macOS iTerm2: point the default bookmark's "Normal Font" at the bundled font. */
187
+ export function configureIterm2() {
188
+ const plist = join(env.home, 'Library', 'Preferences', 'com.googlecode.iterm2.plist')
189
+ if (!existsSync(plist)) return 'iTerm2 plist not found (start iTerm2 once, then re-run)'
190
+ // PlistBuddy paths: keys with spaces MUST be quoted (`:"New Bookmarks"`).
191
+ const guid = pbGet(plist, '"Default Bookmark Guid"')
192
+ if (guid === null) return 'no Default Bookmark Guid in the iTerm2 plist'
193
+ // Find the bookmark index carrying the default guid (bounded scan).
194
+ let index = -1
195
+ for (let i = 0; i < 128; i++) {
196
+ const candidate = pbGet(plist, `"New Bookmarks":${i}:Guid`)
197
+ if (candidate === null) break
198
+ if (candidate === guid) { index = i; break }
199
+ }
200
+ if (index < 0) return `default bookmark (${guid}) not found in New Bookmarks`
201
+ const size = parseFontSize(pbGet(plist, `"New Bookmarks":${index}:"Normal Font"`))
202
+ const value = `${FONT_POSTSCRIPT} ${size}`
203
+ // Prefer a targeted write on the default bookmark; a direct `defaults write`
204
+ // of the legacy "Normal Font" key is a harmless best-effort extra.
205
+ const pb = sh(PLISTBUDDY, ['-c', `Set :"New Bookmarks":${index}:"Normal Font" "${value}"`, plist])
206
+ const dw = sh('defaults', ['write', 'com.googlecode.iterm2', 'Normal Font', '-string', value])
207
+ if (pb === null && dw === null) return `could not write iTerm2 "Normal Font" (${value})`
208
+ return `iTerm2 default bookmark → "${value}" (size preserved)`
209
+ }
210
+
211
+ // ------------------------------------------------------ GNOME Terminal (linux) --
212
+
213
+ /** Strip the surrounding quotes gsettings wraps string values in (`'Ubuntu Mono 11'`). */
214
+ function unquote(value) {
215
+ return value === null ? null : value.replace(/^'|'$/g, '')
216
+ }
217
+
218
+ /**
219
+ * The font size to preserve when switching a GNOME Terminal profile to the
220
+ * bundled font — the font actually in use: the profile's `font` while
221
+ * `use-system-font` is false, else the desktop monospace font. Raw gsettings
222
+ * string values (possibly null / quoted) in, a numeric size string out, '12'
223
+ * fallback when nothing readable.
224
+ */
225
+ export function gnomeSizeToPreserve(useSystemFont, profileFont, desktopMono) {
226
+ if (useSystemFont === 'true') return parseFontSize(unquote(desktopMono))
227
+ return parseFontSize(unquote(profileFont))
228
+ }
229
+
230
+ /** Linux GNOME Terminal: switch the default profile off system font + set ours. */
231
+ export function configureGnomeTerminal() {
232
+ const profileId = sh('gsettings', ['get', 'org.gnome.Terminal.ProfilesList', 'default'])
233
+ if (profileId === null) return 'gsettings not available (no GNOME Terminal?)'
234
+ const id = profileId.replace(/^'|'$/g, '')
235
+ if (id === '') return 'no default GNOME Terminal profile'
236
+ const base = `org.gnome.Terminal.Legacy.Profile:/org/gnome/terminal/legacy/profiles:/:${id}/`
237
+ // Preserve the current font size: read the font in use before flipping
238
+ // use-system-font off, then backfill our family at that size.
239
+ const size = gnomeSizeToPreserve(
240
+ sh('gsettings', ['get', base, 'use-system-font']),
241
+ sh('gsettings', ['get', base, 'font']),
242
+ sh('gsettings', ['get', 'org.gnome.desktop.interface', 'monospace-font-name']),
243
+ )
244
+ const s1 = sh('gsettings', ['set', base, 'use-system-font', 'false'])
245
+ const s2 = sh('gsettings', ['set', base, 'font', `${FONT_FAMILY} ${size}`])
246
+ if (s1 === null || s2 === null) return `gsettings write failed for profile ${id}`
247
+ return `GNOME Terminal profile ${id} → "${FONT_FAMILY} ${size}" (use-system-font off)`
248
+ }
249
+
250
+ // ------------------------------------------------------ linux config terminals --
251
+
252
+ /** Linux kitty/alacritty/wezterm: edit the detected config files (best-effort). */
253
+ export function configureLinuxConfigFiles() {
254
+ const candidates = [
255
+ [join(env.home, '.config', 'kitty', 'kitty.conf'), kittyTransform, 'kitty'],
256
+ [join(env.home, '.config', 'alacritty', 'alacritty.toml'), alacrittyTomlTransform, 'alacritty'],
257
+ [join(env.home, '.config', 'alacritty', 'alacritty.yml'), alacrittyYmlTransform, 'alacritty'],
258
+ [join(env.home, '.config', 'wezterm', 'wezterm.lua'), weztermTransform, 'wezterm'],
259
+ ]
260
+ const changed = []
261
+ for (const [path, transform, name] of candidates) {
262
+ if (!existsSync(path)) continue
263
+ try {
264
+ if (editConfigWithBackup(path, transform)) changed.push(`${name} (${path})`)
265
+ } catch (error) {
266
+ log.warn(`${name} config edit failed (${path} restored): ${error instanceof Error ? error.message : String(error)}`)
267
+ }
268
+ }
269
+ return changed
270
+ }
271
+
272
+ // --------------------------------------------------------------- dispatcher --
273
+
274
+ /** Best-effort per-platform terminal configuration; returns the summary line. */
275
+ export function configureTerminal() {
276
+ if (isSsh()) {
277
+ log.warn('SSH session detected — skipping terminal config (set the font in the local terminal)')
278
+ return null
279
+ }
280
+ if (env.platform === 'darwin') {
281
+ const result = (() => { try { return configureIterm2() } catch (error) { return `iTerm2 config failed: ${error instanceof Error ? error.message : String(error)}` } })()
282
+ log.ok(result)
283
+ log.warn('Terminal.app is not supported (its font is a binary blob) — set it in Settings → Profiles → Text')
284
+ return result
285
+ }
286
+ if (env.platform === 'linux') {
287
+ const gnome = (() => { try { return configureGnomeTerminal() } catch (error) { return `GNOME Terminal config failed: ${error instanceof Error ? error.message : String(error)}` } })()
288
+ log.ok(gnome)
289
+ const changed = configureLinuxConfigFiles()
290
+ if (changed.length === 0) log.warn('no kitty/alacritty/wezterm config file found to edit')
291
+ for (const entry of changed) log.ok(`config updated: ${entry}`)
292
+ return `${gnome}${changed.length > 0 ? `; ${changed.length} config file(s) updated` : ''}`
293
+ }
294
+ log.warn(`terminal config not supported on ${env.platform} (xterm/urxvt/Windows) — set the font by hand`)
295
+ return null
296
+ }
297
+
298
+ // ------------------------------------------------------------------- main --
299
+
300
+ function main() {
301
+ log.info('dsh-tui-pi font installer (icon-set "auto" needs a Nerd/Powerline font)')
302
+ if (!existsSync(FONT_SRC)) {
303
+ log.warn(`bundled font not found: ${FONT_SRC}`)
304
+ log.warn('generate it first with: node assets/fonts-gen.mjs')
305
+ return
306
+ }
307
+
308
+ let installDir = null
309
+ try {
310
+ installDir = installFont()
311
+ if (installDir !== null) log.ok(`installed ${FONT_FILE} → ${installDir}`)
312
+ } catch (error) {
313
+ log.warn(`font install failed: ${error instanceof Error ? error.message : String(error)}`)
314
+ }
315
+
316
+ const summary = installDir !== null ? configureTerminal() : null
317
+
318
+ log.info('--- result ---')
319
+ log.info(installDir !== null
320
+ ? `font installed: ${FONT_FILE} (${FONT_FAMILY} / ${FONT_POSTSCRIPT})`
321
+ : 'font NOT installed — see the warnings above')
322
+ log.info(summary !== null ? `terminal config: ${summary}` : 'terminal config: skipped — see the notes above')
323
+ log.info('restart the terminal (or open a new tab) — auto icon-set now resolves to the powerline glyphs')
324
+ }
325
+
326
+ // Run directly (`node scripts/install-font.mjs`); importable for tests otherwise.
327
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
328
+ main()
329
+ }