@volter/supercode-teams 0.2.80 → 0.2.82
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/package.json +1 -1
- package/terminal-look.mjs +83 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-teams",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.82",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A machine daemon serving this machine's doors, and a local or remote Teams server for shared session discovery, OpenTelemetry ingestion and access to enrolled machines.",
|
|
6
6
|
"license": "MIT",
|
package/terminal-look.mjs
CHANGED
|
@@ -45,7 +45,7 @@ function run() {
|
|
|
45
45
|
const font = archived('Font');
|
|
46
46
|
return JSON.stringify({
|
|
47
47
|
name, colors,
|
|
48
|
-
font: font && !font.isNil() ? { family: ObjC.unwrap(font.familyName), size: font.pointSize,
|
|
48
|
+
font: font && !font.isNil() ? { family: ObjC.unwrap(font.familyName), size: font.pointSize, advance: font.advancementForGlyph(font.glyphWithName('M')).width, ascender: font.ascender, descender: font.descender, leading: font.leading } : null,
|
|
49
49
|
widthSpacing: value('FontWidthSpacing'), heightSpacing: value('FontHeightSpacing'),
|
|
50
50
|
cursorType: value('CursorType'), cursorBlink: value('CursorBlink'), optionIsMeta: value('useOptionAsMetaKey'),
|
|
51
51
|
bell: value('Bell'), visualBell: value('VisualBell'), brightBold: value('UseBrightBold'),
|
|
@@ -53,6 +53,38 @@ function run() {
|
|
|
53
53
|
});
|
|
54
54
|
}`;
|
|
55
55
|
|
|
56
|
+
// AppKit's conversion of sRGB colours into each screen's colour space, keyed by the screen's scale. WezTerm writes its
|
|
57
|
+
// colours to the screen unconverted, where Terminal.app's are colour-managed: on the owner's external monitor Clear
|
|
58
|
+
// Dark's ground #212734 reached the glass as #212734 from WezTerm and as #1e242d from Terminal.app (#1d232d is AppKit's
|
|
59
|
+
// conversion), so every colour looked lighter and bluer. Two screens at one scale share the main screen's conversion.
|
|
60
|
+
const CONVERT_COLOURS = `
|
|
61
|
+
ObjC.import('AppKit');
|
|
62
|
+
function run(argv) {
|
|
63
|
+
const hexes = JSON.parse(argv[0]);
|
|
64
|
+
const two = (v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, '0');
|
|
65
|
+
const screens = $.NSScreen.screens, out = [];
|
|
66
|
+
for (let i = 0; i < screens.count; i++) {
|
|
67
|
+
const screen = screens.objectAtIndex(i), space = screen.colorSpace, map = {};
|
|
68
|
+
for (const hex of hexes) {
|
|
69
|
+
const [r, g, b] = [1, 3, 5].map((k) => parseInt(hex.slice(k, k + 2), 16) / 255);
|
|
70
|
+
const c = $.NSColor.colorWithSRGBRedGreenBlueAlpha(r, g, b, 1).colorUsingColorSpace(space);
|
|
71
|
+
map[hex] = '#' + two(c.redComponent) + two(c.greenComponent) + two(c.blueComponent);
|
|
72
|
+
}
|
|
73
|
+
out.push({ scale: screen.backingScaleFactor, map });
|
|
74
|
+
}
|
|
75
|
+
return JSON.stringify(out);
|
|
76
|
+
}`;
|
|
77
|
+
|
|
78
|
+
/** Each screen's conversion of `hexes` ([{ scale, map: { hex: hex } }], the main screen first); [] off macOS. */
|
|
79
|
+
export function screenColours(hexes, platform = process.platform) {
|
|
80
|
+
if (platform !== 'darwin' || !hexes.length) return [];
|
|
81
|
+
try {
|
|
82
|
+
return JSON.parse(execFileSync('osascript', ['-l', 'JavaScript', '-e', CONVERT_COLOURS, JSON.stringify(hexes)], { encoding: 'utf8', timeout: 5_000, stdio: ['ignore', 'pipe', 'ignore'] }));
|
|
83
|
+
} catch {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
56
88
|
/** This machine's Terminal.app default profile, as read by AppKit; null off macOS or when it cannot be read. */
|
|
57
89
|
export function terminalAppProfile(platform = process.platform) {
|
|
58
90
|
if (platform !== 'darwin') return null;
|
|
@@ -67,7 +99,7 @@ const hex = ([r, g, b]) => `#${[r, g, b].map((part) => Math.round(Math.min(1, Ma
|
|
|
67
99
|
const lua = (value) => (typeof value === 'string' ? JSON.stringify(value) : String(value));
|
|
68
100
|
|
|
69
101
|
/** WezTerm's config (Lua) for a window that looks like Terminal.app with `profile` (from terminalAppProfile, or null). */
|
|
70
|
-
export function weztermConfig(profile, { fontDirs = existsSync(TERMINAL_FONTS) ? [TERMINAL_FONTS] : [] } = {}) {
|
|
102
|
+
export function weztermConfig(profile, { fontDirs = existsSync(TERMINAL_FONTS) ? [TERMINAL_FONTS] : [], screens = [] } = {}) {
|
|
71
103
|
const mac = fontDirs.length > 0;
|
|
72
104
|
const stored = profile?.colors ?? {};
|
|
73
105
|
// One colour table per appearance: the profile's colour where it stores one, else Basic's for that appearance.
|
|
@@ -85,29 +117,63 @@ export function weztermConfig(profile, { fontDirs = existsSync(TERMINAL_FONTS) ?
|
|
|
85
117
|
};
|
|
86
118
|
};
|
|
87
119
|
const table = (colors) => `{\n${Object.entries(colors).map(([key, value]) => ` ${key} = ${Array.isArray(value) ? `{ ${value.map(lua).join(', ')} }` : lua(value)},`).join('\n')}\n }`;
|
|
88
|
-
|
|
89
|
-
//
|
|
120
|
+
// Terminal.app's face drawn by CoreText is heavier than the same face drawn by WezTerm's FreeType: on the same Retina
|
|
121
|
+
// display, SF Mono Terminal 12 put 14432 of ink per cell in Terminal.app, 12043 at Medium and 15864 at DemiBold in
|
|
122
|
+
// WezTerm (Regular: 72%). DemiBold is the nearest; bold text takes the face's Bold in both (94%).
|
|
123
|
+
const primary = `{ family = ${lua(profile?.font?.family ?? 'SF Mono Terminal')}, weight = 'DemiBold' }`;
|
|
124
|
+
const families = mac ? [primary, ...MAC_CASCADE.map(lua)] : [];
|
|
125
|
+
// Terminal.app's cell is whole points: the advance rounded down (7 pt for SF Mono Terminal 12's 7.418) and the line
|
|
126
|
+
// (ascent + descent + leading) rounded up (15 pt for 14.32), measured as 14 x 30 px on a Retina display. WezTerm rounds
|
|
127
|
+
// its cell up to whole pixels before and after these factors, so the width factor is floor/ceil of the advance (14 px
|
|
128
|
+
// at 2x) and the height factor lands on the doubled line at 2x (30 px). Measured on both of the owner's displays: 14 x
|
|
129
|
+
// 30 px at 2x and 7 x 15 px at 1x, the same as Terminal.app's.
|
|
90
130
|
const font = profile?.font;
|
|
91
|
-
const
|
|
92
|
-
const
|
|
131
|
+
const advance = (font?.advance ?? 0) * (profile?.widthSpacing ?? 1);
|
|
132
|
+
const cellWidth = advance > 0 ? Math.floor(advance) / Math.ceil(advance) : 1;
|
|
133
|
+
const height = font ? font.ascender - font.descender + (font.leading ?? 0) : 0;
|
|
134
|
+
const lineHeight = height > 0 ? (2 * Math.ceil(height) - 0.5) / Math.ceil(2 * height) : 1;
|
|
135
|
+
// Terminal.app's translucent, blurred ground at 0.95 rendered within 2 levels of the opaque colour; WezTerm's at 0.95
|
|
136
|
+
// rendered 8 levels lighter over the same desktop. So a nearly opaque profile is drawn opaque (below 0.9 the profile's
|
|
137
|
+
// opacity is kept: unmeasured).
|
|
138
|
+
const alpha = stored.BackgroundColor?.[3] ?? 1;
|
|
139
|
+
const opacity = alpha >= 0.9 ? 1 : alpha;
|
|
93
140
|
const cursorShape = ['Block', 'Underline', 'Bar'][profile?.cursorType ?? 0] ?? 'Block';
|
|
94
141
|
const composed = !profile?.optionIsMeta;
|
|
142
|
+
const light = scheme(TERMINAL_BASIC.light), dark = scheme(TERMINAL_BASIC.dark);
|
|
143
|
+
const convert = (colors, map) => Object.fromEntries(Object.entries(colors).map(([key, value]) => [key, Array.isArray(value) ? value.map((v) => map[v] ?? v) : map[value] ?? value]));
|
|
144
|
+
const entry = (key, map) => ` ${key} = { light = ${table(convert(light, map))}, dark = ${table(convert(dark, map))} },`;
|
|
145
|
+
const byScale = new Map();
|
|
146
|
+
for (const screen of screens) if (!byScale.has(screen.scale)) byScale.set(screen.scale, screen.map);
|
|
147
|
+
const palettes = [entry('main', screens[0]?.map ?? {}), ...[...byScale].map(([scale, map]) => entry(`[${scale}]`, map))].join('\n');
|
|
95
148
|
const lines = [
|
|
96
149
|
'-- Generated by supercode (sdk/teams/terminal-look.mjs): this window looks like Terminal.app' + (profile?.name ? ` with this machine's "${profile.name}" profile.` : "'s Basic profile."),
|
|
97
150
|
"local wezterm = require 'wezterm'",
|
|
98
151
|
'local config = wezterm.config_builder()',
|
|
99
|
-
`local
|
|
152
|
+
`local palettes = {\n${palettes}\n}`,
|
|
100
153
|
"local appearance = wezterm.gui and wezterm.gui.get_appearance() or 'Dark'",
|
|
101
|
-
"
|
|
154
|
+
"local function colours(scale) local p = palettes[scale] or palettes.main; return appearance:find('Dark') and p.dark or p.light end",
|
|
155
|
+
'config.colors = colours()',
|
|
156
|
+
// A window takes the palette converted for the screen it is on (by its scale), when it opens and when it moves.
|
|
157
|
+
'local shown = {}',
|
|
158
|
+
'local function fit(window)',
|
|
159
|
+
' local scale = math.floor(window:get_dimensions().dpi / 72 + 0.5)',
|
|
160
|
+
' if shown[window:window_id()] == scale then return end',
|
|
161
|
+
' shown[window:window_id()] = scale',
|
|
162
|
+
' local overrides = window:get_config_overrides() or {}',
|
|
163
|
+
' overrides.colors = colours(scale)',
|
|
164
|
+
' window:set_config_overrides(overrides)',
|
|
165
|
+
'end',
|
|
166
|
+
"wezterm.on('window-config-reloaded', fit)",
|
|
167
|
+
"wezterm.on('window-resized', fit)",
|
|
102
168
|
`config.font_dirs = { ${fontDirs.map(lua).join(', ')} }`,
|
|
103
|
-
...(families.length ? [`config.font = wezterm.font_with_fallback({ ${families.
|
|
169
|
+
...(families.length ? [`config.font = wezterm.font_with_fallback({ ${families.join(', ')} })`] : []),
|
|
104
170
|
// CoreText draws glyphs unhinted; FreeType's default hinting snaps their outlines to the pixel grid.
|
|
105
171
|
"config.freetype_load_flags = 'NO_HINTING'",
|
|
106
172
|
// Box and block characters are the face's own glyphs, as CoreText draws them, not WezTerm's drawn lines.
|
|
107
173
|
'config.custom_block_glyphs = false',
|
|
108
174
|
`config.font_size = ${profile?.font?.size ?? TERMINAL_BASIC.fontSize}`,
|
|
109
|
-
`config.cell_width = ${
|
|
110
|
-
`config.line_height = ${Number(((profile?.heightSpacing ?? 1) *
|
|
175
|
+
`config.cell_width = ${Number(cellWidth.toFixed(4))}`,
|
|
176
|
+
`config.line_height = ${Number(((profile?.heightSpacing ?? 1) * lineHeight).toFixed(4))}`,
|
|
111
177
|
`config.default_cursor_style = ${lua(`${profile?.cursorBlink ? 'Blinking' : 'Steady'}${cursorShape}`)}`,
|
|
112
178
|
`config.send_composed_key_when_left_alt_is_pressed = ${composed}`,
|
|
113
179
|
`config.send_composed_key_when_right_alt_is_pressed = ${composed}`,
|
|
@@ -119,8 +185,8 @@ export function weztermConfig(profile, { fontDirs = existsSync(TERMINAL_FONTS) ?
|
|
|
119
185
|
`config.macos_window_background_blur = ${opacity < 1 ? Math.round((profile?.blur ?? 0) * 40) : 0}`,
|
|
120
186
|
`config.initial_cols = ${profile?.columns ?? 80}`,
|
|
121
187
|
`config.initial_rows = ${profile?.rows ?? 24}`,
|
|
122
|
-
// Terminal.app's
|
|
123
|
-
|
|
188
|
+
// Terminal.app's text starts 11 pt from the window's edge (22 px at 2x, one point of it the glyph's own bearing).
|
|
189
|
+
"config.window_padding = { left = '10pt', right = '10pt', top = 2, bottom = 2 }",
|
|
124
190
|
'config.hide_tab_bar_if_only_one_tab = true',
|
|
125
191
|
'config.enable_scroll_bar = false',
|
|
126
192
|
// Terminal.app does not ask before closing a window whose process is tmux (its default "ask before closing" list).
|
|
@@ -149,7 +215,10 @@ export function weztermConfig(profile, { fontDirs = existsSync(TERMINAL_FONTS) ?
|
|
|
149
215
|
/** Writes the config for this machine, when it differs from the one on disk, and returns its path. */
|
|
150
216
|
export function weztermConfigFile(platform = process.platform) {
|
|
151
217
|
const path = join(tmpdir(), `supercode-wezterm-${process.getuid?.() ?? 'user'}.lua`);
|
|
152
|
-
const
|
|
218
|
+
const profile = terminalAppProfile(platform);
|
|
219
|
+
const plain = weztermConfig(profile);
|
|
220
|
+
const hexes = [...new Set(plain.match(/#[0-9a-f]{6}/g) ?? [])];
|
|
221
|
+
const config = weztermConfig(profile, { screens: screenColours(hexes, platform) });
|
|
153
222
|
let current = null;
|
|
154
223
|
try { current = readFileSync(path, 'utf8'); } catch { /* not written yet */ }
|
|
155
224
|
if (current === config) return path;
|