acuvo-code 0.3.3 → 0.3.4

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 (2) hide show
  1. package/lib/banner.mjs +76 -48
  2. package/package.json +1 -1
package/lib/banner.mjs CHANGED
@@ -3,36 +3,61 @@
3
3
  *
4
4
  * Roman, 2026-08-22, having typed it: *"it's not opening as a typable terminal,
5
5
  * with acuvo logo top left and details up top etc, like how claude code opens.
6
- * have you actually designed the page?"*
6
+ * have you actually designed the page?"* — and then: *"no we want OUR logo"*.
7
7
  *
8
- * No the previous version printed two dense lines of facts and a prompt. Every
9
- * fact was correct and none of it was designed. This is the opening screen: a
10
- * wordmark, one instruction, and the four things a person needs to know before
11
- * they type anything.
8
+ * So this is the real mark, not letters spelling the name. It is
9
+ * `console/public/brand/acuvo-mark.png` the angular A resampled to
10
+ * half-blocks at 14x14 and embedded as text.
12
11
  *
13
- * ── ⚠️ THE CONSTRAINTS THAT SHAPED IT, NOT PREFERENCES ──────────────────────
12
+ * ── ⚠️ WHY IT IS EMBEDDED RATHER THAN DECODED AT RUNTIME ────────────────────
14
13
  *
15
- * · **Half-block glyphs only** (▀ █). Braille and fancy box-drawing render as
16
- * tofu in cmd.exe and in a lot of CI log viewers, and a logo that renders as
17
- * question marks is worse than no logo.
18
- * · **No colour codes here.** The caller owns colour and already honours
19
- * NO_COLOR; a module that hard-codes escapes produces garbage the moment its
20
- * output is piped to a file.
21
- * · **Every line under 80 columns**, because the narrowest terminal anyone
22
- * actually uses is 80 and a wrapped banner looks broken rather than dense.
14
+ * This package has ZERO dependencies, deliberately, and Node cannot decode a
15
+ * PNG without one. Converting at build time and pasting the result keeps that
16
+ * promise and costs nothing at startup. If the mark ever changes, re-run the
17
+ * conversion the logo is DERIVED from the brand asset, not drawn by hand, so
18
+ * it stays honest to it.
19
+ *
20
+ * ── ⚠️ THE CONSTRAINTS, WHICH ARE NOT PREFERENCES ───────────────────────────
21
+ *
22
+ * · **Half-block glyphs only** (▀ ▄ █). Braille and box-drawing render as tofu
23
+ * in cmd.exe and in many CI log viewers, and a logo that renders as question
24
+ * marks is worse than no logo — on the exact platform this is developed on.
25
+ * · **No colour escapes here.** The caller owns colour and honours NO_COLOR; a
26
+ * module that hard-codes them emits garbage the moment output is piped.
27
+ * · **Every line under 80 columns.** The narrowest terminal in real use is 80,
28
+ * and a wrapped banner does not read as dense, it reads as broken.
29
+ *
30
+ * ⭐ A NOTE ON DOING BETTER: `lib/terminal-graphics.mjs` can send a real PNG
31
+ * inline on Kitty and iTerm2. It is deliberately NOT used here — Windows
32
+ * Terminal speaks neither protocol, so the block art is what most users would
33
+ * see anyway, and one rendering that is the same everywhere beats two that
34
+ * disagree.
23
35
  */
24
36
 
25
37
  /**
26
- * ACUVO in half-blocks. Three rows, because five is a splash screen it belongs
27
- * to something you open once a day, not something you run forty times.
38
+ * The Acuvo mark, resampled from the brand PNG. Seven rows: tall enough to be
39
+ * the mark rather than a smudge, short enough for something run forty times a
40
+ * day rather than opened once.
28
41
  */
29
- const WORDMARK = [
30
- '▄▀█ █▀▀ █ █ █ █ █▀█',
31
- '█▀█ █▄▄ █▄█ ▀▄▀ █▄█',
42
+ const MARK = [
43
+ ' ▄█',
44
+ ' ▄███',
45
+ ' ▄█▀▀██',
46
+ ' ▄█▀ ▀██',
47
+ ' ▄█▀ ██ ▀██',
48
+ ' ▄████▀▀█████',
49
+ '█▀ █▀ ▀█',
32
50
  ];
33
51
 
52
+ const MARK_WIDTH = Math.max(...MARK.map((l) => l.length));
53
+ const GUTTER = 2;
54
+ export const MAX_BANNER_COLUMNS = 80;
55
+
56
+ /** Columns left for the detail rows once the mark and gutter are placed. */
57
+ const TEXT_COLUMNS = MAX_BANNER_COLUMNS - MARK_WIDTH - GUTTER;
58
+
34
59
  /**
35
- * Build the opening screen.
60
+ * Build the opening screen: mark on the left, facts on the right.
36
61
  *
37
62
  * @param {object} o
38
63
  * @param {string} o.version
@@ -47,36 +72,47 @@ export function openingScreen({ version, workspace, model, billing, canRun, inte
47
72
  /**
48
73
  * ── ⚠️⚠️ ELIDED, BECAUSE THE VALUES ARE NOT OURS ────────────────────────────
49
74
  *
50
- * Every value here arrives at runtime: a deep monorepo path, a long model id,
51
- * the shell-mode warning. The first version of this function assumed they
52
- * would be short and its own test caught it wrapping at 80 columns on
53
- * perfectly ordinary inputs.
75
+ * Every value arrives at runtime: a deep monorepo path, a long model id, the
76
+ * shell-mode warning. The first version assumed they would be short and its
77
+ * own test caught it wrapping at 80 columns on ordinary inputs.
54
78
  *
55
- * ⭐ ELIDED IN THE MIDDLE, NOT THE END. The informative parts of a path are the
56
- * drive and the leaf; chopping the tail leaves `C:\Users\somebody\Projects\a-`
57
- * which identifies nothing. Same for a model id, where the family is at the
58
- * front and the variant at the back.
79
+ * ⭐ ELIDED IN THE MIDDLE, NOT THE END. The informative parts of a path are
80
+ * the drive and the leaf; chopping the tail leaves
81
+ * `C:\Users\somebody\Projects\a-`, which identifies nothing. Same for a model
82
+ * id, where the family is at the front and the variant at the back.
59
83
  */
60
- const room = MAX_BANNER_COLUMNS - 2 - 11;
84
+ const room = TEXT_COLUMNS - 11;
61
85
  const fit = (v) => {
62
86
  const s = String(v ?? '');
63
87
  if (s.length <= room) return s;
64
88
  const head = Math.ceil((room - 1) / 2);
65
- const tail = room - 1 - head;
66
- return `${s.slice(0, head)}…${s.slice(s.length - tail)}`;
89
+ return `${s.slice(0, head)}…${s.slice(s.length - (room - 1 - head))}`;
67
90
  };
68
- const label = (k, v) => ` ${k.padEnd(11)}${fit(v)}`;
69
- const lines = [
70
- '',
71
- ` ${WORDMARK[0]}`,
72
- ` ${WORDMARK[1]} CODE${version ? ` ${version}` : ''}`,
91
+
92
+ const right = [
93
+ `ACUVO CODE${version ? ` ${version}` : ''}`,
73
94
  '',
74
- label('workspace', workspace),
75
- label('model', model),
76
- label('billing', billing),
77
- label('can run', canRun),
95
+ `workspace ${fit(workspace)}`,
96
+ `model ${fit(model)}`,
97
+ `billing ${fit(billing)}`,
98
+ `can run ${fit(canRun)}`,
78
99
  '',
79
100
  ];
101
+
102
+ /**
103
+ * ⚠️ THE TWO COLUMNS ARE ZIPPED, NOT CONCATENATED, and the row counts are
104
+ * allowed to differ — whichever is shorter simply runs out. Assuming they
105
+ * match would break the layout the first time a row is added to either side.
106
+ */
107
+ const rows = Math.max(MARK.length, right.length);
108
+ const lines = [''];
109
+ for (let i = 0; i < rows; i += 1) {
110
+ const mark = (MARK[i] ?? '').padEnd(MARK_WIDTH + GUTTER);
111
+ const text = right[i] ?? '';
112
+ lines.push(`${mark}${text}`.trimEnd());
113
+ }
114
+ lines.push('');
115
+
80
116
  /**
81
117
  * ⚠️ ONLY WHEN A PROMPT ACTUALLY FOLLOWS. Printing "type what you want done"
82
118
  * above a one-shot run that has already been given its task is an instruction
@@ -87,11 +123,3 @@ export function openingScreen({ version, workspace, model, billing, canRun, inte
87
123
  }
88
124
  return lines.join('\n');
89
125
  }
90
-
91
- /**
92
- * ⚠️ EXPORTED SO A TEST CAN ASSERT THE WIDTH RULE RATHER THAN TRUST IT. The
93
- * banner is assembled from values supplied at runtime — a long model id or a
94
- * deep workspace path is what would push it over, and neither is visible from
95
- * reading this file.
96
- */
97
- export const MAX_BANNER_COLUMNS = 80;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "acuvo-code",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "Acuvo Code — the terminal client for the Acuvo capability registry. Zero dependencies, by design.",
5
5
  "type": "module",
6
6
  "bin": {