@wdyy/skills 0.1.2 → 0.1.4
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 +3 -3
- package/lib/wdyy-cli.js +104 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ npm install -g @wdyy/skills
|
|
|
29
29
|
wdyy init
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
`wdyy init`
|
|
32
|
+
`wdyy init` 会在系统用户目录 `.agents/skills/` 安装或更新 5 个受管理 Skill,不在目标项目创建 `.agents/skills/`。它还会执行 `git init`,创建或补齐 `.gitignore` 的 `.env`、`node_modules/`、`venv/`、`.pnpm-store/`、`logs/`、`dist/`、`.DS_Store`、`*.tar.gz` 规则,创建 `src/frontend`、`src/backend`、`database`、`deploy`、`docs`、`scripts`、`tests` 和空 `.env.example`,并执行 `openspec init`、创建或追加 `docs/bug_record.md` 模板。若目标项目已有 `AGENTS.md`,原文件保持不变,命令将生成 `AGENTS_new.md`。
|
|
33
33
|
|
|
34
34
|
### 仅更新已安装的 Skill
|
|
35
35
|
|
|
@@ -41,9 +41,9 @@ wdyy update-skill wdyy-logging-standard
|
|
|
41
41
|
wdyy update-skill --all
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
`wdyy update-skill <skill-name>` 只接受 5 个受管理的 `wdyy-*` Skill
|
|
44
|
+
`wdyy update-skill <skill-name>` 只接受 5 个受管理的 `wdyy-*` Skill,且仅替换系统用户目录 `.agents/skills/` 中的指定目录;`--all` 替换全部 5 个受管理 Skill。两种方式都不会写入调用项目的 `AGENTS.md`、`AGENTS_new.md`、`docs/bug_record.md` 或 `.agents/skills/`,也不会执行 `openspec init`。首次初始化或需要重新生成项目规则时,使用 `wdyy init`。
|
|
45
45
|
|
|
46
|
-
中大型变更先使用 `/opsx:explore` 或 `/opsx:propose <change-name>`,在方案确认后使用 `/opsx:apply`;完成验证后使用 `/opsx:archive`。涉及数据库、内部 API、日志、部署时,按 `AGENTS.md` 的路由加载相应企业 Skill
|
|
46
|
+
中大型变更先使用 `/opsx:explore` 或 `/opsx:propose <change-name>`,在方案确认后使用 `/opsx:apply`;完成验证后使用 `/opsx:archive`。涉及数据库、内部 API、日志、部署时,按 `AGENTS.md` 的路由加载相应企业 Skill。所有 URL、端口和 IP 地址从 `.env` 读取,不得硬编码;不得提交秘密或生产环境 `.env`。项目完成后创建 `README.md`,说明技术栈、目录结构和安装部署。
|
|
47
47
|
|
|
48
48
|
## 固定技术栈
|
|
49
49
|
|
package/lib/wdyy-cli.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
2
|
import { access, appendFile, cp, mkdir, mkdtemp, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
3
4
|
import { dirname, join } from 'node:path';
|
|
4
5
|
import { fileURLToPath } from 'node:url';
|
|
5
6
|
|
|
@@ -12,6 +13,29 @@ const managedSkillNames = [
|
|
|
12
13
|
'wdyy-deployment-standard'
|
|
13
14
|
];
|
|
14
15
|
|
|
16
|
+
const defaultProjectDirectories = [
|
|
17
|
+
'src/frontend',
|
|
18
|
+
'src/backend',
|
|
19
|
+
'database',
|
|
20
|
+
'deploy',
|
|
21
|
+
'docs',
|
|
22
|
+
'scripts',
|
|
23
|
+
'tests'
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const requiredGitIgnoreEntries = [
|
|
27
|
+
'.env',
|
|
28
|
+
'node_modules/',
|
|
29
|
+
'venv/',
|
|
30
|
+
'.pnpm-store/',
|
|
31
|
+
'logs/',
|
|
32
|
+
'dist/',
|
|
33
|
+
'.DS_Store',
|
|
34
|
+
'*.tar.gz'
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const defaultProjectLayout = [...defaultProjectDirectories, '.env.example'];
|
|
38
|
+
|
|
15
39
|
const generatedAgentsContent = `# 企业开发规则
|
|
16
40
|
|
|
17
41
|
本项目同时使用OpenSpec及企业 Skill统一开发规则及流程。
|
|
@@ -23,9 +47,11 @@ const generatedAgentsContent = `# 企业开发规则
|
|
|
23
47
|
- 后端:NestJS。
|
|
24
48
|
- 数据库:PostgreSQL 18。
|
|
25
49
|
|
|
26
|
-
默认项目目录为
|
|
50
|
+
默认项目目录为 ${defaultProjectLayout.map((path) => `\`${path}\``).join('、')}。
|
|
27
51
|
|
|
28
|
-
|
|
52
|
+
所有 URL、端口和 IP 地址必须从 \`.env\` 文件读取,禁止在代码中硬编码;不得提交秘密或生产环境 \`.env\`。
|
|
53
|
+
|
|
54
|
+
项目开发完成后必须创建 \`README.md\`,内容包括项目技术栈、目录结构和安装部署说明。
|
|
29
55
|
|
|
30
56
|
## Skill 路由
|
|
31
57
|
|
|
@@ -54,8 +80,7 @@ function printHelp() {
|
|
|
54
80
|
console.log('仅更新当前项目的一个或全部受管理 wdyy Skill,不执行项目初始化。');
|
|
55
81
|
}
|
|
56
82
|
|
|
57
|
-
async function installManagedSkills(
|
|
58
|
-
const skillsRoot = join(targetRoot, '.agents', 'skills');
|
|
83
|
+
async function installManagedSkills(skillsRoot, writtenPaths, skillNames = managedSkillNames) {
|
|
59
84
|
await mkdir(skillsRoot, { recursive: true });
|
|
60
85
|
const temporaryRoot = await mkdtemp(join(skillsRoot, '.wdyy-skills-'));
|
|
61
86
|
|
|
@@ -78,6 +103,72 @@ async function installManagedSkills(targetRoot, writtenPaths, skillNames = manag
|
|
|
78
103
|
}
|
|
79
104
|
}
|
|
80
105
|
|
|
106
|
+
function getGlobalSkillsRoot() {
|
|
107
|
+
return join(homedir(), '.agents', 'skills');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function printWrittenPaths(writtenPaths) {
|
|
111
|
+
if (writtenPaths.length > 0) console.error(`已写入路径:\n${writtenPaths.map((path) => `- ${path}`).join('\n')}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function initializeGit(targetRoot, writtenPaths) {
|
|
115
|
+
const result = spawnSync('git', ['init'], { cwd: targetRoot, stdio: 'inherit' });
|
|
116
|
+
if (result.error || result.status !== 0) {
|
|
117
|
+
const detail = result.error?.message ?? `退出码 ${result.status ?? 1}`;
|
|
118
|
+
console.error(`Git 初始化失败: ${detail}`);
|
|
119
|
+
printWrittenPaths(writtenPaths);
|
|
120
|
+
return result.status ?? 1;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
writtenPaths.push(join(targetRoot, '.git'));
|
|
124
|
+
console.log('Git 初始化完成。');
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function appendGitIgnoreEntries(targetRoot, writtenPaths) {
|
|
129
|
+
const gitIgnorePath = join(targetRoot, '.gitignore');
|
|
130
|
+
let existing = '';
|
|
131
|
+
try {
|
|
132
|
+
existing = await readFile(gitIgnorePath, 'utf8');
|
|
133
|
+
} catch (error) {
|
|
134
|
+
if (error.code !== 'ENOENT') throw error;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const existingEntries = new Set(existing.split(/\r?\n/).map((entry) => entry.trim()).filter(Boolean));
|
|
138
|
+
const missingEntries = requiredGitIgnoreEntries.filter((entry) => !existingEntries.has(entry));
|
|
139
|
+
if (missingEntries.length === 0 && existing.length > 0) return;
|
|
140
|
+
|
|
141
|
+
const prefix = existing.length === 0 ? '' : existing.endsWith('\n') ? '' : '\n';
|
|
142
|
+
await appendFile(gitIgnorePath, `${prefix}${missingEntries.join('\n')}\n`, 'utf8');
|
|
143
|
+
writtenPaths.push(gitIgnorePath);
|
|
144
|
+
console.log(`已更新 Git 忽略规则: ${gitIgnorePath}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function createDefaultProjectLayout(targetRoot, writtenPaths) {
|
|
148
|
+
for (const directory of defaultProjectDirectories) {
|
|
149
|
+
const destination = join(targetRoot, directory);
|
|
150
|
+
let existed = true;
|
|
151
|
+
try {
|
|
152
|
+
await access(destination);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (error.code !== 'ENOENT') throw error;
|
|
155
|
+
existed = false;
|
|
156
|
+
}
|
|
157
|
+
await mkdir(destination, { recursive: true });
|
|
158
|
+
if (!existed) writtenPaths.push(destination);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const envExamplePath = join(targetRoot, '.env.example');
|
|
162
|
+
try {
|
|
163
|
+
await access(envExamplePath);
|
|
164
|
+
} catch (error) {
|
|
165
|
+
if (error.code !== 'ENOENT') throw error;
|
|
166
|
+
await writeFile(envExamplePath, '', 'utf8');
|
|
167
|
+
writtenPaths.push(envExamplePath);
|
|
168
|
+
}
|
|
169
|
+
console.log(`已准备默认项目目录: ${defaultProjectDirectories.join('、')}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
81
172
|
async function writeAgentsFile(targetRoot, writtenPaths) {
|
|
82
173
|
const agentsPath = join(targetRoot, 'AGENTS.md');
|
|
83
174
|
let destination = agentsPath;
|
|
@@ -115,7 +206,7 @@ function initializeOpenSpec(targetRoot, writtenPaths) {
|
|
|
115
206
|
if (result.error || result.status !== 0) {
|
|
116
207
|
const detail = result.error?.message ?? `退出码 ${result.status ?? 1}`;
|
|
117
208
|
console.error(`OpenSpec 初始化失败: ${detail}`);
|
|
118
|
-
|
|
209
|
+
printWrittenPaths(writtenPaths);
|
|
119
210
|
return result.status ?? 1;
|
|
120
211
|
}
|
|
121
212
|
|
|
@@ -127,8 +218,12 @@ export async function run(argumentsList) {
|
|
|
127
218
|
if (argumentsList.length === 1 && argumentsList[0] === 'init') {
|
|
128
219
|
const writtenPaths = [];
|
|
129
220
|
try {
|
|
221
|
+
const gitExitCode = initializeGit(process.cwd(), writtenPaths);
|
|
222
|
+
if (gitExitCode !== 0) return gitExitCode;
|
|
130
223
|
await writeAgentsFile(process.cwd(), writtenPaths);
|
|
131
|
-
await installManagedSkills(
|
|
224
|
+
await installManagedSkills(getGlobalSkillsRoot(), writtenPaths);
|
|
225
|
+
await appendGitIgnoreEntries(process.cwd(), writtenPaths);
|
|
226
|
+
await createDefaultProjectLayout(process.cwd(), writtenPaths);
|
|
132
227
|
await appendBugRecordTemplate(process.cwd(), writtenPaths);
|
|
133
228
|
const openSpecExitCode = initializeOpenSpec(process.cwd(), writtenPaths);
|
|
134
229
|
if (openSpecExitCode !== 0) return openSpecExitCode;
|
|
@@ -136,7 +231,7 @@ export async function run(argumentsList) {
|
|
|
136
231
|
return 0;
|
|
137
232
|
} catch (error) {
|
|
138
233
|
console.error(`wdyy 初始化失败: ${error.message}`);
|
|
139
|
-
|
|
234
|
+
printWrittenPaths(writtenPaths);
|
|
140
235
|
return 1;
|
|
141
236
|
}
|
|
142
237
|
}
|
|
@@ -156,11 +251,11 @@ export async function run(argumentsList) {
|
|
|
156
251
|
|
|
157
252
|
const writtenPaths = [];
|
|
158
253
|
try {
|
|
159
|
-
await installManagedSkills(
|
|
254
|
+
await installManagedSkills(getGlobalSkillsRoot(), writtenPaths, skillNames);
|
|
160
255
|
return 0;
|
|
161
256
|
} catch (error) {
|
|
162
257
|
console.error(`Skill 更新失败: ${error.message}`);
|
|
163
|
-
|
|
258
|
+
printWrittenPaths(writtenPaths);
|
|
164
259
|
return 1;
|
|
165
260
|
}
|
|
166
261
|
}
|