@aiwayds/dsh-tui-pi 0.8.3 → 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/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/package.json +2 -1
- package/scripts/install-font.mjs +329 -0
|
@@ -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
|
+
}
|