sillyspec 3.8.7 → 3.9.1
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/skills/sillyspec-archive/SKILL.md +17 -0
- package/.claude/skills/sillyspec-auto/SKILL.md +78 -0
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +17 -0
- package/{templates/commit.md → .claude/skills/sillyspec-commit/SKILL.md} +32 -47
- package/.claude/skills/sillyspec-continue/SKILL.md +45 -0
- package/.claude/skills/sillyspec-doctor/SKILL.md +27 -0
- package/.claude/skills/sillyspec-execute/SKILL.md +17 -0
- package/.claude/skills/sillyspec-explore/SKILL.md +96 -0
- package/.claude/skills/sillyspec-export/SKILL.md +53 -0
- package/.claude/skills/sillyspec-init/SKILL.md +170 -0
- package/.claude/skills/sillyspec-plan/SKILL.md +52 -0
- package/.claude/skills/sillyspec-propose/SKILL.md +17 -0
- package/.claude/skills/sillyspec-quick/SKILL.md +17 -0
- package/.claude/skills/sillyspec-resume/SKILL.md +111 -0
- package/.claude/skills/sillyspec-scan/SKILL.md +17 -0
- package/.claude/skills/sillyspec-state/SKILL.md +54 -0
- package/.claude/skills/sillyspec-status/SKILL.md +17 -0
- package/.claude/skills/sillyspec-verify/SKILL.md +17 -0
- package/.claude/skills/sillyspec-workspace/SKILL.md +149 -0
- package/.sillyspec/changes/archive/2026-04-08-derive-state/design.md +97 -0
- package/.sillyspec/changes/archive/2026-04-08-derive-state/plan.md +51 -0
- package/.sillyspec/changes/archive/2026-04-08-derive-state/proposal.md +29 -0
- package/.sillyspec/changes/archive/2026-04-08-derive-state/requirements.md +34 -0
- package/.sillyspec/changes/archive/2026-04-08-derive-state/tasks.md +13 -0
- package/.sillyspec/changes/archive/2026-04-08-derive-state/verify-result.md +43 -0
- package/.sillyspec/changes/auto-mode/design.md +50 -0
- package/.sillyspec/changes/auto-mode/proposal.md +19 -0
- package/.sillyspec/changes/auto-mode/requirements.md +21 -0
- package/.sillyspec/changes/auto-mode/tasks.md +7 -0
- package/.sillyspec/changes/brainstorm-archive/2026-04-05-unified-docs-design.md +199 -0
- package/.sillyspec/changes/dashboard/design.md.braindraft +206 -0
- package/.sillyspec/changes/run-command-design/design.md +1230 -0
- package/.sillyspec/changes/unified-docs-design/design.md +199 -0
- package/.sillyspec/docs/sillyspec/scan/.gitkeep +0 -0
- package/.sillyspec/knowledge/INDEX.md +8 -0
- package/.sillyspec/knowledge/uncategorized.md +3 -0
- package/.sillyspec/projects/sillyspec.yaml +3 -0
- package/README.md +12 -5
- package/package.json +9 -11
- package/packages/dashboard/dist/assets/index-CntACGUN.css +1 -0
- package/packages/dashboard/dist/assets/index-RsLVPAy7.js +7446 -0
- package/packages/dashboard/dist/index.html +3 -2
- package/packages/dashboard/package-lock.json +226 -6
- package/packages/dashboard/package.json +8 -5
- package/packages/dashboard/public/logo.jpg +0 -0
- package/packages/dashboard/server/executor.js +1 -1
- package/packages/dashboard/server/index.js +336 -113
- package/packages/dashboard/server/parser.js +333 -29
- package/packages/dashboard/server/watcher.js +203 -131
- package/packages/dashboard/src/App.vue +187 -11
- package/packages/dashboard/src/components/ActionBar.vue +26 -42
- package/packages/dashboard/src/components/CommandPalette.vue +40 -65
- package/packages/dashboard/src/components/DetailPanel.vue +68 -53
- package/packages/dashboard/src/components/DocPreview.vue +160 -0
- package/packages/dashboard/src/components/DocTree.vue +58 -0
- package/packages/dashboard/src/components/LogStream.vue +13 -33
- package/packages/dashboard/src/components/PipelineStage.vue +8 -8
- package/packages/dashboard/src/components/PipelineView.vue +80 -45
- package/packages/dashboard/src/components/ProjectList.vue +103 -45
- package/packages/dashboard/src/components/ProjectOverview.vue +178 -0
- package/packages/dashboard/src/components/StageBadge.vue +13 -13
- package/packages/dashboard/src/components/StepCard.vue +15 -15
- package/packages/dashboard/src/components/detail/DocsDetail.vue +48 -0
- package/packages/dashboard/src/components/detail/GitDetail.vue +61 -0
- package/packages/dashboard/src/components/detail/TechDetail.vue +43 -0
- package/packages/dashboard/src/composables/useDashboard.js +20 -6
- package/packages/dashboard/src/composables/useKeyboard.js +6 -4
- package/packages/dashboard/src/main.js +4 -1
- package/packages/dashboard/src/style.css +17 -17
- package/src/index.js +136 -14
- package/src/init.js +83 -228
- package/src/migrate.js +117 -0
- package/src/progress.js +459 -0
- package/src/run.js +624 -0
- package/src/setup.js +2 -72
- package/src/stages/archive.js +54 -0
- package/src/stages/brainstorm.js +239 -0
- package/src/stages/doctor.js +303 -0
- package/src/stages/execute.js +262 -0
- package/src/stages/index.js +26 -0
- package/src/stages/plan.js +282 -0
- package/src/stages/propose.js +115 -0
- package/src/stages/quick.js +64 -0
- package/src/stages/scan.js +141 -0
- package/src/stages/status.js +65 -0
- package/src/stages/verify.js +135 -0
- package/docs/.vitepress/config.mts +0 -45
- package/docs/.vitepress/dist/404.html +0 -25
- package/docs/.vitepress/dist/assets/app.YytxICdd.js +0 -1
- package/docs/.vitepress/dist/assets/chunks/framework.Czhw_PXq.js +0 -19
- package/docs/.vitepress/dist/assets/chunks/theme.DusTRZQk.js +0 -1
- package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.js +0 -1
- package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.lean.js +0 -1
- 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 +0 -15
- package/docs/.vitepress/dist/assets/sillyspec_commands.md.CXFFsj08.lean.js +0 -1
- package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.js +0 -4
- package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.lean.js +0 -1
- package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.js +0 -1
- package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.lean.js +0 -1
- package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.js +0 -4
- package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.lean.js +0 -1
- package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.js +0 -5
- package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.lean.js +0 -1
- package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.js +0 -28
- package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.lean.js +0 -1
- package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.js +0 -30
- package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.lean.js +0 -1
- package/docs/.vitepress/dist/assets/style.DFTx90Kk.css +0 -1
- package/docs/.vitepress/dist/hashmap.json +0 -1
- package/docs/.vitepress/dist/index.html +0 -28
- package/docs/.vitepress/dist/sillyspec/commands.html +0 -42
- package/docs/.vitepress/dist/sillyspec/dashboard.html +0 -31
- package/docs/.vitepress/dist/sillyspec/file-io.html +0 -28
- package/docs/.vitepress/dist/sillyspec/getting-started.html +0 -31
- package/docs/.vitepress/dist/sillyspec/install.html +0 -32
- package/docs/.vitepress/dist/sillyspec/lifecycle.html +0 -55
- package/docs/.vitepress/dist/sillyspec/structure.html +0 -57
- package/docs/.vitepress/dist/vp-icons.css +0 -1
- package/docs/index.md +0 -34
- package/docs/sillyspec/commands.md +0 -218
- package/docs/sillyspec/dashboard.md +0 -51
- package/docs/sillyspec/file-io.md +0 -34
- package/docs/sillyspec/getting-started.md +0 -61
- package/docs/sillyspec/install.md +0 -51
- package/docs/sillyspec/lifecycle.md +0 -146
- package/docs/sillyspec/structure.md +0 -62
- package/packages/dashboard/dist/assets/index-Bh-GPjKY.css +0 -1
- package/packages/dashboard/dist/assets/index-CrCn5Gg6.js +0 -17
- package/templates/archive.md +0 -120
- package/templates/brainstorm.md +0 -170
- package/templates/continue.md +0 -32
- package/templates/execute.md +0 -304
- package/templates/explore.md +0 -59
- package/templates/export.md +0 -21
- package/templates/init.md +0 -61
- package/templates/plan.md +0 -146
- package/templates/quick.md +0 -135
- package/templates/scan-quick.md +0 -49
- package/templates/scan.md +0 -156
- package/templates/skills/playwright-e2e/SKILL.md +0 -340
- package/templates/status.md +0 -75
- package/templates/verify.md +0 -236
- package/templates/workspace-sync.md +0 -99
- package/templates/workspace.md +0 -70
- /package/.sillyspec/{specs → changes/brainstorm-archive}/2026-04-05-dashboard-design.md +0 -0
- /package/{docs/.vitepress/dist/logo.jpg → logo.jpg} +0 -0
- /package/{docs/.vitepress → packages/dashboard}/dist/favicon.jpg +0 -0
- /package/{docs/public → packages/dashboard/dist}/logo.jpg +0 -0
- /package/{docs → packages/dashboard}/public/favicon.jpg +0 -0
package/src/index.js
CHANGED
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
* SillySpec CLI — 安装工具
|
|
5
5
|
*
|
|
6
6
|
* 只负责两件事:init(安装命令模板)和 setup(安装 MCP 工具)。
|
|
7
|
-
*
|
|
7
|
+
* 状态管理通过 progress.json 完成,使用 `sillyspec progress` 命令。
|
|
8
8
|
*/
|
|
9
|
-
import { existsSync } from 'fs';
|
|
10
|
-
import { resolve } from 'path';
|
|
9
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
|
|
10
|
+
import { join, resolve } from 'path';
|
|
11
11
|
import { cmdInit, getVersion } from './init.js';
|
|
12
|
+
import { ProgressManager } from './progress.js';
|
|
12
13
|
|
|
13
14
|
// ── CLI 入口 ──
|
|
14
15
|
|
|
@@ -19,11 +20,32 @@ SillySpec CLI — 规范驱动开发工具包
|
|
|
19
20
|
用法:
|
|
20
21
|
sillyspec init 初始化(零交互,自动检测工具)
|
|
21
22
|
[--tool <name>] 只安装指定工具
|
|
22
|
-
[--workspace] 工作区模式
|
|
23
23
|
[--interactive] 交互式引导
|
|
24
24
|
[--dir <path>] 指定目录
|
|
25
|
+
|
|
25
26
|
sillyspec setup [--list] 安装推荐 MCP 工具
|
|
26
27
|
[--list] 查看已安装状态
|
|
28
|
+
|
|
29
|
+
sillyspec run <stage> 执行阶段步骤(核心命令)
|
|
30
|
+
--done --output "..." 完成当前步骤
|
|
31
|
+
--skip 跳过可选步骤
|
|
32
|
+
--status 查看阶段进度
|
|
33
|
+
--reset 重置阶段
|
|
34
|
+
--change <name> 设置当前变更名
|
|
35
|
+
auto 连续推进 brainstorm→plan→execute→verify
|
|
36
|
+
|
|
37
|
+
sillyspec progress <cmd> 进度记录(轻量,不强制顺序)
|
|
38
|
+
init 初始化 progress.json
|
|
39
|
+
show 查看当前进度
|
|
40
|
+
set-stage <stage> 设置当前阶段
|
|
41
|
+
add-step <stage> <name> 添加步骤
|
|
42
|
+
update-step <s> <n> --status <st> [--output <t>]
|
|
43
|
+
complete-stage <stage> 标记阶段完成
|
|
44
|
+
validate 校验并修复
|
|
45
|
+
reset [--stage X] 重置进度
|
|
46
|
+
|
|
47
|
+
sillyspec docs migrate 迁移旧文档到统一结构
|
|
48
|
+
|
|
27
49
|
sillyspec dashboard 启动 Dashboard Web UI
|
|
28
50
|
[--port <number>] 指定端口(默认 3456)
|
|
29
51
|
[--no-open] 不自动打开浏览器
|
|
@@ -34,11 +56,9 @@ SillySpec CLI — 规范驱动开发工具包
|
|
|
34
56
|
|
|
35
57
|
示例:
|
|
36
58
|
sillyspec init
|
|
37
|
-
sillyspec
|
|
38
|
-
sillyspec
|
|
39
|
-
sillyspec setup
|
|
59
|
+
sillyspec run brainstorm
|
|
60
|
+
sillyspec run brainstorm --done --output "需求已澄清"
|
|
40
61
|
sillyspec setup --list
|
|
41
|
-
sillyspec dashboard
|
|
42
62
|
sillyspec dashboard --port 8080 --no-open
|
|
43
63
|
`);
|
|
44
64
|
}
|
|
@@ -60,7 +80,6 @@ async function main() {
|
|
|
60
80
|
let json = false;
|
|
61
81
|
let targetDir = process.cwd();
|
|
62
82
|
let tool = null;
|
|
63
|
-
let workspace = false;
|
|
64
83
|
let interactive = false;
|
|
65
84
|
const filteredArgs = [];
|
|
66
85
|
|
|
@@ -73,8 +92,6 @@ async function main() {
|
|
|
73
92
|
} else if (args[i] === '--tool' && args[i + 1]) {
|
|
74
93
|
tool = args[i + 1];
|
|
75
94
|
i++;
|
|
76
|
-
} else if (args[i] === '--workspace' || args[i] === '-w') {
|
|
77
|
-
workspace = true;
|
|
78
95
|
} else if (args[i] === '--interactive' || args[i] === '-i') {
|
|
79
96
|
interactive = true;
|
|
80
97
|
} else if (args[i] === '--list' || args[i] === '-l') {
|
|
@@ -85,8 +102,18 @@ async function main() {
|
|
|
85
102
|
}
|
|
86
103
|
|
|
87
104
|
const command = filteredArgs[0];
|
|
105
|
+
// 支持 sillyspec init /path/to/project 语法:如果第二个参数看起来像路径,当作 targetDir
|
|
106
|
+
if (command === 'init' && filteredArgs[1] && !filteredArgs[1].startsWith('-')) {
|
|
107
|
+
targetDir = resolve(filteredArgs[1]);
|
|
108
|
+
filteredArgs.splice(1, 1);
|
|
109
|
+
}
|
|
88
110
|
const dir = targetDir;
|
|
89
111
|
|
|
112
|
+
if (command === 'init' && !existsSync(dir)) {
|
|
113
|
+
const { mkdirSync } = await import('fs');
|
|
114
|
+
mkdirSync(dir, { recursive: true });
|
|
115
|
+
}
|
|
116
|
+
|
|
90
117
|
if (!existsSync(dir)) {
|
|
91
118
|
console.error(`❌ 目录不存在: ${dir}`);
|
|
92
119
|
process.exit(1);
|
|
@@ -94,15 +121,110 @@ async function main() {
|
|
|
94
121
|
|
|
95
122
|
switch (command) {
|
|
96
123
|
case 'init':
|
|
97
|
-
await cmdInit(dir, { tool,
|
|
124
|
+
await cmdInit(dir, { tool, interactive });
|
|
98
125
|
break;
|
|
99
126
|
case 'setup':
|
|
100
127
|
const setupList = filteredArgs.includes('--list') || filteredArgs.includes('-l');
|
|
101
128
|
await (await import('./setup.js')).cmdSetup(dir, { json, list: setupList });
|
|
102
129
|
break;
|
|
103
|
-
case 'progress':
|
|
104
|
-
|
|
130
|
+
case 'progress': {
|
|
131
|
+
const pm = new ProgressManager();
|
|
132
|
+
const subCommand = filteredArgs[1];
|
|
133
|
+
const stageIdx = filteredArgs.indexOf('--stage');
|
|
134
|
+
const stage = stageIdx >= 0 && filteredArgs[stageIdx + 1] ? filteredArgs[stageIdx + 1] : null;
|
|
135
|
+
|
|
136
|
+
switch (subCommand) {
|
|
137
|
+
case 'init':
|
|
138
|
+
pm.init(dir);
|
|
139
|
+
break;
|
|
140
|
+
case 'status':
|
|
141
|
+
case 'show':
|
|
142
|
+
pm.show(dir);
|
|
143
|
+
break;
|
|
144
|
+
case 'validate':
|
|
145
|
+
await pm.validate(dir);
|
|
146
|
+
break;
|
|
147
|
+
case 'reset':
|
|
148
|
+
pm.reset(dir, stage);
|
|
149
|
+
break;
|
|
150
|
+
case 'set-stage': {
|
|
151
|
+
const setStageName = filteredArgs[2];
|
|
152
|
+
if (!setStageName) { console.log('❌ 用法: sillyspec progress set-stage <stage>'); break; }
|
|
153
|
+
pm.setStage(dir, setStageName);
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case 'add-step': {
|
|
157
|
+
const addStepStage = filteredArgs[2];
|
|
158
|
+
const addStepName = filteredArgs[3];
|
|
159
|
+
if (!addStepStage || !addStepName) { console.log('❌ 用法: sillyspec progress add-step <stage> <step-name>'); break; }
|
|
160
|
+
pm.addStep(dir, addStepStage, addStepName);
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case 'update-step': {
|
|
164
|
+
const updStepStage = filteredArgs[2];
|
|
165
|
+
const updStepName = filteredArgs[3];
|
|
166
|
+
if (!updStepStage || !updStepName) { console.log('❌ 用法: sillyspec progress update-step <stage> <step-name> --status <status> [--output <text>]'); break; }
|
|
167
|
+
// Parse --status and --output from args
|
|
168
|
+
let updStatus = null, updOutput = undefined;
|
|
169
|
+
for (let ai = 0; ai < args.length; ai++) {
|
|
170
|
+
if (args[ai] === '--status' && args[ai + 1]) { updStatus = args[ai + 1]; ai++; }
|
|
171
|
+
if (args[ai] === '--output' && args[ai + 1]) { updOutput = args[ai + 1]; ai++; }
|
|
172
|
+
}
|
|
173
|
+
pm.updateStep(dir, updStepStage, updStepName, { status: updStatus, output: updOutput });
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
case 'complete-stage': {
|
|
177
|
+
const compStageName = filteredArgs[2];
|
|
178
|
+
if (!compStageName) { console.log('❌ 用法: sillyspec progress complete-stage <stage>'); break; }
|
|
179
|
+
pm.completeStage(dir, compStageName);
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
case 'batch': {
|
|
183
|
+
if (filteredArgs.includes('--status')) {
|
|
184
|
+
const bp = pm.readBatchProgress(dir);
|
|
185
|
+
if (!bp) { console.log('📭 无批量进度数据'); break; }
|
|
186
|
+
const line = pm._renderBatchProgress(bp);
|
|
187
|
+
console.log(line || '📭 无批量进度数据');
|
|
188
|
+
console.log(JSON.stringify(bp, null, 2));
|
|
189
|
+
} else {
|
|
190
|
+
let batchData = {};
|
|
191
|
+
const a = args;
|
|
192
|
+
for (let i = 0; i < a.length; i++) {
|
|
193
|
+
if (a[i] === '--total' && a[i + 1]) { batchData.total = parseInt(a[i + 1]); i++; }
|
|
194
|
+
if (a[i] === '--completed' && a[i + 1]) { batchData.completed = parseInt(a[i + 1]); i++; }
|
|
195
|
+
if (a[i] === '--failed' && a[i + 1]) { batchData.failed = parseInt(a[i + 1]); i++; }
|
|
196
|
+
if (a[i] === '--skipped' && a[i + 1]) { batchData.skipped = parseInt(a[i + 1]); i++; }
|
|
197
|
+
}
|
|
198
|
+
if (Object.keys(batchData).length === 0) {
|
|
199
|
+
console.log('用法: sillyspec progress batch --total 100 --completed 73');
|
|
200
|
+
console.log(' sillyspec progress batch --status');
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
pm.updateBatchProgress(dir, batchData);
|
|
204
|
+
console.log('✅ 批量进度已更新');
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
default:
|
|
209
|
+
console.log('用法: sillyspec progress <init|show|validate|reset|set-stage|add-step|update-step|complete-stage>');
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
case 'docs': {
|
|
214
|
+
const docsSubCmd = filteredArgs[1];
|
|
215
|
+
if (docsSubCmd === 'migrate') {
|
|
216
|
+
const { migrateDocs } = await import('./migrate.js');
|
|
217
|
+
migrateDocs(dir);
|
|
218
|
+
} else {
|
|
219
|
+
console.log('用法: sillyspec docs migrate');
|
|
220
|
+
}
|
|
105
221
|
break;
|
|
222
|
+
}
|
|
223
|
+
case 'run': {
|
|
224
|
+
const { runCommand } = await import('./run.js')
|
|
225
|
+
await runCommand(filteredArgs.slice(1), dir)
|
|
226
|
+
break
|
|
227
|
+
}
|
|
106
228
|
case 'dashboard': {
|
|
107
229
|
// Parse dashboard options
|
|
108
230
|
let port = 3456;
|
package/src/init.js
CHANGED
|
@@ -1,55 +1,31 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync,
|
|
2
|
-
import { join, resolve, dirname } from 'path';
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, statSync } from 'fs';
|
|
2
|
+
import { join, resolve, dirname, basename } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { checkbox, confirm, input } from '@inquirer/prompts';
|
|
5
|
+
import { ProgressManager } from './progress.js';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
-
import ora from 'ora';
|
|
8
7
|
|
|
9
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
9
|
const __dirname = dirname(__filename);
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
// ── 递归复制目录 ──
|
|
12
|
+
function copyDirSync(src, dst) {
|
|
13
|
+
mkdirSync(dst, { recursive: true });
|
|
14
|
+
for (const entry of readdirSync(src, { withFileTypes: true })) {
|
|
15
|
+
if (entry.name === 'node_modules' || entry.name === '.git') continue;
|
|
16
|
+
const srcPath = join(src, entry.name);
|
|
17
|
+
const dstPath = join(dst, entry.name);
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
copyDirSync(srcPath, dstPath);
|
|
20
|
+
} else if (entry.name.endsWith('.md')) {
|
|
21
|
+
writeFileSync(dstPath, readFileSync(srcPath));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
12
25
|
|
|
13
26
|
// ── 元数据映射 ──
|
|
14
27
|
|
|
15
|
-
const DESCRIPTIONS = {
|
|
16
|
-
init: '绿地项目初始化 — 深度提问、调研、需求文档、路线图',
|
|
17
|
-
scan: '代码库扫描 — 支持快速扫描和深度扫描两阶段',
|
|
18
|
-
explore: '自由思考模式 — 讨论、画图、调研,不写代码',
|
|
19
|
-
brainstorm: '需求探索 — 结构化头脑风暴,生成设计文档(创建性工作前必用)',
|
|
20
|
-
plan: '编写实现计划 — 任务拆分与实现路径',
|
|
21
|
-
execute: '波次执行 — 子代理并行 + 强制 TDD + 两阶段审查',
|
|
22
|
-
verify: '验证实现 — 对照规范检查 + 测试套件',
|
|
23
|
-
archive: '归档变更 — 规范沉淀,可追溯',
|
|
24
|
-
commit: '智能提交 — 自动收集变更信息,生成 commit message',
|
|
25
|
-
status: '查看项目进度和状态',
|
|
26
|
-
continue: '自动判断并执行下一步',
|
|
27
|
-
state: '查看当前工作状态 — 显示 STATE.md 内容',
|
|
28
|
-
|
|
29
|
-
quick: '快速任务 — 跳过完整流程,直接做',
|
|
30
|
-
workspace: '工作区管理 — 初始化、管理多项目工作区,查看子项目状态',
|
|
31
|
-
export: '导出成功方案为可复用模板',
|
|
32
|
-
};
|
|
33
28
|
|
|
34
|
-
const ARG_HINTS = {
|
|
35
|
-
init: '[项目名]',
|
|
36
|
-
scan: '[可选:指定区域,如 \'api\' 或 \'auth\'] [--deep 深度扫描]',
|
|
37
|
-
explore: '[探索主题]',
|
|
38
|
-
brainstorm: '[需求或想法描述]',
|
|
39
|
-
|
|
40
|
-
plan: '[计划名]',
|
|
41
|
-
execute: '[任务编号或 \'all\']',
|
|
42
|
-
verify: '[可选:指定验证范围]',
|
|
43
|
-
archive: '[变更名]',
|
|
44
|
-
commit: '[可选:自定义 commit message]',
|
|
45
|
-
status: '',
|
|
46
|
-
continue: '',
|
|
47
|
-
state: '[可选备注]',
|
|
48
|
-
|
|
49
|
-
quick: '[任务描述]',
|
|
50
|
-
workspace: '[可选:add/remove/status/info]',
|
|
51
|
-
export: '<change-name> [--to <path>]',
|
|
52
|
-
};
|
|
53
29
|
|
|
54
30
|
const VALID_TOOLS = ['claude', 'claude_skills', 'cursor', 'openclaw', 'codex', 'gemini', 'opencode'];
|
|
55
31
|
|
|
@@ -63,8 +39,6 @@ const TOOL_LABELS = {
|
|
|
63
39
|
opencode: 'OpenCode (通过 INSTRUCTIONS.md)',
|
|
64
40
|
};
|
|
65
41
|
|
|
66
|
-
|
|
67
|
-
// 指令文件工具:注入规范引用到指令文件
|
|
68
42
|
const INSTRUCTION_TOOLS = ['codex', 'gemini', 'opencode'];
|
|
69
43
|
|
|
70
44
|
const INSTRUCTION_FILE_MAP = {
|
|
@@ -78,83 +52,16 @@ const INJECTION_CONTENT = `## SillySpec — 规范驱动开发
|
|
|
78
52
|
在执行开发任务时,遵循以下规范:
|
|
79
53
|
|
|
80
54
|
### 代码规范
|
|
81
|
-
- 写代码前先读取 \`.sillyspec/
|
|
55
|
+
- 写代码前先读取 \`.sillyspec/docs/<project>/scan/CONVENTIONS.md\`(代码风格)和 \`.sillyspec/docs/<project>/scan/ARCHITECTURE.md\`(架构)
|
|
82
56
|
- 调用已有方法前,用 grep 确认方法存在,不许编造
|
|
83
|
-
- 遵循 \`.sillyspec/
|
|
57
|
+
- 遵循 \`.sillyspec/docs/<project>/scan/CONVENTIONS.md\` 中的代码风格
|
|
84
58
|
|
|
85
59
|
### 工作流程
|
|
86
|
-
- 读取 \`.sillyspec/
|
|
60
|
+
- 读取 \`.sillyspec/.runtime/progress.json\` 确认当前阶段(使用 \`sillyspec progress show\`)
|
|
87
61
|
- 各阶段产出文件位于 \`.sillyspec/changes/<变更名>/\` 下
|
|
88
|
-
- 详细流程参考模板文件:\`.sillyspec/.templates/\`(brainstorm.md, plan.md, execute.md 等)
|
|
89
62
|
`;
|
|
90
63
|
|
|
91
|
-
// ──
|
|
92
|
-
|
|
93
|
-
function generateClaude(projectDir, name, desc, body, argHint, version) {
|
|
94
|
-
const outDir = join(projectDir, '.claude', 'commands', 'sillyspec');
|
|
95
|
-
mkdirSync(outDir, { recursive: true });
|
|
96
|
-
writeFileSync(join(outDir, `${name}.md`),
|
|
97
|
-
`---
|
|
98
|
-
description: ${desc}
|
|
99
|
-
argument-hint: "${argHint}"
|
|
100
|
-
version: "${version}"
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
${body}`
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function generateClaudeSkills(projectDir, name, desc, body, argHint, version) {
|
|
108
|
-
const outDir = join(projectDir, '.claude', 'skills', `sillyspec-${name}`);
|
|
109
|
-
mkdirSync(outDir, { recursive: true });
|
|
110
|
-
writeFileSync(join(outDir, 'SKILL.md'),
|
|
111
|
-
`---
|
|
112
|
-
name: sillyspec:${name}
|
|
113
|
-
description: ${desc}
|
|
114
|
-
version: "${version}"
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
${body}`
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function generateCursor(projectDir, name, desc, body, argHint, version) {
|
|
122
|
-
const outDir = join(projectDir, '.cursor', 'commands');
|
|
123
|
-
mkdirSync(outDir, { recursive: true });
|
|
124
|
-
writeFileSync(join(outDir, `sillyspec-${name}.md`),
|
|
125
|
-
`---
|
|
126
|
-
name: /sillyspec-${name}
|
|
127
|
-
id: sillyspec-${name}
|
|
128
|
-
description: ${desc}
|
|
129
|
-
version: "${version}"
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
${body}`
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function generateOpenclaw(projectDir, name, desc, body, argHint, version) {
|
|
137
|
-
const outDir = join(projectDir, '.openclaw', 'skills', `sillyspec-${name}`);
|
|
138
|
-
mkdirSync(outDir, { recursive: true });
|
|
139
|
-
writeFileSync(join(outDir, 'SKILL.md'),
|
|
140
|
-
`---
|
|
141
|
-
name: sillyspec:${name}
|
|
142
|
-
description: ${desc}
|
|
143
|
-
version: "${version}"
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
${body}`
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const GENERATORS = {
|
|
151
|
-
claude: generateClaude,
|
|
152
|
-
claude_skills: generateClaudeSkills,
|
|
153
|
-
cursor: generateCursor,
|
|
154
|
-
openclaw: generateOpenclaw,
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
// ── 指令文件注入 ──
|
|
64
|
+
// ── 注入指令文件 ──
|
|
158
65
|
|
|
159
66
|
function injectInstructions(tool, projectDir) {
|
|
160
67
|
const fileName = INSTRUCTION_FILE_MAP[tool];
|
|
@@ -198,22 +105,33 @@ function isTTY() {
|
|
|
198
105
|
|
|
199
106
|
// ── 核心安装逻辑 ──
|
|
200
107
|
|
|
201
|
-
async function doInstall(projectDir, tools,
|
|
108
|
+
async function doInstall(projectDir, tools, subprojects = []) {
|
|
202
109
|
// 创建基础目录
|
|
203
|
-
// .sillyspec/
|
|
204
|
-
// .sillyspec/
|
|
205
|
-
// .sillyspec/
|
|
206
|
-
// .sillyspec/
|
|
207
|
-
|
|
208
|
-
//
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
110
|
+
// .sillyspec/projects/ → 项目注册表
|
|
111
|
+
// .sillyspec/docs/<name>/ → 统一文档中心
|
|
112
|
+
// .sillyspec/knowledge/ → 跨项目共享知识库
|
|
113
|
+
// .sillyspec/.runtime/ → progress (gitignored)
|
|
114
|
+
|
|
115
|
+
// 注册当前项目到 projects/
|
|
116
|
+
const projectName = basename(projectDir) || 'project';
|
|
117
|
+
const projectsDir = join(projectDir, '.sillyspec', 'projects');
|
|
118
|
+
mkdirSync(projectsDir, { recursive: true });
|
|
119
|
+
const projectYamlPath = join(projectsDir, `${projectName}.yaml`);
|
|
120
|
+
if (!existsSync(projectYamlPath)) {
|
|
121
|
+
writeFileSync(projectYamlPath, `name: ${projectName}\npath: .\nstatus: active\n`);
|
|
214
122
|
}
|
|
215
123
|
|
|
216
|
-
//
|
|
124
|
+
// 创建 docs/<projectName>/scan/ 子目录(代码扫描结果)
|
|
125
|
+
const scanDir = join(projectDir, '.sillyspec', 'docs', projectName, 'scan');
|
|
126
|
+
mkdirSync(scanDir, { recursive: true });
|
|
127
|
+
const gitkeepPath = join(scanDir, '.gitkeep');
|
|
128
|
+
if (!existsSync(gitkeepPath)) writeFileSync(gitkeepPath, '');
|
|
129
|
+
|
|
130
|
+
// 创建 shared/workspace 目录
|
|
131
|
+
mkdirSync(join(projectDir, '.sillyspec', 'shared'), { recursive: true });
|
|
132
|
+
mkdirSync(join(projectDir, '.sillyspec', 'workspace'), { recursive: true });
|
|
133
|
+
|
|
134
|
+
// 创建知识库骨架
|
|
217
135
|
const knowledgeDir = join(projectDir, '.sillyspec', 'knowledge');
|
|
218
136
|
mkdirSync(knowledgeDir, { recursive: true });
|
|
219
137
|
const indexPath = join(knowledgeDir, 'INDEX.md');
|
|
@@ -231,6 +149,13 @@ async function doInstall(projectDir, tools, isWorkspace, subprojects = []) {
|
|
|
231
149
|
mkdirSync(join(runtimeDir, sub), { recursive: true });
|
|
232
150
|
}
|
|
233
151
|
|
|
152
|
+
// 创建初始 progress.json
|
|
153
|
+
const progressPath = join(runtimeDir, 'progress.json');
|
|
154
|
+
if (!existsSync(progressPath)) {
|
|
155
|
+
const pm = new ProgressManager();
|
|
156
|
+
pm.init(projectDir);
|
|
157
|
+
}
|
|
158
|
+
|
|
234
159
|
// 创建初始 user-inputs.md
|
|
235
160
|
const inputsPath = join(runtimeDir, 'user-inputs.md');
|
|
236
161
|
if (!existsSync(inputsPath)) {
|
|
@@ -238,7 +163,7 @@ async function doInstall(projectDir, tools, isWorkspace, subprojects = []) {
|
|
|
238
163
|
}
|
|
239
164
|
|
|
240
165
|
const gitignorePath = join(projectDir, '.gitignore');
|
|
241
|
-
const ignoreRules = ['.sillyspec/
|
|
166
|
+
const ignoreRules = ['.sillyspec/codebase/SCAN-RAW.md', '.sillyspec/local.yaml', '.sillyspec/.runtime/'];
|
|
242
167
|
if (existsSync(gitignorePath)) {
|
|
243
168
|
const content = readFileSync(gitignorePath, 'utf8');
|
|
244
169
|
let updated = content.trimEnd();
|
|
@@ -252,83 +177,35 @@ async function doInstall(projectDir, tools, isWorkspace, subprojects = []) {
|
|
|
252
177
|
writeFileSync(gitignorePath, ignoreRules.join('\n') + '\n');
|
|
253
178
|
}
|
|
254
179
|
|
|
255
|
-
//
|
|
256
|
-
const templateFiles = readdirSync(TEMPLATE_DIR).filter(f => f.endsWith('.md'));
|
|
257
|
-
let count = 0;
|
|
258
|
-
|
|
180
|
+
// 注入指令文件(codex/gemini/opencode)
|
|
259
181
|
for (let i = 0; i < tools.length; i++) {
|
|
260
182
|
const toolName = tools[i];
|
|
261
|
-
const label = TOOL_LABELS[toolName] || toolName;
|
|
262
|
-
|
|
263
183
|
if (INSTRUCTION_TOOLS.includes(toolName)) {
|
|
264
|
-
|
|
265
|
-
try {
|
|
266
|
-
injectInstructions(toolName, projectDir);
|
|
267
|
-
// 复制模板文件到 .sillyspec/.templates/
|
|
268
|
-
const templatesSourceDir = join(TEMPLATE_DIR);
|
|
269
|
-
const templatesDir = join(projectDir, '.sillyspec', '.templates');
|
|
270
|
-
if (!existsSync(templatesDir)) {
|
|
271
|
-
mkdirSync(templatesDir, { recursive: true });
|
|
272
|
-
for (const file of readdirSync(templatesSourceDir)) {
|
|
273
|
-
if (file.endsWith('.md')) {
|
|
274
|
-
copyFileSync(join(templatesSourceDir, file), join(templatesDir, file));
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
spinner.succeed(`${label} 完成`);
|
|
279
|
-
count++;
|
|
280
|
-
} catch (err) {
|
|
281
|
-
spinner.fail(`${label} 失败: ${err.message}`);
|
|
282
|
-
throw err;
|
|
283
|
-
}
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const spinner = ora(`安装 ${label}... (${i + 1}/${tools.length})`).start();
|
|
288
|
-
try {
|
|
289
|
-
const gen = GENERATORS[toolName];
|
|
290
|
-
const ver = getVersion();
|
|
291
|
-
for (const file of templateFiles) {
|
|
292
|
-
const name = file.replace('.md', '');
|
|
293
|
-
const desc = DESCRIPTIONS[name] || `SillySpec ${name}`;
|
|
294
|
-
const argHint = ARG_HINTS[name] || '';
|
|
295
|
-
const body = readFileSync(join(TEMPLATE_DIR, file), 'utf8');
|
|
296
|
-
gen(projectDir, name, desc, body, argHint, ver);
|
|
297
|
-
count++;
|
|
298
|
-
}
|
|
299
|
-
spinner.succeed(`${label} 完成`);
|
|
300
|
-
} catch (err) {
|
|
301
|
-
spinner.fail(`${label} 失败: ${err.message}`);
|
|
302
|
-
throw err;
|
|
184
|
+
injectInstructions(toolName, projectDir);
|
|
303
185
|
}
|
|
304
186
|
}
|
|
305
187
|
|
|
306
|
-
//
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
name: ${p.name}
|
|
316
|
-
path: ${p.path}
|
|
317
|
-
role: ${p.role || p.name}${p.repo ? `\nrepo: ${p.repo}` : ''}
|
|
318
|
-
`
|
|
319
|
-
);
|
|
188
|
+
// 复制 skills 到 .claude/skills/(给 Claude Code 使用)
|
|
189
|
+
const claudeSkillsDir = join(projectDir, '.claude', 'skills');
|
|
190
|
+
const skillsSource = join(__dirname, '..', '.claude', 'skills');
|
|
191
|
+
if (existsSync(skillsSource)) {
|
|
192
|
+
const sillyspecSkills = readdirSync(skillsSource).filter(f => f.startsWith('sillyspec-') && statSync(join(skillsSource, f)).isDirectory());
|
|
193
|
+
if (sillyspecSkills.length > 0) {
|
|
194
|
+
mkdirSync(claudeSkillsDir, { recursive: true });
|
|
195
|
+
for (const skill of sillyspecSkills) {
|
|
196
|
+
copyDirSync(join(skillsSource, skill), join(claudeSkillsDir, skill));
|
|
320
197
|
}
|
|
198
|
+
console.log(chalk.green(' ✓ Claude Code skills 已同步 (' + sillyspecSkills.length + ' 个)'));
|
|
321
199
|
}
|
|
200
|
+
} else {
|
|
201
|
+
console.log(chalk.yellow(' ⚠ 未找到 skills 目录(npm 包内无 .claude/skills/),跳过同步'));
|
|
322
202
|
}
|
|
323
|
-
|
|
324
|
-
return count;
|
|
325
203
|
}
|
|
326
204
|
|
|
327
205
|
// ── 安装完成总结 ──
|
|
328
206
|
|
|
329
|
-
function showSummary(version, tools
|
|
207
|
+
function showSummary(version, tools) {
|
|
330
208
|
const toolLabels = tools.map(t => TOOL_LABELS[t] || t);
|
|
331
|
-
const mode = isWorkspace ? '多项目工作区' : '单项目';
|
|
332
209
|
|
|
333
210
|
console.log('');
|
|
334
211
|
console.log(chalk.green(' ═══════════════════════════════════════'));
|
|
@@ -336,20 +213,13 @@ function showSummary(version, tools, isWorkspace, count) {
|
|
|
336
213
|
console.log(chalk.green(' ═══════════════════════════════════════'));
|
|
337
214
|
console.log('');
|
|
338
215
|
console.log(` 已安装工具: ${chalk.cyan(toolLabels.join(', '))}`);
|
|
339
|
-
console.log(` 模式: ${chalk.yellow(mode)}`);
|
|
340
|
-
console.log('');
|
|
341
|
-
console.log(` 📄 ${count} 个命令已就绪`);
|
|
342
216
|
console.log(' 📁 .sillyspec/ — 项目规范目录');
|
|
343
217
|
console.log('');
|
|
344
|
-
console.log('
|
|
345
|
-
console.log('
|
|
346
|
-
console.log('
|
|
347
|
-
console.log(' 自由思考:' + chalk.bold('/sillyspec:explore "你的想法"'));
|
|
348
|
-
console.log('');
|
|
349
|
-
console.log(chalk.gray(' 重启你的 AI 工具以使 slash commands 生效。'));
|
|
218
|
+
console.log(' 下一步:使用 AI 技能开始工作');
|
|
219
|
+
console.log(' OpenClaw: ' + chalk.bold('/sillyspec:brainstorm'));
|
|
220
|
+
console.log(' Claude Code: ' + chalk.bold('/sillyspec:brainstorm'));
|
|
350
221
|
console.log('');
|
|
351
222
|
console.log(chalk.dim(' 💡 推荐安装 MCP 工具增强 AI 能力:sillyspec setup'));
|
|
352
|
-
console.log(chalk.dim(' Context7 — 查最新文档 | grep.app — 搜开源实现 | Chrome DevTools — 浏览器自动化'));
|
|
353
223
|
console.log('');
|
|
354
224
|
}
|
|
355
225
|
|
|
@@ -367,7 +237,7 @@ export function getVersion() {
|
|
|
367
237
|
// ── 主命令 ──
|
|
368
238
|
|
|
369
239
|
export async function cmdInit(projectDir, options = {}) {
|
|
370
|
-
const { tool,
|
|
240
|
+
const { tool, interactive } = options;
|
|
371
241
|
const version = getVersion();
|
|
372
242
|
|
|
373
243
|
// ── 交互式模式(--interactive 或 -i)──
|
|
@@ -399,20 +269,11 @@ export async function cmdInit(projectDir, options = {}) {
|
|
|
399
269
|
validate: (answer) => answer.length > 0 || '至少选择一个工具',
|
|
400
270
|
});
|
|
401
271
|
|
|
402
|
-
//
|
|
403
|
-
const isWorkspace = await select({
|
|
404
|
-
message: '选择项目模式',
|
|
405
|
-
choices: [
|
|
406
|
-
{ name: '单项目模式', value: 'false' },
|
|
407
|
-
{ name: '多项目工作区', value: 'true' },
|
|
408
|
-
],
|
|
409
|
-
}) === 'true';
|
|
410
|
-
|
|
411
|
-
// 工作区子项目引导
|
|
272
|
+
// 子项目引导(仅交互模式)
|
|
412
273
|
let subprojects = [];
|
|
413
|
-
|
|
274
|
+
{
|
|
414
275
|
console.log('');
|
|
415
|
-
console.log(chalk.yellow('📋
|
|
276
|
+
console.log(chalk.yellow('📋 添加子项目'));
|
|
416
277
|
console.log(chalk.dim(' 子项目是工作区中的独立项目目录(如 frontend/、backend/)'));
|
|
417
278
|
console.log('');
|
|
418
279
|
|
|
@@ -475,8 +336,8 @@ export async function cmdInit(projectDir, options = {}) {
|
|
|
475
336
|
}
|
|
476
337
|
|
|
477
338
|
console.log('');
|
|
478
|
-
|
|
479
|
-
showSummary(version, selectedTools
|
|
339
|
+
await doInstall(projectDir, selectedTools, subprojects);
|
|
340
|
+
showSummary(version, selectedTools);
|
|
480
341
|
return;
|
|
481
342
|
}
|
|
482
343
|
|
|
@@ -494,23 +355,17 @@ export async function cmdInit(projectDir, options = {}) {
|
|
|
494
355
|
tools = detectTools(projectDir);
|
|
495
356
|
}
|
|
496
357
|
|
|
497
|
-
|
|
358
|
+
await doInstall(projectDir, tools);
|
|
498
359
|
|
|
499
360
|
console.log('');
|
|
500
361
|
console.log(chalk.green(` ✅ SillySpec v${version} 安装完成!`));
|
|
501
362
|
console.log('');
|
|
502
|
-
console.log(` 📄 ${count} 个命令已就绪`);
|
|
503
363
|
console.log(' 📁 .sillyspec/ — 项目规范目录');
|
|
504
364
|
console.log('');
|
|
505
|
-
console.log('
|
|
506
|
-
console.log(`
|
|
507
|
-
console.log(`
|
|
508
|
-
console.log(` 自由探索 → ${chalk.bold('/sillyspec:explore "你的想法"')}`);
|
|
509
|
-
if (workspace) {
|
|
510
|
-
console.log(` 管理子项目 → ${chalk.bold('/sillyspec:workspace add')}`);
|
|
511
|
-
}
|
|
365
|
+
console.log(' 下一步:使用 AI 技能开始工作');
|
|
366
|
+
console.log(` OpenClaw: ${chalk.bold('/sillyspec:brainstorm')}`);
|
|
367
|
+
console.log(` Claude Code: ${chalk.bold('/sillyspec:brainstorm')}`);
|
|
512
368
|
console.log('');
|
|
513
369
|
console.log(chalk.dim(' 💡 增强能力:sillyspec setup(安装 MCP 工具)'));
|
|
514
|
-
console.log(chalk.dim(' 💡 完整配置:sillyspec init --interactive'));
|
|
515
370
|
console.log('');
|
|
516
371
|
}
|