sillyspec 3.7.0 → 3.7.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/package.json +1 -1
- package/src/index.js +11 -483
- package/src/setup.js +234 -66
- package/templates/brainstorm.md +2 -6
- package/templates/execute.md +19 -0
- package/templates/plan.md +6 -6
- package/templates/propose.md +3 -7
- package/templates/quick.md +2 -0
- package/templates/scan.md +17 -5
- 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
|
-
import { join } from 'path';
|
|
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 = [
|
|
@@ -54,16 +101,18 @@ function readMcpConfig(dir, configPath) {
|
|
|
54
101
|
|
|
55
102
|
function writeMcpConfig(dir, configPath, config) {
|
|
56
103
|
const fullPath = join(dir, configPath);
|
|
57
|
-
mkdirSync(
|
|
104
|
+
mkdirSync(dirname(fullPath), { recursive: true });
|
|
58
105
|
writeFileSync(fullPath, JSON.stringify(config, null, 2) + '\n');
|
|
59
106
|
}
|
|
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,18 @@ cat .sillyspec/knowledge/INDEX.md 2>/dev/null
|
|
|
54
54
|
|
|
55
55
|
子代理遇到不熟悉的库或 API 时,优先使用已配置的 MCP 工具(Context7 等)或 web search 查最新文档,不要凭记忆猜测用法。
|
|
56
56
|
|
|
57
|
+
**MCP 能力检测(主代理执行):**
|
|
58
|
+
```bash
|
|
59
|
+
for cfg in .claude/mcp.json .cursor/mcp.json; do
|
|
60
|
+
[ -f "$cfg" ] && echo "=== $cfg ===" && cat "$cfg"
|
|
61
|
+
done
|
|
62
|
+
```
|
|
63
|
+
根据检测结果,在子代理 prompt 的「文档查询指引」段动态注入:
|
|
64
|
+
- 有 `context7` → `遇到不熟悉的库/API,使用 Context7 MCP(resolve-library-id → query-docs)查询最新文档`
|
|
65
|
+
- 无 `context7` → `遇到不熟悉的库/API,使用 web search 查询最新官方文档`
|
|
66
|
+
- 有数据库 MCP(postgres/sqlite/mysql/redis)→ 在「数据操作」段注入对应 MCP 可用
|
|
67
|
+
- 检测为空 → 不注入额外提示
|
|
68
|
+
|
|
57
69
|
如果 `$ARGUMENTS` 指定范围(如 `wave-1`、`task-3`),只执行对应部分。
|
|
58
70
|
|
|
59
71
|
---
|
|
@@ -103,6 +115,13 @@ cat .sillyspec/knowledge/INDEX.md 2>/dev/null
|
|
|
103
115
|
## 相关知识(如有)
|
|
104
116
|
{主代理从 knowledge/ 中按任务关键词匹配到的内容,未命中则删除此段}
|
|
105
117
|
|
|
118
|
+
## 文档查询指引
|
|
119
|
+
{主代理根据 MCP 检测结果动态注入:有 Context7 提示用 MCP,无则提示用 web search}
|
|
120
|
+
|
|
121
|
+
## 数据操作
|
|
122
|
+
{主代理根据 MCP 检测结果动态注入:如检测到数据库 MCP,提示可用}
|
|
123
|
+
⛔ 任何改变现有数据的操作(DML: INSERT/UPDATE/DELETE/DML、DDL: ALTER/DROP/TRUNCATE/RENAME,以及所有非 SELECT 的数据库操作)必须暂停并报告给用户确认,不得自动执行。新建表不受此限制。
|
|
124
|
+
|
|
106
125
|
## 铁律(必须遵守)
|
|
107
126
|
1. **先读后写:** 先 cat 要修改的文件和参考文件,确认风格和方法签名后再写
|
|
108
127
|
2. **grep 确认:** 调用已有方法前必须 grep 确认存在,grep 不到 → 报告 BLOCKED
|
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
|
|
|
@@ -126,8 +126,8 @@ cat .claude/mcp.json .cursor/mcp.json 2>/dev/null | grep -i "browser\|chrome\|de
|
|
|
126
126
|
|
|
127
127
|
### 7. 完成
|
|
128
128
|
|
|
129
|
+
更新 `.sillyspec/STATE.md`:阶段改为 `plan ✅`,下一步 `/sillyspec:execute`。
|
|
130
|
+
|
|
129
131
|
```bash
|
|
130
|
-
|
|
132
|
+
cat .sillyspec/STATE.md 2>/dev/null
|
|
131
133
|
```
|
|
132
|
-
|
|
133
|
-
更新 `.sillyspec/STATE.md`:阶段改为 `plan ✅`,下一步 `/sillyspec:execute`。
|
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
|
@@ -26,7 +26,9 @@ $ARGUMENTS
|
|
|
26
26
|
cat .sillyspec/knowledge/INDEX.md 2>/dev/null
|
|
27
27
|
```
|
|
28
28
|
根据当前任务描述中的关键词匹配 INDEX.md 条目,命中时 `cat` 对应知识文件,将内容纳入后续开发考量。未命中则跳过。
|
|
29
|
+
**MCP 检测:** `cat .claude/mcp.json .cursor/mcp.json 2>/dev/null`,有 Context7 则用 MCP 查文档,无则用 web search。
|
|
29
30
|
5. **先读后写:** 调用已有方法前 `cat` 源文件确认签名,`grep` 确认方法存在
|
|
31
|
+
6. **数据操作安全:** 任何改变现有数据的操作(非 SELECT 的数据库操作)必须暂停并报告给用户确认,不得自动执行。新建表不受此限制
|
|
30
32
|
6. **TDD 执行:**
|
|
31
33
|
```
|
|
32
34
|
🔴 RED → 先写测试,运行确认失败
|
package/templates/scan.md
CHANGED
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
## 流程控制(必须先执行)
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
sillyspec
|
|
14
|
+
cat .sillyspec/STATE.md 2>/dev/null
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
有 STATE.md 且 phase 为 `scan` 或未记录 → 继续。
|
|
18
|
+
其他 phase → STATE.md 中记录的下一步命令为准。
|
|
18
19
|
|
|
19
20
|
---
|
|
20
21
|
|
|
@@ -135,9 +136,20 @@ if [ ! -f ".sillyspec/knowledge/uncategorized.md" ]; then
|
|
|
135
136
|
EOF
|
|
136
137
|
fi
|
|
137
138
|
|
|
138
|
-
#
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
# 更新状态
|
|
140
|
+
cat > .sillyspec/STATE.md << 'EOF'
|
|
141
|
+
# 项目状态
|
|
142
|
+
|
|
143
|
+
## 当前阶段
|
|
144
|
+
- 阶段:scan ✅
|
|
145
|
+
- 下一步:/sillyspec:brainstorm
|
|
146
|
+
|
|
147
|
+
## 关键决策
|
|
148
|
+
- (扫描中发现的技术决策)
|
|
149
|
+
|
|
150
|
+
## 历史记录
|
|
151
|
+
- $(date '+%Y-%m-%d %H:%M:%S') scan 完成
|
|
152
|
+
EOF
|
|
141
153
|
|
|
142
154
|
# 清理
|
|
143
155
|
rm -f .sillyspec/codebase/_env-detect.md
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
## 交互规范
|
|
2
|
-
**当需要用户从多个选项中做出选择时,必须使用 Claude Code 内置的 AskUserQuestion 工具,将选项以参数传入。**
|
|
3
|
-
|
|
4
|
-
## 核心约束(必须遵守)
|
|
5
|
-
- ❌ 未经验证就归档(必须先确认验证通过)
|
|
6
|
-
- ❌ 未勾选的 checkbox 未告知用户就归档
|
|
7
|
-
- ❌ 归档后留下活跃变更的残留状态
|
|
8
|
-
- ❌ 覆盖已存在的归档目录
|
|
9
|
-
|
|
10
|
-
## 变更名称
|
|
11
|
-
$ARGUMENTS
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## 流程
|
|
16
|
-
|
|
17
|
-
### 1. 前置检查(门禁)
|
|
18
|
-
|
|
19
|
-
读取 `.sillyspec/changes/<change-name>/` 下所有必要文件,逐项检查:
|
|
20
|
-
|
|
21
|
-
- [ ] **文件完整性:** 检查 `design.md` 是否存在,缺失则警告
|
|
22
|
-
- [ ] **任务完成度:** 读取 `tasks.md`,统计已完成/未完成任务数。**有未完成的 → 用 AskUserQuestion 询问:**
|
|
23
|
-
- ① 继续归档(未完成任务将被标记完成)
|
|
24
|
-
- ② 取消,回去完成任务
|
|
25
|
-
|
|
26
|
-
> 任一门禁不通过且用户选择取消 → 终止流程。
|
|
27
|
-
|
|
28
|
-
### 2. 展示归档清单
|
|
29
|
-
|
|
30
|
-
展示即将归档的内容摘要:
|
|
31
|
-
- 变更目录名
|
|
32
|
-
- 包含的文件列表
|
|
33
|
-
- 任务完成统计(✅ 已完成 / ⬜ 未完成)
|
|
34
|
-
- 一句话总结本次变更
|
|
35
|
-
|
|
36
|
-
### 3. Spec 沉淀
|
|
37
|
-
|
|
38
|
-
将 `.sillyspec/changes/<change-name>/` 下的设计文档**复制到 `.sillyspec/knowledge/` 主目录**,确保已完成的设计规范可被后续变更参考。如目标已存在同名文件则跳过并提示。
|
|
39
|
-
|
|
40
|
-
### 4. 用户确认
|
|
41
|
-
|
|
42
|
-
用 AskUserQuestion 让用户确认:
|
|
43
|
-
- ① 确认归档
|
|
44
|
-
- ② 取消
|
|
45
|
-
|
|
46
|
-
### 5. 执行归档
|
|
47
|
-
|
|
48
|
-
- 目标路径:`.sillyspec/changes/archive/YYYY-MM-DD-<change-name>/`
|
|
49
|
-
- **检查目标路径是否已存在**,存在则中止并报错,防止覆盖
|
|
50
|
-
- 移动变更目录到归档路径
|
|
51
|
-
|
|
52
|
-
### 6. 归档后更新
|
|
53
|
-
|
|
54
|
-
- **tasks.md:** 确保所有 checkbox 都已勾选 `[x]`
|
|
55
|
-
- **ROADMAP.md**(如存在):标记对应 Phase 已完成
|
|
56
|
-
- **STATE.md:** 清除当前变更信息,历史记录追加归档完成(含精确到秒的时间戳)
|
|
57
|
-
- **Git 提交:** `git add .sillyspec/ && git commit -m "docs: archive sillyspec change <change-name>"`
|
|
58
|
-
|
|
59
|
-
**工作区模式下:** 如果变更属于某个子项目,cd 到子项目目录执行 git commit。工作区根目录无 git 则跳过。
|
|
60
|
-
|
|
61
|
-
### 最后说:
|
|
62
|
-
|
|
63
|
-
> ✅ 变更 `<change-name>` 已归档到 `archive/YYYY-MM-DD-<change-name>/`。继续:`/sillyspec:brainstorm "新想法"`
|