@ztffn/presentation-generator-plugin 1.0.3 → 1.0.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.
- package/bin/index.js +177 -75
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -1,144 +1,237 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const https = require("https");
|
|
4
|
+
const { execSync } = require("child_process");
|
|
4
5
|
const fs = require("fs");
|
|
5
6
|
const path = require("path");
|
|
6
7
|
const os = require("os");
|
|
7
8
|
|
|
8
|
-
const
|
|
9
|
-
"https://github.com/ztffn/presentation-generator-plugin.git";
|
|
9
|
+
const NPM_PACKAGE = "@ztffn/presentation-generator-plugin";
|
|
10
10
|
const PLUGIN_NAME = "presentation-generator";
|
|
11
11
|
const INSTALL_DIR = path.join(os.homedir(), ".claude", "plugins", PLUGIN_NAME);
|
|
12
12
|
const CURRENT_VERSION = require("../package.json").version;
|
|
13
13
|
|
|
14
14
|
const command = process.argv[2] || "help";
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
return execSync(cmd, { stdio: "inherit", ...opts });
|
|
18
|
-
}
|
|
16
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
19
17
|
|
|
20
|
-
function
|
|
18
|
+
function getInstalledVersion() {
|
|
19
|
+
const pkgPath = path.join(INSTALL_DIR, "package.json");
|
|
20
|
+
if (!fs.existsSync(pkgPath)) return null;
|
|
21
21
|
try {
|
|
22
|
-
return
|
|
22
|
+
return JSON.parse(fs.readFileSync(pkgPath, "utf8")).version;
|
|
23
23
|
} catch {
|
|
24
24
|
return null;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
function fetchJson(url) {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
https
|
|
31
|
+
.get(url, { headers: { Accept: "application/json" } }, (res) => {
|
|
32
|
+
let data = "";
|
|
33
|
+
res.on("data", (chunk) => (data += chunk));
|
|
34
|
+
res.on("end", () => {
|
|
35
|
+
try {
|
|
36
|
+
resolve(JSON.parse(data));
|
|
37
|
+
} catch (e) {
|
|
38
|
+
reject(e);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
})
|
|
42
|
+
.on("error", reject);
|
|
43
|
+
});
|
|
35
44
|
}
|
|
36
45
|
|
|
37
|
-
function
|
|
38
|
-
|
|
39
|
-
|
|
46
|
+
function downloadFile(url, dest) {
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
const follow = (u) => {
|
|
49
|
+
https
|
|
50
|
+
.get(u, (res) => {
|
|
51
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
52
|
+
follow(res.headers.location);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const file = fs.createWriteStream(dest);
|
|
56
|
+
res.pipe(file);
|
|
57
|
+
file.on("finish", () => file.close(resolve));
|
|
58
|
+
file.on("error", reject);
|
|
59
|
+
})
|
|
60
|
+
.on("error", reject);
|
|
61
|
+
};
|
|
62
|
+
follow(url);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function getLatestNpmMeta() {
|
|
40
67
|
try {
|
|
41
|
-
|
|
68
|
+
const data = await fetchJson(
|
|
69
|
+
`https://registry.npmjs.org/${NPM_PACKAGE}/latest`
|
|
70
|
+
);
|
|
71
|
+
if (!data.version || !data.dist?.tarball) return null;
|
|
72
|
+
return { version: data.version, tarball: data.dist.tarball };
|
|
42
73
|
} catch {
|
|
43
74
|
return null;
|
|
44
75
|
}
|
|
45
76
|
}
|
|
46
77
|
|
|
47
|
-
function
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
78
|
+
async function downloadAndExtract(version, tarballUrl) {
|
|
79
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "claude-plugin-"));
|
|
80
|
+
const tarball = path.join(tmpDir, "plugin.tgz");
|
|
81
|
+
|
|
82
|
+
console.log(`Downloading v${version} from npm...`);
|
|
83
|
+
await downloadFile(tarballUrl, tarball);
|
|
84
|
+
|
|
85
|
+
console.log("Extracting...");
|
|
86
|
+
execSync(`tar -xzf "${tarball}" -C "${tmpDir}"`);
|
|
87
|
+
|
|
88
|
+
// npm tarballs always extract to a "package/" subdirectory
|
|
89
|
+
const extracted = path.join(tmpDir, "package");
|
|
90
|
+
if (!fs.existsSync(extracted)) {
|
|
91
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
92
|
+
throw new Error("Extraction failed: no package/ directory in tarball");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (fs.existsSync(INSTALL_DIR)) {
|
|
96
|
+
fs.rmSync(INSTALL_DIR, { recursive: true, force: true });
|
|
97
|
+
}
|
|
98
|
+
fs.mkdirSync(path.dirname(INSTALL_DIR), { recursive: true });
|
|
99
|
+
fs.renameSync(extracted, INSTALL_DIR);
|
|
100
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
52
101
|
}
|
|
53
102
|
|
|
54
103
|
function registerPlugin() {
|
|
55
104
|
console.log("\nRegistering plugin with Claude Code...");
|
|
56
105
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
106
|
+
// Prefer project-level settings if .claude/ exists in cwd, else user-level
|
|
107
|
+
const projectDir = path.join(process.cwd(), ".claude");
|
|
108
|
+
const settingsPath = fs.existsSync(projectDir)
|
|
109
|
+
? path.join(projectDir, "settings.json")
|
|
110
|
+
: path.join(os.homedir(), ".claude", "settings.json");
|
|
62
111
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
112
|
+
try {
|
|
113
|
+
let settings = {};
|
|
114
|
+
if (fs.existsSync(settingsPath)) {
|
|
115
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (!Array.isArray(settings.enabledPlugins)) {
|
|
119
|
+
settings.enabledPlugins = [];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!settings.enabledPlugins.includes(INSTALL_DIR)) {
|
|
123
|
+
settings.enabledPlugins.push(INSTALL_DIR);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
127
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
128
|
+
|
|
129
|
+
const label = settingsPath.startsWith(process.cwd())
|
|
130
|
+
? ".claude/settings.json"
|
|
131
|
+
: settingsPath;
|
|
132
|
+
console.log(`Plugin registered in ${label} ✓`);
|
|
133
|
+
|
|
134
|
+
if (settingsPath.startsWith(process.cwd())) {
|
|
135
|
+
console.log("Commit that file to share the plugin with your team.");
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
console.log(
|
|
139
|
+
"\nCould not write settings. Add manually to .claude/settings.json:"
|
|
140
|
+
);
|
|
141
|
+
console.log(JSON.stringify({ enabledPlugins: [INSTALL_DIR] }, null, 2));
|
|
142
|
+
console.log(`\nOr load for a single session:`);
|
|
70
143
|
console.log(` claude --plugin-dir "${INSTALL_DIR}"`);
|
|
71
144
|
}
|
|
72
145
|
}
|
|
73
146
|
|
|
74
147
|
// ── Commands ──────────────────────────────────────────────────────────────────
|
|
75
148
|
|
|
76
|
-
function install() {
|
|
77
|
-
|
|
149
|
+
async function install() {
|
|
150
|
+
const meta = await getLatestNpmMeta();
|
|
78
151
|
|
|
79
152
|
if (fs.existsSync(INSTALL_DIR)) {
|
|
80
153
|
const installed = getInstalledVersion();
|
|
81
|
-
const latest = getLatestRemoteVersion();
|
|
82
154
|
|
|
83
|
-
if (
|
|
155
|
+
if (meta && installed && installed !== meta.version) {
|
|
84
156
|
console.log(`\nPlugin already installed (v${installed}).`);
|
|
85
|
-
console.log(
|
|
157
|
+
console.log(
|
|
158
|
+
`v${meta.version} is available — run: npx ${NPM_PACKAGE} update\n`
|
|
159
|
+
);
|
|
86
160
|
} else {
|
|
87
|
-
console.log(
|
|
161
|
+
console.log(
|
|
162
|
+
`\nPlugin already installed (v${installed || "unknown"}). Nothing to do.\n`
|
|
163
|
+
);
|
|
88
164
|
}
|
|
89
165
|
registerPlugin();
|
|
90
166
|
return;
|
|
91
167
|
}
|
|
92
168
|
|
|
93
169
|
console.log(`\nInstalling presentation-generator plugin...`);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
170
|
+
|
|
171
|
+
if (!meta) {
|
|
172
|
+
console.error(
|
|
173
|
+
"\nCould not fetch latest version from npm registry. Check your internet connection.\n"
|
|
174
|
+
);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
await downloadAndExtract(meta.version, meta.tarball);
|
|
179
|
+
console.log(`\nInstalled v${meta.version} to: ${INSTALL_DIR}`);
|
|
97
180
|
registerPlugin();
|
|
98
181
|
}
|
|
99
182
|
|
|
100
|
-
function update() {
|
|
101
|
-
checkGitAuth();
|
|
102
|
-
|
|
183
|
+
async function update() {
|
|
103
184
|
if (!fs.existsSync(INSTALL_DIR)) {
|
|
104
185
|
console.log("\nPlugin not installed. Run install first:");
|
|
105
|
-
console.log(
|
|
186
|
+
console.log(` npx ${NPM_PACKAGE} install\n`);
|
|
106
187
|
process.exit(1);
|
|
107
188
|
}
|
|
108
189
|
|
|
109
190
|
const before = getInstalledVersion();
|
|
110
|
-
|
|
111
|
-
run(`git -C "${INSTALL_DIR}" pull`);
|
|
191
|
+
const meta = await getLatestNpmMeta();
|
|
112
192
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
193
|
+
if (!meta) {
|
|
194
|
+
console.error(
|
|
195
|
+
"\nCould not fetch latest version from npm registry. Check your internet connection.\n"
|
|
196
|
+
);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (before === meta.version) {
|
|
201
|
+
console.log(`\nAlready up to date (v${before}) ✓`);
|
|
202
|
+
registerPlugin();
|
|
203
|
+
return;
|
|
118
204
|
}
|
|
119
205
|
|
|
206
|
+
console.log(
|
|
207
|
+
`\nUpdating presentation-generator plugin (v${before || "unknown"} → v${meta.version})...`
|
|
208
|
+
);
|
|
209
|
+
await downloadAndExtract(meta.version, meta.tarball);
|
|
210
|
+
console.log(`\nUpdated to v${meta.version} ✓`);
|
|
120
211
|
registerPlugin();
|
|
121
212
|
}
|
|
122
213
|
|
|
123
|
-
function checkUpdate() {
|
|
214
|
+
async function checkUpdate() {
|
|
124
215
|
if (!fs.existsSync(INSTALL_DIR)) {
|
|
125
|
-
console.log("\nPlugin not installed
|
|
216
|
+
console.log("\nPlugin not installed.\n");
|
|
126
217
|
return;
|
|
127
218
|
}
|
|
128
219
|
|
|
129
220
|
const installed = getInstalledVersion();
|
|
130
|
-
const
|
|
221
|
+
const meta = await getLatestNpmMeta();
|
|
131
222
|
|
|
132
|
-
if (!
|
|
133
|
-
console.log(
|
|
223
|
+
if (!meta) {
|
|
224
|
+
console.log(
|
|
225
|
+
`\nInstalled: v${installed || "unknown"} (could not reach npm registry)\n`
|
|
226
|
+
);
|
|
134
227
|
return;
|
|
135
228
|
}
|
|
136
229
|
|
|
137
|
-
if (installed ===
|
|
230
|
+
if (installed === meta.version) {
|
|
138
231
|
console.log(`\nUp to date: v${installed} ✓\n`);
|
|
139
232
|
} else {
|
|
140
|
-
console.log(`\nUpdate available: v${installed} → v${
|
|
141
|
-
console.log(`Run: npx
|
|
233
|
+
console.log(`\nUpdate available: v${installed} → v${meta.version}`);
|
|
234
|
+
console.log(`Run: npx ${NPM_PACKAGE} update\n`);
|
|
142
235
|
}
|
|
143
236
|
}
|
|
144
237
|
|
|
@@ -148,8 +241,7 @@ function uninstall() {
|
|
|
148
241
|
return;
|
|
149
242
|
}
|
|
150
243
|
fs.rmSync(INSTALL_DIR, { recursive: true, force: true });
|
|
151
|
-
console.log(`\nRemoved: ${INSTALL_DIR}`);
|
|
152
|
-
console.log("You may also want to run: claude plugin uninstall presentation-generator\n");
|
|
244
|
+
console.log(`\nRemoved: ${INSTALL_DIR}\n`);
|
|
153
245
|
}
|
|
154
246
|
|
|
155
247
|
function help() {
|
|
@@ -157,21 +249,28 @@ function help() {
|
|
|
157
249
|
presentation-generator-plugin v${CURRENT_VERSION}
|
|
158
250
|
|
|
159
251
|
Commands:
|
|
160
|
-
install
|
|
161
|
-
update
|
|
252
|
+
install Download plugin from npm and register with Claude Code
|
|
253
|
+
update Download and install the latest version from npm
|
|
162
254
|
check-update Report whether an update is available
|
|
163
255
|
uninstall Remove plugin from ~/.claude/plugins/
|
|
164
256
|
|
|
165
257
|
Usage:
|
|
166
|
-
npx
|
|
167
|
-
npx
|
|
168
|
-
npx
|
|
169
|
-
|
|
170
|
-
Requires: gh auth login (GitHub authentication)
|
|
258
|
+
npx ${NPM_PACKAGE} install
|
|
259
|
+
npx ${NPM_PACKAGE} update
|
|
260
|
+
npx ${NPM_PACKAGE} check-update
|
|
171
261
|
`);
|
|
172
262
|
}
|
|
173
263
|
|
|
174
|
-
|
|
264
|
+
// ── Dispatch ──────────────────────────────────────────────────────────────────
|
|
265
|
+
|
|
266
|
+
const commands = {
|
|
267
|
+
install,
|
|
268
|
+
update,
|
|
269
|
+
"check-update": checkUpdate,
|
|
270
|
+
uninstall,
|
|
271
|
+
help,
|
|
272
|
+
};
|
|
273
|
+
|
|
175
274
|
const fn = commands[command];
|
|
176
275
|
|
|
177
276
|
if (!fn) {
|
|
@@ -180,4 +279,7 @@ if (!fn) {
|
|
|
180
279
|
process.exit(1);
|
|
181
280
|
}
|
|
182
281
|
|
|
183
|
-
fn()
|
|
282
|
+
Promise.resolve(fn()).catch((err) => {
|
|
283
|
+
console.error("\nError:", err.message, "\n");
|
|
284
|
+
process.exit(1);
|
|
285
|
+
});
|