gitroots 0.6.1 → 0.6.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitroots",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "gitroots CLI: code governance and agent sessions.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/runtime.js CHANGED
@@ -5,7 +5,7 @@ import os from 'node:os';
5
5
  import path from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
 
8
- export const VERSION = '0.6.1';
8
+ export const VERSION = '0.6.2';
9
9
 
10
10
  // Default download location for install.sh / gitroots update. Override with GITROOTS_DOWNLOAD_BASE.
11
11
  export const DOWNLOAD_BASE = process.env.GITROOTS_DOWNLOAD_BASE || 'https://gitroots.com/cli';
@@ -0,0 +1,56 @@
1
+ // Generated by scripts/make-logo.py from assets/logo.png. Do not edit by hand.
2
+ // Pixel rows (two per terminal row), 6 hex digits per pixel, '------' = transparent.
3
+ export const ART = {
4
+ 14: { w: 91, px: [
5
+ '586a26b3da44b3da44b3da44b3da44586a26------4c652197d03997d03997d03997d0394c6521------30582159b23859b23859b23859b238305821------164a2a20944d20944d20944d20944d164a2a------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
6
+ 'b3da44b3da44b3da44b3da44b3da44b3da44------97d03997d03997d03997d03997d03997d039------59b23859b23859b23859b23859b23859b238------20944d20944d20944d20944d20944d20944d------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
7
+ 'b3da44b3da44b3da44b3da44b3da44b3da44------97d03997d03997d03997d03997d03997d039------59b23859b23859b23859b23859b23859b238------20944d20944d20944d20944d20944d20944d------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
8
+ 'b3da44b3da44b3da44b3da44b3da44b3da44------97d03997d03997d03997d03997d03997d039------59b23859b23859b23859b23859b23859b238------20944d20944d20944d20944d20944d20944d------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
9
+ 'b3da44b3da44b3da44b3da44b3da44b3da44------97d03997d03997d03997d03997d03997d039------59b23859b23859b23859b23859b23859b238------20944d20944d20944d20944d20944d20944d------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
10
+ '586a26b3da44b3da44b3da44b3da44586a26------4c652197d03997d03997d03997d0394c6521------30582159b23859b23859b23859b238305821------164a2a20944d20944d20944d20944d164a2a------------------------------------------------------------------------------------------------36383b------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
11
+ '------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------8d949de3edfc979da6------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
12
+ '3f5f207ac1357ac1357ac1357ac1353f5f20------35591e64b53264b53264b53264b53235591e------17461e238b32238b32238b32238b3217461e------0b3c2407753e07753e07753e07753e0b3c24------------------------------------------------------------------------------------------898d97e3edfc9197a1------------acb4bfb3bac64d5054------------------------------------------------------------------------------------------------------------------------------------------------------------------------797d85b3bac67e848b------------------------------------------------------------',
13
+ '7ac1357ac1357ac1357ac1357ac1357ac135------64b53264b53264b53264b53264b53264b532------238b32238b32238b32238b32238b32238b32------07753e07753e07753e07753e07753e07753e------------------------------------------------------------------------------------------------------------------------dbe5f3e3edfc5f6269------------------------------------------------------------------------------------------------------------------------------------------------------------------------989ea7e3edfc9fa6b0------------------------------------------------------------',
14
+ '7ac1357ac1357ac1357ac1357ac1357ac135------64b53264b53264b53264b53264b53264b532------238b32238b32238b32238b32238b32238b32------07753e07753e07753e07753e07753e07753e------------------------------------3536399ba3adbec6d29fa6b0------969ca5a9b0bb4e5155------6e737aa9b0bb797e86------a9b0bbe0eaf9e3edfcbfc7d3a7adb9------60646aa9b0bb7e828a56595eb7bfcb80848d------------6c7077aeb5c0bec7d3a8b0b95e6167------------------------------848a92b7bfcbbcc4d1999fa93f4144------------9196a0ced7e5e3edfcd0dae7a9b0bb3e4043------------8d949db8c0ccbdc5d19ea5af484b4f------',
15
+ '7ac1357ac1357ac1357ac1357ac1357ac135------64b53264b53264b53264b53264b53264b532------238b32238b32238b32238b32238b32238b32------07753e07753e07753e07753e07753e07753e------------------------------313335d9e3f1e3edfce3edfce3edfcc7d0ddd0d9e6e3edfc65696f------9399a3e3edfca1a8b3------e3edfce3edfce3edfce3edfce0e9f8------7f858de3edfcc1c9d6dfe9f7e3edfc999fa9------aab2bde3edfce3edfce3edfce3edfce3edfc8f959e------------------cfd8e6e3edfce3edfce3edfce3edfce0e9f855585d------c2cad7e3edfce3edfce3edfce3edfc4f5356------d6dfede3edfcd6dfedc9d2dfe3edfce1ebfa53575c',
16
+ '7ac1357ac1357ac1357ac1357ac1357ac135------64b53264b53264b53264b53264b53264b532------238b32238b32238b32238b32238b32238b32------07753e07753e07753e07753e07753e07753e------------------------------999fa9e3edfcd4ddeb404246------8e949de3edfce3edfc65696f------9399a3e3edfca1a8b3------------dbe5f3e3edfc666a71------------7f858de3edfce3edfc8990983e404332333660646ae3edfce0e9f7515358------6a6e74e3edfce3edfc42454a------9ba1abe3edfcc7d0dd------------9ea4aee3edfcd4dcea------------9da3ade3edfca3aab5------------6f7379e3edfcd1dae7------------6f747aa1a8b25f6368',
17
+ '3f5f207ac1357ac1357ac1357ac1353f5f20------35591e64b53264b53264b53264b53235591e------17461e238b32238b32238b32238b3217461e------0b3c2407753e07753e07753e07753e0b3c24------------------------------cfd8e5e3edfc82878f------------------dee8f6e3edfc65696f------9399a3e3edfca1a8b3------------dbe5f3e3edfc5f6269------------7f858de3edfcc7cedb------------------a2a9b3e3edfca5acb8------------------c2cbd8e3edfc848992------dae3f2e3edfc6c7077------------------e3edfce3edfc4a4d51------989ea7e3edfc9fa6b0------------61646ae3edfce1ebfa848a924c4e53------------------',
18
+ '------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------dee8f6e3edfc65696f------------------cbd4e2e3edfc65696f------9399a3e3edfca1a8b3------------dbe5f3e3edfc5f6269------------7f858de3edfcb4bdc9------------------b8c0cbe3edfc898f97------------------a5acb8e3edfc999fa9------e3edfce3edfc4f5256------------------dfe9f7e3edfc5f6368------989ea7e3edfc9fa6b0------------------a3aab5e3edfce3edfce3edfce1ebfab3bcc836383b',
19
+ '15441d1d872f1d872f1d872f1d872f15441d------103c2312743d12743d12743d12743d103c23------0c36200967360967360967360967360c3620------0c2c1c09512e09512e09512e09512e0c2c1c------------------------------d2dbe9e3edfc7a8088------------------dbe5f4e3edfc65696f------9399a3e3edfca1a8b3------------dbe5f3e3edfc5f6269------------7f858de3edfcb4bdc9------------------abb2bde3edfc9aa0aa------------------b7bfcbe3edfc8c929b------e0e9f8e3edfc606369------------------e3edfce3edfc53565b------989ea7e3edfc9fa6b0------------------------31333564686e9399a2d7e2efe3edfcc0c8d4',
20
+ '1d872f1d872f1d872f1d872f1d872f1d872f------12743d12743d12743d12743d12743d12743d------096736096736096736096736096736096736------09512e09512e09512e09512e09512e09512e------------------------------a2a8b3e3edfccdd6e4333437------80858de3edfce3edfc65696f------9399a3e3edfca1a8b3------------dae4f2e3edfc666a71------------7f858de3edfcb4bdc9------------------767b82e3edfcd6e1ee------------3c3e42e0eaf9e3edfc585c61------b0b8c3e3edfcb1b9c4------------777b83e3edfcdfe9f6------------979da6e3edfca5acb8------------585b619aa0aa7c818a------------70757ce3edfcd7e2ef',
21
+ '1d872f1d872f1d872f1d872f1d872f1d872f------12743d12743d12743d12743d12743d12743d------096736096736096736096736096736096736------09512e09512e09512e09512e09512e09512e------------------------------383a3ddce6f4e3edfce3edfce1ebfac5cedad4ddeae3edfc65696f------9399a3e3edfca1a8b3------------bbc3d0e3edfcd9e3f0bfc7d4------7f858de3edfcb4bdc9------------------------cbd5e1e3edfcd7e1eeb3bac6dde6f4e3edfcb8c0cb------------434549e0e9f8e3edfcc9d2dfbac2cee3edfce3edfc7e848b------------7a7f86e3edfce1ebf9c2cad7484a4e585b60e3edfce3edfcabb3be999fa9d7e2efe3edfc939aa3',
22
+ '1d872f1d872f1d872f1d872f1d872f1d872f------12743d12743d12743d12743d12743d12743d------096736096736096736096736096736096736------09512e09512e09512e09512e09512e09512e------------------------------------37393c979da6b4bdc9999fa8------cad3e0e3edfc65696f------878d96cfd8e6949aa4------------3c3e41c0c8d4e3edfcdce6f4------757a82cfd8e6a5acb8------------------------------a0a7b1dee7f5e3edfcd9e3f19198a1------------------------47494eb8c0cce1ebfae3edfccdd6e470747b------------------------a3aab5dfe9f7e1ebfa686c72------61656bc5cedae3edfce3edfcd1dbe7828790------',
23
+ '1d872f1d872f1d872f1d872f1d872f1d872f------12743d12743d12743d12743d12743d12743d------096736096736096736096736096736096736------09512e09512e09512e09512e09512e09512e------------------------------------------------------------------d8e2f0e3edfc595d62------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
24
+ '15441d1d872f1d872f1d872f1d872f15441d------103c2312743d12743d12743d12743d103c23------0c36200967360967360967360967360c3620------0c2c1c09512e09512e09512e09512e0c2c1c------------------------------73787fe3edfcd1dae773777e64686eacb4bfe3edfcd6e1ee------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
25
+ '------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------969ca5e0e9f8e3edfce3edfce3edfcc5cdda404346------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
26
+ '0b2f1f0758330758330758330758330b2f1f------0c2d1a0a52290a52290a52290a52290c2d1a------0c241a0a3e280a3e280a3e280a3e280c241a------0c211a0a39290a39290a39290a39290c211a------------------------------------------------494c504f525635373a------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
27
+ '075833075833075833075833075833075833------0a52290a52290a52290a52290a52290a5229------0a3e280a3e280a3e280a3e280a3e280a3e28------0a39290a39290a39290a39290a39290a3929------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
28
+ '075833075833075833075833075833075833------0a52290a52290a52290a52290a52290a5229------0a3e280a3e280a3e280a3e280a3e280a3e28------0a39290a39290a39290a39290a39290a3929------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
29
+ '075833075833075833075833075833075833------0a52290a52290a52290a52290a52290a5229------0a3e280a3e280a3e280a3e280a3e280a3e28------0a39290a39290a39290a39290a39290a3929------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
30
+ '075833075833075833075833075833075833------0a52290a52290a52290a52290a52290a5229------0a3e280a3e280a3e280a3e280a3e280a3e28------0a39290a39290a39290a39290a39290a3929------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
31
+ '0b2f1f0758330758330758330758330b2f1f------0c2d1a0a52290a52290a52290a52290c2d1a------0c241a0a3e280a3e280a3e280a3e280c241a------0c211a0a39290a39290a39290a39290c211a------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
32
+ '------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
33
+ ] },
34
+ 10: { w: 65, px: [
35
+ 'b3da44b3da44b3da44b3da44------97d03997d03997d03997d039------59b23859b23859b23859b238------20944d20944d20944d20944d------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
36
+ 'b3da44b3da44b3da44b3da44------97d03997d03997d03997d039------59b23859b23859b23859b238------20944d20944d20944d20944d------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
37
+ 'b3da44b3da44b3da44b3da44------97d03997d03997d03997d039------59b23859b23859b23859b238------20944d20944d20944d20944d------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
38
+ 'b3da44b3da44b3da44b3da44------97d03997d03997d03997d039------59b23859b23859b23859b238------20944d20944d20944d20944d------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
39
+ '------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------7d818ac2ccd9------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
40
+ '7ac1357ac1357ac1357ac135------64b53264b53264b53264b532------238b32238b32238b32238b32------07753e07753e07753e07753e------------------------------------------------------------------5d6167969da5------434549d0d9e755585d------------------------------------------------------------------------------------------------------------------------d0d9e78f959e------------------------------------------',
41
+ '7ac1357ac1357ac1357ac135------64b53264b53264b53264b532------238b32238b32238b32238b32------07753e07753e07753e07753e------------------------------4c4f537e858d4a4d514e515671767d------4c4f5471767d------90969fe3edfc9ba1ab424448383a3d71767d36383b7b8188------------55585d7f858d6b7076------------------------5d606680858d676c72------------64686ee3edfcbcc5d15d6166------------72777e7f858d53575c------',
42
+ '7ac1357ac1357ac1357ac135------64b53264b53264b53264b532------238b32238b32238b32238b32------07753e07753e07753e07753e------------------------666a70e3edfccbd5e1c7cfdcc7d0dde3edfc------9399a3e3edfc------c1cad6e3edfcc6ceda65696f686d73e3edfcccd5e2cfd8e54243479aa0aae1ebfab4bdc9d7e2efcbd5e2------------adb4bfe0e9f8b3bac7dae4f3c1cad6------9da3ade3edfcd2dcea9298a1------d8e3f0c6ceda9ea5afe0e9f8838891',
43
+ '7ac1357ac1357ac1357ac135------64b53264b53264b53264b532------238b32238b32238b32238b32------07753e07753e07753e07753e------------------------c7cedbd1dae7------------c5cddae3edfc------9399a3e3edfc------484b4fe3edfc5c6065------686d73e3edfc6e7379------383a3de3edfc8b9199------434649e3edfc7e838c4b4e52e3edfc767a82------515559e3edfc696d74------e3edfc9ba3ad------515358e3edfc828890------3a3c3f------',
44
+ '------------------------------------------------------------------------------------------------------------------------------------------dfe9f7abb3be------------9aa0aae3edfc------9399a3e3edfc------484b4fe3edfc5c6065------686d73e3edfc404246------575b60e3edfc5b5f64------------e3edfc9da4af6a6e75e3edfc46484c------------e3edfc898d97------e3edfc9ba3ad------------a7adb9e1ebfae1ebfac2cad754585d',
45
+ '1d872f1d872f1d872f1d872f------12743d12743d12743d12743d------096736096736096736096736------09512e09512e09512e09512e------------------------cad3e0ccd5e3------------bfc8d4e3edfc------9399a3e3edfc------484b4fe3edfc5c6065------686d73e3edfc404246------434449e3edfc7a8088------333637e3edfc888d9755585de3edfc656a70------424447e3edfc73777f------e3edfc9ba3ad------------404246------4e5156cbd3e1d6deed',
46
+ '1d872f1d872f1d872f1d872f------12743d12743d12743d12743d------096736096736096736096736------09512e09512e09512e09512e------------------------6c7278e3edfcc5cedac0c8d5c8d1dee3edfc------9399a3e3edfc------35373ae3edfcb9c1cd575b60686d73e3edfc404246------------b4bdc9dce6f490969fc6cedbdae3f2323336------c3cdd9d6e1ee8e949dcbd3e1d2dbe9------------d1dbe7d1dbe87b80884a4d51e1ebfaa9b1bc7d828bd6dfedb0b8c3',
47
+ '1d872f1d872f1d872f1d872f------12743d12743d12743d12743d------096736096736096736096736------09512e09512e09512e09512e------------------------------4a4d52797e8547494d999fa9e1ebfa------5e61688d939c------------64686e9ea5af64686e44474a8d939c------------------------7a8088a5acb89197a0353639------------------838890a5aeb88d939c------------------40444699a0a88b9199------4d505599a1a9a4acb77b8088------',
48
+ '1d872f1d872f1d872f1d872f------12743d12743d12743d12743d------096736096736096736096736------09512e09512e09512e09512e------------------------62666dabb3be484b4f494b4fcdd6e4bbc3cf------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
49
+ '------------------------------------------------------------------------------------------------------------------------------------------------abb3bedfe9f6dfe9f6adb5c0303134------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
50
+ '075833075833075833075833------0a52290a52290a52290a5229------0a3e280a3e280a3e280a3e28------0a39290a39290a39290a3929------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
51
+ '075833075833075833075833------0a52290a52290a52290a5229------0a3e280a3e280a3e280a3e28------0a39290a39290a39290a3929------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
52
+ '075833075833075833075833------0a52290a52290a52290a5229------0a3e280a3e280a3e280a3e28------0a39290a39290a39290a3929------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
53
+ '075833075833075833075833------0a52290a52290a52290a5229------0a3e280a3e280a3e280a3e28------0a39290a39290a39290a3929------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
54
+ '------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------',
55
+ ] },
56
+ };
@@ -1,107 +1,88 @@
1
- // The gitroots logo as terminal pixel art: the 4×4 mark and the "gitroots" wordmark.
2
- // One pixel is one column wide and half a row tall (▀ ▄ █ with fg/bg colors), so pixels are about square.
1
+ // The gitroots logo in the welcome box.
2
+ // iTerm2, Ghostty, WezTerm, Kitty: the real assets/logo.png, drawn as an image.
3
+ // Every other terminal (Terminal.app, …): the same image in half-block pixels (src/session/logo-art.js).
3
4
  import { state as colorState, c, width, fit } from '../ui/ansi.js';
5
+ import { imageProtocol, logoImage } from '../ui/term.js';
6
+ import { ART } from './logo-art.js';
4
7
 
5
- // Colors sampled from assets/logo.png.
6
- const CELLS = [
7
- ['#B3DA44', '#97D039', '#59B238', '#20944D'],
8
- ['#7AC135', '#64B532', '#238B32', '#07753E'],
9
- ['#1D872F', '#12743D', '#096736', '#09512E'],
10
- ['#075833', '#0A5229', '#0A3E28', '#0A3929'],
11
- ];
12
- const WORD = '#E3EDFC';
8
+ const rgb = (h) => [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
13
9
 
14
- // 8 px tall glyphs: ascenders in rows 0-1, x-height 2-5, descender 6-7.
15
- const GLYPHS = {
16
- g: ['....', '....', '.###', '#..#', '#..#', '.###', '...#', '.##.'],
17
- i: ['#', '.', '#', '#', '#', '#', '.', '.'],
18
- t: ['.#.', '.#.', '###', '.#.', '.#.', '.##', '...', '...'],
19
- r: ['...', '...', '#.#', '##.', '#..', '#..', '...', '...'],
20
- o: ['....', '....', '.##.', '#..#', '#..#', '.##.', '....', '....'],
21
- s: ['....', '....', '.###', '#...', '..##', '###.', '....', '....'],
22
- };
23
-
24
- const CELL = 2;
25
- const GAP = 1;
26
- const MARK = 4 * CELL + 3 * GAP; // 11 px
27
- const SPACE = 4;
28
-
29
- function canvas() {
30
- const word = [...'gitroots'].reduce((rows, ch, i) => rows.map((r, y) => r + (i ? '.' : '') + GLYPHS[ch][y]), Array(8).fill(''));
31
- let H = Math.max(MARK, 8);
32
- if (H % 2) H += 1;
33
- const W = MARK + SPACE + word[0].length;
34
- const px = Array.from({ length: H }, () => Array(W).fill(null));
35
- for (let r = 0; r < 4; r++) {
36
- for (let col = 0; col < 4; col++) {
37
- for (let y = 0; y < CELL; y++) for (let x = 0; x < CELL; x++) px[r * (CELL + GAP) + y][col * (CELL + GAP) + x] = CELLS[r][col];
38
- }
39
- }
40
- const oy = Math.floor((H - 8) / 2);
41
- word.forEach((row, y) => [...row].forEach((ch, x) => { if (ch === '#') px[oy + y][MARK + SPACE + x] = WORD; }));
42
- return { px, W, H };
43
- }
44
-
45
- const rgb = (hex) => [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16));
46
-
47
- // Nearest xterm-256 color for terminals without truecolor.
10
+ // Nearest xterm-256 color for terminals without 24-bit color.
48
11
  function x256([r, g, b]) {
49
12
  const q = (v) => (v < 48 ? 0 : v < 115 ? 1 : Math.floor((v - 35) / 40));
50
13
  const lv = [0, 95, 135, 175, 215, 255];
51
14
  const [qr, qg, qb] = [q(r), q(g), q(b)];
52
- const cube = 16 + 36 * qr + 6 * qg + qb;
53
15
  const dc = (lv[qr] - r) ** 2 + (lv[qg] - g) ** 2 + (lv[qb] - b) ** 2;
54
16
  const gray = Math.max(0, Math.min(23, Math.round(((r + g + b) / 3 - 8) / 10)));
55
17
  const gv = 8 + gray * 10;
56
- const dg = (gv - r) ** 2 + (gv - g) ** 2 + (gv - b) ** 2;
57
- return dg < dc ? 232 + gray : cube;
18
+ return (gv - r) ** 2 + (gv - g) ** 2 + (gv - b) ** 2 < dc ? 232 + gray : 16 + 36 * qr + 6 * qg + qb;
58
19
  }
20
+ const fg = (h) => (colorState.truecolor ? `\x1b[38;2;${rgb(h).join(';')}m` : `\x1b[38;5;${x256(rgb(h))}m`);
21
+ const bg = (h) => (colorState.truecolor ? `\x1b[48;2;${rgb(h).join(';')}m` : `\x1b[48;5;${x256(rgb(h))}m`);
59
22
 
60
- const fg = (hex) => (colorState.truecolor ? `\x1b[38;2;${rgb(hex).join(';')}m` : `\x1b[38;5;${x256(rgb(hex))}m`);
61
- const bg = (hex) => (colorState.truecolor ? `\x1b[48;2;${rgb(hex).join(';')}m` : `\x1b[48;5;${x256(rgb(hex))}m`);
23
+ function pixelAt(art, x, y) {
24
+ const p = art.px[y].slice(x * 6, x * 6 + 6);
25
+ return p === '------' ? null : p;
26
+ }
62
27
 
63
- let cached = null;
64
- /** The logo as terminal lines (6 rows × 48 columns). */
65
- export function logoLines() {
66
- if (cached && cached.color === colorState.color && cached.tc === colorState.truecolor) return cached.lines;
67
- const { px, W, H } = canvas();
28
+ /** The logo drawn with half blocks: `rows` terminal rows (12 or 8). */
29
+ export function logoLines(rows = 14) {
30
+ const art = ART[rows] || ART[14];
68
31
  const lines = [];
69
- for (let y = 0; y < H; y += 2) {
32
+ for (let y = 0; y < art.px.length; y += 2) {
70
33
  let s = '';
71
- for (let x = 0; x < W; x++) {
72
- const top = px[y][x];
73
- const bot = px[y + 1][x];
74
- if (!colorState.color) { s += top && bot ? '█' : top ? '▀' : bot ? '▄' : ' '; continue; }
75
- if (!top && !bot) s += ' ';
76
- else if (top && bot && top === bot) s += `${fg(top)}█\x1b[39m`;
77
- else if (top && bot) s += `${fg(top)}${bg(bot)}▀\x1b[39;49m`;
78
- else if (top) s += `${fg(top)}▀\x1b[39m`;
79
- else s += `${fg(bot)}▄\x1b[39m`;
34
+ for (let x = 0; x < art.w; x++) {
35
+ const t = pixelAt(art, x, y);
36
+ const b = pixelAt(art, x, y + 1);
37
+ if (!colorState.color) { s += t && b ? '█' : t ? '▀' : b ? '▄' : ' '; continue; }
38
+ if (!t && !b) s += ' ';
39
+ else if (t && b && t === b) s += `${fg(t)}█\x1b[39m`;
40
+ else if (t && b) s += `${fg(t)}${bg(b)}▀\x1b[39;49m`;
41
+ else if (t) s += `${fg(t)}▀\x1b[39m`;
42
+ else s += `${fg(b)}▄\x1b[39m`;
80
43
  }
81
44
  lines.push(s);
82
45
  }
83
- cached = { color: colorState.color, tc: colorState.truecolor, lines };
84
46
  return lines;
85
47
  }
86
48
 
87
- /** Welcome box: the logo with the info lines beside it (or under it in narrow terminals). */
49
+ /**
50
+ * Welcome box: logo plus info lines (beside it when there's room, under it otherwise).
51
+ * Returns { lines, image } — when the terminal can show images, `image` says where to draw logo.png
52
+ * (rows up from the end of the box, column) and the logo area in `lines` is left blank for it.
53
+ */
88
54
  export function welcomeBox(info, cols) {
89
- const logo = logoLines();
90
- const logoW = width(logo[0]);
55
+ const rows = cols >= 100 ? 14 : 10;
56
+ const art = ART[rows];
57
+ const proto = colorState.color ? imageProtocol() : null;
58
+ const logo = proto ? Array(rows).fill(' '.repeat(art.w)) : logoLines(rows);
59
+ const logoW = art.w;
91
60
  const infoW = Math.max(...info.map((l) => width(l)));
92
- const side = cols >= logoW + infoW + 12;
93
- const inner = Math.max(logoW + 4, Math.min(cols - 2, side ? logoW + infoW + 9 : Math.max(logoW, infoW) + 6));
61
+ const side = cols >= logoW + infoW + 14;
62
+ const inner = Math.min(cols - 2, side ? logoW + infoW + 11 : Math.max(logoW, infoW) + 6);
94
63
  const b = (s) => c.g(s);
95
- const row = (s) => `${b('│')} ${fit(s, inner - 4)}${' '.repeat(Math.max(0, inner - 4 - width(fit(s, inner - 4))))} ${b('│')}`;
96
- const out = [b(`╭${'─'.repeat(inner)}╮`), row('')];
64
+ const row = (s) => { const t = fit(s, inner - 4); return `${b('│')} ${t}${' '.repeat(Math.max(0, inner - 4 - width(t)))} ${b('│')}`; };
65
+ const lines = [b(`╭${'─'.repeat(inner)}╮`), row('')];
66
+ const logoTop = lines.length;
97
67
  if (side) {
98
- const off = Math.max(0, Math.floor((logo.length - info.length) / 2));
99
- for (let i = 0; i < logo.length; i++) out.push(row(`${logo[i]} ${info[i - off] || ''}`));
68
+ const off = Math.max(0, Math.floor((rows - info.length) / 2));
69
+ for (let i = 0; i < rows; i++) lines.push(row(`${logo[i]} ${info[i - off] ?? ''}`));
100
70
  } else {
101
- for (const l of logo) out.push(row(l));
102
- out.push(row(''));
103
- for (const l of info) out.push(row(l));
71
+ for (const l of logo) lines.push(row(l));
72
+ lines.push(row(''));
73
+ for (const l of info) lines.push(row(l));
74
+ }
75
+ lines.push(row(''), b(`╰${'─'.repeat(inner)}╯`));
76
+ const image = proto ? { up: lines.length - logoTop, col: 3, cols: logoW, rows } : null;
77
+ return { lines, image };
78
+ }
79
+
80
+ /** Print the welcome box; in image-capable terminals, draw logo.png into its space. */
81
+ export function printWelcome(write, info, cols) {
82
+ const { lines, image } = welcomeBox(info, cols);
83
+ write(`${lines.join('\n')}\n`);
84
+ if (image) {
85
+ const esc = logoImage(image.cols, image.rows);
86
+ if (esc) write(`\x1b7\x1b[${image.up}A\r\x1b[${image.col}C${esc}\x1b8`);
104
87
  }
105
- out.push(row(''), b(`╰${'─'.repeat(inner)}╯`));
106
- return out;
107
88
  }
@@ -8,7 +8,7 @@ import { VERSION } from '../runtime.js';
8
8
  import { tryGit } from '../git/checks.js';
9
9
  import { localSessions, shortPath } from '../agents/local.js';
10
10
  import { remoteFullName } from '../rules.js';
11
- import { welcomeBox } from './logo.js';
11
+ import { printWelcome } from './logo.js';
12
12
  import { COMMANDS, find, match, suggest } from './registry.js';
13
13
 
14
14
  const MENU_ROWS = 8;
@@ -42,7 +42,7 @@ function header(ctx) {
42
42
  const who = ctx.api.signedIn
43
43
  ? `${c.b(cfg.user?.name || cfg.username)} ${c.m('·')} ${cfg.org ? `${cfg.org.name} ${c.m(`(${cfg.org.role})`)}` : c.w('no workspace · /workspace')} ${c.m(`· ${ctx.api.host}`)}`
44
44
  : `${c.w('Not signed in')} ${c.m('· /login to connect your gitroots account')}`;
45
- return welcomeBox([
45
+ printWelcome(write, [
46
46
  `${c.s(`v${VERSION}`)} ${c.m('· code governance and agent sessions')}`,
47
47
  '',
48
48
  who,
@@ -169,7 +169,7 @@ class Repl {
169
169
  this.notice = c.w(' press ctrl-c again to exit');
170
170
  break;
171
171
  case 'ctrl-d': if (!this.input) return this.exit(); this.input = this.input.slice(0, this.pos) + this.input.slice(this.pos + 1); break;
172
- case 'ctrl-l': write('\x1b[2J\x1b[H'); this.drawn = 0; write(`${header(this.ctx).join('\n')}\n\n`); break;
172
+ case 'ctrl-l': write('\x1b[2J\x1b[H'); this.drawn = 0; header(this.ctx); write('\n'); break;
173
173
  case 'left': this.pos = Math.max(0, this.pos - 1); break;
174
174
  case 'right': this.pos = Math.min(this.input.length, this.pos + 1); break;
175
175
  case 'home': case 'ctrl-a': this.pos = 0; break;
@@ -229,7 +229,7 @@ class Repl {
229
229
  return;
230
230
  }
231
231
  if (cmd.name === 'exit') return this.exit();
232
- if (cmd.name === 'clear') { write('\x1b[2J\x1b[3J\x1b[H'); write(`${header(this.ctx).join('\n')}\n\n`); this.draw(); return; }
232
+ if (cmd.name === 'clear') { write('\x1b[2J\x1b[3J\x1b[H'); header(this.ctx); write('\n'); this.draw(); return; }
233
233
  if (cmd.name === 'help') { printHelp(true); write('\n'); this.draw(); return; }
234
234
  await this.run(cmd, rest);
235
235
  }
@@ -293,7 +293,8 @@ class Repl {
293
293
  }
294
294
 
295
295
  start() {
296
- write(`\n${header(this.ctx).join('\n')}\n`);
296
+ write('\n');
297
+ header(this.ctx);
297
298
  write(` ${c.m('Type')} ${c.g('/')} ${c.m('to pick a command, or')} ${c.g('/help')} ${c.m('for all of them.')}${this.ctx.api.signedIn ? '' : ` ${c.m('Start with')} ${c.g('/login')}${c.m('.')}`}\n\n`);
298
299
  process.stdin.setRawMode(true);
299
300
  process.stdin.resume();
package/src/ui/ansi.js CHANGED
@@ -23,6 +23,8 @@ function detectTruecolor() {
23
23
  const tp = env.TERM_PROGRAM || '';
24
24
  if (['iTerm.app', 'WezTerm', 'ghostty', 'vscode', 'Hyper'].includes(tp)) return true;
25
25
  if (env.WT_SESSION) return true;
26
+ // Terminal.app gained 24-bit color in macOS 26 (Terminal 460+).
27
+ if (tp === 'Apple_Terminal' && Number(String(env.TERM_PROGRAM_VERSION || '').split('.')[0]) >= 460) return true;
26
28
  const term = env.TERM || '';
27
29
  return /kitty|ghostty|direct|truecolor/.test(term);
28
30
  }