lcap-frontend-library 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +271 -0
- package/bin/lcap-frontend-library.mjs +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +27 -0
- package/dist/init.d.ts +6 -0
- package/dist/init.js +79 -0
- package/dist/sync.d.ts +4 -0
- package/dist/sync.js +70 -0
- package/dist/utils.d.ts +19 -0
- package/dist/utils.js +101 -0
- package/package.json +34 -0
- package/packages/lcap-frontend-library/LEARNINGS.md +11 -0
- package/packages/lcap-frontend-library/SKILL.md +86 -0
- package/packages/lcap-frontend-library/commands/migrate.check.md +287 -0
- package/packages/lcap-frontend-library/commands/migrate.green.md +190 -0
- package/packages/lcap-frontend-library/commands/migrate.plan.md +169 -0
- package/packages/lcap-frontend-library/commands/migrate.red.md +160 -0
- package/packages/lcap-frontend-library/commands/migrate.scan.md +151 -0
- package/packages/lcap-frontend-library/commands/migrate.spec.md +144 -0
- package/packages/lcap-frontend-library/commands/migrate.tasks.md +179 -0
- package/packages/lcap-frontend-library/commands/speckit.create.md +201 -0
- package/packages/lcap-frontend-library/commands/speckit.implement.md +88 -0
- package/packages/lcap-frontend-library/commands/speckit.plan.md +79 -0
- package/packages/lcap-frontend-library/commands/speckit.self-check.md +177 -0
- package/packages/lcap-frontend-library/commands/speckit.specify.md +91 -0
- package/packages/lcap-frontend-library/commands/speckit.tasks.md +61 -0
- package/packages/lcap-frontend-library/references/frontend-design/LICENSE.txt +177 -0
- package/packages/lcap-frontend-library/references/frontend-design/SKILL.md +42 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/SKILL.md +360 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/api.md +331 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/block.md +160 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/i18n.md +95 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/icon.md +27 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide/container.md +728 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide/element.md +312 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide/expression.md +154 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide/index.md +113 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide/modal.md +189 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide/popover.md +171 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide.md +799 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/implementation-rules.md +242 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/index.md +27 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/nasl-view-component.md +895 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/accessibility.md +185 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/child.md +82 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/data-source.md +261 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/event.md +171 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/form.md +266 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/function.md +80 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/link.md +137 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/slot.md +128 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/theme-variables-ant-design.md +1470 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/theme-variables-cloud-ui.md +259 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/theme-variables-element-plus.md +580 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/theme-variables-element-ui.md +1007 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/theme-variables-mobile-ui.md +85 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/theme.md +234 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/workflow-guardrails.md +328 -0
- package/packages/lcap-frontend-library/references/nasl-logic-authoring/SKILL.md +201 -0
- package/packages/lcap-frontend-library/scripts/bash/create-component-files.sh +95 -0
- package/packages/lcap-frontend-library/scripts/bash/create-extension-project.sh +109 -0
- package/packages/lcap-frontend-library/scripts/bash/create-logic-files.sh +149 -0
- package/packages/lcap-frontend-library/scripts/bash/create-spec.sh +109 -0
- package/packages/lcap-frontend-library/scripts/bash/get-available-port.sh +35 -0
- package/packages/lcap-frontend-library/scripts/bash/list-specs.sh +19 -0
- package/packages/lcap-frontend-library/scripts/node/setup-extension-project.mjs +166 -0
- package/packages/lcap-frontend-library/templates/component-self-check.md +31 -0
- package/packages/lcap-frontend-library/templates/component-template.md +96 -0
- package/packages/lcap-frontend-library/templates/library-report-template.md +52 -0
- package/packages/lcap-frontend-library/templates/logic-template.md +44 -0
- package/packages/lcap-frontend-library/templates/migration-manifest-template.md +84 -0
- package/packages/lcap-frontend-library/templates/migration-plan-template.md +138 -0
- package/packages/lcap-frontend-library/templates/migration-report-template.md +227 -0
- package/packages/lcap-frontend-library/templates/migration-spec-template.md +135 -0
- package/packages/lcap-frontend-library/templates/migration-tasks-template.md +129 -0
- package/packages/lcap-frontend-library/templates/plan-template.md +299 -0
- package/packages/lcap-frontend-library/templates/self-check-report-template.md +148 -0
- package/packages/lcap-frontend-library/templates/tasks-template.md +81 -0
- package/packages/lcap-frontend-library/workflows/create/flow.md +199 -0
- package/packages/lcap-frontend-library/workflows/evolve/flow.md +249 -0
- package/packages/lcap-frontend-library/workflows/generate/flow.md +10 -0
- package/packages/lcap-frontend-library/workflows/harness/flow.md +82 -0
- package/packages/lcap-frontend-library/workflows/migrate/flow.md +302 -0
- package/packages/lcap-frontend-library/workflows/migrate/knowledge-base.md +564 -0
package/README.md
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# lcap-frontend-library
|
|
2
|
+
|
|
3
|
+
> LCAP 前端扩展组件库 AI Skill 分发 CLI —— 将领域知识注入 AI 编码助手
|
|
4
|
+
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
[](https://www.npmjs.com/package/lcap-frontend-library)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 这是什么
|
|
11
|
+
|
|
12
|
+
`lcap-frontend-library` 是一个 npm CLI 工具,将 LCAP 前端扩展组件库的 AI Skill(结构化 Markdown 指令集)部署到 AI 编码助手的 skill 目录中。
|
|
13
|
+
|
|
14
|
+
**核心理念**:AI Skill as npm package —— 安装即部署,升级即同步。同一份 Skill 内容通过路径映射适配 Claude Code、Cursor、Codex 三个平台,无需任何平台专有 API。
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 快速开始
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# 部署 Skill 到 AI 工具目录
|
|
22
|
+
npx lcap-frontend-library init
|
|
23
|
+
|
|
24
|
+
# 交互选择:安装范围(项目/全局)+ 目标工具(claude/cursor/codex)
|
|
25
|
+
|
|
26
|
+
# 在 AI 工具中使用 —— 输入自然语言即可
|
|
27
|
+
# 「生成一个二维码组件」
|
|
28
|
+
# 「把这个库从 Vue2 迁移到 Vue3」
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
验证安装:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
ls .claude/skills/lcap-frontend-library/SKILL.md
|
|
35
|
+
cat .lcap-skill.json
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## CLI 命令
|
|
41
|
+
|
|
42
|
+
### `init`
|
|
43
|
+
|
|
44
|
+
首次部署 Skill。
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx lcap-frontend-library init [options]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
| 选项 | 说明 | 示例 |
|
|
51
|
+
|------|------|------|
|
|
52
|
+
| `--tools <list>` | 指定目标工具(逗号分隔) | `--tools claude,cursor` |
|
|
53
|
+
| `--global` | 部署到全局目录(`~/.{tool}/skills/`) | `--global` |
|
|
54
|
+
| `--all` | 部署到所有支持的工具 | `--all` |
|
|
55
|
+
|
|
56
|
+
**行为**:
|
|
57
|
+
- 无 flag + TTY:交互模式(select + checkbox)
|
|
58
|
+
- 无 flag + 非 TTY(CI):自动部署所有工具,项目级
|
|
59
|
+
- 已安装时:提示使用 `sync`
|
|
60
|
+
|
|
61
|
+
### `sync`
|
|
62
|
+
|
|
63
|
+
更新已部署的 Skill 到最新版本。
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx lcap-frontend-library sync [options]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
| 选项 | 说明 |
|
|
70
|
+
|------|------|
|
|
71
|
+
| `--tools <list>` | 覆盖同步目标(默认同步所有已安装工具) |
|
|
72
|
+
|
|
73
|
+
**行为**:
|
|
74
|
+
1. 读取 `.lcap-skill.json` 获取安装信息
|
|
75
|
+
2. 删除旧 skill 目录 → 复制最新内容
|
|
76
|
+
3. 保留 `LEARNINGS.md`(含 `### LEARN-` 标记时)
|
|
77
|
+
4. 更新 marker 版本号
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 架构
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
lcap-frontend-library/
|
|
85
|
+
├── bin/
|
|
86
|
+
│ └── lcap-frontend-library.mjs # CLI 入口(ESM shebang)
|
|
87
|
+
├── src/
|
|
88
|
+
│ ├── index.ts # Commander 程序定义(init + sync)
|
|
89
|
+
│ ├── init.ts # 初始化逻辑(交互/flag/非TTY 三路径)
|
|
90
|
+
│ ├── sync.ts # 同步逻辑(删旧→复新→恢复 LEARNINGS)
|
|
91
|
+
│ └── utils.ts # 工具函数(路径映射、文件操作、marker 读写)
|
|
92
|
+
├── skill/ # AI Skill 内容(随包分发)
|
|
93
|
+
│ ├── SKILL.md # 顶层路由分发器
|
|
94
|
+
│ ├── LEARNINGS.md # 经验库
|
|
95
|
+
│ ├── commands/ # 13 个阶段命令
|
|
96
|
+
│ ├── workflows/ # 流程编排(create/evolve/migrate/harness)
|
|
97
|
+
│ ├── references/ # 领域知识库
|
|
98
|
+
│ ├── templates/ # 输出格式模板
|
|
99
|
+
│ └── scripts/ # 脚手架脚本(bash + node)
|
|
100
|
+
├── dist/ # TypeScript 编译产物
|
|
101
|
+
├── package.json
|
|
102
|
+
└── tsconfig.json
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 技术栈
|
|
106
|
+
|
|
107
|
+
| 依赖 | 用途 |
|
|
108
|
+
|------|------|
|
|
109
|
+
| `commander` ^12 | CLI 命令框架 |
|
|
110
|
+
| `@inquirer/prompts` ^7 | 交互式选择 |
|
|
111
|
+
| `typescript` ^5.5 | 类型安全 + 编译 |
|
|
112
|
+
|
|
113
|
+
### 分发模型
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
上游 Skill 源(monorepo)
|
|
117
|
+
│ npm run sync-skill
|
|
118
|
+
▼
|
|
119
|
+
npm 包(skill/ 目录)
|
|
120
|
+
│ npx lcap-frontend-library init/sync
|
|
121
|
+
▼
|
|
122
|
+
用户项目 AI 工具目录
|
|
123
|
+
.claude/skills/lcap-frontend-library/
|
|
124
|
+
.cursor/skills/lcap-frontend-library/
|
|
125
|
+
.codex/skills/lcap-frontend-library/
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 多平台适配
|
|
131
|
+
|
|
132
|
+
### 路径映射
|
|
133
|
+
|
|
134
|
+
在 `src/utils.ts` 中定义:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
export const TOOL_PATHS: Record<string, string> = {
|
|
138
|
+
claude: `.claude/skills/${SKILL_NAME}`,
|
|
139
|
+
cursor: `.cursor/skills/${SKILL_NAME}`,
|
|
140
|
+
codex: `.codex/skills/${SKILL_NAME}`,
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export const GLOBAL_TOOL_PATHS: Record<string, string> = {
|
|
144
|
+
claude: path.join(os.homedir(), '.claude', 'skills', SKILL_NAME),
|
|
145
|
+
cursor: path.join(os.homedir(), '.cursor', 'skills', SKILL_NAME),
|
|
146
|
+
codex: path.join(os.homedir(), '.codex', 'skills', SKILL_NAME),
|
|
147
|
+
};
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 添加新平台
|
|
151
|
+
|
|
152
|
+
仅需在 `TOOL_PATHS` 和 `GLOBAL_TOOL_PATHS` 中添加条目:
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
windsurf: `.windsurf/skills/${SKILL_NAME}`,
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`init.ts` 和 `sync.ts` 动态读取 key,无需额外修改。
|
|
159
|
+
|
|
160
|
+
### 平台路径对照
|
|
161
|
+
|
|
162
|
+
| 工具 | 项目级 | 全局级 |
|
|
163
|
+
|------|--------|--------|
|
|
164
|
+
| claude | `.claude/skills/lcap-frontend-library/` | `~/.claude/skills/lcap-frontend-library/` |
|
|
165
|
+
| cursor | `.cursor/skills/lcap-frontend-library/` | `~/.cursor/skills/lcap-frontend-library/` |
|
|
166
|
+
| codex | `.codex/skills/lcap-frontend-library/` | `~/.codex/skills/lcap-frontend-library/` |
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Marker 文件
|
|
171
|
+
|
|
172
|
+
`.lcap-skill.json` 记录安装状态:
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
interface Marker {
|
|
176
|
+
version: string; // npm 包版本
|
|
177
|
+
tools: string[]; // 已部署的工具列表
|
|
178
|
+
scope: 'global' | 'project';
|
|
179
|
+
installedAt: string; // ISO 时间戳
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
- 项目级:写入项目根目录
|
|
184
|
+
- 全局级:写入 `~/`
|
|
185
|
+
- `init` 检查此文件防止重复安装
|
|
186
|
+
- `sync` 依赖此文件确定同步目标
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 开发
|
|
191
|
+
|
|
192
|
+
### 环境准备
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
git clone <repo-url>
|
|
196
|
+
cd npm/lcap-frontend-library
|
|
197
|
+
npm install
|
|
198
|
+
npm run build
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 本地测试
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
# 直接运行
|
|
205
|
+
node bin/lcap-frontend-library.mjs init --tools claude
|
|
206
|
+
|
|
207
|
+
# 或 npm link
|
|
208
|
+
npm link
|
|
209
|
+
lcap-frontend-library init
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Skill 内容更新
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# 从上游 monorepo 同步 Skill 源
|
|
216
|
+
npm run sync-skill
|
|
217
|
+
|
|
218
|
+
# 验证后发布
|
|
219
|
+
npm version patch
|
|
220
|
+
npm publish
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
用户通过 `npx lcap-frontend-library sync` 获取更新。
|
|
224
|
+
|
|
225
|
+
### 项目构建
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
npm run build # TypeScript 编译到 dist/
|
|
229
|
+
npm run prepare # publish 前自动触发 build
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Skill 能力概览
|
|
235
|
+
|
|
236
|
+
部署后,AI 工具获得以下能力:
|
|
237
|
+
|
|
238
|
+
| 工作流 | 触发词 | 产出 |
|
|
239
|
+
|--------|--------|------|
|
|
240
|
+
| **Create** | 生成、新建、创建 | 完整可构建 LCAP 项目 + ZIP 产物 |
|
|
241
|
+
| **Evolve** | 修改、增强、更新 | 增量功能 + 零回归保证 |
|
|
242
|
+
| **Migrate** | 迁移、升级、Vue2→Vue3 | 行为等价的 Vue3 项目 |
|
|
243
|
+
| **Harness** | 归因回流、记录教训 | LEARNINGS.md 经验条目 |
|
|
244
|
+
|
|
245
|
+
详细说明参见 [USAGE.md](./USAGE.md)。
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 设计决策
|
|
250
|
+
|
|
251
|
+
| 决策 | 理由 |
|
|
252
|
+
|------|------|
|
|
253
|
+
| 纯 Markdown Skill | 零平台依赖,一份内容多平台复用 |
|
|
254
|
+
| npm 分发 | semver + 一致性 + CI 友好 |
|
|
255
|
+
| 路径映射而非配置文件 | 新增平台只改一行代码 |
|
|
256
|
+
| LEARNINGS.md 保留策略 | sync 不丢失用户积累的经验 |
|
|
257
|
+
| ESM + Node >= 18 | 使用原生 fs recursive、top-level await |
|
|
258
|
+
| 脚本 chmod 自动化 | 用户无需手动 `chmod +x` |
|
|
259
|
+
| marker 文件防重复 | init 幂等,sync 精准定位 |
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## 相关文档
|
|
264
|
+
|
|
265
|
+
- [USAGE.md](./USAGE.md) — 完整使用说明(功能详解、使用案例、内部机制、设计亮点、对比分析)
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## License
|
|
270
|
+
|
|
271
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function main(): Promise<void>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { init } from './init.js';
|
|
3
|
+
import { sync } from './sync.js';
|
|
4
|
+
export async function main() {
|
|
5
|
+
const program = new Command();
|
|
6
|
+
program
|
|
7
|
+
.name('lcap-frontend-library')
|
|
8
|
+
.description('LCAP 前端扩展组件库 AI Skill 分发器')
|
|
9
|
+
.version('0.1.0');
|
|
10
|
+
program
|
|
11
|
+
.command('init')
|
|
12
|
+
.description('首次安装:选择工具 → 投放 skill')
|
|
13
|
+
.option('--tools <tools>', '指定工具(逗号分隔):claude,cursor,codex')
|
|
14
|
+
.option('--global', '安装到全局目录(~/.claude/skills/ 等)')
|
|
15
|
+
.option('--all', '投放到所有支持的工具')
|
|
16
|
+
.action(async (options) => {
|
|
17
|
+
await init(process.cwd(), options);
|
|
18
|
+
});
|
|
19
|
+
program
|
|
20
|
+
.command('sync')
|
|
21
|
+
.description('同步:将包内最新 skill 投放到已记录的工具目录')
|
|
22
|
+
.option('--tools <tools>', '指定工具(逗号分隔),默认使用 init 时的选择')
|
|
23
|
+
.action((options) => {
|
|
24
|
+
sync(process.cwd(), options);
|
|
25
|
+
});
|
|
26
|
+
await program.parseAsync();
|
|
27
|
+
}
|
package/dist/init.d.ts
ADDED
package/dist/init.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { select, checkbox } from '@inquirer/prompts';
|
|
4
|
+
import { TOOL_PATHS, GLOBAL_TOOL_PATHS, SKILL_NAME, getSkillSourceDir, getPackageVersion, readMarker, writeMarker, copyDirRecursive, chmodScripts, } from './utils.js';
|
|
5
|
+
export async function init(projectDir, options) {
|
|
6
|
+
// Determine scope from flags
|
|
7
|
+
let scope = options.global ? 'global' : 'project';
|
|
8
|
+
// Check if already installed for this scope
|
|
9
|
+
const marker = readMarker(projectDir, scope);
|
|
10
|
+
if (marker) {
|
|
11
|
+
console.log(`⚠ ${SKILL_NAME} 已安装 (v${marker.version}),范围: ${marker.scope},工具: ${marker.tools.join(', ')}`);
|
|
12
|
+
console.log(` 如需同步最新版本,请使用: npx ${SKILL_NAME} sync`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
let tools;
|
|
16
|
+
if (options.all) {
|
|
17
|
+
// --all: select all tools for the determined scope
|
|
18
|
+
tools = scope === 'global' ? Object.keys(GLOBAL_TOOL_PATHS) : Object.keys(TOOL_PATHS);
|
|
19
|
+
}
|
|
20
|
+
else if (options.tools) {
|
|
21
|
+
// --tools provided: direct execution
|
|
22
|
+
const pathMap = scope === 'global' ? GLOBAL_TOOL_PATHS : TOOL_PATHS;
|
|
23
|
+
tools = options.tools.split(',').map(t => t.trim()).filter(t => t in pathMap);
|
|
24
|
+
if (tools.length === 0) {
|
|
25
|
+
console.error(`错误:无效的工具名。可选: ${Object.keys(pathMap).join(', ')}`);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
else if (process.stdout.isTTY) {
|
|
30
|
+
// Interactive mode
|
|
31
|
+
scope = await select({
|
|
32
|
+
message: '安装范围',
|
|
33
|
+
choices: [
|
|
34
|
+
{ value: 'project', name: '当前项目(推荐)' },
|
|
35
|
+
{ value: 'global', name: '全局(所有项目共享)' },
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
const availableTools = scope === 'global'
|
|
39
|
+
? Object.keys(GLOBAL_TOOL_PATHS)
|
|
40
|
+
: Object.keys(TOOL_PATHS);
|
|
41
|
+
tools = await checkbox({
|
|
42
|
+
message: '选择要安装的 AI 工具(空格选择,回车确认)',
|
|
43
|
+
choices: availableTools.map(t => ({ value: t, name: t, checked: true })),
|
|
44
|
+
});
|
|
45
|
+
if (tools.length === 0) {
|
|
46
|
+
console.error('错误:至少选择一个工具');
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// Non-TTY fallback: project-level, all tools
|
|
52
|
+
tools = Object.keys(TOOL_PATHS);
|
|
53
|
+
console.log(`未检测到终端交互,将为所有工具创建: ${tools.join(', ')}`);
|
|
54
|
+
}
|
|
55
|
+
const skillSrc = getSkillSourceDir();
|
|
56
|
+
if (!fs.existsSync(skillSrc)) {
|
|
57
|
+
console.error(`错误:skill 源目录不存在: ${skillSrc}`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
const version = getPackageVersion();
|
|
61
|
+
// Deploy to each tool
|
|
62
|
+
for (const tool of tools) {
|
|
63
|
+
const targetDir = scope === 'global'
|
|
64
|
+
? GLOBAL_TOOL_PATHS[tool]
|
|
65
|
+
: path.join(projectDir, TOOL_PATHS[tool]);
|
|
66
|
+
console.log(` → ${scope === 'global' ? GLOBAL_TOOL_PATHS[tool] : TOOL_PATHS[tool]}/`);
|
|
67
|
+
copyDirRecursive(skillSrc, targetDir);
|
|
68
|
+
chmodScripts(targetDir);
|
|
69
|
+
}
|
|
70
|
+
// Write marker
|
|
71
|
+
writeMarker(projectDir, {
|
|
72
|
+
version,
|
|
73
|
+
tools,
|
|
74
|
+
scope,
|
|
75
|
+
installedAt: new Date().toISOString(),
|
|
76
|
+
});
|
|
77
|
+
console.log(`\n✓ ${SKILL_NAME} v${version} 已安装(${scope === 'global' ? '全局' : '项目级'})`);
|
|
78
|
+
console.log(`\n使用方式:在 AI 工具中输入 /${SKILL_NAME}`);
|
|
79
|
+
}
|
package/dist/sync.d.ts
ADDED
package/dist/sync.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { TOOL_PATHS, GLOBAL_TOOL_PATHS, SKILL_NAME, getSkillSourceDir, getPackageVersion, readMarker, writeMarker, copyDirRecursive, chmodScripts, rmDirRecursive, } from './utils.js';
|
|
4
|
+
export function sync(projectDir, options) {
|
|
5
|
+
const marker = readMarker(projectDir);
|
|
6
|
+
if (!marker) {
|
|
7
|
+
console.error(`错误:未找到 .lcap-skill.json,请先执行: npx ${SKILL_NAME} init`);
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
const scope = marker.scope || 'project';
|
|
11
|
+
const pathMap = scope === 'global' ? GLOBAL_TOOL_PATHS : TOOL_PATHS;
|
|
12
|
+
// Determine target tools
|
|
13
|
+
let tools;
|
|
14
|
+
if (options.tools) {
|
|
15
|
+
tools = options.tools.split(',').map(t => t.trim()).filter(t => t in pathMap);
|
|
16
|
+
if (tools.length === 0) {
|
|
17
|
+
console.error(`错误:无效的工具名。可选: ${Object.keys(pathMap).join(', ')}`);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
tools = marker.tools;
|
|
23
|
+
}
|
|
24
|
+
const skillSrc = getSkillSourceDir();
|
|
25
|
+
if (!fs.existsSync(skillSrc)) {
|
|
26
|
+
console.error(`错误:skill 源目录不存在: ${skillSrc}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const oldVersion = marker.version;
|
|
30
|
+
const newVersion = getPackageVersion();
|
|
31
|
+
for (const tool of tools) {
|
|
32
|
+
const targetDir = scope === 'global'
|
|
33
|
+
? GLOBAL_TOOL_PATHS[tool]
|
|
34
|
+
: path.join(projectDir, TOOL_PATHS[tool]);
|
|
35
|
+
// Backup LEARNINGS.md if it exists and has user content
|
|
36
|
+
const learningsPath = path.join(targetDir, 'LEARNINGS.md');
|
|
37
|
+
let learningsBackup = null;
|
|
38
|
+
if (fs.existsSync(learningsPath)) {
|
|
39
|
+
const content = fs.readFileSync(learningsPath, 'utf8');
|
|
40
|
+
if (content.includes('### LEARN-')) {
|
|
41
|
+
learningsBackup = content;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Remove old skill directory
|
|
45
|
+
rmDirRecursive(targetDir);
|
|
46
|
+
// Copy fresh skill
|
|
47
|
+
const displayPath = scope === 'global' ? GLOBAL_TOOL_PATHS[tool] : TOOL_PATHS[tool];
|
|
48
|
+
console.log(` → ${displayPath}/`);
|
|
49
|
+
copyDirRecursive(skillSrc, targetDir);
|
|
50
|
+
chmodScripts(targetDir);
|
|
51
|
+
// Restore LEARNINGS.md
|
|
52
|
+
if (learningsBackup) {
|
|
53
|
+
fs.writeFileSync(learningsPath, learningsBackup);
|
|
54
|
+
console.log(` ↳ LEARNINGS.md 已保留(含用户记录)`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Update marker
|
|
58
|
+
writeMarker(projectDir, {
|
|
59
|
+
version: newVersion,
|
|
60
|
+
tools,
|
|
61
|
+
scope,
|
|
62
|
+
installedAt: new Date().toISOString(),
|
|
63
|
+
});
|
|
64
|
+
if (oldVersion !== newVersion) {
|
|
65
|
+
console.log(`\n✓ synced v${oldVersion} → v${newVersion}`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
console.log(`\n✓ synced (v${newVersion},内容已同步)`);
|
|
69
|
+
}
|
|
70
|
+
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const SKILL_NAME = "lcap-frontend-library";
|
|
2
|
+
export declare const TOOL_PATHS: Record<string, string>;
|
|
3
|
+
export declare const GLOBAL_TOOL_PATHS: Record<string, string>;
|
|
4
|
+
export declare const MARKER_FILE = ".lcap-skill.json";
|
|
5
|
+
export interface Marker {
|
|
6
|
+
version: string;
|
|
7
|
+
tools: string[];
|
|
8
|
+
scope: 'global' | 'project';
|
|
9
|
+
installedAt: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function getSkillSourceDir(): string;
|
|
12
|
+
export declare function getPackageVersion(): string;
|
|
13
|
+
export declare function getMarkerPath(projectDir: string, scope: 'global' | 'project'): string;
|
|
14
|
+
export declare function readMarker(projectDir: string, scope?: 'global' | 'project'): Marker | null;
|
|
15
|
+
export declare function writeMarker(projectDir: string, marker: Marker): void;
|
|
16
|
+
export declare function detectTools(projectDir: string): string[];
|
|
17
|
+
export declare function copyDirRecursive(src: string, dest: string): void;
|
|
18
|
+
export declare function chmodScripts(skillDir: string): void;
|
|
19
|
+
export declare function rmDirRecursive(dir: string): void;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
export const SKILL_NAME = 'lcap-frontend-library';
|
|
7
|
+
export const TOOL_PATHS = {
|
|
8
|
+
claude: `.claude/skills/${SKILL_NAME}`,
|
|
9
|
+
cursor: `.cursor/skills/${SKILL_NAME}`,
|
|
10
|
+
codex: `.codex/skills/${SKILL_NAME}`,
|
|
11
|
+
};
|
|
12
|
+
export const GLOBAL_TOOL_PATHS = {
|
|
13
|
+
claude: path.join(os.homedir(), '.claude', 'skills', SKILL_NAME),
|
|
14
|
+
cursor: path.join(os.homedir(), '.cursor', 'skills', SKILL_NAME),
|
|
15
|
+
codex: path.join(os.homedir(), '.codex', 'skills', SKILL_NAME),
|
|
16
|
+
};
|
|
17
|
+
export const MARKER_FILE = '.lcap-skill.json';
|
|
18
|
+
export function getSkillSourceDir() {
|
|
19
|
+
return path.resolve(__dirname, '..', 'packages', 'lcap-frontend-library');
|
|
20
|
+
}
|
|
21
|
+
export function getPackageVersion() {
|
|
22
|
+
const pkgPath = path.resolve(__dirname, '..', 'package.json');
|
|
23
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
24
|
+
return pkg.version;
|
|
25
|
+
}
|
|
26
|
+
export function getMarkerPath(projectDir, scope) {
|
|
27
|
+
if (scope === 'global')
|
|
28
|
+
return path.join(os.homedir(), MARKER_FILE);
|
|
29
|
+
return path.join(projectDir, MARKER_FILE);
|
|
30
|
+
}
|
|
31
|
+
export function readMarker(projectDir, scope) {
|
|
32
|
+
// If scope is specified, only check that scope
|
|
33
|
+
if (scope) {
|
|
34
|
+
const markerPath = getMarkerPath(projectDir, scope);
|
|
35
|
+
if (!fs.existsSync(markerPath))
|
|
36
|
+
return null;
|
|
37
|
+
try {
|
|
38
|
+
return JSON.parse(fs.readFileSync(markerPath, 'utf8'));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Try project first, then global
|
|
45
|
+
for (const s of ['project', 'global']) {
|
|
46
|
+
const markerPath = getMarkerPath(projectDir, s);
|
|
47
|
+
if (fs.existsSync(markerPath)) {
|
|
48
|
+
try {
|
|
49
|
+
return JSON.parse(fs.readFileSync(markerPath, 'utf8'));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
export function writeMarker(projectDir, marker) {
|
|
59
|
+
const markerPath = getMarkerPath(projectDir, marker.scope);
|
|
60
|
+
fs.writeFileSync(markerPath, JSON.stringify(marker, null, 2) + '\n');
|
|
61
|
+
}
|
|
62
|
+
export function detectTools(projectDir) {
|
|
63
|
+
const detected = [];
|
|
64
|
+
for (const tool of Object.keys(TOOL_PATHS)) {
|
|
65
|
+
const toolRoot = path.join(projectDir, `.${tool}`);
|
|
66
|
+
if (fs.existsSync(toolRoot)) {
|
|
67
|
+
detected.push(tool);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return detected;
|
|
71
|
+
}
|
|
72
|
+
export function copyDirRecursive(src, dest) {
|
|
73
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
74
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
75
|
+
for (const entry of entries) {
|
|
76
|
+
const srcPath = path.join(src, entry.name);
|
|
77
|
+
const destPath = path.join(dest, entry.name);
|
|
78
|
+
if (entry.isDirectory()) {
|
|
79
|
+
copyDirRecursive(srcPath, destPath);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
fs.copyFileSync(srcPath, destPath);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export function chmodScripts(skillDir) {
|
|
87
|
+
const bashDir = path.join(skillDir, 'scripts', 'bash');
|
|
88
|
+
if (!fs.existsSync(bashDir))
|
|
89
|
+
return;
|
|
90
|
+
const files = fs.readdirSync(bashDir);
|
|
91
|
+
for (const file of files) {
|
|
92
|
+
if (file.endsWith('.sh')) {
|
|
93
|
+
fs.chmodSync(path.join(bashDir, file), 0o755);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export function rmDirRecursive(dir) {
|
|
98
|
+
if (fs.existsSync(dir)) {
|
|
99
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
100
|
+
}
|
|
101
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lcap-frontend-library",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "LCAP 前端扩展组件库 AI Skill(Claude Code / Cursor / Codex)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"lcap-frontend-library": "./bin/lcap-frontend-library.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"bin",
|
|
12
|
+
"packages/lcap-frontend-library"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"prepare": "npm run build",
|
|
17
|
+
"prepublishOnly": "npm run build",
|
|
18
|
+
"test": "npm run build && node --test tests/",
|
|
19
|
+
"publish:dry-run": "npm pack --dry-run",
|
|
20
|
+
"publish:npm": "npm publish"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"commander": "^12.0.0",
|
|
24
|
+
"@inquirer/prompts": "^7.0.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"typescript": "^5.5.0",
|
|
28
|
+
"@types/node": "^20.0.0"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18"
|
|
32
|
+
},
|
|
33
|
+
"license": "MIT"
|
|
34
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# LEARNINGS
|
|
2
|
+
|
|
3
|
+
> 轻量经验库:用户主动归因回流写入;generate / migrate 下次执行时只读引用。
|
|
4
|
+
> **写入**:仅用户说「归因回流」等触发 harness,不自动写入。
|
|
5
|
+
> **读取**:作为先验知识(plan)、checklist(self-check/check)、流程约束(implement/green)。
|
|
6
|
+
> 区别于 `workflows/migrate/knowledge-base.md` §pitfalls(权威静态规则)与 `workflow-guardrails.md`(跨流程护栏)。
|
|
7
|
+
> 每条格式:**[场景关键词]**:什么情况 + 什么坑/正确做法。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
(暂无记录,随使用积累)
|