acuvo-code 0.5.1 → 0.5.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/ENTERPRISE.md +4 -4
- package/lib/chat.mjs +15 -1
- package/lib/input-box.mjs +44 -14
- package/package.json +1 -1
package/ENTERPRISE.md
CHANGED
|
@@ -189,7 +189,7 @@ are the numbers to quote. Counting is the first thing a reviewer does.
|
|
|
189
189
|
|
|
190
190
|
⚠️ **This said "18 shipped files", then "41", then "90", then "101", then "108", and every
|
|
191
191
|
one went stale in turn.** The package ships **120 files — 118 in `lib/`, 2 in
|
|
192
|
-
`bin/` — about
|
|
192
|
+
`bin/` — about 78328 lines**, with **237 test files** beside them (counted 2026-08-22).
|
|
193
193
|
|
|
194
194
|
⭐ **AND THE 108 WENT STALE IN THE MOST INSTRUCTIVE WAY POSSIBLE: THREE OF THE FILES IT
|
|
195
195
|
MISSED WERE REACHABLE FROM NOTHING.** `wiring-reach.test.mjs` was naming
|
|
@@ -203,7 +203,7 @@ exactly the kind of number this section warns about.
|
|
|
203
203
|
allowlist also carries **`test/`, `ENTERPRISE.md` and `ROADMAP.md`**, and the published
|
|
204
204
|
tarball is **265 files, 5.1 MB unpacked — 182 of them tests against 98 of `lib/`.** That is
|
|
205
205
|
deliberate, not drift (commit `ed08f2710`, *"ship the tests, and add CI that would have
|
|
206
|
-
caught the false green"*): a document that invites you to audit
|
|
206
|
+
caught the false green"*): a document that invites you to audit 78328 lines and then ships
|
|
207
207
|
you the source without the tests is asking to be taken on trust, which is the one thing this
|
|
208
208
|
file refuses to ask for. ⭐ **Run them yourself: `npm test` inside the installed package.**
|
|
209
209
|
The stale sentence is the more interesting failure — it under-claimed, so nobody would ever
|
|
@@ -892,8 +892,8 @@ For completeness, the properties none of them offers:
|
|
|
892
892
|
(`lib/media.mjs`), and generates imagery with no configuration and no account
|
|
893
893
|
(`lib/imagegen.mjs`) — critiqued before it is accepted, and reported as unreviewed when
|
|
894
894
|
no critic is available.
|
|
895
|
-
- ⭐ **Zero dependencies.** The entire auditable surface is
|
|
896
|
-
and there is no `node_modules` behind it. (Counted 2026-08-
|
|
895
|
+
- ⭐ **Zero dependencies.** The entire auditable surface is 120 files and 78328 lines,
|
|
896
|
+
and there is no `node_modules` behind it. (Counted 2026-08-22 from
|
|
897
897
|
`lib/*.mjs` + `bin/*.mjs`; `test/docs-truth.test.mjs` fails the build if this number
|
|
898
898
|
drifts, which is why it went 18 → 41 → 46 → 52 → 53 → 57 → 60 → 61 → 62 → 65 → 66 → 69 → 70 → 71 → 72 → 73 → 80 → 84 → 90 → 100 → 101 → 102 → 103 → 107 → 108 → 111 as modules landed (111 = the three that were WRITTEN and imported by nothing — `python.mjs`, `cache-floor.mjs`, `plan-coherence.mjs`; 108 = `warm-provider.mjs`, which keeps a session on the upstream that holds its prompt cache; 107 = `login.mjs`, the command that stores an Acuvo credential — until it existed, `writeAccount` was called by nothing and every user fell through to BYOK). ⚠️ Two of those three landed on this count while remaining UNREACHABLE, which is the sharpest illustration this document has that a file count is a claim about bytes, never about capability. ⭐ A
|
|
899
899
|
count that fails the build is the only kind that stays true — this one has now caught its own
|
package/lib/chat.mjs
CHANGED
|
@@ -353,7 +353,14 @@ export async function runChat({
|
|
|
353
353
|
* quits) has to arrive here too, or the escape hatch is a single-use one.
|
|
354
354
|
*/
|
|
355
355
|
if (rl) rl.on('SIGINT', () => { onInterrupt(); });
|
|
356
|
-
|
|
356
|
+
/**
|
|
357
|
+
* ⚠️⚠️ THE BANNER IS DEFERRED UNTIL AFTER THE PIN, AND THE ORDER IS NOT
|
|
358
|
+
* COSMETIC. `pinRegion` CLEARS the screen so the transcript starts at the top
|
|
359
|
+
* of a clean one — printed before that, the banner is erased by the very
|
|
360
|
+
* thing meant to sit beneath it, which is exactly what a screenshot showed:
|
|
361
|
+
* a banner cut in half with the conversation crammed at the bottom.
|
|
362
|
+
*/
|
|
363
|
+
const writeBanner = () => { if (banner) output.write(`${banner}\n`); };
|
|
357
364
|
// ⚠️ `/help` IS ADVERTISED IN THE ONE LINE EVERY SESSION PRINTS. A command
|
|
358
365
|
// surface nobody is told about is the same defect item 14 closed for `--help`:
|
|
359
366
|
// the feature worked and nothing a stranger would read mentioned it.
|
|
@@ -398,6 +405,13 @@ export async function runChat({
|
|
|
398
405
|
process.once('SIGTERM', releasePin);
|
|
399
406
|
}
|
|
400
407
|
|
|
408
|
+
/**
|
|
409
|
+
* ⭐ NOW the banner, at the top of a screen the pin has just cleared, with the
|
|
410
|
+
* conversation free to grow downward beneath it — which is the direction every
|
|
411
|
+
* scrollback in existence runs.
|
|
412
|
+
*/
|
|
413
|
+
writeBanner();
|
|
414
|
+
|
|
401
415
|
try {
|
|
402
416
|
for (;;) {
|
|
403
417
|
/**
|
package/lib/input-box.mjs
CHANGED
|
@@ -96,16 +96,30 @@ export function renderBox({ value = '', cursor = 0, columns = 80, prompt = '›
|
|
|
96
96
|
const shown = value.slice(start, start + room);
|
|
97
97
|
|
|
98
98
|
const body = `${prompt}${shown}`;
|
|
99
|
-
const pad = ' '.repeat(Math.max(0,
|
|
99
|
+
const pad = ' '.repeat(Math.max(0, width - visibleWidth(body)));
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* ── ⚠️⚠️ A RULE AND A PROMPT — NOT A BOX. THE SCREENSHOT SETTLED IT ─────────
|
|
103
|
+
*
|
|
104
|
+
* I built a four-sided box because Roman said "copy Claude's box exactly", and
|
|
105
|
+
* a screenshot of the real thing shows there IS no box: a horizontal rule
|
|
106
|
+
* across the full width, then `❯ ` beneath it. The submitted line gets a
|
|
107
|
+
* subtle highlight bar rather than a border.
|
|
108
|
+
*
|
|
109
|
+
* ⭐ AND THE RULE IS WHY IT LOOKS SETTLED RATHER THAN DRAWN. Two borders and
|
|
110
|
+
* two side walls make the input an object floating in the terminal; one rule
|
|
111
|
+
* makes it the bottom of the page. Roman: *"ours is organised weirdly."*
|
|
112
|
+
*
|
|
113
|
+
* ⚠️ Two rows, not three — so the reserved region shrinks with it and the
|
|
114
|
+
* transcript gets a row back.
|
|
115
|
+
*/
|
|
101
116
|
return {
|
|
102
117
|
lines: [
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
`╰${'─'.repeat(width - 2)}╯`,
|
|
118
|
+
'─'.repeat(width),
|
|
119
|
+
`${body}${pad}`,
|
|
106
120
|
],
|
|
107
|
-
// 1-based
|
|
108
|
-
cursorColumn: 1 +
|
|
121
|
+
// 1-based, and there is no left border to skip any more.
|
|
122
|
+
cursorColumn: 1 + promptWidth + (cursor - start),
|
|
109
123
|
};
|
|
110
124
|
}
|
|
111
125
|
|
|
@@ -274,10 +288,17 @@ export function paint(output, state, { first = false, atRow = 0 } = {}) {
|
|
|
274
288
|
* viewport when the box is at the bottom of the screen, and every subsequent
|
|
275
289
|
* `up` is then off by a row for the rest of the session.
|
|
276
290
|
*/
|
|
277
|
-
|
|
291
|
+
/**
|
|
292
|
+
* ⚠️ THE ROW MATH FOLLOWS THE ROW COUNT, and it changed when the box became a
|
|
293
|
+
* rule. With TWO rows the cursor already ends on the prompt line after the
|
|
294
|
+
* write, so there is no reposition to make — the old `ESC[1A` was correct for
|
|
295
|
+
* three rows and would now land on the RULE, one row too high, which is the
|
|
296
|
+
* same off-by-one that walked the box up the screen before.
|
|
297
|
+
*/
|
|
298
|
+
const home = first ? '' : `\r${CSI}${lines.length - 1}A`;
|
|
278
299
|
output.write(
|
|
279
300
|
`${CSI}?25l${home}${CSI}0J${lines.join('\n')}` +
|
|
280
|
-
|
|
301
|
+
`\r${CSI}${cursorColumn}G${CSI}?25h`,
|
|
281
302
|
);
|
|
282
303
|
}
|
|
283
304
|
|
|
@@ -409,7 +430,7 @@ export function readBoxedLine({ input, output, history = [], onInterrupt = null,
|
|
|
409
430
|
* ⚠️ AND IT IS OPT-IN. A reserved region is a claim on somebody's whole screen;
|
|
410
431
|
* off a TTY, in CI, under a pipe or with ACUVO_NO_PIN=1 it is never set.
|
|
411
432
|
*/
|
|
412
|
-
export function pinRegion(output, { rows =
|
|
433
|
+
export function pinRegion(output, { rows = 2, env = process.env } = {}) {
|
|
413
434
|
const height = output?.rows ?? process.stdout?.rows ?? 0;
|
|
414
435
|
const enabled = Boolean(output?.isTTY)
|
|
415
436
|
&& height > rows + 4
|
|
@@ -422,12 +443,21 @@ export function pinRegion(output, { rows = 3, env = process.env } = {}) {
|
|
|
422
443
|
let released = false;
|
|
423
444
|
|
|
424
445
|
/**
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
446
|
+
* ── ⚠️⚠️ CLEAR, THEN START AT THE TOP. MY FIRST VERSION STARTED AT THE BOTTOM ─
|
|
447
|
+
*
|
|
448
|
+
* Roman, from a screenshot: the banner was cut in half with a huge empty gap
|
|
449
|
+
* beneath it and the conversation crammed at the bottom of the screen.
|
|
450
|
+
*
|
|
451
|
+
* The cause: this parked the cursor at the BOTTOM of the region, so the first
|
|
452
|
+
* line printed on the last usable row and everything after it scrolled. A
|
|
453
|
+
* terminal fills downward — the transcript has to START at the top and grow
|
|
454
|
+
* toward the input, which is what every scrollback in existence does.
|
|
455
|
+
*
|
|
456
|
+
* ⚠️ AND THE SCREEN IS CLEARED FIRST. Whatever the shell left behind would
|
|
457
|
+
* otherwise sit inside our region and scroll along with the session, so the
|
|
458
|
+
* banner would never be at the top of anything.
|
|
429
459
|
*/
|
|
430
|
-
output.write(`${CSI}1;${bottom}r${CSI}
|
|
460
|
+
output.write(`${CSI}2J${CSI}1;${bottom}r${CSI}1;1H`);
|
|
431
461
|
|
|
432
462
|
const release = () => {
|
|
433
463
|
if (released) return;
|