oh-skillhub 0.1.18 → 0.1.20

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/package.json +1 -1
  2. package/src/cli.js +81 -26
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-skillhub",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "OpenHarmony Skills installer for Codex, Claude Code, and OpenCode.",
5
5
  "type": "commonjs",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -555,20 +555,21 @@ async function runPromptSelection(input, output, choices, agent = "codex", exist
555
555
  function runRawTuiSelection(input, output, choices, agent = "codex") {
556
556
  return new Promise((resolve, reject) => {
557
557
  let cursor = 8;
558
- const selected = new Set([cursor]);
558
+ const selected = new Set();
559
+ let notice = "";
559
560
  const wasRaw = input.isRaw;
560
561
 
561
- readline.emitKeypressEvents(input);
562
- input.setRawMode(true);
562
+ prepareRawInput(input);
563
563
 
564
564
  function render() {
565
565
  output.write("\x1b[2J\x1b[H");
566
- output.write(renderRawTuiMenu(choices, cursor, selected, agent));
566
+ output.write(renderRawTuiMenu(choices, cursor, selected, agent, notice));
567
+ notice = "";
567
568
  }
568
569
 
569
570
  function cleanup() {
570
571
  input.removeListener("keypress", onKeypress);
571
- input.setRawMode(Boolean(wasRaw));
572
+ releaseRawInput(input, wasRaw);
572
573
  output.write("\x1b[?25h");
573
574
  }
574
575
 
@@ -595,8 +596,13 @@ function runRawTuiSelection(input, output, choices, agent = "codex") {
595
596
  return;
596
597
  }
597
598
  if (key && key.name === "return") {
599
+ if (!selected.size) {
600
+ notice = "Select at least one group with Space.";
601
+ render();
602
+ return;
603
+ }
598
604
  cleanup();
599
- resolve(selected.size ? Array.from(selected).sort((a, b) => a - b) : [cursor]);
605
+ resolve(Array.from(selected).sort((a, b) => a - b));
600
606
  }
601
607
  }
602
608
 
@@ -609,20 +615,21 @@ function runRawTuiSelection(input, output, choices, agent = "codex") {
609
615
  function runRawAgentSelection(input, output) {
610
616
  return new Promise((resolve, reject) => {
611
617
  let cursor = 0;
612
- const selected = new Set([0]);
618
+ const selected = new Set();
619
+ let notice = "";
613
620
  const wasRaw = input.isRaw;
614
621
 
615
- readline.emitKeypressEvents(input);
616
- input.setRawMode(true);
622
+ prepareRawInput(input);
617
623
 
618
624
  function render() {
619
625
  output.write("\x1b[2J\x1b[H");
620
- output.write(renderRawAgentMenu(cursor, selected));
626
+ output.write(renderRawAgentMenu(cursor, selected, notice));
627
+ notice = "";
621
628
  }
622
629
 
623
630
  function cleanup() {
624
631
  input.removeListener("keypress", onKeypress);
625
- input.setRawMode(Boolean(wasRaw));
632
+ releaseRawInput(input, wasRaw);
626
633
  output.write("\x1b[?25h");
627
634
  }
628
635
 
@@ -648,6 +655,11 @@ function runRawAgentSelection(input, output) {
648
655
  return;
649
656
  }
650
657
  if (key && key.name === "return") {
658
+ if (!normalizeAgentIndexes(selected).size) {
659
+ notice = "Select at least one target with Space.";
660
+ render();
661
+ return;
662
+ }
651
663
  cleanup();
652
664
  resolve(agentSelectionFromIndexes(selected, cursor));
653
665
  }
@@ -662,20 +674,21 @@ function runRawAgentSelection(input, output) {
662
674
  function runRawActionSelection(input, output) {
663
675
  return new Promise((resolve, reject) => {
664
676
  let cursor = 0;
665
- let selected = 0;
677
+ let selected = null;
678
+ let notice = "";
666
679
  const wasRaw = input.isRaw;
667
680
 
668
- readline.emitKeypressEvents(input);
669
- input.setRawMode(true);
681
+ prepareRawInput(input);
670
682
 
671
683
  function render() {
672
684
  output.write("\x1b[2J\x1b[H");
673
- output.write(renderRawActionMenu(cursor, selected));
685
+ output.write(renderRawActionMenu(cursor, selected, notice));
686
+ notice = "";
674
687
  }
675
688
 
676
689
  function cleanup() {
677
690
  input.removeListener("keypress", onKeypress);
678
- input.setRawMode(Boolean(wasRaw));
691
+ releaseRawInput(input, wasRaw);
679
692
  output.write("\x1b[?25h");
680
693
  }
681
694
 
@@ -701,6 +714,11 @@ function runRawActionSelection(input, output) {
701
714
  return;
702
715
  }
703
716
  if (key && key.name === "return") {
717
+ if (selected === null) {
718
+ notice = "Select an action with Space.";
719
+ render();
720
+ return;
721
+ }
704
722
  cleanup();
705
723
  resolve(ACTION_CHOICES[selected].action);
706
724
  }
@@ -712,7 +730,7 @@ function runRawActionSelection(input, output) {
712
730
  });
713
731
  }
714
732
 
715
- function renderRawActionMenu(cursor, selected = cursor) {
733
+ function renderRawActionMenu(cursor, selected = null, notice = "") {
716
734
  const width = 76;
717
735
  const line = `+${"-".repeat(width - 2)}+`;
718
736
  const lines = [
@@ -731,11 +749,31 @@ function renderRawActionMenu(cursor, selected = cursor) {
731
749
  const row = `${pointer} ${rawCheckbox(index === selected, highlighted)} ${choice.label.padEnd(22, " ")} ${choice.hint}`;
732
750
  lines.push(index === cursor ? colorize(row, ANSI.reverse, ANSI.bold) : row);
733
751
  });
752
+ if (notice) {
753
+ lines.push("", colorize(notice, ANSI.cyan, ANSI.bold));
754
+ }
734
755
  lines.push("");
735
756
  return `${lines.join("\n")}\n`;
736
757
  }
737
758
 
738
- function renderRawAgentMenu(cursor, selected = new Set([cursor])) {
759
+ function prepareRawInput(input) {
760
+ if (typeof input.on === "function" && typeof input.listenerCount === "function") {
761
+ readline.emitKeypressEvents(input);
762
+ }
763
+ input.setRawMode(true);
764
+ if (typeof input.resume === "function") {
765
+ input.resume();
766
+ }
767
+ }
768
+
769
+ function releaseRawInput(input, wasRaw) {
770
+ input.setRawMode(Boolean(wasRaw));
771
+ if (!wasRaw && typeof input.pause === "function") {
772
+ input.pause();
773
+ }
774
+ }
775
+
776
+ function renderRawAgentMenu(cursor, selected = new Set(), notice = "") {
739
777
  const width = 76;
740
778
  const line = `+${"-".repeat(width - 2)}+`;
741
779
  const selectedIndexes = normalizeAgentIndexes(selected);
@@ -755,11 +793,14 @@ function renderRawAgentMenu(cursor, selected = new Set([cursor])) {
755
793
  const row = `${pointer} ${rawCheckbox(isAgentIndexSelected(selectedIndexes, index), highlighted)} ${choice.label.padEnd(10, " ")} ${choice.hint}`;
756
794
  lines.push(index === cursor ? colorize(row, ANSI.reverse, ANSI.bold) : row);
757
795
  });
796
+ if (notice) {
797
+ lines.push("", colorize(notice, ANSI.cyan, ANSI.bold));
798
+ }
758
799
  lines.push("");
759
800
  return `${lines.join("\n")}\n`;
760
801
  }
761
802
 
762
- function renderRawTuiMenu(choices, cursor, selected, agent = "codex") {
803
+ function renderRawTuiMenu(choices, cursor, selected, agent = "codex", notice = "") {
763
804
  const width = 76;
764
805
  const line = `+${"-".repeat(width - 2)}+`;
765
806
  const lines = [
@@ -786,6 +827,9 @@ function renderRawTuiMenu(choices, cursor, selected, agent = "codex") {
786
827
  lines.push(colorize(` - ${leaf}`, ANSI.dim));
787
828
  }
788
829
  });
830
+ if (notice) {
831
+ lines.push("", colorize(notice, ANSI.cyan, ANSI.bold));
832
+ }
789
833
  lines.push("");
790
834
  return `${lines.join("\n")}\n`;
791
835
  }
@@ -793,20 +837,21 @@ function renderRawTuiMenu(choices, cursor, selected, agent = "codex") {
793
837
  function runRawCleanSelection(input, output, skills) {
794
838
  return new Promise((resolve, reject) => {
795
839
  let cursor = 0;
796
- const selected = new Set([cursor]);
840
+ const selected = new Set();
841
+ let notice = "";
797
842
  const wasRaw = input.isRaw;
798
843
 
799
- readline.emitKeypressEvents(input);
800
- input.setRawMode(true);
844
+ prepareRawInput(input);
801
845
 
802
846
  function render() {
803
847
  output.write("\x1b[2J\x1b[H");
804
- output.write(renderRawCleanSelectionMenu(skills, cursor, selected));
848
+ output.write(renderRawCleanSelectionMenu(skills, cursor, selected, notice));
849
+ notice = "";
805
850
  }
806
851
 
807
852
  function cleanup() {
808
853
  input.removeListener("keypress", onKeypress);
809
- input.setRawMode(Boolean(wasRaw));
854
+ releaseRawInput(input, wasRaw);
810
855
  output.write("\x1b[?25h");
811
856
  }
812
857
 
@@ -833,8 +878,13 @@ function runRawCleanSelection(input, output, skills) {
833
878
  return;
834
879
  }
835
880
  if (key && key.name === "return") {
881
+ if (!selected.size) {
882
+ notice = "Select at least one skill with Space.";
883
+ render();
884
+ return;
885
+ }
836
886
  cleanup();
837
- resolve(selected.size ? Array.from(selected).sort((a, b) => a - b) : [cursor]);
887
+ resolve(Array.from(selected).sort((a, b) => a - b));
838
888
  }
839
889
  }
840
890
 
@@ -844,7 +894,7 @@ function runRawCleanSelection(input, output, skills) {
844
894
  });
845
895
  }
846
896
 
847
- function renderRawCleanSelectionMenu(skills, cursor, selected) {
897
+ function renderRawCleanSelectionMenu(skills, cursor, selected, notice = "") {
848
898
  const width = 92;
849
899
  const line = `+${"-".repeat(width - 2)}+`;
850
900
  const lines = [
@@ -865,6 +915,9 @@ function renderRawCleanSelectionMenu(skills, cursor, selected) {
865
915
  const row = `${pointer} ${checkbox} ${skill.name.padEnd(36, " ")} ${skill.status.padEnd(9, " ")} ${group}`;
866
916
  lines.push(highlighted ? colorize(row, ANSI.reverse, ANSI.bold) : row);
867
917
  });
918
+ if (notice) {
919
+ lines.push("", colorize(notice, ANSI.cyan, ANSI.bold));
920
+ }
868
921
  lines.push("");
869
922
  return `${lines.join("\n")}\n`;
870
923
  }
@@ -1156,6 +1209,8 @@ module.exports = {
1156
1209
  renderRawAgentMenu,
1157
1210
  renderRawCleanSelectionMenu,
1158
1211
  parseSelection,
1212
+ prepareRawInput,
1213
+ releaseRawInput,
1159
1214
  renderRawTuiMenu,
1160
1215
  renderTuiMenu,
1161
1216
  withSpinner,