sillyspec 3.18.1 → 3.18.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.
@@ -3,41 +3,42 @@ name: sillyspec:brainstorm
3
3
  description: 用于正式开始开发前的需求澄清和技术方案设计。适合用户提出新功能、新模块、架构调整、复杂改造,或说"先做需求分析、输出技术方案、创建变更前先梳理、帮我设计下"。产出结构化方案,但不直接写代码。
4
4
  ---
5
5
 
6
- # SillySpec Brainstorm — 需求探索
6
+ ## 多变更说明
7
7
 
8
- ## 用法
9
- 用户触发此 skill 时,使用 `sillyspec run brainstorm` 逐步执行需求探索。
8
+ 如果项目有多个活跃变更(`.sillyspec/changes/` 下有多个目录),所有 `sillyspec run` 命令需要加 `--change <变更名>`。只有一个变更时可省略(CLI 自动检测)。
10
9
 
11
- ## 执行步骤
10
+ ## 执行
12
11
 
13
- 1. 确定变更名(格式:`YYYY-MM-DD-<简短描述>`,如 `2026-05-28-agent-log-streaming`)
14
- 2. 运行 `sillyspec run brainstorm --change <变更名>` 获取当前步骤指令
15
- 3. 按步骤指令执行(对话、分析需求、设计方案等)
16
- 4. 完成步骤后运行 `sillyspec run brainstorm --done --change <变更名> --output "步骤摘要"`
17
- 5. CLI 会自动输出下一步的指令,重复 3-4 直到阶段完成
12
+ **你必须使用 exec 工具(shell)执行以下命令,不要自己编造流程:**
18
13
 
19
- ## 示例
14
+ 1. 运行 `sillyspec run brainstorm` — 读取输出的步骤 prompt
15
+ 2. 按照输出的 prompt **严格执行**,不要跳过或自行添加步骤
16
+ 3. 步骤完成后,运行 `sillyspec run brainstorm --done --output "你的摘要"`
17
+ 4. 重复 2-3 直到阶段完成
18
+ 5. **禁止**在没有运行 CLI 的情况下自行决定流程
20
19
 
21
- ```bash
22
- # 首次启动(推荐指定变更名)
23
- sillyspec run brainstorm --change 2026-05-28-agent-log-streaming
20
+ ## 特殊步骤:requiresWait
24
21
 
25
- # 不指定变更名时自动生成(格式:YYYY-MM-DD-new-change)
26
- sillyspec run brainstorm
22
+ 某些步骤(如"对话式探索")需要等待用户输入。AI agent 可以:
27
23
 
28
- # 完成当前步骤
29
- sillyspec run brainstorm --done --change 2026-05-28-agent-log-streaming --output "需求已澄清"
24
+ - **方式一(推荐)**:通过自己的对话工具与用户交互,完成后直接 `--done --answer "用户回答"` 一步完成
25
+ - **方式二**:先 `--wait` 记录等待状态,再 `--continue --answer "用户回答"`,最后 `--done`
30
26
 
31
- # 查看进度
32
- sillyspec run brainstorm --status --change 2026-05-28-agent-log-streaming
27
+ ```bash
28
+ # 一步完成 wait + done(AI agent 已自行与用户交互)
29
+ sillyspec run brainstorm --done --change <变更名> --answer "信息够了,进入方案讨论" --output "需求已澄清"
33
30
 
34
- # 重置阶段
35
- sillyspec run brainstorm --reset --change 2026-05-28-agent-log-streaming
31
+ # 分步完成
32
+ sillyspec run brainstorm --wait --change <变更名> --reason "等待用户回答" --output "探索问题"
33
+ sillyspec run brainstorm --continue --answer "用户回答" --change <变更名>
34
+ sillyspec run brainstorm --done --change <变更名> --output "需求已澄清"
36
35
  ```
37
36
 
38
37
  ## 注意
39
- - 推荐指定 `--change <变更名>`(格式:`YYYY-MM-DD-<简短描述>`),不指定时自动生成 `YYYY-MM-DD-new-change`
38
+ - 推荐指定 `--change <变更名>`(格式:`YYYY-MM-DD-<简短描述>`),不指定时自动生成
40
39
  - 步骤 prompt 由 CLI 管理,不需要手动读取
41
40
  - 依赖 scan 阶段完成,CLI 会自动提醒
42
- - brainstorm 阶段末步会自动生成四件套(proposal.md + design.md + requirements.md + tasks.md)
43
41
  - brainstorm 完成后,运行 `sillyspec run plan --change <变更名>` 进入实现计划
42
+
43
+ ## 用户指令
44
+ $ARGUMENTS
@@ -11,11 +11,18 @@ description: 用于按 plan 执行代码实现。适合用户说"开始写代码
11
11
 
12
12
  **你必须使用 exec 工具(shell)执行以下命令,不要自己编造流程:**
13
13
 
14
- 1. 运行 `sillyspec run execute` — 读取输出的步骤 prompt
14
+ 1. 运行 `sillyspec run execute` — CLI 会自动创建 worktree 隔离环境,然后输出步骤 prompt
15
15
  2. 按照输出的 prompt **严格执行**,不要跳过或自行添加步骤
16
16
  3. 步骤完成后,运行 `sillyspec run execute --done --output "你的摘要"`
17
17
  4. 重复 2-3 直到阶段完成
18
18
  5. **禁止**在没有运行 CLI 的情况下自行决定流程
19
19
 
20
+ ## Worktree 隔离
21
+
22
+ - CLI 启动 execute 阶段时**自动创建 git worktree**,AI agent 不需要手动创建
23
+ - Worktree 路径在 Step 3(确认 worktree 路径)中输出,后续子代理的 cwd 必须设为该路径
24
+ - **禁止跳过 worktree 或在主仓库直接写代码**
25
+ - 如果 worktree 创建失败,CLI 会报错并退出,需要排查后再重试
26
+
20
27
  ## 用户指令
21
28
  $ARGUMENTS
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sillyspec",
3
- "version": "3.18.1",
3
+ "version": "3.18.2",
4
4
  "description": "SillySpec CLI — 流程状态机,让 AI 严格按步骤来",
5
5
  "icon": "logo.jpg",
6
6
  "homepage": "https://sillyspec.ppdmq.top/",
package/src/run.js CHANGED
@@ -1253,7 +1253,8 @@ export async function runCommand(args, cwd, specDir = null) {
1253
1253
 
1254
1254
  // --done
1255
1255
  if (isDone) {
1256
- return await completeStep(pm, progress, stageName, cwd, outputText, inputText, { confirm: isConfirm, changeName: effectiveChange, nonInteractive: isNonInteractive && !isInteractive, platformOpts, confirmMode })
1256
+ const doneAnswer = getFlagValue('--answer')
1257
+ return await completeStep(pm, progress, stageName, cwd, outputText, inputText, { confirm: isConfirm, changeName: effectiveChange, nonInteractive: isNonInteractive && !isInteractive, platformOpts, confirmMode, doneAnswer })
1257
1258
  }
1258
1259
 
1259
1260
  // 默认:输出当前步骤
@@ -1301,6 +1302,26 @@ async function runStage(pm, progress, stageName, cwd, changeName, skipApproval =
1301
1302
  }
1302
1303
  }
1303
1304
 
1305
+ // execute 阶段:CLI 自动创建 worktree(不等 AI agent)
1306
+ if (stageName === 'execute' && changeName) {
1307
+ const effectiveChange = changeName
1308
+ const { WorktreeManager } = await import('./worktree.js')
1309
+ const wm = new WorktreeManager({ cwd })
1310
+ const existingMeta = wm.getMeta(effectiveChange)
1311
+ if (existingMeta) {
1312
+ console.log(`🔗 worktree 已存在: ${existingMeta.worktreePath} (${existingMeta.mode})`)
1313
+ } else {
1314
+ try {
1315
+ const result = wm.create(effectiveChange)
1316
+ console.log(`🔗 worktree 已创建: ${result.worktreePath} (分支: ${result.branch}, 模式: ${result.mode})`)
1317
+ } catch (e) {
1318
+ console.error(`❌ worktree 创建失败: ${e.message}`)
1319
+ console.error(` 继续执行前请解决上述问题,或使用 --no-worktree 跳过。`)
1320
+ process.exit(1)
1321
+ }
1322
+ }
1323
+ }
1324
+
1304
1325
  // 自动探测 currentChange
1305
1326
  if (autoDetectChange(progress, cwd)) {
1306
1327
  progress.lastActive = new Date().toLocaleString('zh-CN', { hour12: false })
@@ -1832,14 +1853,24 @@ async function completeStep(pm, progress, stageName, cwd, outputText, inputText
1832
1853
  const currentStepDef = defStepsForCurrent?.[currentIdx] || {}
1833
1854
  const currentStep = steps[currentIdx]
1834
1855
  if (currentStepDef.requiresWait === true && !currentStep.waitAnswer) {
1835
- console.error(`❌ Step "${currentStep.name}" 必须先等待用户输入,不能直接 --done。`)
1836
- console.error(` 原因:${currentStepDef.waitReason || '该步骤需要人工确认/回答'}`)
1837
- if (currentStepDef.waitOptions) {
1838
- console.error(` 选项:${currentStepDef.waitOptions.join(', ')}`)
1856
+ // 检查 --done 是否带了 --answer:如果是,自动补全 waitAnswer 状态,一步完成
1857
+ const doneAnswer = typeof options !== 'undefined' && options.doneAnswer ? options.doneAnswer : null
1858
+ if (doneAnswer) {
1859
+ currentStep.status = 'waiting'
1860
+ currentStep.waitAnswer = doneAnswer
1861
+ currentStep.waitReason = currentStepDef.waitReason || '等待用户输入'
1862
+ console.log(`⚠️ Step "${currentStep.name}" 需要 wait,但 --done 带了 --answer,自动补全 wait 状态。`)
1863
+ } else {
1864
+ console.error(`❌ Step "${currentStep.name}" 必须先等待用户输入,不能直接 --done。`)
1865
+ console.error(` 原因:${currentStepDef.waitReason || '该步骤需要人工确认/回答'}`)
1866
+ if (currentStepDef.waitOptions) {
1867
+ console.error(` 选项:${currentStepDef.waitOptions.join(', ')}`)
1868
+ }
1869
+ console.error(` 请先执行:`)
1870
+ console.error(` sillyspec run ${stageName} --wait --reason "${currentStepDef.waitReason || '等待用户输入'}" --options "${(currentStepDef.waitOptions || ['确认']).join(',')}"${changeName ? ` --change ${changeName}` : ''} --output "你的问题/方案摘要"`)
1871
+ console.error(` 或使用 --done --answer "用户回答" 一步完成 wait + done`)
1872
+ process.exit(1)
1839
1873
  }
1840
- console.error(` 请先执行:`)
1841
- console.error(` sillyspec run ${stageName} --wait --reason "${currentStepDef.waitReason || '等待用户输入'}" --options "${(currentStepDef.waitOptions || ['确认']).join(',')}"${changeName ? ` --change ${changeName}` : ''} --output "你的问题/方案摘要"`)
1842
- process.exit(1)
1843
1874
  }
1844
1875
 
1845
1876
  steps[currentIdx].status = 'completed'
@@ -2234,10 +2265,16 @@ async function completeStep(pm, progress, stageName, cwd, outputText, inputText
2234
2265
  }
2235
2266
  }
2236
2267
 
2268
+ // 防御性守卫变量:确认所有步骤确实标记为 completed
2269
+ const actualCompleted = steps.filter(s => s.status === 'completed').length
2270
+ const actualTotal = steps.length
2271
+
2237
2272
  validateMetadata(cwd, stageName, specBase)
2238
2273
 
2239
- // 验证关键文件是否在正确的变更目录下
2240
- validateFileLocations(cwd, stageName, progress, changeName, specBase)
2274
+ // 验证关键文件是否在正确的变更目录下(仅当所有步骤确实完成时才校验)
2275
+ if (actualCompleted === actualTotal && actualTotal > 0) {
2276
+ validateFileLocations(cwd, stageName, progress, changeName, specBase)
2277
+ }
2241
2278
 
2242
2279
  // 辅助阶段完成后重置步骤
2243
2280
  const stageDef = stageRegistry[stageName]
@@ -2281,24 +2318,30 @@ async function completeStep(pm, progress, stageName, cwd, outputText, inputText
2281
2318
  } else {
2282
2319
  console.log(`\n下一步由你决定:sillyspec run <stage>(brainstorm/plan/execute/verify/archive 等)`)
2283
2320
  }
2284
- return { stageCompleted: true, currentIdx, nextPendingIdx: -1 }
2285
- }
2286
2321
 
2287
- // 阶段完成校验
2288
- const projectName = progress.project || basename(cwd)
2289
- const contractResult = runValidators(stageName, cwd, changeName, { projectName, specRoot: platformOpts?.specRoot })
2290
- if (contractResult.errors.length > 0) {
2291
- console.error(`\n❌ 阶段 ${stageName} 校验失败:`)
2292
- for (const err of contractResult.errors) {
2293
- console.error(` - ${err}`)
2294
- }
2295
- console.error(`\n 提示:修复缺失产物后重新运行此步骤,或使用 --skip-approval 跳过校验`)
2296
- }
2297
- if (contractResult.warnings.length > 0) {
2298
- console.warn(`\n⚠️ 阶段 ${stageName} 校验警告:`)
2299
- for (const w of contractResult.warnings) {
2300
- console.warn(` - ${w}`)
2322
+ // 阶段完成校验 — 防御性守卫:仅当所有步骤确实标记为 completed 时才跑 validator
2323
+ if (actualCompleted === actualTotal && actualTotal > 0) {
2324
+ const projectName = progress.project || basename(cwd)
2325
+ const contractResult = runValidators(stageName, cwd, changeName, { projectName, specRoot: platformOpts?.specRoot })
2326
+ if (contractResult.errors.length > 0) {
2327
+ console.error(`\n❌ 阶段 ${stageName} 校验失败:`)
2328
+ for (const err of contractResult.errors) {
2329
+ console.error(` - ${err}`)
2330
+ }
2331
+ console.error(`\n 提示:修复缺失产物后重新运行此步骤,或使用 --skip-approval 跳过校验`)
2332
+ }
2333
+ if (contractResult.warnings.length > 0) {
2334
+ console.warn(`\n⚠️ 阶段 ${stageName} 校验警告:`)
2335
+ for (const w of contractResult.warnings) {
2336
+ console.warn(` - ${w}`)
2337
+ }
2338
+ }
2339
+ } else if (actualCompleted < actualTotal) {
2340
+ // 实际步骤未全部完成,跳过 validator(状态可能不同步)
2341
+ console.log(`\n⚠️ 阶段校验跳过:${actualTotal} 步中仅 ${actualCompleted} 步标记为已完成,可能存在状态不同步。如确认阶段已完成,请运行 --status 确认。`)
2301
2342
  }
2343
+
2344
+ return { stageCompleted: true, currentIdx, nextPendingIdx: -1 }
2302
2345
  }
2303
2346
 
2304
2347
  progress.lastActive = new Date().toLocaleString('zh-CN',{hour12:false})
@@ -520,6 +520,11 @@ export function checkTransition(fromStage, toStage) {
520
520
  return { allowed: true }
521
521
  }
522
522
 
523
+ // 同阶段内重复运行:允许(继续执行当前阶段的下一步)
524
+ if (fromStage === toStage) {
525
+ return { allowed: true }
526
+ }
527
+
523
528
  // archive 特殊处理:从 verify 来的允许,从其他主流程阶段来的需要校验
524
529
  if (toStage === 'archive') {
525
530
  if (fromStage === 'verify') {
@@ -52,27 +52,25 @@ const fixedPrefix = [
52
52
  optional: false
53
53
  },
54
54
  {
55
- name: '创建 worktree',
56
- prompt: `为本次执行创建隔离的 git worktree。
55
+ name: '确认 worktree 路径',
56
+ prompt: `确认当前 worktree 状态,提取隔离路径。
57
57
 
58
58
  ### 操作
59
- 1. 运行 \`sillyspec worktree create <change-name>\`
60
- 2. 记录输出的 worktree 路径
61
- 3. 后续所有子代理的 cwd 设为该 worktree 路径
62
- 4. 如果创建失败 → 报错并停止(不要在无隔离状态下继续)
59
+ 1. 运行 \`sillyspec worktree meta <change-name>\` 读取 meta.json
60
+ 2. 从输出中提取 worktreePath、branch、mode 字段
61
+ 3. 确认 worktree 目录存在(如果是 worktree/native-worktree 模式)
63
62
 
64
- ### 降级模式
65
- CLI 可能自动降级(sandbox 限制、已在 linked worktree 中):
66
- - \`mode: native-worktree\` 已在 linked worktree,直接复用
67
- - \`mode: in-place-fallback\` — git worktree add 失败,降级为 in-place + baseline protection
68
- - 这两种模式都会输出 worktree 路径和分支名,正常继续即可
63
+ ### 铁律
64
+ - **worktree 已由 CLI execute 阶段启动时自动创建,不要自行创建或跳过**
65
+ - **后续所有子代理的 cwd 必须设为该 worktree 路径**
66
+ - 如果 meta.json 不存在(说明创建失败),停止并报错
69
67
 
70
68
  ### 输出
71
- worktree 路径 + 分支名 + 模式(如果有)
69
+ worktree 路径 + 分支名 + 模式
72
70
 
73
71
  ### 完成后执行
74
- sillyspec run execute --done --output "worktree 路径 + 分支名"`,
75
- outputHint: 'worktree 路径 + 分支名',
72
+ sillyspec run execute --done --output "worktree 路径 + 分支名 + 模式"`,
73
+ outputHint: 'worktree 路径 + 分支名 + 模式',
76
74
  optional: false
77
75
  },
78
76
  {