agentic-skill-mill 1.0.9 → 1.0.11

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/install.js ADDED
@@ -0,0 +1,555 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Unified install script for agentic-skill-mill.
4
+ *
5
+ * Cross-platform Node.js implementation that replaces:
6
+ * - install.sh / install.ps1
7
+ * - install-local.sh / install-local.ps1
8
+ *
9
+ * Usage:
10
+ * node install.js [options]
11
+ *
12
+ * Options:
13
+ * --claude Install skills for Claude Code
14
+ * --cursor Install skills for Cursor
15
+ * --windsurf Install skills for Windsurf
16
+ * --opencode Install skills for OpenCode
17
+ * --codex Install skills for Codex
18
+ * --all Install for all five tools
19
+ * --skills-only Skip npm install/build/link (just copy skills)
20
+ * --uninstall Remove installed skills from target tools
21
+ * --compile-only Generate compiled/ output directory (no install)
22
+ * -h, --help Show this help
23
+ *
24
+ * If no flags are provided, the script auto-detects installed tools.
25
+ */
26
+
27
+ import fs from 'node:fs';
28
+ import path from 'node:path';
29
+ import os from 'node:os';
30
+ import { spawnSync } from 'node:child_process';
31
+ import { fileURLToPath } from 'node:url';
32
+
33
+ const __filename = fileURLToPath(import.meta.url);
34
+ const repoDir = path.dirname(path.resolve(__filename));
35
+
36
+ // --- Constants -------------------------------------------------------------
37
+
38
+ const MANAGED_MARKER = 'managed_by: agentic-skill-mill';
39
+ const PROJECT_NAME = 'agentic-skill-mill';
40
+ const CLI_BIN_NAME = 'skillmill';
41
+ const SKILL_NAME = 'agentic-skill-mill';
42
+
43
+ const HOME = os.homedir();
44
+ const APPDATA = process.env.APPDATA;
45
+
46
+ // --- Source dirs (compiled output) -------------------------------------
47
+
48
+ const COMPILED_DIR = path.join(repoDir, 'compiled');
49
+
50
+ const SRC = {
51
+ claude: path.join(COMPILED_DIR, 'claude', SKILL_NAME),
52
+ cursorSkills: path.join(COMPILED_DIR, 'cursor', 'skills'),
53
+ windsurfSkills: path.join(COMPILED_DIR, 'windsurf', 'skills'),
54
+ opencode: path.join(COMPILED_DIR, 'opencode'),
55
+ codex: path.join(COMPILED_DIR, 'codex', SKILL_NAME),
56
+ };
57
+
58
+ // --- Target directories -----------------------------------------------------
59
+
60
+ const DEST = {
61
+ claude: path.join(HOME, '.claude', 'skills', SKILL_NAME),
62
+ cursorSkills: path.join(HOME, '.cursor', 'skills', SKILL_NAME),
63
+ windsurfSkills: path.join(HOME, '.codeium', 'windsurf', 'skills', SKILL_NAME),
64
+ opencode: path.join(APPDATA || path.join(HOME, '.config', 'opencode'), 'agents'),
65
+ codex: path.join(process.env.CODEX_HOME || path.join(HOME, '.codex'), 'skills', SKILL_NAME),
66
+ };
67
+
68
+ // --- Filesystem helpers ----------------------------------------------------
69
+
70
+ function ensureDir(dir) {
71
+ fs.mkdirSync(dir, { recursive: true });
72
+ }
73
+
74
+ function listFiles(dir, ext) {
75
+ if (!fs.existsSync(dir)) return [];
76
+ return fs.readdirSync(dir)
77
+ .filter((name) => name.endsWith(ext))
78
+ .map((name) => path.join(dir, name));
79
+ }
80
+
81
+ function readText(file) {
82
+ return fs.readFileSync(file, 'utf8');
83
+ }
84
+
85
+ function writeText(file, content) {
86
+ ensureDir(path.dirname(file));
87
+ fs.writeFileSync(file, content);
88
+ }
89
+
90
+ function fileExists(file) {
91
+ try {
92
+ return fs.statSync(file).isFile();
93
+ } catch {
94
+ return false;
95
+ }
96
+ }
97
+
98
+ function dirExists(dir) {
99
+ try {
100
+ return fs.statSync(dir).isDirectory();
101
+ } catch {
102
+ return false;
103
+ }
104
+ }
105
+
106
+ function fileContains(file, marker) {
107
+ if (!fileExists(file)) return false;
108
+ return readText(file).includes(marker);
109
+ }
110
+
111
+ function cleanupManagedFiles(destDir) {
112
+ if (!dirExists(destDir)) return;
113
+ const walk = (d) => {
114
+ for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
115
+ const full = path.join(d, entry.name);
116
+ if (entry.isDirectory()) {
117
+ walk(full);
118
+ } else if (entry.isFile() && fileContains(full, MANAGED_MARKER)) {
119
+ fs.unlinkSync(full);
120
+ console.log(` Removed stale: ${full}`);
121
+ // Try to remove empty parent dirs
122
+ const parent = path.dirname(full);
123
+ try {
124
+ if (dirExists(parent) && fs.readdirSync(parent).length === 0) {
125
+ fs.rmdirSync(parent);
126
+ }
127
+ } catch {
128
+ // Ignore errors
129
+ }
130
+ }
131
+ }
132
+ };
133
+ walk(destDir);
134
+ }
135
+
136
+ function copyFile(src, dest) {
137
+ ensureDir(path.dirname(dest));
138
+ fs.copyFileSync(src, dest);
139
+ console.log(` ${dest}`);
140
+ }
141
+
142
+ // --- Shell helpers --------------------------------------------------------
143
+
144
+ function runNode(args, options = {}) {
145
+ const result = spawnSync('node', args, {
146
+ stdio: 'inherit',
147
+ cwd: repoDir,
148
+ ...options,
149
+ });
150
+ if (result.status !== 0) {
151
+ process.exit(result.status ?? 1);
152
+ }
153
+ }
154
+
155
+ function runNpm(args, options = {}) {
156
+ const result = spawnSync('npm', args, {
157
+ stdio: 'inherit',
158
+ cwd: repoDir,
159
+ ...options,
160
+ });
161
+ if (result.status !== 0) {
162
+ process.exit(result.status ?? 1);
163
+ }
164
+ }
165
+
166
+ // --- Install functions ------------------------------------------------------
167
+
168
+ function installClaude() {
169
+ const src = SRC.claude;
170
+ const dest = DEST.claude;
171
+ if (!dirExists(src)) {
172
+ console.log(` Warning: source missing ${src}`);
173
+ return;
174
+ }
175
+ ensureDir(dest);
176
+ const srcFile = path.join(src, 'SKILL.md');
177
+ if (fileExists(srcFile)) {
178
+ copyFile(srcFile, path.join(dest, 'SKILL.md'));
179
+ }
180
+ console.log(` Claude: ${dest}`);
181
+ }
182
+
183
+ function installCursor() {
184
+ // Skills directory only (not rules)
185
+ const srcSkills = SRC.cursorSkills;
186
+ const destSkills = DEST.cursorSkills;
187
+ if (dirExists(srcSkills)) {
188
+ ensureDir(destSkills);
189
+ const srcFile = path.join(srcSkills, 'SKILL.md');
190
+ if (fileExists(srcFile)) {
191
+ copyFile(srcFile, path.join(destSkills, 'SKILL.md'));
192
+ }
193
+ }
194
+ console.log(` Cursor: skills -> ${destSkills}`);
195
+ }
196
+
197
+ function installWindsurf() {
198
+ // Skills directory only (not rules)
199
+ const srcSkills = SRC.windsurfSkills;
200
+ const destSkills = DEST.windsurfSkills;
201
+ if (dirExists(srcSkills)) {
202
+ ensureDir(destSkills);
203
+ const srcFile = path.join(srcSkills, 'SKILL.md');
204
+ if (fileExists(srcFile)) {
205
+ copyFile(srcFile, path.join(destSkills, 'SKILL.md'));
206
+ }
207
+ }
208
+ console.log(` Windsurf: skills -> ${destSkills}`);
209
+ }
210
+
211
+ function installOpenCode() {
212
+ const src = SRC.opencode;
213
+ const dest = DEST.opencode;
214
+ if (!dirExists(src)) {
215
+ console.log(` Warning: source missing ${src}`);
216
+ return;
217
+ }
218
+ ensureDir(dest);
219
+ // opencode uses .md files directly in agents directory
220
+ for (const srcFile of listFiles(src, '.md')) {
221
+ const destFile = path.join(dest, path.basename(srcFile));
222
+ copyFile(srcFile, destFile);
223
+ }
224
+ console.log(` OpenCode: ${dest}`);
225
+ }
226
+
227
+ function installCodex() {
228
+ const src = SRC.codex;
229
+ const dest = DEST.codex;
230
+ if (!dirExists(src)) {
231
+ console.log(` Warning: source missing ${src}`);
232
+ return;
233
+ }
234
+ ensureDir(dest);
235
+ const srcFile = path.join(src, 'SKILL.md');
236
+ if (fileExists(srcFile)) {
237
+ copyFile(srcFile, path.join(dest, 'SKILL.md'));
238
+ }
239
+ console.log(` Codex: ${dest}`);
240
+ }
241
+
242
+ // --- Uninstall functions ---------------------------------------------------
243
+
244
+ function uninstallClaude() {
245
+ const dest = DEST.claude;
246
+ if (dirExists(dest)) {
247
+ fs.rmSync(dest, { recursive: true, force: true });
248
+ }
249
+ console.log(` Claude: removed`);
250
+ }
251
+
252
+ function uninstallCursor() {
253
+ const destSkills = DEST.cursorSkills;
254
+ if (dirExists(destSkills)) {
255
+ fs.rmSync(destSkills, { recursive: true, force: true });
256
+ }
257
+ console.log(` Cursor: removed`);
258
+ }
259
+
260
+ function uninstallWindsurf() {
261
+ const destSkills = DEST.windsurfSkills;
262
+ if (dirExists(destSkills)) {
263
+ fs.rmSync(destSkills, { recursive: true, force: true });
264
+ }
265
+ console.log(` Windsurf: removed`);
266
+ }
267
+
268
+ function uninstallOpenCode() {
269
+ const dest = DEST.opencode;
270
+ if (dirExists(dest)) {
271
+ for (const f of listFiles(dest, '.md')) {
272
+ if (fileContains(f, MANAGED_MARKER)) {
273
+ fs.unlinkSync(f);
274
+ }
275
+ }
276
+ }
277
+ console.log(` OpenCode: removed`);
278
+ }
279
+
280
+ function uninstallCodex() {
281
+ const dest = DEST.codex;
282
+ if (dirExists(dest)) {
283
+ fs.rmSync(dest, { recursive: true, force: true });
284
+ }
285
+ console.log(` Codex: removed`);
286
+ }
287
+
288
+ // --- Auto-detection -------------------------------------------------------
289
+
290
+ function detectEditors() {
291
+ const detected = [];
292
+ if (dirExists(path.join(HOME, '.claude'))) detected.push('claude');
293
+ if (dirExists(path.join(HOME, '.cursor'))) detected.push('cursor');
294
+ if (
295
+ dirExists(path.join(HOME, '.windsurf')) ||
296
+ dirExists(path.join(HOME, '.codeium', 'windsurf'))
297
+ ) {
298
+ detected.push('windsurf');
299
+ }
300
+ if (
301
+ dirExists(path.join(APPDATA || path.join(HOME, '.config', 'opencode'))) ||
302
+ dirExists(path.join(HOME, '.config', 'opencode'))
303
+ ) {
304
+ detected.push('opencode');
305
+ }
306
+ if (
307
+ process.env.CODEX_HOME ||
308
+ dirExists(path.join(HOME, '.codex'))
309
+ ) {
310
+ detected.push('codex');
311
+ }
312
+ return detected;
313
+ }
314
+
315
+ // --- CLI parsing ---------------------------------------------------------
316
+
317
+ function printHelp() {
318
+ process.stdout.write(`Usage: node install.js [options]
319
+
320
+ Options:
321
+ --claude Install skills for Claude Code
322
+ --cursor Install skills for Cursor
323
+ --windsurf Install skills for Windsurf
324
+ --opencode Install skills for OpenCode
325
+ --codex Install skills for Codex
326
+ --all Install for all five tools
327
+ --skills-only Skip npm install/build/link (just copy skills)
328
+ --uninstall Remove installed skills from target tools
329
+ --compile-only Generate compiled/ output directory (no install)
330
+ -h, --help Show this help
331
+
332
+ No flags = auto-detect installed tools.
333
+
334
+ Environment overrides:
335
+ CODEX_HOME Codex home directory (default: ~/.codex)
336
+ `);
337
+ }
338
+
339
+ function parseArgs(argv) {
340
+ const targets = [];
341
+ const flags = {
342
+ help: false,
343
+ skillsOnly: false,
344
+ uninstall: false,
345
+ compileOnly: false,
346
+ all: false,
347
+ };
348
+
349
+ for (const arg of argv) {
350
+ switch (arg) {
351
+ case '--claude':
352
+ targets.push('claude');
353
+ break;
354
+ case '--cursor':
355
+ targets.push('cursor');
356
+ break;
357
+ case '--windsurf':
358
+ targets.push('windsurf');
359
+ break;
360
+ case '--opencode':
361
+ targets.push('opencode');
362
+ break;
363
+ case '--codex':
364
+ targets.push('codex');
365
+ break;
366
+ case '--all':
367
+ flags.all = true;
368
+ break;
369
+ case '--skills-only':
370
+ flags.skillsOnly = true;
371
+ break;
372
+ case '--uninstall':
373
+ flags.uninstall = true;
374
+ break;
375
+ case '--compile-only':
376
+ flags.compileOnly = true;
377
+ break;
378
+ case '-h':
379
+ case '--help':
380
+ flags.help = true;
381
+ break;
382
+ default:
383
+ console.error(`Unknown option: ${arg}`);
384
+ console.error('Run: node install.js --help');
385
+ process.exit(1);
386
+ }
387
+ }
388
+
389
+ if (flags.all) {
390
+ targets.length = 0;
391
+ targets.push('claude', 'cursor', 'windsurf', 'opencode', 'codex');
392
+ }
393
+
394
+ return { targets, flags };
395
+ }
396
+
397
+ // --- Build orchestration -------------------------------------------------
398
+
399
+ function buildProject() {
400
+ console.log('--> Installing dependencies...');
401
+ runNpm(['install']);
402
+
403
+ console.log('--> Cleaning previous build...');
404
+ const distDir = path.join(repoDir, 'dist');
405
+ if (dirExists(distDir)) {
406
+ fs.rmSync(distDir, { recursive: true });
407
+ }
408
+
409
+ console.log('--> Building TypeScript...');
410
+ runNpm(['run', 'build']);
411
+
412
+ const distCli = path.join(distDir, 'cli', 'index.js');
413
+ if (fileExists(distCli)) {
414
+ fs.chmodSync(distCli, 0o755);
415
+ }
416
+
417
+ console.log('--> Compiling skills...');
418
+ runNpm(['run', 'compile']);
419
+
420
+ console.log('--> Linking CLI globally...');
421
+ runNpm(['link']);
422
+
423
+ // Verify CLI is available
424
+ const npmPrefix = spawnSync('npm', ['prefix', '-g'], { encoding: 'utf8' }).stdout.trim();
425
+ const cliPath = path.join(npmPrefix, 'bin', CLI_BIN_NAME);
426
+ const cliPathAlt = path.join(npmPrefix, 'bin', `${CLI_BIN_NAME}.cmd`);
427
+
428
+ if (fileExists(cliPath) || fileExists(cliPathAlt)) {
429
+ console.log(` ${CLI_BIN_NAME}: ${cliPath}`);
430
+ } else {
431
+ console.log(` Warning: ${CLI_BIN_NAME} not found after npm link. Try: npm link`);
432
+ }
433
+ }
434
+
435
+ // --- Main -----------------------------------------------------------------
436
+
437
+ function main(argv) {
438
+ const { targets, flags } = parseArgs(argv);
439
+
440
+ if (flags.help) {
441
+ printHelp();
442
+ return;
443
+ }
444
+
445
+ // Compile-only path
446
+ if (flags.compileOnly) {
447
+ console.log('==> Compiling skills...');
448
+ runNode([path.join(repoDir, 'skill', 'build', 'compile.mjs')]);
449
+ console.log('==> Done.');
450
+ return;
451
+ }
452
+
453
+ // Resolve targets
454
+ let resolvedTargets = targets.length > 0 ? targets : detectEditors();
455
+
456
+ if (resolvedTargets.length === 0) {
457
+ console.error(
458
+ 'ERROR: No supported tools detected. Use --claude, --cursor, --windsurf, --opencode, or --codex.'
459
+ );
460
+ process.exit(1);
461
+ }
462
+ // Dedupe
463
+ resolvedTargets = [...new Set(resolvedTargets)];
464
+
465
+ console.log(`==> ${PROJECT_NAME} setup`);
466
+ console.log(` Project: ${repoDir}`);
467
+ console.log(` Targets: ${resolvedTargets.join(' ')}`);
468
+ console.log('');
469
+
470
+ // Uninstall path
471
+ if (flags.uninstall) {
472
+ console.log('==> Uninstalling...');
473
+ for (const t of resolvedTargets) {
474
+ switch (t) {
475
+ case 'claude':
476
+ uninstallClaude();
477
+ break;
478
+ case 'cursor':
479
+ uninstallCursor();
480
+ break;
481
+ case 'windsurf':
482
+ uninstallWindsurf();
483
+ break;
484
+ case 'opencode':
485
+ uninstallOpenCode();
486
+ break;
487
+ case 'codex':
488
+ uninstallCodex();
489
+ break;
490
+ }
491
+ }
492
+
493
+ console.log('--> Removing CLI link...');
494
+ runNpm(['unlink', PROJECT_NAME]);
495
+
496
+ console.log('');
497
+ console.log('==> Done. Skills and CLI removed.');
498
+ return;
499
+ }
500
+
501
+ // Install path
502
+ if (!flags.skillsOnly) {
503
+ buildProject();
504
+ }
505
+
506
+ console.log('--> Cleaning stale files...');
507
+ for (const t of resolvedTargets) {
508
+ switch (t) {
509
+ case 'claude':
510
+ cleanupManagedFiles(DEST.claude);
511
+ break;
512
+ case 'cursor':
513
+ cleanupManagedFiles(DEST.cursorSkills);
514
+ break;
515
+ case 'windsurf':
516
+ cleanupManagedFiles(DEST.windsurfSkills);
517
+ break;
518
+ case 'opencode':
519
+ cleanupManagedFiles(DEST.opencode);
520
+ break;
521
+ case 'codex':
522
+ cleanupManagedFiles(DEST.codex);
523
+ break;
524
+ }
525
+ }
526
+
527
+ console.log('--> Installing skills...');
528
+ for (const t of resolvedTargets) {
529
+ switch (t) {
530
+ case 'claude':
531
+ installClaude();
532
+ break;
533
+ case 'cursor':
534
+ installCursor();
535
+ break;
536
+ case 'windsurf':
537
+ installWindsurf();
538
+ break;
539
+ case 'opencode':
540
+ installOpenCode();
541
+ break;
542
+ case 'codex':
543
+ installCodex();
544
+ break;
545
+ }
546
+ }
547
+
548
+ console.log('');
549
+ console.log('==> Done.');
550
+ console.log('');
551
+ console.log(`Skills installed for: ${resolvedTargets.join(' ')}`);
552
+ console.log(`CLI available as: ${CLI_BIN_NAME}`);
553
+ }
554
+
555
+ main(process.argv.slice(2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-skill-mill",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Forge and refine agent skill projects -- fragment-composed skills compiled to 7 IDE targets with a companion CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,10 +19,7 @@
19
19
  "compiled",
20
20
  "skill",
21
21
  "README.md",
22
- "install.sh",
23
- "install-local.sh",
24
- "install.ps1",
25
- "install-local.ps1"
22
+ "install.js"
26
23
  ],
27
24
  "scripts": {
28
25
  "build": "tsc -p tsconfig.build.json",
@@ -31,14 +28,14 @@
31
28
  "test:coverage": "vitest run --coverage",
32
29
  "lint": "eslint src",
33
30
  "typecheck": "tsc --noEmit",
34
- "setup": "bash install-local.sh",
35
- "setup:all": "bash install-local.sh --all",
36
- "setup:windows": "powershell -ExecutionPolicy Bypass -File ./install-local.ps1",
37
- "setup:windows:all": "powershell -ExecutionPolicy Bypass -File ./install-local.ps1 --all",
38
- "install-skills": "bash install-local.sh --skills-only",
39
- "install-skills:windows": "powershell -ExecutionPolicy Bypass -File ./install-local.ps1 --skills-only",
40
- "uninstall-skills": "bash install-local.sh --uninstall",
41
- "uninstall-skills:windows": "powershell -ExecutionPolicy Bypass -File ./install-local.ps1 --uninstall",
31
+ "setup": "node install.js",
32
+ "setup:all": "node install.js --all",
33
+ "setup:windows": "node install.js",
34
+ "setup:windows:all": "node install.js --all",
35
+ "install-skills": "node install.js --skills-only",
36
+ "install-skills:windows": "node install.js --skills-only",
37
+ "uninstall-skills": "node install.js --uninstall",
38
+ "uninstall-skills:windows": "node install.js --uninstall",
42
39
  "compile": "node skill/build/compile.mjs",
43
40
  "compile:validate": "node skill/build/compile.mjs --validate",
44
41
  "compile:watch": "node skill/build/compile.mjs --watch"
@@ -1,9 +1,7 @@
1
1
  {
2
2
  "targets": [
3
3
  "claude",
4
- "cursor-rules",
5
4
  "cursor-skills",
6
- "windsurf-rules",
7
5
  "windsurf-skills",
8
6
  "opencode",
9
7
  "codex"
@@ -6,7 +6,7 @@ Skills (what to do) CLI Companion (tools to do it with)
6
6
  skill/fragments/*.md src/core/*.ts
7
7
  | |
8
8
  v v
9
- compiled/ (7 IDE formats) dist/ (npm -> npx or global CLI)
9
+ compiled/ (5 IDE formats) dist/ (npm -> npx or global CLI)
10
10
  | |
11
11
  +---------> Agent <----------+
12
12
  ^
@@ -31,7 +31,9 @@ Skills (what to do) CLI Companion (tools to do it with)
31
31
  - `src/errors/types.ts` — Typed error hierarchy (AppError, NotFoundError, etc.)
32
32
  - `src/cache/cache-manager.ts` — Two-tier cache (memory + disk) with TTL
33
33
 
34
- **The local installer** (`install-local.sh`) builds the CLI, compiles skills, and copies compiled outputs to IDE-specific directories (~/.claude/skills, ~/.cursor/rules, etc.) with marker-based stale file cleanup. The bootstrap installer is hosted at `https://agenticskillmill.com/install.sh` (source: `site/install.sh`) and is also bundled in the npm package as `install.sh`. It installs the npm utility first, then delegates to `install-local.sh --skills-only`. Local installer functions use `set -e` for fail-fast behavior. Any function that uses an early-exit guard (`[[ -d ... ]] || return`, `[[ -z ... ]] && return`) **must** use `return 0`, never bare `return`. Bare `return` inherits the exit code of the last command, which for a failed conditional test is 1 -- and `set -e` treats that as a script-terminating failure with no error message.
34
+ **Local installers:** Every project ships a single cross-platform `install.js` (Node.js).
35
+
36
+ **The installer** (`install.js`) builds the CLI, compiles skills, and copies compiled outputs to IDE-specific directories (~/.claude/skills, ~/.cursor/rules, etc.) with marker-based stale file cleanup. The bootstrap installer is hosted at `https://agenticskillmill.com/install.sh` and bundled in the npm package. It installs the npm utility first, then delegates to `node install.js --skills-only`.
35
37
 
36
38
  ### Key files to modify when augmenting a project
37
39
 
@@ -39,8 +41,8 @@ Skills (what to do) CLI Companion (tools to do it with)
39
41
  |------|---------|
40
42
  | Add a CLI command | `src/core/<name>.ts`, `src/cli/commands/<name>.ts`, `src/cli/index.ts`, `src/index.ts` |
41
43
  | Add a fragment | `skill/fragments/<category>/<name>.md`, `skill/build/manifest.json`, skill source |
42
- | Add a skill | `skill/skills/<name>/<name>.md`, `skill/build/manifest.json`, `install-local.sh` SKILLS array |
43
- | Change installer behavior | `install.sh` (repo root) then copy to `site/install.sh` |
44
+ | Add a skill | `skill/skills/<name>/<name>.md`, `skill/build/manifest.json` |
45
+ | Change installer behavior | `install.js`, then copy to `site/install.sh` and `site/install.ps1` |
44
46
  | Update the landing page | `site/index.html`, `site/style.css` |
45
47
  | Change CI secrets or workflow | `.github/workflows/release.yml` or `deploy-pages.yml`, repo settings |
46
48
  | Rename the project | See the rename workflow |