prompt-plus 1.1.0 → 1.1.2
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 +42 -55
- package/dist/cli.js +8 -1
- package/dist/commands.d.ts +4 -0
- package/dist/commands.js +177 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
AI 技能包管理工具 - 基于技能包驱动的开发工作流
|
|
4
4
|
|
|
5
|
-
> ⚠️ **v1.1.0
|
|
5
|
+
> ⚠️ **v1.1.0+ 断档式更新**:不兼容 v1.0.x,请重新安装
|
|
6
6
|
|
|
7
7
|
## 安装
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ npm install -g prompt-plus
|
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
# 1. 添加技能包仓库
|
|
17
|
-
pp repo add official https://github.com/
|
|
17
|
+
pp repo add official https://github.com/LeeSeaside/prompt-plus-templates.git
|
|
18
18
|
|
|
19
19
|
# 2. 同步仓库
|
|
20
20
|
pp repo sync
|
|
@@ -34,29 +34,32 @@ pp skill installed
|
|
|
34
34
|
### 仓库管理
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
pp repo add <name> <url>
|
|
37
|
+
pp repo add <name> <url> # 添加技能包仓库
|
|
38
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>
|
|
39
|
+
pp repo remove <name> # 移除仓库
|
|
40
|
+
pp repo list # 列出所有仓库
|
|
41
|
+
pp repo sync # 同步所有仓库
|
|
42
|
+
pp repo sync <name> # 同步指定仓库
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
### 技能包管理
|
|
46
46
|
|
|
47
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
|
|
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 简写
|
|
53
56
|
```
|
|
54
57
|
|
|
55
58
|
### 工作区管理
|
|
56
59
|
|
|
57
60
|
```bash
|
|
58
|
-
pp workspace init
|
|
59
|
-
pp ws init
|
|
61
|
+
pp workspace init # 初始化 AI 工作区
|
|
62
|
+
pp ws init # 简写
|
|
60
63
|
```
|
|
61
64
|
|
|
62
65
|
---
|
|
@@ -66,7 +69,7 @@ pp ws init # 简写
|
|
|
66
69
|
如果你想创建自己的技能包仓库,请按以下格式组织:
|
|
67
70
|
|
|
68
71
|
```
|
|
69
|
-
|
|
72
|
+
prompt-plus-templates/
|
|
70
73
|
└── skills/
|
|
71
74
|
├── backend_api/
|
|
72
75
|
│ ├── manifest.md # 执行流程和规范(必需)
|
|
@@ -79,8 +82,6 @@ your-repo/
|
|
|
79
82
|
│ ├── init.md # 初始化提示词
|
|
80
83
|
│ └── dev.md # 开发提示词
|
|
81
84
|
├── frontend_api/
|
|
82
|
-
│ ├── manifest.md
|
|
83
|
-
│ ├── context.md
|
|
84
85
|
│ └── ...
|
|
85
86
|
└── another_skill/
|
|
86
87
|
└── ...
|
|
@@ -114,43 +115,6 @@ your-repo/
|
|
|
114
115
|
- 约束 2
|
|
115
116
|
```
|
|
116
117
|
|
|
117
|
-
### context.md 格式
|
|
118
|
-
|
|
119
|
-
```markdown
|
|
120
|
-
# Project Context Configuration
|
|
121
|
-
|
|
122
|
-
> ⚠️ 此文件需要初始化
|
|
123
|
-
|
|
124
|
-
## Tech Stack
|
|
125
|
-
- **Framework**: <!-- 待填充 -->
|
|
126
|
-
- **ORM**: <!-- 待填充 -->
|
|
127
|
-
|
|
128
|
-
## Directory Mapping
|
|
129
|
-
- **Controller Path**: <!-- 待填充 -->
|
|
130
|
-
- **Service Path**: <!-- 待填充 -->
|
|
131
|
-
|
|
132
|
-
## Code Style
|
|
133
|
-
- **Naming Convention**: <!-- 待填充 -->
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### tools/init.md 格式
|
|
137
|
-
|
|
138
|
-
```markdown
|
|
139
|
-
# 技能名 - 初始化提示词
|
|
140
|
-
|
|
141
|
-
## 使用方法
|
|
142
|
-
复制以下内容发送给 AI
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
\`\`\`
|
|
147
|
-
请执行 xxx 技能初始化:
|
|
148
|
-
1. 扫描项目结构
|
|
149
|
-
2. 识别技术栈
|
|
150
|
-
3. 将结果写入 context.md
|
|
151
|
-
\`\`\`
|
|
152
|
-
```
|
|
153
|
-
|
|
154
118
|
---
|
|
155
119
|
|
|
156
120
|
## 安装后的项目结构
|
|
@@ -158,7 +122,7 @@ your-repo/
|
|
|
158
122
|
```
|
|
159
123
|
your-project/
|
|
160
124
|
├── .ai-workspace/
|
|
161
|
-
│ ├── RULES.md # AI
|
|
125
|
+
│ ├── RULES.md # AI 工作流规则(自动生成)
|
|
162
126
|
│ └── skills/
|
|
163
127
|
│ ├── backend_api/
|
|
164
128
|
│ │ ├── manifest.md
|
|
@@ -178,6 +142,29 @@ your-project/
|
|
|
178
142
|
3. **AI 扫描项目**:AI 会分析项目并填充 `context.md`
|
|
179
143
|
4. **开始开发**:将需求文档放入 `input/`,使用 `tools/dev.md` 的提示词
|
|
180
144
|
|
|
145
|
+
## 技能包升级
|
|
146
|
+
|
|
147
|
+
当仓库有更新时:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
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 生成前端代码
|
|
166
|
+
```
|
|
167
|
+
|
|
181
168
|
## License
|
|
182
169
|
|
|
183
170
|
MIT
|
package/dist/cli.js
CHANGED
|
@@ -88,7 +88,14 @@ program
|
|
|
88
88
|
.addCommand(new commander_1.Command('installed')
|
|
89
89
|
.description('查看已安装的技能包')
|
|
90
90
|
.option('-o, --output <path>', '工作区路径', '.ai-workspace')
|
|
91
|
-
.action(commands_1.installedSkills))
|
|
91
|
+
.action(commands_1.installedSkills))
|
|
92
|
+
.addCommand(new commander_1.Command('upgrade')
|
|
93
|
+
.alias('up')
|
|
94
|
+
.description('升级技能包(智能合并 context.md)')
|
|
95
|
+
.argument('[skillName]', '技能包名称(不指定则交互式选择)')
|
|
96
|
+
.option('-o, --output <path>', '工作区路径', '.ai-workspace')
|
|
97
|
+
.option('-m, --mode <mode>', 'context.md 处理策略: merge(智能合并) | keep(保留本地) | overwrite(使用仓库)')
|
|
98
|
+
.action(commands_1.upgradeSkill));
|
|
92
99
|
// 工作区管理
|
|
93
100
|
program
|
|
94
101
|
.command('workspace')
|
package/dist/commands.d.ts
CHANGED
|
@@ -17,3 +17,7 @@ export declare function initWorkspace(options?: {
|
|
|
17
17
|
export declare function installedSkills(options?: {
|
|
18
18
|
output?: string;
|
|
19
19
|
}): Promise<void>;
|
|
20
|
+
export declare function upgradeSkill(skillName?: string, options?: {
|
|
21
|
+
output?: string;
|
|
22
|
+
mode?: string;
|
|
23
|
+
}): Promise<void>;
|
package/dist/commands.js
CHANGED
|
@@ -41,6 +41,7 @@ exports.listSkills = listSkills;
|
|
|
41
41
|
exports.installSkill = installSkill;
|
|
42
42
|
exports.initWorkspace = initWorkspace;
|
|
43
43
|
exports.installedSkills = installedSkills;
|
|
44
|
+
exports.upgradeSkill = upgradeSkill;
|
|
44
45
|
const fs = __importStar(require("fs"));
|
|
45
46
|
const path = __importStar(require("path"));
|
|
46
47
|
const child_process_1 = require("child_process");
|
|
@@ -116,7 +117,7 @@ async function listRepos() {
|
|
|
116
117
|
console.log(chalk.cyan('\n📦 技能包仓库列表:\n'));
|
|
117
118
|
if (config.repos.length === 0) {
|
|
118
119
|
console.log(chalk.gray(' 暂无仓库,请先添加:'));
|
|
119
|
-
console.log(chalk.gray(' pp repo add official https://github.com/
|
|
120
|
+
console.log(chalk.gray(' pp repo add official https://github.com/LeeSeaside/prompt-plus-templates.git\n'));
|
|
120
121
|
return;
|
|
121
122
|
}
|
|
122
123
|
for (const repo of config.repos) {
|
|
@@ -413,3 +414,178 @@ async function installedSkills(options) {
|
|
|
413
414
|
}
|
|
414
415
|
console.log(chalk.gray(`\n📁 位置: ${skillsDir}\n`));
|
|
415
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:保留用户填充的值,更新模板结构
|
|
448
|
+
function mergeContextMd(localContent, repoContent) {
|
|
449
|
+
// 提取本地已填充的值(非注释、非占位符的内容)
|
|
450
|
+
const userValues = new Map();
|
|
451
|
+
// 匹配 "- **Key**: Value" 或 "- Key: Value" 格式
|
|
452
|
+
const valuePattern = /^[-*]\s*\*?\*?([^:*]+)\*?\*?:\s*(.+)$/gm;
|
|
453
|
+
let match;
|
|
454
|
+
while ((match = valuePattern.exec(localContent)) !== null) {
|
|
455
|
+
const key = match[1].trim();
|
|
456
|
+
const value = match[2].trim();
|
|
457
|
+
// 跳过占位符和注释
|
|
458
|
+
if (value && !value.startsWith('<!--') && !value.includes('待填充') && !value.includes('⚠️')) {
|
|
459
|
+
userValues.set(key.toLowerCase(), value);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
// 在新模板中填充用户值
|
|
463
|
+
let merged = repoContent;
|
|
464
|
+
for (const [key, value] of userValues) {
|
|
465
|
+
// 替换占位符
|
|
466
|
+
const placeholderPattern = new RegExp(`([-*]\\s*\\*?\\*?${key}\\*?\\*?:\\s*)<!--[^>]*-->`, 'gi');
|
|
467
|
+
merged = merged.replace(placeholderPattern, `$1${value}`);
|
|
468
|
+
}
|
|
469
|
+
return merged;
|
|
470
|
+
}
|
|
471
|
+
// 升级技能包
|
|
472
|
+
async function upgradeSkill(skillName, options) {
|
|
473
|
+
const chalk = await getChalk();
|
|
474
|
+
const inquirer = await getInquirer();
|
|
475
|
+
const baseDir = options?.output || '.ai-workspace';
|
|
476
|
+
const localSkillsDir = path.join(process.cwd(), baseDir, 'skills');
|
|
477
|
+
if (!fs.existsSync(localSkillsDir)) {
|
|
478
|
+
console.log(chalk.yellow('\n⚠️ 未找到 AI 工作区'));
|
|
479
|
+
console.log(chalk.gray('使用 "pp workspace init" 初始化工作区\n'));
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const localSkills = (0, skills_1.loadSkillsFromDir)(localSkillsDir);
|
|
483
|
+
if (localSkills.length === 0) {
|
|
484
|
+
console.log(chalk.yellow('\n⚠️ 未安装任何技能包\n'));
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
// 获取仓库中的技能包
|
|
488
|
+
const repoSkills = await getAllSkillsWithRepo();
|
|
489
|
+
let skillsToUpgrade = [];
|
|
490
|
+
if (skillName) {
|
|
491
|
+
if (!localSkills.find((s) => s.name === skillName)) {
|
|
492
|
+
console.log(chalk.red(`\n❌ 未安装技能包: ${skillName}\n`));
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
skillsToUpgrade = [skillName];
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
const choices = localSkills.map((s) => ({
|
|
499
|
+
name: s.name,
|
|
500
|
+
value: s.name,
|
|
501
|
+
checked: true,
|
|
502
|
+
}));
|
|
503
|
+
const answer = await inquirer.prompt([
|
|
504
|
+
{
|
|
505
|
+
type: 'checkbox',
|
|
506
|
+
name: 'skills',
|
|
507
|
+
message: '选择要升级的技能包:',
|
|
508
|
+
choices,
|
|
509
|
+
},
|
|
510
|
+
]);
|
|
511
|
+
skillsToUpgrade = answer.skills;
|
|
512
|
+
}
|
|
513
|
+
if (skillsToUpgrade.length === 0) {
|
|
514
|
+
console.log(chalk.yellow('\n⚠️ 未选择任何技能包\n'));
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
// 选择 context.md 处理策略
|
|
518
|
+
let contextMode = options?.mode;
|
|
519
|
+
if (!contextMode) {
|
|
520
|
+
const modeAnswer = await inquirer.prompt([
|
|
521
|
+
{
|
|
522
|
+
type: 'list',
|
|
523
|
+
name: 'mode',
|
|
524
|
+
message: 'context.md 处理策略:',
|
|
525
|
+
choices: [
|
|
526
|
+
{ name: '智能合并 - 保留用户数据,更新模板结构(推荐)', value: 'merge' },
|
|
527
|
+
{ name: '保留本地 - 完全保留本地 context.md', value: 'keep' },
|
|
528
|
+
{ name: '使用仓库 - 使用仓库最新版本(会丢失已填充数据)', value: 'overwrite' },
|
|
529
|
+
],
|
|
530
|
+
default: 'merge',
|
|
531
|
+
},
|
|
532
|
+
]);
|
|
533
|
+
contextMode = modeAnswer.mode;
|
|
534
|
+
}
|
|
535
|
+
console.log(chalk.cyan('\n🔄 开始升级技能包...\n'));
|
|
536
|
+
for (const name of skillsToUpgrade) {
|
|
537
|
+
const repoSkill = repoSkills.find((s) => s.name === name);
|
|
538
|
+
if (!repoSkill) {
|
|
539
|
+
console.log(chalk.yellow(` ⚠️ ${name}: 仓库中未找到,跳过`));
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
const localDir = path.join(localSkillsDir, name);
|
|
543
|
+
const contextPath = path.join(localDir, 'context.md');
|
|
544
|
+
const inputDir = path.join(localDir, 'input');
|
|
545
|
+
const outputDir = path.join(localDir, 'output');
|
|
546
|
+
// 备份
|
|
547
|
+
const localContext = fs.existsSync(contextPath) ? fs.readFileSync(contextPath, 'utf-8') : null;
|
|
548
|
+
const inputBackup = fs.existsSync(inputDir) ? copyDirToMemory(inputDir) : null;
|
|
549
|
+
const outputBackup = fs.existsSync(outputDir) ? copyDirToMemory(outputDir) : null;
|
|
550
|
+
// 删除旧技能包
|
|
551
|
+
fs.rmSync(localDir, { recursive: true, force: true });
|
|
552
|
+
// 复制新技能包
|
|
553
|
+
(0, skills_1.copySkill)(repoSkill.path, localDir);
|
|
554
|
+
// 处理 context.md
|
|
555
|
+
const repoContextPath = path.join(repoSkill.path, 'context.md');
|
|
556
|
+
const repoContext = fs.existsSync(repoContextPath) ? fs.readFileSync(repoContextPath, 'utf-8') : null;
|
|
557
|
+
if (localContext && repoContext) {
|
|
558
|
+
let finalContext;
|
|
559
|
+
switch (contextMode) {
|
|
560
|
+
case 'keep':
|
|
561
|
+
finalContext = localContext;
|
|
562
|
+
break;
|
|
563
|
+
case 'overwrite':
|
|
564
|
+
finalContext = repoContext;
|
|
565
|
+
break;
|
|
566
|
+
case 'merge':
|
|
567
|
+
default:
|
|
568
|
+
finalContext = mergeContextMd(localContext, repoContext);
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
fs.writeFileSync(contextPath, finalContext, 'utf-8');
|
|
572
|
+
}
|
|
573
|
+
else if (localContext) {
|
|
574
|
+
fs.writeFileSync(contextPath, localContext, 'utf-8');
|
|
575
|
+
}
|
|
576
|
+
// 恢复 input 和 output
|
|
577
|
+
if (inputBackup) {
|
|
578
|
+
restoreDirFromMemory(inputDir, inputBackup);
|
|
579
|
+
}
|
|
580
|
+
if (outputBackup) {
|
|
581
|
+
restoreDirFromMemory(outputDir, outputBackup);
|
|
582
|
+
}
|
|
583
|
+
const modeLabel = contextMode === 'merge' ? '智能合并' : contextMode === 'keep' ? '保留本地' : '使用仓库';
|
|
584
|
+
console.log(chalk.green(` ✅ ${name}: 已升级(context.md: ${modeLabel})`));
|
|
585
|
+
}
|
|
586
|
+
console.log(chalk.gray('\n升级完成!\n'));
|
|
587
|
+
if (contextMode === 'merge') {
|
|
588
|
+
console.log(chalk.cyan('💡 提示: 智能合并已尝试保留您的配置数据。'));
|
|
589
|
+
console.log(chalk.gray(' 如果仓库新增了配置项,请检查 context.md 并补充填写。\n'));
|
|
590
|
+
}
|
|
591
|
+
}
|