@lyupro/skillforge-mcp 1.1.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 (221) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/LICENSE +21 -0
  3. package/README.md +231 -0
  4. package/dist/cli/install.d.ts +41 -0
  5. package/dist/cli/install.d.ts.map +1 -0
  6. package/dist/cli/install.js +223 -0
  7. package/dist/cli/install.js.map +1 -0
  8. package/dist/config/config-schema.d.ts +175 -0
  9. package/dist/config/config-schema.d.ts.map +1 -0
  10. package/dist/config/config-schema.js +49 -0
  11. package/dist/config/config-schema.js.map +1 -0
  12. package/dist/config/config-store.d.ts +24 -0
  13. package/dist/config/config-store.d.ts.map +1 -0
  14. package/dist/config/config-store.js +67 -0
  15. package/dist/config/config-store.js.map +1 -0
  16. package/dist/config/index.d.ts +5 -0
  17. package/dist/config/index.d.ts.map +1 -0
  18. package/dist/config/index.js +3 -0
  19. package/dist/config/index.js.map +1 -0
  20. package/dist/config.d.ts +25 -0
  21. package/dist/config.d.ts.map +1 -0
  22. package/dist/config.js +73 -0
  23. package/dist/config.js.map +1 -0
  24. package/dist/core/errors.d.ts +9 -0
  25. package/dist/core/errors.d.ts.map +1 -0
  26. package/dist/core/errors.js +13 -0
  27. package/dist/core/errors.js.map +1 -0
  28. package/dist/core/index.d.ts +6 -0
  29. package/dist/core/index.d.ts.map +1 -0
  30. package/dist/core/index.js +5 -0
  31. package/dist/core/index.js.map +1 -0
  32. package/dist/core/skill-content-cache.d.ts +18 -0
  33. package/dist/core/skill-content-cache.d.ts.map +1 -0
  34. package/dist/core/skill-content-cache.js +56 -0
  35. package/dist/core/skill-content-cache.js.map +1 -0
  36. package/dist/core/skill-metadata-cache.d.ts +15 -0
  37. package/dist/core/skill-metadata-cache.d.ts.map +1 -0
  38. package/dist/core/skill-metadata-cache.js +31 -0
  39. package/dist/core/skill-metadata-cache.js.map +1 -0
  40. package/dist/core/skill-registry.d.ts +12 -0
  41. package/dist/core/skill-registry.d.ts.map +1 -0
  42. package/dist/core/skill-registry.js +28 -0
  43. package/dist/core/skill-registry.js.map +1 -0
  44. package/dist/core/skill-resolver.d.ts +6 -0
  45. package/dist/core/skill-resolver.d.ts.map +1 -0
  46. package/dist/core/skill-resolver.js +32 -0
  47. package/dist/core/skill-resolver.js.map +1 -0
  48. package/dist/core/types.d.ts +80 -0
  49. package/dist/core/types.d.ts.map +1 -0
  50. package/dist/core/types.js +10 -0
  51. package/dist/core/types.js.map +1 -0
  52. package/dist/decorators/base-decorator.d.ts +10 -0
  53. package/dist/decorators/base-decorator.d.ts.map +1 -0
  54. package/dist/decorators/base-decorator.js +13 -0
  55. package/dist/decorators/base-decorator.js.map +1 -0
  56. package/dist/decorators/cache-decorator.d.ts +33 -0
  57. package/dist/decorators/cache-decorator.d.ts.map +1 -0
  58. package/dist/decorators/cache-decorator.js +89 -0
  59. package/dist/decorators/cache-decorator.js.map +1 -0
  60. package/dist/decorators/decorator-chain.d.ts +16 -0
  61. package/dist/decorators/decorator-chain.d.ts.map +1 -0
  62. package/dist/decorators/decorator-chain.js +31 -0
  63. package/dist/decorators/decorator-chain.js.map +1 -0
  64. package/dist/decorators/index.d.ts +10 -0
  65. package/dist/decorators/index.d.ts.map +1 -0
  66. package/dist/decorators/index.js +6 -0
  67. package/dist/decorators/index.js.map +1 -0
  68. package/dist/decorators/logging-decorator.d.ts +15 -0
  69. package/dist/decorators/logging-decorator.d.ts.map +1 -0
  70. package/dist/decorators/logging-decorator.js +34 -0
  71. package/dist/decorators/logging-decorator.js.map +1 -0
  72. package/dist/decorators/timeout-decorator.d.ts +19 -0
  73. package/dist/decorators/timeout-decorator.d.ts.map +1 -0
  74. package/dist/decorators/timeout-decorator.js +59 -0
  75. package/dist/decorators/timeout-decorator.js.map +1 -0
  76. package/dist/factory/index.d.ts +2 -0
  77. package/dist/factory/index.d.ts.map +1 -0
  78. package/dist/factory/index.js +2 -0
  79. package/dist/factory/index.js.map +1 -0
  80. package/dist/factory/strategy-factory.d.ts +10 -0
  81. package/dist/factory/strategy-factory.d.ts.map +1 -0
  82. package/dist/factory/strategy-factory.js +37 -0
  83. package/dist/factory/strategy-factory.js.map +1 -0
  84. package/dist/handlers/composite-resolver.d.ts +34 -0
  85. package/dist/handlers/composite-resolver.d.ts.map +1 -0
  86. package/dist/handlers/composite-resolver.js +94 -0
  87. package/dist/handlers/composite-resolver.js.map +1 -0
  88. package/dist/handlers/hybrid-strategy.d.ts +14 -0
  89. package/dist/handlers/hybrid-strategy.d.ts.map +1 -0
  90. package/dist/handlers/hybrid-strategy.js +42 -0
  91. package/dist/handlers/hybrid-strategy.js.map +1 -0
  92. package/dist/handlers/index.d.ts +3 -0
  93. package/dist/handlers/index.d.ts.map +1 -0
  94. package/dist/handlers/index.js +2 -0
  95. package/dist/handlers/index.js.map +1 -0
  96. package/dist/handlers/invocation-strategy.d.ts +17 -0
  97. package/dist/handlers/invocation-strategy.d.ts.map +1 -0
  98. package/dist/handlers/invocation-strategy.js +2 -0
  99. package/dist/handlers/invocation-strategy.js.map +1 -0
  100. package/dist/handlers/prompt-strategy.d.ts +8 -0
  101. package/dist/handlers/prompt-strategy.d.ts.map +1 -0
  102. package/dist/handlers/prompt-strategy.js +31 -0
  103. package/dist/handlers/prompt-strategy.js.map +1 -0
  104. package/dist/handlers/script-strategy.d.ts +20 -0
  105. package/dist/handlers/script-strategy.d.ts.map +1 -0
  106. package/dist/handlers/script-strategy.js +87 -0
  107. package/dist/handlers/script-strategy.js.map +1 -0
  108. package/dist/installers/atomic-write.d.ts +13 -0
  109. package/dist/installers/atomic-write.d.ts.map +1 -0
  110. package/dist/installers/atomic-write.js +98 -0
  111. package/dist/installers/atomic-write.js.map +1 -0
  112. package/dist/installers/claude-installer.d.ts +26 -0
  113. package/dist/installers/claude-installer.d.ts.map +1 -0
  114. package/dist/installers/claude-installer.js +118 -0
  115. package/dist/installers/claude-installer.js.map +1 -0
  116. package/dist/installers/codex-installer.d.ts +30 -0
  117. package/dist/installers/codex-installer.d.ts.map +1 -0
  118. package/dist/installers/codex-installer.js +125 -0
  119. package/dist/installers/codex-installer.js.map +1 -0
  120. package/dist/installers/cursor-installer.d.ts +29 -0
  121. package/dist/installers/cursor-installer.d.ts.map +1 -0
  122. package/dist/installers/cursor-installer.js +126 -0
  123. package/dist/installers/cursor-installer.js.map +1 -0
  124. package/dist/installers/paths.d.ts +20 -0
  125. package/dist/installers/paths.d.ts.map +1 -0
  126. package/dist/installers/paths.js +50 -0
  127. package/dist/installers/paths.js.map +1 -0
  128. package/dist/installers/registry.d.ts +8 -0
  129. package/dist/installers/registry.d.ts.map +1 -0
  130. package/dist/installers/registry.js +18 -0
  131. package/dist/installers/registry.js.map +1 -0
  132. package/dist/installers/types.d.ts +45 -0
  133. package/dist/installers/types.d.ts.map +1 -0
  134. package/dist/installers/types.js +9 -0
  135. package/dist/installers/types.js.map +1 -0
  136. package/dist/parser/file-scanner.d.ts +10 -0
  137. package/dist/parser/file-scanner.d.ts.map +1 -0
  138. package/dist/parser/file-scanner.js +37 -0
  139. package/dist/parser/file-scanner.js.map +1 -0
  140. package/dist/parser/format-detector.d.ts +11 -0
  141. package/dist/parser/format-detector.d.ts.map +1 -0
  142. package/dist/parser/format-detector.js +13 -0
  143. package/dist/parser/format-detector.js.map +1 -0
  144. package/dist/parser/frontmatter-parser.d.ts +14 -0
  145. package/dist/parser/frontmatter-parser.d.ts.map +1 -0
  146. package/dist/parser/frontmatter-parser.js +98 -0
  147. package/dist/parser/frontmatter-parser.js.map +1 -0
  148. package/dist/parser/index.d.ts +4 -0
  149. package/dist/parser/index.d.ts.map +1 -0
  150. package/dist/parser/index.js +4 -0
  151. package/dist/parser/index.js.map +1 -0
  152. package/dist/parser/scripts-dir-detector.d.ts +7 -0
  153. package/dist/parser/scripts-dir-detector.d.ts.map +1 -0
  154. package/dist/parser/scripts-dir-detector.js +17 -0
  155. package/dist/parser/scripts-dir-detector.js.map +1 -0
  156. package/dist/security/blacklist-filter.d.ts +32 -0
  157. package/dist/security/blacklist-filter.d.ts.map +1 -0
  158. package/dist/security/blacklist-filter.js +35 -0
  159. package/dist/security/blacklist-filter.js.map +1 -0
  160. package/dist/security/index.d.ts +5 -0
  161. package/dist/security/index.d.ts.map +1 -0
  162. package/dist/security/index.js +3 -0
  163. package/dist/security/index.js.map +1 -0
  164. package/dist/security/pattern-scanner.d.ts +27 -0
  165. package/dist/security/pattern-scanner.d.ts.map +1 -0
  166. package/dist/security/pattern-scanner.js +46 -0
  167. package/dist/security/pattern-scanner.js.map +1 -0
  168. package/dist/security/sandbox-runner.d.ts +48 -0
  169. package/dist/security/sandbox-runner.d.ts.map +1 -0
  170. package/dist/security/sandbox-runner.js +131 -0
  171. package/dist/security/sandbox-runner.js.map +1 -0
  172. package/dist/server-deps.d.ts +28 -0
  173. package/dist/server-deps.d.ts.map +1 -0
  174. package/dist/server-deps.js +2 -0
  175. package/dist/server-deps.js.map +1 -0
  176. package/dist/server.d.ts +12 -0
  177. package/dist/server.d.ts.map +1 -0
  178. package/dist/server.js +174 -0
  179. package/dist/server.js.map +1 -0
  180. package/dist/tools/configure.d.ts +22 -0
  181. package/dist/tools/configure.d.ts.map +1 -0
  182. package/dist/tools/configure.js +126 -0
  183. package/dist/tools/configure.js.map +1 -0
  184. package/dist/tools/get.d.ts +10 -0
  185. package/dist/tools/get.d.ts.map +1 -0
  186. package/dist/tools/get.js +20 -0
  187. package/dist/tools/get.js.map +1 -0
  188. package/dist/tools/index.d.ts +9 -0
  189. package/dist/tools/index.d.ts.map +1 -0
  190. package/dist/tools/index.js +7 -0
  191. package/dist/tools/index.js.map +1 -0
  192. package/dist/tools/invoke.d.ts +12 -0
  193. package/dist/tools/invoke.d.ts.map +1 -0
  194. package/dist/tools/invoke.js +36 -0
  195. package/dist/tools/invoke.js.map +1 -0
  196. package/dist/tools/list.d.ts +16 -0
  197. package/dist/tools/list.d.ts.map +1 -0
  198. package/dist/tools/list.js +33 -0
  199. package/dist/tools/list.js.map +1 -0
  200. package/dist/tools/loader.d.ts +30 -0
  201. package/dist/tools/loader.d.ts.map +1 -0
  202. package/dist/tools/loader.js +92 -0
  203. package/dist/tools/loader.js.map +1 -0
  204. package/dist/tools/reload.d.ts +22 -0
  205. package/dist/tools/reload.d.ts.map +1 -0
  206. package/dist/tools/reload.js +39 -0
  207. package/dist/tools/reload.js.map +1 -0
  208. package/dist/watcher/chokidar-types.d.ts +20 -0
  209. package/dist/watcher/chokidar-types.d.ts.map +1 -0
  210. package/dist/watcher/chokidar-types.js +2 -0
  211. package/dist/watcher/chokidar-types.js.map +1 -0
  212. package/dist/watcher/folder-watcher.d.ts +27 -0
  213. package/dist/watcher/folder-watcher.d.ts.map +1 -0
  214. package/dist/watcher/folder-watcher.js +123 -0
  215. package/dist/watcher/folder-watcher.js.map +1 -0
  216. package/dist/watcher/index.d.ts +4 -0
  217. package/dist/watcher/index.d.ts.map +1 -0
  218. package/dist/watcher/index.js +2 -0
  219. package/dist/watcher/index.js.map +1 -0
  220. package/manifest.json +96 -0
  221. package/package.json +78 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,114 @@
1
+ # Changelog
2
+
3
+ All notable changes to **SkillForge MCP** are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
+
5
+ ## [1.1.0] — 2026-05-14
6
+
7
+ One-command install across Claude Code, Codex CLI, and Cursor.
8
+
9
+ ### Added
10
+
11
+ - `skillforge install` CLI — wires SkillForge MCP into host tools by editing each host's config file directly.
12
+ - Three installers — Claude Code (`~/.claude.json`), Codex CLI (`~/.codex/config.toml`), Cursor (OS-specific `settings.json`).
13
+ - Flags — `--claude`, `--codex`, `--cursor`, `--all`, `--dry-run`, `--uninstall`, `--force`, `--entry npx|local`, `--binary-path <path>`.
14
+ - Atomic-write helper with `.backup` snapshot — failed write never leaves the host config in a broken state.
15
+ - OS-specific path detection for Cursor (Windows `%APPDATA%`, macOS `Library/Application Support`, Linux `~/.config`).
16
+ - Second package bin — `skillforge` → `./dist/cli/install.js` alongside the existing `skillforge-mcp` stdio server entry.
17
+ - New documentation — [docs/INSTALL_CLI.md](./docs/INSTALL_CLI.md) (flag table, examples, host edit shapes, troubleshooting).
18
+
19
+ ### Verified
20
+
21
+ - 451 / 451 tests passing + 1 win32-skip (+81 new tests for the install CLI).
22
+ - `pnpm lint` (`tsc --noEmit`) clean.
23
+ - `pnpm build` clean.
24
+ - `pnpm check:size` — all 54 source files ≤ 400 lines.
25
+
26
+ ## [1.0.0] — 2026-05-13
27
+
28
+ First public release. Universal Skills MCP server: load Markdown skills from arbitrary folders, lazy-by-design, cross-tool (Claude Code / Codex CLI / Cursor / custom MCP clients).
29
+
30
+ ### Added — MCP tool surface (5 tools)
31
+
32
+ - `skills__list` — enumerate available skills with metadata-only response (filters: `folder`, `search`, `source`).
33
+ - `skills__get` — retrieve full content (body + metadata) of a named skill.
34
+ - `skills__invoke` — invoke a skill by name, forwarding optional input. Composite skills walk nested skills sequentially with DFS cycle detection. Pipeline: Logging → Timeout → Cache → strategy (Prompt / Script / Hybrid).
35
+ - `skills__configure` — manage configured folders, blacklist, reset (actions: `add_folder`, `remove_folder`, `list_folders`, `set_blacklist`, `get_blacklist`, `reset`). Persists to platform config path.
36
+ - `skills__reload` — force a full rescan of all configured folders. Returns `{ loaded, added, removed, errors }` diff.
37
+
38
+ ### Added — Strategies
39
+
40
+ - **PromptStrategy** — default for skills without `scripts` metadata. Returns Markdown body as MCP text content.
41
+ - **ScriptStrategy** — sibling `scripts/` directory + manifest `scripts: [...]` entry. Opt-in via both `config.security.allowScripts = true` and frontmatter `allowScripts: true`. Sandboxed: env whitelist, mkdtemp cwd, AbortSignal kill.
42
+ - **HybridStrategy** — script produces context block prepended to the prompt body. Useful for `git log --since=last-tag` style enrichment.
43
+ - **CompositeResolver** — `skills: [a, b, c]` frontmatter walks nested skills sequentially. DFS cycle detection. Combined output returned.
44
+
45
+ ### Added — Decorators
46
+
47
+ - **LoggingDecorator** — stderr trace of invocation lifecycle. Includes strategy name + ms duration.
48
+ - **TimeoutDecorator** — wraps `InvocationContext.signal` to enforce per-invocation timeout. Default 30s, override via `metadata.timeoutMs`.
49
+ - **CacheDecorator** — opt-in via `metadata.cacheable = true`. Returns identical `InvocationResult` instance (frozen `durationMs`) for repeat invocations within TTL.
50
+
51
+ ### Added — Universal skill format
52
+
53
+ - Markdown body + YAML frontmatter contract.
54
+ - Canonical camelCase frontmatter + 4 snake_case aliases (`allow_scripts` / `allow_network` / `timeout_ms` / `cache_ttl_ms`).
55
+ - Four format dialects auto-detected: Claude (Anthropic), Codex (TOML-flavored), persona (character-style), custom (anything with frontmatter).
56
+ - Strategy decision tree: explicit `kind` field → metadata signals → default Prompt.
57
+
58
+ ### Added — Configuration
59
+
60
+ - Persistent JSON config at the canonical Lyu Pro brand path `~/.lyupro/.skillforge/config.json`, resolved cross-platform via `os.homedir()`. Skills shared content lives under `~/.lyupro/skills/`.
61
+ - Folder cascade with priority — higher priority wins on name conflicts.
62
+ - Blacklist (manual + automatic via `PatternScanner` security audit).
63
+ - Hot reload via `chokidar` `FolderWatcher` — debounced batches, content-cache invalidation.
64
+ - Five worked configs in `examples/configs/`: `default.json`, `team-shared-folder.json`, `team-priority-with-default-fallback.json`, `scripts-enabled.json`, `multifolder-cascade.json`.
65
+
66
+ ### Added — Security
67
+
68
+ - `PatternScanner` audit primitive — regex-based detection of dangerous patterns (`subprocess`, `os.system`, `pickle`, `__import__`, etc.).
69
+ - `BlacklistFilter` — manual entries + auto-flagged via audit. Loader gates skills before registry insertion.
70
+ - `SandboxRunner` for ScriptStrategy — env whitelist (`/usr/bin:/bin` POSIX), `mkdtemp` cwd, stdout/stderr cap (1 MB), AbortSignal kill on timeout, exit-code propagation.
71
+ - `Composite cycle detection` — DFS visited-set throws `CompositeCycleError` on loops.
72
+
73
+ ### Added — Documentation
74
+
75
+ - `README.md` v1.0 — Pain/solution matrix, 60-second Quick Start, badges, status banner.
76
+ - `docs/INSTALL.md` — 4 wiring tracks (Claude Code / Codex CLI / Cursor / manual MCP client), folder-config 3 ways, verify checklist, upgrade/uninstall, 8-row troubleshooting matrix.
77
+ - `docs/SKILL_FORMAT.md` — field-level frontmatter contract, 4 dialects, strategy decision tree, 5 worked examples (prompt / script / hybrid / composite / persona), conflict resolution, validation rules.
78
+ - `docs/CONFIGURATION.md` — env vars + persisted JSON layers, annotated schema (live vs reserved fields), 5 `skills__configure` actions, `skills__reload` semantics, 4 worked configs.
79
+ - `docs/ARCHITECTURE.md` — module map (11 directories), 9 design patterns with local references, full `skills__invoke` request flow trace, 3 cache surfaces, 5 extension points with snippets, rationale for anchor decisions.
80
+ - `docs/SECURITY.md` — threat model (8 in-scope + 5 out-of-scope rows), 5-step SandboxRunner contract, defence-in-depth layers, Windows PATH compromise documentation, operator checklist, responsible-disclosure policy.
81
+ - `docs/INTEGRATION/` — per-tool wiring: claude-code.md, codex.md, cursor.md, custom-llm-tools.md.
82
+
83
+ ### Added — Sample skills
84
+
85
+ 10 production-quality skills in `skills/`:
86
+
87
+ - **6 prompt** — `apple-hig-check`, `refactor-suggester`, `commit-message-writer`, `prompt-optimizer`, `idea-onepager`, `obsidian-resume`.
88
+ - **2 script** — `dependency-checker` (npm audit summariser, `scripts/main.sh`), `markdown-linter` (stdlib-only Python, `scripts/main.py`).
89
+ - **2 hybrid** — `changelog-generator` (git log since last semver tag), `git-blame-summary` (blame + recent commits enriched prompt).
90
+
91
+ All 10 verified through real parse pipeline + `StrategyFactory.create()` correct-kind assertion.
92
+
93
+ ### Added — Marketplace artifacts
94
+
95
+ - `manifest.json` (upstream MCP schema) — 5 tools, env vars, doc pointers, verification commands.
96
+ - `plugin.json` (Claude Code marketplace schema) — install command, exposedTools, honest permissions block (subprocess opt-in, network none, filesystem write = platform config + tmpdir sandbox).
97
+
98
+ ### Fixed — Real-frontmatter promotion (commit `a38e2c4`)
99
+
100
+ - `FrontmatterParser.CONSUMED_KEYS` now promotes `scripts`, `cacheable`, `cache_ttl_ms`, `cacheTtlMs` from real frontmatter. Earlier these fields fell into `extra` because `CONSUMED_KEYS` whitelist was opt-in; `ScriptStrategy.canHandle()` always returned false in the real subprocess pipeline.
101
+ - Defensive extraction: array-of-strings for `scripts`, boolean literal for `cacheable`, finite positive for `cacheTtlMs`.
102
+ - +6 unit tests (promotion, snake_case alias, defensive drops, extra-isolation).
103
+ - +2 integration tests verifying `script-promo` skill triggers `ScriptStrategy` and `cached-prompt` skill activates `CacheDecorator` (second invoke returns identical instance with frozen `durationMs`).
104
+
105
+ ### Verified
106
+
107
+ - **370 / 370** tests passing + 1 win32-skip.
108
+ - **46** source files all ≤ 400 lines (`pnpm check:size`).
109
+ - **`pnpm lint`** (`tsc --noEmit`) clean.
110
+ - **`pnpm build`** clean.
111
+ - **`pnpm smoke`** end-to-end via subprocess `dist/server.js` — LoggingDecorator trace visible.
112
+
113
+ [1.1.0]: https://github.com/lyupro/skillforge-mcp/releases/tag/v1.1.0
114
+ [1.0.0]: https://github.com/lyupro/skillforge-mcp/releases/tag/v1.0.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 lyupro
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,231 @@
1
+ # SkillForge MCP
2
+
3
+ > Universal Skills MCP server — load Markdown skills from arbitrary folders, lazy-by-design, cross-tool.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
6
+ [![Node](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org)
7
+ [![MCP](https://img.shields.io/badge/MCP-stdio-purple)](https://modelcontextprotocol.io)
8
+
9
+ **v1.1.0** — 5 MCP tools, one-command install across Claude Code / Codex CLI / Cursor, 451 tests, 10 sample skills, modular architecture (all source files ≤ 400 lines).
10
+
11
+ ---
12
+
13
+ ## What it is
14
+
15
+ A standalone [Model Context Protocol](https://modelcontextprotocol.io) server that exposes Markdown-defined **skills** (prompts, templates, scripts) to any MCP-capable LLM tool — Claude Code, OpenAI Codex CLI, Cursor, or custom clients via `@modelcontextprotocol/sdk`.
16
+
17
+ One skill folder. One config file. Any tool can ask for any skill on demand.
18
+
19
+ ## Why it exists
20
+
21
+ | Pain | Today | With SkillForge |
22
+ |------|-------|-----------------|
23
+ | Auto-loading 122+ skills per session burns ~4880 tokens on init | Every Claude Code session pays the toll, most skills are never used | Lazy MCP discovery — pay only for `skills__get` / `skills__invoke` calls actually made |
24
+ | Hardcoded paths (`~/.claude/plugins/cache/...`, `~/.codex/skills/`) | One folder, one tool, hardcoded | Multi-folder, per-project, priority-ordered, env override |
25
+ | No cross-tool format | Each tool ships its own skill layout | Universal frontmatter parser auto-detects Claude / Codex / persona / custom dialects |
26
+ | Skill execution = "just inline body in prompt" | No scripts, no caching, no timeouts, no composition | Strategy pattern (prompt / script / hybrid) + decorator chain (logging → timeout → cache) + composite skills with cycle detection |
27
+
28
+ ## One-command install (v1.1)
29
+
30
+ ```bash
31
+ npx @lyupro/skillforge-mcp install --all
32
+ ```
33
+
34
+ Auto-detects Claude Code, Codex CLI, and Cursor on your machine and wires SkillForge into each. Supports `--dry-run`, `--uninstall`, and `--force`. Full reference: [docs/INSTALL_CLI.md](./docs/INSTALL_CLI.md).
35
+
36
+ ## Quick Start
37
+
38
+ ### Option 1 — Claude Code marketplace (recommended)
39
+
40
+ ```bash
41
+ /plugin marketplace add lyupro/llm-plugins-marketplace
42
+ /plugin install skillforge-mcp@lyupro-llm-plugins
43
+ ```
44
+
45
+ Restart your Claude Code session. The five tools (`skills__list`, `skills__get`, `skills__invoke`, `skills__configure`, `skills__reload`) appear in the tool list.
46
+
47
+ ### Option 2 — npm
48
+
49
+ ```bash
50
+ claude mcp add skillforge -- npx -y @lyupro/skillforge-mcp
51
+ ```
52
+
53
+ Works for any MCP host that can spawn a stdio command (Claude Code, Codex CLI, Cursor).
54
+
55
+ ### Option 3 — local build
56
+
57
+ See [Contributing](#contributing).
58
+
59
+ After install, point SkillForge at your skill folder:
60
+
61
+ ```
62
+ > use skills__configure with action="add_folder", folder="/abs/path/to/your/skills"
63
+ > use skills__list
64
+ ```
65
+
66
+ See [docs/INSTALL.md](./docs/INSTALL.md) for Codex CLI, Cursor, and manual MCP-client setups.
67
+
68
+ ## Verify Installation
69
+
70
+ After the install step, run these three checks from inside any wired LLM tool session:
71
+
72
+ 1. `skills__list` — returns an array of skill summaries (possibly empty if no skills folders are configured yet).
73
+ 2. `skills__configure` with `action: "list_folders"` — shows the resolved folder list with priorities and `enabled` flags.
74
+ 3. `skills__reload` — forces a fresh scan, returns `{loaded, added, removed, errors}` diff.
75
+
76
+ If any call fails with `[skillforge] fatal:` on stderr, the most likely cause is a corrupt config file or a missing folder path — the error message points at the offending file. Delete or fix `~/.lyupro/.skillforge/config.json` and retry.
77
+
78
+ ## MCP tool surface
79
+
80
+ | Tool | Purpose |
81
+ |------|---------|
82
+ | `skills__list` | Enumerate available skills (metadata only). Filters: `folder`, `search`, `source`. |
83
+ | `skills__get` | Fetch full SKILL.md body + metadata for one skill. |
84
+ | `skills__invoke` | Execute a skill via its assigned strategy, wrapped in the decorator chain (Logging → Timeout → Cache). Composite skills (`metadata.skills: [a, b]`) walk nested skills sequentially with DFS cycle detection. |
85
+ | `skills__configure` | Manage configured folders + manual blacklist. Actions: `add_folder`, `remove_folder`, `list_folders`, `set_blacklist`, `get_blacklist`, `reset`. Persists to the config file and reconciles in-process state without restart. |
86
+ | `skills__reload` | Force a full rescan of all configured folders. Returns `{ loaded, added, removed, errors }` diff vs. the previous registry snapshot. |
87
+
88
+ ## Configure which folders to scan
89
+
90
+ By default SkillForge scans `~/.claude/plugins/cache/claude-code-skills/`. Override via environment:
91
+
92
+ ```bash
93
+ # Windows (PowerShell)
94
+ $env:SKILLFORGE_FOLDERS = "C:\path\to\skills;C:\other\folder"
95
+
96
+ # macOS / Linux
97
+ export SKILLFORGE_FOLDERS=/home/me/skills:/home/me/team-skills
98
+ ```
99
+
100
+ Path separator is platform-native (`;` on Windows, `:` elsewhere). Or use `skills__configure` to manage the persisted list — see [docs/CONFIGURATION.md](./docs/CONFIGURATION.md).
101
+
102
+ For shared content across multiple tools, the convention is `~/.lyupro/skills/` (Lyu Pro brand shared content folder).
103
+
104
+ ## Persisted config + hot reload
105
+
106
+ - **Config file:** `~/.lyupro/.skillforge/config.json` (resolved cross-platform via `os.homedir()`). Schema-validated via Zod; missing → schema defaults; corrupt JSON / schema → loud error with the file path.
107
+ - **Merge order for folders:** `SKILLFORGE_FOLDERS` env (when set) > persisted `folders[]` with `enabled: true` sorted by `priority` desc > built-in default.
108
+ - **Auto-audit:** `security.autoAudit: true` (default) scans skill bodies on load against `security.auditPatterns` (default: `shell=True`, `eval(`, `exec(`, `base64.b64decode`). Matched skills are excluded and logged to stderr.
109
+ - **Manual blacklist:** `blacklist: string[]` excludes skills by exact name (case-sensitive). Short-circuits before the audit step.
110
+ - **Hot reload:** chokidar watches all configured folders for `.md` add/change/unlink events. Debounced batches invalidate the metadata cache so the next `skills__list` re-scans. Folders mutated via `skills__configure` auto-re-watch via the same diff path.
111
+
112
+ ## Skill format
113
+
114
+ Any `.md` file with a YAML frontmatter block defining at least `name:`:
115
+
116
+ ```markdown
117
+ ---
118
+ name: apple-hig-check
119
+ description: Audit code against Apple Human Interface Guidelines.
120
+ tags: [ios, design]
121
+ ---
122
+
123
+ You are an Apple HIG expert. When asked to review code...
124
+ ```
125
+
126
+ Optional camelCase fields validated by `SkillMetadata`: `strategy` (`prompt` / `script` / `hybrid`), `allowScripts`, `allowNetwork`, `skills` (composite — string[] of nested skill names invoked sequentially), `timeoutMs`, `cacheable`, `cacheTtlMs`, `scripts` (string[], single-entry — `main.py` / `entry.sh` / `app.mjs`). Anything else passes through to `extra`.
127
+
128
+ `FormatDetector` recognizes Claude (`SKILL.md`), Codex (`AGENTS.md`), persona-style (frontmatter has `persona:`), and generic-custom dialects automatically.
129
+
130
+ Full spec: [docs/SKILL_FORMAT.md](./docs/SKILL_FORMAT.md).
131
+
132
+ ## Architecture (one-liner)
133
+
134
+ `MCP request → Tool handler → Registry lookup → DecoratorChain.wrap(strategy).invoke(skill, ctx) → Logging → Timeout → Cache → Strategy (Prompt / Script / Hybrid / Composite-resolver) → InvocationResult`
135
+
136
+ Patterns used: Registry, Strategy, Factory, Adapter, Decorator (chain composition), Composite (sequential nested invocation), Observer (chokidar), Singleton.
137
+
138
+ Full design: [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md).
139
+
140
+ ## Limitations
141
+
142
+ Read this before enabling scripts.
143
+
144
+ `ScriptStrategy` runs user-provided scripts in a `SandboxRunner` subprocess. **The sandbox is best-effort env/cwd isolation, not an OS-grade jail.** Node `child_process` cannot guarantee network isolation, filesystem confinement outside `cwd`, or CPU/memory limits — those require Docker/firecracker/gVisor (future enhancement).
145
+
146
+ | Property | Enforced? | How |
147
+ |----------|-----------|-----|
148
+ | `env` whitelist | Yes | Subprocess receives only `PATH` (+ explicit `opts.env` like `SKILLFORGE_INPUT`). No `HOME`/`USER`/`SSH_AUTH_SOCK`/`~/.ssh`/`~/.aws` propagation. |
149
+ | Temp `cwd` | Yes | Fresh `fs.mkdtemp(os.tmpdir()/skillforge-XXXX)`, recursive cleanup in `finally`. |
150
+ | Abort signal | Yes | `signal.abort()` → SIGTERM → 5s grace → SIGKILL. |
151
+ | stdout/stderr cap | Yes | Tail-truncate at 1 MB each. |
152
+ | Network egress | No | Subprocess inherits host network stack. `metadata.allowNetwork` is a documentation signal, not a runtime constraint. |
153
+ | Filesystem reads outside `cwd` | No | Subprocess has full OS user permissions. |
154
+ | Filesystem writes outside `cwd` | No | Same. |
155
+ | CPU / memory limits | No | Only the timeout decorator wall-clock-kills runaways. |
156
+
157
+ **Defence in depth** layered on top:
158
+
159
+ 1. **Global gate** — `config.security.allowScripts: false` by default.
160
+ 2. **Per-skill opt-in** — `metadata.allowScripts: true` required per skill.
161
+ 3. **Audit pattern scanner** — `PatternScanner` detects `shell=True`, `eval(`, `exec(`, base64 decode patterns in skill bodies before load.
162
+ 4. **Manual blacklist** — explicit skill names in `config.security.blacklist`.
163
+
164
+ For production use with untrusted skill authors, run SkillForge inside Docker or another OS-level sandbox. Full threat model: [docs/SECURITY.md](./docs/SECURITY.md).
165
+
166
+ ## Updating
167
+
168
+ ```bash
169
+ # Marketplace install
170
+ /plugin update skillforge-mcp@lyupro-llm-plugins
171
+
172
+ # npm install
173
+ claude mcp remove skillforge
174
+ claude mcp add skillforge -- npx -y @lyupro/skillforge-mcp@latest
175
+
176
+ # Local-build install
177
+ cd skillforge-mcp
178
+ git pull
179
+ pnpm install
180
+ pnpm build
181
+ ```
182
+
183
+ The wiring in Claude Code / Codex / Cursor points at the same binary path — restarting the host session picks up the new build. Your persisted config at `~/.lyupro/.skillforge/config.json` survives the upgrade.
184
+
185
+ ## Documentation
186
+
187
+ | Doc | Audience |
188
+ |-----|----------|
189
+ | [docs/INSTALL.md](./docs/INSTALL.md) | First-time setup for Claude Code, Codex CLI, Cursor, manual MCP clients |
190
+ | [docs/SKILL_FORMAT.md](./docs/SKILL_FORMAT.md) | Skill authors — full frontmatter spec, dialect detection, examples |
191
+ | [docs/CONFIGURATION.md](./docs/CONFIGURATION.md) | Power users — folder management, blacklist, sandbox config, env overrides |
192
+ | [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) | Contributors — design patterns, module responsibilities, extension points |
193
+ | [docs/SECURITY.md](./docs/SECURITY.md) | Security-conscious operators — threat model, audit checklist, sandbox limits, disclosure policy |
194
+ | [docs/INTEGRATION/](./docs/INTEGRATION/) | Per-tool wiring guides (claude-code / codex / cursor / custom-llm-tools) |
195
+ | [skills/](./skills/) | 10 ready-to-use sample skills (prompt / script / hybrid examples) |
196
+ | [examples/configs/](./examples/configs/) | Sample `config.json` files for common setups |
197
+
198
+ ## Contributing
199
+
200
+ Local build (for development or pre-publish testing):
201
+
202
+ ```bash
203
+ git clone https://github.com/lyupro/skillforge-mcp.git
204
+ cd skillforge-mcp
205
+ pnpm install
206
+ pnpm build
207
+
208
+ # Wire into Claude Code using the absolute path
209
+ claude mcp add skillforge -- node /absolute/path/to/skillforge-mcp/dist/server.js
210
+ ```
211
+
212
+ Development commands:
213
+
214
+ ```bash
215
+ pnpm install
216
+ pnpm dev # tsx watch src/server.ts
217
+ pnpm test # vitest run
218
+ pnpm test:coverage # coverage report
219
+ pnpm lint # tsc --noEmit
220
+ pnpm check:size # file-size gate (≤400 lines per file)
221
+ pnpm build # emit dist/
222
+ pnpm smoke # post-build subprocess smoke test
223
+ ```
224
+
225
+ ## License
226
+
227
+ MIT — see [LICENSE](./LICENSE).
228
+
229
+ ## Author
230
+
231
+ [lyupro](https://lyupro.com) — independent dev. Part of the Lyu Pro tooling portfolio.
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * SkillForge install CLI (v1.1).
4
+ *
5
+ * Wires SkillForge MCP into Claude Code, Codex CLI, and Cursor by editing
6
+ * each host's config file. Manual argv parsing — no `commander` dep.
7
+ *
8
+ * Usage:
9
+ * skillforge install --claude
10
+ * skillforge install --codex --cursor
11
+ * skillforge install --all
12
+ * skillforge install --all --dry-run
13
+ * skillforge install --claude --uninstall
14
+ * skillforge install --all --entry local --binary-path /abs/path/to/server.js
15
+ * skillforge install --claude --force
16
+ */
17
+ import type { Installer } from '../installers/types.js';
18
+ export interface ParsedArgs {
19
+ claude: boolean;
20
+ codex: boolean;
21
+ cursor: boolean;
22
+ all: boolean;
23
+ dryRun: boolean;
24
+ uninstall: boolean;
25
+ force: boolean;
26
+ entry: 'npx' | 'local';
27
+ binaryPath?: string;
28
+ showHelp: boolean;
29
+ }
30
+ export declare class UsageError extends Error {
31
+ constructor(message: string);
32
+ }
33
+ export declare function parseArgs(argv: string[]): ParsedArgs;
34
+ export interface RunDeps {
35
+ installers?: Installer[];
36
+ stdout?: (line: string) => void;
37
+ stderr?: (line: string) => void;
38
+ }
39
+ export declare function runInstall(args: ParsedArgs, deps?: RunDeps): Promise<number>;
40
+ export declare function main(rawArgv: string[]): Promise<number>;
41
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/cli/install.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EACV,SAAS,EAKV,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B;AA0BD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA+DpD;AAED,MAAM,WAAW,OAAO;IACtB,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAkCD,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE,OAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAwDtF;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAc7D"}
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * SkillForge install CLI (v1.1).
4
+ *
5
+ * Wires SkillForge MCP into Claude Code, Codex CLI, and Cursor by editing
6
+ * each host's config file. Manual argv parsing — no `commander` dep.
7
+ *
8
+ * Usage:
9
+ * skillforge install --claude
10
+ * skillforge install --codex --cursor
11
+ * skillforge install --all
12
+ * skillforge install --all --dry-run
13
+ * skillforge install --claude --uninstall
14
+ * skillforge install --all --entry local --binary-path /abs/path/to/server.js
15
+ * skillforge install --claude --force
16
+ */
17
+ import { getAllInstallers, getInstallerByName } from '../installers/registry.js';
18
+ export class UsageError extends Error {
19
+ constructor(message) {
20
+ super(message);
21
+ this.name = 'UsageError';
22
+ }
23
+ }
24
+ const USAGE = `skillforge install — wire SkillForge MCP into Claude Code / Codex CLI / Cursor.
25
+
26
+ Usage:
27
+ skillforge install [flags]
28
+
29
+ Targets (at least one required, unless --help):
30
+ --claude Edit ~/.claude.json
31
+ --codex Edit ~/.codex/config.toml
32
+ --cursor Edit Cursor's settings.json (OS-specific path)
33
+ --all Auto-detect installed hosts and install into each
34
+
35
+ Modes:
36
+ --dry-run Print intended edits, do not touch disk
37
+ --uninstall Reverse a previous install
38
+ --force Overwrite an existing SkillForge entry
39
+
40
+ Entry shape:
41
+ --entry npx (default) command=npx args=['-y','@lyupro/skillforge-mcp']
42
+ --entry local command=node args=[<binary-path>]
43
+ --binary-path PATH Override the local-entry binary path (defaults to dist/server.js)
44
+
45
+ --help, -h Show this message
46
+ `;
47
+ export function parseArgs(argv) {
48
+ const out = {
49
+ claude: false,
50
+ codex: false,
51
+ cursor: false,
52
+ all: false,
53
+ dryRun: false,
54
+ uninstall: false,
55
+ force: false,
56
+ entry: 'npx',
57
+ showHelp: false,
58
+ };
59
+ for (let i = 0; i < argv.length; i++) {
60
+ const arg = argv[i];
61
+ switch (arg) {
62
+ case '--claude':
63
+ out.claude = true;
64
+ break;
65
+ case '--codex':
66
+ out.codex = true;
67
+ break;
68
+ case '--cursor':
69
+ out.cursor = true;
70
+ break;
71
+ case '--all':
72
+ out.all = true;
73
+ break;
74
+ case '--dry-run':
75
+ out.dryRun = true;
76
+ break;
77
+ case '--uninstall':
78
+ out.uninstall = true;
79
+ break;
80
+ case '--force':
81
+ out.force = true;
82
+ break;
83
+ case '--help':
84
+ case '-h':
85
+ out.showHelp = true;
86
+ break;
87
+ case '--entry': {
88
+ const next = argv[++i];
89
+ if (next !== 'npx' && next !== 'local') {
90
+ throw new UsageError(`--entry must be 'npx' or 'local' (got: ${String(next)})`);
91
+ }
92
+ out.entry = next;
93
+ break;
94
+ }
95
+ case '--binary-path': {
96
+ const next = argv[++i];
97
+ if (next === undefined || next.startsWith('--')) {
98
+ throw new UsageError(`--binary-path requires a path argument`);
99
+ }
100
+ out.binaryPath = next;
101
+ break;
102
+ }
103
+ default:
104
+ throw new UsageError(`Unknown flag: ${arg}`);
105
+ }
106
+ }
107
+ return out;
108
+ }
109
+ function chooseInstallers(args, all) {
110
+ if (args.all)
111
+ return all;
112
+ const picked = [];
113
+ if (args.claude)
114
+ picked.push(all.find((i) => i.name === 'claude') ?? getInstallerByName('claude'));
115
+ if (args.codex)
116
+ picked.push(all.find((i) => i.name === 'codex') ?? getInstallerByName('codex'));
117
+ if (args.cursor)
118
+ picked.push(all.find((i) => i.name === 'cursor') ?? getInstallerByName('cursor'));
119
+ return picked;
120
+ }
121
+ function formatInstall(r) {
122
+ const tag = r.status.toUpperCase();
123
+ const msg = r.message !== undefined ? ` (${r.message})` : '';
124
+ return `[${r.tool}] ${tag} ${r.configPath}${msg}`;
125
+ }
126
+ function formatUninstall(r) {
127
+ const tag = r.status.toUpperCase();
128
+ const msg = r.message !== undefined ? ` (${r.message})` : '';
129
+ return `[${r.tool}] ${tag} ${r.configPath}${msg}`;
130
+ }
131
+ function formatPreview(r) {
132
+ const lines = [
133
+ `--- DRY RUN [${r.tool}] action=${r.action} configPath=${r.configPath} willCreate=${r.willCreate}`,
134
+ `--- before:`,
135
+ r.before ?? '(file does not exist)',
136
+ `--- after:`,
137
+ r.after,
138
+ ];
139
+ return lines.join('\n');
140
+ }
141
+ export async function runInstall(args, deps = {}) {
142
+ const stdout = deps.stdout ?? ((line) => console.log(line));
143
+ const stderr = deps.stderr ?? ((line) => console.error(line));
144
+ if (args.showHelp) {
145
+ stdout(USAGE);
146
+ return 0;
147
+ }
148
+ if (!args.all && !args.claude && !args.codex && !args.cursor) {
149
+ stderr(USAGE);
150
+ stderr('\nError: choose at least one of --claude / --codex / --cursor / --all');
151
+ return 2;
152
+ }
153
+ const allInstallers = deps.installers ?? getAllInstallers();
154
+ let installers = chooseInstallers(args, allInstallers);
155
+ if (args.all) {
156
+ const detected = [];
157
+ for (const inst of installers) {
158
+ if (await inst.detect())
159
+ detected.push(inst);
160
+ }
161
+ if (detected.length === 0) {
162
+ stderr('No supported hosts detected (claude / codex / cursor). Pass --claude / --codex / --cursor explicitly to force.');
163
+ return 1;
164
+ }
165
+ installers = detected;
166
+ }
167
+ const opts = {
168
+ entry: args.entry,
169
+ binaryPath: args.binaryPath,
170
+ force: args.force,
171
+ };
172
+ let exit = 0;
173
+ for (const inst of installers) {
174
+ try {
175
+ if (args.dryRun) {
176
+ const preview = await inst.preview({ ...opts, action: args.uninstall ? 'uninstall' : 'install' });
177
+ stdout(formatPreview(preview));
178
+ }
179
+ else if (args.uninstall) {
180
+ const result = await inst.uninstall();
181
+ stdout(formatUninstall(result));
182
+ }
183
+ else {
184
+ const result = await inst.install(opts);
185
+ stdout(formatInstall(result));
186
+ if (result.status === 'already-installed')
187
+ exit = exit === 0 ? 0 : exit;
188
+ }
189
+ }
190
+ catch (err) {
191
+ const msg = err instanceof Error ? err.message : String(err);
192
+ stderr(`[${inst.name}] error: ${msg}`);
193
+ exit = 1;
194
+ }
195
+ }
196
+ return exit;
197
+ }
198
+ export async function main(rawArgv) {
199
+ try {
200
+ const args = parseArgs(rawArgv);
201
+ return await runInstall(args);
202
+ }
203
+ catch (err) {
204
+ if (err instanceof UsageError) {
205
+ console.error(USAGE);
206
+ console.error(`\nError: ${err.message}`);
207
+ return 2;
208
+ }
209
+ const msg = err instanceof Error ? err.message : String(err);
210
+ console.error(`skillforge install: fatal: ${msg}`);
211
+ return 1;
212
+ }
213
+ }
214
+ import { fileURLToPath } from 'node:url';
215
+ const isDirectRun = process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1];
216
+ if (isDirectRun) {
217
+ // First positional arg may be the subcommand "install" — strip it if present
218
+ // so users can invoke as `skillforge install --claude` or `skillforge-install --claude`.
219
+ const argv = process.argv.slice(2);
220
+ const stripped = argv[0] === 'install' ? argv.slice(1) : argv;
221
+ main(stripped).then((code) => process.exit(code));
222
+ }
223
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/cli/install.ts"],"names":[],"mappings":"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"}