ginskill-init 2.7.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 (128) hide show
  1. package/.wrangler/cache/pages.json +4 -0
  2. package/.wrangler/cache/wrangler-account.json +6 -0
  3. package/DEVELOPMENT.md +510 -0
  4. package/README.md +104 -0
  5. package/agents/developer.md +56 -0
  6. package/agents/frontend-design.md +69 -0
  7. package/agents/mobile-reviewer.md +36 -0
  8. package/agents/review-code.md +49 -0
  9. package/agents/security-scanner.md +50 -0
  10. package/agents/tester.md +72 -0
  11. package/bin/cli.js +461 -0
  12. package/landing/ai-build-ai.png +0 -0
  13. package/landing/index.html +1495 -0
  14. package/landing/logo.png +0 -0
  15. package/package.json +37 -0
  16. package/skills/active-life-dev/SKILL.md +157 -0
  17. package/skills/active-life-dev/docs/auth.md +187 -0
  18. package/skills/active-life-dev/docs/customers.md +216 -0
  19. package/skills/active-life-dev/docs/integrations.md +209 -0
  20. package/skills/active-life-dev/docs/inventory.md +192 -0
  21. package/skills/active-life-dev/docs/modules.md +181 -0
  22. package/skills/active-life-dev/docs/orders.md +180 -0
  23. package/skills/active-life-dev/docs/patterns.md +319 -0
  24. package/skills/active-life-dev/docs/products.md +216 -0
  25. package/skills/active-life-dev/docs/schema.md +502 -0
  26. package/skills/active-life-dev/docs/setup.md +169 -0
  27. package/skills/active-life-dev/docs/vouchers.md +144 -0
  28. package/skills/ai-asset-generator/SKILL.md +247 -0
  29. package/skills/ai-asset-generator/docs/gen-image.md +274 -0
  30. package/skills/ai-asset-generator/docs/genvideo.md +341 -0
  31. package/skills/ai-asset-generator/docs/remove-background.md +19 -0
  32. package/skills/ai-asset-generator/lib/bg-remove.mjs +34 -0
  33. package/skills/ai-asset-generator/lib/env.mjs +48 -0
  34. package/skills/ai-asset-generator/lib/kie-client.mjs +100 -0
  35. package/skills/ai-build-ai/SKILL.md +127 -0
  36. package/skills/ai-build-ai/docs/agent-teams.md +293 -0
  37. package/skills/ai-build-ai/docs/checkpointing.md +161 -0
  38. package/skills/ai-build-ai/docs/create-agent.md +399 -0
  39. package/skills/ai-build-ai/docs/create-mcp.md +395 -0
  40. package/skills/ai-build-ai/docs/create-skill.md +299 -0
  41. package/skills/ai-build-ai/docs/headless-mode.md +614 -0
  42. package/skills/ai-build-ai/docs/hooks.md +578 -0
  43. package/skills/ai-build-ai/docs/memory-claude-md.md +375 -0
  44. package/skills/ai-build-ai/docs/output-styles.md +208 -0
  45. package/skills/ai-build-ai/docs/overview.md +162 -0
  46. package/skills/ai-build-ai/docs/permissions.md +391 -0
  47. package/skills/ai-build-ai/docs/plugins.md +396 -0
  48. package/skills/ai-build-ai/docs/sandbox.md +262 -0
  49. package/skills/ai-build-ai/docs/team-lead-workflow.md +648 -0
  50. package/skills/ant-design/SKILL.md +323 -0
  51. package/skills/ant-design/docs/components.md +160 -0
  52. package/skills/ant-design/docs/data-entry.md +406 -0
  53. package/skills/ant-design/docs/display.md +594 -0
  54. package/skills/ant-design/docs/feedback.md +451 -0
  55. package/skills/ant-design/docs/key-components.md +414 -0
  56. package/skills/ant-design/docs/navigation.md +310 -0
  57. package/skills/ant-design/docs/pro-components.md +543 -0
  58. package/skills/ant-design/docs/setup.md +213 -0
  59. package/skills/ant-design/docs/theme.md +265 -0
  60. package/skills/flutter-performance/SKILL.md +803 -0
  61. package/skills/flutter-performance/references/flutter-patterns.md +595 -0
  62. package/skills/icon-generator/SKILL.md +270 -0
  63. package/skills/mobile-app-review/SKILL.md +321 -0
  64. package/skills/mobile-app-review/references/apple-review.md +132 -0
  65. package/skills/mobile-app-review/references/google-play-review.md +203 -0
  66. package/skills/mongodb/SKILL.md +667 -0
  67. package/skills/mongodb/references/mongoose-patterns.md +368 -0
  68. package/skills/nestjs-architecture/SKILL.md +1086 -0
  69. package/skills/nestjs-architecture/references/advanced-patterns.md +590 -0
  70. package/skills/performance/SKILL.md +509 -0
  71. package/skills/react-fsd-architecture/SKILL.md +693 -0
  72. package/skills/react-fsd-architecture/references/fsd-patterns.md +747 -0
  73. package/skills/react-native-expo/SKILL.md +128 -0
  74. package/skills/react-native-expo/references/data-layer.md +252 -0
  75. package/skills/react-native-expo/references/design-system.md +252 -0
  76. package/skills/react-native-expo/references/navigation.md +199 -0
  77. package/skills/react-native-expo/references/performance.md +229 -0
  78. package/skills/react-native-expo/references/platform-services.md +179 -0
  79. package/skills/react-native-expo/references/state-management.md +209 -0
  80. package/skills/react-native-expo/references/ui-patterns.md +301 -0
  81. package/skills/react-query/SKILL.md +685 -0
  82. package/skills/react-query/references/query-patterns.md +365 -0
  83. package/skills/review-code/SKILL.md +374 -0
  84. package/skills/review-code/references/clean-code-principles.md +395 -0
  85. package/skills/review-code/references/frontend-patterns.md +136 -0
  86. package/skills/review-code/references/nestjs-patterns.md +184 -0
  87. package/skills/security-scanner/SKILL.md +366 -0
  88. package/skills/security-scanner/references/nestjs-security.md +260 -0
  89. package/skills/security-scanner/references/nextjs-security.md +201 -0
  90. package/skills/security-scanner/references/react-native-security.md +199 -0
  91. package/skills/traefik/SKILL.md +105 -0
  92. package/skills/traefik/docs/advanced-routing.md +186 -0
  93. package/skills/traefik/docs/auth-providers.md +137 -0
  94. package/skills/traefik/docs/cicd-devops.md +396 -0
  95. package/skills/traefik/docs/core-config.md +171 -0
  96. package/skills/traefik/docs/distributed-config.md +96 -0
  97. package/skills/traefik/docs/docker-compose.md +182 -0
  98. package/skills/traefik/docs/ha-performance.md +177 -0
  99. package/skills/traefik/docs/kubernetes.md +278 -0
  100. package/skills/traefik/docs/middleware.md +205 -0
  101. package/skills/traefik/docs/monitoring.md +357 -0
  102. package/skills/traefik/docs/security.md +391 -0
  103. package/skills/traefik/docs/tls-acme.md +155 -0
  104. package/skills/ui-ux-pro-max/SKILL.md +377 -0
  105. package/skills/ui-ux-pro-max/data/charts.csv +26 -0
  106. package/skills/ui-ux-pro-max/data/colors.csv +97 -0
  107. package/skills/ui-ux-pro-max/data/icons.csv +101 -0
  108. package/skills/ui-ux-pro-max/data/landing.csv +31 -0
  109. package/skills/ui-ux-pro-max/data/products.csv +97 -0
  110. package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  111. package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  112. package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  113. package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  114. package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  115. package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  116. package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  117. package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  118. package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  119. package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  120. package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  121. package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  122. package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  123. package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  124. package/skills/ui-ux-pro-max/data/styles.csv +68 -0
  125. package/skills/ui-ux-pro-max/data/typography.csv +58 -0
  126. package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  127. package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  128. package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
package/bin/cli.js ADDED
@@ -0,0 +1,461 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { fileURLToPath } from 'url';
4
+ import { dirname, join } from 'path';
5
+ import { existsSync, readdirSync, statSync, mkdirSync, copyFileSync, rmSync, readFileSync } from 'fs';
6
+ import { homedir } from 'os';
7
+ import { execSync } from 'child_process';
8
+ import { Command } from 'commander';
9
+ import chalk from 'chalk';
10
+ import ora from 'ora';
11
+ import prompts from 'prompts';
12
+
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const PACKAGE_DIR = join(__dirname, '..');
15
+ const SRC_SKILLS = join(PACKAGE_DIR, 'skills');
16
+ const SRC_AGENTS = join(PACKAGE_DIR, 'agents');
17
+ const PKG = JSON.parse(readFileSync(join(PACKAGE_DIR, 'package.json'), 'utf-8'));
18
+
19
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
20
+
21
+ function getDirs(dir) {
22
+ if (!existsSync(dir)) return [];
23
+ return readdirSync(dir).filter(f => statSync(join(dir, f)).isDirectory());
24
+ }
25
+
26
+ function getMdFiles(dir) {
27
+ if (!existsSync(dir)) return [];
28
+ return readdirSync(dir)
29
+ .filter(f => f.endsWith('.md') && statSync(join(dir, f)).isFile())
30
+ .map(f => f.replace('.md', ''));
31
+ }
32
+
33
+ function unique(arr) {
34
+ return [...new Set(arr)];
35
+ }
36
+
37
+ function copyDir(src, dest) {
38
+ mkdirSync(dest, { recursive: true });
39
+ for (const entry of readdirSync(src)) {
40
+ const s = join(src, entry), d = join(dest, entry);
41
+ statSync(s).isDirectory() ? copyDir(s, d) : copyFileSync(s, d);
42
+ }
43
+ }
44
+
45
+ function resolveTarget(targetArg, isGlobal) {
46
+ if (isGlobal) return join(homedir(), '.claude');
47
+ if (targetArg) return join(targetArg, '.claude');
48
+ return join(process.cwd(), '.claude');
49
+ }
50
+
51
+ function getAvailable() {
52
+ const skills = getDirs(SRC_SKILLS);
53
+ const agents = unique([...getDirs(SRC_AGENTS), ...getMdFiles(SRC_AGENTS)]);
54
+ return { skills, agents };
55
+ }
56
+
57
+ function getInstalled(claudeDir) {
58
+ const skills = getDirs(join(claudeDir, 'skills'))
59
+ .filter(s => getDirs(SRC_SKILLS).includes(s)); // only ours
60
+ const agentDir = join(claudeDir, 'agents');
61
+ const available = getAvailable().agents;
62
+ const agents = unique([
63
+ ...getDirs(agentDir),
64
+ ...getMdFiles(agentDir),
65
+ ]).filter(a => available.includes(a));
66
+ return { skills, agents };
67
+ }
68
+
69
+ // ─── Logger ───────────────────────────────────────────────────────────────────
70
+
71
+ const log = {
72
+ title: msg => console.log('\n' + chalk.bold.cyan(msg) + '\n'),
73
+ info: msg => console.log(chalk.blue(' info ') + msg),
74
+ success: msg => console.log(chalk.green(' ✓ ') + msg),
75
+ warn: msg => console.log(chalk.yellow(' warn ') + msg),
76
+ error: msg => console.log(chalk.red(' error ') + msg),
77
+ dim: msg => console.log(chalk.dim(' ' + msg)),
78
+ };
79
+
80
+ const onCancel = () => { log.warn('Cancelled.'); process.exit(0); };
81
+
82
+ // ─── Core Install ─────────────────────────────────────────────────────────────
83
+
84
+ async function runInstall({ target, skills, agents, verb = 'Installed' }) {
85
+ const destSkills = join(target, 'skills');
86
+ const destAgents = join(target, 'agents');
87
+
88
+ if (skills.length === 0 && agents.length === 0) {
89
+ log.warn('Nothing selected.');
90
+ return;
91
+ }
92
+
93
+ const spinner = ora({ text: 'Working...', color: 'cyan' }).start();
94
+ let count = 0;
95
+
96
+ for (const skill of skills) {
97
+ spinner.text = `${verb.replace('d','ing')} skill ${chalk.cyan(skill)}...`;
98
+ copyDir(join(SRC_SKILLS, skill), join(destSkills, skill));
99
+ count++;
100
+ }
101
+
102
+ for (const agent of agents) {
103
+ spinner.text = `${verb.replace('d','ing')} agent ${chalk.cyan(agent)}...`;
104
+ const srcDir = join(SRC_AGENTS, agent);
105
+ const srcFile = join(SRC_AGENTS, `${agent}.md`);
106
+ mkdirSync(destAgents, { recursive: true });
107
+ if (existsSync(srcDir) && statSync(srcDir).isDirectory()) {
108
+ copyDir(srcDir, join(destAgents, agent));
109
+ } else if (existsSync(srcFile)) {
110
+ copyFileSync(srcFile, join(destAgents, `${agent}.md`));
111
+ }
112
+ count++;
113
+ }
114
+
115
+ spinner.succeed(chalk.bold.green(`${verb}! ${count} item(s)`));
116
+ console.log();
117
+ log.info(`Target: ${chalk.cyan(target)}`);
118
+ log.dim('Restart Claude Code (or run /agents) to pick up changes.');
119
+ console.log();
120
+ }
121
+
122
+ // ─── Multiselect helper ───────────────────────────────────────────────────────
123
+
124
+ async function multiSelect(message, choices) {
125
+ const { selected } = await prompts({
126
+ type: 'multiselect',
127
+ name: 'selected',
128
+ message,
129
+ choices,
130
+ hint: 'Space to toggle · A to toggle all · Enter to confirm',
131
+ instructions: false,
132
+ min: 0,
133
+ }, { onCancel });
134
+ return selected ?? [];
135
+ }
136
+
137
+ async function confirmPrompt(message) {
138
+ const { ok } = await prompts({ type: 'confirm', name: 'ok', message, initial: true }, { onCancel });
139
+ return ok;
140
+ }
141
+
142
+ // ─── COMMAND: install ─────────────────────────────────────────────────────────
143
+
144
+ async function cmdInstall(options, targetArg) {
145
+ log.title('GinStudio — Install Skills & Agents');
146
+
147
+ const target = resolveTarget(options.target || targetArg, options.global);
148
+ const { skills: allSkills, agents: allAgents } = getAvailable();
149
+
150
+ // Non-interactive shortcut flags
151
+ if (options.all || options.skills || options.agents) {
152
+ const skills = options.all ? allSkills
153
+ : options.skills ? options.skills.split(',').map(s => s.trim()).filter(s => allSkills.includes(s))
154
+ : allSkills;
155
+ const agents = options.all ? allAgents
156
+ : options.agents ? options.agents.split(',').map(s => s.trim()).filter(s => allAgents.includes(s))
157
+ : allAgents;
158
+
159
+ log.info(`Target: ${chalk.cyan(target)}`);
160
+ log.info(`Skills (${skills.length}): ${chalk.green(skills.join(', ') || 'none')}`);
161
+ log.info(`Agents (${agents.length}): ${chalk.cyan(agents.join(', ') || 'none')}`);
162
+ console.log();
163
+ return runInstall({ target, skills, agents });
164
+ }
165
+
166
+ // Full TUI
167
+ log.info(`Target: ${chalk.cyan(target)}\n`);
168
+
169
+ const installed = getInstalled(target);
170
+
171
+ const skills = await multiSelect('Select skills to install:', allSkills.map(s => ({
172
+ title: s,
173
+ value: s,
174
+ selected: installed.skills.includes(s) || !existsSync(target),
175
+ })));
176
+
177
+ console.log();
178
+
179
+ const agents = await multiSelect('Select agents to install:', allAgents.map(a => ({
180
+ title: a,
181
+ value: a,
182
+ selected: installed.agents.includes(a) || !existsSync(target),
183
+ })));
184
+
185
+ console.log();
186
+ console.log(chalk.bold(' Summary'));
187
+ console.log(` ${chalk.green('Skills')} (${skills.length}): ${skills.join(', ') || chalk.dim('none')}`);
188
+ console.log(` ${chalk.cyan('Agents')} (${agents.length}): ${agents.join(', ') || chalk.dim('none')}`);
189
+ console.log(` Target: ${target}`);
190
+ console.log();
191
+
192
+ if (!await confirmPrompt('Install?')) { log.warn('Cancelled.'); return; }
193
+ console.log();
194
+
195
+ return runInstall({ target, skills, agents });
196
+ }
197
+
198
+ // ─── COMMAND: upgrade ─────────────────────────────────────────────────────────
199
+
200
+ async function cmdUpgrade(options, targetArg) {
201
+ log.title('GinStudio — Upgrade Skills & Agents');
202
+
203
+ const target = resolveTarget(options.target || targetArg, options.global);
204
+ const installed = getInstalled(target);
205
+ const total = installed.skills.length + installed.agents.length;
206
+
207
+ if (total === 0) {
208
+ log.warn(`Nothing from GinStudio is installed in ${chalk.cyan(target)}.`);
209
+ log.dim(`Run ${chalk.white('ginskill-init')} to install first.`);
210
+ console.log();
211
+ return;
212
+ }
213
+
214
+ log.info(`Target: ${chalk.cyan(target)}`);
215
+ log.info(`Current package: ${chalk.cyan(`v${PKG.version}`)}\n`);
216
+
217
+ // Non-interactive
218
+ if (options.all) {
219
+ return runInstall({ target, skills: installed.skills, agents: installed.agents, verb: 'Upgraded' });
220
+ }
221
+
222
+ const skills = await multiSelect('Select skills to upgrade:', installed.skills.map(s => ({
223
+ title: s, value: s, selected: true,
224
+ })));
225
+
226
+ console.log();
227
+
228
+ const agents = await multiSelect('Select agents to upgrade:', installed.agents.map(a => ({
229
+ title: a, value: a, selected: true,
230
+ })));
231
+
232
+ console.log();
233
+
234
+ if (!await confirmPrompt(`Re-install ${skills.length + agents.length} item(s) from v${PKG.version}?`)) {
235
+ log.warn('Cancelled.');
236
+ return;
237
+ }
238
+ console.log();
239
+
240
+ return runInstall({ target, skills, agents, verb: 'Upgraded' });
241
+ }
242
+
243
+ // ─── COMMAND: uninstall ───────────────────────────────────────────────────────
244
+
245
+ async function cmdUninstall(options, targetArg) {
246
+ log.title('GinStudio — Uninstall Skills & Agents');
247
+
248
+ const target = resolveTarget(options.target || targetArg, options.global);
249
+ const installed = getInstalled(target);
250
+ const total = installed.skills.length + installed.agents.length;
251
+
252
+ if (total === 0) {
253
+ log.warn(`Nothing from GinStudio is installed in ${chalk.cyan(target)}.`);
254
+ console.log();
255
+ return;
256
+ }
257
+
258
+ log.info(`Target: ${chalk.cyan(target)}\n`);
259
+
260
+ const skills = await multiSelect('Select skills to uninstall:', installed.skills.map(s => ({
261
+ title: s, value: s, selected: false,
262
+ })));
263
+
264
+ console.log();
265
+
266
+ const agents = await multiSelect('Select agents to uninstall:', installed.agents.map(a => ({
267
+ title: a, value: a, selected: false,
268
+ })));
269
+
270
+ console.log();
271
+
272
+ const count = skills.length + agents.length;
273
+ if (count === 0) { log.warn('Nothing selected.'); return; }
274
+
275
+ console.log(chalk.bold(' Will remove:'));
276
+ skills.forEach(s => console.log(` ${chalk.red('✕')} skill ${s}`));
277
+ agents.forEach(a => console.log(` ${chalk.red('✕')} agent ${a}`));
278
+ console.log();
279
+
280
+ if (!await confirmPrompt(chalk.red(`Permanently remove ${count} item(s)?`))) {
281
+ log.warn('Cancelled.');
282
+ return;
283
+ }
284
+
285
+ const spinner = ora({ text: 'Removing...', color: 'red' }).start();
286
+
287
+ for (const skill of skills) {
288
+ const dir = join(target, 'skills', skill);
289
+ if (existsSync(dir)) rmSync(dir, { recursive: true, force: true });
290
+ }
291
+ for (const agent of agents) {
292
+ const dir = join(target, 'agents', agent);
293
+ const file = join(target, 'agents', `${agent}.md`);
294
+ if (existsSync(dir)) rmSync(dir, { recursive: true, force: true });
295
+ if (existsSync(file)) rmSync(file, { force: true });
296
+ }
297
+
298
+ spinner.succeed(chalk.bold.red(`Removed ${count} item(s)`));
299
+ console.log();
300
+ log.dim('Restart Claude Code to pick up changes.');
301
+ console.log();
302
+ }
303
+
304
+ // ─── COMMAND: status ──────────────────────────────────────────────────────────
305
+
306
+ function cmdStatus(options, targetArg) {
307
+ log.title('GinStudio — Status');
308
+
309
+ const target = resolveTarget(options.target || targetArg, options.global);
310
+ const { skills: allSkills, agents: allAgents } = getAvailable();
311
+ const installed = getInstalled(target);
312
+
313
+ log.info(`Package: ${chalk.cyan(`ginskill-init v${PKG.version}`)}`);
314
+ log.info(`Target: ${chalk.cyan(target)}`);
315
+ console.log();
316
+
317
+ console.log(chalk.bold(' Skills:'));
318
+ for (const s of allSkills) {
319
+ const isInstalled = installed.skills.includes(s);
320
+ const icon = isInstalled ? chalk.green('✓') : chalk.dim('○');
321
+ const label = isInstalled ? chalk.white(s) : chalk.dim(s);
322
+ const badge = isInstalled ? chalk.green('installed') : chalk.dim('not installed');
323
+ console.log(` ${icon} ${label.padEnd(28)} ${badge}`);
324
+ }
325
+
326
+ console.log();
327
+ console.log(chalk.bold(' Agents:'));
328
+ for (const a of allAgents) {
329
+ const isInstalled = installed.agents.includes(a);
330
+ const icon = isInstalled ? chalk.green('✓') : chalk.dim('○');
331
+ const label = isInstalled ? chalk.cyan(a) : chalk.dim(a);
332
+ const badge = isInstalled ? chalk.green('installed') : chalk.dim('not installed');
333
+ console.log(` ${icon} ${label.padEnd(28)} ${badge}`);
334
+ }
335
+
336
+ console.log();
337
+ const si = installed.skills.length, ai = installed.agents.length;
338
+ log.info(`${si} skill(s) · ${ai} agent(s) installed out of ${allSkills.length} skills · ${allAgents.length} agents available`);
339
+ console.log();
340
+ }
341
+
342
+ // ─── COMMAND: versions ────────────────────────────────────────────────────────
343
+
344
+ async function cmdVersions() {
345
+ log.title('GinStudio — Available Versions');
346
+
347
+ const spinner = ora({ text: 'Fetching from npm registry...', color: 'cyan' }).start();
348
+
349
+ try {
350
+ const res = await fetch(`https://registry.npmjs.org/${PKG.name}`);
351
+ if (!res.ok) throw new Error(`Registry returned ${res.status}`);
352
+ const data = await res.json();
353
+
354
+ const versions = Object.keys(data.versions || {}).reverse();
355
+ const latest = data['dist-tags']?.latest;
356
+ const times = data.time || {};
357
+
358
+ spinner.succeed(`Found ${versions.length} version(s)\n`);
359
+
360
+ console.log(chalk.bold(' Available versions:\n'));
361
+ for (const v of versions.slice(0, 20)) {
362
+ const isLatest = v === latest;
363
+ const date = times[v] ? new Date(times[v]).toLocaleDateString() : '';
364
+ const isCurrent = v === PKG.version;
365
+ const tag = isLatest ? chalk.green('[latest]') : '';
366
+ const cur = isCurrent ? chalk.blue('[current]') : '';
367
+ const vStr = isLatest ? chalk.bold.green(`v${v}`) : chalk.white(`v${v}`);
368
+ console.log(` ${vStr} ${chalk.dim(date)} ${tag} ${cur}`);
369
+ }
370
+ if (versions.length > 20) log.dim(`... and ${versions.length - 20} more`);
371
+
372
+ console.log();
373
+ log.dim(`Run ${chalk.white('npx ginskill-init@latest')} to get the newest version.`);
374
+ console.log();
375
+
376
+ } catch (err) {
377
+ spinner.fail('Could not fetch versions from npm registry.');
378
+ log.error(err.message);
379
+ log.dim(`Current installed version: ${chalk.cyan(`v${PKG.version}`)}`);
380
+ console.log();
381
+ }
382
+ }
383
+
384
+ // ─── COMMAND: list ────────────────────────────────────────────────────────────
385
+
386
+ function cmdList() {
387
+ log.title('GinStudio — Available Skills & Agents');
388
+ const { skills, agents } = getAvailable();
389
+
390
+ console.log(chalk.bold(' Skills:'));
391
+ skills.forEach(s => console.log(` ${chalk.green('✦')} ${s}`));
392
+ console.log();
393
+ console.log(chalk.bold(' Agents:'));
394
+ agents.forEach(a => console.log(` ${chalk.cyan('✦')} ${a}`));
395
+ console.log();
396
+ }
397
+
398
+ // ─── CLI wiring ───────────────────────────────────────────────────────────────
399
+
400
+ const program = new Command();
401
+
402
+ program
403
+ .name('ginskill-init')
404
+ .description('Install GinStudio skills & agents for Claude Code')
405
+ .version(PKG.version);
406
+
407
+ // Shared options factory
408
+ function addTargetOptions(cmd) {
409
+ return cmd
410
+ .option('-g, --global', 'Target ~/.claude/ (available in all projects)')
411
+ .option('-t, --target <path>', 'Custom target project path')
412
+ .argument('[target]', 'Target project path (positional)');
413
+ }
414
+
415
+ // Default: install
416
+ addTargetOptions(
417
+ program
418
+ .option('-a, --all', 'Install all without prompts')
419
+ .option('--skills <list>', 'Install specific skills (comma-separated names)')
420
+ .option('--agents <list>', 'Install specific agents (comma-separated names)')
421
+ )
422
+ .action((targetArg, opts) => cmdInstall(opts, targetArg));
423
+
424
+ // Merge parent opts (handles case where Commander consumes -t/-g at parent level)
425
+ function mergeOpts(opts) {
426
+ return { ...program.opts(), ...opts };
427
+ }
428
+
429
+ // upgrade
430
+ addTargetOptions(
431
+ program.command('upgrade')
432
+ .description('Upgrade installed skills & agents to the bundled version')
433
+ .option('-a, --all', 'Upgrade all without prompts')
434
+ )
435
+ .action((targetArg, opts) => cmdUpgrade(mergeOpts(opts), targetArg));
436
+
437
+ // uninstall
438
+ addTargetOptions(
439
+ program.command('uninstall').alias('remove')
440
+ .description('Remove installed skills & agents')
441
+ )
442
+ .action((targetArg, opts) => cmdUninstall(mergeOpts(opts), targetArg));
443
+
444
+ // status
445
+ addTargetOptions(
446
+ program.command('status').alias('info')
447
+ .description('Show installed vs available skills & agents')
448
+ )
449
+ .action((targetArg, opts) => cmdStatus(mergeOpts(opts), targetArg));
450
+
451
+ // versions
452
+ program.command('versions').alias('ver')
453
+ .description('List all published npm versions')
454
+ .action(() => cmdVersions());
455
+
456
+ // list
457
+ program.command('list').alias('ls')
458
+ .description('List all available skills & agents in this package')
459
+ .action(() => cmdList());
460
+
461
+ program.parse();
Binary file