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