groundcrew-cli 0.16.1 → 0.16.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.
Files changed (3) hide show
  1. package/dist/index.js +24 -19
  2. package/package.json +1 -1
  3. package/src/index.ts +36 -24
package/dist/index.js CHANGED
@@ -494,8 +494,20 @@ function readMultilineInput(sessionId, projectName, gitCtx) {
494
494
  buf.push(" ".repeat(padWidth) + lines[i]);
495
495
  }
496
496
  }
497
+ let suggestionRows = 0;
498
+ if (lines.length === 1 && lines[0].startsWith("/") && !lines[0].includes(" ")) {
499
+ const partial = lines[0];
500
+ const matches = CHAT_COMMANDS.filter((c) => c.cmd.startsWith(partial));
501
+ if (matches.length > 0 && partial.length >= 1) {
502
+ for (const m of matches) {
503
+ buf.push(`
504
+ ${cyan(m.cmd.padEnd(14))} ${dim(m.desc)}`);
505
+ suggestionRows++;
506
+ }
507
+ }
508
+ }
497
509
  const lastRow = lines.length - 1;
498
- const rowsUp = lastRow - crow;
510
+ const rowsUp = lastRow - crow + suggestionRows;
499
511
  if (rowsUp > 0) buf.push(`\x1B[${rowsUp}A`);
500
512
  buf.push("\r");
501
513
  const col = padWidth + ccol;
@@ -509,13 +521,17 @@ function readMultilineInput(sessionId, projectName, gitCtx) {
509
521
  };
510
522
  const submit = () => {
511
523
  const text = fullText();
512
- const lastRow = lines.length - 1;
513
- const rowsDown = lastRow - crow;
514
524
  const buf = [];
515
- if (rowsDown > 0) buf.push(`\x1B[${rowsDown}B`);
516
- buf.push("\r");
517
- const endCol = padWidth + lines[lastRow].length;
518
- if (endCol > 0) buf.push(`\x1B[${endCol}C`);
525
+ if (lastTermRow > 0) buf.push(`\x1B[${lastTermRow}A`);
526
+ buf.push("\r\x1B[J");
527
+ for (let i = 0; i < lines.length; i++) {
528
+ if (i > 0) buf.push("\n");
529
+ if (i === 0) {
530
+ buf.push(dim(`[${sessionId}]`) + " " + bold(">") + " " + lines[i]);
531
+ } else {
532
+ buf.push(" ".repeat(padWidth) + lines[i]);
533
+ }
534
+ }
519
535
  buf.push("\n");
520
536
  process.stdout.write(buf.join(""));
521
537
  lastTermRow = 0;
@@ -664,15 +680,10 @@ function readMultilineInput(sessionId, projectName, gitCtx) {
664
680
  switch (codepoint) {
665
681
  case 99:
666
682
  if (fullText() || lines.length > 1 || lines[0].length > 0) {
667
- const lastRow = lines.length - 1;
668
- const rowsDown = lastRow - crow;
669
- if (rowsDown > 0) process.stdout.write(`\x1B[${rowsDown}B`);
670
- process.stdout.write("\r\n");
671
683
  lines.length = 0;
672
684
  lines.push("");
673
685
  crow = 0;
674
686
  ccol = 0;
675
- lastTermRow = 0;
676
687
  render();
677
688
  } else {
678
689
  process.stdout.write("\r\n");
@@ -748,17 +759,11 @@ function readMultilineInput(sessionId, projectName, gitCtx) {
748
759
  continue;
749
760
  }
750
761
  if (str[i] === "") {
751
- const hasText = fullText();
752
- if (hasText || lines.length > 1 || lines[0].length > 0) {
753
- const lastRow = lines.length - 1;
754
- const rowsDown = lastRow - crow;
755
- if (rowsDown > 0) process.stdout.write(`\x1B[${rowsDown}B`);
756
- process.stdout.write("\r\n");
762
+ if (fullText() || lines.length > 1 || lines[0].length > 0) {
757
763
  lines.length = 0;
758
764
  lines.push("");
759
765
  crow = 0;
760
766
  ccol = 0;
761
- lastTermRow = 0;
762
767
  render();
763
768
  } else {
764
769
  process.stdout.write("\r\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "groundcrew-cli",
3
- "version": "0.16.1",
3
+ "version": "0.16.3",
4
4
  "description": "CLI companion for Groundcrew — queue tasks, send feedback, monitor your Copilot agent from another terminal.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -626,7 +626,7 @@ function readMultilineInput(sessionId: string, projectName: string, gitCtx: { br
626
626
  const render = () => {
627
627
  const buf: string[] = [];
628
628
 
629
- // Move to start of input area (includes separator line)
629
+ // Move to start of input area (includes separator line + suggestions)
630
630
  if (lastTermRow > 0) buf.push(`\x1b[${lastTermRow}A`);
631
631
  buf.push("\r\x1b[J"); // col 0 + clear to end of screen
632
632
 
@@ -652,17 +652,31 @@ function readMultilineInput(sessionId: string, projectName: string, gitCtx: { br
652
652
  }
653
653
  }
654
654
 
655
+ // Auto-show slash command suggestions below input
656
+ let suggestionRows = 0;
657
+ if (lines.length === 1 && lines[0].startsWith("/") && !lines[0].includes(" ")) {
658
+ const partial = lines[0];
659
+ const matches = CHAT_COMMANDS.filter(c => c.cmd.startsWith(partial));
660
+ if (matches.length > 0 && partial.length >= 1) {
661
+ for (const m of matches) {
662
+ buf.push(`\n ${cyan(m.cmd.padEnd(14))} ${dim(m.desc)}`);
663
+ suggestionRows++;
664
+ }
665
+ }
666
+ }
667
+
655
668
  // Position cursor at (crow, ccol)
656
669
  const lastRow = lines.length - 1;
657
- const rowsUp = lastRow - crow;
670
+ // Position cursor at (crow, ccol) — move up past remaining input lines + suggestions
671
+ const rowsUp = (lastRow - crow) + suggestionRows;
658
672
  if (rowsUp > 0) buf.push(`\x1b[${rowsUp}A`);
659
673
 
660
674
  buf.push("\r");
661
675
  const col = padWidth + ccol;
662
676
  if (col > 0) buf.push(`\x1b[${col}C`);
663
677
 
664
- // lastTermRow = rows from cursor back to top of separator
665
- // separator is 1 row, then crow rows of input below it
678
+ // lastTermRow = rows above cursor (separator + input lines above crow)
679
+ // Suggestion rows below cursor are cleared by \x1b[J on next render
666
680
  lastTermRow = 1 + crow;
667
681
  process.stdout.write(buf.join(""));
668
682
  };
@@ -674,14 +688,20 @@ function readMultilineInput(sessionId: string, projectName: string, gitCtx: { br
674
688
 
675
689
  const submit = () => {
676
690
  const text = fullText();
677
- // Move cursor to end of input for clean output
678
- const lastRow = lines.length - 1;
679
- const rowsDown = lastRow - crow;
691
+ // Erase the separator + input area, then re-draw only the prompt (no separator in history)
680
692
  const buf: string[] = [];
681
- if (rowsDown > 0) buf.push(`\x1b[${rowsDown}B`);
682
- buf.push("\r");
683
- const endCol = padWidth + lines[lastRow].length;
684
- if (endCol > 0) buf.push(`\x1b[${endCol}C`);
693
+ if (lastTermRow > 0) buf.push(`\x1b[${lastTermRow}A`);
694
+ buf.push("\r\x1b[J"); // clear from separator line down
695
+
696
+ // Re-draw only the input lines (no separator)
697
+ for (let i = 0; i < lines.length; i++) {
698
+ if (i > 0) buf.push("\n");
699
+ if (i === 0) {
700
+ buf.push(dim(`[${sessionId}]`) + " " + bold(">") + " " + lines[i]);
701
+ } else {
702
+ buf.push(" ".repeat(padWidth) + lines[i]);
703
+ }
704
+ }
685
705
  buf.push("\n");
686
706
  process.stdout.write(buf.join(""));
687
707
  lastTermRow = 0;
@@ -816,12 +836,9 @@ function readMultilineInput(sessionId: string, projectName: string, gitCtx: { br
816
836
  switch (codepoint) {
817
837
  case 99: // Ctrl+C
818
838
  if (fullText() || lines.length > 1 || lines[0].length > 0) {
819
- const lastRow = lines.length - 1;
820
- const rowsDown = lastRow - crow;
821
- if (rowsDown > 0) process.stdout.write(`\x1b[${rowsDown}B`);
822
- process.stdout.write("\r\n");
839
+ // Clear input in-place (no scrollback residue)
823
840
  lines.length = 0; lines.push("");
824
- crow = 0; ccol = 0; lastTermRow = 0;
841
+ crow = 0; ccol = 0;
825
842
  render();
826
843
  } else {
827
844
  process.stdout.write("\r\n");
@@ -869,15 +886,10 @@ function readMultilineInput(sessionId: string, projectName: string, gitCtx: { br
869
886
 
870
887
  // Ctrl+C — clear input or exit
871
888
  if (str[i] === "\x03") {
872
- const hasText = fullText();
873
- if (hasText || lines.length > 1 || lines[0].length > 0) {
874
- // Move past current rendering to below last line, start fresh
875
- const lastRow = lines.length - 1;
876
- const rowsDown = lastRow - crow;
877
- if (rowsDown > 0) process.stdout.write(`\x1b[${rowsDown}B`);
878
- process.stdout.write("\r\n");
889
+ if (fullText() || lines.length > 1 || lines[0].length > 0) {
890
+ // Clear input in-place (no scrollback residue)
879
891
  lines.length = 0; lines.push("");
880
- crow = 0; ccol = 0; lastTermRow = 0;
892
+ crow = 0; ccol = 0;
881
893
  render();
882
894
  } else {
883
895
  process.stdout.write("\r\n");