opencode-hub 1.0.12 → 1.0.14

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/oc-tui.js +65 -27
  2. package/package.json +27 -27
package/oc-tui.js CHANGED
@@ -25,7 +25,7 @@ function loadNpmPlugins() {
25
25
  if (!existsSync(ocPath)) return [];
26
26
  try {
27
27
  var raw = readFileSync(ocPath, "utf-8");
28
- var stripped = raw.replace(/\/\/[^\n]*/g, "");
28
+ var stripped = raw.replace(/^\s*\/\/[^\n]*/gm, "");
29
29
  var oc = JSON.parse(stripped);
30
30
  var plugins = oc.plugin || [];
31
31
  return plugins
@@ -276,7 +276,7 @@ function buildPluginList() {
276
276
 
277
277
  function fetchPluginRemotes(pluginItems) {
278
278
  for (var p of pluginItems) {
279
- if (!p.installed) continue;
279
+ if (p.type === "npm" || !p.installed) continue;
280
280
  var dir = join(REPOS_DIR, p.folderName);
281
281
  gitText(["git", "fetch", "origin"], dir);
282
282
  for (var ref of ["origin/HEAD", "origin/main", "origin/master"]) {
@@ -376,8 +376,35 @@ function showCur() { process.stderr.write(E + "?25h"); }
376
376
  // ---------------------------------------------------------------------------
377
377
 
378
378
  var items = buildList();
379
- var pluginItems = buildPluginList();
380
- var npmPluginItems = loadNpmPlugins();
379
+
380
+ function buildCombinedPluginList() {
381
+ var git = buildPluginList();
382
+ var npm = loadNpmPlugins().map(function(np) {
383
+ return {
384
+ type: "npm",
385
+ name: np.name,
386
+ version: np.version,
387
+ raw: np.raw,
388
+ // filler fields so shared code doesn't crash
389
+ enabled: true,
390
+ autoUpdate: false,
391
+ installed: !!np.version,
392
+ deployed: !!np.version,
393
+ updateAvail: false,
394
+ localHead: "",
395
+ remoteHead: "",
396
+ latestTag: np.version || "",
397
+ subject: "npm plugin",
398
+ folderName: "",
399
+ url: "",
400
+ hasBuild: false,
401
+ pluginFile: ""
402
+ };
403
+ });
404
+ return git.concat(npm);
405
+ }
406
+
407
+ var pluginItems = buildCombinedPluginList();
381
408
  var cursor = 0;
382
409
  var pcursor = 0; // plugin page cursor
383
410
  var mode = "list"; // "list" | "actions" | "input" | "pactions"
@@ -662,6 +689,17 @@ function buildPluginItem(pushBody, i, pitem, nameW, cols, isSelected) {
662
689
  var bg = sel ? BG_SEL : "";
663
690
  var nameStyle = sel ? (BOLD + WHITE) : DIM;
664
691
 
692
+ // NPM plugins: simpler read-only row
693
+ if (pitem.type === "npm") {
694
+ var nvstr = pitem.version ? (GRAY + "v" + pitem.version + RST) : (GRAY + "not installed" + RST);
695
+ pushBody(" " + bg + arrow + nameStyle + pad(trunc(pitem.name, nameW), nameW) + RST + bg + " " + CYAN + "npm" + RST + " " + nvstr + RST, isSelected);
696
+ if (sel) {
697
+ var subInfo = GRAY + " managed via npm (opencode.json)" + RST;
698
+ pushBody(" " + subInfo, isSelected);
699
+ }
700
+ return;
701
+ }
702
+
665
703
  var statusParts = [];
666
704
  if (!pitem.enabled) {
667
705
  statusParts.push(RED + "disabled" + RST);
@@ -745,34 +783,33 @@ function buildPlugins(pushBody, pushFoot, cols, barW) {
745
783
 
746
784
  var autoCount = 0, manualCount = 0, updateCount = 0, disabledCount = 0;
747
785
  for (var p of pluginItems) {
786
+ if (p.type === "npm") continue;
748
787
  if (!p.enabled) disabledCount++;
749
788
  else if (p.autoUpdate) autoCount++; else manualCount++;
750
789
  if (p.updateAvail) updateCount++;
751
790
  }
752
791
 
792
+ var npmCount = pluginItems.filter(function(p) { return p.type === "npm"; }).length;
753
793
  pushBody(" " + MAGENTA + "#" + GRAY + " Plugins " +
754
794
  DIM + "(" + autoCount + " auto, " + manualCount + " manual" +
755
795
  (disabledCount > 0 ? ", " + RED + disabledCount + " disabled" + DIM : "") +
756
796
  (updateCount > 0 ? ", " + CYAN + updateCount + " updates" + DIM : "") +
757
- (npmPluginItems.length > 0 ? ", " + GRAY + npmPluginItems.length + " npm" + DIM : "") +
797
+ (npmCount > 0 ? ", " + GRAY + npmCount + " npm" + DIM : "") +
758
798
  ")" + RST, false);
759
799
 
760
800
  if (!pluginFetched) {
761
801
  pushBody(" " + GRAY + " Press " + RST + "F" + GRAY + " to check for updates" + RST, false);
762
802
  }
763
803
 
804
+ var lastWasGit = false;
764
805
  for (var i = 0; i < pluginItems.length; i++) {
765
- buildPluginItem(pushBody, i, pluginItems[i], nameW, cols, i === pcursor);
766
- }
767
-
768
- if (npmPluginItems.length > 0) {
769
- pushBody("", false);
770
- pushBody(" " + MAGENTA + "#" + GRAY + " npm plugins" + RST, false);
771
- for (var ni = 0; ni < npmPluginItems.length; ni++) {
772
- var np = npmPluginItems[ni];
773
- var nvstr = np.version ? (GRAY + "v" + np.version + RST) : (GRAY + "not installed" + RST);
774
- pushBody(" " + DIM + np.name + RST + " " + nvstr, false);
806
+ var pitem = pluginItems[i];
807
+ // Insert a section header when transitioning to npm plugins
808
+ if (pitem.type === "npm" && (i === 0 || pluginItems[i - 1].type !== "npm")) {
809
+ pushBody("", false);
810
+ pushBody(" " + MAGENTA + "#" + GRAY + " npm plugins" + RST, false);
775
811
  }
812
+ buildPluginItem(pushBody, i, pitem, nameW, cols, i === pcursor);
776
813
  }
777
814
 
778
815
  pushBody("", false);
@@ -823,7 +860,7 @@ function render() {
823
860
  pushHead("");
824
861
  pushHead(" " + BOLD + CYAN + " OpenCode" + RST + GRAY + " Launcher" + RST);
825
862
  pushHead(" " + GRAY + "-".repeat(barW) + RST);
826
- var showPluginsTab = pluginItems.length > 0 || npmPluginItems.length > 0;
863
+ var showPluginsTab = pluginItems.length > 0;
827
864
  var projTab = page === "projects" ? (BOLD + WHITE + BG_SEL + " Projects " + RST) : (GRAY + " Projects " + RST);
828
865
  var plugTab = showPluginsTab ? (page === "plugins" ? (BOLD + WHITE + BG_SEL + " Plugins " + RST) : (GRAY + " Plugins " + RST)) : "";
829
866
  pushHead(" " + projTab + (showPluginsTab ? " " + plugTab + " " + DIM + "<- ->" + RST : ""));
@@ -948,7 +985,8 @@ function handlePluginKey(key) {
948
985
  if (key === "up" || key === "w") { pcursor = Math.max(0, pcursor - 1); }
949
986
  else if (key === "down" || key === "s") { pcursor = Math.min(pluginItems.length - 1, pcursor + 1); }
950
987
  else if (key === "enter" || key === "space") {
951
- if (pluginItems.length > 0) { mode = "pactions"; pacursor = 0; }
988
+ if (pluginItems.length > 0 && pluginItems[pcursor].type !== "npm") { mode = "pactions"; pacursor = 0; }
989
+ else if (pluginItems.length > 0 && pluginItems[pcursor].type === "npm") { flash(pluginItems[pcursor].name + " is managed via npm"); }
952
990
  }
953
991
  else if (key === "f") {
954
992
  flash("Fetching remotes...");
@@ -960,7 +998,7 @@ function handlePluginKey(key) {
960
998
  flash(updateCount > 0 ? updateCount + " update(s) available" : "All plugins up to date");
961
999
  }
962
1000
  else if (key === "a") {
963
- var toUpdate = pluginItems.filter(function(p) { return p.updateAvail || !p.deployed; });
1001
+ var toUpdate = pluginItems.filter(function(p) { return p.type !== "npm" && (p.updateAvail || !p.deployed); });
964
1002
  if (toUpdate.length === 0) {
965
1003
  flash("All plugins are already up to date.");
966
1004
  } else {
@@ -971,31 +1009,31 @@ function handlePluginKey(key) {
971
1009
  var e = runPluginUpdate(pi);
972
1010
  if (e) errors.push(pi.name + ": " + e);
973
1011
  }
974
- pluginItems = buildPluginList();
1012
+ pluginItems = buildCombinedPluginList();
975
1013
  if (pcursor >= pluginItems.length) pcursor = Math.max(0, pluginItems.length - 1);
976
1014
  flash(errors.length > 0 ? errors.join("; ") : toUpdate.length + " plugin(s) updated. Restart OpenCode to apply.");
977
1015
  }
978
1016
  }
979
1017
  else if (key === "u") {
980
- if (pluginItems.length > 0) {
1018
+ if (pluginItems.length > 0 && pluginItems[pcursor].type !== "npm") {
981
1019
  var p = pluginItems[pcursor];
982
1020
  flash("Updating " + p.name + "...");
983
1021
  render();
984
1022
  var err = runPluginUpdate(p);
985
- pluginItems = buildPluginList();
1023
+ pluginItems = buildCombinedPluginList();
986
1024
  if (pcursor >= pluginItems.length) pcursor = Math.max(0, pluginItems.length - 1);
987
1025
  flash(err ? p.name + ": " + err : p.name + " updated. Restart OpenCode to apply.");
988
1026
  }
989
1027
  }
990
1028
  else if (key === "d") {
991
- if (pluginItems.length > 0) {
1029
+ if (pluginItems.length > 0 && pluginItems[pcursor].type !== "npm") {
992
1030
  var p = pluginItems[pcursor];
993
1031
  var plugins = loadPlugins();
994
1032
  var match = plugins.find(function(r) { return r.name === p.name; });
995
1033
  if (match) { match.enabled = false; savePlugins(plugins); }
996
1034
  var deployedPath = join(PLUGINS_DIR, p.pluginFile);
997
1035
  if (existsSync(deployedPath)) { try { unlinkSync(deployedPath); } catch {} }
998
- pluginItems = buildPluginList();
1036
+ pluginItems = buildCombinedPluginList();
999
1037
  if (pcursor >= pluginItems.length) pcursor = Math.max(0, pluginItems.length - 1);
1000
1038
  flash(p.name + " disabled. Restart OpenCode to unload.");
1001
1039
  }
@@ -1012,7 +1050,7 @@ function handlePluginKey(key) {
1012
1050
  flash("Updating " + pitem.name + "...");
1013
1051
  render();
1014
1052
  var err = runPluginUpdate(pitem);
1015
- pluginItems = buildPluginList();
1053
+ pluginItems = buildCombinedPluginList();
1016
1054
  if (pcursor >= pluginItems.length) pcursor = Math.max(0, pluginItems.length - 1);
1017
1055
  flash(err ? pitem.name + ": " + err : pitem.name + " updated. Restart OpenCode to apply.");
1018
1056
  mode = "list";
@@ -1032,7 +1070,7 @@ function handlePluginKey(key) {
1032
1070
  if (match) { match.enabled = false; savePlugins(plugins); }
1033
1071
  var deployedPath = join(PLUGINS_DIR, pitem.pluginFile);
1034
1072
  if (existsSync(deployedPath)) { try { unlinkSync(deployedPath); } catch {} }
1035
- pluginItems = buildPluginList();
1073
+ pluginItems = buildCombinedPluginList();
1036
1074
  if (pcursor >= pluginItems.length) pcursor = Math.max(0, pluginItems.length - 1);
1037
1075
  flash(pitem.name + " disabled. Restart OpenCode to unload.");
1038
1076
  mode = "list";
@@ -1041,7 +1079,7 @@ function handlePluginKey(key) {
1041
1079
  var plugins = loadPlugins();
1042
1080
  var match = plugins.find(function(r) { return r.name === pitem.name; });
1043
1081
  if (match) { delete match.enabled; savePlugins(plugins); }
1044
- pluginItems = buildPluginList();
1082
+ pluginItems = buildCombinedPluginList();
1045
1083
  if (pcursor >= pluginItems.length) pcursor = Math.max(0, pluginItems.length - 1);
1046
1084
  flash(pitem.name + " enabled. Use Update to deploy.");
1047
1085
  mode = "list";
@@ -1111,7 +1149,7 @@ function handlePluginKey(key) {
1111
1149
  err = "Build output not found";
1112
1150
  }
1113
1151
  }
1114
- pluginItems = buildPluginList();
1152
+ pluginItems = buildCombinedPluginList();
1115
1153
  if (err) flash("Error: " + err);
1116
1154
  else flash("Downgraded to " + citem.hash.substring(0,7));
1117
1155
  mode = "list";
package/package.json CHANGED
@@ -1,29 +1,29 @@
1
1
  {
2
- "name": "opencode-hub",
3
- "version": "1.0.12",
4
- "description": "TUI launcher for OpenCode - project switcher and plugin manager with oc command",
5
- "main": "plugin.js",
6
- "type": "module",
7
- "license": "MIT",
8
- "author": "intisy",
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/intisy/opencode-hub.git"
12
- },
13
- "homepage": "https://github.com/intisy/opencode-hub#readme",
14
- "keywords": [
15
- "opencode",
16
- "launcher",
17
- "tui",
18
- "project-switcher",
19
- "plugin"
20
- ],
21
- "engines": {
22
- "node": ">=20.0.0"
23
- },
24
- "files": [
25
- "plugin.js",
26
- "oc-tui.js",
27
- "README.md"
28
- ]
2
+ "name": "opencode-hub",
3
+ "version": "1.0.14",
4
+ "description": "TUI launcher for OpenCode - project switcher and plugin manager with oc command",
5
+ "main": "plugin.js",
6
+ "type": "module",
7
+ "license": "MIT",
8
+ "author": "intisy",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/intisy/opencode-hub.git"
12
+ },
13
+ "homepage": "https://github.com/intisy/opencode-hub#readme",
14
+ "keywords": [
15
+ "opencode",
16
+ "launcher",
17
+ "tui",
18
+ "project-switcher",
19
+ "plugin"
20
+ ],
21
+ "engines": {
22
+ "node": ">=20.0.0"
23
+ },
24
+ "files": [
25
+ "plugin.js",
26
+ "oc-tui.js",
27
+ "README.md"
28
+ ]
29
29
  }