prompt-plus 1.0.5 → 1.1.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 CHANGED
@@ -1,6 +1,8 @@
1
1
  # prompt-plus
2
2
 
3
- AI 提示词模板管理工具 - 生成符合项目规范的提示词
3
+ AI 技能包管理工具 - 基于技能包驱动的开发工作流
4
+
5
+ > ⚠️ **v1.1.0+ 断档式更新**:不兼容 v1.0.x,请重新安装
4
6
 
5
7
  ## 安装
6
8
 
@@ -11,106 +13,156 @@ npm install -g prompt-plus
11
13
  ## 快速开始
12
14
 
13
15
  ```bash
14
- # 1. 添加官方模板仓库
15
- prompt-plus repo add official https://github.com/LeeSeaside/prompt-plus-templates.git
16
+ # 1. 添加技能包仓库
17
+ pp repo add official https://github.com/your-repo/skills.git
18
+
19
+ # 2. 同步仓库
20
+ pp repo sync
16
21
 
17
- # 2. 同步模板
18
- prompt-plus repo sync
22
+ # 3. 查看可用技能包
23
+ pp skill list
19
24
 
20
- # 3. 查看可用模板
21
- prompt-plus list
25
+ # 4. 安装技能包到当前项目
26
+ pp skill install backend_api
22
27
 
23
- # 4. 使用模板
24
- prompt-plus use backend-api
28
+ # 5. 查看已安装的技能包
29
+ pp skill installed
25
30
  ```
26
31
 
27
- ## 命令
32
+ ## 命令列表
28
33
 
29
- ### 模板操作
34
+ ### 仓库管理
30
35
 
31
36
  ```bash
32
- # 列出所有模板
33
- prompt-plus list
34
- prompt-plus ls
35
-
36
- # 使用模板(交互式选择)
37
- prompt-plus use
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
- prompt-plus use <模板名> -o ./my-prompts
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 # 查看已安装的技能包
53
+ pp skill upgrade # 升级技能包(保留 context.md)
54
+ pp skill upgrade <name> # 升级指定技能包
55
+ pp skill up # upgrade 简写
44
56
  ```
45
57
 
46
- ### 仓库管理
58
+ ### 工作区管理
47
59
 
48
60
  ```bash
49
- # 查看仓库列表
50
- prompt-plus repo ls
61
+ pp workspace init # 初始化 AI 工作区
62
+ pp ws init # 简写
63
+ ```
51
64
 
52
- # 添加仓库
53
- prompt-plus repo add <名称> <Git地址>
54
- prompt-plus repo add official https://github.com/LeeSeaside/prompt-plus-templates.git
65
+ ---
55
66
 
56
- # 添加私有仓库(指定分支)
57
- prompt-plus repo add company git@github.com:company/prompts.git -b develop
67
+ ## 技能包仓库格式
58
68
 
59
- # 同步仓库
60
- prompt-plus repo sync # 同步所有
61
- prompt-plus repo sync official # 同步指定仓库
69
+ 如果你想创建自己的技能包仓库,请按以下格式组织:
62
70
 
63
- # 移除仓库
64
- prompt-plus repo rm <名称>
71
+ ```
72
+ your-repo/
73
+ └── skills/
74
+ ├── backend_api/
75
+ │ ├── manifest.md # 执行流程和规范(必需)
76
+ │ ├── context.md # 项目配置模板(必需)
77
+ │ ├── input/ # 输入文档目录
78
+ │ │ └── .gitkeep
79
+ │ ├── output/ # 输出文档目录
80
+ │ │ └── .gitkeep
81
+ │ └── tools/ # 提示词工具
82
+ │ ├── init.md # 初始化提示词
83
+ │ └── dev.md # 开发提示词
84
+ ├── frontend_api/
85
+ │ └── ...
86
+ └── another_skill/
87
+ └── ...
65
88
  ```
66
89
 
67
- ## 自建模板仓库
90
+ ### manifest.md 格式
68
91
 
69
- 创建 Git 仓库,在 `templates/` 目录下放置 Markdown 模板文件:
92
+ ```markdown
93
+ # Skill Manifest: 技能名称
70
94
 
71
- ```
72
- my-templates/
73
- └── templates/
74
- ├── my-template-1.md
75
- └── my-template-2.md
76
- ```
95
+ ## 技能描述
96
+ 简要说明这个技能包的用途。
77
97
 
78
- 模板格式(Markdown + Front Matter):
98
+ ## 执行协议
99
+ 定义 AI 执行任务的步骤流程。
79
100
 
80
- ```markdown
81
- ---
82
- name: my-template
83
- description: 模板描述
84
- category: backend
85
- outputFileName: my-template-prompt.md
86
- ---
101
+ ### 1. Context Check (上下文检查)
102
+ ...
87
103
 
88
- # 模板标题
104
+ ### 2. Input Acquisition (获取需求)
105
+ ...
89
106
 
90
- ## 任务
91
- 模板内容...
92
- ```
107
+ ### 3. Code Generation (代码生成)
108
+ ...
93
109
 
94
- ## 工作流程
110
+ ### 4. Documentation Output (文档输出)
111
+ ...
95
112
 
113
+ ## 约束条件
114
+ - 约束 1
115
+ - 约束 2
96
116
  ```
97
- 模板 → 正式提示词 → 对接文档/代码
98
117
 
99
- .prompts/
100
- ├── templates/ # 提示词模板
101
- └── generated/ # 正式提示词(AI 生成)
118
+ ---
102
119
 
103
- docs/
104
- └── api/ # 对接文档(业务相关)
120
+ ## 安装后的项目结构
121
+
122
+ ```
123
+ your-project/
124
+ ├── .ai-workspace/
125
+ │ ├── RULES.md # AI 工作流规则(自动生成)
126
+ │ └── skills/
127
+ │ ├── backend_api/
128
+ │ │ ├── manifest.md
129
+ │ │ ├── context.md # 需要初始化
130
+ │ │ ├── input/
131
+ │ │ ├── output/
132
+ │ │ └── tools/
133
+ │ └── frontend_api/
134
+ │ └── ...
135
+ └── (你的项目源码)
105
136
  ```
106
137
 
107
- ## 本地开发
138
+ ## 使用流程
139
+
140
+ 1. **安装技能包**:`pp skill install backend_api`
141
+ 2. **初始化配置**:查看 `tools/init.md`,复制提示词发送给 AI
142
+ 3. **AI 扫描项目**:AI 会分析项目并填充 `context.md`
143
+ 4. **开始开发**:将需求文档放入 `input/`,使用 `tools/dev.md` 的提示词
144
+
145
+ ## 技能包升级
146
+
147
+ 当仓库有更新时:
108
148
 
109
149
  ```bash
110
- npm install
111
- npm run build
112
- npm link
113
- prompt-plus list
150
+ pp repo sync # 同步仓库(不影响已安装的技能包)
151
+ pp skill upgrade # 升级技能包(保留 context.md、input/、output/)
152
+ ```
153
+
154
+ ## 工作流闭环
155
+
156
+ backend_api 会输出前端对接文档,可直接用于 frontend_api:
157
+
158
+ ```
159
+ backend_api 开发完成
160
+
161
+ 输出 output/api-spec-[模块].md
162
+
163
+ 复制到 frontend_api/input/
164
+
165
+ frontend_api 生成前端代码
114
166
  ```
115
167
 
116
168
  ## License
package/dist/cli.js CHANGED
@@ -44,44 +44,64 @@ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
44
44
  const program = new commander_1.Command();
45
45
  program
46
46
  .name('prompt-plus')
47
- .description('AI提示词模板管理工具 - 生成符合项目规范的提示词')
47
+ .description('AI 技能包管理工具 - 基于技能包驱动的开发工作流')
48
48
  .version(pkg.version);
49
- program
50
- .command('list')
51
- .alias('ls')
52
- .description('列出所有可用的提示词模板')
53
- .option('-r, --repo <name>', '指定仓库名称')
54
- .action(commands_1.listTemplates);
55
- program
56
- .command('use [templateName]')
57
- .description('选择并使用模板生成提示词')
58
- .option('-o, --output <path>', '输出路径', '.prompts')
59
- .option('-r, --repo <name>', '指定仓库名称')
60
- .action(commands_1.useTemplate);
61
- program
62
- .command('init')
63
- .description('初始化配置文件')
64
- .action(commands_1.initConfig);
49
+ // 仓库管理
65
50
  program
66
51
  .command('repo')
67
- .description('管理模板仓库')
52
+ .description('管理技能包仓库')
68
53
  .addCommand(new commander_1.Command('add')
69
- .description('添加模板仓库')
54
+ .description('添加技能包仓库')
70
55
  .argument('<name>', '仓库名称')
71
56
  .argument('<url>', '仓库地址')
72
57
  .option('-b, --branch <branch>', '分支名称', 'main')
73
58
  .action(commands_1.addRepo))
74
59
  .addCommand(new commander_1.Command('remove')
75
60
  .alias('rm')
76
- .description('移除模板仓库')
61
+ .description('移除仓库')
77
62
  .argument('<name>', '仓库名称')
78
63
  .action(commands_1.removeRepo))
79
64
  .addCommand(new commander_1.Command('list')
80
65
  .alias('ls')
81
- .description('列出所有模板仓库')
66
+ .description('列出所有仓库')
82
67
  .action(commands_1.listRepos))
83
68
  .addCommand(new commander_1.Command('sync')
84
- .description('同步模板仓库')
69
+ .description('同步仓库')
85
70
  .argument('[name]', '仓库名称(不指定则同步所有)')
86
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
+ .addCommand(new commander_1.Command('upgrade')
93
+ .alias('up')
94
+ .description('升级技能包(保留 context.md、input/、output/)')
95
+ .argument('[skillName]', '技能包名称(不指定则交互式选择)')
96
+ .option('-o, --output <path>', '工作区路径', '.ai-workspace')
97
+ .action(commands_1.upgradeSkill));
98
+ // 工作区管理
99
+ program
100
+ .command('workspace')
101
+ .alias('ws')
102
+ .description('管理 AI 工作区')
103
+ .addCommand(new commander_1.Command('init')
104
+ .description('初始化 AI 工作区')
105
+ .option('-o, --output <path>', '输出路径', '.ai-workspace')
106
+ .action(commands_1.initWorkspace));
87
107
  program.parse();
@@ -1,14 +1,22 @@
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>;
20
+ export declare function upgradeSkill(skillName?: string, options?: {
21
+ output?: string;
22
+ }): Promise<void>;
package/dist/commands.js CHANGED
@@ -33,17 +33,19 @@ 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;
44
+ exports.upgradeSkill = upgradeSkill;
43
45
  const fs = __importStar(require("fs"));
44
46
  const path = __importStar(require("path"));
45
47
  const child_process_1 = require("child_process");
46
- const templates_1 = require("./templates");
48
+ const skills_1 = require("./skills");
47
49
  // 配置文件路径(全局配置)
48
50
  const getGlobalConfigDir = () => path.join(process.env.HOME || process.env.USERPROFILE || '', '.prompt-plus');
49
51
  const getGlobalConfigPath = () => path.join(getGlobalConfigDir(), 'config.json');
@@ -64,7 +66,7 @@ function getConfig() {
64
66
  return {
65
67
  defaultRepo: '',
66
68
  repos: [],
67
- outputDir: '.prompts',
69
+ outputDir: '.ai-workspace',
68
70
  };
69
71
  }
70
72
  // 保存全局配置
@@ -75,140 +77,7 @@ function saveConfig(config) {
75
77
  }
76
78
  fs.writeFileSync(getGlobalConfigPath(), JSON.stringify(config, null, 2), 'utf-8');
77
79
  }
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
- }
80
+ // ==================== 仓库管理 ====================
212
81
  async function addRepo(name, url, options) {
213
82
  const chalk = await getChalk();
214
83
  const config = getConfig();
@@ -223,7 +92,7 @@ async function addRepo(name, url, options) {
223
92
  });
224
93
  saveConfig(config);
225
94
  console.log(chalk.green(`\n✅ 已添加仓库: ${name}`));
226
- console.log(chalk.gray(`使用 "prompt-plus repo sync ${name}" 同步模板\n`));
95
+ console.log(chalk.gray(`使用 "pp repo sync ${name}" 同步仓库\n`));
227
96
  }
228
97
  async function removeRepo(name) {
229
98
  const chalk = await getChalk();
@@ -245,19 +114,28 @@ async function removeRepo(name) {
245
114
  async function listRepos() {
246
115
  const chalk = await getChalk();
247
116
  const config = getConfig();
248
- console.log(chalk.cyan('\n📦 模板仓库列表:\n'));
117
+ console.log(chalk.cyan('\n📦 技能包仓库列表:\n'));
249
118
  if (config.repos.length === 0) {
250
119
  console.log(chalk.gray(' 暂无仓库,请先添加:'));
251
- console.log(chalk.gray(' prompt-plus repo add official https://github.com/LeeSeaside/prompt-plus-templates.git\n'));
120
+ console.log(chalk.gray(' pp repo add official https://github.com/your-repo/skills.git\n'));
252
121
  return;
253
122
  }
254
123
  for (const repo of config.repos) {
255
- const synced = fs.existsSync(path.join(getReposDir(), repo.name));
124
+ const repoDir = path.join(getReposDir(), repo.name);
125
+ const synced = fs.existsSync(repoDir);
256
126
  const status = synced ? chalk.green('✓ 已同步') : chalk.yellow('未同步');
257
- console.log(chalk.white(` • ${repo.name}`), chalk.gray(`- ${repo.url}`), status);
127
+ // 检查技能包数量
128
+ let skillCount = 0;
129
+ if (synced) {
130
+ const skillsDir = path.join(repoDir, 'skills');
131
+ if (fs.existsSync(skillsDir)) {
132
+ skillCount = (0, skills_1.loadSkillsFromDir)(skillsDir).length;
133
+ }
134
+ }
135
+ console.log(chalk.white(` • ${repo.name}`), chalk.gray(`- ${repo.url}`), status, synced ? chalk.gray(`(${skillCount} 个技能包)`) : '');
258
136
  }
259
- console.log(chalk.gray('\n使用 "prompt-plus repo add <name> <url>" 添加仓库'));
260
- console.log(chalk.gray('使用 "prompt-plus repo sync [name]" 同步仓库\n'));
137
+ console.log(chalk.gray('\n使用 "pp repo add <name> <url>" 添加仓库'));
138
+ console.log(chalk.gray('使用 "pp repo sync [name]" 同步仓库\n'));
261
139
  }
262
140
  async function syncRepo(name) {
263
141
  const chalk = await getChalk();
@@ -273,7 +151,7 @@ async function syncRepo(name) {
273
151
  }
274
152
  else {
275
153
  console.log(chalk.yellow('\n⚠️ 没有配置任何仓库'));
276
- console.log(chalk.gray('使用 "prompt-plus repo add <name> <url>" 添加仓库\n'));
154
+ console.log(chalk.gray('使用 "pp repo add <name> <url>" 添加仓库\n'));
277
155
  }
278
156
  return;
279
157
  }
@@ -289,6 +167,12 @@ async function syncRepo(name) {
289
167
  (0, child_process_1.execSync)(`git clone -b ${repo.branch || 'main'} "${repo.url}" "${repoDir}"`, { stdio: 'pipe' });
290
168
  console.log(chalk.green(`✅ 已克隆: ${repo.name}`));
291
169
  }
170
+ // 显示技能包数量
171
+ const skillsDir = path.join(repoDir, 'skills');
172
+ if (fs.existsSync(skillsDir)) {
173
+ const skills = (0, skills_1.loadSkillsFromDir)(skillsDir);
174
+ console.log(chalk.gray(` 发现 ${skills.length} 个技能包`));
175
+ }
292
176
  }
293
177
  catch (error) {
294
178
  console.log(chalk.red(`❌ 同步失败: ${repo.name}`));
@@ -297,3 +181,347 @@ async function syncRepo(name) {
297
181
  }
298
182
  console.log();
299
183
  }
184
+ // 获取所有技能包(按仓库分组)
185
+ async function getAllSkillsWithRepo(repoName) {
186
+ const config = getConfig();
187
+ const skills = [];
188
+ if (repoName) {
189
+ const repo = config.repos.find((r) => r.name === repoName);
190
+ if (repo) {
191
+ const repoDir = path.join(getReposDir(), repo.name);
192
+ if (fs.existsSync(repoDir)) {
193
+ const repoSkills = (0, skills_1.loadSkillsFromDir)(path.join(repoDir, 'skills'));
194
+ return repoSkills.map((s) => ({ ...s, repoName: repo.name }));
195
+ }
196
+ }
197
+ return [];
198
+ }
199
+ for (const repo of config.repos) {
200
+ const repoDir = path.join(getReposDir(), repo.name);
201
+ if (fs.existsSync(repoDir)) {
202
+ const repoSkills = (0, skills_1.loadSkillsFromDir)(path.join(repoDir, 'skills'));
203
+ skills.push(...repoSkills.map((s) => ({ ...s, repoName: repo.name })));
204
+ }
205
+ }
206
+ return skills;
207
+ }
208
+ // 列出所有技能包
209
+ async function listSkills(options) {
210
+ const chalk = await getChalk();
211
+ const skills = await getAllSkillsWithRepo(options?.repo);
212
+ if (skills.length === 0) {
213
+ console.log(chalk.yellow('\n⚠️ 没有找到技能包'));
214
+ console.log(chalk.gray('请先添加并同步仓库:'));
215
+ console.log(chalk.gray(' pp repo add official <仓库地址>'));
216
+ console.log(chalk.gray(' pp repo sync\n'));
217
+ return;
218
+ }
219
+ console.log(chalk.cyan('\n🎯 可用的技能包:\n'));
220
+ const repoNames = [...new Set(skills.map((s) => s.repoName))];
221
+ for (const repoName of repoNames) {
222
+ console.log(chalk.magenta(`📦 ${repoName}`));
223
+ const repoSkills = skills.filter((s) => s.repoName === repoName);
224
+ for (const skill of repoSkills) {
225
+ const status = [];
226
+ if (skill.hasManifest)
227
+ status.push(chalk.green('✓manifest'));
228
+ if (skill.hasContext)
229
+ status.push(chalk.green('✓context'));
230
+ if (skill.hasTools)
231
+ status.push(chalk.green('✓tools'));
232
+ console.log(chalk.white(` • ${skill.name}`), chalk.gray(`- ${skill.description || '无描述'}`), chalk.gray(`[${status.join(' ')}]`));
233
+ }
234
+ console.log();
235
+ }
236
+ console.log(chalk.gray('使用 "pp skill install <技能名>" 安装技能包到当前项目\n'));
237
+ }
238
+ // 安装技能包到当前项目
239
+ async function installSkill(skillName, options) {
240
+ const chalk = await getChalk();
241
+ const inquirer = await getInquirer();
242
+ const skills = await getAllSkillsWithRepo(options?.repo);
243
+ let selectedSkill;
244
+ if (skillName) {
245
+ selectedSkill = skills.find((s) => s.name === skillName);
246
+ if (!selectedSkill) {
247
+ console.log(chalk.red(`\n❌ 未找到技能包: ${skillName}`));
248
+ console.log(chalk.gray('使用 "pp skill list" 查看可用技能包\n'));
249
+ return;
250
+ }
251
+ }
252
+ else {
253
+ if (skills.length === 0) {
254
+ console.log(chalk.yellow('\n⚠️ 没有可用技能包'));
255
+ console.log(chalk.gray('请先添加并同步仓库\n'));
256
+ return;
257
+ }
258
+ const choices = skills.map((s) => ({
259
+ name: `[${s.repoName}] ${s.name} - ${s.description || '无描述'}`,
260
+ value: s.name,
261
+ }));
262
+ const answer = await inquirer.prompt([
263
+ {
264
+ type: 'list',
265
+ name: 'skill',
266
+ message: '请选择要安装的技能包:',
267
+ choices,
268
+ },
269
+ ]);
270
+ selectedSkill = skills.find((s) => s.name === answer.skill);
271
+ }
272
+ if (!selectedSkill) {
273
+ console.log(chalk.red('\n❌ 技能包选择失败'));
274
+ return;
275
+ }
276
+ const baseDir = options?.output || '.ai-workspace';
277
+ const targetDir = path.join(process.cwd(), baseDir, 'skills', selectedSkill.name);
278
+ // 检查是否已安装
279
+ if (fs.existsSync(targetDir)) {
280
+ const { overwrite } = await inquirer.prompt([
281
+ {
282
+ type: 'confirm',
283
+ name: 'overwrite',
284
+ message: `技能包 "${selectedSkill.name}" 已存在,是否覆盖?`,
285
+ default: false,
286
+ },
287
+ ]);
288
+ if (!overwrite) {
289
+ console.log(chalk.yellow('\n⚠️ 已取消安装\n'));
290
+ return;
291
+ }
292
+ fs.rmSync(targetDir, { recursive: true, force: true });
293
+ }
294
+ // 复制技能包
295
+ (0, skills_1.copySkill)(selectedSkill.path, targetDir);
296
+ // 确保 RULES.md 存在
297
+ const rulesPath = path.join(process.cwd(), baseDir, 'RULES.md');
298
+ if (!fs.existsSync(rulesPath)) {
299
+ await initWorkspace({ output: baseDir });
300
+ }
301
+ console.log(chalk.green(`\n✅ 技能包已安装: ${targetDir}`));
302
+ console.log(chalk.cyan('\n📝 下一步:'));
303
+ console.log(chalk.white(` 1. 查看 ${baseDir}/skills/${selectedSkill.name}/tools/init.md`));
304
+ console.log(chalk.white(' 2. 复制初始化提示词发送给 AI'));
305
+ console.log(chalk.white(' 3. AI 会扫描项目并填充 context.md\n'));
306
+ }
307
+ // 初始化 AI 工作区
308
+ async function initWorkspace(options) {
309
+ const chalk = await getChalk();
310
+ const baseDir = options?.output || '.ai-workspace';
311
+ const workspaceDir = path.join(process.cwd(), baseDir);
312
+ const rulesPath = path.join(workspaceDir, 'RULES.md');
313
+ if (fs.existsSync(rulesPath)) {
314
+ console.log(chalk.yellow('\n⚠️ AI 工作区已存在'));
315
+ console.log(chalk.gray(`路径: ${workspaceDir}\n`));
316
+ return;
317
+ }
318
+ // 创建目录结构
319
+ fs.mkdirSync(path.join(workspaceDir, 'skills'), { recursive: true });
320
+ // 创建 RULES.md
321
+ const rulesContent = `# AI WORKSPACE - SYSTEM PROTOCOL
322
+
323
+ > 此文件定义 AI 助手的强制性工作流规则,适用于所有 AI 编辑器(Cursor、Copilot、Kiro、Claude 等)
324
+
325
+ ## PRIORITY: ABSOLUTE (最高优先级)
326
+
327
+ 你是一个基于"技能包"驱动的开发助手。在处理任何开发任务之前,必须强制执行以下协议。
328
+
329
+ ## SKILL DISCOVERY
330
+
331
+ **动态发现技能**:扫描 \`.ai-workspace/skills/\` 目录,每个子目录即为一个技能包。
332
+
333
+ ## SKILL STRUCTURE
334
+
335
+ 每个技能包的标准结构:
336
+ \`\`\`
337
+ skills/[skill_name]/
338
+ ├── manifest.md # 执行流程和规范(必读)
339
+ ├── context.md # 项目配置(需初始化)
340
+ ├── input/ # 该技能的输入文档
341
+ ├── output/ # 该技能的输出文档
342
+ └── tools/ # 该技能的提示词工具
343
+ \`\`\`
344
+
345
+ ## MANDATORY WORKFLOW
346
+
347
+ ### 1. Skill Discovery (技能发现)
348
+ - 扫描 \`skills/\` 目录,列出所有可用技能
349
+ - 读取每个技能的 \`manifest.md\` 了解其用途
350
+
351
+ ### 2. Skill Selection (技能选择)
352
+ - 根据用户任务类型,选择对应的技能包
353
+ - 如果不确定,询问用户或列出可用技能供选择
354
+
355
+ ### 3. Load Skill (加载技能)
356
+ - 读取 \`skills/[skill]/manifest.md\` 获取执行流程
357
+ - 读取 \`skills/[skill]/context.md\` 获取项目配置
358
+
359
+ ### 4. Context Check (上下文检查)
360
+ - 如果 \`context.md\` 未初始化,**终止任务**
361
+ - 提示用户:"请先执行项目初始化,参考 \`skills/[skill]/tools/init.md\`"
362
+
363
+ ### 5. Input Acquisition (获取输入)
364
+ - 从 \`skills/[skill]/input/\` 读取需求文档
365
+
366
+ ### 6. Execute Task (执行任务)
367
+ - 按照 \`manifest.md\` 定义的流程执行
368
+ - 代码输出到项目源码目录(由 context.md 指定)
369
+
370
+ ### 7. Output Documentation (输出文档)
371
+ - 执行日志输出到 \`skills/[skill]/output/\`
372
+
373
+ ## CONSTRAINTS
374
+
375
+ - 严格遵循所选技能的 manifest.md 流程
376
+ - 代码路径受控于 context.md
377
+ - 禁止跨技能读写 input/output
378
+ - 禁止臆造依赖库或目录
379
+ - 新技能自动可用,无需修改此文件
380
+ `;
381
+ fs.writeFileSync(rulesPath, rulesContent, 'utf-8');
382
+ console.log(chalk.green('\n✅ AI 工作区已创建'));
383
+ console.log(chalk.gray(`路径: ${workspaceDir}`));
384
+ console.log(chalk.cyan('\n📝 下一步:'));
385
+ console.log(chalk.gray(' pp skill list # 查看可用技能包'));
386
+ console.log(chalk.gray(' pp skill install # 安装技能包\n'));
387
+ }
388
+ // 查看已安装的技能包
389
+ async function installedSkills(options) {
390
+ const chalk = await getChalk();
391
+ const baseDir = options?.output || '.ai-workspace';
392
+ const skillsDir = path.join(process.cwd(), baseDir, 'skills');
393
+ if (!fs.existsSync(skillsDir)) {
394
+ console.log(chalk.yellow('\n⚠️ 未找到 AI 工作区'));
395
+ console.log(chalk.gray('使用 "pp workspace init" 初始化工作区\n'));
396
+ return;
397
+ }
398
+ const skills = (0, skills_1.loadSkillsFromDir)(skillsDir);
399
+ if (skills.length === 0) {
400
+ console.log(chalk.yellow('\n⚠️ 未安装任何技能包'));
401
+ console.log(chalk.gray('使用 "pp skill install" 安装技能包\n'));
402
+ return;
403
+ }
404
+ console.log(chalk.cyan('\n🎯 已安装的技能包:\n'));
405
+ for (const skill of skills) {
406
+ const status = [];
407
+ if (skill.hasManifest)
408
+ status.push(chalk.green('✓manifest'));
409
+ if (skill.hasContext)
410
+ status.push(chalk.green('✓context'));
411
+ if (skill.hasTools)
412
+ status.push(chalk.green('✓tools'));
413
+ console.log(chalk.white(` • ${skill.name}`), chalk.gray(`- ${skill.description || '无描述'}`), chalk.gray(`[${status.join(' ')}]`));
414
+ }
415
+ console.log(chalk.gray(`\n📁 位置: ${skillsDir}\n`));
416
+ }
417
+ // 辅助函数:将目录内容复制到内存
418
+ function copyDirToMemory(dir) {
419
+ const files = new Map();
420
+ function readDir(currentDir, prefix = '') {
421
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
422
+ for (const entry of entries) {
423
+ const fullPath = path.join(currentDir, entry.name);
424
+ const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
425
+ if (entry.isDirectory()) {
426
+ readDir(fullPath, relativePath);
427
+ }
428
+ else {
429
+ files.set(relativePath, fs.readFileSync(fullPath));
430
+ }
431
+ }
432
+ }
433
+ readDir(dir);
434
+ return files;
435
+ }
436
+ // 辅助函数:从内存恢复目录
437
+ function restoreDirFromMemory(dir, files) {
438
+ for (const [relativePath, content] of files) {
439
+ const fullPath = path.join(dir, relativePath);
440
+ const dirPath = path.dirname(fullPath);
441
+ if (!fs.existsSync(dirPath)) {
442
+ fs.mkdirSync(dirPath, { recursive: true });
443
+ }
444
+ fs.writeFileSync(fullPath, content);
445
+ }
446
+ }
447
+ // 升级技能包(保留 context.md、input/、output/)
448
+ async function upgradeSkill(skillName, options) {
449
+ const chalk = await getChalk();
450
+ const inquirer = await getInquirer();
451
+ const baseDir = options?.output || '.ai-workspace';
452
+ const localSkillsDir = path.join(process.cwd(), baseDir, 'skills');
453
+ if (!fs.existsSync(localSkillsDir)) {
454
+ console.log(chalk.yellow('\n⚠️ 未找到 AI 工作区'));
455
+ console.log(chalk.gray('使用 "pp workspace init" 初始化工作区\n'));
456
+ return;
457
+ }
458
+ const localSkills = (0, skills_1.loadSkillsFromDir)(localSkillsDir);
459
+ if (localSkills.length === 0) {
460
+ console.log(chalk.yellow('\n⚠️ 未安装任何技能包\n'));
461
+ return;
462
+ }
463
+ // 获取仓库中的技能包
464
+ const repoSkills = await getAllSkillsWithRepo();
465
+ let skillsToUpgrade = [];
466
+ if (skillName) {
467
+ // 指定技能名
468
+ if (!localSkills.find((s) => s.name === skillName)) {
469
+ console.log(chalk.red(`\n❌ 未安装技能包: ${skillName}\n`));
470
+ return;
471
+ }
472
+ skillsToUpgrade = [skillName];
473
+ }
474
+ else {
475
+ // 交互式选择
476
+ const choices = localSkills.map((s) => ({
477
+ name: s.name,
478
+ value: s.name,
479
+ checked: true,
480
+ }));
481
+ const answer = await inquirer.prompt([
482
+ {
483
+ type: 'checkbox',
484
+ name: 'skills',
485
+ message: '选择要升级的技能包:',
486
+ choices,
487
+ },
488
+ ]);
489
+ skillsToUpgrade = answer.skills;
490
+ }
491
+ if (skillsToUpgrade.length === 0) {
492
+ console.log(chalk.yellow('\n⚠️ 未选择任何技能包\n'));
493
+ return;
494
+ }
495
+ console.log(chalk.cyan('\n🔄 开始升级技能包...\n'));
496
+ for (const name of skillsToUpgrade) {
497
+ const repoSkill = repoSkills.find((s) => s.name === name);
498
+ if (!repoSkill) {
499
+ console.log(chalk.yellow(` ⚠️ ${name}: 仓库中未找到,跳过`));
500
+ continue;
501
+ }
502
+ const localDir = path.join(localSkillsDir, name);
503
+ // 备份需要保留的文件
504
+ const contextPath = path.join(localDir, 'context.md');
505
+ const inputDir = path.join(localDir, 'input');
506
+ const outputDir = path.join(localDir, 'output');
507
+ const contextBackup = fs.existsSync(contextPath) ? fs.readFileSync(contextPath, 'utf-8') : null;
508
+ const inputBackup = fs.existsSync(inputDir) ? copyDirToMemory(inputDir) : null;
509
+ const outputBackup = fs.existsSync(outputDir) ? copyDirToMemory(outputDir) : null;
510
+ // 删除旧技能包
511
+ fs.rmSync(localDir, { recursive: true, force: true });
512
+ // 复制新技能包
513
+ (0, skills_1.copySkill)(repoSkill.path, localDir);
514
+ // 恢复备份
515
+ if (contextBackup) {
516
+ fs.writeFileSync(contextPath, contextBackup, 'utf-8');
517
+ }
518
+ if (inputBackup) {
519
+ restoreDirFromMemory(inputDir, inputBackup);
520
+ }
521
+ if (outputBackup) {
522
+ restoreDirFromMemory(outputDir, outputBackup);
523
+ }
524
+ console.log(chalk.green(` ✅ ${name}: 已升级(保留 context.md、input/、output/)`));
525
+ }
526
+ console.log(chalk.gray('\n升级完成!\n'));
527
+ }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { loadTemplatesFromDir } from './templates';
2
- export type { Template } from './types';
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.loadTemplatesFromDir = void 0;
4
- var templates_1 = require("./templates");
5
- Object.defineProperty(exports, "loadTemplatesFromDir", { enumerable: true, get: function () { return templates_1.loadTemplatesFromDir; } });
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; } });
@@ -0,0 +1,3 @@
1
+ import { Skill } from './types';
2
+ export declare function loadSkillsFromDir(skillsDir: string): Skill[];
3
+ export declare function copySkill(skillPath: string, targetDir: string): void;
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 Template {
1
+ export interface Skill {
2
2
  name: string;
3
3
  description: string;
4
4
  category: string;
5
- content: string;
6
- outputFileName: string;
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?: string;
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "prompt-plus",
3
- "version": "1.0.5",
4
- "description": "AI提示词模板管理工具 - 生成符合项目规范的提示词",
3
+ "version": "1.1.1",
4
+ "description": "AI技能包管理工具 - 基于技能包驱动的 AI 开发工作流",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "bin": {
@@ -1,2 +0,0 @@
1
- import { Template } from '../types';
2
- export declare function loadTemplatesFromDir(dir: string): Template[];
@@ -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
- }