prompt-plus 1.0.4 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -65
- package/dist/cli.js +75 -23
- package/dist/commands.d.ts +13 -8
- package/dist/commands.js +263 -147
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -3
- package/dist/skills.d.ts +3 -0
- package/dist/skills.js +114 -0
- package/dist/types.d.ts +11 -4
- package/package.json +2 -2
- package/dist/templates/index.d.ts +0 -2
- package/dist/templates/index.js +0 -92
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# prompt-plus
|
|
2
2
|
|
|
3
|
-
AI
|
|
3
|
+
AI 技能包管理工具 - 基于技能包驱动的开发工作流
|
|
4
|
+
|
|
5
|
+
> ⚠️ **v1.1.0 断档式更新**:不兼容旧版本,请重新安装
|
|
4
6
|
|
|
5
7
|
## 安装
|
|
6
8
|
|
|
@@ -11,108 +13,171 @@ npm install -g prompt-plus
|
|
|
11
13
|
## 快速开始
|
|
12
14
|
|
|
13
15
|
```bash
|
|
14
|
-
# 1.
|
|
15
|
-
|
|
16
|
+
# 1. 添加技能包仓库
|
|
17
|
+
pp repo add official https://github.com/your-repo/skills.git
|
|
18
|
+
|
|
19
|
+
# 2. 同步仓库
|
|
20
|
+
pp repo sync
|
|
16
21
|
|
|
17
|
-
#
|
|
18
|
-
|
|
22
|
+
# 3. 查看可用技能包
|
|
23
|
+
pp skill list
|
|
19
24
|
|
|
20
|
-
#
|
|
21
|
-
|
|
25
|
+
# 4. 安装技能包到当前项目
|
|
26
|
+
pp skill install backend_api
|
|
22
27
|
|
|
23
|
-
#
|
|
24
|
-
|
|
28
|
+
# 5. 查看已安装的技能包
|
|
29
|
+
pp skill installed
|
|
25
30
|
```
|
|
26
31
|
|
|
27
|
-
##
|
|
32
|
+
## 命令列表
|
|
28
33
|
|
|
29
|
-
###
|
|
34
|
+
### 仓库管理
|
|
30
35
|
|
|
31
36
|
```bash
|
|
32
|
-
#
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
#
|
|
37
|
-
|
|
37
|
+
pp repo add <name> <url> # 添加技能包仓库
|
|
38
|
+
pp repo add <name> <url> -b <branch> # 指定分支
|
|
39
|
+
pp repo remove <name> # 移除仓库
|
|
40
|
+
pp repo list # 列出所有仓库
|
|
41
|
+
pp repo sync # 同步所有仓库
|
|
42
|
+
pp repo sync <name> # 同步指定仓库
|
|
43
|
+
```
|
|
38
44
|
|
|
39
|
-
|
|
40
|
-
prompt-plus use <模板名>
|
|
45
|
+
### 技能包管理
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
```bash
|
|
48
|
+
pp skill list # 列出所有可用技能包
|
|
49
|
+
pp skill list -r <repo> # 列出指定仓库的技能包
|
|
50
|
+
pp skill install # 交互式安装技能包
|
|
51
|
+
pp skill install <name> # 安装指定技能包
|
|
52
|
+
pp skill installed # 查看已安装的技能包
|
|
44
53
|
```
|
|
45
54
|
|
|
46
|
-
###
|
|
55
|
+
### 工作区管理
|
|
47
56
|
|
|
48
57
|
```bash
|
|
49
|
-
#
|
|
50
|
-
|
|
58
|
+
pp workspace init # 初始化 AI 工作区
|
|
59
|
+
pp ws init # 简写
|
|
60
|
+
```
|
|
51
61
|
|
|
52
|
-
|
|
53
|
-
prompt-plus repo add <名称> <Git地址>
|
|
54
|
-
prompt-plus repo add official https://github.com/LeeSeaside/prompt-plus-templates.git
|
|
62
|
+
---
|
|
55
63
|
|
|
56
|
-
|
|
57
|
-
prompt-plus repo add company git@github.com:company/prompts.git -b develop
|
|
64
|
+
## 技能包仓库格式
|
|
58
65
|
|
|
59
|
-
|
|
60
|
-
prompt-plus repo sync # 同步所有
|
|
61
|
-
prompt-plus repo sync official # 同步指定仓库
|
|
66
|
+
如果你想创建自己的技能包仓库,请按以下格式组织:
|
|
62
67
|
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
```
|
|
69
|
+
your-repo/
|
|
70
|
+
└── skills/
|
|
71
|
+
├── backend_api/
|
|
72
|
+
│ ├── manifest.md # 执行流程和规范(必需)
|
|
73
|
+
│ ├── context.md # 项目配置模板(必需)
|
|
74
|
+
│ ├── input/ # 输入文档目录
|
|
75
|
+
│ │ └── .gitkeep
|
|
76
|
+
│ ├── output/ # 输出文档目录
|
|
77
|
+
│ │ └── .gitkeep
|
|
78
|
+
│ └── tools/ # 提示词工具
|
|
79
|
+
│ ├── init.md # 初始化提示词
|
|
80
|
+
│ └── dev.md # 开发提示词
|
|
81
|
+
├── frontend_api/
|
|
82
|
+
│ ├── manifest.md
|
|
83
|
+
│ ├── context.md
|
|
84
|
+
│ └── ...
|
|
85
|
+
└── another_skill/
|
|
86
|
+
└── ...
|
|
65
87
|
```
|
|
66
88
|
|
|
67
|
-
|
|
89
|
+
### manifest.md 格式
|
|
68
90
|
|
|
69
|
-
|
|
91
|
+
```markdown
|
|
92
|
+
# Skill Manifest: 技能名称
|
|
70
93
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
94
|
+
## 技能描述
|
|
95
|
+
简要说明这个技能包的用途。
|
|
96
|
+
|
|
97
|
+
## 执行协议
|
|
98
|
+
定义 AI 执行任务的步骤流程。
|
|
99
|
+
|
|
100
|
+
### 1. Context Check (上下文检查)
|
|
101
|
+
...
|
|
102
|
+
|
|
103
|
+
### 2. Input Acquisition (获取需求)
|
|
104
|
+
...
|
|
105
|
+
|
|
106
|
+
### 3. Code Generation (代码生成)
|
|
107
|
+
...
|
|
108
|
+
|
|
109
|
+
### 4. Documentation Output (文档输出)
|
|
110
|
+
...
|
|
111
|
+
|
|
112
|
+
## 约束条件
|
|
113
|
+
- 约束 1
|
|
114
|
+
- 约束 2
|
|
76
115
|
```
|
|
77
116
|
|
|
78
|
-
|
|
117
|
+
### context.md 格式
|
|
79
118
|
|
|
80
119
|
```markdown
|
|
81
|
-
|
|
82
|
-
name: my-template
|
|
83
|
-
description: 模板描述
|
|
84
|
-
category: backend
|
|
85
|
-
outputFileName: my-template-prompt.md
|
|
86
|
-
---
|
|
120
|
+
# Project Context Configuration
|
|
87
121
|
|
|
88
|
-
|
|
122
|
+
> ⚠️ 此文件需要初始化
|
|
89
123
|
|
|
90
|
-
##
|
|
91
|
-
|
|
92
|
-
|
|
124
|
+
## Tech Stack
|
|
125
|
+
- **Framework**: <!-- 待填充 -->
|
|
126
|
+
- **ORM**: <!-- 待填充 -->
|
|
93
127
|
|
|
94
|
-
##
|
|
128
|
+
## Directory Mapping
|
|
129
|
+
- **Controller Path**: <!-- 待填充 -->
|
|
130
|
+
- **Service Path**: <!-- 待填充 -->
|
|
95
131
|
|
|
132
|
+
## Code Style
|
|
133
|
+
- **Naming Convention**: <!-- 待填充 -->
|
|
96
134
|
```
|
|
97
|
-
模板 → 正式提示词 → 对接文档/代码
|
|
98
135
|
|
|
99
|
-
.
|
|
100
|
-
|
|
101
|
-
|
|
136
|
+
### tools/init.md 格式
|
|
137
|
+
|
|
138
|
+
```markdown
|
|
139
|
+
# 技能名 - 初始化提示词
|
|
140
|
+
|
|
141
|
+
## 使用方法
|
|
142
|
+
复制以下内容发送给 AI
|
|
102
143
|
|
|
103
|
-
|
|
104
|
-
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
\`\`\`
|
|
147
|
+
请执行 xxx 技能初始化:
|
|
148
|
+
1. 扫描项目结构
|
|
149
|
+
2. 识别技术栈
|
|
150
|
+
3. 将结果写入 context.md
|
|
151
|
+
\`\`\`
|
|
105
152
|
```
|
|
106
153
|
|
|
107
|
-
|
|
154
|
+
---
|
|
108
155
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
156
|
+
## 安装后的项目结构
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
your-project/
|
|
160
|
+
├── .ai-workspace/
|
|
161
|
+
│ ├── RULES.md # AI 工作流规则
|
|
162
|
+
│ └── skills/
|
|
163
|
+
│ ├── backend_api/
|
|
164
|
+
│ │ ├── manifest.md
|
|
165
|
+
│ │ ├── context.md # 需要初始化
|
|
166
|
+
│ │ ├── input/
|
|
167
|
+
│ │ ├── output/
|
|
168
|
+
│ │ └── tools/
|
|
169
|
+
│ └── frontend_api/
|
|
170
|
+
│ └── ...
|
|
171
|
+
└── (你的项目源码)
|
|
114
172
|
```
|
|
115
173
|
|
|
174
|
+
## 使用流程
|
|
175
|
+
|
|
176
|
+
1. **安装技能包**:`pp skill install backend_api`
|
|
177
|
+
2. **初始化配置**:查看 `tools/init.md`,复制提示词发送给 AI
|
|
178
|
+
3. **AI 扫描项目**:AI 会分析项目并填充 `context.md`
|
|
179
|
+
4. **开始开发**:将需求文档放入 `input/`,使用 `tools/dev.md` 的提示词
|
|
180
|
+
|
|
116
181
|
## License
|
|
117
182
|
|
|
118
183
|
MIT
|
package/dist/cli.js
CHANGED
|
@@ -1,49 +1,101 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
3
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
37
|
const commander_1 = require("commander");
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
5
40
|
const commands_1 = require("./commands");
|
|
41
|
+
// 读取版本号
|
|
42
|
+
const pkgPath = path.join(__dirname, '..', 'package.json');
|
|
43
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
6
44
|
const program = new commander_1.Command();
|
|
7
45
|
program
|
|
8
46
|
.name('prompt-plus')
|
|
9
|
-
.description('AI
|
|
10
|
-
.version(
|
|
11
|
-
|
|
12
|
-
.command('list')
|
|
13
|
-
.alias('ls')
|
|
14
|
-
.description('列出所有可用的提示词模板')
|
|
15
|
-
.option('-r, --repo <name>', '指定仓库名称')
|
|
16
|
-
.action(commands_1.listTemplates);
|
|
17
|
-
program
|
|
18
|
-
.command('use [templateName]')
|
|
19
|
-
.description('选择并使用模板生成提示词')
|
|
20
|
-
.option('-o, --output <path>', '输出路径', '.prompts')
|
|
21
|
-
.option('-r, --repo <name>', '指定仓库名称')
|
|
22
|
-
.action(commands_1.useTemplate);
|
|
23
|
-
program
|
|
24
|
-
.command('init')
|
|
25
|
-
.description('初始化配置文件')
|
|
26
|
-
.action(commands_1.initConfig);
|
|
47
|
+
.description('AI 技能包管理工具 - 基于技能包驱动的开发工作流')
|
|
48
|
+
.version(pkg.version);
|
|
49
|
+
// 仓库管理
|
|
27
50
|
program
|
|
28
51
|
.command('repo')
|
|
29
|
-
.description('
|
|
52
|
+
.description('管理技能包仓库')
|
|
30
53
|
.addCommand(new commander_1.Command('add')
|
|
31
|
-
.description('
|
|
54
|
+
.description('添加技能包仓库')
|
|
32
55
|
.argument('<name>', '仓库名称')
|
|
33
56
|
.argument('<url>', '仓库地址')
|
|
34
57
|
.option('-b, --branch <branch>', '分支名称', 'main')
|
|
35
58
|
.action(commands_1.addRepo))
|
|
36
59
|
.addCommand(new commander_1.Command('remove')
|
|
37
60
|
.alias('rm')
|
|
38
|
-
.description('
|
|
61
|
+
.description('移除仓库')
|
|
39
62
|
.argument('<name>', '仓库名称')
|
|
40
63
|
.action(commands_1.removeRepo))
|
|
41
64
|
.addCommand(new commander_1.Command('list')
|
|
42
65
|
.alias('ls')
|
|
43
|
-
.description('
|
|
66
|
+
.description('列出所有仓库')
|
|
44
67
|
.action(commands_1.listRepos))
|
|
45
68
|
.addCommand(new commander_1.Command('sync')
|
|
46
|
-
.description('
|
|
69
|
+
.description('同步仓库')
|
|
47
70
|
.argument('[name]', '仓库名称(不指定则同步所有)')
|
|
48
71
|
.action(commands_1.syncRepo));
|
|
72
|
+
// 技能包管理
|
|
73
|
+
program
|
|
74
|
+
.command('skill')
|
|
75
|
+
.description('管理技能包')
|
|
76
|
+
.addCommand(new commander_1.Command('list')
|
|
77
|
+
.alias('ls')
|
|
78
|
+
.description('列出所有可用技能包')
|
|
79
|
+
.option('-r, --repo <name>', '指定仓库名称')
|
|
80
|
+
.action(commands_1.listSkills))
|
|
81
|
+
.addCommand(new commander_1.Command('install')
|
|
82
|
+
.alias('i')
|
|
83
|
+
.description('安装技能包到当前项目')
|
|
84
|
+
.argument('[skillName]', '技能包名称')
|
|
85
|
+
.option('-r, --repo <name>', '指定仓库名称')
|
|
86
|
+
.option('-o, --output <path>', '输出路径', '.ai-workspace')
|
|
87
|
+
.action(commands_1.installSkill))
|
|
88
|
+
.addCommand(new commander_1.Command('installed')
|
|
89
|
+
.description('查看已安装的技能包')
|
|
90
|
+
.option('-o, --output <path>', '工作区路径', '.ai-workspace')
|
|
91
|
+
.action(commands_1.installedSkills));
|
|
92
|
+
// 工作区管理
|
|
93
|
+
program
|
|
94
|
+
.command('workspace')
|
|
95
|
+
.alias('ws')
|
|
96
|
+
.description('管理 AI 工作区')
|
|
97
|
+
.addCommand(new commander_1.Command('init')
|
|
98
|
+
.description('初始化 AI 工作区')
|
|
99
|
+
.option('-o, --output <path>', '输出路径', '.ai-workspace')
|
|
100
|
+
.action(commands_1.initWorkspace));
|
|
49
101
|
program.parse();
|
package/dist/commands.d.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
export declare function listTemplates(options?: {
|
|
2
|
-
repo?: string;
|
|
3
|
-
}): Promise<void>;
|
|
4
|
-
export declare function useTemplate(templateName?: string, options?: {
|
|
5
|
-
output?: string;
|
|
6
|
-
repo?: string;
|
|
7
|
-
}): Promise<void>;
|
|
8
|
-
export declare function initConfig(): Promise<void>;
|
|
9
1
|
export declare function addRepo(name: string, url: string, options?: {
|
|
10
2
|
branch?: string;
|
|
11
3
|
}): Promise<void>;
|
|
12
4
|
export declare function removeRepo(name: string): Promise<void>;
|
|
13
5
|
export declare function listRepos(): Promise<void>;
|
|
14
6
|
export declare function syncRepo(name?: string): Promise<void>;
|
|
7
|
+
export declare function listSkills(options?: {
|
|
8
|
+
repo?: string;
|
|
9
|
+
}): Promise<void>;
|
|
10
|
+
export declare function installSkill(skillName?: string, options?: {
|
|
11
|
+
repo?: string;
|
|
12
|
+
output?: string;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
export declare function initWorkspace(options?: {
|
|
15
|
+
output?: string;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
export declare function installedSkills(options?: {
|
|
18
|
+
output?: string;
|
|
19
|
+
}): Promise<void>;
|
package/dist/commands.js
CHANGED
|
@@ -33,17 +33,18 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.listTemplates = listTemplates;
|
|
37
|
-
exports.useTemplate = useTemplate;
|
|
38
|
-
exports.initConfig = initConfig;
|
|
39
36
|
exports.addRepo = addRepo;
|
|
40
37
|
exports.removeRepo = removeRepo;
|
|
41
38
|
exports.listRepos = listRepos;
|
|
42
39
|
exports.syncRepo = syncRepo;
|
|
40
|
+
exports.listSkills = listSkills;
|
|
41
|
+
exports.installSkill = installSkill;
|
|
42
|
+
exports.initWorkspace = initWorkspace;
|
|
43
|
+
exports.installedSkills = installedSkills;
|
|
43
44
|
const fs = __importStar(require("fs"));
|
|
44
45
|
const path = __importStar(require("path"));
|
|
45
46
|
const child_process_1 = require("child_process");
|
|
46
|
-
const
|
|
47
|
+
const skills_1 = require("./skills");
|
|
47
48
|
// 配置文件路径(全局配置)
|
|
48
49
|
const getGlobalConfigDir = () => path.join(process.env.HOME || process.env.USERPROFILE || '', '.prompt-plus');
|
|
49
50
|
const getGlobalConfigPath = () => path.join(getGlobalConfigDir(), 'config.json');
|
|
@@ -64,7 +65,7 @@ function getConfig() {
|
|
|
64
65
|
return {
|
|
65
66
|
defaultRepo: '',
|
|
66
67
|
repos: [],
|
|
67
|
-
outputDir: '.
|
|
68
|
+
outputDir: '.ai-workspace',
|
|
68
69
|
};
|
|
69
70
|
}
|
|
70
71
|
// 保存全局配置
|
|
@@ -75,140 +76,7 @@ function saveConfig(config) {
|
|
|
75
76
|
}
|
|
76
77
|
fs.writeFileSync(getGlobalConfigPath(), JSON.stringify(config, null, 2), 'utf-8');
|
|
77
78
|
}
|
|
78
|
-
//
|
|
79
|
-
async function getAllTemplatesWithRepo(repoName) {
|
|
80
|
-
const config = getConfig();
|
|
81
|
-
const templates = [];
|
|
82
|
-
// 指定了具体仓库
|
|
83
|
-
if (repoName) {
|
|
84
|
-
const repo = config.repos.find((r) => r.name === repoName);
|
|
85
|
-
if (repo) {
|
|
86
|
-
const repoDir = path.join(getReposDir(), repo.name);
|
|
87
|
-
if (fs.existsSync(repoDir)) {
|
|
88
|
-
const repoTemplates = (0, templates_1.loadTemplatesFromDir)(path.join(repoDir, 'templates'));
|
|
89
|
-
return repoTemplates.map((t) => ({ ...t, repoName: repo.name }));
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return [];
|
|
93
|
-
}
|
|
94
|
-
// 未指定仓库:合并所有已同步仓库模板
|
|
95
|
-
for (const repo of config.repos) {
|
|
96
|
-
const repoDir = path.join(getReposDir(), repo.name);
|
|
97
|
-
if (fs.existsSync(repoDir)) {
|
|
98
|
-
const repoTemplates = (0, templates_1.loadTemplatesFromDir)(path.join(repoDir, 'templates'));
|
|
99
|
-
templates.push(...repoTemplates.map((t) => ({ ...t, repoName: repo.name })));
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return templates;
|
|
103
|
-
}
|
|
104
|
-
async function listTemplates(options) {
|
|
105
|
-
const chalk = await getChalk();
|
|
106
|
-
const templates = await getAllTemplatesWithRepo(options?.repo);
|
|
107
|
-
if (templates.length === 0) {
|
|
108
|
-
console.log(chalk.yellow('\n⚠️ 没有找到模板'));
|
|
109
|
-
console.log(chalk.gray('请先添加并同步模板仓库:'));
|
|
110
|
-
console.log(chalk.gray(' prompt-plus repo add official https://github.com/LeeSeaside/prompt-plus-templates.git'));
|
|
111
|
-
console.log(chalk.gray(' prompt-plus repo sync\n'));
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
console.log(chalk.cyan('\n📋 可用的提示词模板:\n'));
|
|
115
|
-
// 按仓库分组
|
|
116
|
-
const repoNames = [...new Set(templates.map((t) => t.repoName))];
|
|
117
|
-
for (const repoName of repoNames) {
|
|
118
|
-
console.log(chalk.magenta(`📦 ${repoName}`));
|
|
119
|
-
const repoTemplates = templates.filter((t) => t.repoName === repoName);
|
|
120
|
-
// 按分类分组
|
|
121
|
-
const categories = [...new Set(repoTemplates.map((t) => t.category))];
|
|
122
|
-
for (const category of categories) {
|
|
123
|
-
console.log(chalk.yellow(` [${category}]`));
|
|
124
|
-
const categoryTemplates = repoTemplates.filter((t) => t.category === category);
|
|
125
|
-
for (const template of categoryTemplates) {
|
|
126
|
-
console.log(chalk.white(` • ${template.name}`), chalk.gray(`- ${template.description}`));
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
console.log();
|
|
130
|
-
}
|
|
131
|
-
console.log(chalk.gray('使用 "prompt-plus use <模板名>" 或 "prompt-plus use" 交互式选择\n'));
|
|
132
|
-
}
|
|
133
|
-
async function useTemplate(templateName, options) {
|
|
134
|
-
const chalk = await getChalk();
|
|
135
|
-
const inquirer = await getInquirer();
|
|
136
|
-
const templates = await getAllTemplatesWithRepo(options?.repo);
|
|
137
|
-
let selectedTemplate;
|
|
138
|
-
if (templateName) {
|
|
139
|
-
selectedTemplate = templates.find((t) => t.name === templateName);
|
|
140
|
-
if (!selectedTemplate) {
|
|
141
|
-
console.log(chalk.red(`\n❌ 未找到模板: ${templateName}`));
|
|
142
|
-
console.log(chalk.gray('使用 "prompt-plus list" 查看可用模板\n'));
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
else {
|
|
147
|
-
if (templates.length === 0) {
|
|
148
|
-
console.log(chalk.yellow('\n⚠️ 没有可用模板'));
|
|
149
|
-
console.log(chalk.gray('请先添加并同步模板仓库\n'));
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
const choices = templates.map((t) => ({
|
|
153
|
-
name: `[${t.repoName}] ${t.name} - ${t.description}`,
|
|
154
|
-
value: t.name,
|
|
155
|
-
}));
|
|
156
|
-
const answer = await inquirer.prompt([
|
|
157
|
-
{
|
|
158
|
-
type: 'list',
|
|
159
|
-
name: 'template',
|
|
160
|
-
message: '请选择要使用的模板:',
|
|
161
|
-
choices,
|
|
162
|
-
},
|
|
163
|
-
]);
|
|
164
|
-
selectedTemplate = templates.find((t) => t.name === answer.template);
|
|
165
|
-
}
|
|
166
|
-
if (!selectedTemplate) {
|
|
167
|
-
console.log(chalk.red('\n❌ 模板选择失败'));
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
const baseDir = options?.output || '.prompts';
|
|
171
|
-
const templatesDir = path.join(process.cwd(), baseDir, 'templates');
|
|
172
|
-
const generatedDir = path.join(process.cwd(), baseDir, 'generated');
|
|
173
|
-
if (!fs.existsSync(templatesDir)) {
|
|
174
|
-
fs.mkdirSync(templatesDir, { recursive: true });
|
|
175
|
-
}
|
|
176
|
-
if (!fs.existsSync(generatedDir)) {
|
|
177
|
-
fs.mkdirSync(generatedDir, { recursive: true });
|
|
178
|
-
}
|
|
179
|
-
const filePath = path.join(templatesDir, selectedTemplate.outputFileName);
|
|
180
|
-
fs.writeFileSync(filePath, selectedTemplate.content, 'utf-8');
|
|
181
|
-
console.log(chalk.green(`\n✅ 模板已生成: ${filePath}`));
|
|
182
|
-
console.log(chalk.cyan('\n📝 使用方法:'));
|
|
183
|
-
console.log(chalk.white(' 1. 打开生成的提示词文件'));
|
|
184
|
-
console.log(chalk.white(' 2. 复制内容到AI编辑器(Cursor/Trae等)'));
|
|
185
|
-
console.log(chalk.white(' 3. AI会分析你的项目并生成具体的开发提示词'));
|
|
186
|
-
console.log(chalk.white(` 4. 将AI生成的正式提示词保存到: ${chalk.yellow(baseDir + '/generated/')}`));
|
|
187
|
-
console.log(chalk.white(' 5. 使用正式提示词进行实际开发\n'));
|
|
188
|
-
console.log(chalk.gray(`📁 目录结构:`));
|
|
189
|
-
console.log(chalk.gray(` ${baseDir}/`));
|
|
190
|
-
console.log(chalk.gray(` ├── templates/ # 提示词模板`));
|
|
191
|
-
console.log(chalk.gray(` └── generated/ # 正式提示词\n`));
|
|
192
|
-
}
|
|
193
|
-
async function initConfig() {
|
|
194
|
-
const chalk = await getChalk();
|
|
195
|
-
const configPath = getGlobalConfigPath();
|
|
196
|
-
if (fs.existsSync(configPath)) {
|
|
197
|
-
console.log(chalk.yellow('\n⚠️ 配置文件已存在'));
|
|
198
|
-
console.log(chalk.gray(`路径: ${configPath}\n`));
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
const defaultConfig = {
|
|
202
|
-
defaultRepo: '',
|
|
203
|
-
repos: [],
|
|
204
|
-
outputDir: '.prompts',
|
|
205
|
-
};
|
|
206
|
-
saveConfig(defaultConfig);
|
|
207
|
-
console.log(chalk.green('\n✅ 配置文件已创建'));
|
|
208
|
-
console.log(chalk.gray(`路径: ${configPath}`));
|
|
209
|
-
console.log(chalk.gray('\n下一步: 添加模板仓库'));
|
|
210
|
-
console.log(chalk.gray(' prompt-plus repo add official https://github.com/LeeSeaside/prompt-plus-templates.git\n'));
|
|
211
|
-
}
|
|
79
|
+
// ==================== 仓库管理 ====================
|
|
212
80
|
async function addRepo(name, url, options) {
|
|
213
81
|
const chalk = await getChalk();
|
|
214
82
|
const config = getConfig();
|
|
@@ -223,7 +91,7 @@ async function addRepo(name, url, options) {
|
|
|
223
91
|
});
|
|
224
92
|
saveConfig(config);
|
|
225
93
|
console.log(chalk.green(`\n✅ 已添加仓库: ${name}`));
|
|
226
|
-
console.log(chalk.gray(`使用 "
|
|
94
|
+
console.log(chalk.gray(`使用 "pp repo sync ${name}" 同步仓库\n`));
|
|
227
95
|
}
|
|
228
96
|
async function removeRepo(name) {
|
|
229
97
|
const chalk = await getChalk();
|
|
@@ -245,19 +113,28 @@ async function removeRepo(name) {
|
|
|
245
113
|
async function listRepos() {
|
|
246
114
|
const chalk = await getChalk();
|
|
247
115
|
const config = getConfig();
|
|
248
|
-
console.log(chalk.cyan('\n📦
|
|
116
|
+
console.log(chalk.cyan('\n📦 技能包仓库列表:\n'));
|
|
249
117
|
if (config.repos.length === 0) {
|
|
250
118
|
console.log(chalk.gray(' 暂无仓库,请先添加:'));
|
|
251
|
-
console.log(chalk.gray('
|
|
119
|
+
console.log(chalk.gray(' pp repo add official https://github.com/your-repo/skills.git\n'));
|
|
252
120
|
return;
|
|
253
121
|
}
|
|
254
122
|
for (const repo of config.repos) {
|
|
255
|
-
const
|
|
123
|
+
const repoDir = path.join(getReposDir(), repo.name);
|
|
124
|
+
const synced = fs.existsSync(repoDir);
|
|
256
125
|
const status = synced ? chalk.green('✓ 已同步') : chalk.yellow('未同步');
|
|
257
|
-
|
|
126
|
+
// 检查技能包数量
|
|
127
|
+
let skillCount = 0;
|
|
128
|
+
if (synced) {
|
|
129
|
+
const skillsDir = path.join(repoDir, 'skills');
|
|
130
|
+
if (fs.existsSync(skillsDir)) {
|
|
131
|
+
skillCount = (0, skills_1.loadSkillsFromDir)(skillsDir).length;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
console.log(chalk.white(` • ${repo.name}`), chalk.gray(`- ${repo.url}`), status, synced ? chalk.gray(`(${skillCount} 个技能包)`) : '');
|
|
258
135
|
}
|
|
259
|
-
console.log(chalk.gray('\n使用 "
|
|
260
|
-
console.log(chalk.gray('使用 "
|
|
136
|
+
console.log(chalk.gray('\n使用 "pp repo add <name> <url>" 添加仓库'));
|
|
137
|
+
console.log(chalk.gray('使用 "pp repo sync [name]" 同步仓库\n'));
|
|
261
138
|
}
|
|
262
139
|
async function syncRepo(name) {
|
|
263
140
|
const chalk = await getChalk();
|
|
@@ -273,7 +150,7 @@ async function syncRepo(name) {
|
|
|
273
150
|
}
|
|
274
151
|
else {
|
|
275
152
|
console.log(chalk.yellow('\n⚠️ 没有配置任何仓库'));
|
|
276
|
-
console.log(chalk.gray('使用 "
|
|
153
|
+
console.log(chalk.gray('使用 "pp repo add <name> <url>" 添加仓库\n'));
|
|
277
154
|
}
|
|
278
155
|
return;
|
|
279
156
|
}
|
|
@@ -289,6 +166,12 @@ async function syncRepo(name) {
|
|
|
289
166
|
(0, child_process_1.execSync)(`git clone -b ${repo.branch || 'main'} "${repo.url}" "${repoDir}"`, { stdio: 'pipe' });
|
|
290
167
|
console.log(chalk.green(`✅ 已克隆: ${repo.name}`));
|
|
291
168
|
}
|
|
169
|
+
// 显示技能包数量
|
|
170
|
+
const skillsDir = path.join(repoDir, 'skills');
|
|
171
|
+
if (fs.existsSync(skillsDir)) {
|
|
172
|
+
const skills = (0, skills_1.loadSkillsFromDir)(skillsDir);
|
|
173
|
+
console.log(chalk.gray(` 发现 ${skills.length} 个技能包`));
|
|
174
|
+
}
|
|
292
175
|
}
|
|
293
176
|
catch (error) {
|
|
294
177
|
console.log(chalk.red(`❌ 同步失败: ${repo.name}`));
|
|
@@ -297,3 +180,236 @@ async function syncRepo(name) {
|
|
|
297
180
|
}
|
|
298
181
|
console.log();
|
|
299
182
|
}
|
|
183
|
+
// 获取所有技能包(按仓库分组)
|
|
184
|
+
async function getAllSkillsWithRepo(repoName) {
|
|
185
|
+
const config = getConfig();
|
|
186
|
+
const skills = [];
|
|
187
|
+
if (repoName) {
|
|
188
|
+
const repo = config.repos.find((r) => r.name === repoName);
|
|
189
|
+
if (repo) {
|
|
190
|
+
const repoDir = path.join(getReposDir(), repo.name);
|
|
191
|
+
if (fs.existsSync(repoDir)) {
|
|
192
|
+
const repoSkills = (0, skills_1.loadSkillsFromDir)(path.join(repoDir, 'skills'));
|
|
193
|
+
return repoSkills.map((s) => ({ ...s, repoName: repo.name }));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
198
|
+
for (const repo of config.repos) {
|
|
199
|
+
const repoDir = path.join(getReposDir(), repo.name);
|
|
200
|
+
if (fs.existsSync(repoDir)) {
|
|
201
|
+
const repoSkills = (0, skills_1.loadSkillsFromDir)(path.join(repoDir, 'skills'));
|
|
202
|
+
skills.push(...repoSkills.map((s) => ({ ...s, repoName: repo.name })));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return skills;
|
|
206
|
+
}
|
|
207
|
+
// 列出所有技能包
|
|
208
|
+
async function listSkills(options) {
|
|
209
|
+
const chalk = await getChalk();
|
|
210
|
+
const skills = await getAllSkillsWithRepo(options?.repo);
|
|
211
|
+
if (skills.length === 0) {
|
|
212
|
+
console.log(chalk.yellow('\n⚠️ 没有找到技能包'));
|
|
213
|
+
console.log(chalk.gray('请先添加并同步仓库:'));
|
|
214
|
+
console.log(chalk.gray(' pp repo add official <仓库地址>'));
|
|
215
|
+
console.log(chalk.gray(' pp repo sync\n'));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
console.log(chalk.cyan('\n🎯 可用的技能包:\n'));
|
|
219
|
+
const repoNames = [...new Set(skills.map((s) => s.repoName))];
|
|
220
|
+
for (const repoName of repoNames) {
|
|
221
|
+
console.log(chalk.magenta(`📦 ${repoName}`));
|
|
222
|
+
const repoSkills = skills.filter((s) => s.repoName === repoName);
|
|
223
|
+
for (const skill of repoSkills) {
|
|
224
|
+
const status = [];
|
|
225
|
+
if (skill.hasManifest)
|
|
226
|
+
status.push(chalk.green('✓manifest'));
|
|
227
|
+
if (skill.hasContext)
|
|
228
|
+
status.push(chalk.green('✓context'));
|
|
229
|
+
if (skill.hasTools)
|
|
230
|
+
status.push(chalk.green('✓tools'));
|
|
231
|
+
console.log(chalk.white(` • ${skill.name}`), chalk.gray(`- ${skill.description || '无描述'}`), chalk.gray(`[${status.join(' ')}]`));
|
|
232
|
+
}
|
|
233
|
+
console.log();
|
|
234
|
+
}
|
|
235
|
+
console.log(chalk.gray('使用 "pp skill install <技能名>" 安装技能包到当前项目\n'));
|
|
236
|
+
}
|
|
237
|
+
// 安装技能包到当前项目
|
|
238
|
+
async function installSkill(skillName, options) {
|
|
239
|
+
const chalk = await getChalk();
|
|
240
|
+
const inquirer = await getInquirer();
|
|
241
|
+
const skills = await getAllSkillsWithRepo(options?.repo);
|
|
242
|
+
let selectedSkill;
|
|
243
|
+
if (skillName) {
|
|
244
|
+
selectedSkill = skills.find((s) => s.name === skillName);
|
|
245
|
+
if (!selectedSkill) {
|
|
246
|
+
console.log(chalk.red(`\n❌ 未找到技能包: ${skillName}`));
|
|
247
|
+
console.log(chalk.gray('使用 "pp skill list" 查看可用技能包\n'));
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
if (skills.length === 0) {
|
|
253
|
+
console.log(chalk.yellow('\n⚠️ 没有可用技能包'));
|
|
254
|
+
console.log(chalk.gray('请先添加并同步仓库\n'));
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const choices = skills.map((s) => ({
|
|
258
|
+
name: `[${s.repoName}] ${s.name} - ${s.description || '无描述'}`,
|
|
259
|
+
value: s.name,
|
|
260
|
+
}));
|
|
261
|
+
const answer = await inquirer.prompt([
|
|
262
|
+
{
|
|
263
|
+
type: 'list',
|
|
264
|
+
name: 'skill',
|
|
265
|
+
message: '请选择要安装的技能包:',
|
|
266
|
+
choices,
|
|
267
|
+
},
|
|
268
|
+
]);
|
|
269
|
+
selectedSkill = skills.find((s) => s.name === answer.skill);
|
|
270
|
+
}
|
|
271
|
+
if (!selectedSkill) {
|
|
272
|
+
console.log(chalk.red('\n❌ 技能包选择失败'));
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const baseDir = options?.output || '.ai-workspace';
|
|
276
|
+
const targetDir = path.join(process.cwd(), baseDir, 'skills', selectedSkill.name);
|
|
277
|
+
// 检查是否已安装
|
|
278
|
+
if (fs.existsSync(targetDir)) {
|
|
279
|
+
const { overwrite } = await inquirer.prompt([
|
|
280
|
+
{
|
|
281
|
+
type: 'confirm',
|
|
282
|
+
name: 'overwrite',
|
|
283
|
+
message: `技能包 "${selectedSkill.name}" 已存在,是否覆盖?`,
|
|
284
|
+
default: false,
|
|
285
|
+
},
|
|
286
|
+
]);
|
|
287
|
+
if (!overwrite) {
|
|
288
|
+
console.log(chalk.yellow('\n⚠️ 已取消安装\n'));
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
292
|
+
}
|
|
293
|
+
// 复制技能包
|
|
294
|
+
(0, skills_1.copySkill)(selectedSkill.path, targetDir);
|
|
295
|
+
// 确保 RULES.md 存在
|
|
296
|
+
const rulesPath = path.join(process.cwd(), baseDir, 'RULES.md');
|
|
297
|
+
if (!fs.existsSync(rulesPath)) {
|
|
298
|
+
await initWorkspace({ output: baseDir });
|
|
299
|
+
}
|
|
300
|
+
console.log(chalk.green(`\n✅ 技能包已安装: ${targetDir}`));
|
|
301
|
+
console.log(chalk.cyan('\n📝 下一步:'));
|
|
302
|
+
console.log(chalk.white(` 1. 查看 ${baseDir}/skills/${selectedSkill.name}/tools/init.md`));
|
|
303
|
+
console.log(chalk.white(' 2. 复制初始化提示词发送给 AI'));
|
|
304
|
+
console.log(chalk.white(' 3. AI 会扫描项目并填充 context.md\n'));
|
|
305
|
+
}
|
|
306
|
+
// 初始化 AI 工作区
|
|
307
|
+
async function initWorkspace(options) {
|
|
308
|
+
const chalk = await getChalk();
|
|
309
|
+
const baseDir = options?.output || '.ai-workspace';
|
|
310
|
+
const workspaceDir = path.join(process.cwd(), baseDir);
|
|
311
|
+
const rulesPath = path.join(workspaceDir, 'RULES.md');
|
|
312
|
+
if (fs.existsSync(rulesPath)) {
|
|
313
|
+
console.log(chalk.yellow('\n⚠️ AI 工作区已存在'));
|
|
314
|
+
console.log(chalk.gray(`路径: ${workspaceDir}\n`));
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
// 创建目录结构
|
|
318
|
+
fs.mkdirSync(path.join(workspaceDir, 'skills'), { recursive: true });
|
|
319
|
+
// 创建 RULES.md
|
|
320
|
+
const rulesContent = `# AI WORKSPACE - SYSTEM PROTOCOL
|
|
321
|
+
|
|
322
|
+
> 此文件定义 AI 助手的强制性工作流规则,适用于所有 AI 编辑器(Cursor、Copilot、Kiro、Claude 等)
|
|
323
|
+
|
|
324
|
+
## PRIORITY: ABSOLUTE (最高优先级)
|
|
325
|
+
|
|
326
|
+
你是一个基于"技能包"驱动的开发助手。在处理任何开发任务之前,必须强制执行以下协议。
|
|
327
|
+
|
|
328
|
+
## SKILL DISCOVERY
|
|
329
|
+
|
|
330
|
+
**动态发现技能**:扫描 \`.ai-workspace/skills/\` 目录,每个子目录即为一个技能包。
|
|
331
|
+
|
|
332
|
+
## SKILL STRUCTURE
|
|
333
|
+
|
|
334
|
+
每个技能包的标准结构:
|
|
335
|
+
\`\`\`
|
|
336
|
+
skills/[skill_name]/
|
|
337
|
+
├── manifest.md # 执行流程和规范(必读)
|
|
338
|
+
├── context.md # 项目配置(需初始化)
|
|
339
|
+
├── input/ # 该技能的输入文档
|
|
340
|
+
├── output/ # 该技能的输出文档
|
|
341
|
+
└── tools/ # 该技能的提示词工具
|
|
342
|
+
\`\`\`
|
|
343
|
+
|
|
344
|
+
## MANDATORY WORKFLOW
|
|
345
|
+
|
|
346
|
+
### 1. Skill Discovery (技能发现)
|
|
347
|
+
- 扫描 \`skills/\` 目录,列出所有可用技能
|
|
348
|
+
- 读取每个技能的 \`manifest.md\` 了解其用途
|
|
349
|
+
|
|
350
|
+
### 2. Skill Selection (技能选择)
|
|
351
|
+
- 根据用户任务类型,选择对应的技能包
|
|
352
|
+
- 如果不确定,询问用户或列出可用技能供选择
|
|
353
|
+
|
|
354
|
+
### 3. Load Skill (加载技能)
|
|
355
|
+
- 读取 \`skills/[skill]/manifest.md\` 获取执行流程
|
|
356
|
+
- 读取 \`skills/[skill]/context.md\` 获取项目配置
|
|
357
|
+
|
|
358
|
+
### 4. Context Check (上下文检查)
|
|
359
|
+
- 如果 \`context.md\` 未初始化,**终止任务**
|
|
360
|
+
- 提示用户:"请先执行项目初始化,参考 \`skills/[skill]/tools/init.md\`"
|
|
361
|
+
|
|
362
|
+
### 5. Input Acquisition (获取输入)
|
|
363
|
+
- 从 \`skills/[skill]/input/\` 读取需求文档
|
|
364
|
+
|
|
365
|
+
### 6. Execute Task (执行任务)
|
|
366
|
+
- 按照 \`manifest.md\` 定义的流程执行
|
|
367
|
+
- 代码输出到项目源码目录(由 context.md 指定)
|
|
368
|
+
|
|
369
|
+
### 7. Output Documentation (输出文档)
|
|
370
|
+
- 执行日志输出到 \`skills/[skill]/output/\`
|
|
371
|
+
|
|
372
|
+
## CONSTRAINTS
|
|
373
|
+
|
|
374
|
+
- 严格遵循所选技能的 manifest.md 流程
|
|
375
|
+
- 代码路径受控于 context.md
|
|
376
|
+
- 禁止跨技能读写 input/output
|
|
377
|
+
- 禁止臆造依赖库或目录
|
|
378
|
+
- 新技能自动可用,无需修改此文件
|
|
379
|
+
`;
|
|
380
|
+
fs.writeFileSync(rulesPath, rulesContent, 'utf-8');
|
|
381
|
+
console.log(chalk.green('\n✅ AI 工作区已创建'));
|
|
382
|
+
console.log(chalk.gray(`路径: ${workspaceDir}`));
|
|
383
|
+
console.log(chalk.cyan('\n📝 下一步:'));
|
|
384
|
+
console.log(chalk.gray(' pp skill list # 查看可用技能包'));
|
|
385
|
+
console.log(chalk.gray(' pp skill install # 安装技能包\n'));
|
|
386
|
+
}
|
|
387
|
+
// 查看已安装的技能包
|
|
388
|
+
async function installedSkills(options) {
|
|
389
|
+
const chalk = await getChalk();
|
|
390
|
+
const baseDir = options?.output || '.ai-workspace';
|
|
391
|
+
const skillsDir = path.join(process.cwd(), baseDir, 'skills');
|
|
392
|
+
if (!fs.existsSync(skillsDir)) {
|
|
393
|
+
console.log(chalk.yellow('\n⚠️ 未找到 AI 工作区'));
|
|
394
|
+
console.log(chalk.gray('使用 "pp workspace init" 初始化工作区\n'));
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const skills = (0, skills_1.loadSkillsFromDir)(skillsDir);
|
|
398
|
+
if (skills.length === 0) {
|
|
399
|
+
console.log(chalk.yellow('\n⚠️ 未安装任何技能包'));
|
|
400
|
+
console.log(chalk.gray('使用 "pp skill install" 安装技能包\n'));
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
console.log(chalk.cyan('\n🎯 已安装的技能包:\n'));
|
|
404
|
+
for (const skill of skills) {
|
|
405
|
+
const status = [];
|
|
406
|
+
if (skill.hasManifest)
|
|
407
|
+
status.push(chalk.green('✓manifest'));
|
|
408
|
+
if (skill.hasContext)
|
|
409
|
+
status.push(chalk.green('✓context'));
|
|
410
|
+
if (skill.hasTools)
|
|
411
|
+
status.push(chalk.green('✓tools'));
|
|
412
|
+
console.log(chalk.white(` • ${skill.name}`), chalk.gray(`- ${skill.description || '无描述'}`), chalk.gray(`[${status.join(' ')}]`));
|
|
413
|
+
}
|
|
414
|
+
console.log(chalk.gray(`\n📁 位置: ${skillsDir}\n`));
|
|
415
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type {
|
|
1
|
+
export { loadSkillsFromDir, copySkill } from './skills';
|
|
2
|
+
export type { Skill, SkillMeta, RepoConfig, PromptPlusConfig } from './types';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
var
|
|
5
|
-
Object.defineProperty(exports, "
|
|
3
|
+
exports.copySkill = exports.loadSkillsFromDir = void 0;
|
|
4
|
+
var skills_1 = require("./skills");
|
|
5
|
+
Object.defineProperty(exports, "loadSkillsFromDir", { enumerable: true, get: function () { return skills_1.loadSkillsFromDir; } });
|
|
6
|
+
Object.defineProperty(exports, "copySkill", { enumerable: true, get: function () { return skills_1.copySkill; } });
|
package/dist/skills.d.ts
ADDED
package/dist/skills.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadSkillsFromDir = loadSkillsFromDir;
|
|
37
|
+
exports.copySkill = copySkill;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
// 从 manifest.md 解析技能元数据
|
|
41
|
+
function parseSkillMeta(manifestPath) {
|
|
42
|
+
if (!fs.existsSync(manifestPath)) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const content = fs.readFileSync(manifestPath, 'utf-8');
|
|
46
|
+
const lines = content.split('\n');
|
|
47
|
+
// 解析标题作为名称
|
|
48
|
+
const titleMatch = content.match(/^#\s+(?:Skill Manifest:\s*)?(.+)/m);
|
|
49
|
+
const name = titleMatch ? titleMatch[1].trim() : '';
|
|
50
|
+
// 解析描述(## 技能描述 或 ## 核心职责 下的内容)
|
|
51
|
+
let description = '';
|
|
52
|
+
const descMatch = content.match(/##\s*(?:技能描述|核心职责)\s*\n([^\n#]+)/);
|
|
53
|
+
if (descMatch) {
|
|
54
|
+
description = descMatch[1].trim();
|
|
55
|
+
}
|
|
56
|
+
// 解析分类(如果有)
|
|
57
|
+
let category = 'general';
|
|
58
|
+
const categoryMatch = content.match(/category:\s*(\w+)/i);
|
|
59
|
+
if (categoryMatch) {
|
|
60
|
+
category = categoryMatch[1];
|
|
61
|
+
}
|
|
62
|
+
return { name, description, category };
|
|
63
|
+
}
|
|
64
|
+
// 从目录加载技能包
|
|
65
|
+
function loadSkillsFromDir(skillsDir) {
|
|
66
|
+
if (!fs.existsSync(skillsDir)) {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
const skills = [];
|
|
70
|
+
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
71
|
+
for (const entry of entries) {
|
|
72
|
+
if (!entry.isDirectory())
|
|
73
|
+
continue;
|
|
74
|
+
const skillPath = path.join(skillsDir, entry.name);
|
|
75
|
+
const manifestPath = path.join(skillPath, 'manifest.md');
|
|
76
|
+
const contextPath = path.join(skillPath, 'context.md');
|
|
77
|
+
const toolsPath = path.join(skillPath, 'tools');
|
|
78
|
+
const meta = parseSkillMeta(manifestPath);
|
|
79
|
+
skills.push({
|
|
80
|
+
name: entry.name,
|
|
81
|
+
description: meta?.description || '',
|
|
82
|
+
category: meta?.category || 'general',
|
|
83
|
+
path: skillPath,
|
|
84
|
+
hasManifest: fs.existsSync(manifestPath),
|
|
85
|
+
hasContext: fs.existsSync(contextPath),
|
|
86
|
+
hasTools: fs.existsSync(toolsPath),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return skills;
|
|
90
|
+
}
|
|
91
|
+
// 复制技能包到目标目录
|
|
92
|
+
function copySkill(skillPath, targetDir) {
|
|
93
|
+
if (!fs.existsSync(targetDir)) {
|
|
94
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
copyDirRecursive(skillPath, targetDir);
|
|
97
|
+
}
|
|
98
|
+
// 递归复制目录
|
|
99
|
+
function copyDirRecursive(src, dest) {
|
|
100
|
+
if (!fs.existsSync(dest)) {
|
|
101
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
102
|
+
}
|
|
103
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
104
|
+
for (const entry of entries) {
|
|
105
|
+
const srcPath = path.join(src, entry.name);
|
|
106
|
+
const destPath = path.join(dest, entry.name);
|
|
107
|
+
if (entry.isDirectory()) {
|
|
108
|
+
copyDirRecursive(srcPath, destPath);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
fs.copyFileSync(srcPath, destPath);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface Skill {
|
|
2
2
|
name: string;
|
|
3
3
|
description: string;
|
|
4
4
|
category: string;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
path: string;
|
|
6
|
+
hasManifest: boolean;
|
|
7
|
+
hasContext: boolean;
|
|
8
|
+
hasTools: boolean;
|
|
7
9
|
}
|
|
8
10
|
export interface RepoConfig {
|
|
9
11
|
name: string;
|
|
10
12
|
url: string;
|
|
11
|
-
branch
|
|
13
|
+
branch: string;
|
|
12
14
|
}
|
|
13
15
|
export interface PromptPlusConfig {
|
|
14
16
|
defaultRepo: string;
|
|
15
17
|
repos: RepoConfig[];
|
|
16
18
|
outputDir: string;
|
|
17
19
|
}
|
|
20
|
+
export interface SkillMeta {
|
|
21
|
+
name: string;
|
|
22
|
+
description: string;
|
|
23
|
+
category?: string;
|
|
24
|
+
}
|
package/package.json
CHANGED
package/dist/templates/index.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.loadTemplatesFromDir = loadTemplatesFromDir;
|
|
37
|
-
const fs = __importStar(require("fs"));
|
|
38
|
-
const path = __importStar(require("path"));
|
|
39
|
-
// 解析 Markdown Front Matter
|
|
40
|
-
function parseFrontMatter(content) {
|
|
41
|
-
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
|
|
42
|
-
if (!match) {
|
|
43
|
-
return { meta: {}, body: content };
|
|
44
|
-
}
|
|
45
|
-
const meta = {};
|
|
46
|
-
const yamlContent = match[1];
|
|
47
|
-
const body = match[2];
|
|
48
|
-
yamlContent.split('\n').forEach((line) => {
|
|
49
|
-
const colonIndex = line.indexOf(':');
|
|
50
|
-
if (colonIndex > 0) {
|
|
51
|
-
const key = line.slice(0, colonIndex).trim();
|
|
52
|
-
const value = line.slice(colonIndex + 1).trim();
|
|
53
|
-
meta[key] = value;
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
return { meta, body };
|
|
57
|
-
}
|
|
58
|
-
// 从目录加载模板(支持 .md 和 .json)
|
|
59
|
-
function loadTemplatesFromDir(dir) {
|
|
60
|
-
if (!fs.existsSync(dir)) {
|
|
61
|
-
return [];
|
|
62
|
-
}
|
|
63
|
-
const templates = [];
|
|
64
|
-
const files = fs.readdirSync(dir);
|
|
65
|
-
for (const file of files) {
|
|
66
|
-
const filePath = path.join(dir, file);
|
|
67
|
-
try {
|
|
68
|
-
if (file.endsWith('.md') && file !== 'README.md') {
|
|
69
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
70
|
-
const { meta, body } = parseFrontMatter(content);
|
|
71
|
-
if (meta.name) {
|
|
72
|
-
templates.push({
|
|
73
|
-
name: meta.name,
|
|
74
|
-
description: meta.description || '',
|
|
75
|
-
category: meta.category || 'other',
|
|
76
|
-
outputFileName: meta.outputFileName || `${meta.name}-prompt.md`,
|
|
77
|
-
content: body.trim(),
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
else if (file.endsWith('.json')) {
|
|
82
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
83
|
-
const template = JSON.parse(content);
|
|
84
|
-
templates.push(template);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
catch {
|
|
88
|
-
// 忽略解析错误
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return templates;
|
|
92
|
-
}
|