sillyspec 2.4.0
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/.claude/commands/sillyspec/archive.md +63 -0
- package/.claude/commands/sillyspec/brainstorm.md +463 -0
- package/.claude/commands/sillyspec/continue.md +44 -0
- package/.claude/commands/sillyspec/execute.md +255 -0
- package/.claude/commands/sillyspec/explore.md +88 -0
- package/.claude/commands/sillyspec/export.md +53 -0
- package/.claude/commands/sillyspec/init.md +166 -0
- package/.claude/commands/sillyspec/plan.md +238 -0
- package/.claude/commands/sillyspec/propose.md +234 -0
- package/.claude/commands/sillyspec/quick.md +62 -0
- package/.claude/commands/sillyspec/resume.md +100 -0
- package/.claude/commands/sillyspec/scan.md +672 -0
- package/.claude/commands/sillyspec/status.md +122 -0
- package/.claude/commands/sillyspec/verify.md +141 -0
- package/.claude/commands/sillyspec/workspace.md +122 -0
- package/README.md +158 -0
- package/SKILL.md +46 -0
- package/adapters/adapters.sh +172 -0
- package/bin/sillyspec.js +2 -0
- package/commands/sillyspec/archive.md +62 -0
- package/commands/sillyspec/brainstorm.md +462 -0
- package/commands/sillyspec/continue.md +41 -0
- package/commands/sillyspec/execute.md +254 -0
- package/commands/sillyspec/explore.md +85 -0
- package/commands/sillyspec/export.md +51 -0
- package/commands/sillyspec/init.md +163 -0
- package/commands/sillyspec/plan.md +237 -0
- package/commands/sillyspec/propose.md +233 -0
- package/commands/sillyspec/quick.md +59 -0
- package/commands/sillyspec/resume.md +99 -0
- package/commands/sillyspec/scan.md +671 -0
- package/commands/sillyspec/status.md +119 -0
- package/commands/sillyspec/verify.md +140 -0
- package/commands/sillyspec/workspace.md +120 -0
- package/package.json +14 -0
- package/scripts/init.sh +2 -0
- package/scripts/install.ps1 +316 -0
- package/scripts/scan-preprocess.sh +378 -0
- package/scripts/validate-all.sh +50 -0
- package/scripts/validate-plan.sh +44 -0
- package/scripts/validate-proposal.sh +87 -0
- package/scripts/validate-scan.sh +90 -0
- package/src/index.js +560 -0
- package/src/init.js +269 -0
- package/templates/archive.md +58 -0
- package/templates/brainstorm.md +458 -0
- package/templates/continue.md +39 -0
- package/templates/execute.md +250 -0
- package/templates/explore.md +83 -0
- package/templates/export.md +48 -0
- package/templates/init.md +161 -0
- package/templates/plan.md +233 -0
- package/templates/propose.md +229 -0
- package/templates/quick.md +57 -0
- package/templates/resume.md +95 -0
- package/templates/scan.md +667 -0
- package/templates/status.md +117 -0
- package/templates/verify.md +136 -0
- package/templates/workspace.md +117 -0
package/src/init.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { join, resolve, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { homedir } from 'os';
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
const TEMPLATE_DIR = resolve(__dirname, '..', 'templates');
|
|
9
|
+
|
|
10
|
+
// ── 元数据映射 ──
|
|
11
|
+
|
|
12
|
+
const DESCRIPTIONS = {
|
|
13
|
+
init: '绿地项目初始化 — 深度提问、调研、需求文档、路线图',
|
|
14
|
+
scan: '代码库扫描 — 支持快速扫描和深度扫描两阶段',
|
|
15
|
+
explore: '自由思考模式 — 讨论、画图、调研,不写代码',
|
|
16
|
+
brainstorm: '需求探索 — 结构化头脑风暴,生成设计文档(创建性工作前必用)',
|
|
17
|
+
propose: '生成结构化规范 — proposal + design + tasks',
|
|
18
|
+
plan: '编写实现计划 — 2-5 分钟粒度,精确到文件路径和代码',
|
|
19
|
+
execute: '波次执行 — 子代理并行 + 强制 TDD + 两阶段审查',
|
|
20
|
+
verify: '验证实现 — 对照规范检查 + 测试套件',
|
|
21
|
+
archive: '归档变更 — 规范沉淀,可追溯',
|
|
22
|
+
status: '查看项目进度和状态',
|
|
23
|
+
continue: '自动判断并执行下一步',
|
|
24
|
+
state: '查看当前工作状态 — 显示 STATE.md 内容',
|
|
25
|
+
resume: '恢复工作 — 从中断处继续',
|
|
26
|
+
quick: '快速任务 — 跳过完整流程,直接做',
|
|
27
|
+
workspace: '工作区管理 — 初始化、管理多项目工作区,查看子项目状态',
|
|
28
|
+
export: '导出成功方案为可复用模板',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const ARG_HINTS = {
|
|
32
|
+
init: '[项目名]',
|
|
33
|
+
scan: '[可选:指定区域,如 \'api\' 或 \'auth\'] [--deep 深度扫描]',
|
|
34
|
+
explore: '[探索主题]',
|
|
35
|
+
brainstorm: '[需求或想法描述]',
|
|
36
|
+
propose: '[变更名]',
|
|
37
|
+
plan: '[计划名]',
|
|
38
|
+
execute: '[任务编号或 \'all\']',
|
|
39
|
+
verify: '[可选:指定验证范围]',
|
|
40
|
+
archive: '[变更名]',
|
|
41
|
+
status: '',
|
|
42
|
+
continue: '',
|
|
43
|
+
state: '[可选备注]',
|
|
44
|
+
resume: '',
|
|
45
|
+
quick: '[任务描述]',
|
|
46
|
+
workspace: '[可选:add/remove/status/info]',
|
|
47
|
+
export: '<change-name> [--to <path>]',
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const VALID_TOOLS = ['claude', 'claude_skills', 'cursor', 'codex', 'opencode', 'openclaw'];
|
|
51
|
+
|
|
52
|
+
// ── 适配器 ──
|
|
53
|
+
|
|
54
|
+
function generateClaude(projectDir, name, desc, body, argHint) {
|
|
55
|
+
const outDir = join(projectDir, '.claude', 'commands', 'sillyspec');
|
|
56
|
+
mkdirSync(outDir, { recursive: true });
|
|
57
|
+
writeFileSync(join(outDir, `${name}.md`),
|
|
58
|
+
`---
|
|
59
|
+
description: ${desc}
|
|
60
|
+
argument-hint: "${argHint}"
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
${body}`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function generateClaudeSkills(projectDir, name, desc, body, argHint) {
|
|
68
|
+
const outDir = join(projectDir, '.claude', 'skills', `sillyspec-${name}`);
|
|
69
|
+
mkdirSync(outDir, { recursive: true });
|
|
70
|
+
writeFileSync(join(outDir, 'SKILL.md'),
|
|
71
|
+
`---
|
|
72
|
+
name: sillyspec:${name}
|
|
73
|
+
description: ${desc}
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
${body}`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function generateCursor(projectDir, name, desc, body, argHint) {
|
|
81
|
+
const outDir = join(projectDir, '.cursor', 'commands');
|
|
82
|
+
mkdirSync(outDir, { recursive: true });
|
|
83
|
+
writeFileSync(join(outDir, `sillyspec-${name}.md`),
|
|
84
|
+
`---
|
|
85
|
+
name: /sillyspec-${name}
|
|
86
|
+
id: sillyspec-${name}
|
|
87
|
+
description: ${desc}
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
${body}`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function generateCodex(projectDir, name, desc, body, argHint) {
|
|
95
|
+
// codex outputs to user home directory
|
|
96
|
+
const outDir = join(homedir(), '.agents', 'skills', `sillyspec-${name}`);
|
|
97
|
+
mkdirSync(outDir, { recursive: true });
|
|
98
|
+
writeFileSync(join(outDir, 'SKILL.md'),
|
|
99
|
+
`---
|
|
100
|
+
name: sillyspec:${name}
|
|
101
|
+
description: ${desc}
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
${body}`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function generateOpencode(projectDir, name, desc, body, argHint) {
|
|
109
|
+
const outDir = join(projectDir, '.opencode', 'skills', `sillyspec-${name}`);
|
|
110
|
+
mkdirSync(outDir, { recursive: true });
|
|
111
|
+
writeFileSync(join(outDir, 'SKILL.md'),
|
|
112
|
+
`---
|
|
113
|
+
name: sillyspec:${name}
|
|
114
|
+
description: ${desc}
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
${body}`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function generateOpenclaw(projectDir, name, desc, body, argHint) {
|
|
122
|
+
const outDir = join(projectDir, '.openclaw', 'skills', `sillyspec-${name}`);
|
|
123
|
+
mkdirSync(outDir, { recursive: true });
|
|
124
|
+
writeFileSync(join(outDir, 'SKILL.md'),
|
|
125
|
+
`---
|
|
126
|
+
name: sillyspec:${name}
|
|
127
|
+
description: ${desc}
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
${body}`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const GENERATORS = {
|
|
135
|
+
claude: generateClaude,
|
|
136
|
+
claude_skills: generateClaudeSkills,
|
|
137
|
+
cursor: generateCursor,
|
|
138
|
+
codex: generateCodex,
|
|
139
|
+
opencode: generateOpencode,
|
|
140
|
+
openclaw: generateOpenclaw,
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// ── 检测工具 ──
|
|
144
|
+
|
|
145
|
+
function detectTools(projectDir) {
|
|
146
|
+
const found = [];
|
|
147
|
+
if (existsSync(join(projectDir, '.claude'))) found.push('claude');
|
|
148
|
+
if (existsSync(join(projectDir, '.claude', 'skills'))) found.push('claude_skills');
|
|
149
|
+
if (existsSync(join(projectDir, '.cursor'))) found.push('cursor');
|
|
150
|
+
if (existsSync(join(projectDir, '.opencode'))) found.push('opencode');
|
|
151
|
+
if (existsSync(join(projectDir, '.openclaw'))) found.push('openclaw');
|
|
152
|
+
if (existsSync(join(homedir(), '.agents', 'skills'))) found.push('codex');
|
|
153
|
+
if (found.length === 0) found.push('claude');
|
|
154
|
+
return found;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ── 主命令 ──
|
|
158
|
+
|
|
159
|
+
export function cmdInit(projectDir, options = {}) {
|
|
160
|
+
const { tool, workspace } = options;
|
|
161
|
+
|
|
162
|
+
// 确定要安装的工具
|
|
163
|
+
let tools;
|
|
164
|
+
if (tool) {
|
|
165
|
+
if (!VALID_TOOLS.includes(tool)) {
|
|
166
|
+
console.error(`❌ 未知工具: ${tool}`);
|
|
167
|
+
console.error(`支持的工具: ${VALID_TOOLS.join(', ')}`);
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
tools = [tool];
|
|
171
|
+
} else {
|
|
172
|
+
tools = detectTools(projectDir);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
console.log('🤪 SillySpec v2.2 — 规范驱动开发');
|
|
176
|
+
console.log('====================================');
|
|
177
|
+
console.log('');
|
|
178
|
+
console.log(`📦 安装工具: ${tools.join(', ')}`);
|
|
179
|
+
if (workspace) console.log('📦 工作区模式');
|
|
180
|
+
console.log('');
|
|
181
|
+
|
|
182
|
+
// 创建基础目录
|
|
183
|
+
const dirs = [
|
|
184
|
+
'.sillyspec/codebase',
|
|
185
|
+
'.sillyspec/changes/archive',
|
|
186
|
+
'.sillyspec/plans',
|
|
187
|
+
'.sillyspec/specs',
|
|
188
|
+
'.sillyspec/phases',
|
|
189
|
+
];
|
|
190
|
+
if (workspace) {
|
|
191
|
+
dirs.push('.sillyspec/shared', '.sillyspec/workspace');
|
|
192
|
+
}
|
|
193
|
+
for (const d of dirs) {
|
|
194
|
+
mkdirSync(join(projectDir, d), { recursive: true });
|
|
195
|
+
}
|
|
196
|
+
mkdirSync(join(homedir(), '.sillyspec', 'templates'), { recursive: true });
|
|
197
|
+
|
|
198
|
+
// .gitignore
|
|
199
|
+
const gitignorePath = join(projectDir, '.gitignore');
|
|
200
|
+
if (!existsSync(gitignorePath)) {
|
|
201
|
+
writeFileSync(gitignorePath, '.sillyspec/STATE.md\n');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// 为每个工具生成文件
|
|
205
|
+
const templateFiles = readdirSync(TEMPLATE_DIR).filter(f => f.endsWith('.md'));
|
|
206
|
+
let count = 0;
|
|
207
|
+
|
|
208
|
+
for (const toolName of tools) {
|
|
209
|
+
console.log(`🔧 安装 ${toolName}...`);
|
|
210
|
+
const gen = GENERATORS[toolName];
|
|
211
|
+
for (const file of templateFiles) {
|
|
212
|
+
const name = file.replace('.md', '');
|
|
213
|
+
const desc = DESCRIPTIONS[name] || `SillySpec ${name}`;
|
|
214
|
+
const argHint = ARG_HINTS[name] || '';
|
|
215
|
+
const body = readFileSync(join(TEMPLATE_DIR, file), 'utf8');
|
|
216
|
+
gen(projectDir, name, desc, body, argHint);
|
|
217
|
+
count++;
|
|
218
|
+
}
|
|
219
|
+
console.log(` ✅ ${toolName} 完成`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
console.log('');
|
|
223
|
+
console.log(`📄 ${count} 个命令已安装`);
|
|
224
|
+
|
|
225
|
+
// 工作区配置
|
|
226
|
+
if (workspace) {
|
|
227
|
+
const configPath = join(projectDir, '.sillyspec', 'config.yaml');
|
|
228
|
+
if (!existsSync(configPath)) {
|
|
229
|
+
writeFileSync(configPath,
|
|
230
|
+
`# SillySpec 工作区配置
|
|
231
|
+
# 修改此文件后运行 /sillyspec:workspace 更新
|
|
232
|
+
|
|
233
|
+
projects: {}
|
|
234
|
+
# 示例:
|
|
235
|
+
# frontend:
|
|
236
|
+
# path: ./frontend
|
|
237
|
+
# role: 前端 - Vue3 + TypeScript
|
|
238
|
+
# backend:
|
|
239
|
+
# path: ./backend
|
|
240
|
+
# role: 后端 - Node.js + PostgreSQL
|
|
241
|
+
|
|
242
|
+
shared: []
|
|
243
|
+
`
|
|
244
|
+
);
|
|
245
|
+
console.log('📄 .sillyspec/config.yaml → 工作区配置 ✓');
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
console.log('');
|
|
250
|
+
console.log('=====================================');
|
|
251
|
+
if (workspace) {
|
|
252
|
+
console.log('✅ SillySpec v2.2 安装完成!(工作区模式)');
|
|
253
|
+
console.log('');
|
|
254
|
+
console.log(`已安装工具: ${tools.join(', ')}`);
|
|
255
|
+
console.log('');
|
|
256
|
+
console.log('工作区命令:');
|
|
257
|
+
console.log(' /sillyspec:workspace add — 添加子项目');
|
|
258
|
+
console.log(' /sillyspec:workspace status — 查看工作区状态');
|
|
259
|
+
} else {
|
|
260
|
+
console.log('✅ SillySpec v2.2 安装完成!');
|
|
261
|
+
console.log('');
|
|
262
|
+
console.log(`已安装工具: ${tools.join(', ')}`);
|
|
263
|
+
console.log('');
|
|
264
|
+
console.log('入口选择:');
|
|
265
|
+
console.log(' 绿地项目:/sillyspec:init');
|
|
266
|
+
console.log(' 棕地项目:/sillyspec:scan');
|
|
267
|
+
console.log(' 自由思考:/sillyspec:explore "你的想法"');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
你现在是 SillySpec 的归档器。
|
|
2
|
+
|
|
3
|
+
## 变更名称
|
|
4
|
+
$ARGUMENTS
|
|
5
|
+
|
|
6
|
+
## 流程
|
|
7
|
+
|
|
8
|
+
### 1. 确认验证通过
|
|
9
|
+
|
|
10
|
+
检查是否执行过验证。如果没有 → 提示先运行 `/sillyspec:verify`。
|
|
11
|
+
|
|
12
|
+
### 2. 归档
|
|
13
|
+
|
|
14
|
+
### 3. 确认归档
|
|
15
|
+
|
|
16
|
+
在移动文件之前,展示即将归档的内容:
|
|
17
|
+
- 变更目录名
|
|
18
|
+
- 包含的文件列表
|
|
19
|
+
- 生成总结
|
|
20
|
+
|
|
21
|
+
**等待用户确认后再执行归档操作。**
|
|
22
|
+
|
|
23
|
+
将 `.sillyspec/changes/<change-name>/` 移动到 `.sillyspec/changes/archive/YYYY-MM-DD-<change-name>/`。
|
|
24
|
+
|
|
25
|
+
### 3. 更新 tasks.md
|
|
26
|
+
|
|
27
|
+
确保所有 checkbox 都已勾选。如有遗漏 → 打勾。
|
|
28
|
+
|
|
29
|
+
### 4. 更新路线图(如存在)
|
|
30
|
+
|
|
31
|
+
如果 `.sillyspec/ROADMAP.md` 存在,标记对应 Phase 为已完成。
|
|
32
|
+
|
|
33
|
+
### 5. Git 提交
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
git add .sillyspec/
|
|
37
|
+
git commit -m "docs: archive sillyspec change <change-name>"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 最后说:
|
|
41
|
+
|
|
42
|
+
> ✅ 变更 `<change-name>` 已归档。
|
|
43
|
+
>
|
|
44
|
+
> 累积规范:
|
|
45
|
+
> - `.sillyspec/changes/archive/` — X 个已归档变更
|
|
46
|
+
> - `.sillyspec/specs/` — X 份设计文档
|
|
47
|
+
> - `.sillyspec/plans/` — X 份实现计划
|
|
48
|
+
>
|
|
49
|
+
> 继续下一个:`/sillyspec:brainstorm "新想法"`
|
|
50
|
+
|
|
51
|
+
### 更新 STATE.md
|
|
52
|
+
|
|
53
|
+
archive 完成后,**必须自动更新** `.sillyspec/STATE.md`:
|
|
54
|
+
|
|
55
|
+
- 清除当前变更信息(归档后不再活跃)
|
|
56
|
+
- 如果是主变更(有 MASTER.md),标记所有阶段为 ✅,然后清除
|
|
57
|
+
- 历史记录追加时间 + 归档完成
|
|
58
|
+
- 下一步改为 `/sillyspec:brainstorm "新想法"` 或留空
|