@step-forge/step-forge 0.0.25-alpha.1 → 0.0.25-alpha.3
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/RUNTIME.md +5 -2
- package/dist/cli.cjs +80 -7
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +80 -7
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ import * as fs from "node:fs";
|
|
|
10
10
|
import { parseArgs } from "node:util";
|
|
11
11
|
import { spawn } from "node:child_process";
|
|
12
12
|
import * as readline from "node:readline";
|
|
13
|
+
import { PassThrough } from "node:stream";
|
|
13
14
|
//#region src/runtime/config.ts
|
|
14
15
|
const DEFAULT_FEATURES = "**/*.feature";
|
|
15
16
|
const DEFAULT_STEPS = "**/*.steps.ts";
|
|
@@ -526,9 +527,14 @@ var Prompt = class {
|
|
|
526
527
|
results = freshResults();
|
|
527
528
|
failScroll = 0;
|
|
528
529
|
started = false;
|
|
530
|
+
/** Filtered key stream: raw stdin minus the mouse sequences we handle. */
|
|
531
|
+
input;
|
|
529
532
|
keyListener;
|
|
533
|
+
dataListener;
|
|
530
534
|
resizeListener;
|
|
531
535
|
signalCleanup;
|
|
536
|
+
/** Carry an incomplete mouse sequence split across stdin chunks. */
|
|
537
|
+
mousePending = "";
|
|
532
538
|
constructor(options) {
|
|
533
539
|
this.handlers = options.handlers;
|
|
534
540
|
this.prefix = options.prefix ?? "› ";
|
|
@@ -583,11 +589,14 @@ var Prompt = class {
|
|
|
583
589
|
start() {
|
|
584
590
|
if (this.started) return;
|
|
585
591
|
this.started = true;
|
|
586
|
-
readline.emitKeypressEvents(process.stdin);
|
|
587
592
|
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
588
|
-
write("\x1B[?1049h");
|
|
593
|
+
write("\x1B[?1049h\x1B[?1000h\x1B[?1006h");
|
|
594
|
+
this.input = new PassThrough();
|
|
595
|
+
readline.emitKeypressEvents(this.input);
|
|
589
596
|
this.keyListener = (str, key) => this.onKey(str, key ?? {});
|
|
590
|
-
|
|
597
|
+
this.input.on("keypress", this.keyListener);
|
|
598
|
+
this.dataListener = (chunk) => this.onStdinData(chunk);
|
|
599
|
+
process.stdin.on("data", this.dataListener);
|
|
591
600
|
process.stdin.resume();
|
|
592
601
|
this.resizeListener = () => this.render();
|
|
593
602
|
process.stdout.on("resize", this.resizeListener);
|
|
@@ -598,11 +607,14 @@ var Prompt = class {
|
|
|
598
607
|
stop() {
|
|
599
608
|
if (!this.started) return;
|
|
600
609
|
this.started = false;
|
|
601
|
-
if (this.
|
|
610
|
+
if (this.dataListener) process.stdin.off("data", this.dataListener);
|
|
611
|
+
if (this.keyListener) this.input?.off("keypress", this.keyListener);
|
|
602
612
|
if (this.resizeListener) process.stdout.off("resize", this.resizeListener);
|
|
603
613
|
this.signalCleanup?.();
|
|
604
614
|
this.restoreTerminal();
|
|
605
615
|
process.stdin.pause();
|
|
616
|
+
this.input = void 0;
|
|
617
|
+
this.mousePending = "";
|
|
606
618
|
}
|
|
607
619
|
/** Force a repaint (after mutating `status`, say). No-op until started. */
|
|
608
620
|
redraw() {
|
|
@@ -615,6 +627,7 @@ var Prompt = class {
|
|
|
615
627
|
*/
|
|
616
628
|
restoreTerminal() {
|
|
617
629
|
if (process.stdin.isTTY) process.stdin.setRawMode(false);
|
|
630
|
+
write("\x1B[?1006l\x1B[?1000l");
|
|
618
631
|
write("\x1B[?25h");
|
|
619
632
|
write("\x1B[?1049l");
|
|
620
633
|
}
|
|
@@ -718,12 +731,72 @@ var Prompt = class {
|
|
|
718
731
|
this.reWindow();
|
|
719
732
|
this.render();
|
|
720
733
|
}
|
|
721
|
-
/** Scroll the failures pane by
|
|
734
|
+
/** Scroll the failures pane by whole pages (PgUp/PgDn). */
|
|
722
735
|
scrollFailures(pages) {
|
|
723
|
-
this.
|
|
724
|
-
this.render();
|
|
736
|
+
this.adjustFailScroll(pages * this.failPage);
|
|
725
737
|
}
|
|
726
738
|
failPage = 1;
|
|
739
|
+
/**
|
|
740
|
+
* Move the failures viewport by `deltaLines` (clamped in {@link render}).
|
|
741
|
+
* Scrolling repaints via {@link scheduleRender} so a burst of wheel events
|
|
742
|
+
* (a trackpad fires many per gesture) collapses into a single frame instead of
|
|
743
|
+
* one full-screen repaint each — which is what made small scrolls stutter.
|
|
744
|
+
*/
|
|
745
|
+
adjustFailScroll(deltaLines) {
|
|
746
|
+
this.failScroll = Math.max(0, this.failScroll + deltaLines);
|
|
747
|
+
this.scheduleRender();
|
|
748
|
+
}
|
|
749
|
+
renderQueued = false;
|
|
750
|
+
/** Coalesce repaints scheduled within the same tick into one frame. */
|
|
751
|
+
scheduleRender() {
|
|
752
|
+
if (this.renderQueued) return;
|
|
753
|
+
this.renderQueued = true;
|
|
754
|
+
queueMicrotask(() => {
|
|
755
|
+
this.renderQueued = false;
|
|
756
|
+
if (this.started) this.render();
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Split a raw stdin chunk: decode SGR/legacy mouse sequences here (only the
|
|
761
|
+
* wheel is acted on — it scrolls the failures pane by a few lines) and forward
|
|
762
|
+
* everything else to readline. An incomplete trailing mouse sequence is held
|
|
763
|
+
* in {@link mousePending} for the next chunk. `latin1` keeps every byte 1:1 so
|
|
764
|
+
* the forwarded bytes reassemble exactly (including multibyte input).
|
|
765
|
+
*/
|
|
766
|
+
onStdinData(chunk) {
|
|
767
|
+
const buf = this.mousePending + chunk.toString("latin1");
|
|
768
|
+
let out = "";
|
|
769
|
+
let i = 0;
|
|
770
|
+
while (i < buf.length) {
|
|
771
|
+
if (buf.startsWith("\x1B[<", i)) {
|
|
772
|
+
const rel = /[Mm]/.exec(buf.slice(i + 3));
|
|
773
|
+
if (!rel) break;
|
|
774
|
+
const end = i + 3 + rel.index + 1;
|
|
775
|
+
this.handleMouse(buf.slice(i, end));
|
|
776
|
+
i = end;
|
|
777
|
+
continue;
|
|
778
|
+
}
|
|
779
|
+
if (buf.startsWith("\x1B[M", i)) {
|
|
780
|
+
if (i + 6 > buf.length) break;
|
|
781
|
+
this.handleMouse(buf.slice(i, i + 6));
|
|
782
|
+
i += 6;
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
785
|
+
out += buf[i];
|
|
786
|
+
i++;
|
|
787
|
+
}
|
|
788
|
+
this.mousePending = buf.slice(i);
|
|
789
|
+
if (out) this.input?.write(Buffer.from(out, "latin1"));
|
|
790
|
+
}
|
|
791
|
+
/** Act on a decoded mouse sequence — wheel up/down scrolls failures; else ignore. */
|
|
792
|
+
handleMouse(seq) {
|
|
793
|
+
let button = null;
|
|
794
|
+
const sgr = /^\x1b\[<(\d+);\d+;\d+[Mm]$/.exec(seq);
|
|
795
|
+
if (sgr) button = parseInt(sgr[1], 10);
|
|
796
|
+
else if (seq.length === 6) button = seq.charCodeAt(3) - 32;
|
|
797
|
+
if (button === null || (button & 64) === 0) return;
|
|
798
|
+
this.adjustFailScroll((button & 1) === 0 ? -1 : 1);
|
|
799
|
+
}
|
|
727
800
|
refilter() {
|
|
728
801
|
const q = this.query.trim().toLowerCase();
|
|
729
802
|
this.matches = this.all.map((s, index) => ({
|