@bovinphang/frontend-craft 2.5.0 → 2.6.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 (77) hide show
  1. package/.claude-plugin/marketplace.json +7 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +39 -0
  4. package/CHANGELOG.zh-CN.md +40 -0
  5. package/CONTRIBUTING.md +15 -10
  6. package/CONTRIBUTING.zh-CN.md +15 -10
  7. package/README.md +61 -39
  8. package/README.openclaw.md +8 -8
  9. package/README.openclaw.zh-CN.md +8 -8
  10. package/README.zh-CN.md +61 -39
  11. package/commands/fec-doc-sync.md +7 -6
  12. package/dist/bin/frontend-craft.js +30 -27
  13. package/docs/example-prompts.md +4 -3
  14. package/docs/ja-JP/README.md +61 -39
  15. package/docs/ko-KR/README.md +61 -39
  16. package/docs/runtimes/antigravity.md +1 -1
  17. package/docs/runtimes/augment.md +1 -1
  18. package/docs/runtimes/claude.md +16 -10
  19. package/docs/runtimes/claude.zh-CN.md +16 -10
  20. package/docs/runtimes/cline.md +1 -1
  21. package/docs/runtimes/codebuddy.md +1 -1
  22. package/docs/runtimes/codex.md +1 -1
  23. package/docs/runtimes/copilot.md +1 -1
  24. package/docs/runtimes/cursor.md +1 -1
  25. package/docs/runtimes/gemini.md +1 -1
  26. package/docs/runtimes/kilo.md +1 -1
  27. package/docs/runtimes/openclaw.md +1 -1
  28. package/docs/runtimes/opencode.md +1 -1
  29. package/docs/runtimes/qoder.md +1 -1
  30. package/docs/runtimes/trae.md +1 -1
  31. package/docs/runtimes/windsurf.md +1 -1
  32. package/docs/zh-CN/example-prompts.md +4 -3
  33. package/docs/zh-TW/README.md +61 -39
  34. package/openclaw.plugin.json +1 -1
  35. package/package.json +1 -1
  36. package/skills/eval_queries.json +25 -0
  37. package/skills/fec-accessibility-check/SKILL.md +1 -1
  38. package/skills/fec-alchemy/SKILL.md +74 -0
  39. package/skills/fec-alchemy/assets/absorption-plan-template.md +47 -0
  40. package/skills/fec-alchemy/assets/intake-template.md +55 -0
  41. package/skills/fec-alchemy/assets/review-checklist.md +31 -0
  42. package/skills/fec-alchemy/references/methodology.md +94 -0
  43. package/skills/fec-alchemy/references/originality-and-licensing.md +57 -0
  44. package/skills/fec-browser-storage/SKILL.md +1 -1
  45. package/skills/fec-canvas-threejs/SKILL.md +1 -1
  46. package/skills/fec-code-review/SKILL.md +10 -2
  47. package/skills/fec-data-fetching/SKILL.md +15 -15
  48. package/skills/fec-data-fetching/references/query-patterns.md +27 -1
  49. package/skills/fec-debug-framework/SKILL.md +14 -19
  50. package/skills/fec-debug-framework/references/report-template.md +58 -0
  51. package/skills/fec-doc-sync/SKILL.md +19 -17
  52. package/skills/fec-e2e-testing/SKILL.md +3 -3
  53. package/skills/fec-form-handling/SKILL.md +11 -11
  54. package/skills/fec-form-handling/references/advanced-form-patterns.md +34 -5
  55. package/skills/fec-implement-from-design/SKILL.md +2 -2
  56. package/skills/fec-legacy-to-modern-migration/SKILL.md +33 -23
  57. package/skills/fec-legacy-web-standard/SKILL.md +1 -1
  58. package/skills/fec-list-virtualization/SKILL.md +3 -3
  59. package/skills/fec-list-virtualization/references/virtualization-patterns.md +32 -4
  60. package/skills/fec-performance-optimization/SKILL.md +5 -1
  61. package/skills/fec-performance-optimization/references/report-template.md +53 -0
  62. package/skills/fec-pwa-implementation/SKILL.md +3 -4
  63. package/skills/fec-react-project-standard/SKILL.md +1 -1
  64. package/skills/fec-refactor-clean/SKILL.md +4 -1
  65. package/skills/fec-refactor-clean/references/report-template.md +42 -0
  66. package/skills/fec-security-review/SKILL.md +3 -3
  67. package/skills/fec-state-management/SKILL.md +1 -1
  68. package/skills/fec-storybook-component-doc/SKILL.md +2 -2
  69. package/skills/fec-typescript-type-safety/SKILL.md +1 -1
  70. package/skills/fec-validation-fix/SKILL.md +5 -2
  71. package/skills/fec-validation-fix/references/report-template.md +43 -0
  72. package/skills/fec-vue3-project-standard/SKILL.md +1 -1
  73. package/skills/fec-web-workers/SKILL.md +3 -4
  74. package/skills/metadata.json +82 -45
  75. package/skills/relations.json +20 -0
  76. package/docs/superpowers/plans/2026-05-29-fec-debug.md +0 -491
  77. package/docs/superpowers/specs/2026-05-29-fec-debug-design.md +0 -340
package/README.zh-CN.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  [![Stars](https://img.shields.io/github/stars/bovinphang/frontend-craft?style=flat)](https://github.com/bovinphang/frontend-craft/stargazers)
10
10
  [![CI](https://github.com/bovinphang/frontend-craft/actions/workflows/ci.yml/badge.svg)](https://github.com/bovinphang/frontend-craft/actions/workflows/ci.yml)
11
- [![npm version](https://img.shields.io/npm/v/frontend-craft)](https://www.npmjs.com/package/frontend-craft)
11
+ [![npm version](https://img.shields.io/npm/v/@bovinphang/frontend-craft)](https://www.npmjs.com/package/@bovinphang/frontend-craft)
12
12
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
13
13
  ![Node](https://img.shields.io/badge/Node.js-22+-5FA04E?logo=node.js&logoColor=white)
14
14
  ![TypeScript](https://img.shields.io/badge/-TypeScript-3178C6?logo=typescript&logoColor=white)
@@ -32,7 +32,7 @@
32
32
 
33
33
  各运行时的路径与注意事项详见 [`docs/runtimes/`](docs/runtimes/)。
34
34
 
35
- 它将 **13 个专业 agent**、**40 个自动激活 skill**、**8 个斜杠命令**、**5 个事件驱动 hook**、面向 6 个设计工具端点的 **MCP 集成**以及一整套**规则库**打包为一个可安装单元。运行一条命令,团队里的每一次 AI 会话都将以相同的方式编写 React、Vue、Next.js 或 Nuxt——类型安全、可访问、安全、一致。
35
+ 它将 **13 个专业 agent**、**41 个自动激活 skill**、**8 个斜杠命令**、**5 个事件驱动 hook**、面向 6 个设计工具端点的 **MCP 集成**以及一整套**规则库**打包为一个可安装单元。运行一条命令,团队里的每一次 AI 会话都将以相同的方式编写 React、Vue、Next.js 或 Nuxt——类型安全、可访问、安全、一致。
36
36
 
37
37
  ---
38
38
 
@@ -40,7 +40,7 @@
40
40
 
41
41
  | 痛点 | frontend-craft 的解法 |
42
42
  | --------------------------------------------- | --------------------------------------------------------------------- |
43
- | AI 助手写出的前端代码风格不一、缺类型、不安全 | **40 个 skill** 将团队规范编码为可自动激活的工作流 |
43
+ | AI 助手写出的前端代码风格不一、缺类型、不安全 | **41 个 skill** 将团队规范编码为可自动激活的工作流 |
44
44
  | 每款 AI 工具都有自己的插件格式 | **一条 CLI 命令** 把相同的规则、agent 和 hook 安装到 15 个运行时 |
45
45
  | 设计稿到代码的交接总有信息损失 | **MCP 集成** 从 Figma、Figma Desktop、Sketch、MasterGo、Pixso、墨刀引入更完整设计上下文 |
46
46
  | 代码评审随意、浅层 | **13 个 agent** 输出分级报告:代码、安全、无障碍、性能、TS、UI 还原度 |
@@ -53,45 +53,59 @@
53
53
 
54
54
  需要 **Node.js 22+**。完整支持 **Windows、macOS 和 Linux**(所有钩子和脚本均使用 Node.js 实现)。
55
55
 
56
- ### 方式一:全局 CLI 初始化项目(推荐)
56
+ ### 方式一:全局安装 fec CLI(推荐)
57
57
 
58
58
  ```bash
59
- npm install -g frontend-craft@latest
59
+ # 1. 全局安装 fec 命令
60
+ npm install -g @bovinphang/frontend-craft@latest
61
+
62
+ # 2. 进入你的前端项目
60
63
  cd your-project
61
- fec init
62
- fec init codex # 初始化指定运行时
63
- fec init claude # 初始化 Claude Code
64
- ```
65
64
 
66
- `fec init` 是终端里的 CLI 初始化命令,用来初始化当前项目。在交互式终端中,不传 runtime 时会弹出选择提示;在非交互环境中,不传 runtime 时 CLI 默认使用 `claude`。`init` 默认安装到当前项目,除非显式传入 `--global`,例如 `fec init codex --global`。AI 助手内的 `/fec-init` 斜杠命令是另一个入口,需要先把 frontend-craft 安装到对应运行时后再使用。
65
+ # 3. 交互选择要接入的 AI 运行时
66
+ fec setup
67
67
 
68
- ### 方式二:免全局安装的交互向导
68
+ # 4. 接入当前项目
69
+ fec setup codex
70
+ fec setup claude
71
+ fec setup all
69
72
 
70
- ```bash
71
- npx frontend-craft@latest
73
+ # 5. 全局接入,适用于所有项目
74
+ fec setup codex --global
75
+ fec setup claude --global
76
+ fec setup all --global
77
+
78
+ # 6. 预览 / 查询
79
+ fec install --all --dry-run --global
80
+ fec list
72
81
  ```
73
82
 
74
- 不想全局安装 `fec` 命令时使用这种方式。向导会走完整安装流程:先选择一个或多个运行时,再决定安装到全局还是当前项目。
83
+ `npm install -g` 只是安装 `fec` 终端命令。`fec setup` 是终端里的 CLI 项目接入命令,不是 AI 助手内的 `/fec-init` 斜杠命令。在交互式终端中,不带参数的 `fec setup` 会先让你选择 runtime;`fec setup <runtime>` 和 `fec setup all` 会默认接入当前项目。只有传入 `--global` 时,才会接入对应 AI 工具的全局配置目录,适用于所有项目。
75
84
 
76
- ### 方式三:脚本化安装
85
+ ### 方式二:用 npx 临时运行(免全局安装 fec)
77
86
 
78
87
  ```bash
79
- # 安装到当前项目
80
- npx frontend-craft@latest install --local claude
81
-
82
- # 全局安装到某个运行时
83
- npx frontend-craft@latest install --global codex
84
-
85
- # 预览所有运行时的安装内容(不实际写入)
86
- npx frontend-craft@latest install --all --dry-run --global
87
-
88
- # 列出支持的运行时
89
- npx frontend-craft@latest list
88
+ # 1. 交互向导
89
+ npx @bovinphang/frontend-craft@latest
90
+
91
+ # 2. 接入当前项目
92
+ npx @bovinphang/frontend-craft@latest install --local codex
93
+ npx @bovinphang/frontend-craft@latest install --local claude
94
+ npx @bovinphang/frontend-craft@latest install --all --local
95
+
96
+ # 3. 全局接入,适用于所有项目
97
+ npx @bovinphang/frontend-craft@latest install --global codex
98
+ npx @bovinphang/frontend-craft@latest install --global claude
99
+ npx @bovinphang/frontend-craft@latest install --all --global
100
+
101
+ # 4. 预览 / 查询
102
+ npx @bovinphang/frontend-craft@latest install --all --dry-run --global
103
+ npx @bovinphang/frontend-craft@latest list
90
104
  ```
91
105
 
92
- > **CI / 脚本场景:** 始终带上 `--global` / `-g` 或 `--local` / `-l`。非 TTY 且未指定时,CLI 默认安装到 `claude --global`。
106
+ 不想全局安装 `fec` 命令时使用 `npx`。不带参数会进入交互向导:先选择一个或多个运行时,再决定接入全局还是当前项目。脚本化安装全部 runtime 时使用 `install --all --local` 或 `install --all --global`,不要写成 `install all`。CI / 脚本场景请始终带上 `--global` / `-g` 或 `--local` / `-l`;非 TTY 且未指定时,CLI 默认安装到 `claude --global`。
93
107
 
94
- ### 方式四:Claude Code Marketplace
108
+ ### 方式三:Claude Code Marketplace
95
109
 
96
110
  对 Claude Code 用户,**Claude Code Marketplace** 是推荐的单一来源安装方式。只有在需要跨运行时安装、脚本化/离线复制文件,或非 Marketplace 环境时,才建议对 Claude 使用 CLI。
97
111
 
@@ -133,7 +147,7 @@ npx frontend-craft@latest list
133
147
  ```text
134
148
  你:「合并前请评审我最近的改动。重点看架构、类型安全、渲染行为、样式、无障碍和缺失测试。」
135
149
  你:「先不要写代码,请规划账号账单功能:路由结构、组件边界、数据流、状态归属、校验流程和上线风险。」
136
- 你:「请用 React Hook Form + Zod 构建多步注册表单,包含文件上传、条件字段、异步校验和可访问错误提示。」
150
+ 你:「请构建多步注册表单:根据项目框架选择表单与 schema 校验方案,包含文件上传、条件字段、异步校验和可访问错误提示。」
137
151
  你:「请按 Figma 节点 123:456 实现 UI。复用现有 design token 和组件,匹配间距与响应式状态,并说明假设。」
138
152
  你:「`/fec-refactor-clean` 请清理这个模块里的死代码。」
139
153
  ```
@@ -155,13 +169,13 @@ npx frontend-craft@latest list
155
169
  | `/fec-tdd` | 红 → 绿 → 重构的前端 TDD 循环 | — |
156
170
  | `/fec-debug` | 前端问题诊断与修复:构建失败、运行时错误、UI 异常、接口问题 | `debug-*.md` |
157
171
  | `/fec-refactor-clean` | 分类并安全清理死代码、未使用导出、样式和依赖 | `refactor-clean-*.md` |
158
- | `/fec-doc-sync` | 同步 README、runtime 文档、能力表和公开 metadata | — |
172
+ | `/fec-doc-sync` | 同步 README、docs、环境变量、脚本、API/路由说明和部署文档 | — |
159
173
 
160
174
  ### 技能(Skills,自动激活)
161
175
 
162
176
  技能是根据文件模式、框架或任务上下文**自动激活**的工作流定义,编码了评审维度、输出约定和报告格式。
163
177
 
164
- 下方按使用场景分组列出全部自动激活的技能,便于快速找到项目规范、实现、测试、评审、设计、迁移和文档维护能力。
178
+ 下方按使用场景分组列出全部自动激活的技能,便于快速找到项目规范、实现、测试、评审、设计、迁移、项目演进和文档维护能力。
165
179
 
166
180
  **项目规范** — 检测到对应框架时自动生效:
167
181
 
@@ -178,17 +192,17 @@ npx frontend-craft@latest list
178
192
 
179
193
  | 技能 | 范围 |
180
194
  | ------------------------- | ---------------------------------------------------------- |
181
- | `fec-data-fetching` | TanStack Query / 服务端状态获取、缓存、乐观更新 |
195
+ | `fec-data-fetching` | 服务端状态获取、缓存、失效、SSR、无限加载 |
182
196
  | `fec-api-integration` | 类型化 API client、鉴权刷新、上传、实时集成 |
183
197
  | `fec-state-management` | 状态归属、store 选型、URL 状态、服务端/表单/本地状态边界 |
184
- | `fec-form-handling` | React Hook Form + Zod、动态字段、上传、多步流程 |
198
+ | `fec-form-handling` | 跨框架表单选型、schema 校验、动态字段、上传 |
185
199
  | `fec-browser-storage` | localStorage / sessionStorage / IndexedDB / Cookies 选型 |
186
200
  | `fec-route-protection` | React Router、Next.js、Vue Router、Nuxt 的登录态与权限路由 |
187
201
  | `fec-pwa-implementation` | manifest、Service Worker、离线缓存、安装提示 |
188
202
  | `fec-web-workers` | Web Worker、Transferable、Comlink、Worker 池 |
189
203
  | `fec-canvas-threejs` | Canvas 2D、Three.js、React Three Fiber、WebGL |
190
204
  | `fec-svg-animation` | CSS / Framer Motion / GSAP SVG 动画与 reduced-motion |
191
- | `fec-list-virtualization` | react-window / TanStack Virtual 大列表虚拟滚动 |
205
+ | `fec-list-virtualization` | 按框架选型的大列表虚拟滚动、测量、网格和无限滚动 |
192
206
 
193
207
  **测试** — 规划或编写前端测试覆盖时激活:
194
208
 
@@ -204,6 +218,7 @@ npx frontend-craft@latest list
204
218
  | 技能 | 范围 |
205
219
  | ------------------------------ | ----------------------------------------------------- |
206
220
  | `fec-code-review` | 架构、类型、渲染、样式、可访问性评审 |
221
+ | `fec-debug-framework` | 系统化诊断构建、运行时、UI 和 API/数据问题 |
207
222
  | `fec-typescript-type-safety` | 类型契约、DTO 映射、类型守卫、泛型和类型级检查 |
208
223
  | `fec-security-review` | XSS、CSRF、敏感数据泄露、输入校验 |
209
224
  | `fec-accessibility-check` | WCAG 2.2、键盘、焦点、触控和屏幕阅读器行为 |
@@ -228,13 +243,19 @@ npx frontend-craft@latest list
228
243
  | 技能 | 范围 |
229
244
  | -------------------------------- | ---------------------------------------------- |
230
245
  | `fec-legacy-web-standard` | JS + jQuery + HTML 遗留项目的开发与维护规范 |
231
- | `fec-legacy-to-modern-migration` | jQuery/MPA → React/Vue 3 + TS 策略与分阶段流程 |
246
+ | `fec-legacy-to-modern-migration` | 遗留前端现代化、目标栈识别与分阶段迁移流程 |
247
+
248
+ **项目演进** — 吸收参考系统并原创化落到当前项目时激活:
249
+
250
+ | 技能 | 范围 |
251
+ | ------------- | ------------------------------------------ |
252
+ | `fec-alchemy` | 将参考系统能力原创化吸收到当前项目原生体系 |
232
253
 
233
254
  **文档维护** — 文档维护时激活:
234
255
 
235
256
  | 技能 | 范围 |
236
257
  | ------------------------------- | ------------------------------------------ |
237
- | `fec-doc-sync` | 让公开文档与脚本、技能、代理、命令保持同步 |
258
+ | `fec-doc-sync` | 让前端文档与代码、配置、脚本、路由、API、环境变量和部署事实保持同步 |
238
259
  | `fec-source-driven-development` | 以项目事实和官方来源验证版本敏感的前端决策 |
239
260
 
240
261
  ### 代理(Agents)
@@ -365,11 +386,12 @@ $env:MODAO_TOKEN = "your-modao-token"
365
386
  每一次评审、分析和评估都会输出带时间戳的 Markdown 报告到 `reports/`,可作为审计记录和 PR 交付物。
366
387
 
367
388
  <details>
368
- <summary>查看全部 15 种报告类型</summary>
389
+ <summary>查看全部 16 种报告类型</summary>
369
390
 
370
391
  | 报告类型 | 文件名模式 | 来源 |
371
392
  | -------------- | -------------------------------------------- | ------------------------------------------------------------------- |
372
393
  | 代码审查 | `code-review-YYYY-MM-DD-HHmmss.md` | `/fec-review`、`fec-code-review`、`fec-code-reviewer` |
394
+ | 调试诊断 | `debug-YYYY-MM-DD-HHmmss.md` | `/fec-debug`、`fec-debug-framework`、`fec-debugger` |
373
395
  | TS/JS 专项评审 | `typescript-review-YYYY-MM-DD-HHmmss.md` | `fec-typescript-reviewer` |
374
396
  | 安全审查 | `security-review-YYYY-MM-DD-HHmmss.md` | `fec-security-review`、`fec-security-reviewer` |
375
397
  | 无障碍检查 | `accessibility-review-YYYY-MM-DD-HHmmss.md` | `fec-accessibility-check` |
@@ -393,7 +415,7 @@ $env:MODAO_TOKEN = "your-modao-token"
393
415
 
394
416
  ## 更新与移除
395
417
 
396
- `fec` 是 `frontend-craft` 的短命令。如果没有全局安装 `fec`,可以把同样参数接在 `npx frontend-craft@latest` 后使用,例如 `npx frontend-craft@latest update`。
418
+ `fec` 是 `frontend-craft` 的短命令。如果没有全局安装 `fec`,可以把同样参数接在 `npx @bovinphang/frontend-craft@latest` 后使用,例如 `npx @bovinphang/frontend-craft@latest update`。
397
419
 
398
420
  ### 更新
399
421
 
@@ -437,7 +459,7 @@ npx skills check # 预览可用更新
437
459
 
438
460
  | CLI | 安装内容 |
439
461
  | -------------------- | --------------------------------------------- |
440
- | `npx frontend-craft` | 技能 + 运行时专属代理、命令、钩子、规则、模板 |
462
+ | `npx @bovinphang/frontend-craft` | 技能 + 运行时专属代理、命令、钩子、规则、模板 |
441
463
  | `npx skills` | 仅技能(适用于已有 Skills CLI 工作流) |
442
464
 
443
465
  关闭遥测:`DISABLE_TELEMETRY=1`。详见 [skills.sh CLI 文档](https://skills.sh/docs/cli)。
@@ -1,17 +1,18 @@
1
1
  ---
2
2
  name: fec-doc-sync
3
- description: 从代码和元数据同步 README、runtime docs、项目结构、能力表、命令清单和报告说明。
3
+ description: 从代码和项目事实源同步 README、docs、环境变量、脚本、API/路由/组件说明和部署说明。
4
4
  ---
5
5
 
6
6
  按 `fec-doc-sync` 同步前端工程文档。复杂多语言更新可委托 **`fec-doc-updater`**。
7
7
 
8
8
  ## 执行步骤
9
9
 
10
- 1. 读取事实来源:`package.json`、`skills/metadata.json`、`agents/`、`commands/`、`templates/shared/rules/`。
11
- 2. 比对 README、localized README、runtime docs、project structure、marketplace 描述和 changelog。
12
- 3. 更新数量、命令名、skill id、agent id、报告文件名、示例 prompts、依赖升级/ADR 说明和安装说明。
13
- 4. 多语言文档保持信息一致。
14
- 5. 运行元数据一致性、打包或相关测试。
10
+ 1. 读取事实来源:`package.json`、lockfile、config、`.env.example`、路由、API clients/server routes、types/schemas、组件、测试、CI、build/deploy config。
11
+ 2. 比对 README、docs、ADR、changelog、example prompts、setup/deploy/env docs。
12
+ 3. 更新稳定的命令、环境变量、路由/API 行为、组件说明、部署步骤、版本约束和迁移说明。
13
+ 4. 多语言文档保持关键信息一致。
14
+ 5. 当目标仓库本身是 skill/agent/command 分发仓库时,也同步能力表、metadata、runtime docs 和 marketplace 描述。
15
+ 6. 运行文档一致性、typecheck、测试、构建或相关打包检查。
15
16
 
16
17
  ## 输出要求
17
18
 
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import m from"node:fs";import d from"node:path";import xt from"node:readline";import j from"node:path";import H from"node:fs";import k from"node:fs";import v from"node:path";import Wn from"node:crypto";import Vn from"node:os";var z;function Ae({baseDir:e,cwd:n=process.cwd(),mode:t,packageVersion:o,runtime:i,isGlobal:r}){let s=v.join(e,"frontend-craft.manifest.json");z={baseDir:v.resolve(e),cwd:v.resolve(n),homeDir:v.resolve(Vn.homedir()),mode:t,packageVersion:o,runtime:i,scope:r?"global":"local",manifestPath:s,previousFiles:qn(s),writtenFiles:new Map,skippedFiles:new Set}}function Ge(){let e=z;if(z=void 0,!e)return;for(let[o,i]of e.previousFiles)e.skippedFiles.has(o)&&!e.writtenFiles.has(o)&&e.writtenFiles.set(o,i);let n=[...e.writtenFiles.entries()].map(([o,i])=>qe(o,i)).sort((o,i)=>o.path.localeCompare(i.path)),t={packageVersion:e.packageVersion,runtime:e.runtime,scope:e.scope,installedAt:new Date().toISOString(),files:n};f(v.dirname(e.manifestPath)),k.writeFileSync(e.manifestPath,`${JSON.stringify(t,null,2)}
3
- `,"utf8")}function Le(){z=void 0}function le(e){return v.join(e,"frontend-craft.manifest.json")}function xe(e){if(k.existsSync(e))try{let n=JSON.parse(k.readFileSync(e,"utf8"));return{...n,files:(n.files??[]).map(t=>({...t,path:ve(t.path)}))}}catch{return}}function qn(e){let n=xe(e);return new Map((n?.files??[]).map(t=>[Ve(t.root??"baseDir",ve(t.path)),t.hash]))}function Ue(e){return Wn.createHash("sha256").update(e).digest("hex")}function Ie(e){return Ue(k.readFileSync(e))}function We(e){let n=z;if(!n)return;let t=v.resolve(e),o=[["baseDir",n.baseDir],["cwd",n.cwd],["home",n.homeDir]];for(let[i,r]of o){let s=v.relative(r,t);if(s&&!s.startsWith("..")&&!v.isAbsolute(s))return Ve(i,ve(s))}}function ve(e){return e.split(v.sep).join("/")}function Ve(e,n){return`${e}:${n}`}function qe(e,n){let t=/^(baseDir|cwd|home):(.*)$/.exec(e);if(!t)return{path:e,hash:n};let o=t[1];return{...o==="baseDir"?{}:{root:o},path:t[2],hash:n}}function Be(e){let n=z,t=We(e);if(!n||!t||n.mode!=="update"||!k.existsSync(e))return!1;let o=n.previousFiles.get(t);return!o||Ie(e)===o?!1:(n.skippedFiles.add(t),console.log(`Skipped modified file: ${qe(t,o).path}`),!0)}function ze(e,n){let t=z,o=We(e);!t||!o||t.writtenFiles.set(o,Ue(n))}function f(e){k.existsSync(e)||k.mkdirSync(e,{recursive:!0})}function D(e,n){if(Be(n))return;f(v.dirname(n));let t=k.readFileSync(e);k.copyFileSync(e,n),ze(n,t)}function p(e,n,t={}){if(k.existsSync(e)){f(n);for(let o of k.readdirSync(e)){let i=v.join(e,o),r=o;if(t.filter&&!t.filter(r))continue;let s=v.join(n,o);k.statSync(i).isDirectory()?p(i,s,t):D(i,s)}}}function C(e){return k.readFileSync(e,"utf8")}function y(e,n){Be(e)||(f(v.dirname(e)),k.writeFileSync(e,n,"utf8"),ze(e,n))}function Bn(e,n){let t=j.resolve(e);return n.replaceAll("${CLAUDE_PLUGIN_ROOT}",t).replaceAll("${FRONTEND_CRAFT_ROOT}",t)}function zn(e){let n=j.join(e,"hooks","hooks.json"),t=C(n);return Bn(e,t)}async function He(e){let{pluginRoot:n,baseDir:t,dryRun:o,cwd:i,isGlobal:r}=e;if(o){console.log(`[dry-run] would install Claude Code files into ${t}`);return}f(t),p(j.join(n,"skills"),j.join(t,"skills")),p(j.join(n,"agents"),j.join(t,"agents")),p(j.join(n,"commands"),j.join(t,"commands")),r||p(j.join(n,"templates","shared","rules"),j.join(t,"rules"));let s=j.join(n,"templates","claude");if(H.existsSync(s))for(let l of H.readdirSync(s)){let c=j.join(t,l);H.existsSync(c)||D(j.join(s,l),c)}if(y(j.join(t,"hooks.json"),zn(n)),!r&&H.existsSync(j.join(n,".mcp.json"))){let l=j.join(i,".mcp.json");H.existsSync(l)||D(j.join(n,".mcp.json"),l)}let a=j.join(n,".claude-plugin","plugin.json");if(!r&&H.existsSync(a)){f(j.join(i,".claude-plugin")),D(a,j.join(i,".claude-plugin","plugin.json"));let l=j.join(n,".claude-plugin","marketplace.json");H.existsSync(l)&&D(l,j.join(i,".claude-plugin","marketplace.json"))}}import $ from"node:path";import oe from"node:fs";import Hn from"node:os";function Ke(e,n){let t=e.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);if(!t)throw new Error(`no frontmatter: ${n}`);let o=t[1],i=t[2].trim().replace(/\.claude\/rules/g,".codex/rules").replace(/\bCLAUDE\.md\b/g,"AGENTS.md"),r=o.match(/^name:\s*(.+)$/m);if(!r)throw new Error(`no name in frontmatter: ${n}`);let s=r[1].trim(),a=o.match(/^description:\s*(.+)$/m),l=a?a[1].trim():"";return`name = "${s}"
2
+ import m from"node:fs";import d from"node:path";import It from"node:readline";import j from"node:path";import z from"node:fs";import k from"node:fs";import v from"node:path";import Vn from"node:crypto";import qn from"node:os";var B;function Ge({baseDir:e,cwd:n=process.cwd(),mode:t,packageVersion:o,runtime:i,isGlobal:r}){let s=v.join(e,"frontend-craft.manifest.json");B={baseDir:v.resolve(e),cwd:v.resolve(n),homeDir:v.resolve(qn.homedir()),mode:t,packageVersion:o,runtime:i,scope:r?"global":"local",manifestPath:s,previousFiles:Bn(s),writtenFiles:new Map,skippedFiles:new Set}}function Le(){let e=B;if(B=void 0,!e)return;for(let[o,i]of e.previousFiles)e.skippedFiles.has(o)&&!e.writtenFiles.has(o)&&e.writtenFiles.set(o,i);let n=[...e.writtenFiles.entries()].map(([o,i])=>Be(o,i)).sort((o,i)=>o.path.localeCompare(i.path)),t={packageVersion:e.packageVersion,runtime:e.runtime,scope:e.scope,installedAt:new Date().toISOString(),files:n};f(v.dirname(e.manifestPath)),k.writeFileSync(e.manifestPath,`${JSON.stringify(t,null,2)}
3
+ `,"utf8")}function Ue(){B=void 0}function ae(e){return v.join(e,"frontend-craft.manifest.json")}function Ie(e){if(k.existsSync(e))try{let n=JSON.parse(k.readFileSync(e,"utf8"));return{...n,files:(n.files??[]).map(t=>({...t,path:ke(t.path)}))}}catch{return}}function Bn(e){let n=Ie(e);return new Map((n?.files??[]).map(t=>[qe(t.root??"baseDir",ke(t.path)),t.hash]))}function We(e){return Vn.createHash("sha256").update(e).digest("hex")}function ve(e){return We(k.readFileSync(e))}function Ve(e){let n=B;if(!n)return;let t=v.resolve(e),o=[["baseDir",n.baseDir],["cwd",n.cwd],["home",n.homeDir]];for(let[i,r]of o){let s=v.relative(r,t);if(s&&!s.startsWith("..")&&!v.isAbsolute(s))return qe(i,ke(s))}}function ke(e){return e.split(v.sep).join("/")}function qe(e,n){return`${e}:${n}`}function Be(e,n){let t=/^(baseDir|cwd|home):(.*)$/.exec(e);if(!t)return{path:e,hash:n};let o=t[1];return{...o==="baseDir"?{}:{root:o},path:t[2],hash:n}}function ze(e){let n=B,t=Ve(e);if(!n||!t||n.mode!=="update"||!k.existsSync(e))return!1;let o=n.previousFiles.get(t);return!o||ve(e)===o?!1:(n.skippedFiles.add(t),console.log(`Skipped modified file: ${Be(t,o).path}`),!0)}function He(e,n){let t=B,o=Ve(e);!t||!o||t.writtenFiles.set(o,We(n))}function f(e){k.existsSync(e)||k.mkdirSync(e,{recursive:!0})}function D(e,n){if(ze(n))return;f(v.dirname(n));let t=k.readFileSync(e);k.copyFileSync(e,n),He(n,t)}function p(e,n,t={}){if(k.existsSync(e)){f(n);for(let o of k.readdirSync(e)){let i=v.join(e,o),r=o;if(t.filter&&!t.filter(r))continue;let s=v.join(n,o);k.statSync(i).isDirectory()?p(i,s,t):D(i,s)}}}function C(e){return k.readFileSync(e,"utf8")}function y(e,n){ze(e)||(f(v.dirname(e)),k.writeFileSync(e,n,"utf8"),He(e,n))}function zn(e,n){let t=j.resolve(e);return n.replaceAll("${CLAUDE_PLUGIN_ROOT}",t).replaceAll("${FRONTEND_CRAFT_ROOT}",t)}function Hn(e){let n=j.join(e,"hooks","hooks.json"),t=C(n);return zn(e,t)}async function Ke(e){let{pluginRoot:n,baseDir:t,dryRun:o,cwd:i,isGlobal:r}=e;if(o){console.log(`[dry-run] would install Claude Code files into ${t}`);return}f(t),p(j.join(n,"skills"),j.join(t,"skills")),p(j.join(n,"agents"),j.join(t,"agents")),p(j.join(n,"commands"),j.join(t,"commands")),r||p(j.join(n,"templates","shared","rules"),j.join(t,"rules"));let s=j.join(n,"templates","claude");if(z.existsSync(s))for(let l of z.readdirSync(s)){let c=j.join(t,l);z.existsSync(c)||D(j.join(s,l),c)}if(y(j.join(t,"hooks.json"),Hn(n)),!r&&z.existsSync(j.join(n,".mcp.json"))){let l=j.join(i,".mcp.json");z.existsSync(l)||D(j.join(n,".mcp.json"),l)}let a=j.join(n,".claude-plugin","plugin.json");if(!r&&z.existsSync(a)){f(j.join(i,".claude-plugin")),D(a,j.join(i,".claude-plugin","plugin.json"));let l=j.join(n,".claude-plugin","marketplace.json");z.existsSync(l)&&D(l,j.join(i,".claude-plugin","marketplace.json"))}}import $ from"node:path";import se from"node:fs";import Kn from"node:os";function Je(e,n){let t=e.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);if(!t)throw new Error(`no frontmatter: ${n}`);let o=t[1],i=t[2].trim().replace(/\.claude\/rules/g,".codex/rules").replace(/\bCLAUDE\.md\b/g,"AGENTS.md"),r=o.match(/^name:\s*(.+)$/m);if(!r)throw new Error(`no name in frontmatter: ${n}`);let s=r[1].trim(),a=o.match(/^description:\s*(.+)$/m),l=a?a[1].trim():"";return`name = "${s}"
4
4
  description = "${(u=>u.replace(/\\/g,"\\\\").replace(/"/g,'\\"'))(l)}"
5
5
 
6
6
  model = "gpt-5.4"
@@ -9,50 +9,52 @@ model_reasoning_effort = "high"
9
9
  developer_instructions = """
10
10
  `+i+`
11
11
  """
12
- `}async function Je(e){let{pluginRoot:n,baseDir:t,cwd:o,dryRun:i,isGlobal:r}=e,s=$.join(n,"agents"),a=$.join(t,"agents"),l=$.join(t,"rules"),c=r?$.join(Hn.homedir(),".agents","skills"):$.join(o,".agents","skills");if(i){console.log(`[dry-run] codex: ${t}, agents -> ${a}, skills -> ${c}`);return}f(a),f(c);for(let b of oe.readdirSync(s)){if(!b.endsWith(".md"))continue;let I=C($.join(s,b)),M=Ke(I,b);y($.join(a,b.replace(/\.md$/,".toml")),M)}p($.join(n,"skills"),c);let u=$.join(n,"templates","shared","rules");!r&&oe.existsSync(u)&&p(u,l);let g=$.join(n,"templates","codex","AGENTS.md"),R=$.join(n,"templates","codex","config.toml");if(!r&&oe.existsSync(g)){let b=$.join(o,"AGENTS.md");oe.existsSync(b)||D(g,b)}oe.existsSync(R)&&D(R,$.join(t,"config.toml"))}import Y from"node:path";import Ye from"node:fs";async function Qe(e){let{pluginRoot:n,baseDir:t,dryRun:o,isGlobal:i}=e;if(o){console.log(`[dry-run] cursor -> ${t}`);return}f(t);let r=Y.join(t,"skills");p(Y.join(n,"skills"),r);let s=Y.join(n,"templates","shared","rules"),a=Y.join(t,"rules");if(!i&&Ye.existsSync(s)){f(a);for(let l of Ye.readdirSync(s)){if(!l.endsWith(".md"))continue;let c=C(Y.join(s,l)),u=l.replace(/\.md$/,""),g=`---
12
+ `}async function Ye(e){let{pluginRoot:n,baseDir:t,cwd:o,dryRun:i,isGlobal:r}=e,s=$.join(n,"agents"),a=$.join(t,"agents"),l=$.join(t,"rules"),c=r?$.join(Kn.homedir(),".agents","skills"):$.join(o,".agents","skills");if(i){console.log(`[dry-run] codex: ${t}, agents -> ${a}, skills -> ${c}`);return}f(a),f(c);for(let S of se.readdirSync(s)){if(!S.endsWith(".md"))continue;let M=C($.join(s,S)),I=Je(M,S);y($.join(a,S.replace(/\.md$/,".toml")),I)}p($.join(n,"skills"),c);let u=$.join(n,"templates","shared","rules");!r&&se.existsSync(u)&&p(u,l);let g=$.join(n,"templates","codex","AGENTS.md"),R=$.join(n,"templates","codex","config.toml");if(!r&&se.existsSync(g)){let S=$.join(o,"AGENTS.md");se.existsSync(S)||D(g,S)}se.existsSync(R)&&D(R,$.join(t,"config.toml"))}import Y from"node:path";import Qe from"node:fs";async function Xe(e){let{pluginRoot:n,baseDir:t,dryRun:o,isGlobal:i}=e;if(o){console.log(`[dry-run] cursor -> ${t}`);return}f(t);let r=Y.join(t,"skills");p(Y.join(n,"skills"),r);let s=Y.join(n,"templates","shared","rules"),a=Y.join(t,"rules");if(!i&&Qe.existsSync(s)){f(a);for(let l of Qe.readdirSync(s)){if(!l.endsWith(".md"))continue;let c=C(Y.join(s,l)),u=l.replace(/\.md$/,""),g=`---
13
13
  description: Frontend Craft - ${u}
14
14
  globs: "**/*.{ts,tsx,vue,js,jsx,css,scss,less,html}"
15
15
  ---
16
16
 
17
17
  `+c+`
18
- `;y(Y.join(a,`${u}.mdc`),g)}}}import E from"node:path";import ke from"node:fs";async function Xe(e){let{pluginRoot:n,baseDir:t,dryRun:o,isGlobal:i}=e;if(o){console.log(`[dry-run] windsurf -> ${t}`);return}f(t);let r=E.join(t,"workflows"),s=E.join(t,"rules");f(r);let a=E.join(n,"commands");for(let c of ke.readdirSync(a)){if(!c.endsWith(".md"))continue;let u=C(E.join(a,c));y(E.join(r,c),u)}let l=E.join(n,"templates","shared","rules");if(!i&&ke.existsSync(l)){f(s);for(let c of ke.readdirSync(l)){if(!c.endsWith(".md"))continue;let u=C(E.join(l,c));y(E.join(s,c),u)}}p(E.join(n,"skills"),E.join(t,"skills"))}import A from"node:path";import se from"node:fs";async function ae(e){let{pluginRoot:n,baseDir:t,dryRun:o}=e,i=A.join(t,"command");if(o){console.log(`[dry-run] opencode/kilo commands -> ${i}`);return}f(i);let r=A.join(n,"commands");for(let c of se.readdirSync(r)){if(!c.endsWith(".md"))continue;let u=C(A.join(r,c));y(A.join(i,c),u)}let s=A.join(t,"skills");f(s);let a=A.join(n,"skills");for(let c of se.readdirSync(a)){let u=A.join(a,c);if(!se.statSync(u).isDirectory())continue;let g=A.join(u,"SKILL.md");if(se.existsSync(g)){let R=A.join(s,c);p(u,R)}}let l=A.join(t,"opencode.jsonc");e.runtime==="opencode"&&!se.existsSync(l)&&y(l,`{
18
+ `;y(Y.join(a,`${u}.mdc`),g)}}}import E from"node:path";import we from"node:fs";async function Ze(e){let{pluginRoot:n,baseDir:t,dryRun:o,isGlobal:i}=e;if(o){console.log(`[dry-run] windsurf -> ${t}`);return}f(t);let r=E.join(t,"workflows"),s=E.join(t,"rules");f(r);let a=E.join(n,"commands");for(let c of we.readdirSync(a)){if(!c.endsWith(".md"))continue;let u=C(E.join(a,c));y(E.join(r,c),u)}let l=E.join(n,"templates","shared","rules");if(!i&&we.existsSync(l)){f(s);for(let c of we.readdirSync(l)){if(!c.endsWith(".md"))continue;let u=C(E.join(l,c));y(E.join(s,c),u)}}p(E.join(n,"skills"),E.join(t,"skills"))}import A from"node:path";import ie from"node:fs";async function ce(e){let{pluginRoot:n,baseDir:t,dryRun:o}=e,i=A.join(t,"command");if(o){console.log(`[dry-run] opencode/kilo commands -> ${i}`);return}f(i);let r=A.join(n,"commands");for(let c of ie.readdirSync(r)){if(!c.endsWith(".md"))continue;let u=C(A.join(r,c));y(A.join(i,c),u)}let s=A.join(t,"skills");f(s);let a=A.join(n,"skills");for(let c of ie.readdirSync(a)){let u=A.join(a,c);if(!ie.statSync(u).isDirectory())continue;let g=A.join(u,"SKILL.md");if(ie.existsSync(g)){let R=A.join(s,c);p(u,R)}}let l=A.join(t,"opencode.jsonc");e.runtime==="opencode"&&!ie.existsSync(l)&&y(l,`{
19
19
  "$schema": "https://opencode.ai/config.json",
20
20
  "permissions": { "bash": "allow" }
21
21
  }
22
- `)}async function Ze(e){return ae(e)}async function en(e){return ae(e)}import ie from"node:path";import nn from"node:fs";async function tn(e){let{pluginRoot:n,baseDir:t,cwd:o,dryRun:i,isGlobal:r}=e;if(i){console.log(`[dry-run] gemini -> ${t}`);return}f(t);let s=ie.join(t,"extensions","frontend-craft");f(s),p(ie.join(n,"skills"),ie.join(s,"skills"));let a=ie.join(n,"templates","claude","CLAUDE.md"),l=ie.join(o,"GEMINI.md");if(!r&&!nn.existsSync(l)&&nn.existsSync(a)){let c=C(a).replaceAll(".claude/",".gemini/").replaceAll("CLAUDE.md","GEMINI.md");y(l,c)}}import U from"node:path";import we from"node:fs";async function on(e){let{pluginRoot:n,baseDir:t,dryRun:o,isGlobal:i}=e;if(o){console.log(`[dry-run] copilot -> ${t}`);return}f(t);let r=U.join(t,"instructions"),s=U.join(t,"prompts");if(f(s),!i){f(r);let l=U.join(n,"templates","shared","rules"),c=[`# Frontend Craft - Copilot instructions
23
- `];if(we.existsSync(l))for(let u of we.readdirSync(l))u.endsWith(".md")&&c.push(`
22
+ `)}async function en(e){return ce(e)}async function nn(e){return ce(e)}import re from"node:path";import tn from"node:fs";async function on(e){let{pluginRoot:n,baseDir:t,cwd:o,dryRun:i,isGlobal:r}=e;if(i){console.log(`[dry-run] gemini -> ${t}`);return}f(t);let s=re.join(t,"extensions","frontend-craft");f(s),p(re.join(n,"skills"),re.join(s,"skills"));let a=re.join(n,"templates","claude","CLAUDE.md"),l=re.join(o,"GEMINI.md");if(!r&&!tn.existsSync(l)&&tn.existsSync(a)){let c=C(a).replaceAll(".claude/",".gemini/").replaceAll("CLAUDE.md","GEMINI.md");y(l,c)}}import L from"node:path";import Re from"node:fs";async function sn(e){let{pluginRoot:n,baseDir:t,dryRun:o,isGlobal:i}=e;if(o){console.log(`[dry-run] copilot -> ${t}`);return}f(t);let r=L.join(t,"instructions"),s=L.join(t,"prompts");if(f(s),!i){f(r);let l=L.join(n,"templates","shared","rules"),c=[`# Frontend Craft - Copilot instructions
23
+ `];if(Re.existsSync(l))for(let u of Re.readdirSync(l))u.endsWith(".md")&&c.push(`
24
24
  ## ${u}
25
25
 
26
- `,C(U.join(l,u)));y(U.join(r,"frontend-craft.instructions.md"),c.join(""))}let a=U.join(n,"commands");for(let l of we.readdirSync(a))l.endsWith(".md")&&y(U.join(s,l),C(U.join(a,l)))}import Q from"node:path";async function sn(e){let{pluginRoot:n,baseDir:t,dryRun:o}=e;if(o)return console.log(`[dry-run] antigravity -> ${t}`);f(t),p(Q.join(n,"skills"),Q.join(t,"skills"))}async function rn(e){let{pluginRoot:n,baseDir:t,dryRun:o}=e;if(o)return console.log(`[dry-run] augment -> ${t}`);f(t),p(Q.join(n,"skills"),Q.join(t,"skills"))}async function ln(e){let{pluginRoot:n,baseDir:t,dryRun:o}=e;if(o)return console.log(`[dry-run] codebuddy -> ${t}`);f(t),p(Q.join(n,"skills"),Q.join(t,"skills"))}import ce from"node:path";import an from"node:fs";async function cn(e){let{pluginRoot:n,baseDir:t,dryRun:o,isGlobal:i}=e;if(o)return console.log(`[dry-run] trae -> ${t}`);if(i)return;let r=ce.join(t,"rules");f(r);let s=ce.join(n,"templates","shared","rules"),a=[`# Frontend Craft - Trae rules bundle
27
- `];if(an.existsSync(s))for(let l of an.readdirSync(s))l.endsWith(".md")&&a.push(`
26
+ `,C(L.join(l,u)));y(L.join(r,"frontend-craft.instructions.md"),c.join(""))}let a=L.join(n,"commands");for(let l of Re.readdirSync(a))l.endsWith(".md")&&y(L.join(s,l),C(L.join(a,l)))}import Q from"node:path";async function rn(e){let{pluginRoot:n,baseDir:t,dryRun:o}=e;if(o)return console.log(`[dry-run] antigravity -> ${t}`);f(t),p(Q.join(n,"skills"),Q.join(t,"skills"))}async function ln(e){let{pluginRoot:n,baseDir:t,dryRun:o}=e;if(o)return console.log(`[dry-run] augment -> ${t}`);f(t),p(Q.join(n,"skills"),Q.join(t,"skills"))}async function an(e){let{pluginRoot:n,baseDir:t,dryRun:o}=e;if(o)return console.log(`[dry-run] codebuddy -> ${t}`);f(t),p(Q.join(n,"skills"),Q.join(t,"skills"))}import ue from"node:path";import cn from"node:fs";async function un(e){let{pluginRoot:n,baseDir:t,dryRun:o,isGlobal:i}=e;if(o)return console.log(`[dry-run] trae -> ${t}`);if(i)return;let r=ue.join(t,"rules");f(r);let s=ue.join(n,"templates","shared","rules"),a=[`# Frontend Craft - Trae rules bundle
27
+ `];if(cn.existsSync(s))for(let l of cn.readdirSync(s))l.endsWith(".md")&&a.push(`
28
28
  ## ${l}
29
29
 
30
- `,C(ce.join(s,l)));y(ce.join(r,"frontend-craft.md"),a.join(""))}import ue from"node:path";import un from"node:fs";async function fn(e){let{pluginRoot:n,baseDir:t,dryRun:o,isGlobal:i}=e;if(o)return console.log(`[dry-run] cline -> ${ue.join(t,".clinerules")}`);if(i)return;let r=ue.join(n,"templates","shared","rules"),s=[`# Frontend Craft - Cline rules
31
- `];if(un.existsSync(r))for(let a of un.readdirSync(r))a.endsWith(".md")&&s.push(`
30
+ `,C(ue.join(s,l)));y(ue.join(r,"frontend-craft.md"),a.join(""))}import fe from"node:path";import fn from"node:fs";async function dn(e){let{pluginRoot:n,baseDir:t,dryRun:o,isGlobal:i}=e;if(o)return console.log(`[dry-run] cline -> ${fe.join(t,".clinerules")}`);if(i)return;let r=fe.join(n,"templates","shared","rules"),s=[`# Frontend Craft - Cline rules
31
+ `];if(fn.existsSync(r))for(let a of fn.readdirSync(r))a.endsWith(".md")&&s.push(`
32
32
  ## ${a}
33
33
 
34
- `,C(ue.join(r,a)));y(ue.join(t,".clinerules"),s.join(""))}import K from"node:path";import Re from"node:fs";async function dn(e){let{pluginRoot:n,baseDir:t,cwd:o,dryRun:i}=e;if(i)return console.log(`[dry-run] openclaw -> ${t}`);f(t),p(K.join(n,"skills"),K.join(t,"skills")),p(K.join(n,"commands"),K.join(t,"commands"));let r=K.join(n,"templates","openclaw");if(Re.existsSync(r))for(let s of Re.readdirSync(r)){if(!s.endsWith(".md"))continue;let a=K.join(o,s);Re.existsSync(a)||D(K.join(r,s),a)}}import O from"node:path";import pn from"node:fs";var Kn=["fec-security-check.js","fec-format-changed-file.js","fec-run-tests.js","fec-notify.js"];async function mn(e){let{pluginRoot:n,baseDir:t,dryRun:o,isGlobal:i}=e;if(o){console.log(`[dry-run] qoder -> ${t}`);return}f(t),p(O.join(n,"skills"),O.join(t,"skills")),p(O.join(n,"commands"),O.join(t,"commands")),p(O.join(n,"agents"),O.join(t,"agents")),i||p(O.join(n,"templates","shared","rules"),O.join(t,"rules")),Jn(n,O.join(t,"hooks")),y(O.join(t,"settings.json"),JSON.stringify(Yn(t),null,2)+`
35
- `)}function Jn(e,n){f(n);for(let t of Kn){let o=O.join(e,"dist","hooks",t);if(!pn.existsSync(o))throw new Error(`Missing built hook script: ${o}. Run "npm run build" before installing.`);D(o,O.join(n,t))}}function Yn(e){let n=O.join(e,"settings.json"),t=Qn(n);return{...t,hooks:{...X(t.hooks),PreToolUse:[...de(X(t.hooks).PreToolUse),fe("Bash|Shell",".qoder/hooks/fec-security-check.js","Checking command safety...")],PostToolUse:[...de(X(t.hooks).PostToolUse),fe("Write|Edit|MultiEdit",".qoder/hooks/fec-format-changed-file.js","Running formatter...")],Stop:[...de(X(t.hooks).Stop),fe(".*",".qoder/hooks/fec-run-tests.js","Running final validation...")],Notification:[...de(X(t.hooks).Notification),fe(".*",".qoder/hooks/fec-notify.js")]}}}function Qn(e){if(!pn.existsSync(e))return{};try{let n=JSON.parse(C(e));return X(n)}catch{return{}}}function fe(e,n,t){return{matcher:e,hooks:[{type:"command",command:`node "${n}"`,...t?{statusMessage:t}:{}}]}}function X(e){return e!=null&&typeof e=="object"&&!Array.isArray(e)?e:{}}function de(e){return Array.isArray(e)?e:[]}var F=["claude","codex","cursor","windsurf","opencode","kilo","gemini","copilot","antigravity","augment","trae","codebuddy","cline","openclaw","qoder"],pe={claude:He,codex:Je,cursor:Qe,windsurf:Xe,opencode:Ze,kilo:en,gemini:tn,copilot:on,antigravity:sn,augment:rn,trae:cn,codebuddy:ln,cline:fn,openclaw:dn,qoder:mn};import Xn from"node:fs";import Zn from"node:os";import et from"node:path";import ge from"node:readline";import gn from"node:os";import S from"node:path";function x(e){return e&&(e.startsWith("~/")||e==="~"?S.join(gn.homedir(),e.slice(1)):e)}function me(e){let n=gn.homedir(),t=process.env;switch(e){case"claude":return t.CLAUDE_CONFIG_DIR?x(t.CLAUDE_CONFIG_DIR):S.join(n,".claude");case"cursor":return t.CURSOR_CONFIG_DIR?x(t.CURSOR_CONFIG_DIR):S.join(n,".cursor");case"gemini":return t.GEMINI_CONFIG_DIR?x(t.GEMINI_CONFIG_DIR):S.join(n,".gemini");case"codex":return t.CODEX_HOME?x(t.CODEX_HOME):S.join(n,".codex");case"copilot":return t.COPILOT_CONFIG_DIR?x(t.COPILOT_CONFIG_DIR):S.join(n,".copilot");case"antigravity":return t.ANTIGRAVITY_CONFIG_DIR?x(t.ANTIGRAVITY_CONFIG_DIR):S.join(n,".gemini","antigravity");case"windsurf":return t.WINDSURF_CONFIG_DIR?x(t.WINDSURF_CONFIG_DIR):S.join(n,".codeium","windsurf");case"augment":return t.AUGMENT_CONFIG_DIR?x(t.AUGMENT_CONFIG_DIR):S.join(n,".augment");case"trae":return t.TRAE_CONFIG_DIR?x(t.TRAE_CONFIG_DIR):S.join(n,".trae");case"codebuddy":return t.CODEBUDDY_CONFIG_DIR?x(t.CODEBUDDY_CONFIG_DIR):S.join(n,".codebuddy");case"cline":return t.CLINE_CONFIG_DIR?x(t.CLINE_CONFIG_DIR):S.join(n,".cline");case"opencode":return t.OPENCODE_CONFIG_DIR?x(t.OPENCODE_CONFIG_DIR):t.XDG_CONFIG_HOME?S.join(x(t.XDG_CONFIG_HOME),"opencode"):S.join(n,".config","opencode");case"kilo":return t.KILO_CONFIG_DIR?x(t.KILO_CONFIG_DIR):t.XDG_CONFIG_HOME?S.join(x(t.XDG_CONFIG_HOME),"kilo"):S.join(n,".config","kilo");case"openclaw":return t.OPENCLAW_CONFIG_DIR?x(t.OPENCLAW_CONFIG_DIR):S.join(n,".openclaw");case"qoder":return t.QODER_CONFIG_DIR?x(t.QODER_CONFIG_DIR):S.join(n,".qoder");default:return t.CLAUDE_CONFIG_DIR?x(t.CLAUDE_CONFIG_DIR):S.join(n,".claude")}}var De={claude:".claude",codex:".codex",cursor:".cursor",windsurf:".windsurf",opencode:".opencode",kilo:".kilo",gemini:".gemini",copilot:".github",antigravity:".agent",augment:".augment",trae:".trae",codebuddy:".codebuddy",cline:"",openclaw:".openclaw",qoder:".qoder"};function Z({runtime:e,isGlobal:n,cwd:t}){if(n)return me(e);if(e==="cline")return t;let o=De[e]??".claude";return S.join(t,o)}var nt={claude:"Claude Code",codex:"Codex",cursor:"Cursor",windsurf:"Windsurf",opencode:"OpenCode",kilo:"Kilo",gemini:"Gemini",copilot:"Copilot",antigravity:"Antigravity",augment:"Augment",trae:"Trae",codebuddy:"CodeBuddy",cline:"Cline",openclaw:"OpenClaw",qoder:"Qoder"};function yn(e){let n=Zn.homedir();return e===n?"~":e.startsWith(`${n}${et.sep}`)?`~${e.slice(n.length)}`:e}function tt(e){let n=De[e];return n?`./${n}`:"./"}var ye=F.map((e,n)=>({choice:String(n+1),runtime:e,label:nt[e]??e})),ot=String(ye.length+1);function hn(e){return e.filter((n,t)=>e.indexOf(n)===t)}function st(e,n,t){return Math.max(n,Math.min(t,e))}function it(e){return!e||e.ctrl||e.meta?"":typeof e.sequence=="string"&&e.sequence.length===1&&e.sequence>=" "?e.sequence:typeof e.name=="string"&&e.name.length===1?e.name:""}function rt(){return ye.map(e=>{let n=yn(me(e.runtime));return{value:e.runtime,label:e.label,description:n,selectedSuffix:"selected"}})}function lt(e){let n=hn(e.map(o=>yn(me(o)))).join(", "),t=hn(e.map(o=>tt(o))).join(", ");return[{value:"global",label:"Global",description:`${n} - available in all projects`,selectedSuffix:"selected"},{value:"local",label:"Local",description:`${t} - this project only`,selectedSuffix:"selected"}]}function Cn({message:e,options:n,selected:t=[],multiple:o=!0,pageSize:i=15,validate:r=a=>a.length>0,transform:s=(a=>a)}){return{message:e,options:n,selected:t.filter((l,c)=>t.indexOf(l)===c),multiple:o,pageSize:i,search:"",cursor:0,error:"",visibleOptions(){let l=this.search.trim().toLowerCase();return l?this.options.filter(c=>c.label.toLowerCase().includes(l)||c.value.toLowerCase().includes(l)):this.options},move(l){let c=this.visibleOptions();this.cursor=st(this.cursor+l,0,Math.max(0,c.length-1)),this.error=""},toggle(){let l=this.visibleOptions()[this.cursor];l&&(this.multiple?this.selected.includes(l.value)?this.selected=this.selected.filter(c=>c!==l.value):this.selected=[...this.selected,l.value]:this.selected=[l.value],this.error="")},backspace(){this.search.length>0?(this.search=this.search.slice(0,-1),this.cursor=0):this.selected.length>0&&(this.selected=this.selected.slice(0,-1)),this.error=""},type(l){this.search+=l,this.cursor=0,this.error=""},confirm(){let l=r(this.selected);if(l!==!0){this.error=typeof l=="string"?l:"Select at least one option";return}return s(this.selected)}}}function jn(e={}){return Cn({message:`Which runtime(s) would you like to install for? (${ye.length} available)`,options:rt(),selected:["claude"],multiple:!0,pageSize:e.pageSize??15,transform:n=>n})}function Sn(e,n={}){return Cn({message:"Where would you like to install?",options:lt(e),selected:["global"],multiple:!1,pageSize:n.pageSize??15,transform:t=>t[0]!=="local"})}function he(e){let n=e.visibleOptions(),t=new Set(e.selected),o=new Map(e.options.map(s=>[s.value,s])),i=e.selected.length?e.selected.map(s=>o.get(s)?.label??s).join(", "):"(none selected)",r=[`? ${e.message}`,` Selected: ${i}`,` Search: [${e.search||"type to filter"}]`," Up/Down navigate - Space toggle - Backspace remove - Enter confirm"];if(n.length===0)r.push(" No matches");else{let s=Math.max(0,Math.min(e.cursor-Math.floor(e.pageSize/2),n.length-e.pageSize)),a=Math.min(s+e.pageSize,n.length),l=n.slice(s,a);for(let c=0;c<l.length;c++){let u=l[c],R=s+c===e.cursor,b=t.has(u.value),I=R?">":" ",M=b?"[x]":"[ ]",V=u.description?` (${u.description})`:"",G=b?` (${u.selectedSuffix??"selected"})`:V;r.push(` ${I} ${M} ${u.label}${G}`)}if(n.length>e.pageSize){let c=Math.floor(e.cursor/e.pageSize)+1,u=Math.ceil(n.length/e.pageSize);r.push(` (${c}/${u})`)}}return e.error&&r.push(` ${e.error}`),r.join(`
36
- `)}function at(){return he(jn())}function ct(e){let t=((e==null?"":String(e)).trim()||"1").split(/[\s,]+/).filter(Boolean);if(t.includes(ot))return F.slice();let o=[],i=new Set,r=new Map(ye.map(s=>[s.choice,s.runtime]));for(let s of t){let a=r.get(s);!a||i.has(a)||(i.add(a),o.push(a))}return o.length?o:["claude"]}function ut(e){return he(Sn(e))}function ft(e){return((e==null?"":String(e)).trim()||"1")!=="2"}var $e;function bn(e){return process.stdout.write(e),$e||($e=Xn.readFileSync(0,"utf8").split(/\r?\n/)),$e.shift()??""}function xn(e){return process.env.FRONTEND_CRAFT_FORCE_INTERACTIVE==="1"&&!process.stdin.isTTY?Promise.resolve(bn(e)):new Promise(n=>{let t=ge.createInterface({input:process.stdin,output:process.stdout});t.question(e,o=>{t.close(),n(o)}),t.on("close",()=>n(""))})}async function In(e){return process.env.FRONTEND_CRAFT_FORCE_INTERACTIVE==="1"&&!process.stdin.isTTY?bn(`${he(e)}
37
- `):new Promise(n=>{let t=process.stdin,o=process.stdout,i=t.isRaw,r=0;function s(){r>0&&(ge.moveCursor(o,0,-r),ge.clearScreenDown(o));let c=he(e);o.write(c),o.write(`
34
+ `,C(fe.join(r,a)));y(fe.join(t,".clinerules"),s.join(""))}import H from"node:path";import De from"node:fs";async function pn(e){let{pluginRoot:n,baseDir:t,cwd:o,dryRun:i}=e;if(i)return console.log(`[dry-run] openclaw -> ${t}`);f(t),p(H.join(n,"skills"),H.join(t,"skills")),p(H.join(n,"commands"),H.join(t,"commands"));let r=H.join(n,"templates","openclaw");if(De.existsSync(r))for(let s of De.readdirSync(r)){if(!s.endsWith(".md"))continue;let a=H.join(o,s);De.existsSync(a)||D(H.join(r,s),a)}}import O from"node:path";import mn from"node:fs";var Jn=["fec-security-check.js","fec-format-changed-file.js","fec-run-tests.js","fec-notify.js"];async function gn(e){let{pluginRoot:n,baseDir:t,dryRun:o,isGlobal:i}=e;if(o){console.log(`[dry-run] qoder -> ${t}`);return}f(t),p(O.join(n,"skills"),O.join(t,"skills")),p(O.join(n,"commands"),O.join(t,"commands")),p(O.join(n,"agents"),O.join(t,"agents")),i||p(O.join(n,"templates","shared","rules"),O.join(t,"rules")),Yn(n,O.join(t,"hooks")),y(O.join(t,"settings.json"),JSON.stringify(Qn(t),null,2)+`
35
+ `)}function Yn(e,n){f(n);for(let t of Jn){let o=O.join(e,"dist","hooks",t);if(!mn.existsSync(o))throw new Error(`Missing built hook script: ${o}. Run "npm run build" before installing.`);D(o,O.join(n,t))}}function Qn(e){let n=O.join(e,"settings.json"),t=Xn(n);return{...t,hooks:{...X(t.hooks),PreToolUse:[...pe(X(t.hooks).PreToolUse),de("Bash|Shell",".qoder/hooks/fec-security-check.js","Checking command safety...")],PostToolUse:[...pe(X(t.hooks).PostToolUse),de("Write|Edit|MultiEdit",".qoder/hooks/fec-format-changed-file.js","Running formatter...")],Stop:[...pe(X(t.hooks).Stop),de(".*",".qoder/hooks/fec-run-tests.js","Running final validation...")],Notification:[...pe(X(t.hooks).Notification),de(".*",".qoder/hooks/fec-notify.js")]}}}function Xn(e){if(!mn.existsSync(e))return{};try{let n=JSON.parse(C(e));return X(n)}catch{return{}}}function de(e,n,t){return{matcher:e,hooks:[{type:"command",command:`node "${n}"`,...t?{statusMessage:t}:{}}]}}function X(e){return e!=null&&typeof e=="object"&&!Array.isArray(e)?e:{}}function pe(e){return Array.isArray(e)?e:[]}var F=["claude","codex","cursor","windsurf","opencode","kilo","gemini","copilot","antigravity","augment","trae","codebuddy","cline","openclaw","qoder"],me={claude:Ke,codex:Ye,cursor:Xe,windsurf:Ze,opencode:en,kilo:nn,gemini:on,copilot:sn,antigravity:rn,augment:ln,trae:un,codebuddy:an,cline:dn,openclaw:pn,qoder:gn};import Zn from"node:fs";import et from"node:os";import nt from"node:path";import he from"node:readline";import hn from"node:os";import b from"node:path";function x(e){return e&&(e.startsWith("~/")||e==="~"?b.join(hn.homedir(),e.slice(1)):e)}function ge(e){let n=hn.homedir(),t=process.env;switch(e){case"claude":return t.CLAUDE_CONFIG_DIR?x(t.CLAUDE_CONFIG_DIR):b.join(n,".claude");case"cursor":return t.CURSOR_CONFIG_DIR?x(t.CURSOR_CONFIG_DIR):b.join(n,".cursor");case"gemini":return t.GEMINI_CONFIG_DIR?x(t.GEMINI_CONFIG_DIR):b.join(n,".gemini");case"codex":return t.CODEX_HOME?x(t.CODEX_HOME):b.join(n,".codex");case"copilot":return t.COPILOT_CONFIG_DIR?x(t.COPILOT_CONFIG_DIR):b.join(n,".copilot");case"antigravity":return t.ANTIGRAVITY_CONFIG_DIR?x(t.ANTIGRAVITY_CONFIG_DIR):b.join(n,".gemini","antigravity");case"windsurf":return t.WINDSURF_CONFIG_DIR?x(t.WINDSURF_CONFIG_DIR):b.join(n,".codeium","windsurf");case"augment":return t.AUGMENT_CONFIG_DIR?x(t.AUGMENT_CONFIG_DIR):b.join(n,".augment");case"trae":return t.TRAE_CONFIG_DIR?x(t.TRAE_CONFIG_DIR):b.join(n,".trae");case"codebuddy":return t.CODEBUDDY_CONFIG_DIR?x(t.CODEBUDDY_CONFIG_DIR):b.join(n,".codebuddy");case"cline":return t.CLINE_CONFIG_DIR?x(t.CLINE_CONFIG_DIR):b.join(n,".cline");case"opencode":return t.OPENCODE_CONFIG_DIR?x(t.OPENCODE_CONFIG_DIR):t.XDG_CONFIG_HOME?b.join(x(t.XDG_CONFIG_HOME),"opencode"):b.join(n,".config","opencode");case"kilo":return t.KILO_CONFIG_DIR?x(t.KILO_CONFIG_DIR):t.XDG_CONFIG_HOME?b.join(x(t.XDG_CONFIG_HOME),"kilo"):b.join(n,".config","kilo");case"openclaw":return t.OPENCLAW_CONFIG_DIR?x(t.OPENCLAW_CONFIG_DIR):b.join(n,".openclaw");case"qoder":return t.QODER_CONFIG_DIR?x(t.QODER_CONFIG_DIR):b.join(n,".qoder");default:return t.CLAUDE_CONFIG_DIR?x(t.CLAUDE_CONFIG_DIR):b.join(n,".claude")}}var $e={claude:".claude",codex:".codex",cursor:".cursor",windsurf:".windsurf",opencode:".opencode",kilo:".kilo",gemini:".gemini",copilot:".github",antigravity:".agent",augment:".augment",trae:".trae",codebuddy:".codebuddy",cline:"",openclaw:".openclaw",qoder:".qoder"};function Z({runtime:e,isGlobal:n,cwd:t}){if(n)return ge(e);if(e==="cline")return t;let o=$e[e]??".claude";return b.join(t,o)}var tt={claude:"Claude Code",codex:"Codex",cursor:"Cursor",windsurf:"Windsurf",opencode:"OpenCode",kilo:"Kilo",gemini:"Gemini",copilot:"Copilot",antigravity:"Antigravity",augment:"Augment",trae:"Trae",codebuddy:"CodeBuddy",cline:"Cline",openclaw:"OpenClaw",qoder:"Qoder"};function Cn(e){let n=et.homedir();return e===n?"~":e.startsWith(`${n}${nt.sep}`)?`~${e.slice(n.length)}`:e}function ot(e){let n=$e[e];return n?`./${n}`:"./"}var Ce=F.map((e,n)=>({choice:String(n+1),runtime:e,label:tt[e]??e})),st=String(Ce.length+1);function yn(e){return e.filter((n,t)=>e.indexOf(n)===t)}function it(e,n,t){return Math.max(n,Math.min(t,e))}function rt(e){return!e||e.ctrl||e.meta?"":typeof e.sequence=="string"&&e.sequence.length===1&&e.sequence>=" "?e.sequence:typeof e.name=="string"&&e.name.length===1?e.name:""}function lt(){return Ce.map(e=>{let n=Cn(ge(e.runtime));return{value:e.runtime,label:e.label,description:n,selectedSuffix:"selected"}})}function at(e){let n=yn(e.map(o=>Cn(ge(o)))).join(", "),t=yn(e.map(o=>ot(o))).join(", ");return[{value:"global",label:"Global",description:`${n} - available in all projects`,selectedSuffix:"selected"},{value:"local",label:"Local",description:`${t} - this project only`,selectedSuffix:"selected"}]}function jn({message:e,options:n,selected:t=[],multiple:o=!0,pageSize:i=15,validate:r=a=>a.length>0,transform:s=(a=>a)}){return{message:e,options:n,selected:t.filter((l,c)=>t.indexOf(l)===c),multiple:o,pageSize:i,search:"",cursor:0,error:"",visibleOptions(){let l=this.search.trim().toLowerCase();return l?this.options.filter(c=>c.label.toLowerCase().includes(l)||c.value.toLowerCase().includes(l)):this.options},move(l){let c=this.visibleOptions();this.cursor=it(this.cursor+l,0,Math.max(0,c.length-1)),this.error=""},toggle(){let l=this.visibleOptions()[this.cursor];l&&(this.multiple?this.selected.includes(l.value)?this.selected=this.selected.filter(c=>c!==l.value):this.selected=[...this.selected,l.value]:this.selected=[l.value],this.error="")},backspace(){this.search.length>0?(this.search=this.search.slice(0,-1),this.cursor=0):this.selected.length>0&&(this.selected=this.selected.slice(0,-1)),this.error=""},type(l){this.search+=l,this.cursor=0,this.error=""},confirm(){let l=r(this.selected);if(l!==!0){this.error=typeof l=="string"?l:"Select at least one option";return}return s(this.selected)}}}function Sn(e={}){return jn({message:`Which runtime(s) would you like to install for? (${Ce.length} available)`,options:lt(),selected:["claude"],multiple:!0,pageSize:e.pageSize??15,transform:n=>n})}function bn(e,n={}){return jn({message:"Where would you like to install?",options:at(e),selected:["global"],multiple:!1,pageSize:n.pageSize??15,transform:t=>t[0]!=="local"})}function ye(e){let n=e.visibleOptions(),t=new Set(e.selected),o=new Map(e.options.map(s=>[s.value,s])),i=e.selected.length?e.selected.map(s=>o.get(s)?.label??s).join(", "):"(none selected)",r=[`? ${e.message}`,` Selected: ${i}`,` Search: [${e.search||"type to filter"}]`," Up/Down navigate - Space toggle - Backspace remove - Enter confirm"];if(n.length===0)r.push(" No matches");else{let s=Math.max(0,Math.min(e.cursor-Math.floor(e.pageSize/2),n.length-e.pageSize)),a=Math.min(s+e.pageSize,n.length),l=n.slice(s,a);for(let c=0;c<l.length;c++){let u=l[c],R=s+c===e.cursor,S=t.has(u.value),M=R?">":" ",I=S?"[x]":"[ ]",oe=u.description?` (${u.description})`:"",W=S?` (${u.selectedSuffix??"selected"})`:oe;r.push(` ${M} ${I} ${u.label}${W}`)}if(n.length>e.pageSize){let c=Math.floor(e.cursor/e.pageSize)+1,u=Math.ceil(n.length/e.pageSize);r.push(` (${c}/${u})`)}}return e.error&&r.push(` ${e.error}`),r.join(`
36
+ `)}function ct(){return ye(Sn())}function ut(e){let t=((e==null?"":String(e)).trim()||"1").split(/[\s,]+/).filter(Boolean);if(t.includes(st))return F.slice();let o=[],i=new Set,r=new Map(Ce.map(s=>[s.choice,s.runtime]));for(let s of t){let a=r.get(s);!a||i.has(a)||(i.add(a),o.push(a))}return o.length?o:["claude"]}function ft(e){return ye(bn(e))}function dt(e){return((e==null?"":String(e)).trim()||"1")!=="2"}var Oe;function xn(e){return process.stdout.write(e),Oe||(Oe=Zn.readFileSync(0,"utf8").split(/\r?\n/)),Oe.shift()??""}function In(e){return process.env.FRONTEND_CRAFT_FORCE_INTERACTIVE==="1"&&!process.stdin.isTTY?Promise.resolve(xn(e)):new Promise(n=>{let t=he.createInterface({input:process.stdin,output:process.stdout});t.question(e,o=>{t.close(),n(o)}),t.on("close",()=>n(""))})}async function vn(e){return process.env.FRONTEND_CRAFT_FORCE_INTERACTIVE==="1"&&!process.stdin.isTTY?xn(`${ye(e)}
37
+ `):new Promise(n=>{let t=process.stdin,o=process.stdout,i=t.isRaw,r=0;function s(){r>0&&(he.moveCursor(o,0,-r),he.clearScreenDown(o));let c=ye(e);o.write(c),o.write(`
38
38
  `),r=c.split(`
39
39
  `).length}function a(){t.off("keypress",l),t.isTTY&&t.setRawMode(!!i),t.pause()}function l(c,u){if(u?.ctrl&&u.name==="c"){a(),o.write(`
40
- `),process.exitCode=130,n(void 0);return}if(u?.name==="return"||u?.name==="enter"){let g=e.confirm();s(),g!==void 0&&(a(),n(g));return}if(u?.name==="up")e.move(-1);else if(u?.name==="down")e.move(1);else if(u?.name==="space")e.toggle();else if(u?.name==="backspace")e.backspace();else{let g=it(u);g&&e.type(g)}s()}ge.emitKeypressEvents(t),t.isTTY&&t.setRawMode(!0),t.resume(),t.on("keypress",l),s()})}async function vn(){if(process.stdin.isTTY){let e=await In(jn());return Array.isArray(e)?e:["claude"]}return console.log(`${at()}
41
- `),ct(await xn("Choice [1]: "))}async function kn(e){if(process.stdin.isTTY){let n=await In(Sn(e));return typeof n=="boolean"?n:!0}return console.log(`${ut(e)}
42
- `),ft(await xn("Choice [1]: "))}var Ce={claude:{tier:"full",skills:!0,agents:!0,commands:!0,hooks:!0,rules:!0,templates:!0,mcp:!0,reports:!0,init:"native"},codex:{tier:"full",skills:!0,agents:!0,commands:!1,hooks:!1,rules:!0,templates:!0,mcp:!1,reports:!0,init:"native"},openclaw:{tier:"full",skills:!0,agents:!1,commands:!0,hooks:!1,rules:!1,templates:!0,mcp:!1,reports:!0,init:"native"},qoder:{tier:"full",skills:!0,agents:!0,commands:!0,hooks:!0,rules:!0,templates:!0,mcp:!1,reports:!0,init:"native"},opencode:{tier:"medium",skills:!0,agents:!1,commands:!0,hooks:!1,rules:!1,templates:!0,mcp:!1,reports:!0,init:"rules"},kilo:{tier:"medium",skills:!0,agents:!1,commands:!0,hooks:!1,rules:!1,templates:!1,mcp:!1,reports:!0,init:"rules"},cursor:{tier:"medium",skills:!0,agents:!1,commands:!1,hooks:!1,rules:!0,templates:!1,mcp:!1,reports:!0,init:"rules"},windsurf:{tier:"medium",skills:!0,agents:!1,commands:!0,hooks:!1,rules:!0,templates:!1,mcp:!1,reports:!0,init:"rules"},gemini:{tier:"medium",skills:!0,agents:!1,commands:!1,hooks:!1,rules:!1,templates:!0,mcp:!1,reports:!0,init:"rules"},copilot:{tier:"medium",skills:!1,agents:!1,commands:!0,hooks:!1,rules:!0,templates:!1,mcp:!1,reports:!0,init:"rules"},antigravity:{tier:"skills-rules-only",skills:!0,agents:!1,commands:!1,hooks:!1,rules:!1,templates:!1,mcp:!1,reports:!0,init:"none"},augment:{tier:"skills-rules-only",skills:!0,agents:!1,commands:!1,hooks:!1,rules:!1,templates:!1,mcp:!1,reports:!0,init:"none"},trae:{tier:"skills-rules-only",skills:!1,agents:!1,commands:!1,hooks:!1,rules:!0,templates:!1,mcp:!1,reports:!0,init:"none"},codebuddy:{tier:"skills-rules-only",skills:!0,agents:!1,commands:!1,hooks:!1,rules:!1,templates:!1,mcp:!1,reports:!0,init:"none"},cline:{tier:"skills-rules-only",skills:!1,agents:!1,commands:!1,hooks:!1,rules:!0,templates:!1,mcp:!1,reports:!0,init:"none"}};function wn(e){let n=["Runtime","Tier","Skills","Agents","Commands","Hooks","Rules","Templates","MCP","Reports","Init"],t=e.map(r=>{let s=Ce[r];if(!s)throw new Error(`Missing capability declaration for runtime: ${r}`);return[r,s.tier,W(s.skills),W(s.agents),W(s.commands),W(s.hooks),W(s.rules),W(s.templates),W(s.mcp),W(s.reports),s.init]}),o=n.map((r,s)=>Math.max(r.length,...t.map(a=>a[s].length))),i=r=>r.map((s,a)=>s.padEnd(o[a])).join(" ").trimEnd();return[i(n),...t.map(i)].join(`
43
- `)}function W(e){return e?"yes":"no"}import Rn from"node:fs";import ee from"node:path";import{fileURLToPath as Dn}from"node:url";function $n(e=import.meta.url){let n=ee.dirname(Dn(e));for(;;){if(Rn.existsSync(ee.join(n,"package.json"))&&Rn.existsSync(ee.join(n,"skills")))return n;let t=ee.dirname(n);if(t===n)return ee.resolve(ee.dirname(Dn(e)),"../..");n=t}}import ne from"node:fs";import On from"node:os";import T from"node:path";function je({cwd:e,runtimes:n=F,scopes:t=["local","global"]}){let o=[],i=new Set;for(let r of n)for(let s of t){let a=Z({runtime:r,isGlobal:s==="global",cwd:e}),l=le(a),c=T.resolve(l);if(i.has(c))continue;i.add(c);let u=xe(l);u&&(u.runtime!==r||u.scope!==s||o.push({runtime:r,scope:s,baseDir:a,manifestPath:l,manifest:u}))}return o}function Oe({install:e,cwd:n,dryRun:t,force:o}){let i={removed:[],skipped:[],missing:[]},r=new Set;for(let s of e.manifest.files){let a=dt({filePath:s.path,root:s.root??"baseDir",baseDir:e.baseDir,cwd:n});if(!a)continue;if(!ne.existsSync(a)){i.missing.push(s.path);continue}let l=Ie(a)!==s.hash;if(l&&!o){i.skipped.push(s.path);continue}i.removed.push({path:s.path,modified:l}),r.add(T.dirname(a)),t||ne.rmSync(a,{force:!0})}return!t&&i.skipped.length===0&&(ne.rmSync(e.manifestPath,{force:!0}),pt([...r],[e.baseDir,n,On.homedir()])),i}function dt({filePath:e,root:n,baseDir:t,cwd:o}){let i=n==="baseDir"?t:n==="cwd"?o:On.homedir(),r=T.resolve(i),s=T.resolve(r,e),a=T.relative(r,s);if(!(a.startsWith("..")||T.isAbsolute(a)))return s}function pt(e,n){let t=n.map(o=>T.resolve(o));for(let o of e.sort((i,r)=>r.length-i.length)){let i=T.resolve(o);for(;mt(i,t)&&!t.includes(i)&&!(!ne.existsSync(i)||ne.readdirSync(i).length>0);)ne.rmdirSync(i),i=T.dirname(i)}}function mt(e,n){return n.some(t=>{let o=T.relative(t,e);return o!==""&&!o.startsWith("..")&&!T.isAbsolute(o)})}import N from"node:fs";import Ne from"node:os";import w from"node:path";function Fe({claudeConfigDir:e=_e(),currentVersion:n}){let t=w.join(e,"plugins","cache","frontend-craft","frontend-craft"),o=ht(e),i=gt({cacheDir:t,currentInstallPaths:o.paths,currentVersion:n}),r=o.warning,s=!r&&o.paths.length>0;return{claudeConfigDir:e,cacheDir:t,currentInstallPaths:o.paths,entries:i.map(a=>({...a,shouldDelete:s&&a.shouldDelete,reasons:s?a.reasons:["metadata unavailable"]})),canDelete:s,warning:r}}function _n({claudeConfigDir:e=_e(),currentVersion:n,dryRun:t=!1}){let o=Fe({claudeConfigDir:e,currentVersion:n}),i=[];if(o.canDelete)for(let r of o.entries)r.shouldDelete&&(t||N.rmSync(r.path,{recursive:!0,force:!0}),t||i.push(r));return{...o,deleted:i}}function Me({claudeConfigDir:e=_e(),cwd:n=process.cwd()}={}){let t=yt(e),o=[Nn(w.join(n,".claude","frontend-craft.manifest.json"),"local"),Nn(w.join(e,"frontend-craft.manifest.json"),"global")].filter(i=>i!==void 0);return{native:t,cli:o,hasMultipleActiveSources:t.length+o.length>1}}function re(e){let n=["install sources:"];if(e.native.length===0&&e.cli.length===0)return n.push(" none detected"),n.join(`
40
+ `),process.exitCode=130,n(void 0);return}if(u?.name==="return"||u?.name==="enter"){let g=e.confirm();s(),g!==void 0&&(a(),n(g));return}if(u?.name==="up")e.move(-1);else if(u?.name==="down")e.move(1);else if(u?.name==="space")e.toggle();else if(u?.name==="backspace")e.backspace();else{let g=rt(u);g&&e.type(g)}s()}he.emitKeypressEvents(t),t.isTTY&&t.setRawMode(!0),t.resume(),t.on("keypress",l),s()})}async function kn(){if(process.stdin.isTTY){let e=await vn(Sn());return Array.isArray(e)?e:["claude"]}return console.log(`${ct()}
41
+ `),ut(await In("Choice [1]: "))}async function wn(e){if(process.stdin.isTTY){let n=await vn(bn(e));return typeof n=="boolean"?n:!0}return console.log(`${ft(e)}
42
+ `),dt(await In("Choice [1]: "))}var je={claude:{tier:"full",skills:!0,agents:!0,commands:!0,hooks:!0,rules:!0,templates:!0,mcp:!0,reports:!0,init:"native"},codex:{tier:"full",skills:!0,agents:!0,commands:!1,hooks:!1,rules:!0,templates:!0,mcp:!1,reports:!0,init:"native"},openclaw:{tier:"full",skills:!0,agents:!1,commands:!0,hooks:!1,rules:!1,templates:!0,mcp:!1,reports:!0,init:"native"},qoder:{tier:"full",skills:!0,agents:!0,commands:!0,hooks:!0,rules:!0,templates:!0,mcp:!1,reports:!0,init:"native"},opencode:{tier:"medium",skills:!0,agents:!1,commands:!0,hooks:!1,rules:!1,templates:!0,mcp:!1,reports:!0,init:"rules"},kilo:{tier:"medium",skills:!0,agents:!1,commands:!0,hooks:!1,rules:!1,templates:!1,mcp:!1,reports:!0,init:"rules"},cursor:{tier:"medium",skills:!0,agents:!1,commands:!1,hooks:!1,rules:!0,templates:!1,mcp:!1,reports:!0,init:"rules"},windsurf:{tier:"medium",skills:!0,agents:!1,commands:!0,hooks:!1,rules:!0,templates:!1,mcp:!1,reports:!0,init:"rules"},gemini:{tier:"medium",skills:!0,agents:!1,commands:!1,hooks:!1,rules:!1,templates:!0,mcp:!1,reports:!0,init:"rules"},copilot:{tier:"medium",skills:!1,agents:!1,commands:!0,hooks:!1,rules:!0,templates:!1,mcp:!1,reports:!0,init:"rules"},antigravity:{tier:"skills-rules-only",skills:!0,agents:!1,commands:!1,hooks:!1,rules:!1,templates:!1,mcp:!1,reports:!0,init:"none"},augment:{tier:"skills-rules-only",skills:!0,agents:!1,commands:!1,hooks:!1,rules:!1,templates:!1,mcp:!1,reports:!0,init:"none"},trae:{tier:"skills-rules-only",skills:!1,agents:!1,commands:!1,hooks:!1,rules:!0,templates:!1,mcp:!1,reports:!0,init:"none"},codebuddy:{tier:"skills-rules-only",skills:!0,agents:!1,commands:!1,hooks:!1,rules:!1,templates:!1,mcp:!1,reports:!0,init:"none"},cline:{tier:"skills-rules-only",skills:!1,agents:!1,commands:!1,hooks:!1,rules:!0,templates:!1,mcp:!1,reports:!0,init:"none"}};function Rn(e){let n=["Runtime","Tier","Skills","Agents","Commands","Hooks","Rules","Templates","MCP","Reports","Init"],t=e.map(r=>{let s=je[r];if(!s)throw new Error(`Missing capability declaration for runtime: ${r}`);return[r,s.tier,U(s.skills),U(s.agents),U(s.commands),U(s.hooks),U(s.rules),U(s.templates),U(s.mcp),U(s.reports),s.init]}),o=n.map((r,s)=>Math.max(r.length,...t.map(a=>a[s].length))),i=r=>r.map((s,a)=>s.padEnd(o[a])).join(" ").trimEnd();return[i(n),...t.map(i)].join(`
43
+ `)}function U(e){return e?"yes":"no"}import Dn from"node:fs";import ee from"node:path";import{fileURLToPath as $n}from"node:url";function On(e=import.meta.url){let n=ee.dirname($n(e));for(;;){if(Dn.existsSync(ee.join(n,"package.json"))&&Dn.existsSync(ee.join(n,"skills")))return n;let t=ee.dirname(n);if(t===n)return ee.resolve(ee.dirname($n(e)),"../..");n=t}}import ne from"node:fs";import Nn from"node:os";import T from"node:path";function Se({cwd:e,runtimes:n=F,scopes:t=["local","global"]}){let o=[],i=new Set;for(let r of n)for(let s of t){let a=Z({runtime:r,isGlobal:s==="global",cwd:e}),l=ae(a),c=T.resolve(l);if(i.has(c))continue;i.add(c);let u=Ie(l);u&&(u.runtime!==r||u.scope!==s||o.push({runtime:r,scope:s,baseDir:a,manifestPath:l,manifest:u}))}return o}function Ne({install:e,cwd:n,dryRun:t,force:o}){let i={removed:[],skipped:[],missing:[]},r=new Set;for(let s of e.manifest.files){let a=pt({filePath:s.path,root:s.root??"baseDir",baseDir:e.baseDir,cwd:n});if(!a)continue;if(!ne.existsSync(a)){i.missing.push(s.path);continue}let l=ve(a)!==s.hash;if(l&&!o){i.skipped.push(s.path);continue}i.removed.push({path:s.path,modified:l}),r.add(T.dirname(a)),t||ne.rmSync(a,{force:!0})}return!t&&i.skipped.length===0&&(ne.rmSync(e.manifestPath,{force:!0}),mt([...r],[e.baseDir,n,Nn.homedir()])),i}function pt({filePath:e,root:n,baseDir:t,cwd:o}){let i=n==="baseDir"?t:n==="cwd"?o:Nn.homedir(),r=T.resolve(i),s=T.resolve(r,e),a=T.relative(r,s);if(!(a.startsWith("..")||T.isAbsolute(a)))return s}function mt(e,n){let t=n.map(o=>T.resolve(o));for(let o of e.sort((i,r)=>r.length-i.length)){let i=T.resolve(o);for(;gt(i,t)&&!t.includes(i)&&!(!ne.existsSync(i)||ne.readdirSync(i).length>0);)ne.rmdirSync(i),i=T.dirname(i)}}function gt(e,n){return n.some(t=>{let o=T.relative(t,e);return o!==""&&!o.startsWith("..")&&!T.isAbsolute(o)})}import N from"node:fs";import Fe from"node:os";import w from"node:path";function Me({claudeConfigDir:e=Te(),currentVersion:n}){let t=w.join(e,"plugins","cache","frontend-craft","frontend-craft"),o=yt(e),i=ht({cacheDir:t,currentInstallPaths:o.paths,currentVersion:n}),r=o.warning,s=!r&&o.paths.length>0;return{claudeConfigDir:e,cacheDir:t,currentInstallPaths:o.paths,entries:i.map(a=>({...a,shouldDelete:s&&a.shouldDelete,reasons:s?a.reasons:["metadata unavailable"]})),canDelete:s,warning:r}}function Tn({claudeConfigDir:e=Te(),currentVersion:n,dryRun:t=!1}){let o=Me({claudeConfigDir:e,currentVersion:n}),i=[];if(o.canDelete)for(let r of o.entries)r.shouldDelete&&(t||N.rmSync(r.path,{recursive:!0,force:!0}),t||i.push(r));return{...o,deleted:i}}function _e({claudeConfigDir:e=Te(),cwd:n=process.cwd()}={}){let t=Ct(e),o=[Fn(w.join(n,".claude","frontend-craft.manifest.json"),"local"),Fn(w.join(e,"frontend-craft.manifest.json"),"global")].filter(i=>i!==void 0);return{native:t,cli:o,hasMultipleActiveSources:t.length+o.length>1}}function le(e){let n=["install sources:"];if(e.native.length===0&&e.cli.length===0)return n.push(" none detected"),n.join(`
44
44
  `);for(let t of e.native){let o=[t.version,t.scope].filter(Boolean).join(", ");n.push(` native plugin: ${o||"installed"}${t.installPath?` (${t.installPath})`:""}`)}for(let t of e.cli)n.push(` ${t.scope} CLI: ${t.packageVersion??"unknown"} (${t.manifestPath})`);return e.hasMultipleActiveSources&&n.push(" warning: multiple active sources detected; keep one Claude loader as the source of truth"),n.join(`
45
- `)}function Se(e,n="report"){let t=["native cache:"];if(t.push(` current installs: ${e.currentInstallPaths.length?e.currentInstallPaths.join(", "):"unknown"}`),e.warning&&t.push(` warning: ${e.warning}`),e.entries.length===0)return t.push(" entries: none"),t.join(`
45
+ `)}function be(e,n="report"){let t=["native cache:"];if(t.push(` current installs: ${e.currentInstallPaths.length?e.currentInstallPaths.join(", "):"unknown"}`),e.warning&&t.push(` warning: ${e.warning}`),e.entries.length===0)return t.push(" entries: none"),t.join(`
46
46
  `);for(let o of e.entries){let i=o.isCurrent?"current install":o.reasons.length?o.reasons.join(", "):"healthy",r=n==="dry-run"&&o.shouldDelete?"would delete":n==="fix"&&o.shouldDelete?"delete":"keep";t.push(` ${r} ${o.version}: ${i}`)}return t.join(`
47
- `)}function Tn(e,n){if(n)return Se(e,"dry-run");let t=[Se(e,"fix")];for(let o of e.deleted)t.push(` deleted ${o.version}: ${o.path}`);return e.deleted.length===0&&t.push(" deleted: none"),t.join(`
48
- `)}function _e(){return bt(process.env.CLAUDE_CONFIG_DIR??w.join(Ne.homedir(),".claude"))}function gt({cacheDir:e,currentInstallPaths:n,currentVersion:t}){if(!N.existsSync(e))return[];let o=new Set(n.map(Mn));return N.readdirSync(e,{withFileTypes:!0}).filter(i=>i.isDirectory()).map(i=>{let r=w.join(e,i.name),s=jt(r),a=N.existsSync(w.join(r,"dist")),l=N.existsSync(w.join(r,".orphaned_at")),c=o.has(Mn(r)),u=[];return l&&u.push("orphaned"),a||u.push("missing dist"),s&&St(s,t)<0&&u.push(`package ${s} < ${t}`),{version:i.name,path:r,isCurrent:c,hasDist:a,orphaned:l,packageVersion:s,reasons:u,shouldDelete:!c&&u.length>0}}).sort((i,r)=>i.version.localeCompare(r.version,void 0,{numeric:!0}))}function ht(e){let n=w.join(e,"plugins","installed_plugins.json");if(!N.existsSync(n))return{paths:[],warning:`missing ${n}; refusing to delete cache entries`};try{let t=JSON.parse(N.readFileSync(n,"utf8")),o=(t.plugins?.["frontend-craft@bovinphang/frontend-craft"]??t.plugins?.["frontend-craft@frontend-craft"]??[]).map(i=>i.installPath).filter(i=>typeof i=="string"&&i.length>0).map(i=>w.resolve(i));return o.length===0?{paths:o,warning:`missing frontend-craft plugin entry in ${n}; refusing to delete cache entries`}:{paths:o}}catch{return{paths:[],warning:`invalid ${n}; refusing to delete cache entries`}}}function yt(e){let n=w.join(e,"plugins","installed_plugins.json");if(!N.existsSync(n))return[];try{let t=JSON.parse(N.readFileSync(n,"utf8"));return Object.entries(t.plugins??{}).flatMap(([o,i])=>Ct(o)?i.map(r=>({key:o,installPath:typeof r.installPath=="string"?w.resolve(r.installPath):void 0,scope:typeof r.scope=="string"?r.scope:void 0,version:typeof r.version=="string"?r.version:void 0})):[])}catch{return[]}}function Ct(e){return e==="frontend-craft@bovinphang/frontend-craft"||e==="frontend-craft@frontend-craft"||e.startsWith("frontend-craft@")}function Nn(e,n){if(N.existsSync(e))try{let t=JSON.parse(N.readFileSync(e,"utf8"));return t.runtime!=="claude"?void 0:{scope:n,manifestPath:e,packageVersion:typeof t.packageVersion=="string"?t.packageVersion:void 0}}catch{return{scope:n,manifestPath:e}}}function jt(e){let n=w.join(e,"package.json");if(N.existsSync(n))try{let t=JSON.parse(N.readFileSync(n,"utf8"));return typeof t.version=="string"?t.version:void 0}catch{return}}function St(e,n){let t=Fn(e),o=Fn(n);for(let i=0;i<3;i+=1)if(t[i]!==o[i])return t[i]-o[i];return 0}function Fn(e){let n=e.match(/^(\d+)\.(\d+)\.(\d+)/);return n?[Number(n[1]),Number(n[2]),Number(n[3])]:[0,0,0]}function bt(e){return e==="~"?Ne.homedir():e.startsWith("~/")||e.startsWith("~\\")?w.join(Ne.homedir(),e.slice(2)):e}function Mn(e){let n=w.resolve(e);return process.platform==="win32"?n.toLowerCase():n}function Ee(e){try{let n=d.join(e,"package.json");return JSON.parse(m.readFileSync(n,"utf8")).version??"0.0.0"}catch{return"0.0.0"}}function It(e){let n=null,t=!1,o=!1,i=!1,r=!1,s=!1,a=[];for(let l of e)l==="--global"||l==="-g"?(t=!0,n="global"):l==="--local"||l==="-l"?(o=!0,n="local"):l==="--dry-run"?i=!0:l==="--force"?r=!0:l==="--all"?s=!0:l.startsWith("-")||a.push(l);return{runtime:a[0],installLocation:n,dryRun:i,force:r,all:s,hasGlobal:t,hasLocal:o}}function Te(){console.log(`frontend-craft - universal installer
47
+ `)}function Pn(e,n){if(n)return be(e,"dry-run");let t=[be(e,"fix")];for(let o of e.deleted)t.push(` deleted ${o.version}: ${o.path}`);return e.deleted.length===0&&t.push(" deleted: none"),t.join(`
48
+ `)}function Te(){return xt(process.env.CLAUDE_CONFIG_DIR??w.join(Fe.homedir(),".claude"))}function ht({cacheDir:e,currentInstallPaths:n,currentVersion:t}){if(!N.existsSync(e))return[];let o=new Set(n.map(_n));return N.readdirSync(e,{withFileTypes:!0}).filter(i=>i.isDirectory()).map(i=>{let r=w.join(e,i.name),s=St(r),a=N.existsSync(w.join(r,"dist")),l=N.existsSync(w.join(r,".orphaned_at")),c=o.has(_n(r)),u=[];return l&&u.push("orphaned"),a||u.push("missing dist"),s&&bt(s,t)<0&&u.push(`package ${s} < ${t}`),{version:i.name,path:r,isCurrent:c,hasDist:a,orphaned:l,packageVersion:s,reasons:u,shouldDelete:!c&&u.length>0}}).sort((i,r)=>i.version.localeCompare(r.version,void 0,{numeric:!0}))}function yt(e){let n=w.join(e,"plugins","installed_plugins.json");if(!N.existsSync(n))return{paths:[],warning:`missing ${n}; refusing to delete cache entries`};try{let t=JSON.parse(N.readFileSync(n,"utf8")),o=(t.plugins?.["frontend-craft@bovinphang/frontend-craft"]??t.plugins?.["frontend-craft@frontend-craft"]??[]).map(i=>i.installPath).filter(i=>typeof i=="string"&&i.length>0).map(i=>w.resolve(i));return o.length===0?{paths:o,warning:`missing frontend-craft plugin entry in ${n}; refusing to delete cache entries`}:{paths:o}}catch{return{paths:[],warning:`invalid ${n}; refusing to delete cache entries`}}}function Ct(e){let n=w.join(e,"plugins","installed_plugins.json");if(!N.existsSync(n))return[];try{let t=JSON.parse(N.readFileSync(n,"utf8"));return Object.entries(t.plugins??{}).flatMap(([o,i])=>jt(o)?i.map(r=>({key:o,installPath:typeof r.installPath=="string"?w.resolve(r.installPath):void 0,scope:typeof r.scope=="string"?r.scope:void 0,version:typeof r.version=="string"?r.version:void 0})):[])}catch{return[]}}function jt(e){return e==="frontend-craft@bovinphang/frontend-craft"||e==="frontend-craft@frontend-craft"||e.startsWith("frontend-craft@")}function Fn(e,n){if(N.existsSync(e))try{let t=JSON.parse(N.readFileSync(e,"utf8"));return t.runtime!=="claude"?void 0:{scope:n,manifestPath:e,packageVersion:typeof t.packageVersion=="string"?t.packageVersion:void 0}}catch{return{scope:n,manifestPath:e}}}function St(e){let n=w.join(e,"package.json");if(N.existsSync(n))try{let t=JSON.parse(N.readFileSync(n,"utf8"));return typeof t.version=="string"?t.version:void 0}catch{return}}function bt(e,n){let t=Mn(e),o=Mn(n);for(let i=0;i<3;i+=1)if(t[i]!==o[i])return t[i]-o[i];return 0}function Mn(e){let n=e.match(/^(\d+)\.(\d+)\.(\d+)/);return n?[Number(n[1]),Number(n[2]),Number(n[3])]:[0,0,0]}function xt(e){return e==="~"?Fe.homedir():e.startsWith("~/")||e.startsWith("~\\")?w.join(Fe.homedir(),e.slice(2)):e}function _n(e){let n=w.resolve(e);return process.platform==="win32"?n.toLowerCase():n}function Ae(e){try{let n=d.join(e,"package.json");return JSON.parse(m.readFileSync(n,"utf8")).version??"0.0.0"}catch{return"0.0.0"}}function vt(e){let n=null,t=!1,o=!1,i=!1,r=!1,s=!1,a=[];for(let l of e)l==="--global"||l==="-g"?(t=!0,n="global"):l==="--local"||l==="-l"?(o=!0,n="local"):l==="--dry-run"?i=!0:l==="--force"?r=!0:l==="--all"?s=!0:l.startsWith("-")||a.push(l);return{runtime:a[0],installLocation:n,dryRun:i,force:r,all:s,hasGlobal:t,hasLocal:o}}function Pe(){console.log(`frontend-craft - universal installer
49
49
 
50
50
  Usage:
51
51
  frontend-craft install <runtime> [options]
52
52
  frontend-craft install --all [options]
53
53
  frontend-craft install
54
- frontend-craft init [runtime] [options]
55
- fec init [runtime] [options]
54
+ frontend-craft setup [runtime] [options]
55
+ frontend-craft setup all [options]
56
+ fec setup [runtime] [options]
57
+ fec setup all [options]
56
58
  frontend-craft update [runtime] [options]
57
59
  frontend-craft upgrade [runtime] [options]
58
60
  frontend-craft uninstall|remove [runtime] [options]
@@ -71,12 +73,13 @@ Options:
71
73
  --all Install for every supported runtime
72
74
 
73
75
  Notes:
74
- init is an alias for install --local unless --global is explicitly provided.
76
+ setup connects frontend-craft to the current project. Omit runtime in an interactive terminal to choose runtimes.
77
+ setup <runtime> and setup all install locally by default unless --global is explicitly provided.
75
78
  update without a runtime refreshes discovered frontend-craft manifests.
76
79
  uninstall/remove deletes manifest-managed files and skips modified files unless --force is provided.
77
- /fec-init is the in-assistant slash command; fec init is the terminal CLI command.
80
+ /fec-init is the in-assistant slash command; fec setup is the terminal CLI command.
78
81
 
79
82
  Runtimes:
80
83
  ${F.join(", ")}
81
- `)}function Pn(e){let n=e[0];return n==null||["--dry-run","--all","--global","-g","--local","-l"].includes(n)}async function Un(e){let n=Pn(e)?"install":e[0],t=Pn(e)?e:e.slice(1),o=n==="init",i=$n(import.meta.url);if(n==="version"||n==="-v"||n==="--version"){console.log(Ee(i));return}if(n==="list"){F.forEach(h=>console.log(h));return}if(n==="matrix"){console.log(wn(F));return}if(n==="doctor"){let h=t[0]??"claude",_=t.includes("--global")||t.includes("-g"),P=t.includes("--fix-cache"),q=t.includes("--dry-run"),B=process.cwd(),L=Z({runtime:h,isGlobal:_,cwd:B}),be=Ce[h];if(!be){console.error(`Unknown runtime: ${h}`),process.exitCode=1;return}console.log($t({runtime:h,baseDir:L,cwd:B,cap:be,pluginRoot:i,fixCache:P,dryRun:q,isGlobal:_}));return}if(n==="sync-metadata"){let h=t.includes("--check"),_=Tt(i);if(_.length>0){for(let P of _)console.error(P);process.exitCode=1;return}console.log(h?"metadata is synchronized":"metadata is synchronized; no changes needed");return}if(n==="help"||n==="-h"||n==="--help"){Te();return}let r=n==="update"||n==="upgrade"?"update":"install";if(n!=="install"&&n!=="init"&&n!=="update"&&n!=="upgrade"&&n!=="uninstall"&&n!=="remove"){console.error(`Unknown command: ${n}`),Te(),process.exitCode=1;return}if(t.some(h=>h==="help"||h==="--help"||h==="-h")){Te();return}let{runtime:s,installLocation:a,dryRun:l,force:c,all:u,hasGlobal:g,hasLocal:R}=It(t),b=a??(o?"local":null);if(g&&R){console.error("--global and --local cannot be used together."),process.exitCode=1;return}let I=process.cwd();if(n==="uninstall"||n==="remove"){let h=Gn(R,g),P=je({cwd:I,runtimes:s?[s]:u?F:void 0,scopes:h});if(s&&!pe[s]){console.error(`Unknown runtime: ${s}`),process.exitCode=1;return}if(P.length===0){console.log(Ln("uninstall",s,h));return}for(let q of P){console.log(`Uninstalling frontend-craft for "${q.runtime}" -> ${q.baseDir}${q.scope==="global"?" (global)":""}`);let B=Oe({install:q,cwd:I,dryRun:l,force:c});for(let L of B.removed)console.log(`${l?"[dry-run] would remove":"Removed"}${L.modified?" modified file":" file"}: ${L.path}`);for(let L of B.skipped)console.log(`Skipped modified file: ${L}`);for(let L of B.missing)console.log(`Missing file: ${L}`);l&&B.skipped.length===0&&console.log(`[dry-run] would remove manifest: ${q.manifestPath}`)}return}let M=!!process.stdin.isTTY||process.env.FRONTEND_CRAFT_FORCE_INTERACTIVE==="1";if(r==="update"&&!s){let h=Gn(R,g),_=je({cwd:I,runtimes:u?F:void 0,scopes:h});if(_.length===0){console.log(Ln("update",void 0,h));return}for(let P of _)await En({rt:P.runtime,mode:r,isGlobal:P.scope==="global",baseDir:P.baseDir,pluginRoot:i,cwd:I,dryRun:l});return}let V=u?F:s?[s]:[];V.length||(M?V=await vn():(console.log("Non-interactive terminal detected, defaulting to claude runtime."),V=["claude"]));let G;b==="global"?G=!0:b==="local"?G=!1:M?G=await kn(V):(console.log("Non-interactive terminal detected, defaulting to global install."),G=!0);for(let h of V){if(!pe[h]){console.error(`Unknown runtime: ${h}`),process.exitCode=1;continue}let _=Z({runtime:h,isGlobal:G,cwd:I});await En({rt:h,mode:r,isGlobal:G,baseDir:_,pluginRoot:i,cwd:I,dryRun:l,force:c,canPrompt:M})}}async function En({rt:e,mode:n,isGlobal:t,baseDir:o,pluginRoot:i,cwd:r,dryRun:s,force:a,canPrompt:l}){let c=await vt({rt:e,mode:n,isGlobal:t,cwd:r,dryRun:s,force:!!a,canPrompt:!!l});if(!c)return;c.redirect&&(t=c.redirect.isGlobal,o=c.redirect.baseDir,n="update");let u={pluginRoot:i,cwd:r,runtime:e,isGlobal:t,baseDir:o,dryRun:s,mode:n,capabilities:Ce[e]};n==="install"?(console.log(`Installing frontend-craft for "${e}" -> ${o}${t?" (global)":""}`),!s&&m.existsSync(le(o))&&console.log(`Existing frontend-craft manifest found; use "frontend-craft update ${e}" to refresh managed files.`)):console.log(`Updating frontend-craft for "${e}" -> ${o}${t?" (global)":""}`),s||Ae({baseDir:o,cwd:r,mode:n,packageVersion:Ee(i),runtime:e,isGlobal:t});try{await pe[e](u),s||Ge()}catch(g){throw s||Le(),g}}async function vt({rt:e,mode:n,isGlobal:t,cwd:o,dryRun:i,force:r,canPrompt:s}){if(e!=="claude")return{};let a=Me({cwd:o});if(a.native.length>0){console.log("Claude Code Marketplace install detected for frontend-craft."),console.log(re(a)),console.log("Update frontend-craft through Claude Code Marketplace. CLI install/update is disabled while Marketplace is active."),process.exitCode=1;return}let l=t?"cli-global":"cli-local",c=a.cli.filter(I=>Pe(I)!==l);if(c.length===0)return a.hasMultipleActiveSources&&console.log(re(a)),{};let u=c[0],g=Pe(u);if(console.log(`${J(g)} install detected for frontend-craft.`),console.log(re(a)),i){console.log(`[dry-run] resolve the existing ${J(g)} source before using ${J(l)}.`),process.exitCode=1;return}if(!s){wt(g,l),process.exitCode=1;return}if(await Rt(g,l)==="switch"){if(!kt({installs:c,cwd:o,dryRun:i,force:r})){process.exitCode=1;return}return{}}let b=g==="cli-global";return{redirect:{isGlobal:b,baseDir:Z({runtime:"claude",isGlobal:b,cwd:o})}}}function kt({installs:e,cwd:n,dryRun:t,force:o}){for(let i of e){let r=je({cwd:n,runtimes:["claude"],scopes:[i.scope]})[0];if(!r)continue;console.log(`Uninstalling existing ${J(Pe(i))} install before switching source.`);let s=Oe({install:r,cwd:n,dryRun:t,force:o});for(let a of s.removed)console.log(`${t?"[dry-run] would remove":"Removed"}${a.modified?" modified file":" file"}: ${a.path}`);for(let a of s.skipped)console.log(`Skipped modified file: ${a}`);for(let a of s.missing)console.log(`Missing file: ${a}`);if(s.skipped.length>0)return console.log("Resolve skipped modified files or rerun with --force before switching Claude CLI install source."),!1}return!0}function wt(e,n){let t=An(e),o=An(n);console.log(`Keep the existing source updated with: frontend-craft update claude ${t}`),console.log(`Or switch sources with: frontend-craft uninstall claude ${t} && frontend-craft install claude ${o}`)}async function Rt(e,n){return console.log("Choose how to resolve the Claude CLI install source conflict:"),console.log(` 1. Keep ${J(e)} and update it`),console.log(` 2. Uninstall ${J(e)} and install ${J(n)}`),(await Dt("Choice [1]: ")).trim()==="2"?"switch":"keep"}function Dt(e){return process.env.FRONTEND_CRAFT_FORCE_INTERACTIVE==="1"&&!process.stdin.isTTY?(process.stdout.write(e),Promise.resolve(m.readFileSync(0,"utf8").split(/\r?\n/)[0]??"")):new Promise(n=>{let t=xt.createInterface({input:process.stdin,output:process.stdout});t.question(e,o=>{t.close(),n(o)}),t.on("close",()=>n(""))})}function Pe(e){return e.scope==="global"?"cli-global":"cli-local"}function J(e){return e==="marketplace"?"Claude Code Marketplace":e==="cli-global"?"Claude CLI global":"Claude CLI local"}function An(e){return e==="cli-global"?"--global":"--local"}function Gn(e,n){return e?["local"]:n?["global"]:["local","global"]}function Ln(e,n,t){return`No frontend-craft installs found${n?` for "${n}"`:""} to ${e} (${t.join(", ")}).`}function $t({runtime:e,baseDir:n,cwd:t,cap:o,pluginRoot:i,fixCache:r,dryRun:s,isGlobal:a}){let l=[`frontend-craft doctor: ${e}`,`baseDir: ${n}`,`tier: ${o.tier}`];if(l.push(`skills: ${te(Ot(e,n,t),o.skills)}`),l.push(`agents: ${te(m.existsSync(d.join(n,"agents")),o.agents)}`),l.push(`commands: ${te(Nt(e,n),o.commands)}`),l.push(`hooks: ${te(Ft(e,n),o.hooks)}`),l.push(`rules: ${te(Mt(e,n),o.rules&&!a)}`),l.push(`templates: ${te(_t(e,n,t),o.templates)}`),e==="claude"){let c=Ee(i);l.push(re(Me({cwd:t}))),r?l.push(Tn(_n({currentVersion:c,dryRun:s}),s)):l.push(Se(Fe({currentVersion:c})))}return l.join(`
82
- `)}function te(e,n){return n?e?"ok":"missing":"not expected"}function Ot(e,n,t){return e==="codex"?m.existsSync(d.join(t,".agents","skills","fec-react-project-standard")):e==="gemini"?m.existsSync(d.join(n,"extensions","frontend-craft","skills","fec-react-project-standard")):m.existsSync(d.join(n,"skills","fec-react-project-standard"))}function Nt(e,n){let t=e==="windsurf"?d.join(n,"workflows"):e==="opencode"||e==="kilo"?d.join(n,"command"):e==="copilot"?d.join(n,"prompts"):d.join(n,"commands");return m.existsSync(d.join(t,"fec-init.md"))}function Ft(e,n){return e==="qoder"?m.existsSync(d.join(n,"settings.json"))&&m.existsSync(d.join(n,"hooks","fec-security-check.js")):m.existsSync(d.join(n,"hooks.json"))}function Mt(e,n){return e==="copilot"?m.existsSync(d.join(n,"instructions","frontend-craft.instructions.md")):e==="cline"?m.existsSync(d.join(n,".clinerules")):m.existsSync(d.join(n,"rules"))}function _t(e,n,t){return e==="claude"?m.existsSync(d.join(t,".claude-plugin","plugin.json")):e==="codex"?m.existsSync(d.join(t,"AGENTS.md"))||m.existsSync(d.join(n,"config.toml")):e==="gemini"?m.existsSync(d.join(t,"GEMINI.md")):e==="openclaw"?m.existsSync(d.join(t,"AGENTS.md")):e==="qoder"?m.existsSync(d.join(n,"settings.json")):e==="opencode"?m.existsSync(d.join(n,"opencode.jsonc")):!1}function Tt(e){let n=[],t=JSON.parse(m.readFileSync(d.join(e,"package.json"),"utf8")),o=[[".claude-plugin/plugin.json","version"],[".claude-plugin/marketplace.json","plugins.0.version"],["openclaw.plugin.json","version"]];for(let[c,u]of o){let g=d.join(e,c),R=JSON.parse(m.readFileSync(g,"utf8")),b=u.split(".").reduce((I,M)=>I?.[Number.isNaN(Number(M))?M:Number(M)],R);b!==t.version&&n.push(`${c} ${u} is ${b}, expected ${t.version}`)}let i=JSON.parse(m.readFileSync(d.join(e,"skills","metadata.json"),"utf8"));for(let c of i)c.version!==t.version&&n.push(`skills/metadata.json ${c.id}.version is ${c.version}, expected ${t.version}`);let r=m.readdirSync(d.join(e,"commands")).filter(c=>c.endsWith(".md")).length,s=m.readdirSync(d.join(e,"skills"),{withFileTypes:!0}).filter(c=>c.isDirectory()).length,a=m.readdirSync(d.join(e,"agents")).filter(c=>c.endsWith(".md")).length,l=m.readFileSync(d.join(e,".claude-plugin","marketplace.json"),"utf8");return l.includes(`${a} agents`)||n.push(`marketplace description must mention ${a} agents`),l.includes(`${s} skills`)||n.push(`marketplace description must mention ${s} skills`),l.includes(`${r} commands`)||n.push(`marketplace description must mention ${r} commands`),n}Un(process.argv.slice(2)).catch(e=>{console.error(e),process.exit(1)});
84
+ `)}function En(e){let n=e[0];return n==null||["--dry-run","--all","--global","-g","--local","-l"].includes(n)}async function Wn(e){let n=En(e)?"install":e[0],t=En(e)?e:e.slice(1),o=n==="setup",i=On(import.meta.url);if(n==="version"||n==="-v"||n==="--version"){console.log(Ae(i));return}if(n==="list"){F.forEach(h=>console.log(h));return}if(n==="matrix"){console.log(Rn(F));return}if(n==="doctor"){let h=t[0]??"claude",_=t.includes("--global")||t.includes("-g"),P=t.includes("--fix-cache"),V=t.includes("--dry-run"),q=process.cwd(),G=Z({runtime:h,isGlobal:_,cwd:q}),xe=je[h];if(!xe){console.error(`Unknown runtime: ${h}`),process.exitCode=1;return}console.log(Ot({runtime:h,baseDir:G,cwd:q,cap:xe,pluginRoot:i,fixCache:P,dryRun:V,isGlobal:_}));return}if(n==="sync-metadata"){let h=t.includes("--check"),_=Pt(i);if(_.length>0){for(let P of _)console.error(P);process.exitCode=1;return}console.log(h?"metadata is synchronized":"metadata is synchronized; no changes needed");return}if(n==="help"||n==="-h"||n==="--help"){Pe();return}let r=n==="update"||n==="upgrade"?"update":"install";if(n!=="install"&&n!=="setup"&&n!=="update"&&n!=="upgrade"&&n!=="uninstall"&&n!=="remove"){console.error(`Unknown command: ${n}`),Pe(),process.exitCode=1;return}if(t.some(h=>h==="help"||h==="--help"||h==="-h")){Pe();return}let s=vt(t),a=s.runtime,l=s.all,{installLocation:c,dryRun:u,force:g,hasGlobal:R,hasLocal:S}=s;o&&a==="all"&&(a=void 0,l=!0);let M=c??(o?"local":null);if(R&&S){console.error("--global and --local cannot be used together."),process.exitCode=1;return}let I=process.cwd();if(n==="uninstall"||n==="remove"){let h=Ln(S,R),P=Se({cwd:I,runtimes:a?[a]:l?F:void 0,scopes:h});if(a&&!me[a]){console.error(`Unknown runtime: ${a}`),process.exitCode=1;return}if(P.length===0){console.log(Un("uninstall",a,h));return}for(let V of P){console.log(`Uninstalling frontend-craft for "${V.runtime}" -> ${V.baseDir}${V.scope==="global"?" (global)":""}`);let q=Ne({install:V,cwd:I,dryRun:u,force:g});for(let G of q.removed)console.log(`${u?"[dry-run] would remove":"Removed"}${G.modified?" modified file":" file"}: ${G.path}`);for(let G of q.skipped)console.log(`Skipped modified file: ${G}`);for(let G of q.missing)console.log(`Missing file: ${G}`);u&&q.skipped.length===0&&console.log(`[dry-run] would remove manifest: ${V.manifestPath}`)}return}let oe=!!process.stdin.isTTY||process.env.FRONTEND_CRAFT_FORCE_INTERACTIVE==="1";if(r==="update"&&!a){let h=Ln(S,R),_=Se({cwd:I,runtimes:l?F:void 0,scopes:h});if(_.length===0){console.log(Un("update",void 0,h));return}for(let P of _)await An({rt:P.runtime,mode:r,isGlobal:P.scope==="global",baseDir:P.baseDir,pluginRoot:i,cwd:I,dryRun:u});return}let W=l?F:a?[a]:[];W.length||(oe?W=await kn():(console.log("Non-interactive terminal detected, defaulting to claude runtime."),W=["claude"]));let J;M==="global"?J=!0:M==="local"?J=!1:oe?J=await wn(W):(console.log("Non-interactive terminal detected, defaulting to global install."),J=!0);for(let h of W){if(!me[h]){console.error(`Unknown runtime: ${h}`),process.exitCode=1;continue}let _=Z({runtime:h,isGlobal:J,cwd:I});await An({rt:h,mode:r,isGlobal:J,baseDir:_,pluginRoot:i,cwd:I,dryRun:u,force:g,canPrompt:oe})}}async function An({rt:e,mode:n,isGlobal:t,baseDir:o,pluginRoot:i,cwd:r,dryRun:s,force:a,canPrompt:l}){let c=await kt({rt:e,mode:n,isGlobal:t,cwd:r,dryRun:s,force:!!a,canPrompt:!!l});if(!c)return;c.redirect&&(t=c.redirect.isGlobal,o=c.redirect.baseDir,n="update");let u={pluginRoot:i,cwd:r,runtime:e,isGlobal:t,baseDir:o,dryRun:s,mode:n,capabilities:je[e]};n==="install"?(console.log(`Installing frontend-craft for "${e}" -> ${o}${t?" (global)":""}`),!s&&m.existsSync(ae(o))&&console.log(`Existing frontend-craft manifest found; use "frontend-craft update ${e}" to refresh managed files.`)):console.log(`Updating frontend-craft for "${e}" -> ${o}${t?" (global)":""}`),s||Ge({baseDir:o,cwd:r,mode:n,packageVersion:Ae(i),runtime:e,isGlobal:t});try{await me[e](u),s||Le()}catch(g){throw s||Ue(),g}}async function kt({rt:e,mode:n,isGlobal:t,cwd:o,dryRun:i,force:r,canPrompt:s}){if(e!=="claude")return{};let a=_e({cwd:o});if(a.native.length>0){console.log("Claude Code Marketplace install detected for frontend-craft."),console.log(le(a)),console.log("Update frontend-craft through Claude Code Marketplace. CLI install/update is disabled while Marketplace is active."),process.exitCode=1;return}let l=t?"cli-global":"cli-local",c=a.cli.filter(M=>Ee(M)!==l);if(c.length===0)return a.hasMultipleActiveSources&&console.log(le(a)),{};let u=c[0],g=Ee(u);if(console.log(`${K(g)} install detected for frontend-craft.`),console.log(le(a)),i){console.log(`[dry-run] resolve the existing ${K(g)} source before using ${K(l)}.`),process.exitCode=1;return}if(!s){Rt(g,l),process.exitCode=1;return}if(await Dt(g,l)==="switch"){if(!wt({installs:c,cwd:o,dryRun:i,force:r})){process.exitCode=1;return}return{}}let S=g==="cli-global";return{redirect:{isGlobal:S,baseDir:Z({runtime:"claude",isGlobal:S,cwd:o})}}}function wt({installs:e,cwd:n,dryRun:t,force:o}){for(let i of e){let r=Se({cwd:n,runtimes:["claude"],scopes:[i.scope]})[0];if(!r)continue;console.log(`Uninstalling existing ${K(Ee(i))} install before switching source.`);let s=Ne({install:r,cwd:n,dryRun:t,force:o});for(let a of s.removed)console.log(`${t?"[dry-run] would remove":"Removed"}${a.modified?" modified file":" file"}: ${a.path}`);for(let a of s.skipped)console.log(`Skipped modified file: ${a}`);for(let a of s.missing)console.log(`Missing file: ${a}`);if(s.skipped.length>0)return console.log("Resolve skipped modified files or rerun with --force before switching Claude CLI install source."),!1}return!0}function Rt(e,n){let t=Gn(e),o=Gn(n);console.log(`Keep the existing source updated with: frontend-craft update claude ${t}`),console.log(`Or switch sources with: frontend-craft uninstall claude ${t} && frontend-craft install claude ${o}`)}async function Dt(e,n){return console.log("Choose how to resolve the Claude CLI install source conflict:"),console.log(` 1. Keep ${K(e)} and update it`),console.log(` 2. Uninstall ${K(e)} and install ${K(n)}`),(await $t("Choice [1]: ")).trim()==="2"?"switch":"keep"}function $t(e){return process.env.FRONTEND_CRAFT_FORCE_INTERACTIVE==="1"&&!process.stdin.isTTY?(process.stdout.write(e),Promise.resolve(m.readFileSync(0,"utf8").split(/\r?\n/)[0]??"")):new Promise(n=>{let t=It.createInterface({input:process.stdin,output:process.stdout});t.question(e,o=>{t.close(),n(o)}),t.on("close",()=>n(""))})}function Ee(e){return e.scope==="global"?"cli-global":"cli-local"}function K(e){return e==="marketplace"?"Claude Code Marketplace":e==="cli-global"?"Claude CLI global":"Claude CLI local"}function Gn(e){return e==="cli-global"?"--global":"--local"}function Ln(e,n){return e?["local"]:n?["global"]:["local","global"]}function Un(e,n,t){return`No frontend-craft installs found${n?` for "${n}"`:""} to ${e} (${t.join(", ")}).`}function Ot({runtime:e,baseDir:n,cwd:t,cap:o,pluginRoot:i,fixCache:r,dryRun:s,isGlobal:a}){let l=[`frontend-craft doctor: ${e}`,`baseDir: ${n}`,`tier: ${o.tier}`];if(l.push(`skills: ${te(Nt(e,n,t),o.skills)}`),l.push(`agents: ${te(m.existsSync(d.join(n,"agents")),o.agents)}`),l.push(`commands: ${te(Ft(e,n),o.commands)}`),l.push(`hooks: ${te(Mt(e,n),o.hooks)}`),l.push(`rules: ${te(_t(e,n),o.rules&&!a)}`),l.push(`templates: ${te(Tt(e,n,t),o.templates)}`),e==="claude"){let c=Ae(i);l.push(le(_e({cwd:t}))),r?l.push(Pn(Tn({currentVersion:c,dryRun:s}),s)):l.push(be(Me({currentVersion:c})))}return l.join(`
85
+ `)}function te(e,n){return n?e?"ok":"missing":"not expected"}function Nt(e,n,t){return e==="codex"?m.existsSync(d.join(t,".agents","skills","fec-react-project-standard")):e==="gemini"?m.existsSync(d.join(n,"extensions","frontend-craft","skills","fec-react-project-standard")):m.existsSync(d.join(n,"skills","fec-react-project-standard"))}function Ft(e,n){let t=e==="windsurf"?d.join(n,"workflows"):e==="opencode"||e==="kilo"?d.join(n,"command"):e==="copilot"?d.join(n,"prompts"):d.join(n,"commands");return m.existsSync(d.join(t,"fec-init.md"))}function Mt(e,n){return e==="qoder"?m.existsSync(d.join(n,"settings.json"))&&m.existsSync(d.join(n,"hooks","fec-security-check.js")):m.existsSync(d.join(n,"hooks.json"))}function _t(e,n){return e==="copilot"?m.existsSync(d.join(n,"instructions","frontend-craft.instructions.md")):e==="cline"?m.existsSync(d.join(n,".clinerules")):m.existsSync(d.join(n,"rules"))}function Tt(e,n,t){return e==="claude"?m.existsSync(d.join(t,".claude-plugin","plugin.json")):e==="codex"?m.existsSync(d.join(t,"AGENTS.md"))||m.existsSync(d.join(n,"config.toml")):e==="gemini"?m.existsSync(d.join(t,"GEMINI.md")):e==="openclaw"?m.existsSync(d.join(t,"AGENTS.md")):e==="qoder"?m.existsSync(d.join(n,"settings.json")):e==="opencode"?m.existsSync(d.join(n,"opencode.jsonc")):!1}function Pt(e){let n=[],t=JSON.parse(m.readFileSync(d.join(e,"package.json"),"utf8")),o=[[".claude-plugin/plugin.json","version"],[".claude-plugin/marketplace.json","plugins.0.version"],["openclaw.plugin.json","version"]];for(let[c,u]of o){let g=d.join(e,c),R=JSON.parse(m.readFileSync(g,"utf8")),S=u.split(".").reduce((M,I)=>M?.[Number.isNaN(Number(I))?I:Number(I)],R);S!==t.version&&n.push(`${c} ${u} is ${S}, expected ${t.version}`)}let i=JSON.parse(m.readFileSync(d.join(e,"skills","metadata.json"),"utf8"));for(let c of i)c.version!==t.version&&n.push(`skills/metadata.json ${c.id}.version is ${c.version}, expected ${t.version}`);let r=m.readdirSync(d.join(e,"commands")).filter(c=>c.endsWith(".md")).length,s=m.readdirSync(d.join(e,"skills"),{withFileTypes:!0}).filter(c=>c.isDirectory()).length,a=m.readdirSync(d.join(e,"agents")).filter(c=>c.endsWith(".md")).length,l=m.readFileSync(d.join(e,".claude-plugin","marketplace.json"),"utf8");return l.includes(`${a} agents`)||n.push(`marketplace description must mention ${a} agents`),l.includes(`${s} skills`)||n.push(`marketplace description must mention ${s} skills`),l.includes(`${r} commands`)||n.push(`marketplace description must mention ${r} commands`),n}Wn(process.argv.slice(2)).catch(e=>{console.error(e),process.exit(1)});