plugin-updater 1.0.33 → 1.0.35

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.
package/dist/cli.js CHANGED
@@ -16,19 +16,31 @@ function parseArgs(argv) {
16
16
  }
17
17
  return parsed;
18
18
  }
19
+ function binaryExists(name) {
20
+ try {
21
+ const probe = process.platform === "win32" ? `where ${name}` : `command -v ${name}`;
22
+ require("child_process").execSync(probe, { stdio: "ignore" });
23
+ return true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
19
29
  function detectApp(explicit) {
20
30
  if (explicit === "claude" || explicit === "opencode")
21
31
  return explicit;
22
32
  if (explicit)
23
33
  throw new Error(`Unknown app "${explicit}" - use claude or opencode`);
24
- const hasClaude = fs.existsSync(path.join(os.homedir(), ".claude"));
25
- const hasOpencode = fs.existsSync(path.join(os.homedir(), ".opencode"))
34
+ const hasClaudeDir = fs.existsSync(path.join(os.homedir(), ".claude"));
35
+ const hasOpencodeDir = fs.existsSync(path.join(os.homedir(), ".opencode"))
26
36
  || fs.existsSync(path.join(os.homedir(), ".config", "opencode"));
27
- if (hasClaude && !hasOpencode)
28
- return "claude";
29
- if (hasOpencode && !hasClaude)
30
- return "opencode";
31
- throw new Error("Cannot detect the app automatically - pass --app claude or --app opencode");
37
+ if (hasClaudeDir !== hasOpencodeDir)
38
+ return hasClaudeDir ? "claude" : "opencode";
39
+ const hasClaudeBin = binaryExists("claude");
40
+ const hasOpencodeBin = binaryExists("opencode");
41
+ if (hasClaudeBin !== hasOpencodeBin)
42
+ return hasClaudeBin ? "claude" : "opencode";
43
+ throw new Error("Both apps (or neither) found - pass --app claude or --app opencode");
32
44
  }
33
45
  function getConfigDir(app) {
34
46
  const home = os.homedir();
@@ -59,8 +71,9 @@ function registerClaudeHook(configDir) {
59
71
  const settings = (fs.existsSync(settingsPath) ? readJson(settingsPath) : {}) ?? {};
60
72
  const hooks = (settings.hooks ?? {});
61
73
  const sessionStart = (hooks.SessionStart ?? []);
62
- if (!JSON.stringify(sessionStart).includes("plugin-updater run")) {
63
- sessionStart.push({ hooks: [{ type: "command", command: "npx -y plugin-updater run --app claude" }] });
74
+ if (!JSON.stringify(sessionStart).includes("plugin-updater")) {
75
+ // @latest so npx re-resolves the tag instead of pinning its first cached copy
76
+ sessionStart.push({ hooks: [{ type: "command", command: "npx -y plugin-updater@latest run --app claude" }] });
64
77
  }
65
78
  hooks.SessionStart = sessionStart;
66
79
  settings.hooks = hooks;
@@ -99,6 +112,22 @@ function addPluginEntry(configDir, url, branch) {
99
112
  }
100
113
  return { name, url: cleanUrl, branch };
101
114
  }
115
+ function removePluginEntry(configDir, name) {
116
+ const file = pluginsJsonPath(configDir);
117
+ const entries = readJson(file) ?? [];
118
+ fs.writeFileSync(file, JSON.stringify(entries.filter((e) => e.name !== name), null, 2), "utf8");
119
+ }
120
+ async function setupEntry(updater, configDir, url, branch) {
121
+ const entry = addPluginEntry(configDir, url, branch);
122
+ console.log(`Setting up ${entry.name}...`);
123
+ try {
124
+ await updater.updatePluginPublic(entry.name, entry.url, entry.branch);
125
+ }
126
+ catch (e) {
127
+ removePluginEntry(configDir, entry.name);
128
+ throw e;
129
+ }
130
+ }
102
131
  async function main() {
103
132
  const parsed = parseArgs(process.argv.slice(2));
104
133
  if (!["init", "add", "run"].includes(parsed.command)) {
@@ -119,9 +148,7 @@ async function main() {
119
148
  else
120
149
  registerOpencodePlugin(configDir);
121
150
  for (const url of parsed.urls) {
122
- const entry = addPluginEntry(configDir, url, parsed.branch);
123
- console.log(`Setting up ${entry.name}...`);
124
- await updater.updatePluginPublic(entry.name, entry.url, entry.branch);
151
+ await setupEntry(updater, configDir, url, parsed.branch);
125
152
  }
126
153
  console.log("Init complete.");
127
154
  }
@@ -129,9 +156,7 @@ async function main() {
129
156
  if (parsed.urls.length === 0)
130
157
  throw new Error("add requires at least one git url");
131
158
  for (const url of parsed.urls) {
132
- const entry = addPluginEntry(configDir, url, parsed.branch);
133
- console.log(`Setting up ${entry.name}...`);
134
- await updater.updatePluginPublic(entry.name, entry.url, entry.branch);
159
+ await setupEntry(updater, configDir, url, parsed.branch);
135
160
  }
136
161
  }
137
162
  else {
package/dist/index.js CHANGED
@@ -243,7 +243,9 @@ function updatePlugin(pluginName, gitUrl, branch, commitHash, updateInterval = 1
243
243
  if (!fs.existsSync(reposDir))
244
244
  fs.mkdirSync(reposDir, { recursive: true });
245
245
  const branchFlag = branch ? `--branch ${branch}` : "";
246
- executeGit(`git clone --recurse-submodules ${branchFlag} ${gitUrl} ${pluginName}`, reposDir);
246
+ const cloned = executeGit(`git clone --recurse-submodules ${branchFlag} ${gitUrl} ${pluginName}`, reposDir);
247
+ if (!cloned)
248
+ return { success: false, changed: false };
247
249
  fs.writeFileSync(lastCheckFile, Date.now().toString());
248
250
  didChange = true;
249
251
  }
@@ -481,6 +483,8 @@ export async function updatePluginPublic(pluginName, gitUrl, branch, commitHash)
481
483
  const configDir = getAppConfigDir(getAppName());
482
484
  // interval 0: an explicit update request must never fast-path-skip
483
485
  const result = updatePlugin(pluginName, gitUrl, branch, commitHash ?? null, 0);
486
+ if (!result.success)
487
+ throw new Error(`could not set up ${pluginName} - see the updater log`);
484
488
  await deployToExecutionDir(pluginName, path.join(configDir, "plugin"), result.changed, configDir);
485
489
  }
486
490
  export async function earlyLaunch(configDir, plugins) {
@@ -526,6 +530,10 @@ export async function earlyLaunch(configDir, plugins) {
526
530
  writeLog(`Processing earlyLaunch for ${plugin.name}`);
527
531
  try {
528
532
  const updateResult = updatePlugin(plugin.name, plugin.url, plugin.branch, null, plugin.updateInterval ?? 1);
533
+ if (!updateResult.success) {
534
+ writeLog(`Skipping deploy for ${plugin.name}: update failed`, true);
535
+ continue;
536
+ }
529
537
  await deployToExecutionDir(plugin.name, path.join(configDir, "plugin"), updateResult.changed, configDir);
530
538
  }
531
539
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plugin-updater",
3
- "version": "1.0.33",
3
+ "version": "1.0.35",
4
4
  "description": "Plugin lifecycle manager for OpenCode and Claude Code launchers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",