sillyspec 3.7.1 → 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/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: ['-y', '@nicholasxjy/chrome-devtools-mcp'],
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
- config.mcpServers[mcpTool.id] = {
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
- if (availableTools.length === 0) {
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 installed = {};
140
+ const mcpStatus = {};
100
141
  for (const mcp of MCP_TOOLS) {
101
- installed[mcp.id] = hasMcpInstalled(config, mcp.id);
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
- console.log(chalk.bold(`📋 ${tool} (${data.configPath})`));
112
- for (const mcp of MCP_TOOLS) {
113
- const status = data.mcp[mcp.id] ? chalk.green('✅') : chalk.gray('⬜');
114
- console.log(` ${status} ${mcp.name} ${mcp.description}`);
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 — 安装推荐 MCP 工具'));
202
+ console.log(chalk.cyan('🔧 SillySpec Setup — 增强工具安装'));
136
203
  console.log('');
137
- console.log(' MCP 工具让 AI 能力增强:查文档、搜代码、控制浏览器。');
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 choices = MCP_TOOLS.filter(m => !installedSet.has(m.id)).map(m => ({
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
- if (choices.length === 0) {
157
- console.log(chalk.green(' ✅ 所有推荐的 MCP 工具已安装!'));
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: '选择要安装的 MCP 工具',
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 selectedTools = MCP_TOOLS.filter(m => selected.includes(m.id));
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
- // 选择安装到哪些 AI 工具
174
- const toolChoices = availableTools.map(t => ({
175
- name: t.tool,
176
- value: t.key,
177
- checked: true,
178
- }));
290
+ // ── 收集数据库连接信息 ──
179
291
 
180
- const targetTools = await checkbox({
181
- message: '安装到哪些 AI 工具?',
182
- choices: toolChoices,
183
- });
292
+ if (selectedDb.length > 0) {
293
+ console.log('');
294
+ console.log(chalk.yellow('📡 数据库连接配置'));
295
+ console.log('');
184
296
 
185
- const targets = availableTools.filter(t => targetTools.includes(t.key));
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
- console.log('');
189
- for (const { tool, path } of targets) {
190
- const spinner = ora(`安装到 ${tool}...`).start();
191
- let config = readMcpConfig(dir, path) || { mcpServers: {} };
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
- for (const mcp of selectedTools) {
194
- config = installMcp(config, mcp);
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
- writeMcpConfig(dir, path, config);
198
- spinner.succeed(`${tool} 完成 (${selected.length} 个工具)`);
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(' ✅ MCP 工具安装完成!'));
362
+ console.log(chalk.green(' ✅ 工具安装完成!'));
205
363
  console.log(chalk.green(' ═══════════════════════════════════════'));
206
364
  console.log('');
207
- for (const mcp of selectedTools) {
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
- console.log(chalk.dim(' 重启你的 AI 工具以使 MCP 配置生效。'));
378
+ if (selectedMcp.length > 0) {
379
+ console.log(chalk.dim(' 重启你的 AI 工具以使 MCP 配置生效。'));
380
+ }
213
381
  console.log('');
214
382
  }
@@ -15,10 +15,10 @@
15
15
  ## 状态检查(必须先执行)
16
16
 
17
17
  ```bash
18
- sillyspec status --json
18
+ cat .sillyspec/STATE.md 2>/dev/null
19
19
  ```
20
20
 
21
- - `phase: "brainstorm"` → ✅ 继续
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: 输出技术方案
@@ -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 status --json
12
+ cat .sillyspec/STATE.md 2>/dev/null
13
13
  ```
14
14
 
15
- - `phase: "plan"` → ✅ 继续
16
- - 其他 phase → 提示 `sillyspec next`
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
- sillyspec status --json && sillyspec next
132
+ cat .sillyspec/STATE.md 2>/dev/null
131
133
  ```
132
-
133
- 更新 `.sillyspec/STATE.md`:阶段改为 `plan ✅`,下一步 `/sillyspec:execute`。
@@ -11,11 +11,11 @@
11
11
  ## 状态检查(必须先执行)
12
12
 
13
13
  ```bash
14
- sillyspec status --json
14
+ cat .sillyspec/STATE.md 2>/dev/null
15
15
  ```
16
16
 
17
- - `phase: "propose"` → ✅ 继续
18
- - 其他 phase → 提示 `sillyspec next`
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`。
@@ -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 status --json
14
+ cat .sillyspec/STATE.md 2>/dev/null
15
15
  ```
16
16
 
17
- `init` phase以 CLI 返回为准决定下一步。
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
- # 验证 CLI
139
- sillyspec status --json # 应返回 phase: "brainstorm"
140
- sillyspec next # 推荐给用户
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 "新想法"`