acuvo-code 0.4.3 → 0.5.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/lib/colour.mjs CHANGED
@@ -32,6 +32,21 @@ const CODES = {
32
32
  green: '\x1b[32m', // it worked
33
33
  red: '\x1b[31m', // it failed or was refused
34
34
  cyan: '\x1b[36m', // a remote thing: MCP, a service
35
+ /**
36
+ * ── ⭐ THE BRAND GREEN, SAMPLED FROM THE MARK ITSELF ───────────────────────
37
+ *
38
+ * #C8E91E — the most common opaque pixel in
39
+ * `console/public/brand/acuvo-mark.png`, read rather than eyeballed, so the
40
+ * logo in a terminal is the same green as the one on the website.
41
+ *
42
+ * ⚠️ TRUECOLOR WITH A 256-COLOUR FALLBACK. `ESC[38;2;R;G;Bm` is exact and
43
+ * widely supported (Windows Terminal, iTerm2, kitty, modern VS Code) — but a
44
+ * terminal that does not speak it renders the sequence as LITERAL TEXT across
45
+ * the logo. Index 190 is the nearest lime in the 256-colour cube and is
46
+ * understood almost everywhere, so it ships unless truecolor is advertised.
47
+ */
48
+ brand: '\x1b[38;5;190m',
49
+ brandTrue: '\x1b[38;2;200;233;30m',
35
50
  };
36
51
 
37
52
  /**
@@ -66,6 +81,16 @@ export function createPainter(enabled = colourEnabled()) {
66
81
  green: wrap(CODES.green),
67
82
  red: wrap(CODES.red),
68
83
  cyan: wrap(CODES.cyan),
84
+ /**
85
+ * ⚠️ TRUECOLOR ONLY WHEN THE TERMINAL SAYS SO. `COLORTERM=truecolor` is the
86
+ * signal every emitter uses; without it a 24-bit sequence can print as raw
87
+ * text, which would smear escape codes across the first thing a user sees.
88
+ */
89
+ brand: wrap(
90
+ (process.env.COLORTERM === 'truecolor' || process.env.COLORTERM === '24bit')
91
+ ? CODES.brandTrue
92
+ : CODES.brand,
93
+ ),
69
94
  };
70
95
  }
71
96
 
package/lib/input-box.mjs CHANGED
@@ -349,3 +349,61 @@ export function readBoxedLine({ input, output, history = [], onInterrupt = null,
349
349
  input.once('end', onEnd);
350
350
  });
351
351
  }
352
+
353
+ /**
354
+ * ── ⭐⭐⭐ PINNING THE BOX TO THE BOTTOM OF THE SCREEN ───────────────────────
355
+ *
356
+ * Roman: *"we need that prompt box stuck down the bottom, it is professional."*
357
+ *
358
+ * A terminal can be told to scroll only PART of itself. `ESC[{top};{bottom}r`
359
+ * sets the scrolling region; everything printed scrolls inside it, and the rows
360
+ * below are left alone. Reserve the last three and the box never moves while
361
+ * output flows past above it.
362
+ *
363
+ * ── ⚠️⚠️ THE PART THAT MUST NEVER BE GOT WRONG ──────────────────────────────
364
+ *
365
+ * A process that exits WITHOUT releasing the region leaves the user with a
366
+ * terminal that scrolls inside a box forever, fixable only by typing `reset`
367
+ * blind. That is the same class of harm as leaving raw mode on, and it must be
368
+ * released on every path out — normal exit, Ctrl-C, SIGTERM, and an uncaught
369
+ * throw. `release()` is idempotent and safe to call from all of them.
370
+ *
371
+ * ⚠️ AND IT IS OPT-IN. A reserved region is a claim on somebody's whole screen;
372
+ * off a TTY, in CI, under a pipe or with ACUVO_NO_PIN=1 it is never set.
373
+ */
374
+ export function pinRegion(output, { rows = 3, env = process.env } = {}) {
375
+ const height = output?.rows ?? process.stdout?.rows ?? 0;
376
+ const enabled = Boolean(output?.isTTY)
377
+ && height > rows + 4
378
+ && String(env.ACUVO_NO_PIN ?? '') !== '1'
379
+ && String(env.CI ?? '').toLowerCase() !== 'true';
380
+
381
+ if (!enabled) return { enabled: false, release() {}, rows: 0, bottom: 0 };
382
+
383
+ const bottom = height - rows;
384
+ let released = false;
385
+
386
+ /**
387
+ * ⚠️ THE CURSOR IS PARKED INSIDE THE SCROLL REGION BEFORE ANYTHING PRINTS.
388
+ * Setting a region moves the cursor to home (1,1) on most terminals, so
389
+ * without this the next line of output lands at the TOP of the screen and the
390
+ * transcript reads backwards.
391
+ */
392
+ output.write(`${CSI}1;${bottom}r${CSI}${bottom};1H`);
393
+
394
+ const release = () => {
395
+ if (released) return;
396
+ released = true;
397
+ /**
398
+ * ⚠️ `ESC[r` WITH NO ARGUMENTS RESETS TO THE FULL SCREEN. Then the cursor is
399
+ * moved below the reserved rows so the shell prompt does not land on top of
400
+ * our box — an exit that leaves the terminal technically correct and
401
+ * visually broken is still a bad exit.
402
+ */
403
+ try {
404
+ output.write(`${CSI}r${CSI}${height};1H\n`);
405
+ } catch { /* the stream may already be gone on a hard exit */ }
406
+ };
407
+
408
+ return { enabled: true, release, rows, bottom };
409
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "acuvo-code",
3
- "version": "0.4.3",
3
+ "version": "0.5.0",
4
4
  "description": "Acuvo Code — the terminal client for the Acuvo capability registry. Zero dependencies, by design.",
5
5
  "type": "module",
6
6
  "bin": {