agents: darkwing row 69 build packet (#1562)
Hidden decide box names the way out, its status line stops promising y,
tests for the narrow-terminal guard, U+18D08 and a cut help or detail
box. Candidate manifest c68e6582. Mutants 6/6 killed; gate 13 suites
green on dad20531 plus build.patch.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
# Row 69, terminal app follow-up after row 55, build (Darkwing)
|
||||
|
||||
Issue #1562. Brief: `docs/plans/2026-10-11_terminal-app-follow-up.md`.
|
||||
Reviewers: Dewey and Filbert. The notes come from row 55 round 3: Dewey's
|
||||
comment 27308 and Filbert's comment 27309.
|
||||
|
||||
Base `dad20531`. No commit from `dad20531` to `15ed3513` touches the four
|
||||
paths. Row 92's `57948a81` changed `packages/cli/README.md` after the old
|
||||
base the row was opened on, so I started from a fresh worktree.
|
||||
|
||||
`build.patch` is `git diff --binary dad20531` of the four paths. Apply it
|
||||
with `git apply --index` to a detached worktree of `dad20531`, and
|
||||
`sha256sum -c candidate-manifest.sha256` then gives 4/4 OK (checked on a
|
||||
fresh worktree).
|
||||
|
||||
## What changed
|
||||
|
||||
- `packages/cli/src/screens.mjs`, the hidden box only. It gains a third
|
||||
line, "Resize, or use mosaic decide.", shown while asking and while
|
||||
resolving.
|
||||
- `packages/cli/src/app.mjs`, `render()` only. While the overlay is a
|
||||
decide box and `decideShown()` is false, the frame's status line says
|
||||
"Too small to confirm here." in the warning style. `state.status` is
|
||||
left alone, so when the terminal grows and the box shows again, the
|
||||
Inbox's "Press 1-n to choose. You will see the decision again and
|
||||
confirm with y." comes back with it. Nothing else about `y` changed.
|
||||
- `packages/cli/tests/app.test.mjs`: three tests and one code point.
|
||||
- `packages/cli/README.md`: the hidden box's text, the status line, the
|
||||
too-small screen under 40 columns at any height, and the row counts as
|
||||
an example for a plain decision.
|
||||
|
||||
## Two choices
|
||||
|
||||
The way out is short because of the smallest frame. At 40x10 the body has
|
||||
5 rows and the box is 38 cells wide, 34 inside. The brief's sentence,
|
||||
"Make the terminal bigger, or use mosaic decide <id> <choice>.", wraps to
|
||||
two rows there, so the box is 6 rows and `draw()`'s general cut keeps the
|
||||
top, a cut line and the last two rows. That drops "Any key answers No."
|
||||
and adds a cut line pointing at `mosaic inbox --json`. "Resize, or use
|
||||
mosaic decide." is 29 cells, so the hidden box is 5 rows at every size
|
||||
and is never cut. The second test pins that at 40x10. The tradeoff: the
|
||||
box no longer spells out `<decision> <option>`; `mosaic decide` prints
|
||||
its usage.
|
||||
|
||||
The status text is 26 cells for the same reason. "Too small to confirm
|
||||
this decision here." filled a 40-column status line and lost its last
|
||||
character to the ellipsis.
|
||||
|
||||
## The tests
|
||||
|
||||
| Test | What it pins | From |
|
||||
|---|---|---|
|
||||
| under 40 columns a tall terminal shows the too-small screen even where the decide box would fit; y sends nothing | at 39x29, 35x31, 30x35, 39x33, 39x40, 39x60, 36x60 and 30x80, `1` then `y` shows the too-small screen with "A decision question is open; any key answers No." and sends no `decision.resolve`. Then every size from 30 to 39 columns and 33 to 60 rows, short and long question: `decideShown()` is false and `draw()` gives the too-small screen | Filbert N10, Dewey `r3-shown-no-min`; Dewey's and Filbert's probe sizes |
|
||||
| a hidden decide box names the way out, and the status line under it does not promise y | at 80x24 the status says "confirm with y." before and after `1`; shrunk to 80x18 the box shows its three lines, the status says "Too small to confirm here." and nothing on screen says "with y"; grown back, both return; at 40x10 the hidden box is whole, with no cut line; `y` then sends nothing | Filbert N12, Dewey's note |
|
||||
| width counts terminal cells (existing) | U+18D08 measures 2 | Filbert N11 |
|
||||
| help or a detail box cut to fit keeps its last line, Esc included | at 80x10 the cut help keeps the row the full help ends on (the wrapped end of "Esc closes this help."), and a cut decision detail keeps `│ Esc back │` | Dewey `cut-drops-choice` |
|
||||
|
||||
## Mutants
|
||||
|
||||
`mutants.sh` runs the brief's four and two on this row's own lines, with
|
||||
a copy of `agents/darkwing/work/queue-59-review/r1/mut.mjs` (sha256
|
||||
`a1ed6bca…`) against `packages/cli/tests/app.test.mjs`, 22:49:16Z to
|
||||
22:51:14Z, after a check that exits on another seat's gate or mutant run.
|
||||
**6 of 6 killed** (`mutants.txt`). Every file was restored and still
|
||||
matches the manifest.
|
||||
|
||||
| Mutant | Edit | Killed by |
|
||||
|---|---|---|
|
||||
| `shown-no-min-cols` | `decideShown` without `cols >= MIN_COLS` | under 40 columns a tall terminal… |
|
||||
| `r3-shown-no-min` | `decideShown` without the 40x10 check | under 40 columns a tall terminal… |
|
||||
| `n9-17000-end-off` | `0x18d08` to `0x18cff` | width counts terminal cells… |
|
||||
| `cut-drops-choice` | the general cut keeps one tail row, not two | help or a detail box cut to fit… |
|
||||
| `hidden-no-way-out` | the hidden box without its third line | a hidden decide box names the way out… |
|
||||
| `hidden-status-promises-y` | `render()` never swaps the status | a hidden decide box names the way out… |
|
||||
|
||||
Each dies in its own test and in no other.
|
||||
|
||||
## Found, not fixed
|
||||
|
||||
When help is cut, its cut line says "the whole text is in mosaic inbox
|
||||
--json". Help has no `whole`, so `draw()` falls back to the decide box's
|
||||
pointer, which is wrong for help (`?` shows the whole help on a taller
|
||||
terminal). The help test's screen at 80x10 shows it. That line sits in
|
||||
`draw()`, outside this row's lines of `screens.mjs`, so I left it for a
|
||||
follow-up.
|
||||
|
||||
## Gate
|
||||
|
||||
`gate.sh`, run sequentially in `~/darkwing-scratch/r69/wt` (`dad20531`
|
||||
plus this patch, `node_modules` symlinked), 22:56:22Z to 22:59:22Z, after
|
||||
the busy check found no other seat's run for two minutes
|
||||
(`gate-summary.txt`). All 13 suites exited 0, 0 skipped:
|
||||
|
||||
- node: cli 123 (row 55's 120 plus the three new tests), queue 150;
|
||||
- scripts: auth 15, conductor 17, config 24, discord 66,
|
||||
extension-package 18, foundation 44, queue 27, release 14, task 26
|
||||
(`DOCKER_HOST` at a dead socket).
|
||||
|
||||
test-release left an empty `wt_default` network, created at 22:59:08Z
|
||||
inside my test-release window, and I removed it.
|
||||
@@ -0,0 +1,169 @@
|
||||
diff --git a/packages/cli/README.md b/packages/cli/README.md
|
||||
index 1abec3d0..3fb537fd 100644
|
||||
--- a/packages/cli/README.md
|
||||
+++ b/packages/cli/README.md
|
||||
@@ -129,11 +129,16 @@ and nothing else.
|
||||
action and target, what the choice authorizes, the task, your choice
|
||||
and the `[y/N]` question stay. The cut line points to `mosaic inbox
|
||||
--json`. When even those lines don't fit, the box says only "Too small
|
||||
- to show this decision. Any key answers No." `y` resolves only while the
|
||||
- frame shows the whole box apart from the cut, and the app checks the
|
||||
- size at each key, so a terminal shrunk after the question appeared
|
||||
- answers No. A gated decision with a task needs 20 rows at 80 columns
|
||||
- (21 with a cut question), and 29 rows at 40 columns.
|
||||
+ to show this decision. Any key answers No. Resize, or use mosaic
|
||||
+ decide.", and the status line says "Too small to confirm here." instead
|
||||
+ of promising a `y`. `y` resolves only while the frame shows the whole
|
||||
+ box apart from the cut, and the app checks the size at each key, so a
|
||||
+ terminal shrunk after the question appeared answers No. Under 40
|
||||
+ columns or 10 rows the app shows only the too-small screen, however
|
||||
+ tall the terminal is. How many rows a box needs depends on its lines.
|
||||
+ For example, a plain gated decision with a task needs 20 rows at 80
|
||||
+ columns (21 with a cut question) and 29 rows at 40 columns; one with
|
||||
+ longer lines needs more.
|
||||
- The transport is the verbs' `spawnSync` child, so the screen does not
|
||||
redraw while a read is in flight (up to its 30 s timeout).
|
||||
- On quit, end of input, SIGTERM, SIGINT, SIGHUP or an error (one in a
|
||||
diff --git a/packages/cli/src/app.mjs b/packages/cli/src/app.mjs
|
||||
index 3f5418b0..e2211224 100644
|
||||
--- a/packages/cli/src/app.mjs
|
||||
+++ b/packages/cli/src/app.mjs
|
||||
@@ -96,7 +96,12 @@ export class App {
|
||||
|
||||
render() {
|
||||
if (this.closed) return this.frame;
|
||||
- this.frame = draw(this.state, { cols: this.cols, rows: this.rows, color: this.color, now: this.now() });
|
||||
+ // A hidden decide box can't be confirmed with y, so the status line
|
||||
+ // doesn't say it can.
|
||||
+ const o = this.state.overlay;
|
||||
+ const hidden = o?.kind === "decide" && !decideShown(o, this.cols, this.rows);
|
||||
+ const state = hidden ? { ...this.state, status: "Too small to confirm here.", statusStyle: "warning" } : this.state;
|
||||
+ this.frame = draw(state, { cols: this.cols, rows: this.rows, color: this.color, now: this.now() });
|
||||
this.write(`\x1b[H\x1b[2J${this.frame.join("\r\n")}`);
|
||||
return this.frame;
|
||||
}
|
||||
diff --git a/packages/cli/src/screens.mjs b/packages/cli/src/screens.mjs
|
||||
index 38ac5f94..926daad1 100644
|
||||
--- a/packages/cli/src/screens.mjs
|
||||
+++ b/packages/cli/src/screens.mjs
|
||||
@@ -377,7 +377,9 @@ function overlayBox(o, cols, room) {
|
||||
if (o.kind === "help") return box("help", HELP, Math.min(84, cols - 2));
|
||||
const w = Math.min(84, cols - 2);
|
||||
if (o.kind === "decide") {
|
||||
- return decideBox(o, w, room) ?? box("decide", [["Too small to show this decision.", "warning"], o.asking ? "Any key answers No." : ["resolving…", "muted"]], w);
|
||||
+ // The way out fits the 34 cells a 40-column box has, so the hidden box
|
||||
+ // is never cut.
|
||||
+ return decideBox(o, w, room) ?? box("decide", [["Too small to show this decision.", "warning"], o.asking ? "Any key answers No." : ["resolving…", "muted"], "Resize, or use mosaic decide."], w);
|
||||
}
|
||||
if (o.kind === "unknown") {
|
||||
return box("outcome unknown", [[o.message, "warning"], "", "Nothing was retried, and the choice was not sent twice.", "", "v open the trail r re-read the inbox Esc back"], w);
|
||||
diff --git a/packages/cli/tests/app.test.mjs b/packages/cli/tests/app.test.mjs
|
||||
index a679886a..924384ca 100644
|
||||
--- a/packages/cli/tests/app.test.mjs
|
||||
+++ b/packages/cli/tests/app.test.mjs
|
||||
@@ -191,7 +191,7 @@ test("width counts terminal cells: wide CJK and emoji 2, U+FE0F after a one-cell
|
||||
assert.equal(width(s), cells, JSON.stringify(s));
|
||||
}
|
||||
// East Asian Width W and F outside the blocks above: one from each range.
|
||||
- for (const n of [0x2329, 0x232a, 0xa960, 0xfe10, 0xfe50, 0x16fe0, 0x17000, 0x1aff0, 0x1b2fb]) assert.equal(width(String.fromCodePoint(n)), 2, n.toString(16));
|
||||
+ for (const n of [0x2329, 0x232a, 0xa960, 0xfe10, 0xfe50, 0x16fe0, 0x17000, 0x18d08, 0x1aff0, 0x1b2fb]) assert.equal(width(String.fromCodePoint(n)), 2, n.toString(16));
|
||||
// A line break never splits ❤️ from its U+FE0F; no line is wider than asked.
|
||||
assert.deepEqual(wrapCells("abc❤\uFE0F x", 4), ["abc", "❤\uFE0F x"]);
|
||||
for (const l of wrapCells("ab ❤\uFE0F❤\uFE0F e\u0301e\u0301e\u0301", 4)) assert.ok(width(l) <= 4, JSON.stringify(l));
|
||||
@@ -342,6 +342,68 @@ test("below 40x10 the question is hidden, so every key answers it No, y included
|
||||
assert.equal(g.a.state.status, `resolved ${d.id}: yes`);
|
||||
});
|
||||
|
||||
+test("under 40 columns a tall terminal shows the too-small screen even where the decide box would fit; y sends nothing (Filbert N10)", async (t) => {
|
||||
+ // A plain decision's box fits at cols - 2 from about 29 rows at 39
|
||||
+ // columns and 35 at 30, so each size here would show it if the app
|
||||
+ // checked only the box.
|
||||
+ for (const [cols, rows] of [[39, 29], [35, 31], [30, 35], [39, 33], [39, 40], [39, 60], [36, 60], [30, 80]]) {
|
||||
+ const s = gated(t, cols, rows, false);
|
||||
+ await s.a.start();
|
||||
+ await s.a.input("1");
|
||||
+ const label = `${cols}x${rows}`;
|
||||
+ assert.ok(s.a.state.overlay?.asking, label);
|
||||
+ const flat = s.a.frame.map(strip).join(" ").replace(/\s+/g, " ");
|
||||
+ assert.match(flat, new RegExp(`The terminal is ${cols}x${rows}; the app needs at least 40x10\\.`), label);
|
||||
+ assert.match(flat, /A decision question is open; any key answers No\./, label);
|
||||
+ assert.doesNotMatch(s.screen(), /y resolves/, label);
|
||||
+ await s.a.input("y");
|
||||
+ assert.equal(s.a.state.overlay, null, label);
|
||||
+ assert.equal(s.a.state.status, "not resolved", label);
|
||||
+ assert.ok(!s.calls.some((c) => c.verb === "decision.resolve"), label);
|
||||
+ }
|
||||
+ // Every size from 30 to 39 columns and 33 to 60 rows, short question and long.
|
||||
+ for (const long of [false, true]) {
|
||||
+ const s = gated(t, 120, 40, long);
|
||||
+ await s.a.start();
|
||||
+ await s.a.input("1");
|
||||
+ for (let cols = 30; cols < 40; cols++) {
|
||||
+ for (let rows = 33; rows <= 60; rows++) {
|
||||
+ const label = `${cols}x${rows}${long ? " long" : ""}`;
|
||||
+ assert.equal(decideShown(s.a.state.overlay, cols, rows), false, label);
|
||||
+ assert.match(draw(s.a.state, { cols, rows, color: false, now: NOW }).map(strip).join(" ").replace(/\s+/g, " "), /the app needs at least 40x10\./, label);
|
||||
+ }
|
||||
+ }
|
||||
+ s.a.quit("q");
|
||||
+ }
|
||||
+});
|
||||
+
|
||||
+test("a hidden decide box names the way out, and the status line under it does not promise y (Filbert N12)", async (t) => {
|
||||
+ const status = (s) => strip(s.a.frame.at(-2)).trim();
|
||||
+ const s = gated(t, 80, 24, false);
|
||||
+ await s.a.start();
|
||||
+ assert.match(status(s), /confirm with y\.$/, "the Inbox's own status, before a digit");
|
||||
+ await s.a.input("1");
|
||||
+ assert.match(s.screen(), /y resolves/);
|
||||
+ assert.match(status(s), /confirm with y\.$/, "true while the box shows");
|
||||
+ s.a.resize(80, 18);
|
||||
+ assert.match(s.screen(), /Too small to show this decision\.[\s\S]*Any key answers No\.[\s\S]*Resize, or use mosaic decide\./);
|
||||
+ assert.equal(status(s), "Too small to confirm here.");
|
||||
+ assert.doesNotMatch(s.screen(), /with y/);
|
||||
+ fits(s.a.frame, 80, 18, "hidden at 80x18");
|
||||
+ // Grown back: the box and the status return.
|
||||
+ s.a.resize(80, 24);
|
||||
+ assert.match(s.screen(), /y resolves/);
|
||||
+ assert.match(status(s), /confirm with y\.$/);
|
||||
+ // At the smallest size the hidden box is whole, its way out included.
|
||||
+ s.a.resize(40, 10);
|
||||
+ assert.match(s.screen(), /Any key answers No\.[\s\S]*Resize, or use mosaic decide\./);
|
||||
+ assert.doesNotMatch(s.screen(), /cut to fit/);
|
||||
+ assert.equal(status(s), "Too small to confirm here.");
|
||||
+ await s.a.input("y");
|
||||
+ assert.equal(s.a.state.status, "not resolved");
|
||||
+ assert.ok(!s.calls.some((c) => c.verb === "decision.resolve"));
|
||||
+});
|
||||
+
|
||||
test("a throw while answering the question goes to crash, sends nothing and leaves no job pending", async (t) => {
|
||||
const boom = new Error("the terminal write failed");
|
||||
let fail = false;
|
||||
@@ -624,6 +686,27 @@ test("refused and failed reads keep the last list, marked stale; a refused decid
|
||||
assert.deepEqual([decide.a.state.overlay.kind, decide.a.state.overlay.message], ["error", "refused: unauthenticated"]);
|
||||
});
|
||||
|
||||
+test("help or a detail box cut to fit keeps its last line, Esc included (Dewey)", async (t) => {
|
||||
+ const s = app(t, { cols: 80, rows: 10 });
|
||||
+ s.raise("git.push.protected", { target: "refactor", question: "Push the release?" });
|
||||
+ await s.a.start();
|
||||
+ // The help's last row at full height; at 80x10 it wraps "Esc closes
|
||||
+ // this help." and the cut keeps that row.
|
||||
+ const last = (frame) => frame.map(strip).filter((l) => l.includes("│")).at(-1);
|
||||
+ const whole = draw({ ...s.a.state, overlay: { kind: "help" } }, { cols: 80, rows: 40, color: false, now: NOW });
|
||||
+ assert.match(whole.map(strip).join(" ").replace(/[\s│]+/g, " "), /Esc closes this help\./);
|
||||
+ await s.a.input("?");
|
||||
+ assert.match(s.screen(), /cut to fit/);
|
||||
+ assert.equal(last(s.a.frame), last(whole));
|
||||
+ fits(s.a.frame, 80, 10, "help at 80x10");
|
||||
+ await s.a.input("\x1b");
|
||||
+ await s.a.input("\r");
|
||||
+ assert.equal(s.a.state.overlay?.kind, "detail");
|
||||
+ assert.match(s.screen(), /cut to fit; the whole text is in mosaic inbox --json/);
|
||||
+ assert.match(s.screen(), /│ Esc back +│/);
|
||||
+ fits(s.a.frame, 80, 10, "detail at 80x10");
|
||||
+});
|
||||
+
|
||||
test("keys: views, moving, trail of a selection, the command line, help and quit", async (t) => {
|
||||
const s = app(t);
|
||||
const a = s.raise("git.push.protected", { target: "one" });
|
||||
@@ -0,0 +1,4 @@
|
||||
be564baae877a067a0f752d964b37041c880a69b0bf576a28dcd30ae7ecc6fbc packages/cli/README.md
|
||||
15a8ee212fc37cea28e389f60ddb8916f9e1509cdcfb2e522acfe548702a16dc packages/cli/src/app.mjs
|
||||
9d03335628ae62e85c5fbc08c2e739ed0bd43b10d486faf397129a56a1b343e0 packages/cli/src/screens.mjs
|
||||
9e6e3d0729d9b34f4cc0906cddf541e7353847f9eafd46032797f2fcdccfa8f5 packages/cli/tests/app.test.mjs
|
||||
@@ -0,0 +1,13 @@
|
||||
start 2026-10-12T22:56:22Z
|
||||
cli rc=0 22:56:22-22:56:41 ℹ pass 123 ℹ fail 0 ℹ skipped 0 0 marks
|
||||
queue rc=0 22:56:41-22:57:19 ℹ pass 150 ℹ fail 0 ℹ skipped 0 0 marks
|
||||
test-auth rc=0 22:57:19-22:57:19 selftest: 15 passed, 0 failed
|
||||
test-conductor rc=0 22:57:19-22:57:26 selftest: 17 passed, 0 failed
|
||||
test-config rc=0 22:57:26-22:57:28 selftest: 24 passed, 0 failed
|
||||
test-discord rc=0 22:57:28-22:57:36 discord suite: 66 passed, 0 failed
|
||||
test-extension-package rc=0 22:57:36-22:57:37 extension package selftest: 18 passed, 0 failed
|
||||
test-foundation rc=0 22:57:37-22:58:23 selftest: 44 passed, 0 failed
|
||||
test-queue rc=0 22:58:23-22:59:07 queue suite: 27 passed, 0 failed
|
||||
test-release rc=0 22:59:07-22:59:19 selftest: 14 passed, 0 failed
|
||||
test-task rc=0 22:59:19-22:59:22 selftest: 26 passed, 0 failed
|
||||
end 2026-10-12T22:59:22Z
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
# Row 69 gate on dad20531 plus build.patch: the cli and queue node suites
|
||||
# (each package's own test files, from its directory), then every
|
||||
# scripts/test-*.sh, sequential, full output kept.
|
||||
cd ~/darkwing-scratch/r69/wt || exit 2
|
||||
W=$PWD
|
||||
export TMPDIR=~/darkwing-scratch/r69/tmp
|
||||
O=~/darkwing-scratch/r69/gate
|
||||
mkdir -p "$O" "$TMPDIR"
|
||||
echo "start $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
for p in cli queue; do
|
||||
s=$(date -u +%T)
|
||||
(cd "$W/packages/$p" && node --test tests/*.test.mjs) > $O/node-$p.txt 2>&1; rc=$?
|
||||
echo "$p rc=$rc $s-$(date -u +%T) $(grep -E '^ℹ (pass|fail|skipped)' $O/node-$p.txt | tr '\n' ' ') $(grep -cE '^✖|^not ok' $O/node-$p.txt) marks"
|
||||
done
|
||||
for f in scripts/test-*.sh; do
|
||||
n=$(basename $f .sh); s=$(date -u +%T)
|
||||
if [ $n = test-task ]; then DOCKER_HOST=unix:///nonexistent bash $f > $O/$n.txt 2>&1; else bash $f > $O/$n.txt 2>&1; fi; rc=$?
|
||||
echo "$n rc=$rc $s-$(date -u +%T) $(tail -1 $O/$n.txt | cut -c1-120)"
|
||||
done
|
||||
echo "end $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# Row 69 (#1562) mutants: the brief's four, then two on this row's own
|
||||
# lines. Run from the candidate worktree's root:
|
||||
# LOG=/some/dir bash mutants.sh /path/to/mut.mjs > mutants.txt
|
||||
# Each mutant edits one site with mut.mjs (exactly one match, else exit 3),
|
||||
# runs the app tests and restores the file. "killed" means the run failed;
|
||||
# "survived" means it passed.
|
||||
set -u
|
||||
MUT=$1
|
||||
run() {
|
||||
local name=$1 file=$2 from=$3 to=$4; shift 4
|
||||
cp -- "$file" "$file.orig"
|
||||
if ! node "$MUT" "$file" "$from" "$to"; then
|
||||
echo "$name: NO MATCH"; mv -- "$file.orig" "$file"; return
|
||||
fi
|
||||
if node --test "$@" > "${LOG:-.}/mut-$name.log" 2>&1; then
|
||||
echo "$name: survived"
|
||||
else
|
||||
echo "$name: killed ($(grep -m1 -o 'ℹ fail [0-9]*' "${LOG:-.}/mut-$name.log"); $(grep '^✖ ' "${LOG:-.}/mut-$name.log" | grep -v 'failing tests' | sort -u | sed 's/^✖ //; s/ ([0-9.]*ms)$//' | paste -sd '|'))"
|
||||
fi
|
||||
mv -- "$file.orig" "$file"
|
||||
}
|
||||
S=packages/cli/src/screens.mjs
|
||||
A=packages/cli/src/app.mjs
|
||||
T=(packages/cli/tests/app.test.mjs)
|
||||
run shown-no-min-cols $S 'return cols >= MIN_COLS && rows >= MIN_ROWS && o?.kind' 'return rows >= MIN_ROWS && o?.kind' "${T[@]}"
|
||||
run r3-shown-no-min $S 'return cols >= MIN_COLS && rows >= MIN_ROWS && o?.kind' 'return o?.kind' "${T[@]}"
|
||||
run n9-17000-end-off $S '(n >= 0x17000 && n <= 0x18d08)' '(n >= 0x17000 && n <= 0x18cff)' "${T[@]}"
|
||||
run cut-drops-choice $S 'const tail = b.slice(-2);' 'const tail = b.slice(-1);' "${T[@]}"
|
||||
run hidden-no-way-out $S ', "Resize, or use mosaic decide."]' ']' "${T[@]}"
|
||||
run hidden-status-promises-y $A 'const state = hidden ? {' 'const state = false ? {' "${T[@]}"
|
||||
@@ -0,0 +1,8 @@
|
||||
start 22:49:16Z
|
||||
shown-no-min-cols: killed (ℹ fail 1; under 40 columns a tall terminal shows the too-small screen even where the decide box would fit; y sends nothing (Filbert N10))
|
||||
r3-shown-no-min: killed (ℹ fail 1; under 40 columns a tall terminal shows the too-small screen even where the decide box would fit; y sends nothing (Filbert N10))
|
||||
n9-17000-end-off: killed (ℹ fail 1; width counts terminal cells: wide CJK and emoji 2, U+FE0F after a one-cell base 1, marks 0)
|
||||
cut-drops-choice: killed (ℹ fail 1; help or a detail box cut to fit keeps its last line, Esc included (Dewey))
|
||||
hidden-no-way-out: killed (ℹ fail 1; a hidden decide box names the way out, and the status line under it does not promise y (Filbert N12))
|
||||
hidden-status-promises-y: killed (ℹ fail 1; a hidden decide box names the way out, and the status line under it does not promise y (Filbert N12))
|
||||
end 22:51:14Z
|
||||
Reference in New Issue
Block a user