sillyspec 3.8.5 → 3.8.6
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 +0 -6
- package/docs/.vitepress/config.mts +45 -0
- package/docs/.vitepress/dist/404.html +25 -0
- package/docs/.vitepress/dist/assets/app.YytxICdd.js +1 -0
- package/docs/.vitepress/dist/assets/chunks/framework.Czhw_PXq.js +19 -0
- package/docs/.vitepress/dist/assets/chunks/theme.DusTRZQk.js +1 -0
- package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.js +1 -0
- package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.lean.js +1 -0
- package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
- package/docs/.vitepress/dist/assets/sillyspec_commands.md.CXFFsj08.js +15 -0
- package/docs/.vitepress/dist/assets/sillyspec_commands.md.CXFFsj08.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.js +4 -0
- package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.js +4 -0
- package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.js +5 -0
- package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.js +28 -0
- package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.js +30 -0
- package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.lean.js +1 -0
- package/docs/.vitepress/dist/assets/style.DFTx90Kk.css +1 -0
- package/docs/.vitepress/dist/hashmap.json +1 -0
- package/docs/.vitepress/dist/index.html +28 -0
- package/docs/.vitepress/dist/sillyspec/commands.html +42 -0
- package/docs/.vitepress/dist/sillyspec/dashboard.html +31 -0
- package/docs/.vitepress/dist/sillyspec/file-io.html +28 -0
- package/docs/.vitepress/dist/sillyspec/getting-started.html +31 -0
- package/docs/.vitepress/dist/sillyspec/install.html +32 -0
- package/docs/.vitepress/dist/sillyspec/lifecycle.html +55 -0
- package/docs/.vitepress/dist/sillyspec/structure.html +57 -0
- package/docs/.vitepress/dist/vp-icons.css +1 -0
- package/docs/index.md +34 -0
- package/docs/sillyspec/commands.md +218 -0
- package/docs/sillyspec/dashboard.md +51 -0
- package/docs/sillyspec/file-io.md +34 -0
- package/docs/sillyspec/getting-started.md +61 -0
- package/docs/sillyspec/install.md +51 -0
- package/docs/sillyspec/lifecycle.md +146 -0
- package/docs/sillyspec/structure.md +62 -0
- package/package.json +11 -9
- package/packages/dashboard/dist/assets/index-Bh-GPjKY.css +1 -0
- package/packages/dashboard/dist/assets/index-CrCn5Gg6.js +17 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/package-lock.json +0 -220
- package/packages/dashboard/package.json +5 -8
- package/packages/dashboard/server/index.js +106 -255
- package/packages/dashboard/server/parser.js +29 -333
- package/packages/dashboard/server/watcher.js +131 -203
- package/packages/dashboard/src/App.vue +10 -181
- package/packages/dashboard/src/components/ActionBar.vue +42 -26
- package/packages/dashboard/src/components/CommandPalette.vue +65 -40
- package/packages/dashboard/src/components/DetailPanel.vue +53 -68
- package/packages/dashboard/src/components/LogStream.vue +33 -13
- package/packages/dashboard/src/components/PipelineStage.vue +8 -8
- package/packages/dashboard/src/components/PipelineView.vue +45 -80
- package/packages/dashboard/src/components/ProjectList.vue +45 -103
- package/packages/dashboard/src/components/StageBadge.vue +13 -13
- package/packages/dashboard/src/components/StepCard.vue +15 -15
- package/packages/dashboard/src/composables/useDashboard.js +6 -20
- package/packages/dashboard/src/composables/useKeyboard.js +4 -6
- package/packages/dashboard/src/main.js +1 -4
- package/packages/dashboard/src/style.css +17 -17
- package/src/index.js +12 -123
- package/src/init.js +227 -86
- package/src/setup.js +9 -1
- package/templates/archive.md +121 -0
- package/templates/brainstorm.md +240 -0
- package/{.claude/skills/sillyspec-commit/SKILL.md → templates/commit.md} +47 -29
- package/templates/continue.md +32 -0
- package/templates/execute.md +314 -0
- package/templates/explore.md +60 -0
- package/templates/export.md +21 -0
- package/templates/init.md +61 -0
- package/templates/plan.md +157 -0
- package/templates/quick.md +135 -0
- package/templates/scan-quick.md +49 -0
- package/templates/scan.md +172 -0
- package/templates/skills/playwright-e2e/SKILL.md +340 -0
- package/templates/status.md +75 -0
- package/templates/verify.md +253 -0
- package/templates/workspace-sync.md +99 -0
- package/templates/workspace.md +70 -0
- package/.claude/skills/sillyspec-archive/SKILL.md +0 -17
- package/.claude/skills/sillyspec-auto/SKILL.md +0 -77
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -17
- package/.claude/skills/sillyspec-continue/SKILL.md +0 -44
- package/.claude/skills/sillyspec-doctor/SKILL.md +0 -22
- package/.claude/skills/sillyspec-execute/SKILL.md +0 -17
- package/.claude/skills/sillyspec-explore/SKILL.md +0 -96
- package/.claude/skills/sillyspec-export/SKILL.md +0 -53
- package/.claude/skills/sillyspec-init/SKILL.md +0 -170
- package/.claude/skills/sillyspec-plan/SKILL.md +0 -52
- package/.claude/skills/sillyspec-propose/SKILL.md +0 -17
- package/.claude/skills/sillyspec-quick/SKILL.md +0 -17
- package/.claude/skills/sillyspec-resume/SKILL.md +0 -111
- package/.claude/skills/sillyspec-scan/SKILL.md +0 -17
- package/.claude/skills/sillyspec-state/SKILL.md +0 -54
- package/.claude/skills/sillyspec-status/SKILL.md +0 -17
- package/.claude/skills/sillyspec-verify/SKILL.md +0 -17
- package/.claude/skills/sillyspec-workspace/SKILL.md +0 -149
- package/.sillyspec/changes/archive/2026-04-08-derive-state/design.md +0 -97
- package/.sillyspec/changes/archive/2026-04-08-derive-state/plan.md +0 -51
- package/.sillyspec/changes/archive/2026-04-08-derive-state/proposal.md +0 -29
- package/.sillyspec/changes/archive/2026-04-08-derive-state/requirements.md +0 -34
- package/.sillyspec/changes/archive/2026-04-08-derive-state/tasks.md +0 -13
- package/.sillyspec/changes/archive/2026-04-08-derive-state/verify-result.md +0 -43
- package/.sillyspec/changes/auto-mode/design.md +0 -50
- package/.sillyspec/changes/auto-mode/proposal.md +0 -19
- package/.sillyspec/changes/auto-mode/requirements.md +0 -21
- package/.sillyspec/changes/auto-mode/tasks.md +0 -7
- package/.sillyspec/changes/brainstorm-archive/2026-04-05-unified-docs-design.md +0 -199
- package/.sillyspec/changes/dashboard/design.md.braindraft +0 -206
- package/.sillyspec/changes/run-command-design/design.md +0 -1230
- package/.sillyspec/changes/unified-docs-design/design.md +0 -199
- package/.sillyspec/docs/sillyspec/scan/.gitkeep +0 -0
- package/.sillyspec/knowledge/INDEX.md +0 -8
- package/.sillyspec/knowledge/uncategorized.md +0 -3
- package/.sillyspec/projects/sillyspec.yaml +0 -3
- package/packages/dashboard/dist/assets/index-D1EVTLmc.js +0 -7446
- package/packages/dashboard/dist/assets/index-DGe8CqeP.css +0 -1
- package/packages/dashboard/public/logo.jpg +0 -0
- package/packages/dashboard/src/components/DocPreview.vue +0 -160
- package/packages/dashboard/src/components/DocTree.vue +0 -58
- package/packages/dashboard/src/components/ProjectOverview.vue +0 -178
- package/packages/dashboard/src/components/detail/DocsDetail.vue +0 -48
- package/packages/dashboard/src/components/detail/GitDetail.vue +0 -61
- package/packages/dashboard/src/components/detail/TechDetail.vue +0 -43
- package/src/derive.js +0 -147
- package/src/migrate.js +0 -117
- package/src/progress.js +0 -495
- package/src/run.js +0 -640
- package/src/stages/archive.js +0 -54
- package/src/stages/brainstorm.js +0 -239
- package/src/stages/doctor.js +0 -312
- package/src/stages/execute.js +0 -259
- package/src/stages/index.js +0 -35
- package/src/stages/plan.js +0 -259
- package/src/stages/propose.js +0 -115
- package/src/stages/quick.js +0 -64
- package/src/stages/scan.js +0 -141
- package/src/stages/status.js +0 -65
- package/src/stages/verify.js +0 -135
- /package/.sillyspec/{changes/brainstorm-archive → specs}/2026-04-05-dashboard-design.md +0 -0
- /package/{packages/dashboard → docs/.vitepress}/dist/favicon.jpg +0 -0
- /package/{logo.jpg → docs/.vitepress/dist/logo.jpg} +0 -0
- /package/{packages/dashboard → docs}/public/favicon.jpg +0 -0
- /package/{packages/dashboard/dist → docs/public}/logo.jpg +0 -0
package/src/stages/execute.js
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
|
|
4
|
-
export const definition = {
|
|
5
|
-
name: 'execute',
|
|
6
|
-
title: '波次执行',
|
|
7
|
-
description: '子代理并行 + 强制 TDD + 两阶段审查',
|
|
8
|
-
steps: [] // 动态构建,由 buildExecuteSteps() 生成
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// 固定前缀步骤定义
|
|
12
|
-
const fixedPrefix = [
|
|
13
|
-
{
|
|
14
|
-
name: '状态检查',
|
|
15
|
-
prompt: `检查当前状态,确认可以执行 execute。
|
|
16
|
-
|
|
17
|
-
### 操作
|
|
18
|
-
1. 运行 \`sillyspec progress show\`
|
|
19
|
-
2. 确认 currentStage 为 execute
|
|
20
|
-
3. 如果不是 → 检查是否有未完成的 tasks.md
|
|
21
|
-
4. 确认执行范围($ARGUMENTS 指定 wave/task 或全部)
|
|
22
|
-
|
|
23
|
-
### 输出
|
|
24
|
-
当前状态 + 执行范围确认`,
|
|
25
|
-
outputHint: '当前状态 + 执行范围',
|
|
26
|
-
optional: false
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
name: '加载上下文',
|
|
30
|
-
prompt: `加载计划、设计和代码库上下文。
|
|
31
|
-
|
|
32
|
-
### 操作
|
|
33
|
-
1. 读取 tasks.md(执行计划)
|
|
34
|
-
2. 读取 design.md(技术方案)
|
|
35
|
-
3. 读取 CONVENTIONS.md、ARCHITECTURE.md
|
|
36
|
-
4. 读取 local.yaml(构建命令)
|
|
37
|
-
5. 加载 CODEBASE-OVERVIEW.md
|
|
38
|
-
|
|
39
|
-
### 输出
|
|
40
|
-
已加载的上下文摘要`,
|
|
41
|
-
outputHint: '上下文摘要',
|
|
42
|
-
optional: false
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
name: '确认执行范围',
|
|
46
|
-
prompt: `解析任务,确认执行范围和确认模式。
|
|
47
|
-
|
|
48
|
-
### 操作
|
|
49
|
-
1. 从 plan 中解析 Wave 分组和任务列表
|
|
50
|
-
2. 根据任务描述关键词为每个 Task 建议模型:
|
|
51
|
-
- 架构/复杂推理 → 最强模型
|
|
52
|
-
- 常规实现 → 中等模型
|
|
53
|
-
- 简单修改 → 快速模型
|
|
54
|
-
- 文档/写作 → 写作模型
|
|
55
|
-
3. 用户在 tasks.md 中的 [model:xxx] 标签优先
|
|
56
|
-
4. 询问用户执行确认频率:
|
|
57
|
-
- 每个 Wave 确认 — 每个 Wave 完成后展示结果
|
|
58
|
-
- AI 自主判断 — BLOCKED 或计划外变更时才询问
|
|
59
|
-
- 全自动 — 全部自动执行
|
|
60
|
-
5. 查询知识库:读取 \`.sillyspec/knowledge/INDEX.md\`,根据 Task 关键词匹配
|
|
61
|
-
|
|
62
|
-
### 输出
|
|
63
|
-
Wave 分组 + 模型分配 + 确认模式 + 知识库匹配结果
|
|
64
|
-
|
|
65
|
-
### 注意
|
|
66
|
-
- 默认推荐"每个 Wave 确认"`,
|
|
67
|
-
outputHint: 'Wave 分组 + 模型分配',
|
|
68
|
-
optional: false
|
|
69
|
-
}
|
|
70
|
-
]
|
|
71
|
-
|
|
72
|
-
// 固定后缀步骤定义
|
|
73
|
-
const fixedSuffix = [
|
|
74
|
-
{
|
|
75
|
-
name: '知识库审阅',
|
|
76
|
-
prompt: `检查本轮执行产生的新知识。
|
|
77
|
-
|
|
78
|
-
### 操作
|
|
79
|
-
1. 检查 \`.sillyspec/knowledge/uncategorized.md\` 中待确认条目
|
|
80
|
-
2. 如有 → 提示用户审阅
|
|
81
|
-
3. 用户确认后改为 [已确认],可归类到专题文件
|
|
82
|
-
|
|
83
|
-
### 输出
|
|
84
|
-
新知识条目数量 + 审阅提示(或"无新知识")`,
|
|
85
|
-
outputHint: '知识条目数量',
|
|
86
|
-
optional: true
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
name: '完成确认',
|
|
90
|
-
prompt: `所有任务完成后的收尾。
|
|
91
|
-
|
|
92
|
-
### 操作
|
|
93
|
-
1. 询问用户下一步:
|
|
94
|
-
- 验证 → sillyspec run verify
|
|
95
|
-
- 归档 → /sillyspec:archive
|
|
96
|
-
- 继续开发
|
|
97
|
-
2. 提示 git add 暂存变更
|
|
98
|
-
|
|
99
|
-
### 输出
|
|
100
|
-
用户选择 + 下一步命令
|
|
101
|
-
|
|
102
|
-
### 注意
|
|
103
|
-
- 完成后运行 \`sillyspec run execute --done\` 即可自动推进阶段`,
|
|
104
|
-
outputHint: '用户选择',
|
|
105
|
-
optional: false
|
|
106
|
-
}
|
|
107
|
-
]
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* 从 plan 文件解析 Wave 分组
|
|
111
|
-
*/
|
|
112
|
-
function parseWavesFromPlan(planContent) {
|
|
113
|
-
const waves = []
|
|
114
|
-
const lines = planContent.split('\n')
|
|
115
|
-
let currentWave = null
|
|
116
|
-
let currentTask = null
|
|
117
|
-
|
|
118
|
-
for (const line of lines) {
|
|
119
|
-
const waveMatch = line.match(/^#+\s*Wave\s+(\d+)/i)
|
|
120
|
-
if (waveMatch) {
|
|
121
|
-
currentWave = { index: parseInt(waveMatch[1]), tasks: [] }
|
|
122
|
-
currentTask = null
|
|
123
|
-
waves.push(currentWave)
|
|
124
|
-
continue
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (!currentWave) continue
|
|
128
|
-
|
|
129
|
-
const taskMatch = line.match(/^[-*]\s*\[[ x]\]\s*(.+)/)
|
|
130
|
-
if (taskMatch) {
|
|
131
|
-
currentTask = {
|
|
132
|
-
name: taskMatch[1].trim(),
|
|
133
|
-
file: '',
|
|
134
|
-
steps: '',
|
|
135
|
-
reference: ''
|
|
136
|
-
}
|
|
137
|
-
// 兼容旧格式:任务名后跟 (文件路径)
|
|
138
|
-
const fileMatch = taskMatch[1].match(/\(([^)]+)\)$/)
|
|
139
|
-
if (fileMatch) {
|
|
140
|
-
currentTask.file = fileMatch[1]
|
|
141
|
-
currentTask.name = taskMatch[1].replace(/\([^)]+\)$/, '').trim()
|
|
142
|
-
}
|
|
143
|
-
currentWave.tasks.push(currentTask)
|
|
144
|
-
continue
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// 解析子行信息(修改/参考/步骤)
|
|
148
|
-
if (currentTask) {
|
|
149
|
-
const modMatch = line.match(/^\s+-\s*修改:\s*(.+)/)
|
|
150
|
-
if (modMatch) { currentTask.file = modMatch[1].trim(); continue }
|
|
151
|
-
|
|
152
|
-
const refMatch = line.match(/^\s+-\s*参考:\s*(.+)/)
|
|
153
|
-
if (refMatch) { currentTask.reference = refMatch[1].trim(); continue }
|
|
154
|
-
|
|
155
|
-
const stepMatch = line.match(/^\s+-\s*步骤:/)
|
|
156
|
-
if (stepMatch) { currentTask.steps = line.replace(/^\s+-\s*步骤:\s*/, '').trim(); continue }
|
|
157
|
-
|
|
158
|
-
// 步骤续行(数字开头的子步骤)
|
|
159
|
-
if (currentTask.steps && line.match(/^\s+\d+\./)) {
|
|
160
|
-
currentTask.steps += '\n' + line.trim()
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return waves
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* 为 Wave 生成 prompt
|
|
170
|
-
*/
|
|
171
|
-
function buildWavePrompt(wave, waveIndex, changeDir) {
|
|
172
|
-
const taskList = wave.tasks.map((t, ti) => {
|
|
173
|
-
const taskNum = String(t.index || (ti + 1)).padStart(2, '0')
|
|
174
|
-
const taskFile = changeDir ? `${changeDir}/tasks/task-${taskNum}.md` : ''
|
|
175
|
-
const taskFileExists = taskFile && existsSync(taskFile)
|
|
176
|
-
let s = `- [ ] ${t.name}`
|
|
177
|
-
if (t.file) s += ` (${t.file})`
|
|
178
|
-
if (taskFileExists) {
|
|
179
|
-
const taskContent = readFileSync(taskFile, 'utf8').trim()
|
|
180
|
-
s += `
|
|
181
|
-
\n### 📋 任务蓝图(task-${taskNum}.md)\n${taskContent}`
|
|
182
|
-
}
|
|
183
|
-
if (t.reference) s += `\n 参考: ${t.reference}`
|
|
184
|
-
if (t.steps) s += `\n 步骤: ${t.steps}`
|
|
185
|
-
return s
|
|
186
|
-
}).join('\n')
|
|
187
|
-
const { join } = path
|
|
188
|
-
const hasTaskBlueprints = changeDir && existsSync(join(changeDir, 'tasks'))
|
|
189
|
-
const taskBlueprintRule = hasTaskBlueprints
|
|
190
|
-
? '每个任务有独立的 task-N.md 蓝图——只做蓝图里写的事,不要实现蓝图之外的功能。如果蓝图有问题,**停下来反馈**,不要自己改。问题归因:实现困难 → task 蓝图没写好 → plan 没做好 → design 有缺陷。'
|
|
191
|
-
: '如果发现 plan 不合理,**停下来反馈**,不要自己改方案。问题归因:实现困难 → plan 没做好 → design 有缺陷。'
|
|
192
|
-
return `## Wave ${waveIndex}: 执行以下任务
|
|
193
|
-
|
|
194
|
-
### Wave 开始前
|
|
195
|
-
1. 读取 design.md 的「编码铁律」章节(如果存在),严格遵守
|
|
196
|
-
2. 读取 plan.md 了解全局任务划分和依赖关系
|
|
197
|
-
2. 确认本 Wave 的输入/输出契约(前置 Wave 产出了什么,本 Wave 需要消费什么)
|
|
198
|
-
3. 检查前置 Wave 的产出是否完整(文件是否存在、测试是否通过)
|
|
199
|
-
4. **上下文分层加载**:
|
|
200
|
-
- 🔥 热上下文:design.md 编码铁律 + 当前 Wave 任务(必须加载)
|
|
201
|
-
- 🌡️ 温上下文:CONVENTIONS.md + ARCHITECTURE.md(需要时加载)
|
|
202
|
-
- ❄️ 冷上下文:其他变更的 design.md、历史 plan.md(不要主动加载,除非明确需要)
|
|
203
|
-
|
|
204
|
-
### 本 Wave 任务
|
|
205
|
-
${taskList}
|
|
206
|
-
|
|
207
|
-
### 执行要求
|
|
208
|
-
1. 按任务顺序执行,同一 Wave 内任务可并行
|
|
209
|
-
2. 铁律:先读后写、grep 确认方法存在、不编造、TDD
|
|
210
|
-
3. **禁止发散思维**:你是代码搬运工,严格按任务描述执行,不增不减不改。${taskBlueprintRule}
|
|
211
|
-
4. **Reverse Sync**:发现 Bug 或实现与 design.md/task-N.md 不一致时,先检查是代码错了还是文档有遗漏,有遗漏则先修文档再修代码。
|
|
212
|
-
3. **不要频繁编译!** 编译很慢,只在以下情况运行:
|
|
213
|
-
- 写了大量代码后需要验证语法正确性
|
|
214
|
-
- 最后一个 Wave 完成后做一次全量编译验证
|
|
215
|
-
- 用户明确要求编译时
|
|
216
|
-
4. 单个任务完成后只跑**对应模块的单元测试**(TDD 绿灯确认),不要跑全量编译
|
|
217
|
-
5. 每个任务完成后:
|
|
218
|
-
- 勾选 task-N.md 中的验收标准 checkbox
|
|
219
|
-
- 勾选 plan.md / tasks.md 中对应任务的 checkbox
|
|
220
|
-
- 记录改动文件和测试结果
|
|
221
|
-
6. 遇到 BLOCKED → 记录原因,选择:重试/跳过/停止
|
|
222
|
-
|
|
223
|
-
### 完成后
|
|
224
|
-
运行 sillyspec run execute --done --input "用户原始反馈" --output "Wave ${waveIndex} 结果摘要"`
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* 动态构建 execute 步骤列表
|
|
229
|
-
* @param {string|null} planFilePath - plan 文件路径,null 则用默认 3 Wave
|
|
230
|
-
* @returns {Array} 步骤列表
|
|
231
|
-
*/
|
|
232
|
-
export function buildExecuteSteps(planFilePath = null) {
|
|
233
|
-
let waves
|
|
234
|
-
let changeDir = null
|
|
235
|
-
|
|
236
|
-
if (planFilePath && existsSync(planFilePath)) {
|
|
237
|
-
const planContent = readFileSync(planFilePath, 'utf8')
|
|
238
|
-
waves = parseWavesFromPlan(planContent)
|
|
239
|
-
// 从 planFilePath 推导 changeDir: .sillyspec/changes/<name>/plan.md
|
|
240
|
-
changeDir = path.dirname(planFilePath)
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// 如果没解析出 Wave,生成默认 3 个
|
|
244
|
-
if (!waves || waves.length === 0) {
|
|
245
|
-
waves = []
|
|
246
|
-
for (let i = 1; i <= 3; i++) {
|
|
247
|
-
waves.push({ index: i, tasks: [{ name: `默认任务 ${i}`, file: 'TBD' }] })
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const waveSteps = waves.map((wave, i) => ({
|
|
252
|
-
name: `Wave ${i + 1} 执行`,
|
|
253
|
-
prompt: buildWavePrompt(wave, i + 1, changeDir),
|
|
254
|
-
outputHint: `Wave ${i + 1} 执行结果`,
|
|
255
|
-
optional: false
|
|
256
|
-
}))
|
|
257
|
-
|
|
258
|
-
return [...fixedPrefix, ...waveSteps, ...fixedSuffix]
|
|
259
|
-
}
|
package/src/stages/index.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { definition as brainstorm } from './brainstorm.js'
|
|
2
|
-
import { definition as propose } from './propose.js'
|
|
3
|
-
import { definition as plan } from './plan.js'
|
|
4
|
-
import { definition as execute } from './execute.js'
|
|
5
|
-
import { definition as verify } from './verify.js'
|
|
6
|
-
import { definition as scan } from './scan.js'
|
|
7
|
-
import { definition as quick } from './quick.js'
|
|
8
|
-
import { definition as archive } from './archive.js'
|
|
9
|
-
import { definition as status } from './status.js'
|
|
10
|
-
import { definition as doctor } from './doctor.js'
|
|
11
|
-
|
|
12
|
-
export const stageRegistry = {
|
|
13
|
-
brainstorm,
|
|
14
|
-
propose,
|
|
15
|
-
plan,
|
|
16
|
-
execute,
|
|
17
|
-
verify,
|
|
18
|
-
scan,
|
|
19
|
-
quick,
|
|
20
|
-
archive,
|
|
21
|
-
status,
|
|
22
|
-
doctor
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// 流程阶段顺序,用于 getNextStage
|
|
26
|
-
const stageOrder = ['brainstorm', 'plan', 'execute', 'verify']
|
|
27
|
-
|
|
28
|
-
export function getNextStage(currentStage) {
|
|
29
|
-
const index = stageOrder.indexOf(currentStage)
|
|
30
|
-
if (index === -1 || index >= stageOrder.length - 1) return null
|
|
31
|
-
return stageOrder[index + 1]
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// 辅助命令(不影响流程阶段推进)
|
|
35
|
-
export const auxiliaryStages = ['scan', 'quick', 'archive', 'status', 'doctor']
|
package/src/stages/plan.js
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
|
|
4
|
-
export const definition = {
|
|
5
|
-
name: 'plan',
|
|
6
|
-
title: '实现计划',
|
|
7
|
-
description: '编写实现计划 — 按 Wave 分组,每个任务独立文档',
|
|
8
|
-
steps: null // 动态生成
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// 固定前缀步骤
|
|
12
|
-
const fixedPrefix = [
|
|
13
|
-
{
|
|
14
|
-
name: '状态检查',
|
|
15
|
-
prompt: `检查当前状态,确认可以执行 plan。
|
|
16
|
-
|
|
17
|
-
### 操作
|
|
18
|
-
1. 运行 \`sillyspec progress show\`
|
|
19
|
-
2. 确认 currentStage 为 "plan"
|
|
20
|
-
|
|
21
|
-
### 输出
|
|
22
|
-
当前状态摘要`,
|
|
23
|
-
outputHint: '状态摘要',
|
|
24
|
-
optional: false
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
name: '加载上下文',
|
|
28
|
-
prompt: `加载所有规范文件和代码库上下文。
|
|
29
|
-
|
|
30
|
-
### 操作
|
|
31
|
-
1. 读取 CODEBASE-OVERVIEW.md + 各子项目上下文
|
|
32
|
-
2. 读取 proposal.md、design.md、requirements.md、tasks.md
|
|
33
|
-
3. 读取 CONVENTIONS.md、ARCHITECTURE.md、STACK.md
|
|
34
|
-
4. 读取 local.yaml 获取构建/测试命令
|
|
35
|
-
|
|
36
|
-
### 输出
|
|
37
|
-
已加载的文件清单`,
|
|
38
|
-
outputHint: '文件清单',
|
|
39
|
-
optional: false
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
name: '锚定确认',
|
|
43
|
-
prompt: `确认已读取的文件。
|
|
44
|
-
|
|
45
|
-
### 操作
|
|
46
|
-
列出已读取的文件,标注存在/不存在。
|
|
47
|
-
|
|
48
|
-
### 输出
|
|
49
|
-
文件加载确认清单`,
|
|
50
|
-
outputHint: '文件确认清单',
|
|
51
|
-
optional: false
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
name: '展开任务并分组',
|
|
55
|
-
prompt: `把 tasks.md 每个 checkbox 展开为任务描述,按 Wave 分组,产出 plan.md 总览。
|
|
56
|
-
|
|
57
|
-
### plan.md 格式(轻量总览,PM 视角)
|
|
58
|
-
\`\`\`markdown
|
|
59
|
-
# 实现计划
|
|
60
|
-
|
|
61
|
-
## Wave 1(并行,无依赖)
|
|
62
|
-
- [ ] task-01: 添加用户创建接口
|
|
63
|
-
- [ ] task-02: 添加角色创建接口
|
|
64
|
-
|
|
65
|
-
## Wave 2(依赖 Wave 1)
|
|
66
|
-
- [ ] task-03: 用户创建接口联调
|
|
67
|
-
|
|
68
|
-
## 全局验收标准
|
|
69
|
-
- [ ] 所有单元测试通过
|
|
70
|
-
\`\`\`
|
|
71
|
-
|
|
72
|
-
### 关键规则
|
|
73
|
-
- plan.md 只放任务列表 + Wave 划分 + 全局验收标准,**不放实现细节**
|
|
74
|
-
- 实现细节写到后续的 tasks/task-NN.md 中
|
|
75
|
-
- 每个任务编号格式:task-01、task-02 ...
|
|
76
|
-
|
|
77
|
-
### 批量模式指引
|
|
78
|
-
如果 design.md 或需求中包含批量特征(关键词:批量/模板/引擎/N个相似),按以下原则规划:
|
|
79
|
-
❌ 不要列出每个实例作为独立任务
|
|
80
|
-
❌ 不要在文档中嵌入数据
|
|
81
|
-
✅ 设计通用架构,Wave 1 聚焦架构
|
|
82
|
-
✅ 数据转换用脚本完成,单独一个 Wave
|
|
83
|
-
✅ 总任务数控制在 10 个以内
|
|
84
|
-
|
|
85
|
-
### 操作
|
|
86
|
-
1. 读取 tasks.md 获取任务列表
|
|
87
|
-
2. 读取 design.md 获取文件变更清单
|
|
88
|
-
3. 逐个展开为任务描述
|
|
89
|
-
4. 分析依赖关系,按 Wave 分组
|
|
90
|
-
5. 保存到 \`.sillyspec/changes/<变更名>/plan.md\`
|
|
91
|
-
|
|
92
|
-
### 输出
|
|
93
|
-
plan.md 总览内容`,
|
|
94
|
-
outputHint: 'plan.md 总览',
|
|
95
|
-
optional: false
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
name: '自检总览',
|
|
99
|
-
prompt: `自检 plan.md 总览质量。
|
|
100
|
-
|
|
101
|
-
### 操作
|
|
102
|
-
检查以下各项:
|
|
103
|
-
- [ ] 每个 task 有编号(task-01、task-02 ...)
|
|
104
|
-
- [ ] 每个 task 有 checkbox
|
|
105
|
-
- [ ] 已标注 Wave 分组和依赖关系
|
|
106
|
-
- [ ] 有全局验收标准
|
|
107
|
-
- [ ] 没有实现细节(接口定义、代码示例等不应该在 plan.md 里)
|
|
108
|
-
- [ ] plan.md 与 design.md 的文件变更清单一致
|
|
109
|
-
|
|
110
|
-
### 输出
|
|
111
|
-
自检通过/不通过`,
|
|
112
|
-
outputHint: '自检结果',
|
|
113
|
-
optional: false
|
|
114
|
-
}
|
|
115
|
-
]
|
|
116
|
-
|
|
117
|
-
// 固定后缀步骤
|
|
118
|
-
const fixedSuffix = [
|
|
119
|
-
{
|
|
120
|
-
name: '审查一致性',
|
|
121
|
-
prompt: `审查所有 task-N.md 的一致性。
|
|
122
|
-
|
|
123
|
-
### 操作
|
|
124
|
-
1. 读取所有 tasks/task-NN.md
|
|
125
|
-
2. 检查:
|
|
126
|
-
- 文件路径有没有冲突(两个任务改同一个文件)
|
|
127
|
-
- 依赖关系和 plan.md 的 Wave 分组是否一致
|
|
128
|
-
- 验收标准和 plan.md 的全局标准是否矛盾
|
|
129
|
-
- 接口定义是否自洽
|
|
130
|
-
3. 发现问题 → 列出问题清单,暂停等用户决定是否修复
|
|
131
|
-
|
|
132
|
-
### 输出
|
|
133
|
-
一致性审查结果`,
|
|
134
|
-
outputHint: '审查结果',
|
|
135
|
-
optional: false
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
name: '保存并更新进度',
|
|
139
|
-
prompt: `确认所有文件已保存,更新进度。
|
|
140
|
-
|
|
141
|
-
### 操作
|
|
142
|
-
1. 确认 plan.md 和所有 tasks/task-NN.md 已存在
|
|
143
|
-
2. \`git add .sillyspec/\` — **不要 commit**
|
|
144
|
-
|
|
145
|
-
### 输出
|
|
146
|
-
文件列表 + 下一步命令`,
|
|
147
|
-
outputHint: '文件列表',
|
|
148
|
-
optional: false
|
|
149
|
-
}
|
|
150
|
-
]
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* 解析 plan.md 获取任务数量
|
|
154
|
-
*/
|
|
155
|
-
function parseTaskCount(planContent) {
|
|
156
|
-
const matches = planContent.match(/^[-*]\s*\[[ x]\]\s*task-\d+/gm)
|
|
157
|
-
return matches ? matches.length : 0
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* 生成单个任务的蓝图写作 prompt
|
|
162
|
-
*/
|
|
163
|
-
function buildTaskPrompt(taskNum, taskName, changeDir) {
|
|
164
|
-
return `编写任务蓝图 tasks/task-${String(taskNum).padStart(2, '0')}.md
|
|
165
|
-
|
|
166
|
-
### 任务
|
|
167
|
-
${taskName}
|
|
168
|
-
|
|
169
|
-
### 文件路径
|
|
170
|
-
\`.sillyspec/changes/<变更名>/tasks/task-${String(taskNum).padStart(2, '0')}.md\`
|
|
171
|
-
|
|
172
|
-
### 格式要求(必须严格遵守)
|
|
173
|
-
\`\`\`markdown
|
|
174
|
-
# task-${String(taskNum).padStart(2, '0')}: ${taskName}
|
|
175
|
-
|
|
176
|
-
## 修改文件
|
|
177
|
-
- 具体文件路径列表
|
|
178
|
-
|
|
179
|
-
## 实现要求
|
|
180
|
-
1. 具体做什么,写清楚
|
|
181
|
-
2. ...
|
|
182
|
-
|
|
183
|
-
## 接口定义
|
|
184
|
-
(代码类任务必填,写方法签名、数据结构)
|
|
185
|
-
|
|
186
|
-
## 边界处理
|
|
187
|
-
- 异常场景列表
|
|
188
|
-
|
|
189
|
-
## 参考
|
|
190
|
-
- 已有代码可参考的模式
|
|
191
|
-
- 相关的 CONVENTIONS.md 条目
|
|
192
|
-
|
|
193
|
-
## TDD 步骤
|
|
194
|
-
1. 写测试 ...
|
|
195
|
-
2. 运行 <test-cmd> 确认失败
|
|
196
|
-
3. 写代码 ...
|
|
197
|
-
4. 运行 <test-cmd> 确认通过
|
|
198
|
-
(纯配置/文档类任务简化为:1. 实现 2. 验证)
|
|
199
|
-
|
|
200
|
-
## 验收标准
|
|
201
|
-
- [ ] 具体可测试的验收条件
|
|
202
|
-
\`\`\`
|
|
203
|
-
|
|
204
|
-
### 关键规则
|
|
205
|
-
- task-N.md 必须独立完整,execute 子代理只读这一个文件就能干活
|
|
206
|
-
- 不要依赖其他 task-N.md 的内容
|
|
207
|
-
- 接口定义写到"搬砖工照着做"的程度
|
|
208
|
-
- 写完后保存到文件
|
|
209
|
-
|
|
210
|
-
### 操作
|
|
211
|
-
1. 读取 design.md 和 plan.md 了解上下文
|
|
212
|
-
2. 读取相关源文件了解现有代码
|
|
213
|
-
3. 编写任务蓝图
|
|
214
|
-
4. 保存到 tasks/task-${String(taskNum).padStart(2, '0')}.md
|
|
215
|
-
|
|
216
|
-
### 输出
|
|
217
|
-
任务蓝图内容摘要`
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* 动态构建 plan 步骤列表
|
|
222
|
-
* @param {string|null} changeDir - 变更目录路径
|
|
223
|
-
* @param {string|null} planContent - plan.md 内容(可选,用于解析任务数)
|
|
224
|
-
* @returns {Array} 步骤列表
|
|
225
|
-
*/
|
|
226
|
-
export function buildPlanSteps(changeDir = null, planContent = null) {
|
|
227
|
-
let taskCount = 0
|
|
228
|
-
|
|
229
|
-
// 尝试从 plan.md 解析任务数
|
|
230
|
-
if (planContent) {
|
|
231
|
-
taskCount = parseTaskCount(planContent)
|
|
232
|
-
} else if (changeDir) {
|
|
233
|
-
const planFile = path.join(changeDir, 'plan.md')
|
|
234
|
-
if (existsSync(planFile)) {
|
|
235
|
-
taskCount = parseTaskCount(readFileSync(planFile, 'utf8'))
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// 没有任务数则用固定步骤(兼容旧流程)
|
|
240
|
-
if (taskCount === 0) {
|
|
241
|
-
return [...fixedPrefix, ...fixedSuffix]
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// 动态生成每个任务的蓝图写作步骤
|
|
245
|
-
const taskSteps = []
|
|
246
|
-
for (let i = 1; i <= taskCount; i++) {
|
|
247
|
-
taskSteps.push({
|
|
248
|
-
name: `写任务蓝图 task-${String(i).padStart(2, '0')}`,
|
|
249
|
-
prompt: `### 注意
|
|
250
|
-
这是第 ${i}/${taskCount} 个任务蓝图。focus 在这一个任务上,不要写其他任务的内容。
|
|
251
|
-
|
|
252
|
-
${buildTaskPrompt(i, '(从 plan.md 读取任务名)', changeDir)}`,
|
|
253
|
-
outputHint: `task-${String(i).padStart(2, '0')} 蓝图`,
|
|
254
|
-
optional: false
|
|
255
|
-
})
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return [...fixedPrefix, ...taskSteps, ...fixedSuffix]
|
|
259
|
-
}
|
package/src/stages/propose.js
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
export const definition = {
|
|
2
|
-
name: 'propose',
|
|
3
|
-
title: '方案设计',
|
|
4
|
-
description: '生成结构化规范 — proposal + design + tasks',
|
|
5
|
-
steps: [
|
|
6
|
-
{
|
|
7
|
-
name: '状态检查',
|
|
8
|
-
prompt: `检查当前状态,确认可以执行 propose。
|
|
9
|
-
|
|
10
|
-
### 操作
|
|
11
|
-
1. 运行 \`sillyspec progress show\`
|
|
12
|
-
2. 确认 currentStage 为 "propose"
|
|
13
|
-
3. 如果没有设计文档 → 提示先运行 brainstorm
|
|
14
|
-
|
|
15
|
-
### 输出
|
|
16
|
-
当前状态摘要`,
|
|
17
|
-
outputHint: '状态摘要',
|
|
18
|
-
optional: false
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
name: '加载上下文',
|
|
22
|
-
prompt: `加载所有相关规范和代码库上下文。
|
|
23
|
-
|
|
24
|
-
### 操作
|
|
25
|
-
1. 加载 CODEBASE-OVERVIEW.md 和子项目上下文
|
|
26
|
-
2. 读取最新设计文档、需求文档、代码库约定
|
|
27
|
-
3. 如果是子阶段变更,读取 MASTER.md 和前序阶段设计
|
|
28
|
-
|
|
29
|
-
### 输出
|
|
30
|
-
已加载的文件列表`,
|
|
31
|
-
outputHint: '文件列表',
|
|
32
|
-
optional: false
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
name: '锚定确认',
|
|
36
|
-
prompt: `确认已读取的文件。
|
|
37
|
-
|
|
38
|
-
### 操作
|
|
39
|
-
1. 列出已读取的文件,标注存在/不存在
|
|
40
|
-
2. 格式:\`[x] 文件名 — 说明\` 或 \`[ ] 文件名 — 不存在(正常)\`
|
|
41
|
-
|
|
42
|
-
### 输出
|
|
43
|
-
文件加载确认清单
|
|
44
|
-
|
|
45
|
-
### 注意
|
|
46
|
-
- 文件不存在不是错误,正常标注即可`,
|
|
47
|
-
outputHint: '文件确认清单',
|
|
48
|
-
optional: false
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
name: '探索现有代码',
|
|
52
|
-
prompt: `理解相关模块的当前实现,识别影响范围。
|
|
53
|
-
|
|
54
|
-
### 操作
|
|
55
|
-
1. 根据设计文档中的文件变更清单,读取相关源码
|
|
56
|
-
2. 识别现有接口、方法签名、数据结构
|
|
57
|
-
3. 记录可能受影响的模块
|
|
58
|
-
|
|
59
|
-
### 输出
|
|
60
|
-
影响范围分析(涉及模块、需修改的文件、风险点)`,
|
|
61
|
-
outputHint: '影响范围分析',
|
|
62
|
-
optional: false
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
name: '生成规范文件',
|
|
66
|
-
prompt: `在 \`.sillyspec/changes/<变更名>/\` 下生成四个文件。
|
|
67
|
-
|
|
68
|
-
### 操作
|
|
69
|
-
1. 生成 proposal.md:动机、变更范围、不在范围内、成功标准
|
|
70
|
-
2. 生成 requirements.md:功能需求、用户场景(Given/When/Then)、非功能需求
|
|
71
|
-
3. 生成 design.md:架构决策、文件变更清单、数据模型、API 设计、代码风格参照
|
|
72
|
-
4. 生成 tasks.md:任务列表(只列名称,不展开步骤)
|
|
73
|
-
|
|
74
|
-
### 输出
|
|
75
|
-
四个文件路径
|
|
76
|
-
|
|
77
|
-
### 注意
|
|
78
|
-
- 表名/字段名必须来自真实 schema 或标注"新增"
|
|
79
|
-
- 用户场景必须用 Given/When/Then 格式
|
|
80
|
-
- tasks.md 只列任务名,细节在 plan 阶段展开`,
|
|
81
|
-
outputHint: '四个文件路径',
|
|
82
|
-
optional: false
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
name: '自检门控',
|
|
86
|
-
prompt: `自检生成的规范文件。
|
|
87
|
-
|
|
88
|
-
### 操作
|
|
89
|
-
检查以下各项:
|
|
90
|
-
- [ ] proposal.md 有动机、变更范围、不在范围内、成功标准
|
|
91
|
-
- [ ] design.md 有文件变更清单表格
|
|
92
|
-
- [ ] requirements.md 有 Given/When/Then 用户场景
|
|
93
|
-
- [ ] tasks.md 每个 task 有文件路径
|
|
94
|
-
|
|
95
|
-
任何不通过 → 修正后重新检查。
|
|
96
|
-
|
|
97
|
-
### 输出
|
|
98
|
-
自检通过/不通过`,
|
|
99
|
-
outputHint: '自检结果',
|
|
100
|
-
optional: false
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
name: '展示并更新进度',
|
|
104
|
-
prompt: `展示规范给用户,更新进度。
|
|
105
|
-
|
|
106
|
-
### 操作
|
|
107
|
-
1. 展示 proposal.md 和 design.md 摘要
|
|
108
|
-
|
|
109
|
-
### 输出
|
|
110
|
-
展示结果 + 下一步命令`,
|
|
111
|
-
outputHint: '展示结果',
|
|
112
|
-
optional: false
|
|
113
|
-
}
|
|
114
|
-
]
|
|
115
|
-
}
|