packwise-skills 1.0.0 → 1.2.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 (53) hide show
  1. package/.cursorrules +23 -23
  2. package/CLAUDE.md +25 -25
  3. package/LICENSE +21 -0
  4. package/README.md +404 -295
  5. package/audit.md +224 -224
  6. package/bin/packwise.js +322 -155
  7. package/install.sh +123 -0
  8. package/package.json +32 -31
  9. package/skill.md +944 -719
  10. package/sub-skills/ai/local-llm.md +183 -183
  11. package/sub-skills/ai/python-ml.md +164 -164
  12. package/sub-skills/backend/go-server.md +184 -184
  13. package/sub-skills/backend/java-spring.md +241 -241
  14. package/sub-skills/backend/node-server.md +164 -164
  15. package/sub-skills/backend/php-laravel.md +175 -175
  16. package/sub-skills/backend/python-server.md +164 -164
  17. package/sub-skills/backend/rust-backend.md +118 -118
  18. package/sub-skills/cli/python-cli.md +236 -236
  19. package/sub-skills/cli/sdk-library.md +497 -497
  20. package/sub-skills/cloud/ci-cd-pipelines.md +350 -350
  21. package/sub-skills/cloud/docker.md +191 -191
  22. package/sub-skills/cloud/kubernetes.md +277 -277
  23. package/sub-skills/cloud/payment-integration.md +307 -307
  24. package/sub-skills/cross-platform/multiplatform.md +252 -252
  25. package/sub-skills/desktop/electron.md +783 -783
  26. package/sub-skills/desktop/game-dev.md +443 -443
  27. package/sub-skills/desktop/native-app.md +123 -123
  28. package/sub-skills/desktop/scenarios.md +443 -443
  29. package/sub-skills/desktop/smart-platforms.md +324 -324
  30. package/sub-skills/desktop/tauri.md +428 -428
  31. package/sub-skills/desktop/vr-ar.md +252 -252
  32. package/sub-skills/desktop/web-to-desktop.md +153 -153
  33. package/sub-skills/embedded/car-infotainment.md +129 -129
  34. package/sub-skills/embedded/esp32.md +184 -184
  35. package/sub-skills/embedded/ros.md +150 -150
  36. package/sub-skills/embedded/stm32.md +160 -160
  37. package/sub-skills/mobile/android.md +322 -322
  38. package/sub-skills/mobile/capacitor.md +232 -232
  39. package/sub-skills/mobile/flutter-mobile.md +138 -138
  40. package/sub-skills/mobile/harmonyos.md +150 -150
  41. package/sub-skills/mobile/ios.md +245 -245
  42. package/sub-skills/mobile/react-native.md +443 -443
  43. package/sub-skills/mobile/wearables.md +230 -230
  44. package/sub-skills/plugins/browser-extension.md +308 -308
  45. package/sub-skills/plugins/jetbrains-plugin.md +226 -226
  46. package/sub-skills/plugins/vscode-extension.md +204 -204
  47. package/sub-skills/security/security-tools.md +174 -174
  48. package/sub-skills/web/monorepo.md +274 -274
  49. package/sub-skills/web/pwa.md +220 -220
  50. package/sub-skills/web/serverless-edge.md +295 -295
  51. package/sub-skills/web/spa.md +266 -266
  52. package/sub-skills/web/ssr.md +228 -228
  53. package/sub-skills/web/wasm.md +243 -243
package/bin/packwise.js CHANGED
@@ -1,155 +1,322 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Packwise CLI — Universal installer for AI agent build skills
5
- *
6
- * Detects installed AI agents and copies skill files to the right location.
7
- *
8
- * Usage:
9
- * npx @anthropic-ai/packwise # Auto-detect and install
10
- * npx @anthropic-ai/packwise install # Same as above
11
- * npx @anthropic-ai/packwise uninstall # Remove from all detected agents
12
- * npx @anthropic-ai/packwise list # Show which agents have skills installed
13
- */
14
-
15
- const fs = require('fs');
16
- const path = require('path');
17
- const os = require('os');
18
-
19
- const SKILL_FILES = ['skill.md', 'audit.md'];
20
- const SKILL_DIRS = ['sub-skills'];
21
- const HOME = os.homedir();
22
- const CWD = process.cwd();
23
-
24
- // Agent detection and installation paths
25
- const AGENTS = [
26
- {
27
- name: 'Claude Code',
28
- detect: () => fs.existsSync(path.join(HOME, '.claude')) || fs.existsSync(path.join(CWD, '.claude')),
29
- userDir: path.join(HOME, '.claude', 'skills', 'packwise'),
30
- projectDir: path.join(CWD, '.claude', 'skills', 'packwise'),
31
- installTarget: 'user', // user-level by default
32
- },
33
- {
34
- name: 'Cursor',
35
- detect: () => fs.existsSync(path.join(CWD, '.cursorrules')) || fs.existsSync(path.join(HOME, '.cursor')),
36
- projectDir: path.join(CWD, '.cursor', 'skills', 'packwise'),
37
- installTarget: 'project',
38
- },
39
- {
40
- name: 'Windsurf',
41
- detect: () => fs.existsSync(path.join(HOME, '.windsurf')) || fs.existsSync(path.join(CWD, '.windsurfrules')),
42
- projectDir: path.join(CWD, 'skills', 'packwise'),
43
- installTarget: 'project',
44
- },
45
- {
46
- name: 'OpenCode',
47
- detect: () => fs.existsSync(path.join(HOME, '.opencode')) || fs.existsSync(path.join(CWD, '.opencode')),
48
- projectDir: path.join(CWD, '.opencode', 'skills', 'packwise'),
49
- installTarget: 'project',
50
- },
51
- {
52
- name: 'Zed AI',
53
- detect: () => fs.existsSync(path.join(HOME, '.zed')),
54
- projectDir: path.join(CWD, 'skills', 'packwise'),
55
- installTarget: 'project',
56
- },
57
- ];
58
-
59
- function copyRecursive(src, dest) {
60
- fs.mkdirSync(dest, { recursive: true });
61
- for (const item of fs.readdirSync(src)) {
62
- const srcPath = path.join(src, item);
63
- const destPath = path.join(dest, item);
64
- const stat = fs.statSync(srcPath);
65
- if (stat.isDirectory()) {
66
- copyRecursive(srcPath, destPath);
67
- } else {
68
- fs.copyFileSync(srcPath, destPath);
69
- }
70
- }
71
- }
72
-
73
- function removeRecursive(dir) {
74
- if (fs.existsSync(dir)) {
75
- fs.rmSync(dir, { recursive: true, force: true });
76
- }
77
- }
78
-
79
- const command = process.argv[2] || 'install';
80
- const sourceDir = path.join(__dirname, '..');
81
-
82
- if (command === 'install' || command === undefined) {
83
- console.log('\n Packwise — Universal Build & Packaging Skills\n');
84
-
85
- const installed = [];
86
- let installedAny = false;
87
-
88
- for (const agent of AGENTS) {
89
- if (!agent.detect()) continue;
90
-
91
- const target = agent.installTarget === 'user' && agent.userDir
92
- ? agent.userDir
93
- : agent.projectDir;
94
-
95
- if (!target) continue;
96
-
97
- console.log(` Installing for ${agent.name}...`);
98
- copyRecursive(sourceDir, target);
99
- console.log(` ✓ Installed to ${target}`);
100
- installed.push(agent.name);
101
- installedAny = true;
102
- }
103
-
104
- if (!installedAny) {
105
- // Fallback: install to project root skills/ directory
106
- const fallback = path.join(CWD, 'skills', 'packwise');
107
- console.log(' No AI agents detected. Installing to project...');
108
- copyRecursive(sourceDir, fallback);
109
- console.log(` ✓ Installed to ${fallback}`);
110
- console.log(`\n Reference in your AI agent:`);
111
- console.log(` "Read ${path.relative(CWD, fallback)}/skill.md and help me package this project"`);
112
- } else {
113
- console.log(`\n ✓ Packwise installed for: ${installed.join(', ')}`);
114
- console.log(`\n Usage: ask your AI agent to package your project`);
115
- }
116
- console.log('');
117
- }
118
-
119
- else if (command === 'uninstall') {
120
- console.log('\n Packwise — Uninstall\n');
121
- for (const agent of AGENTS) {
122
- const targets = [agent.userDir, agent.projectDir].filter(Boolean);
123
- for (const target of targets) {
124
- if (fs.existsSync(target)) {
125
- removeRecursive(target);
126
- console.log(` Removed from ${agent.name}: ${target}`);
127
- }
128
- }
129
- }
130
- console.log('');
131
- }
132
-
133
- else if (command === 'list') {
134
- console.log('\n Packwise Installed Agents\n');
135
- let found = false;
136
- for (const agent of AGENTS) {
137
- const targets = [agent.userDir, agent.projectDir].filter(Boolean);
138
- for (const target of targets) {
139
- if (fs.existsSync(target)) {
140
- console.log(` ✓ ${agent.name}: ${target}`);
141
- found = true;
142
- }
143
- }
144
- }
145
- if (!found) {
146
- console.log(' No installations found. Run: npx @anthropic-ai/packwise install');
147
- }
148
- console.log('');
149
- }
150
-
151
- else {
152
- console.log(`\n Unknown command: ${command}`);
153
- console.log(' Usage: npx @anthropic-ai/packwise [install|uninstall|list]\n');
154
- process.exit(1);
155
- }
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Packwise CLI — Universal installer for AI agent build skills
5
+ *
6
+ * Usage:
7
+ * npx packwise-skills # Install all skills
8
+ * npx packwise-skills --only desktop,mobile # By category
9
+ * npx packwise-skills --only electron,react-native # By specific framework
10
+ * npx packwise-skills --only electron,mobile # Mix both
11
+ * npx packwise-skills uninstall # Remove
12
+ * npx packwise-skills list # Show installed
13
+ * npx packwise-skills update # Update to latest version
14
+ *
15
+ * Categories: desktop, mobile, web, backend, ai, cli, plugins, embedded, security, cloud, cross-platform
16
+ */
17
+
18
+ const fs = require('fs');
19
+ const path = require('path');
20
+ const os = require('os');
21
+
22
+ const CORE_FILES = ['skill.md', 'audit.md', 'CLAUDE.md'];
23
+
24
+ const CATEGORY_MAP = {
25
+ desktop: ['electron', 'tauri', 'native-app', 'web-to-desktop', 'game-dev', 'vr-ar', 'smart-platforms', 'scenarios'],
26
+ mobile: ['android', 'ios', 'harmonyos', 'flutter-mobile', 'react-native', 'capacitor', 'wearables'],
27
+ web: ['spa', 'ssr', 'pwa', 'serverless-edge', 'monorepo', 'wasm'],
28
+ backend: ['node-server', 'python-server', 'go-server', 'rust-backend', 'java-spring', 'php-laravel'],
29
+ ai: ['python-ml', 'local-llm'],
30
+ cli: ['python-cli', 'sdk-library'],
31
+ plugins: ['browser-extension', 'vscode-extension', 'jetbrains-plugin'],
32
+ embedded: ['esp32', 'stm32', 'ros', 'car-infotainment'],
33
+ security: ['security-tools'],
34
+ cloud: ['docker', 'kubernetes', 'ci-cd-pipelines', 'payment-integration'],
35
+ 'cross-platform': ['multiplatform'],
36
+ };
37
+
38
+ const ALL_CATEGORIES = Object.keys(CATEGORY_MAP);
39
+ const ALL_FRAMEWORKS = Object.values(CATEGORY_MAP).flat();
40
+ const HOME = os.homedir();
41
+ const CWD = process.cwd();
42
+
43
+ // Agent detection and installation paths
44
+ const AGENTS = [
45
+ {
46
+ name: 'Claude Code',
47
+ detect: () => fs.existsSync(path.join(HOME, '.claude')) || fs.existsSync(path.join(CWD, '.claude')),
48
+ userDir: path.join(HOME, '.claude', 'skills', 'packwise'),
49
+ projectDir: path.join(CWD, '.claude', 'skills', 'packwise'),
50
+ installTarget: 'user', // user-level by default
51
+ },
52
+ {
53
+ name: 'Cursor',
54
+ detect: () => fs.existsSync(path.join(CWD, '.cursorrules')) || fs.existsSync(path.join(HOME, '.cursor')),
55
+ projectDir: path.join(CWD, '.cursor', 'skills', 'packwise'),
56
+ installTarget: 'project',
57
+ },
58
+ {
59
+ name: 'Windsurf',
60
+ detect: () => fs.existsSync(path.join(HOME, '.windsurf')) || fs.existsSync(path.join(CWD, '.windsurfrules')),
61
+ projectDir: path.join(CWD, 'skills', 'packwise'),
62
+ installTarget: 'project',
63
+ },
64
+ {
65
+ name: 'OpenCode',
66
+ detect: () => fs.existsSync(path.join(HOME, '.opencode')) || fs.existsSync(path.join(CWD, '.opencode')),
67
+ projectDir: path.join(CWD, '.opencode', 'skills', 'packwise'),
68
+ installTarget: 'project',
69
+ },
70
+ {
71
+ name: 'Zed AI',
72
+ detect: () => fs.existsSync(path.join(HOME, '.zed')),
73
+ projectDir: path.join(CWD, 'skills', 'packwise'),
74
+ installTarget: 'project',
75
+ },
76
+ {
77
+ name: 'OpenClaw',
78
+ detect: () => fs.existsSync(path.join(HOME, '.openclaw')) || fs.existsSync(path.join(CWD, '.openclaw')),
79
+ projectDir: path.join(CWD, '.openclaw', 'skills', 'packwise'),
80
+ installTarget: 'project',
81
+ },
82
+ {
83
+ name: 'WorkBuddy',
84
+ detect: () => fs.existsSync(path.join(HOME, '.workbuddy')) || fs.existsSync(path.join(CWD, '.workbuddy')),
85
+ userDir: path.join(HOME, '.workbuddy', 'skills', 'packwise'),
86
+ projectDir: path.join(CWD, '.workbuddy', 'skills', 'packwise'),
87
+ installTarget: 'user',
88
+ },
89
+ {
90
+ name: 'Trae',
91
+ detect: () => fs.existsSync(path.join(HOME, '.trae')) || fs.existsSync(path.join(CWD, '.trae')),
92
+ projectDir: path.join(CWD, '.trae', 'skills', 'packwise'),
93
+ installTarget: 'project',
94
+ },
95
+ {
96
+ name: 'Codex CLI',
97
+ detect: () => false, // No directory marker; user must manually place PACKWISE.md
98
+ projectDir: path.join(CWD, 'skills', 'packwise'),
99
+ installTarget: 'project',
100
+ },
101
+ {
102
+ name: 'Hermes',
103
+ detect: () => fs.existsSync(path.join(CWD, 'hermes.config.yaml')) || fs.existsSync(path.join(CWD, 'hermes.config.yml')),
104
+ projectDir: path.join(CWD, 'skills', 'packwise'),
105
+ installTarget: 'project',
106
+ },
107
+ {
108
+ name: 'GitHub Copilot',
109
+ detect: () => fs.existsSync(path.join(CWD, '.copilot')) || fs.existsSync(path.join(HOME, '.copilot')),
110
+ projectDir: path.join(CWD, '.copilot', 'skills', 'packwise'),
111
+ installTarget: 'project',
112
+ },
113
+ ];
114
+
115
+ // Parse --only flag (supports categories and individual frameworks)
116
+ const onlyIndex = process.argv.indexOf('--only');
117
+ const onlyRaw = onlyIndex !== -1
118
+ ? process.argv[onlyIndex + 1]?.split(',').map(c => c.trim().toLowerCase())
119
+ : null;
120
+
121
+ // Resolve to list of frameworks to install
122
+ let onlyFrameworks = null;
123
+ let onlyLabels = [];
124
+
125
+ if (onlyRaw) {
126
+ const invalid = onlyRaw.filter(c => !ALL_CATEGORIES.includes(c) && !ALL_FRAMEWORKS.includes(c));
127
+ if (invalid.length) {
128
+ console.log(`\n Unknown: ${invalid.join(', ')}`);
129
+ console.log(`\n Categories: ${ALL_CATEGORIES.join(', ')}`);
130
+ console.log(` Frameworks: ${ALL_FRAMEWORKS.join(', ')}\n`);
131
+ process.exit(1);
132
+ }
133
+
134
+ onlyFrameworks = new Set();
135
+ for (const item of onlyRaw) {
136
+ if (ALL_CATEGORIES.includes(item)) {
137
+ // Expand category to all its frameworks
138
+ CATEGORY_MAP[item].forEach(f => onlyFrameworks.add(f));
139
+ onlyLabels.push(item);
140
+ } else {
141
+ // Individual framework
142
+ onlyFrameworks.add(item);
143
+ onlyLabels.push(item);
144
+ }
145
+ }
146
+ }
147
+
148
+ // Parse command (skip --only and its value)
149
+ const args = process.argv.filter((a, i) => {
150
+ if (i <= 1) return false; // skip node and script path
151
+ if (a === '--only') return false;
152
+ if (onlyIndex !== -1 && i === onlyIndex + 1) return false;
153
+ return true;
154
+ });
155
+ const command = args[0] || 'install';
156
+
157
+ function copyFile(src, dest) {
158
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
159
+ fs.copyFileSync(src, dest);
160
+ }
161
+
162
+ function copyDir(src, dest) {
163
+ fs.mkdirSync(dest, { recursive: true });
164
+ for (const item of fs.readdirSync(src)) {
165
+ const srcPath = path.join(src, item);
166
+ const destPath = path.join(dest, item);
167
+ if (fs.statSync(srcPath).isDirectory()) {
168
+ copyDir(srcPath, destPath);
169
+ } else {
170
+ fs.copyFileSync(srcPath, destPath);
171
+ }
172
+ }
173
+ }
174
+
175
+ function removeRecursive(dir) {
176
+ if (fs.existsSync(dir)) {
177
+ fs.rmSync(dir, { recursive: true, force: true });
178
+ }
179
+ }
180
+
181
+ function installTo(target) {
182
+ const sourceDir = path.join(__dirname, '..');
183
+
184
+ // Always copy core files
185
+ for (const file of CORE_FILES) {
186
+ const src = path.join(sourceDir, file);
187
+ if (fs.existsSync(src)) copyFile(src, path.join(target, file));
188
+ }
189
+
190
+ // Copy sub-skills
191
+ const subSkillsSrc = path.join(sourceDir, 'sub-skills');
192
+ if (fs.existsSync(subSkillsSrc)) {
193
+ if (onlyFrameworks) {
194
+ // Selective install by individual framework
195
+ for (const cat of ALL_CATEGORIES) {
196
+ for (const fw of CATEGORY_MAP[cat]) {
197
+ if (onlyFrameworks.has(fw)) {
198
+ const fwSrc = path.join(subSkillsSrc, cat, fw + '.md');
199
+ if (fs.existsSync(fwSrc)) {
200
+ const destDir = path.join(target, 'sub-skills', cat);
201
+ fs.mkdirSync(destDir, { recursive: true });
202
+ fs.copyFileSync(fwSrc, path.join(destDir, fw + '.md'));
203
+ }
204
+ }
205
+ }
206
+ }
207
+ } else {
208
+ // Install all
209
+ copyDir(subSkillsSrc, path.join(target, 'sub-skills'));
210
+ }
211
+ }
212
+ }
213
+
214
+
215
+ if (command === 'install' || command === undefined) {
216
+ console.log('\n Packwise — Universal Build & Packaging Skills\n');
217
+
218
+ if (onlyFrameworks) {
219
+ console.log(` Selective install: ${onlyLabels.join(', ')}`);
220
+ console.log(` (skill.md, audit.md, CLAUDE.md are always included)\n`);
221
+ }
222
+
223
+ const installed = [];
224
+ let installedAny = false;
225
+
226
+ for (const agent of AGENTS) {
227
+ if (!agent.detect()) continue;
228
+
229
+ const target = agent.installTarget === 'user' && agent.userDir
230
+ ? agent.userDir
231
+ : agent.projectDir;
232
+
233
+ if (!target) continue;
234
+
235
+ console.log(` Installing for ${agent.name}...`);
236
+ installTo(target);
237
+ console.log(` ✓ Installed to ${target}`);
238
+ installed.push(agent.name);
239
+ installedAny = true;
240
+ }
241
+
242
+ if (!installedAny) {
243
+ const fallback = path.join(CWD, 'skills', 'packwise');
244
+ console.log(' No AI agents detected. Installing to project...');
245
+ installTo(fallback);
246
+ console.log(` ✓ Installed to ${fallback}`);
247
+ console.log(`\n Reference in your AI agent:`);
248
+ console.log(` "Read ${path.relative(CWD, fallback)}/skill.md and help me package this project"`);
249
+ } else {
250
+ console.log(`\n ✓ Packwise installed for: ${installed.join(', ')}`);
251
+ console.log(`\n Usage: ask your AI agent to package your project`);
252
+ }
253
+ console.log('');
254
+ }
255
+
256
+ else if (command === 'uninstall') {
257
+ console.log('\n Packwise — Uninstall\n');
258
+ for (const agent of AGENTS) {
259
+ const targets = [agent.userDir, agent.projectDir].filter(Boolean);
260
+ for (const target of targets) {
261
+ if (fs.existsSync(target)) {
262
+ removeRecursive(target);
263
+ console.log(` ✓ Removed from ${agent.name}: ${target}`);
264
+ }
265
+ }
266
+ }
267
+ console.log('');
268
+ }
269
+
270
+ else if (command === 'list') {
271
+ console.log('\n Packwise — Installed Agents\n');
272
+ let found = false;
273
+ for (const agent of AGENTS) {
274
+ const targets = [agent.userDir, agent.projectDir].filter(Boolean);
275
+ for (const target of targets) {
276
+ if (fs.existsSync(target)) {
277
+ console.log(` ✓ ${agent.name}: ${target}`);
278
+ found = true;
279
+ }
280
+ }
281
+ }
282
+ if (!found) {
283
+ console.log(' No installations found. Run: npx packwise-skills install');
284
+ }
285
+ console.log('');
286
+ }
287
+
288
+ else if (command === 'update') {
289
+ console.log('\n Packwise — Update\n');
290
+
291
+ const { execSync } = require('child_process');
292
+ let updated = false;
293
+
294
+ for (const agent of AGENTS) {
295
+ const targets = [agent.userDir, agent.projectDir].filter(Boolean);
296
+ for (const target of targets) {
297
+ if (fs.existsSync(target) && fs.existsSync(path.join(target, '.git'))) {
298
+ console.log(` Updating ${agent.name}: ${target}`);
299
+ try {
300
+ execSync('git pull', { cwd: target, stdio: 'pipe' });
301
+ console.log(` ✓ Updated ${agent.name}`);
302
+ updated = true;
303
+ } catch (e) {
304
+ console.log(` ✗ Failed to update ${agent.name}: ${e.message}`);
305
+ }
306
+ }
307
+ }
308
+ }
309
+
310
+ if (!updated) {
311
+ console.log(' No git-based installations found.');
312
+ console.log(' If installed via npm, run: npm update -g packwise-skills');
313
+ console.log(' If installed via curl, re-run the install script.');
314
+ }
315
+ console.log('');
316
+ }
317
+
318
+ else {
319
+ console.log(`\n Unknown command: ${command}`);
320
+ console.log(' Usage: npx packwise-skills [install|uninstall|list|update] [--only desktop,mobile]\n');
321
+ process.exit(1);
322
+ }
package/install.sh ADDED
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ REPO="https://github.com/Thomas520TOM/packwise-skills.git"
5
+ SKILL_NAME="packwise-skills"
6
+
7
+ # Category → Framework mapping
8
+ declare -A CAT_FW=(
9
+ [desktop]="electron tauri native-app web-to-desktop game-dev vr-ar smart-platforms scenarios"
10
+ [mobile]="android ios harmonyos flutter-mobile react-native capacitor wearables"
11
+ [web]="spa ssr pwa serverless-edge monorepo wasm"
12
+ [backend]="node-server python-server go-server rust-backend java-spring php-laravel"
13
+ [ai]="python-ml local-llm"
14
+ [cli]="python-cli sdk-library"
15
+ [plugins]="browser-extension vscode-extension jetbrains-plugin"
16
+ [embedded]="esp32 stm32 ros car-infotainment"
17
+ [security]="security-tools"
18
+ [cloud]="docker kubernetes ci-cd-pipelines payment-integration"
19
+ [cross-platform]="multiplatform"
20
+ )
21
+
22
+ ALL_CATEGORIES="${!CAT_FW[*]}"
23
+ ALL_FRAMEWORKS=""
24
+ for fw in "${CAT_FW[@]}"; do ALL_FRAMEWORKS="$ALL_FRAMEWORKS $fw"; done
25
+
26
+ # Parse --only flag
27
+ ONLY=""
28
+ for arg in "$@"; do
29
+ if [ "$prev" = "--only" ]; then
30
+ ONLY="$arg"
31
+ fi
32
+ prev="$arg"
33
+ done
34
+
35
+ # Colors
36
+ GREEN='\033[0;32m'
37
+ YELLOW='\033[1;33m'
38
+ NC='\033[0m'
39
+
40
+ echo "🔧 Installing packwise-skills..."
41
+ echo ""
42
+
43
+ # Detect AI agent
44
+ INSTALL_PATH=""
45
+ if [ -d "$HOME/.claude" ]; then
46
+ INSTALL_PATH="$HOME/.claude/skills/$SKILL_NAME"
47
+ AGENT="Claude Code (user-level)"
48
+ elif [ -d ".claude" ]; then
49
+ INSTALL_PATH=".claude/skills/$SKILL_NAME"
50
+ AGENT="Claude Code (project-level)"
51
+ elif [ -d ".cursor" ]; then
52
+ INSTALL_PATH=".cursor/skills/$SKILL_NAME"
53
+ AGENT="Cursor"
54
+ elif [ -d ".opencode" ]; then
55
+ INSTALL_PATH=".opencode/skills/$SKILL_NAME"
56
+ AGENT="OpenCode"
57
+ else
58
+ INSTALL_PATH="skills/$SKILL_NAME"
59
+ AGENT="Generic (skills/ directory)"
60
+ fi
61
+
62
+ echo -e "📦 Detected agent: ${YELLOW}${AGENT}${NC}"
63
+ echo -e "📁 Install path: ${INSTALL_PATH}"
64
+ echo ""
65
+
66
+ # Clone to temp
67
+ TMP_DIR=$(mktemp -d)
68
+ git clone --depth 1 "$REPO" "$TMP_DIR" > /dev/null 2>&1
69
+ mkdir -p "$INSTALL_PATH"
70
+
71
+ # Always copy core files
72
+ cp "$TMP_DIR/skill.md" "$INSTALL_PATH/"
73
+ cp "$TMP_DIR/audit.md" "$INSTALL_PATH/"
74
+ cp "$TMP_DIR/CLAUDE.md" "$INSTALL_PATH/"
75
+
76
+ # Copy sub-skills
77
+ if [ -n "$ONLY" ]; then
78
+ IFS=',' read -ra ITEMS <<< "$ONLY"
79
+ mkdir -p "$INSTALL_PATH/sub-skills"
80
+
81
+ for item in "${ITEMS[@]}"; do
82
+ item=$(echo "$item" | tr -d ' ')
83
+
84
+ if [[ -n "${CAT_FW[$item]+x}" ]]; then
85
+ # It's a category — install all frameworks in it
86
+ echo " ✓ Category: $item"
87
+ for fw in ${CAT_FW[$item]}; do
88
+ src="$TMP_DIR/sub-skills/$item/$fw.md"
89
+ if [ -f "$src" ]; then
90
+ mkdir -p "$INSTALL_PATH/sub-skills/$item"
91
+ cp "$src" "$INSTALL_PATH/sub-skills/$item/"
92
+ fi
93
+ done
94
+ elif echo "$ALL_FRAMEWORKS" | grep -qw "$item"; then
95
+ # It's an individual framework — find its category and install
96
+ for cat in "${!CAT_FW[@]}"; do
97
+ if echo "${CAT_FW[$cat]}" | grep -qw "$item"; then
98
+ src="$TMP_DIR/sub-skills/$cat/$item.md"
99
+ if [ -f "$src" ]; then
100
+ mkdir -p "$INSTALL_PATH/sub-skills/$cat"
101
+ cp "$src" "$INSTALL_PATH/sub-skills/$cat/"
102
+ echo " ✓ $cat/$item"
103
+ fi
104
+ break
105
+ fi
106
+ done
107
+ else
108
+ echo " ⚠ Unknown: $item"
109
+ fi
110
+ done
111
+ else
112
+ cp -r "$TMP_DIR/sub-skills" "$INSTALL_PATH/"
113
+ fi
114
+
115
+ rm -rf "$TMP_DIR"
116
+
117
+ echo ""
118
+ echo -e "${GREEN}✅ packwise-skills installed successfully!${NC}"
119
+ echo ""
120
+ echo "Next steps:"
121
+ echo " Open your AI agent and say:"
122
+ echo " > package my Electron app for Windows"
123
+ echo ""