plugins 1.2.3 → 1.2.5

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/dist/index.js +120 -31
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -353,7 +353,7 @@ function detectTarget(def) {
353
353
  case "claude-code":
354
354
  return detectBinary("claude");
355
355
  case "cursor":
356
- return detectBinary("cursor") && detectBinary("claude");
356
+ return detectBinary("cursor");
357
357
  default:
358
358
  return false;
359
359
  }
@@ -441,6 +441,13 @@ function barLine(content = "") {
441
441
  function barEmpty() {
442
442
  console.log(`${c.gray(S.bar)}`);
443
443
  }
444
+ var _debug = false;
445
+ function setDebug(enabled) {
446
+ _debug = enabled;
447
+ }
448
+ function barDebug(content = "") {
449
+ if (_debug) barLine(content);
450
+ }
444
451
  function step(content) {
445
452
  console.log(`${c.gray(S.step)} ${content}`);
446
453
  }
@@ -663,29 +670,18 @@ function banner() {
663
670
  }
664
671
 
665
672
  // lib/install.ts
666
- function installerKey(targetId) {
667
- switch (targetId) {
668
- case "claude-code":
669
- case "cursor":
670
- return "claude-code";
671
- default:
672
- return targetId;
673
- }
674
- }
675
- var completedInstallers = /* @__PURE__ */ new Set();
673
+ var cachePopulated = false;
676
674
  async function installPlugins(plugins, target, scope, repoPath, source) {
677
- const key = installerKey(target.id);
678
- if (completedInstallers.has(key)) {
679
- return;
680
- }
681
- switch (key) {
675
+ switch (target.id) {
682
676
  case "claude-code":
683
677
  await installToClaudeCode(plugins, scope, repoPath, source);
684
678
  break;
679
+ case "cursor":
680
+ await installToCursor(plugins, scope, repoPath, source);
681
+ break;
685
682
  default:
686
683
  throw new Error(`Unsupported target: ${target.id}`);
687
684
  }
688
- completedInstallers.add(key);
689
685
  }
690
686
  async function installToClaudeCode(plugins, scope, repoPath, source) {
691
687
  const marketplaceName = plugins[0]?.marketplace ?? deriveMarketplaceName(source);
@@ -695,19 +691,19 @@ async function installToClaudeCode(plugins, scope, repoPath, source) {
695
691
  const marketplaceSource = isAnthropicSource(source) ? normalizeGitUrl(source) : repoPath;
696
692
  const claudePath = findClaude();
697
693
  step("Adding marketplace");
698
- barLine(c.dim(`Binary: ${claudePath}`));
694
+ barDebug(c.dim(`Binary: ${claudePath}`));
699
695
  try {
700
696
  const version = execSync2(`${claudePath} --version`, { encoding: "utf-8", stdio: "pipe" }).trim();
701
- barLine(c.dim(`Version: ${version}`));
697
+ barDebug(c.dim(`Version: ${version}`));
702
698
  } catch {
703
- barLine(c.dim(`Warning: could not get claude version`));
699
+ barDebug(c.dim(`Warning: could not get claude version`));
704
700
  }
705
701
  try {
706
702
  const result = execSync2(`${claudePath} plugin marketplace add ${marketplaceSource}`, {
707
703
  encoding: "utf-8",
708
704
  stdio: "pipe"
709
705
  });
710
- if (result.trim()) barLine(c.dim(result.trim()));
706
+ if (result.trim()) barDebug(c.dim(result.trim()));
711
707
  stepDone("Marketplace added");
712
708
  } catch (err) {
713
709
  const stderr = err.stderr?.toString().trim() ?? "";
@@ -747,6 +743,84 @@ async function installToClaudeCode(plugins, scope, repoPath, source) {
747
743
  }
748
744
  }
749
745
  }
746
+ cachePopulated = true;
747
+ }
748
+ async function installToCursor(plugins, scope, repoPath, source) {
749
+ if (cachePopulated) return;
750
+ const claudePath = findClaudeOrNull();
751
+ if (claudePath) {
752
+ await installToClaudeCode(plugins, scope, repoPath, source);
753
+ return;
754
+ }
755
+ await installToPluginCache(plugins, scope, repoPath, source);
756
+ }
757
+ async function installToPluginCache(plugins, scope, repoPath, source) {
758
+ const marketplaceName = plugins[0]?.marketplace ?? deriveMarketplaceName(source);
759
+ const home = homedir2();
760
+ const pluginsDir = join3(home, ".claude", "plugins");
761
+ const cacheDir = join3(pluginsDir, "cache");
762
+ step("Preparing plugins for Cursor...");
763
+ barEmpty();
764
+ await prepareForClaudeCode(plugins, repoPath, marketplaceName);
765
+ step("Registering marketplace");
766
+ await mkdir(pluginsDir, { recursive: true });
767
+ const knownPath = join3(pluginsDir, "known_marketplaces.json");
768
+ let knownMarketplaces = {};
769
+ if (existsSync2(knownPath)) {
770
+ try {
771
+ knownMarketplaces = JSON.parse(await readFile2(knownPath, "utf-8"));
772
+ } catch {
773
+ }
774
+ }
775
+ if (knownMarketplaces[marketplaceName]) {
776
+ stepDone(`Marketplace ${c.dim("'" + marketplaceName + "'")} already registered`);
777
+ } else {
778
+ knownMarketplaces[marketplaceName] = {
779
+ source: { source: "directory", path: repoPath },
780
+ installLocation: repoPath,
781
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
782
+ };
783
+ await writeFile(knownPath, JSON.stringify(knownMarketplaces, null, 2));
784
+ stepDone("Marketplace registered");
785
+ }
786
+ barEmpty();
787
+ const installedPath = join3(pluginsDir, "installed_plugins.json");
788
+ let installedData = { version: 2, plugins: {} };
789
+ if (existsSync2(installedPath)) {
790
+ try {
791
+ installedData = JSON.parse(await readFile2(installedPath, "utf-8"));
792
+ } catch {
793
+ }
794
+ }
795
+ let gitSha;
796
+ try {
797
+ gitSha = execSync2("git rev-parse HEAD", { cwd: repoPath, encoding: "utf-8", stdio: "pipe" }).trim();
798
+ } catch {
799
+ }
800
+ for (const plugin of plugins) {
801
+ const pluginRef = `${plugin.name}@${marketplaceName}`;
802
+ const version = plugin.version ?? "0.0.0";
803
+ step(`Installing ${c.bold(pluginRef)}...`);
804
+ const cacheDest = join3(cacheDir, marketplaceName, plugin.name, version);
805
+ await mkdir(cacheDest, { recursive: true });
806
+ await cp(plugin.path, cacheDest, { recursive: true });
807
+ barDebug(c.dim(`Cached to ${cacheDest}`));
808
+ const pluginKey = `${plugin.name}@${marketplaceName}`;
809
+ const now = (/* @__PURE__ */ new Date()).toISOString();
810
+ const entry = {
811
+ scope,
812
+ installPath: cacheDest,
813
+ version,
814
+ installedAt: now,
815
+ lastUpdated: now
816
+ };
817
+ if (gitSha) entry.gitCommitSha = gitSha;
818
+ installedData.plugins[pluginKey] = [entry];
819
+ stepDone(`Installed ${c.cyan(pluginRef)}`);
820
+ }
821
+ await writeFile(installedPath, JSON.stringify(installedData, null, 2));
822
+ barDebug(c.dim("Updated installed_plugins.json"));
823
+ cachePopulated = true;
750
824
  }
751
825
  async function prepareForClaudeCode(plugins, repoPath, marketplaceName) {
752
826
  const claudePluginDir = join3(repoPath, ".claude-plugin");
@@ -773,12 +847,12 @@ async function prepareForClaudeCode(plugins, repoPath, marketplaceName) {
773
847
  join3(claudePluginDir, "marketplace.json"),
774
848
  JSON.stringify(marketplaceJson, null, 2)
775
849
  );
776
- barLine(c.dim("Generated .claude-plugin/marketplace.json"));
850
+ barDebug(c.dim("Generated .claude-plugin/marketplace.json"));
777
851
  for (const plugin of plugins) {
778
852
  await preparePluginDirForVendor(plugin, ".claude-plugin", "CLAUDE_PLUGIN_ROOT");
779
853
  }
780
854
  }
781
- function findClaude() {
855
+ function findClaudeOrNull() {
782
856
  try {
783
857
  const path = execSync2("which claude", { encoding: "utf-8", stdio: "pipe" }).trim();
784
858
  if (path) return path;
@@ -793,7 +867,10 @@ function findClaude() {
793
867
  for (const candidate of candidates) {
794
868
  if (existsSync2(candidate)) return candidate;
795
869
  }
796
- return "claude";
870
+ return null;
871
+ }
872
+ function findClaude() {
873
+ return findClaudeOrNull() ?? "claude";
797
874
  }
798
875
  async function preparePluginDirForVendor(plugin, vendorDir, envVar) {
799
876
  const pluginPath = plugin.path;
@@ -803,7 +880,7 @@ async function preparePluginDirForVendor(plugin, vendorDir, envVar) {
803
880
  const hasVendorPlugin = existsSync2(join3(vendorPluginDir, "plugin.json"));
804
881
  if (hasOpenPlugin && !hasVendorPlugin) {
805
882
  await cp(openPluginDir, vendorPluginDir, { recursive: true });
806
- barLine(c.dim(`${plugin.name}: translated .plugin/ \u2192 ${vendorDir}/`));
883
+ barDebug(c.dim(`${plugin.name}: translated .plugin/ \u2192 ${vendorDir}/`));
807
884
  }
808
885
  if (!hasOpenPlugin && !hasVendorPlugin) {
809
886
  await mkdir(vendorPluginDir, { recursive: true });
@@ -819,7 +896,7 @@ async function preparePluginDirForVendor(plugin, vendorDir, envVar) {
819
896
  2
820
897
  )
821
898
  );
822
- barLine(c.dim(`${plugin.name}: generated ${vendorDir}/plugin.json`));
899
+ barDebug(c.dim(`${plugin.name}: generated ${vendorDir}/plugin.json`));
823
900
  }
824
901
  await translateEnvVars(pluginPath, plugin.name, envVar);
825
902
  }
@@ -848,7 +925,7 @@ async function translateEnvVars(pluginPath, pluginName, envVar) {
848
925
  }
849
926
  if (changed) {
850
927
  await writeFile(filePath, content);
851
- barLine(
928
+ barDebug(
852
929
  c.dim(`${pluginName}: translated plugin root \u2192 \${${envVar}} in ${filePath.split("/").pop()}`)
853
930
  );
854
931
  }
@@ -935,12 +1012,14 @@ var { values, positionals } = parseArgs({
935
1012
  target: { type: "string", short: "t" },
936
1013
  scope: { type: "string", short: "s", default: "user" },
937
1014
  yes: { type: "boolean", short: "y" },
938
- remote: { type: "boolean" }
1015
+ remote: { type: "boolean" },
1016
+ debug: { type: "boolean" }
939
1017
  },
940
1018
  allowPositionals: true,
941
1019
  strict: true
942
1020
  });
943
1021
  var [command, ...rest] = positionals;
1022
+ if (values.debug) setDebug(true);
944
1023
  if (values.help || !command) {
945
1024
  printUsage();
946
1025
  process.exit(0);
@@ -973,6 +1052,7 @@ ${c.dim("Options:")}
973
1052
  ${c.yellow("-s, --scope")} <scope> Install scope: user, project, local. Default: user
974
1053
  ${c.yellow("-y, --yes")} Skip confirmation prompts
975
1054
  ${c.yellow("--remote")} Include remote-source plugins in output
1055
+ ${c.yellow("--debug")} Show verbose installation output
976
1056
  ${c.yellow("-h, --help")} Show this help
977
1057
  `);
978
1058
  }
@@ -1070,11 +1150,16 @@ async function cmdInstall(source, opts) {
1070
1150
  footer();
1071
1151
  process.exit(1);
1072
1152
  }
1153
+ if (!found.detected) {
1154
+ barEmpty();
1155
+ barLine(c.yellow(`Warning: ${found.name} was not detected on this system.`));
1156
+ }
1073
1157
  installTargets = [found];
1074
1158
  } else if (detectedTargets.length === 0) {
1075
1159
  barEmpty();
1076
1160
  stepError("No supported targets detected.");
1077
- barLine(c.dim("Use --target to specify one."));
1161
+ barLine(c.dim("Neither 'claude' nor 'cursor' binaries were found on PATH."));
1162
+ barLine(c.dim("Use --target to specify one manually."));
1078
1163
  footer();
1079
1164
  process.exit(1);
1080
1165
  } else {
@@ -1264,11 +1349,15 @@ function resolveSource(source) {
1264
1349
  function readLine(prompt) {
1265
1350
  const rl = createInterface({ input: process.stdin, output: process.stdout });
1266
1351
  return new Promise((resolve2) => {
1352
+ let answered = false;
1267
1353
  rl.on("close", () => {
1268
- process.stdout.write("\n");
1269
- process.exit(0);
1354
+ if (!answered) {
1355
+ process.stdout.write("\n");
1356
+ process.exit(0);
1357
+ }
1270
1358
  });
1271
1359
  rl.question(prompt, (answer) => {
1360
+ answered = true;
1272
1361
  rl.close();
1273
1362
  if (!process.stdin.isTTY) process.stdout.write("\n");
1274
1363
  resolve2(answer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plugins",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "description": "Install open-plugin format plugins into agent tools",
5
5
  "type": "module",
6
6
  "bin": {