prior-cli 1.3.9 → 1.3.11

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 (2) hide show
  1. package/bin/prior.js +64 -50
  2. package/package.json +1 -1
package/bin/prior.js CHANGED
@@ -628,27 +628,56 @@ async function startChat(opts = {}) {
628
628
  { cmd: '/exit', desc: 'Exit' },
629
629
  ];
630
630
 
631
- let _suggCount = 0;
632
- let _suggTimer = null;
631
+ // Unified sub-row tracker — covers image indicator + slash suggestions
632
+ let _subRowCount = 0;
633
+ let _suggTimer = null;
633
634
 
634
- clearSuggestions = function () {
635
- if (_suggCount === 0) return;
635
+ // Clear all rows rendered below the input line
636
+ function clearAllSubRows() {
637
+ if (!_subRowCount) return;
636
638
  process.stdout.write('\x1b[s');
637
- for (let i = 0; i < _suggCount; i++) process.stdout.write('\x1b[B\r\x1b[2K');
639
+ for (let i = 0; i < _subRowCount; i++) process.stdout.write('\x1b[B\r\x1b[2K');
638
640
  process.stdout.write('\x1b[u');
639
- _suggCount = 0;
640
- };
641
+ _subRowCount = 0;
642
+ }
641
643
 
642
- function renderSuggestions(matches) {
643
- clearSuggestions();
644
- if (!matches.length) return;
645
- _suggCount = matches.length;
646
- process.stdout.write('\x1b[s'); // save cursor at end of typed input
647
- for (const { cmd, desc } of matches) {
648
- // \x1b[B = cursor down 1 (no scroll), \r = col 0, \x1b[2K = clear line
649
- process.stdout.write(`\x1b[B\r\x1b[2K${c.brand(' ' + cmd.padEnd(14))}${c.dim(desc)}`);
644
+ // Alias used by the loop's rl.question callback
645
+ clearSuggestions = clearAllSubRows;
646
+
647
+ // Redraw image indicator + slash suggestions — always called together so
648
+ // they share the same row-count and never stomp on each other.
649
+ function renderSubRows(line) {
650
+ clearAllSubRows();
651
+ process.stdout.write('\x1b[s');
652
+ let rows = 0;
653
+
654
+ // Image indicator — always first, persists across backspace/typing
655
+ if (_pendingImageBase64) {
656
+ process.stdout.write(`\x1b[B\r\x1b[2K ${c.brand('◈')} ${c.dim('[Image] attached · alt+v to remove')}`);
657
+ rows++;
650
658
  }
651
- process.stdout.write('\x1b[u'); // restore cursor to end of typed input
659
+
660
+ // Slash-command suggestions
661
+ if ((line || '').startsWith('/')) {
662
+ const word = line.split(' ')[0];
663
+ const matches = SLASH_CMDS.filter(({ cmd }) => cmd.startsWith(word));
664
+ for (const { cmd, desc } of matches) {
665
+ process.stdout.write(`\x1b[B\r\x1b[2K${c.brand(' ' + cmd.padEnd(14))}${c.dim(desc)}`);
666
+ rows++;
667
+ }
668
+ }
669
+
670
+ process.stdout.write('\x1b[u');
671
+ _subRowCount = rows;
672
+ }
673
+
674
+ // Show a one-off message below the input (cleared on next keypress)
675
+ function flashSubRow(msg) {
676
+ clearAllSubRows();
677
+ process.stdout.write('\x1b[s');
678
+ process.stdout.write(`\x1b[B\r\x1b[2K ${msg}`);
679
+ process.stdout.write('\x1b[u');
680
+ _subRowCount = 1;
652
681
  }
653
682
 
654
683
  process.stdin.on('keypress', (ch, key) => {
@@ -661,52 +690,37 @@ async function startChat(opts = {}) {
661
690
  return;
662
691
  }
663
692
 
664
- // Alt+V — paste image from clipboard
693
+ // Alt+V — grab image from clipboard, or remove if already attached
665
694
  if (key.meta && key.name === 'v') {
666
- try {
667
- const ps = `Add-Type -AssemblyName System.Windows.Forms; $img = [System.Windows.Forms.Clipboard]::GetImage(); if ($img) { $ms = New-Object System.IO.MemoryStream; $img.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); [Convert]::ToBase64String($ms.ToArray()) } else { '' }`;
668
- const b64 = execSync(`powershell -NoProfile -Command "${ps}"`, { timeout: 5000 }).toString().trim();
669
- if (b64) {
670
- _pendingImageBase64 = b64;
671
- // Print the indicator below the current input line
672
- process.stdout.write('\x1b[s');
673
- process.stdout.write(`\x1b[B\r\x1b[2K ${c.brand('◈')} ${c.dim('image from clipboard attached — type your prompt and press enter')}`);
674
- process.stdout.write('\x1b[u');
675
- } else {
676
- process.stdout.write('\x1b[s');
677
- process.stdout.write(`\x1b[B\r\x1b[2K ${c.muted('✗ No image found in clipboard')}`);
678
- process.stdout.write('\x1b[u');
695
+ if (_pendingImageBase64) {
696
+ _pendingImageBase64 = null;
697
+ renderSubRows(rl.line || '');
698
+ } else {
699
+ try {
700
+ const ps = `Add-Type -AssemblyName System.Windows.Forms; $img = [System.Windows.Forms.Clipboard]::GetImage(); if ($img) { $ms = New-Object System.IO.MemoryStream; $img.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); [Convert]::ToBase64String($ms.ToArray()) } else { '' }`;
701
+ const b64 = execSync(`powershell -NoProfile -Command "${ps}"`, { timeout: 5000 }).toString().trim();
702
+ if (b64) {
703
+ _pendingImageBase64 = b64;
704
+ renderSubRows(rl.line || '');
705
+ } else {
706
+ flashSubRow(c.muted('✗ No image found in clipboard'));
707
+ }
708
+ } catch {
709
+ flashSubRow(c.muted('✗ Could not read clipboard'));
679
710
  }
680
- } catch {
681
- process.stdout.write('\x1b[s');
682
- process.stdout.write(`\x1b[B\r\x1b[2K ${c.muted('✗ Could not read clipboard')}`);
683
- process.stdout.write('\x1b[u');
684
711
  }
685
712
  return;
686
713
  }
687
714
 
688
715
  if (key.name === 'return' || key.name === 'enter' || (key.ctrl && key.name === 'c')) {
689
- // Clear suggestions and image indicator before readline moves cursor
690
- const clearRows = _suggCount + (_pendingImageBase64 ? 1 : 0);
691
- if (clearRows > 0) {
692
- process.stdout.write('\x1b[s');
693
- for (let i = 0; i < clearRows; i++) process.stdout.write('\x1b[B\r\x1b[2K');
694
- process.stdout.write('\x1b[u');
695
- _suggCount = 0;
696
- }
716
+ clearAllSubRows();
697
717
  return;
698
718
  }
699
719
 
720
+ // Redraw sub-rows on every keypress so backspace / typing never wipes them
700
721
  _suggTimer = setTimeout(() => {
701
722
  _suggTimer = null;
702
- const line = rl.line || '';
703
- if (!line.startsWith('/')) {
704
- clearSuggestions();
705
- return;
706
- }
707
- const word = line.split(' ')[0];
708
- const matches = SLASH_CMDS.filter(({ cmd }) => cmd.startsWith(word));
709
- renderSuggestions(matches);
723
+ renderSubRows(rl.line || '');
710
724
  }, 50);
711
725
  });
712
726
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prior-cli",
3
- "version": "1.3.9",
3
+ "version": "1.3.11",
4
4
  "description": "Prior Network AI — command-line interface",
5
5
  "bin": {
6
6
  "prior": "bin/prior.js"