plugin-updater 1.0.0

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 (3) hide show
  1. package/README.md +56 -0
  2. package/index.js +92 -0
  3. package/package.json +13 -0
package/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # plugin-updater
2
+
3
+ Plugin lifecycle manager for OpenCode and Claude Code launchers. Handles install, update, rebuild, downgrade, and uninstall operations for all plugins.
4
+
5
+ ## Under-the-Hood Architecture
6
+
7
+ ```mermaid
8
+ flowchart TD
9
+ %% Triggers
10
+ subgraph Execution_Triggers [Execution Triggers]
11
+ CLI_BOOT[CLI Startup (claude/oc)]
12
+ TUI_MENU[Launcher TUI Actions]
13
+
14
+ CLI_BOOT -->|Auto-runs hook on start| UPDATER_CORE
15
+ TUI_MENU -->|Manual rebuild/downgrade/uninstall| UPDATER_CORE
16
+ end
17
+
18
+ %% Core Logic
19
+ subgraph Plugin_Updater [Updater Core Logic]
20
+ UPDATER_CORE[Updater Engine]
21
+ API_LAYER[global.OpenCodeAPI Interop]
22
+ GIT_MGR[Git Operations Manager]
23
+ DEPLOYER[Plugin Deployer]
24
+
25
+ UPDATER_CORE <-->|Requests repo paths| API_LAYER
26
+ UPDATER_CORE -->|Trigger sync| GIT_MGR
27
+ UPDATER_CORE -->|Trigger deploy| DEPLOYER
28
+ end
29
+
30
+ %% External & Storage
31
+ subgraph Storage_and_Network [Storage & External]
32
+ GH_REPOS[GitHub (intisy/plugin-*)]
33
+ LOCAL_WORKSPACE[(.config/github/repos/intisy/)]
34
+ CC_PLUGINS[(.claude/plugin/)]
35
+ OC_PLUGINS[(.config/opencode/plugin/)]
36
+
37
+ GIT_MGR <-->|git clone/pull| GH_REPOS
38
+ GIT_MGR -->|Updates source| LOCAL_WORKSPACE
39
+ DEPLOYER -->|Copies compiled output| CC_PLUGINS
40
+ DEPLOYER -->|Copies compiled output| OC_PLUGINS
41
+ end
42
+ ```
43
+
44
+ ## API
45
+
46
+ | Method | Description |
47
+ |---|---|
48
+ | `rebuild(pluginItem)` | Pull latest and redeploy |
49
+ | `downgrade(pluginItem, commitHash)` | Checkout specific commit |
50
+ | `disable(pluginItem)` | Cleanup on disable |
51
+ | `uninstall(pluginItem)` | Remove repo and deployed files |
52
+ | `registerTests(testApi)` | Register sync verification tests |
53
+
54
+ ## License
55
+
56
+ MIT
package/index.js ADDED
@@ -0,0 +1,92 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { execSync } = require('child_process');
4
+
5
+ const REPOS_DIR = path.join(require('os').homedir(), '.config', 'github');
6
+
7
+ function executeGit(cmd, dir) {
8
+ try {
9
+ return execSync(cmd, { cwd: dir, timeout: 60000, stdio: "ignore" });
10
+ } catch (e) {
11
+ console.error(`[Updater] Git command failed: ${cmd} in ${dir}`);
12
+ return false;
13
+ }
14
+ }
15
+
16
+ module.exports = {
17
+ name: "plugin-updater",
18
+
19
+ /**
20
+ * Called by the launcher (OpenCode/Claude Code) to sync a specific plugin
21
+ */
22
+ updatePlugin: function(pluginName, gitUrl, branch = null, commitHash = null) {
23
+ const targetDir = path.join(REPOS_DIR, pluginName);
24
+
25
+ // 1. Ensure directory exists and clone or pull
26
+ if (!fs.existsSync(targetDir)) {
27
+ if (!fs.existsSync(REPOS_DIR)) fs.mkdirSync(REPOS_DIR, { recursive: true });
28
+ const branchFlag = branch ? `--branch ${branch}` : "";
29
+ executeGit(`git clone --recurse-submodules ${branchFlag} ${gitUrl} ${pluginName}`, REPOS_DIR);
30
+ } else {
31
+ executeGit("git fetch origin", targetDir);
32
+ if (commitHash) {
33
+ executeGit(`git checkout ${commitHash}`, targetDir);
34
+ } else if (branch) {
35
+ executeGit(`git checkout ${branch}`, targetDir);
36
+ executeGit(`git pull --ff-only origin ${branch}`, targetDir);
37
+ } else {
38
+ executeGit("git checkout main || git checkout master", targetDir);
39
+ executeGit("git pull --ff-only", targetDir);
40
+ }
41
+ executeGit("git submodule update --init --recursive", targetDir);
42
+ }
43
+
44
+ return true;
45
+ },
46
+
47
+ /**
48
+ * Called to deploy the compiled output to the execution directory
49
+ */
50
+ deployToExecutionDir: function(pluginName, executionPath) {
51
+ const sourceDir = path.join(REPOS_DIR, pluginName);
52
+ if (!fs.existsSync(sourceDir)) return false;
53
+
54
+ // Build if package.json exists
55
+ if (fs.existsSync(path.join(sourceDir, "package.json"))) {
56
+ try {
57
+ execSync("npm install", { cwd: sourceDir, stdio: "ignore" });
58
+ execSync("npm run build", { cwd: sourceDir, stdio: "ignore" });
59
+ } catch (e) {
60
+ // Fallback or ignore if no build step
61
+ }
62
+ }
63
+
64
+ // Determine deployment source (prefer dist, fallback to root)
65
+ const distPath = path.join(sourceDir, "dist");
66
+ const deploySource = fs.existsSync(distPath) ? distPath : sourceDir;
67
+
68
+ // Copy to execution path
69
+ if (!fs.existsSync(executionPath)) {
70
+ fs.mkdirSync(executionPath, { recursive: true });
71
+ }
72
+
73
+ try {
74
+ // Platform agnostic copy (using Node fs)
75
+ fs.cpSync(deploySource, executionPath, { recursive: true, force: true });
76
+ return true;
77
+ } catch (e) {
78
+ console.error(`[Updater] Deploy failed: ${e.message}`);
79
+ return false;
80
+ }
81
+ },
82
+
83
+ /**
84
+ * Specific logic to install/update the launcher itself
85
+ */
86
+ installLauncher: function() {
87
+ // Logic to install opencode-hub / claude-hub if they are missing
88
+ this.updatePlugin("core-hub", "https://github.com/intisy/core-hub.git");
89
+ this.updatePlugin("opencode-hub", "https://github.com/intisy/opencode-hub.git");
90
+ this.updatePlugin("claude-hub", "https://github.com/intisy/claude-hub.git");
91
+ }
92
+ };
package/package.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "plugin-updater",
3
+ "version": "1.0.0",
4
+ "description": "Plugin lifecycle manager for OpenCode and Claude Code launchers",
5
+ "main": "index.js",
6
+ "license": "MIT",
7
+ "author": "intisy",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/intisy/plugin-updater.git"
11
+ },
12
+ "keywords": ["opencode", "claude", "plugin", "updater", "lifecycle"]
13
+ }