plugin-updater 1.0.41 → 1.0.43
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 +19 -2
- package/dist/git.js +21 -0
- package/dist/index.js +34 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -130,8 +130,8 @@ async function setupEntry(updater, configDir, url, branch) {
|
|
|
130
130
|
}
|
|
131
131
|
async function main() {
|
|
132
132
|
const parsed = parseArgs(process.argv.slice(2));
|
|
133
|
-
if (!["init", "add", "run"].includes(parsed.command)) {
|
|
134
|
-
console.log("usage: plugin-updater <init|add|run> [git-urls...] [--app claude|opencode] [--branch name]");
|
|
133
|
+
if (!["init", "add", "run", "remove"].includes(parsed.command)) {
|
|
134
|
+
console.log("usage: plugin-updater <init|add|remove|run> [git-urls-or-names...] [--app claude|opencode] [--branch name]");
|
|
135
135
|
process.exit(parsed.command ? 1 : 0);
|
|
136
136
|
}
|
|
137
137
|
const app = detectApp(parsed.app);
|
|
@@ -159,6 +159,23 @@ async function main() {
|
|
|
159
159
|
await setupEntry(updater, configDir, url, parsed.branch);
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
|
+
else if (parsed.command === "remove") {
|
|
163
|
+
if (parsed.urls.length === 0)
|
|
164
|
+
throw new Error("remove requires at least one plugin name");
|
|
165
|
+
for (const arg of parsed.urls) {
|
|
166
|
+
const name = arg.replace(/\.git$/, "").split("/").pop() ?? arg;
|
|
167
|
+
removePluginEntry(configDir, name);
|
|
168
|
+
try {
|
|
169
|
+
fs.rmSync(path.join(configDir, "repos", name), { recursive: true, force: true });
|
|
170
|
+
}
|
|
171
|
+
catch { /* ignore */ }
|
|
172
|
+
try {
|
|
173
|
+
fs.rmSync(path.join(configDir, "plugin", `${name}.js`), { force: true });
|
|
174
|
+
}
|
|
175
|
+
catch { /* ignore */ }
|
|
176
|
+
console.log(`Removed ${name}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
162
179
|
else {
|
|
163
180
|
const entries = readJson(pluginsJsonPath(configDir)) ?? [];
|
|
164
181
|
await updater.earlyLaunch(configDir, entries);
|
package/dist/git.js
CHANGED
|
@@ -45,6 +45,27 @@ export function updatePlugin(pluginName, gitUrl, branch, commitHash, updateInter
|
|
|
45
45
|
const elapsed = Date.now() - lastCheck;
|
|
46
46
|
if (elapsed < intervalMs) {
|
|
47
47
|
writeLog(`Fast-path: ${pluginName} skipping update check (checked ${Math.floor(elapsed / 60_000)} min ago, interval ${updateInterval}h)`);
|
|
48
|
+
// even when skipping the network check, keep embedded submodules pinned to
|
|
49
|
+
// this checkout — a loader running against a stale core/core-auth is the
|
|
50
|
+
// top cause of "looks broken but it's just stale". Rebuild if they moved.
|
|
51
|
+
if (fs.existsSync(path.join(targetDir, ".gitmodules"))) {
|
|
52
|
+
let before = "";
|
|
53
|
+
try {
|
|
54
|
+
before = execSync("git submodule status --recursive", { cwd: targetDir }).toString();
|
|
55
|
+
}
|
|
56
|
+
catch { /* ignore */ }
|
|
57
|
+
executeGit("git submodule sync --recursive", targetDir);
|
|
58
|
+
executeGit("git submodule update --init --recursive", targetDir);
|
|
59
|
+
let after = "";
|
|
60
|
+
try {
|
|
61
|
+
after = execSync("git submodule status --recursive", { cwd: targetDir }).toString();
|
|
62
|
+
}
|
|
63
|
+
catch { /* ignore */ }
|
|
64
|
+
if (before !== after) {
|
|
65
|
+
writeLog(`Fast-path: ${pluginName} submodules were out of sync — resynced, forcing rebuild`);
|
|
66
|
+
return { success: true, changed: true };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
48
69
|
return { success: true, changed: false };
|
|
49
70
|
}
|
|
50
71
|
fs.writeFileSync(lastCheckFile, Date.now().toString());
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,38 @@ import { selfUpdate, updateNpmPlugin } from "./npm.js";
|
|
|
5
5
|
import { updatePlugin } from "./git.js";
|
|
6
6
|
import { deployToExecutionDir } from "./deploy.js";
|
|
7
7
|
import path from "path";
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
// remove repos/ clones and deployed plugin/ files for plugins no longer in
|
|
10
|
+
// plugins.json, so a removed/renamed plugin stops showing up
|
|
11
|
+
function pruneOrphans(configDir, plugins) {
|
|
12
|
+
const keep = new Set(plugins.map((p) => p.name));
|
|
13
|
+
try {
|
|
14
|
+
for (const dir of fs.readdirSync(path.join(configDir, "repos"))) {
|
|
15
|
+
if (!keep.has(dir)) {
|
|
16
|
+
try {
|
|
17
|
+
fs.rmSync(path.join(configDir, "repos", dir), { recursive: true, force: true });
|
|
18
|
+
writeLog(`Pruned orphaned repos/${dir}`);
|
|
19
|
+
}
|
|
20
|
+
catch { /* ignore */ }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch { /* no repos dir */ }
|
|
25
|
+
try {
|
|
26
|
+
for (const file of fs.readdirSync(path.join(configDir, "plugin"))) {
|
|
27
|
+
if (!file.endsWith(".js"))
|
|
28
|
+
continue;
|
|
29
|
+
if (!keep.has(file.slice(0, -3))) {
|
|
30
|
+
try {
|
|
31
|
+
fs.unlinkSync(path.join(configDir, "plugin", file));
|
|
32
|
+
writeLog(`Pruned orphaned plugin/${file}`);
|
|
33
|
+
}
|
|
34
|
+
catch { /* ignore */ }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch { /* no plugin dir */ }
|
|
39
|
+
}
|
|
8
40
|
// re-exported public API (consumers import these from "plugin-updater")
|
|
9
41
|
export { getNpmPlugins, installNpmPlugin, uninstallNpmPlugin, updateNpmPlugin } from "./npm.js";
|
|
10
42
|
export { getPlugins, getPluginsPath } from "./config.js";
|
|
@@ -70,6 +102,8 @@ export async function earlyLaunch(configDir, plugins) {
|
|
|
70
102
|
writeLog(`Failed to process ${plugin.name}: ${e.message}`, true);
|
|
71
103
|
}
|
|
72
104
|
}
|
|
105
|
+
if (plugins.length > 0)
|
|
106
|
+
pruneOrphans(configDir, plugins);
|
|
73
107
|
}
|
|
74
108
|
export async function activate(opencodeHookInput) {
|
|
75
109
|
// module load below calls activate() with no argument; opencode passes a
|