groundcrew-cli 0.14.2 → 0.15.1
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/dist/index.js +35 -31
- package/package.json +1 -1
- package/src/index.ts +49 -42
package/dist/index.js
CHANGED
|
@@ -398,7 +398,7 @@ var CHAT_COMMANDS = [
|
|
|
398
398
|
{ cmd: "/history", desc: "Show completed tasks" },
|
|
399
399
|
{ cmd: "/queue", desc: "Show pending tasks" },
|
|
400
400
|
{ cmd: "/clear", desc: "Clear pending tasks" },
|
|
401
|
-
{ cmd: "/
|
|
401
|
+
{ cmd: "/exit", desc: "Exit chat" }
|
|
402
402
|
];
|
|
403
403
|
function chatCompleter(line) {
|
|
404
404
|
if (!line.startsWith("/")) return [[], line];
|
|
@@ -415,50 +415,54 @@ function chatCompleter(line) {
|
|
|
415
415
|
return [[], line];
|
|
416
416
|
}
|
|
417
417
|
function setupInlineSuggestions(rl) {
|
|
418
|
-
let
|
|
418
|
+
let ghostLines = 0;
|
|
419
419
|
const clearGhost = () => {
|
|
420
|
-
if (
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
420
|
+
if (ghostLines > 0) {
|
|
421
|
+
for (let i = 0; i < ghostLines; i++) {
|
|
422
|
+
process.stdout.write("\x1B[B\x1B[2K");
|
|
423
|
+
}
|
|
424
|
+
process.stdout.write(`\x1B[${ghostLines}A`);
|
|
425
|
+
ghostLines = 0;
|
|
424
426
|
}
|
|
427
|
+
process.stdout.write("\x1B[u\x1B[K");
|
|
425
428
|
};
|
|
426
429
|
const showGhost = () => {
|
|
427
430
|
const line = rl.line;
|
|
428
431
|
if (!line || !line.startsWith("/") || line.includes(" ")) {
|
|
429
|
-
clearGhost();
|
|
430
432
|
return;
|
|
431
433
|
}
|
|
432
434
|
const matches = CHAT_COMMANDS.filter((c) => c.cmd.startsWith(line));
|
|
433
|
-
if (matches.length === 0)
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
435
|
+
if (matches.length === 0) return;
|
|
436
|
+
process.stdout.write("\x1B[s");
|
|
437
|
+
if (matches.length === 1) {
|
|
438
|
+
const best = matches[0];
|
|
439
|
+
const remainder = best.cmd.slice(line.length);
|
|
440
|
+
if (!remainder) return;
|
|
441
|
+
const ghost = `${remainder} \u2014 ${best.desc}`;
|
|
442
|
+
process.stdout.write("\x1B[K");
|
|
443
|
+
process.stdout.write(`\x1B[2m${ghost}\x1B[0m`);
|
|
444
|
+
process.stdout.write("\x1B[u");
|
|
445
|
+
} else {
|
|
446
|
+
const shown = matches.slice(0, 5);
|
|
447
|
+
process.stdout.write("\x1B[K");
|
|
448
|
+
const best = shown[0];
|
|
449
|
+
const remainder = best.cmd.slice(line.length);
|
|
450
|
+
if (remainder) {
|
|
451
|
+
process.stdout.write(`\x1B[2m${remainder} \u2014 ${best.desc}\x1B[0m`);
|
|
452
|
+
}
|
|
453
|
+
for (let i = 1; i < shown.length; i++) {
|
|
454
|
+
const m = shown[i];
|
|
455
|
+
process.stdout.write(`
|
|
456
|
+
\x1B[2K \x1B[2m${m.cmd.padEnd(12)} \u2014 ${m.desc}\x1B[0m`);
|
|
457
|
+
}
|
|
458
|
+
ghostLines = shown.length - 1;
|
|
459
|
+
process.stdout.write("\x1B[u");
|
|
450
460
|
}
|
|
451
|
-
clearGhost();
|
|
452
|
-
process.stdout.write(`\x1B[2m${fullGhost}\x1B[0m`);
|
|
453
|
-
lastGhostLen = fullGhost.length;
|
|
454
|
-
process.stdout.write("\x1B[" + lastGhostLen + "D");
|
|
455
461
|
};
|
|
456
462
|
process.stdin.on("keypress", (_ch, key) => {
|
|
457
463
|
if (!key) return;
|
|
458
464
|
clearGhost();
|
|
459
|
-
if (key.name !== "return" && key.name !== "tab"
|
|
460
|
-
setImmediate(showGhost);
|
|
461
|
-
} else if (key.name === "backspace") {
|
|
465
|
+
if (key.name !== "return" && key.name !== "tab") {
|
|
462
466
|
setImmediate(showGhost);
|
|
463
467
|
}
|
|
464
468
|
});
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -518,7 +518,7 @@ const CHAT_COMMANDS: Array<{ cmd: string; desc: string }> = [
|
|
|
518
518
|
{ cmd: "/history", desc: "Show completed tasks" },
|
|
519
519
|
{ cmd: "/queue", desc: "Show pending tasks" },
|
|
520
520
|
{ cmd: "/clear", desc: "Clear pending tasks" },
|
|
521
|
-
{ cmd: "/
|
|
521
|
+
{ cmd: "/exit", desc: "Exit chat" },
|
|
522
522
|
];
|
|
523
523
|
|
|
524
524
|
function chatCompleter(line: string): [string[], string] {
|
|
@@ -540,68 +540,75 @@ function chatCompleter(line: string): [string[], string] {
|
|
|
540
540
|
}
|
|
541
541
|
|
|
542
542
|
/**
|
|
543
|
-
* Show inline ghost
|
|
544
|
-
*
|
|
543
|
+
* Show inline ghost suggestions as user types / commands.
|
|
544
|
+
* Single match: inline ghost after cursor.
|
|
545
|
+
* Multiple matches: multi-line dropdown below the prompt (max 5).
|
|
545
546
|
*/
|
|
546
547
|
function setupInlineSuggestions(rl: readline.Interface): void {
|
|
547
|
-
let
|
|
548
|
+
let ghostLines = 0; // how many extra lines we rendered below prompt
|
|
548
549
|
|
|
549
550
|
const clearGhost = () => {
|
|
550
|
-
if (
|
|
551
|
-
// Move
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
551
|
+
if (ghostLines > 0) {
|
|
552
|
+
// Move down and clear each ghost line, then move back up
|
|
553
|
+
for (let i = 0; i < ghostLines; i++) {
|
|
554
|
+
process.stdout.write("\x1b[B\x1b[2K"); // down + clear line
|
|
555
|
+
}
|
|
556
|
+
// Move back up to prompt line
|
|
557
|
+
process.stdout.write(`\x1b[${ghostLines}A`);
|
|
558
|
+
ghostLines = 0;
|
|
555
559
|
}
|
|
560
|
+
// Restore cursor and clear to end of line (for inline ghost)
|
|
561
|
+
process.stdout.write("\x1b[u\x1b[K");
|
|
556
562
|
};
|
|
557
563
|
|
|
558
564
|
const showGhost = () => {
|
|
559
565
|
const line = (rl as any).line as string;
|
|
560
566
|
if (!line || !line.startsWith("/") || line.includes(" ")) {
|
|
561
|
-
clearGhost();
|
|
562
567
|
return;
|
|
563
568
|
}
|
|
564
569
|
|
|
565
570
|
const matches = CHAT_COMMANDS.filter((c) => c.cmd.startsWith(line));
|
|
566
|
-
if (matches.length === 0)
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
571
|
+
if (matches.length === 0) return;
|
|
572
|
+
|
|
573
|
+
// Save cursor position
|
|
574
|
+
process.stdout.write("\x1b[s");
|
|
575
|
+
|
|
576
|
+
if (matches.length === 1) {
|
|
577
|
+
// Single match: inline ghost remainder + description
|
|
578
|
+
const best = matches[0];
|
|
579
|
+
const remainder = best.cmd.slice(line.length);
|
|
580
|
+
if (!remainder) return;
|
|
581
|
+
const ghost = `${remainder} \u2014 ${best.desc}`;
|
|
582
|
+
process.stdout.write("\x1b[K");
|
|
583
|
+
process.stdout.write(`\x1b[2m${ghost}\x1b[0m`);
|
|
584
|
+
process.stdout.write("\x1b[u");
|
|
585
|
+
} else {
|
|
586
|
+
// Multiple matches: show dropdown below prompt (max 5)
|
|
587
|
+
const shown = matches.slice(0, 5);
|
|
588
|
+
// Clear to end of line first
|
|
589
|
+
process.stdout.write("\x1b[K");
|
|
590
|
+
// Inline ghost for the best match remainder
|
|
591
|
+
const best = shown[0];
|
|
592
|
+
const remainder = best.cmd.slice(line.length);
|
|
593
|
+
if (remainder) {
|
|
594
|
+
process.stdout.write(`\x1b[2m${remainder} \u2014 ${best.desc}\x1b[0m`);
|
|
595
|
+
}
|
|
596
|
+
// Render dropdown lines below
|
|
597
|
+
for (let i = 1; i < shown.length; i++) {
|
|
598
|
+
const m = shown[i];
|
|
599
|
+
process.stdout.write(`\n\x1b[2K \x1b[2m${m.cmd.padEnd(12)} \u2014 ${m.desc}\x1b[0m`);
|
|
600
|
+
}
|
|
601
|
+
ghostLines = shown.length - 1;
|
|
602
|
+
// Restore cursor to typing position
|
|
603
|
+
process.stdout.write("\x1b[u");
|
|
589
604
|
}
|
|
590
|
-
|
|
591
|
-
clearGhost();
|
|
592
|
-
process.stdout.write(`\x1b[2m${fullGhost}\x1b[0m`);
|
|
593
|
-
lastGhostLen = fullGhost.length;
|
|
594
|
-
process.stdout.write("\x1b[" + lastGhostLen + "D");
|
|
595
605
|
};
|
|
596
606
|
|
|
597
607
|
// Listen to keypresses
|
|
598
608
|
process.stdin.on("keypress", (_ch: string, key: any) => {
|
|
599
609
|
if (!key) return;
|
|
600
|
-
// Clear ghost first, then show updated one on next tick
|
|
601
610
|
clearGhost();
|
|
602
|
-
if (key.name !== "return" && key.name !== "tab"
|
|
603
|
-
setImmediate(showGhost);
|
|
604
|
-
} else if (key.name === "backspace") {
|
|
611
|
+
if (key.name !== "return" && key.name !== "tab") {
|
|
605
612
|
setImmediate(showGhost);
|
|
606
613
|
}
|
|
607
614
|
});
|