sillyspec 3.7.1 → 3.7.3
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/package.json +1 -1
- package/src/index.js +11 -483
- package/src/setup.js +232 -64
- package/templates/brainstorm.md +2 -6
- package/templates/execute.md +79 -0
- package/templates/explore.md +24 -0
- package/templates/plan.md +30 -6
- package/templates/propose.md +3 -7
- package/templates/quick.md +9 -0
- package/templates/scan.md +17 -5
- package/templates/verify.md +113 -4
- package/.claude/commands/sillyspec/archive.md +0 -63
- package/.claude/commands/sillyspec/brainstorm.md +0 -182
- package/.claude/commands/sillyspec/continue.md +0 -32
- package/.claude/commands/sillyspec/execute.md +0 -133
- package/.claude/commands/sillyspec/explore.md +0 -43
- package/.claude/commands/sillyspec/export.md +0 -21
- package/.claude/commands/sillyspec/init.md +0 -64
- package/.claude/commands/sillyspec/plan.md +0 -112
- package/.claude/commands/sillyspec/propose.md +0 -77
- package/.claude/commands/sillyspec/quick.md +0 -76
- package/.claude/commands/sillyspec/resume.md +0 -53
- package/.claude/commands/sillyspec/scan-quick.md +0 -47
- package/.claude/commands/sillyspec/scan.md +0 -135
- package/.claude/commands/sillyspec/status.md +0 -72
- package/.claude/commands/sillyspec/verify.md +0 -87
- package/.claude/commands/sillyspec/workspace-sync.md +0 -89
- package/.claude/commands/sillyspec/workspace.md +0 -67
- package/.sillyspec/config.yaml +0 -13
package/src/setup.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
2
2
|
import { join, dirname } from 'path';
|
|
3
|
+
import { execSync } from 'child_process';
|
|
3
4
|
import chalk from 'chalk';
|
|
4
5
|
import ora from 'ora';
|
|
5
|
-
import { checkbox, confirm } from '@inquirer/prompts';
|
|
6
|
+
import { checkbox, confirm, input, select } from '@inquirer/prompts';
|
|
6
7
|
|
|
7
8
|
// ── MCP 工具定义 ──
|
|
8
9
|
|
|
@@ -15,24 +16,70 @@ const MCP_TOOLS = [
|
|
|
15
16
|
args: ['-y', '@upstash/context7-mcp@latest'],
|
|
16
17
|
url: 'https://github.com/upstash/context7-mcp',
|
|
17
18
|
},
|
|
18
|
-
{
|
|
19
|
-
id: 'grep-app',
|
|
20
|
-
name: 'grep.app',
|
|
21
|
-
description: '搜索开源代码实现和参考',
|
|
22
|
-
command: 'npx',
|
|
23
|
-
args: ['-y', '@nicobailon/grep-app-mcp'],
|
|
24
|
-
url: 'https://grep.app',
|
|
25
|
-
},
|
|
26
19
|
{
|
|
27
20
|
id: 'chrome-devtools',
|
|
28
21
|
name: 'Chrome DevTools MCP',
|
|
29
22
|
description: '浏览器自动化,支持 E2E 测试(需 Chrome 已运行)',
|
|
30
23
|
command: 'npx',
|
|
31
|
-
args: ['
|
|
24
|
+
args: ['chrome-devtools-mcp@latest'],
|
|
32
25
|
url: 'https://github.com/ChromeDevTools/chrome-devtools-mcp',
|
|
33
26
|
},
|
|
34
27
|
];
|
|
35
28
|
|
|
29
|
+
// ── 数据库 MCP 定义(需要连接信息)──
|
|
30
|
+
|
|
31
|
+
const DB_MCP_TOOLS = [
|
|
32
|
+
{
|
|
33
|
+
id: 'postgres',
|
|
34
|
+
name: 'PostgreSQL',
|
|
35
|
+
description: '只读访问 PostgreSQL 数据库',
|
|
36
|
+
command: 'npx',
|
|
37
|
+
args: ['-y', '@modelcontextprotocol/server-postgres'],
|
|
38
|
+
envTemplate: { POSTGRES_CONNECTION_STRING: 'postgresql://user:password@localhost:5432/dbname' },
|
|
39
|
+
url: 'https://github.com/modelcontextprotocol/servers/tree/main/src/postgres',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 'sqlite',
|
|
43
|
+
name: 'SQLite',
|
|
44
|
+
description: '访问 SQLite 数据库文件',
|
|
45
|
+
command: 'npx',
|
|
46
|
+
args: ['-y', '@modelcontextprotocol/server-sqlite'],
|
|
47
|
+
envTemplate: { SQLITE_DB_PATH: './data.db' },
|
|
48
|
+
url: 'https://github.com/modelcontextprotocol/servers/tree/main/src/sqlite',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'mysql',
|
|
52
|
+
name: 'MySQL / MariaDB',
|
|
53
|
+
description: '访问 MySQL / MariaDB 数据库',
|
|
54
|
+
command: 'npx',
|
|
55
|
+
args: ['-y', '@nicobailon/mysql-mcp-server'],
|
|
56
|
+
envTemplate: { MYSQL_HOST: 'localhost', MYSQL_PORT: '3306', MYSQL_USER: 'root', MYSQL_PASSWORD: '', MYSQL_DATABASE: '' },
|
|
57
|
+
url: 'https://github.com/modelcontextprotocol/servers',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 'redis',
|
|
61
|
+
name: 'Redis',
|
|
62
|
+
description: '访问 Redis 数据库,查看缓存和键值数据',
|
|
63
|
+
command: 'npx',
|
|
64
|
+
args: ['-y', '@modelcontextprotocol/server-redis'],
|
|
65
|
+
envTemplate: { REDIS_URL: 'redis://localhost:6379' },
|
|
66
|
+
url: 'https://github.com/modelcontextprotocol/servers/tree/main/src/redis',
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
// ── 全局工具定义 ──
|
|
71
|
+
|
|
72
|
+
const GLOBAL_TOOLS = [
|
|
73
|
+
{
|
|
74
|
+
id: 'playwright',
|
|
75
|
+
name: 'Playwright',
|
|
76
|
+
description: 'E2E 测试框架,支持浏览器自动化测试',
|
|
77
|
+
checkCommand: 'npx playwright --version',
|
|
78
|
+
installCommand: 'npm install -g @playwright/test && npx playwright install chromium',
|
|
79
|
+
url: 'https://playwright.dev',
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
|
|
36
83
|
// ── MCP 配置文件路径 ──
|
|
37
84
|
|
|
38
85
|
const MCP_CONFIG_PATHS = [
|
|
@@ -60,10 +107,12 @@ function writeMcpConfig(dir, configPath, config) {
|
|
|
60
107
|
|
|
61
108
|
function installMcp(config, mcpTool) {
|
|
62
109
|
if (!config.mcpServers) config.mcpServers = {};
|
|
63
|
-
|
|
110
|
+
const entry = {
|
|
64
111
|
command: mcpTool.command,
|
|
65
112
|
args: mcpTool.args,
|
|
66
113
|
};
|
|
114
|
+
if (mcpTool.env) entry.env = mcpTool.env;
|
|
115
|
+
config.mcpServers[mcpTool.id] = entry;
|
|
67
116
|
return config;
|
|
68
117
|
}
|
|
69
118
|
|
|
@@ -81,26 +130,32 @@ export async function cmdSetup(dir, options = {}) {
|
|
|
81
130
|
return existsSync(join(dir, path));
|
|
82
131
|
});
|
|
83
132
|
|
|
84
|
-
|
|
85
|
-
if (json) {
|
|
86
|
-
console.log(JSON.stringify({ installed: [], message: '未检测到 AI 工具配置文件,请先运行 sillyspec init' }));
|
|
87
|
-
} else {
|
|
88
|
-
console.log(chalk.yellow('⚠️ 未检测到 AI 工具配置文件(.claude/mcp.json 或 .cursor/mcp.json)'));
|
|
89
|
-
console.log(chalk.dim(' 请先运行 sillyspec init 初始化项目'));
|
|
90
|
-
}
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// --list 模式:只查看状态
|
|
133
|
+
// --list 模式:只查看状态(不依赖 AI 工具配置)
|
|
95
134
|
if (options.list) {
|
|
96
135
|
const results = {};
|
|
136
|
+
|
|
137
|
+
// MCP 状态
|
|
97
138
|
for (const { tool, path } of availableTools) {
|
|
98
139
|
const config = readMcpConfig(dir, path);
|
|
99
|
-
const
|
|
140
|
+
const mcpStatus = {};
|
|
100
141
|
for (const mcp of MCP_TOOLS) {
|
|
101
|
-
|
|
142
|
+
mcpStatus[mcp.id] = hasMcpInstalled(config, mcp.id);
|
|
143
|
+
}
|
|
144
|
+
for (const db of DB_MCP_TOOLS) {
|
|
145
|
+
mcpStatus[db.id] = hasMcpInstalled(config, db.id);
|
|
146
|
+
}
|
|
147
|
+
results[tool] = { configPath: path, mcp: mcpStatus };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 全局工具状态
|
|
151
|
+
results['全局工具'] = {};
|
|
152
|
+
for (const g of GLOBAL_TOOLS) {
|
|
153
|
+
try {
|
|
154
|
+
execSync(g.checkCommand, { stdio: 'pipe', encoding: 'utf8' });
|
|
155
|
+
results['全局工具'][g.id] = true;
|
|
156
|
+
} catch {
|
|
157
|
+
results['全局工具'][g.id] = false;
|
|
102
158
|
}
|
|
103
|
-
results[tool] = { configPath: path, mcp: installed };
|
|
104
159
|
}
|
|
105
160
|
|
|
106
161
|
if (json) {
|
|
@@ -108,10 +163,22 @@ export async function cmdSetup(dir, options = {}) {
|
|
|
108
163
|
} else {
|
|
109
164
|
console.log('');
|
|
110
165
|
for (const [tool, data] of Object.entries(results)) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
166
|
+
if (data.mcp) {
|
|
167
|
+
console.log(chalk.bold(`📋 ${tool} (${data.configPath})`));
|
|
168
|
+
for (const mcp of MCP_TOOLS) {
|
|
169
|
+
const status = data.mcp[mcp.id] ? chalk.green('✅') : chalk.gray('⬜');
|
|
170
|
+
console.log(` ${status} ${mcp.name} — ${mcp.description}`);
|
|
171
|
+
}
|
|
172
|
+
for (const db of DB_MCP_TOOLS) {
|
|
173
|
+
const status = data.mcp[db.id] ? chalk.green('✅') : chalk.gray('⬜');
|
|
174
|
+
console.log(` ${status} ${db.name} — ${db.description}`);
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
console.log(chalk.bold(`🛠️ ${tool}`));
|
|
178
|
+
for (const g of GLOBAL_TOOLS) {
|
|
179
|
+
const status = data[g.id] ? chalk.green('✅') : chalk.gray('⬜');
|
|
180
|
+
console.log(` ${status} ${g.name} — ${g.description}`);
|
|
181
|
+
}
|
|
115
182
|
}
|
|
116
183
|
console.log('');
|
|
117
184
|
}
|
|
@@ -119,7 +186,7 @@ export async function cmdSetup(dir, options = {}) {
|
|
|
119
186
|
return;
|
|
120
187
|
}
|
|
121
188
|
|
|
122
|
-
//
|
|
189
|
+
// 非交互模式(或没有 AI 工具但有全局工具要装)
|
|
123
190
|
if (!process.stdin.isTTY) {
|
|
124
191
|
if (json) {
|
|
125
192
|
console.log(JSON.stringify({ message: '交互模式需要 TTY,请运行 sillyspec setup' }));
|
|
@@ -132,13 +199,20 @@ export async function cmdSetup(dir, options = {}) {
|
|
|
132
199
|
// ── 交互式安装 ──
|
|
133
200
|
|
|
134
201
|
console.log('');
|
|
135
|
-
console.log(chalk.cyan('🔧 SillySpec Setup —
|
|
202
|
+
console.log(chalk.cyan('🔧 SillySpec Setup — 增强工具安装'));
|
|
136
203
|
console.log('');
|
|
137
|
-
|
|
204
|
+
|
|
205
|
+
if (availableTools.length === 0) {
|
|
206
|
+
console.log(chalk.dim(' 未检测到 AI 工具配置文件,MCP 工具将跳过。'));
|
|
207
|
+
console.log(chalk.dim(' 请先运行 sillyspec init 初始化项目。'));
|
|
208
|
+
console.log('');
|
|
209
|
+
}
|
|
210
|
+
|
|
138
211
|
console.log(' 选择要安装的工具(已安装的会跳过):');
|
|
139
212
|
console.log('');
|
|
140
213
|
|
|
141
|
-
//
|
|
214
|
+
// ── MCP 工具选择 ──
|
|
215
|
+
|
|
142
216
|
const installedSet = new Set();
|
|
143
217
|
for (const { path } of availableTools) {
|
|
144
218
|
const config = readMcpConfig(dir, path);
|
|
@@ -147,20 +221,61 @@ export async function cmdSetup(dir, options = {}) {
|
|
|
147
221
|
}
|
|
148
222
|
}
|
|
149
223
|
|
|
150
|
-
const
|
|
224
|
+
const mcpChoices = MCP_TOOLS.filter(m => !installedSet.has(m.id)).map(m => ({
|
|
151
225
|
name: `${m.name} — ${m.description}`,
|
|
152
|
-
value: m.id
|
|
226
|
+
value: `mcp:${m.id}`,
|
|
227
|
+
checked: false,
|
|
228
|
+
}));
|
|
229
|
+
|
|
230
|
+
// ── 全局工具选择 ──
|
|
231
|
+
|
|
232
|
+
const globalInstalled = new Set();
|
|
233
|
+
for (const tool of GLOBAL_TOOLS) {
|
|
234
|
+
try {
|
|
235
|
+
execSync(tool.checkCommand, { stdio: 'pipe', encoding: 'utf8' });
|
|
236
|
+
globalInstalled.add(tool.id);
|
|
237
|
+
} catch {}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const globalChoices = GLOBAL_TOOLS.filter(t => !globalInstalled.has(t.id)).map(t => ({
|
|
241
|
+
name: `${t.name} — ${t.description}(全局安装)`,
|
|
242
|
+
value: `global:${t.id}`,
|
|
153
243
|
checked: false,
|
|
154
244
|
}));
|
|
155
245
|
|
|
156
|
-
|
|
157
|
-
|
|
246
|
+
// ── 数据库 MCP 选择 ──
|
|
247
|
+
|
|
248
|
+
const dbInstalled = new Set();
|
|
249
|
+
for (const { path } of availableTools) {
|
|
250
|
+
const config = readMcpConfig(dir, path);
|
|
251
|
+
for (const db of DB_MCP_TOOLS) {
|
|
252
|
+
if (hasMcpInstalled(config, db.id)) dbInstalled.add(db.id);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const dbChoices = DB_MCP_TOOLS.filter(d => !dbInstalled.has(d.id)).map(d => ({
|
|
257
|
+
name: `${d.name} — ${d.description}(需要连接信息)`,
|
|
258
|
+
value: `db:${d.id}`,
|
|
259
|
+
checked: false,
|
|
260
|
+
}));
|
|
261
|
+
|
|
262
|
+
const allChoices = [
|
|
263
|
+
...mcpChoices.length > 0 ? [{ name: chalk.bold('── MCP 工具(AI 能力增强)──'), value: '_mcp_header', disabled: true }] : [],
|
|
264
|
+
...mcpChoices,
|
|
265
|
+
...dbChoices.length > 0 ? [{ name: chalk.bold('── 数据库 MCP ──'), value: '_db_header', disabled: true }] : [],
|
|
266
|
+
...dbChoices,
|
|
267
|
+
...globalChoices.length > 0 ? [{ name: chalk.bold('── 全局工具 ──'), value: '_global_header', disabled: true }] : [],
|
|
268
|
+
...globalChoices,
|
|
269
|
+
];
|
|
270
|
+
|
|
271
|
+
if (allChoices.length === 0) {
|
|
272
|
+
console.log(chalk.green(' ✅ 所有推荐工具已安装!'));
|
|
158
273
|
return;
|
|
159
274
|
}
|
|
160
275
|
|
|
161
276
|
const selected = await checkbox({
|
|
162
|
-
message: '
|
|
163
|
-
choices,
|
|
277
|
+
message: '选择要安装的工具',
|
|
278
|
+
choices: allChoices,
|
|
164
279
|
});
|
|
165
280
|
|
|
166
281
|
if (selected.length === 0) {
|
|
@@ -168,47 +283,100 @@ export async function cmdSetup(dir, options = {}) {
|
|
|
168
283
|
return;
|
|
169
284
|
}
|
|
170
285
|
|
|
171
|
-
const
|
|
286
|
+
const selectedMcp = MCP_TOOLS.filter(m => selected.includes(`mcp:${m.id}`));
|
|
287
|
+
const selectedDb = DB_MCP_TOOLS.filter(d => selected.includes(`db:${d.id}`));
|
|
288
|
+
const selectedGlobal = GLOBAL_TOOLS.filter(t => selected.includes(`global:${t.id}`));
|
|
172
289
|
|
|
173
|
-
//
|
|
174
|
-
const toolChoices = availableTools.map(t => ({
|
|
175
|
-
name: t.tool,
|
|
176
|
-
value: t.key,
|
|
177
|
-
checked: true,
|
|
178
|
-
}));
|
|
290
|
+
// ── 收集数据库连接信息 ──
|
|
179
291
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
292
|
+
if (selectedDb.length > 0) {
|
|
293
|
+
console.log('');
|
|
294
|
+
console.log(chalk.yellow('📡 数据库连接配置'));
|
|
295
|
+
console.log('');
|
|
184
296
|
|
|
185
|
-
|
|
297
|
+
for (const db of selectedDb) {
|
|
298
|
+
console.log(chalk.cyan(` ${db.name}:`));
|
|
299
|
+
const dbWithEnv = { ...db, env: {} };
|
|
300
|
+
for (const [key, placeholder] of Object.entries(db.envTemplate)) {
|
|
301
|
+
const value = await input({
|
|
302
|
+
message: ` ${key}`,
|
|
303
|
+
default: placeholder,
|
|
304
|
+
});
|
|
305
|
+
dbWithEnv.env[key] = value;
|
|
306
|
+
}
|
|
307
|
+
// 用带 env 的版本替换
|
|
308
|
+
const idx = selectedDb.indexOf(db);
|
|
309
|
+
selectedDb[idx] = dbWithEnv;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
186
312
|
|
|
187
|
-
// 安装
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
313
|
+
// ── 安装 MCP 工具 ──
|
|
314
|
+
|
|
315
|
+
const allMcp = [...selectedMcp, ...selectedDb];
|
|
316
|
+
|
|
317
|
+
if (allMcp.length > 0) {
|
|
318
|
+
const toolChoices = availableTools.map(t => ({
|
|
319
|
+
name: t.tool,
|
|
320
|
+
value: t.key,
|
|
321
|
+
checked: true,
|
|
322
|
+
}));
|
|
323
|
+
|
|
324
|
+
const targetTools = await checkbox({
|
|
325
|
+
message: 'MCP 工具安装到哪些 AI 工具?',
|
|
326
|
+
choices: toolChoices,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const targets = availableTools.filter(t => targetTools.includes(t.key));
|
|
192
330
|
|
|
193
|
-
|
|
194
|
-
|
|
331
|
+
console.log('');
|
|
332
|
+
for (const { tool, path } of targets) {
|
|
333
|
+
const spinner = ora(`安装 MCP 到 ${tool}...`).start();
|
|
334
|
+
let config = readMcpConfig(dir, path) || { mcpServers: {} };
|
|
335
|
+
for (const mcp of allMcp) {
|
|
336
|
+
config = installMcp(config, mcp);
|
|
337
|
+
}
|
|
338
|
+
writeMcpConfig(dir, path, config);
|
|
339
|
+
spinner.succeed(`${tool} MCP 完成 (${allMcp.length} 个工具)`);
|
|
195
340
|
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// ── 安装全局工具 ──
|
|
196
344
|
|
|
197
|
-
|
|
198
|
-
|
|
345
|
+
if (selectedGlobal.length > 0) {
|
|
346
|
+
console.log('');
|
|
347
|
+
for (const tool of selectedGlobal) {
|
|
348
|
+
const spinner = ora(`安装 ${tool.name}...`).start();
|
|
349
|
+
try {
|
|
350
|
+
execSync(tool.installCommand, { stdio: 'pipe', encoding: 'utf8', timeout: 120000 });
|
|
351
|
+
spinner.succeed(`${tool.name} 安装完成`);
|
|
352
|
+
} catch (err) {
|
|
353
|
+
spinner.fail(`${tool.name} 安装失败: ${err.message}`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
199
356
|
}
|
|
200
357
|
|
|
201
|
-
// 总结
|
|
358
|
+
// ── 总结 ──
|
|
359
|
+
|
|
202
360
|
console.log('');
|
|
203
361
|
console.log(chalk.green(' ═══════════════════════════════════════'));
|
|
204
|
-
console.log(chalk.green(' ✅
|
|
362
|
+
console.log(chalk.green(' ✅ 工具安装完成!'));
|
|
205
363
|
console.log(chalk.green(' ═══════════════════════════════════════'));
|
|
206
364
|
console.log('');
|
|
207
|
-
for (const mcp of
|
|
365
|
+
for (const mcp of selectedMcp) {
|
|
208
366
|
console.log(` 🔌 ${chalk.cyan(mcp.name)} — ${mcp.description}`);
|
|
209
367
|
console.log(chalk.dim(` ${mcp.url}`));
|
|
210
368
|
}
|
|
369
|
+
for (const db of selectedDb) {
|
|
370
|
+
console.log(` 🗄️ ${chalk.cyan(db.name)} — ${db.description}`);
|
|
371
|
+
console.log(chalk.dim(` ${db.url}`));
|
|
372
|
+
}
|
|
373
|
+
for (const g of selectedGlobal) {
|
|
374
|
+
console.log(` 🛠️ ${chalk.cyan(g.name)} — ${g.description}`);
|
|
375
|
+
console.log(chalk.dim(` ${g.url}`));
|
|
376
|
+
}
|
|
211
377
|
console.log('');
|
|
212
|
-
|
|
378
|
+
if (selectedMcp.length > 0) {
|
|
379
|
+
console.log(chalk.dim(' 重启你的 AI 工具以使 MCP 配置生效。'));
|
|
380
|
+
}
|
|
213
381
|
console.log('');
|
|
214
382
|
}
|
package/templates/brainstorm.md
CHANGED
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
## 状态检查(必须先执行)
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
sillyspec
|
|
18
|
+
cat .sillyspec/STATE.md 2>/dev/null
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
-
|
|
21
|
+
- phase 为 `brainstorm` 或无 STATE.md → ✅ 继续
|
|
22
22
|
- 其他 phase → 提示用户当前阶段,建议先完成
|
|
23
23
|
|
|
24
24
|
## 用户想法
|
|
@@ -167,10 +167,6 @@ git add .sillyspec/changes/<变更名>/MASTER.md
|
|
|
167
167
|
|
|
168
168
|
### Step 8: 用户确认(⛔ 门禁)
|
|
169
169
|
|
|
170
|
-
```bash
|
|
171
|
-
sillyspec status --json
|
|
172
|
-
```
|
|
173
|
-
|
|
174
170
|
展示设计方案,AskUserQuestion:确认 / 需要修改 / 推翻重来。
|
|
175
171
|
|
|
176
172
|
### Step 9: 输出技术方案
|
package/templates/execute.md
CHANGED
|
@@ -54,6 +54,60 @@ cat .sillyspec/knowledge/INDEX.md 2>/dev/null
|
|
|
54
54
|
|
|
55
55
|
子代理遇到不熟悉的库或 API 时,优先使用已配置的 MCP 工具(Context7 等)或 web search 查最新文档,不要凭记忆猜测用法。
|
|
56
56
|
|
|
57
|
+
**编码规范扫描(主代理执行):**
|
|
58
|
+
主代理在 dispatch 子代理前,扫描项目中常见的编码规范配置文件,将关键规则注入子代理 prompt 的「编码规范约束」段。
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# 检测存在的配置文件
|
|
62
|
+
for f in .eslintrc .eslintrc.js .eslintrc.cjs .eslintrc.json .eslintrc.yml \
|
|
63
|
+
.prettierrc .prettierrc.js .prettierrc.json .prettierrc.yml \
|
|
64
|
+
tsconfig.json tsconfig.base.json \
|
|
65
|
+
.editorconfig \
|
|
66
|
+
.tailwind.config.js .tailwind.config.ts \
|
|
67
|
+
.stylelintrc .stylelintrc.js .stylelintrc.json \
|
|
68
|
+
CONTRIBUTING.md CODE_STYLE.md; do
|
|
69
|
+
[ -f "$f" ] && echo "=== $f ===" && cat "$f"
|
|
70
|
+
done
|
|
71
|
+
# 也检查 package.json 中的 lint/format 脚本
|
|
72
|
+
cat package.json 2>/dev/null | grep -A5 '"lint\|"format\|"typecheck\|"type-check'
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
扫描后,主代理根据检测结果生成**编码规范摘要**(不是原文粘贴,是提炼关键约束),格式如下。如果某个类别未检测到对应配置文件,则省略该段:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
## 编码规范约束(自动扫描)
|
|
79
|
+
|
|
80
|
+
### ESLint
|
|
81
|
+
{提取的关键规则,如:禁止 var、要求分号、禁止未使用变量、特定插件规则等}
|
|
82
|
+
|
|
83
|
+
### Prettier
|
|
84
|
+
{提取的格式化规则,如:单引号、2空格缩进、无分号、行宽 80 等}
|
|
85
|
+
|
|
86
|
+
### TypeScript
|
|
87
|
+
{从 tsconfig 提取的严格模式设置,如:strict: true、noUncheckedIndexedAccess 等}
|
|
88
|
+
|
|
89
|
+
### Import / 命名约定
|
|
90
|
+
{从 eslint/import 插件或 editorconfig 提取的导入排序、命名风格等}
|
|
91
|
+
|
|
92
|
+
### 框架约定
|
|
93
|
+
{检测到的框架特定约定,如:Next.js App Router、Tailwind 类名风格等}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
将此摘要注入到每个子代理 prompt 的「项目约定」段之后,并追加一条铁律:
|
|
97
|
+
> **10. 遵守编码规范:** 以上「编码规范约束」中的所有规则必须严格遵守。如规则与任务描述冲突,优先遵守规范约束并报告。
|
|
98
|
+
|
|
99
|
+
**MCP 能力检测(主代理执行):**
|
|
100
|
+
```bash
|
|
101
|
+
for cfg in .claude/mcp.json .cursor/mcp.json; do
|
|
102
|
+
[ -f "$cfg" ] && echo "=== $cfg ===" && cat "$cfg"
|
|
103
|
+
done
|
|
104
|
+
```
|
|
105
|
+
根据检测结果,在子代理 prompt 的「文档查询指引」段动态注入:
|
|
106
|
+
- 有 `context7` → `遇到不熟悉的库/API,使用 Context7 MCP(resolve-library-id → query-docs)查询最新文档`
|
|
107
|
+
- 无 `context7` → `遇到不熟悉的库/API,使用 web search 查询最新官方文档`
|
|
108
|
+
- 有数据库 MCP(postgres/sqlite/mysql/redis)→ 在「数据操作」段注入对应 MCP 可用
|
|
109
|
+
- 检测为空 → 不注入额外提示
|
|
110
|
+
|
|
57
111
|
如果 `$ARGUMENTS` 指定范围(如 `wave-1`、`task-3`),只执行对应部分。
|
|
58
112
|
|
|
59
113
|
---
|
|
@@ -91,6 +145,9 @@ cat .sillyspec/knowledge/INDEX.md 2>/dev/null
|
|
|
91
145
|
## 项目约定
|
|
92
146
|
{CONVENTIONS.md 全文}
|
|
93
147
|
|
|
148
|
+
## 编码规范约束(自动扫描)
|
|
149
|
+
{主代理扫描项目配置文件后生成的规范摘要,见上方「编码规范扫描」步骤}
|
|
150
|
+
|
|
94
151
|
## 项目架构
|
|
95
152
|
{ARCHITECTURE.md 全文}
|
|
96
153
|
|
|
@@ -103,6 +160,13 @@ cat .sillyspec/knowledge/INDEX.md 2>/dev/null
|
|
|
103
160
|
## 相关知识(如有)
|
|
104
161
|
{主代理从 knowledge/ 中按任务关键词匹配到的内容,未命中则删除此段}
|
|
105
162
|
|
|
163
|
+
## 文档查询指引
|
|
164
|
+
{主代理根据 MCP 检测结果动态注入:有 Context7 提示用 MCP,无则提示用 web search}
|
|
165
|
+
|
|
166
|
+
## 数据操作
|
|
167
|
+
{主代理根据 MCP 检测结果动态注入:如检测到数据库 MCP,提示可用}
|
|
168
|
+
⛔ 任何改变现有数据的操作(DML: INSERT/UPDATE/DELETE/DML、DDL: ALTER/DROP/TRUNCATE/RENAME,以及所有非 SELECT 的数据库操作)必须暂停并报告给用户确认,不得自动执行。新建表不受此限制。
|
|
169
|
+
|
|
106
170
|
## 铁律(必须遵守)
|
|
107
171
|
1. **先读后写:** 先 cat 要修改的文件和参考文件,确认风格和方法签名后再写
|
|
108
172
|
2. **grep 确认:** 调用已有方法前必须 grep 确认存在,grep 不到 → 报告 BLOCKED
|
|
@@ -113,6 +177,7 @@ cat .sillyspec/knowledge/INDEX.md 2>/dev/null
|
|
|
113
177
|
7. **E2E 任务:** 如果任务描述包含"E2E"或"端到端",先 cat 相关功能代码和页面组件,理解交互逻辑。有测试框架则编写测试文件,无框架则编写 `.sillyspec/changes/<变更名>/e2e-steps.md` 结构化测试步骤(每条包含操作和断言)
|
|
114
178
|
8. **暂存:** 完成后在工作目录执行 git add -A(不要 commit,由用户通过 /sillyspec:commit 统一提交)
|
|
115
179
|
9. **不修改计划外的文件**,如必须修改则在报告中说明
|
|
180
|
+
10. **遵守编码规范:** prompt 中「编码规范约束」段的所有规则必须严格遵守。如规范与任务描述冲突,优先遵守规范并报告
|
|
116
181
|
|
|
117
182
|
## 完成后报告(严格按此格式)
|
|
118
183
|
|
|
@@ -147,6 +212,20 @@ cat .sillyspec/knowledge/INDEX.md 2>/dev/null
|
|
|
147
212
|
|
|
148
213
|
## 完成后
|
|
149
214
|
|
|
215
|
+
**任务勾选自检(必须执行):**
|
|
216
|
+
所有任务完成后,主代理必须执行以下检查:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
cat .sillyspec/changes/*/tasks.md 2>/dev/null
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
逐条验证:
|
|
223
|
+
1. **所有返回 DONE/DONE_WITH_CONCERNS 的任务是否已勾选 `- [x]`?**
|
|
224
|
+
2. **勾选的任务是否都记录了精确到秒的时间戳 `[YYYY-MM-DD HH:MM:SS]`?**
|
|
225
|
+
3. **tasks.md 中是否还有未勾选 `- [ ]` 的已完成任务?**
|
|
226
|
+
|
|
227
|
+
发现遗漏 → 立即补勾选 + 补时间戳,不要等用户提醒。
|
|
228
|
+
|
|
150
229
|
**知识库审阅:** 检查是否有待确认的知识条目:
|
|
151
230
|
```bash
|
|
152
231
|
grep -c '^\### \[待确认\]' .sillyspec/knowledge/uncategorized.md 2>/dev/null
|
package/templates/explore.md
CHANGED
|
@@ -29,10 +29,34 @@ $ARGUMENTS
|
|
|
29
29
|
```bash
|
|
30
30
|
ls .sillyspec/changes/ 2>/dev/null | grep -v archive
|
|
31
31
|
cat .sillyspec/{REQUIREMENTS,ROADMAP}.md 2>/dev/null
|
|
32
|
+
cat .sillyspec/codebase/{CONVENTIONS,ARCHITECTURE}.md 2>/dev/null
|
|
33
|
+
cat .sillyspec/knowledge/INDEX.md 2>/dev/null
|
|
32
34
|
```
|
|
33
35
|
|
|
34
36
|
有进行中变更时读取其 design/tasks,自然引用。发现重要决策时可提议保存(不自动保存)。
|
|
35
37
|
|
|
38
|
+
## MCP 能力(按需使用)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
cat .claude/mcp.json .cursor/mcp.json 2>/dev/null
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- 有 Context7 → 探索时查询最新文档,验证技术方案的可行性
|
|
45
|
+
- 有浏览器 MCP → 可浏览相关网站、查竞品实现
|
|
46
|
+
- 有搜索 MCP → 搜索技术方案、最佳实践
|
|
47
|
+
- 无 MCP → 使用 web search
|
|
48
|
+
|
|
49
|
+
## 话题升级提示
|
|
50
|
+
|
|
51
|
+
探索过程中,当对话达到一定深度时(讨论了 5+ 轮、或涉及具体实现方案、或用户表达"试试看"/"能不能做"/"怎么搞"),主动用 AskUserQuestion 提示用户:
|
|
52
|
+
|
|
53
|
+
1. **🧠 头脑风暴** — `/sillyspec:brainstorm` 深度探索需求和方案
|
|
54
|
+
2. **⚡ 快速执行** — `/sillyspec:quick` 直接动手做
|
|
55
|
+
3. **📋 创建规范** — `/sillyspec:propose` 生成结构化规范
|
|
56
|
+
4. **🔍 继续探索** — 还没聊透,继续
|
|
57
|
+
|
|
58
|
+
不需要每次都提示,只在对话**明显转向执行意图**时触发。纯讨论、提问、查资料时不要打断。
|
|
59
|
+
|
|
36
60
|
## 没有必需的结束
|
|
37
61
|
|
|
38
62
|
探索可以创建变更提案、产出文档、继续探索或结束。
|
package/templates/plan.md
CHANGED
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
## 状态检查(必须先执行)
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
sillyspec
|
|
12
|
+
cat .sillyspec/STATE.md 2>/dev/null
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
-
|
|
16
|
-
- 其他 phase →
|
|
15
|
+
- phase 为 `plan` 或 STATE.md 中下一步为 `/sillyspec:plan` → ✅ 继续
|
|
16
|
+
- 其他 phase → 提示用户当前阶段
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
@@ -123,11 +123,35 @@ cat .claude/mcp.json .cursor/mcp.json 2>/dev/null | grep -i "browser\|chrome\|de
|
|
|
123
123
|
- [ ] 每个 task 有具体文件路径?
|
|
124
124
|
- [ ] 标注了 Wave 和依赖关系?
|
|
125
125
|
- [ ] 涉及 UI 的任务是否有对应的 E2E 测试任务?
|
|
126
|
+
- [ ] **design.md 中的每个功能点是否都在 tasks.md 中有对应任务?**
|
|
126
127
|
|
|
127
|
-
###
|
|
128
|
+
### 6.5 设计完整性对照(必须完成)
|
|
128
129
|
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
逐条检查 design.md 中的功能描述,确保每个功能点都有对应的 task。特别关注:
|
|
131
|
+
|
|
132
|
+
1. **逐功能点扫描:** 将 design.md 中描述的每个功能点(含子功能)列出,与 tasks.md 逐条对照
|
|
133
|
+
2. **前后端覆盖检查:** 涉及前后端协作的功能,确认前端和后端各有独立 task
|
|
134
|
+
3. **遗漏项处理:** 发现未覆盖的功能点 → 追加 task 到对应 Wave,并提示用户确认
|
|
135
|
+
|
|
136
|
+
**执行方式:**
|
|
137
|
+
```
|
|
138
|
+
从 design.md 提取功能点清单:
|
|
139
|
+
功能 A(后端接口)
|
|
140
|
+
功能 B(前端页面)
|
|
141
|
+
功能 C(前后端联动)
|
|
142
|
+
|
|
143
|
+
与 tasks.md 对照:
|
|
144
|
+
✅ 功能 A → task-3
|
|
145
|
+
❌ 功能 B → 无对应 task → 追加
|
|
146
|
+
⚠️ 功能 C → 只有后端 task,缺少前端 task → 追加
|
|
131
147
|
```
|
|
132
148
|
|
|
149
|
+
发现遗漏时用 AskUserQuestion 确认追加内容,用户确认后再写入 tasks.md。
|
|
150
|
+
|
|
151
|
+
### 7. 完成
|
|
152
|
+
|
|
133
153
|
更新 `.sillyspec/STATE.md`:阶段改为 `plan ✅`,下一步 `/sillyspec:execute`。
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
cat .sillyspec/STATE.md 2>/dev/null
|
|
157
|
+
```
|
package/templates/propose.md
CHANGED
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
## 状态检查(必须先执行)
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
sillyspec
|
|
14
|
+
cat .sillyspec/STATE.md 2>/dev/null
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
-
|
|
18
|
-
- 其他 phase →
|
|
17
|
+
- phase 为 `propose` 或 STATE.md 中下一步为 `/sillyspec:propose` → ✅ 继续
|
|
18
|
+
- 其他 phase → 提示用户当前阶段
|
|
19
19
|
|
|
20
20
|
## 变更名称
|
|
21
21
|
$ARGUMENTS
|
|
@@ -70,8 +70,4 @@ bash scripts/validate-proposal.sh .sillyspec/changes/$ARGUMENTS 2>/dev/null
|
|
|
70
70
|
|
|
71
71
|
### 6. 完成
|
|
72
72
|
|
|
73
|
-
```bash
|
|
74
|
-
sillyspec status --json && sillyspec next
|
|
75
|
-
```
|
|
76
|
-
|
|
77
73
|
更新 `.sillyspec/STATE.md`:阶段改为 `propose ✅`,下一步 `/sillyspec:plan`。
|
package/templates/quick.md
CHANGED
|
@@ -21,12 +21,21 @@ $ARGUMENTS
|
|
|
21
21
|
1. **解析参数:** 检查是否携带 `--change <变更名>`,确定记录方式
|
|
22
22
|
2. **理解任务:** 模糊则问一个问题确认
|
|
23
23
|
3. **加载上下文:** `cat .sillyspec/codebase/{CONVENTIONS,ARCHITECTURE}.md 2>/dev/null`
|
|
24
|
+
3b. **编码规范扫描:** 检测项目中的编码规范配置文件(`.eslintrc*`、`.prettierrc*`、`tsconfig.json`、`.editorconfig`、`tailwind.config.*`、`CONTRIBUTING.md`),提取关键规则生成摘要。写作代码时必须严格遵守这些规则(分号/引号/缩进/命名风格等),如不确定优先遵守规范约束。
|
|
24
25
|
4. **知识库查询(强制步骤):**
|
|
25
26
|
```bash
|
|
26
27
|
cat .sillyspec/knowledge/INDEX.md 2>/dev/null
|
|
27
28
|
```
|
|
28
29
|
根据当前任务描述中的关键词匹配 INDEX.md 条目,命中时 `cat` 对应知识文件,将内容纳入后续开发考量。未命中则跳过。
|
|
30
|
+
**MCP 检测:** `cat .claude/mcp.json .cursor/mcp.json 2>/dev/null`,根据检测结果动态利用:
|
|
31
|
+
- 有 Context7 → 查询不熟悉库/API 的最新文档
|
|
32
|
+
- 有浏览器 MCP → 验证页面改动效果
|
|
33
|
+
- 有数据库 MCP → 查询表结构和数据验证(只读)
|
|
34
|
+
- 有搜索 MCP → 搜索最佳实践和解决方案
|
|
35
|
+
- 有其他 MCP → 按任务需要灵活使用
|
|
36
|
+
- 无 MCP → 使用 web search
|
|
29
37
|
5. **先读后写:** 调用已有方法前 `cat` 源文件确认签名,`grep` 确认方法存在
|
|
38
|
+
6. **数据操作安全:** 任何改变现有数据的操作(非 SELECT 的数据库操作)必须暂停并报告给用户确认,不得自动执行。新建表不受此限制
|
|
30
39
|
6. **TDD 执行:**
|
|
31
40
|
```
|
|
32
41
|
🔴 RED → 先写测试,运行确认失败
|