sillyspec 3.7.26 → 3.7.28
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-doctor/SKILL.md +23 -0
- package/.sillyspec/config.yaml +7 -0
- package/package.json +1 -1
- package/packages/dashboard/server/parser.js +1 -1
- package/packages/dashboard/src/components/DetailPanel.vue +1 -1
- package/packages/dashboard/src/components/DocTree.vue +1 -1
- package/packages/dashboard/src/components/StepCard.vue +4 -4
- package/src/index.js +2 -6
- package/src/init.js +24 -40
- package/src/progress.js +6 -1
- package/src/run.js +11 -3
- package/src/stages/archive.js +1 -1
- package/src/stages/brainstorm.js +5 -6
- package/src/stages/doctor.js +303 -0
- package/src/stages/execute.js +1 -1
- package/src/stages/index.js +4 -2
- package/src/stages/plan.js +1 -2
- package/src/stages/propose.js +1 -1
- package/src/stages/scan.js +9 -9
- package/src/stages/status.js +0 -27
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sillyspec:doctor
|
|
3
|
+
description: 项目自检 — 检查 CLI、配置、构建环境和外部依赖
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## 前置检查
|
|
7
|
+
|
|
8
|
+
**在执行任何检查之前,先确认 SillySpec CLI 是否可用:**
|
|
9
|
+
|
|
10
|
+
1. 运行 `sillyspec --version`
|
|
11
|
+
2. 如果失败,运行 `npx sillyspec --version`
|
|
12
|
+
3. 如果都失败:
|
|
13
|
+
- 输出:❌ SillySpec CLI 未安装,后续检查无法执行
|
|
14
|
+
- 给出安装命令:`npm install -g sillyspec`(生产环境)或 `npx sillyspec`(临时使用)
|
|
15
|
+
- 停止,不要继续后续步骤
|
|
16
|
+
|
|
17
|
+
## 执行
|
|
18
|
+
|
|
19
|
+
CLI 可用后,运行 `sillyspec run doctor`,按提示逐步执行。
|
|
20
|
+
每步完成后运行 `sillyspec run doctor --done --output "摘要"`。
|
|
21
|
+
|
|
22
|
+
## 用户指令
|
|
23
|
+
$ARGUMENTS
|
package/package.json
CHANGED
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
<!-- Output -->
|
|
82
82
|
<div v-if="activeStep.output || activeStep.files" class="px-4 py-3" style="border-bottom: 1px solid #F0F0F3;">
|
|
83
83
|
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">输出</h4>
|
|
84
|
-
<n-code v-if="activeStep.output" :code="activeStep.output" language="text" word-wrap style="max-height:
|
|
84
|
+
<n-code v-if="activeStep.output" :code="activeStep.output" language="text" word-wrap style="max-height: 300px; overflow-y: auto; padding: 8px; border-radius: 4px; background: #F5F5F7;" />
|
|
85
85
|
<div v-if="activeStep.files" class="mt-2 space-y-1">
|
|
86
86
|
<div v-for="(file, i) in activeStep.files" :key="i" class="flex items-center gap-2 text-[10px]" style="color: #6B7280;">
|
|
87
87
|
<svg class="w-3 h-3 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
@@ -39,7 +39,7 @@ const groupIcons = {
|
|
|
39
39
|
const treeData = computed(() => {
|
|
40
40
|
return props.groups.map(group => ({
|
|
41
41
|
key: `group-${group.key}`,
|
|
42
|
-
label: group.label,
|
|
42
|
+
label: group.project ? `${group.label} (${group.project})` : group.label,
|
|
43
43
|
prefix: () => groupIcons[group.label] || '📄',
|
|
44
44
|
children: group.files.map(file => ({
|
|
45
45
|
key: file.path,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
:class="['group relative rounded-md cursor-pointer
|
|
3
|
+
:class="['group relative rounded-md cursor-pointer transition-all duration-200']"
|
|
4
4
|
:style="cardStyle"
|
|
5
5
|
@mouseenter="hovered = true"
|
|
6
6
|
@mouseleave="hovered = false"
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<!-- Left accent bar -->
|
|
10
10
|
<div class="absolute left-0 top-0 bottom-0 w-[2px]" :style="{ background: barColor }" />
|
|
11
11
|
|
|
12
|
-
<div class="pl-
|
|
12
|
+
<div class="pl-4 pr-4 py-3">
|
|
13
13
|
<div class="flex items-center gap-2">
|
|
14
14
|
<h3 class="text-[12px] font-medium transition-colors duration-150" :style="{ color: isActive ? '#D97706' : '#1C1C1E', fontFamily: '\'JetBrains Mono\', monospace' }">
|
|
15
15
|
{{ step.title || step.name }}
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
<!-- Hover summary -->
|
|
21
21
|
<div
|
|
22
22
|
v-if="step.summary || step.description"
|
|
23
|
-
class="
|
|
24
|
-
:style="{ maxHeight: hovered ? '
|
|
23
|
+
class="transition-all duration-200"
|
|
24
|
+
:style="{ maxHeight: hovered ? '80px' : '0', opacity: hovered ? 1 : 0, overflow: 'hidden' }"
|
|
25
25
|
>
|
|
26
26
|
<p class="mt-1.5 text-[11px] line-clamp-2" style="color: #636366;">
|
|
27
27
|
{{ step.summary || step.description }}
|
package/src/index.js
CHANGED
|
@@ -20,7 +20,6 @@ SillySpec CLI — 规范驱动开发工具包
|
|
|
20
20
|
用法:
|
|
21
21
|
sillyspec init 初始化(零交互,自动检测工具)
|
|
22
22
|
[--tool <name>] 只安装指定工具
|
|
23
|
-
[--workspace] 工作区模式
|
|
24
23
|
[--interactive] 交互式引导
|
|
25
24
|
[--dir <path>] 指定目录
|
|
26
25
|
sillyspec setup [--list] 安装推荐 MCP 工具
|
|
@@ -47,7 +46,7 @@ SillySpec CLI — 规范驱动开发工具包
|
|
|
47
46
|
示例:
|
|
48
47
|
sillyspec init
|
|
49
48
|
sillyspec init --tool claude
|
|
50
|
-
|
|
49
|
+
|
|
51
50
|
sillyspec setup
|
|
52
51
|
sillyspec setup --list
|
|
53
52
|
sillyspec dashboard
|
|
@@ -72,7 +71,6 @@ async function main() {
|
|
|
72
71
|
let json = false;
|
|
73
72
|
let targetDir = process.cwd();
|
|
74
73
|
let tool = null;
|
|
75
|
-
let workspace = false;
|
|
76
74
|
let interactive = false;
|
|
77
75
|
const filteredArgs = [];
|
|
78
76
|
|
|
@@ -85,8 +83,6 @@ async function main() {
|
|
|
85
83
|
} else if (args[i] === '--tool' && args[i + 1]) {
|
|
86
84
|
tool = args[i + 1];
|
|
87
85
|
i++;
|
|
88
|
-
} else if (args[i] === '--workspace' || args[i] === '-w') {
|
|
89
|
-
workspace = true;
|
|
90
86
|
} else if (args[i] === '--interactive' || args[i] === '-i') {
|
|
91
87
|
interactive = true;
|
|
92
88
|
} else if (args[i] === '--list' || args[i] === '-l') {
|
|
@@ -111,7 +107,7 @@ async function main() {
|
|
|
111
107
|
|
|
112
108
|
switch (command) {
|
|
113
109
|
case 'init':
|
|
114
|
-
await cmdInit(dir, { tool,
|
|
110
|
+
await cmdInit(dir, { tool, interactive });
|
|
115
111
|
break;
|
|
116
112
|
case 'setup':
|
|
117
113
|
const setupList = filteredArgs.includes('--list') || filteredArgs.includes('-l');
|
package/src/init.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, statSy
|
|
|
2
2
|
import { join, resolve, dirname, basename } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { homedir } from 'os';
|
|
5
|
-
import { checkbox,
|
|
5
|
+
import { checkbox, confirm, input } from '@inquirer/prompts';
|
|
6
6
|
import { ProgressManager } from './progress.js';
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
|
|
@@ -106,7 +106,7 @@ function isTTY() {
|
|
|
106
106
|
|
|
107
107
|
// ── 核心安装逻辑 ──
|
|
108
108
|
|
|
109
|
-
async function doInstall(projectDir, tools,
|
|
109
|
+
async function doInstall(projectDir, tools, subprojects = []) {
|
|
110
110
|
// 创建基础目录
|
|
111
111
|
// .sillyspec/projects/ → 项目注册表
|
|
112
112
|
// .sillyspec/docs/<name>/ → 统一文档中心
|
|
@@ -128,13 +128,11 @@ async function doInstall(projectDir, tools, isWorkspace, subprojects = []) {
|
|
|
128
128
|
const gitkeepPath = join(scanDir, '.gitkeep');
|
|
129
129
|
if (!existsSync(gitkeepPath)) writeFileSync(gitkeepPath, '');
|
|
130
130
|
|
|
131
|
-
//
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
mkdirSync(join(projectDir, '.sillyspec', 'workspace'), { recursive: true });
|
|
135
|
-
}
|
|
131
|
+
// 创建 shared/workspace 目录
|
|
132
|
+
mkdirSync(join(projectDir, '.sillyspec', 'shared'), { recursive: true });
|
|
133
|
+
mkdirSync(join(projectDir, '.sillyspec', 'workspace'), { recursive: true });
|
|
136
134
|
|
|
137
|
-
//
|
|
135
|
+
// 创建知识库骨架
|
|
138
136
|
const knowledgeDir = join(projectDir, '.sillyspec', 'knowledge');
|
|
139
137
|
mkdirSync(knowledgeDir, { recursive: true });
|
|
140
138
|
const indexPath = join(knowledgeDir, 'INDEX.md');
|
|
@@ -207,19 +205,17 @@ async function doInstall(projectDir, tools, isWorkspace, subprojects = []) {
|
|
|
207
205
|
console.log(chalk.yellow(' ⚠ 未找到 skills 目录,跳过 Claude Code skills 同步'));
|
|
208
206
|
}
|
|
209
207
|
|
|
210
|
-
|
|
211
208
|
// 工作区配置
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
209
|
+
const configPath = join(projectDir, '.sillyspec', 'config.yaml');
|
|
210
|
+
if (!existsSync(configPath)) {
|
|
211
|
+
let projectsYaml = '';
|
|
212
|
+
if (subprojects.length > 0) {
|
|
213
|
+
projectsYaml = subprojects.map(p =>
|
|
214
|
+
` ${p.name}:\n path: ${p.path}\n role: ${p.role || p.name}${p.repo ? `\n repo: ${p.repo}` : ''}`
|
|
215
|
+
).join('\n');
|
|
216
|
+
}
|
|
221
217
|
|
|
222
|
-
|
|
218
|
+
writeFileSync(configPath,
|
|
223
219
|
`# SillySpec 工作区配置
|
|
224
220
|
# 修改此文件后运行 /sillyspec:workspace 更新
|
|
225
221
|
|
|
@@ -228,16 +224,14 @@ ${projectsYaml || ' # 运行 /sillyspec:workspace add 添加子项目'}
|
|
|
228
224
|
|
|
229
225
|
shared: []
|
|
230
226
|
`
|
|
231
|
-
|
|
232
|
-
}
|
|
227
|
+
);
|
|
233
228
|
}
|
|
234
229
|
}
|
|
235
230
|
|
|
236
231
|
// ── 安装完成总结 ──
|
|
237
232
|
|
|
238
|
-
function showSummary(version, tools
|
|
233
|
+
function showSummary(version, tools) {
|
|
239
234
|
const toolLabels = tools.map(t => TOOL_LABELS[t] || t);
|
|
240
|
-
const mode = isWorkspace ? '多项目工作区' : '单项目';
|
|
241
235
|
|
|
242
236
|
console.log('');
|
|
243
237
|
console.log(chalk.green(' ═══════════════════════════════════════'));
|
|
@@ -245,7 +239,6 @@ function showSummary(version, tools, isWorkspace) {
|
|
|
245
239
|
console.log(chalk.green(' ═══════════════════════════════════════'));
|
|
246
240
|
console.log('');
|
|
247
241
|
console.log(` 已安装工具: ${chalk.cyan(toolLabels.join(', '))}`);
|
|
248
|
-
console.log(` 模式: ${chalk.yellow(mode)}`);
|
|
249
242
|
console.log(' 📁 .sillyspec/ — 项目规范目录');
|
|
250
243
|
console.log('');
|
|
251
244
|
console.log(' 下一步:使用 AI 技能开始工作');
|
|
@@ -270,7 +263,7 @@ export function getVersion() {
|
|
|
270
263
|
// ── 主命令 ──
|
|
271
264
|
|
|
272
265
|
export async function cmdInit(projectDir, options = {}) {
|
|
273
|
-
const { tool,
|
|
266
|
+
const { tool, interactive } = options;
|
|
274
267
|
const version = getVersion();
|
|
275
268
|
|
|
276
269
|
// ── 交互式模式(--interactive 或 -i)──
|
|
@@ -302,20 +295,11 @@ export async function cmdInit(projectDir, options = {}) {
|
|
|
302
295
|
validate: (answer) => answer.length > 0 || '至少选择一个工具',
|
|
303
296
|
});
|
|
304
297
|
|
|
305
|
-
//
|
|
306
|
-
const isWorkspace = await select({
|
|
307
|
-
message: '选择项目模式',
|
|
308
|
-
choices: [
|
|
309
|
-
{ name: '单项目模式', value: 'false' },
|
|
310
|
-
{ name: '多项目工作区', value: 'true' },
|
|
311
|
-
],
|
|
312
|
-
}) === 'true';
|
|
313
|
-
|
|
314
|
-
// 工作区子项目引导
|
|
298
|
+
// 子项目引导(始终执行)
|
|
315
299
|
let subprojects = [];
|
|
316
|
-
|
|
300
|
+
{
|
|
317
301
|
console.log('');
|
|
318
|
-
console.log(chalk.yellow('📋
|
|
302
|
+
console.log(chalk.yellow('📋 添加子项目'));
|
|
319
303
|
console.log(chalk.dim(' 子项目是工作区中的独立项目目录(如 frontend/、backend/)'));
|
|
320
304
|
console.log('');
|
|
321
305
|
|
|
@@ -378,8 +362,8 @@ export async function cmdInit(projectDir, options = {}) {
|
|
|
378
362
|
}
|
|
379
363
|
|
|
380
364
|
console.log('');
|
|
381
|
-
|
|
382
|
-
showSummary(version, selectedTools
|
|
365
|
+
await doInstall(projectDir, selectedTools, subprojects);
|
|
366
|
+
showSummary(version, selectedTools);
|
|
383
367
|
return;
|
|
384
368
|
}
|
|
385
369
|
|
|
@@ -397,7 +381,7 @@ export async function cmdInit(projectDir, options = {}) {
|
|
|
397
381
|
tools = detectTools(projectDir);
|
|
398
382
|
}
|
|
399
383
|
|
|
400
|
-
await doInstall(projectDir, tools
|
|
384
|
+
await doInstall(projectDir, tools);
|
|
401
385
|
|
|
402
386
|
console.log('');
|
|
403
387
|
console.log(chalk.green(` ✅ SillySpec v${version} 安装完成!`));
|
package/src/progress.js
CHANGED
|
@@ -17,7 +17,7 @@ const PROGRESS_FILE = 'progress.json';
|
|
|
17
17
|
const BACKUP_FILE = 'progress.json.bak';
|
|
18
18
|
|
|
19
19
|
const CURRENT_VERSION = 2;
|
|
20
|
-
const VALID_STAGES = ['brainstorm', 'propose', 'plan', 'execute', 'verify', 'scan', 'quick', 'archive', 'status'];
|
|
20
|
+
const VALID_STAGES = ['brainstorm', 'propose', 'plan', 'execute', 'verify', 'scan', 'quick', 'archive', 'status', 'doctor'];
|
|
21
21
|
const VALID_STATUSES = ['pending', 'in-progress', 'completed', 'failed', 'blocked'];
|
|
22
22
|
|
|
23
23
|
const STAGE_LABELS = {
|
|
@@ -30,6 +30,7 @@ const STAGE_LABELS = {
|
|
|
30
30
|
quick: '⚡ 快速任务',
|
|
31
31
|
archive: '📦 归档变更',
|
|
32
32
|
status: '📊 状态查看',
|
|
33
|
+
doctor: '🩺 项目自检',
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
function emptyStage() {
|
|
@@ -312,6 +313,10 @@ export class ProgressManager {
|
|
|
312
313
|
console.log(`⚠️ 发现问题,尝试修复...`);
|
|
313
314
|
let fixed = { ...data, stages: { ...data.stages } };
|
|
314
315
|
let changed = false;
|
|
316
|
+
if (!fixed.project) {
|
|
317
|
+
fixed.project = basename(cwd);
|
|
318
|
+
changed = true;
|
|
319
|
+
}
|
|
315
320
|
if (!fixed._version || !Number.isInteger(fixed._version) || fixed._version < 1) {
|
|
316
321
|
fixed._version = CURRENT_VERSION;
|
|
317
322
|
changed = true;
|
package/src/run.js
CHANGED
|
@@ -211,13 +211,21 @@ async function runStage(pm, progress, stageName, cwd) {
|
|
|
211
211
|
let currentIdx = steps.findIndex(s => s.status !== 'completed' && s.status !== 'skipped')
|
|
212
212
|
|
|
213
213
|
if (currentIdx === -1) {
|
|
214
|
-
//
|
|
214
|
+
// 阶段已完成
|
|
215
|
+
console.log(`✅ ${stageName} 阶段已完成。`)
|
|
216
|
+
console.log(` 继续执行将重新开始,可用 --reset 显式重置。\n`)
|
|
217
|
+
// 自动重置,允许重复执行
|
|
215
218
|
steps.forEach(s => { s.status = 'pending'; s.completedAt = null; s.output = null; s.startedAt = null })
|
|
216
219
|
stageData.status = 'in_progress'
|
|
217
220
|
stageData.completedAt = null
|
|
218
|
-
console.log(`🔄 ${stageName} 阶段已完成,重新开始...\n`)
|
|
219
221
|
pm._write(cwd, progress)
|
|
220
222
|
currentIdx = 0
|
|
223
|
+
} else if (currentIdx > 0) {
|
|
224
|
+
// 有进行中的步骤,提示用户
|
|
225
|
+
const completed = currentIdx
|
|
226
|
+
const total = steps.length
|
|
227
|
+
console.log(`⚠️ ${stageName} 已进行到第 ${currentIdx + 1}/${total} 步(前 ${completed} 步已完成)。`)
|
|
228
|
+
console.log(` 继续执行将从中断处恢复,用 --reset 可重新开始。\n`)
|
|
221
229
|
}
|
|
222
230
|
|
|
223
231
|
const stageDef = stageRegistry[stageName]
|
|
@@ -284,7 +292,7 @@ async function completeStep(pm, progress, stageName, cwd, outputText) {
|
|
|
284
292
|
// Save full output to artifacts/
|
|
285
293
|
const artifactsDir = join(cwd, '.sillyspec', '.runtime', 'artifacts')
|
|
286
294
|
mkdirSync(artifactsDir, { recursive: true })
|
|
287
|
-
const ts = new Date().
|
|
295
|
+
const ts = new Date().toISOString().slice(0,19).replace(/[-T:]/g, '')
|
|
288
296
|
writeFileSync(join(artifactsDir, `${stageName}-step${currentIdx + 1}-${ts}.txt`), outputText)
|
|
289
297
|
} else {
|
|
290
298
|
steps[currentIdx].output = outputText
|
package/src/stages/archive.js
CHANGED
|
@@ -39,7 +39,7 @@ export const definition = {
|
|
|
39
39
|
|
|
40
40
|
### 操作
|
|
41
41
|
1. 如果 \`.sillyspec/ROADMAP.md\` 存在,标记对应 Phase 为已完成
|
|
42
|
-
2. \`git add .sillyspec
|
|
42
|
+
2. \`git add .sillyspec/\` — **不要 commit**,由用户通过统一提交工具处理
|
|
43
43
|
3. 更新 progress.json:
|
|
44
44
|
- 清除当前变更信息(归档后不再活跃)
|
|
45
45
|
- 如果是主变更(有 MASTER.md),标记所有阶段为 ✅,然后清除
|
package/src/stages/brainstorm.js
CHANGED
|
@@ -27,17 +27,16 @@ export const definition = {
|
|
|
27
27
|
prompt: `加载项目现有上下文,理解代码结构和约定。
|
|
28
28
|
|
|
29
29
|
### 操作
|
|
30
|
-
1.
|
|
31
|
-
2.
|
|
32
|
-
3.
|
|
33
|
-
4.
|
|
34
|
-
5. 查看进行中的变更:\`ls .sillyspec/changes/ | grep -v archive\`
|
|
30
|
+
1. 读取 CODEBASE-OVERVIEW.md + 共享规范 + 子项目上下文
|
|
31
|
+
2. 询问本次需求属于哪个子项目
|
|
32
|
+
3. 棕地项目:读取 docs/<project>/scan/ 下的 STRUCTURE.md、CONVENTIONS.md、ARCHITECTURE.md
|
|
33
|
+
4. 查看进行中的变更:\`ls .sillyspec/changes/ | grep -v archive\`
|
|
35
34
|
|
|
36
35
|
### 输出
|
|
37
36
|
项目现状理解摘要(3-5 句话,关键约定和架构决策)
|
|
38
37
|
|
|
39
38
|
### 注意
|
|
40
|
-
-
|
|
39
|
+
- 始终询问本次需求属于哪个子项目
|
|
41
40
|
- 棕地项目必须读取数据模型章节`,
|
|
42
41
|
outputHint: '上下文摘要',
|
|
43
42
|
optional: false
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
// SillySpec Doctor — 项目自检阶段
|
|
2
|
+
// 检查项通过 prompt 中的 bash 命令执行,此文件仅定义步骤结构
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const definition = {
|
|
6
|
+
name: 'doctor',
|
|
7
|
+
title: '项目自检',
|
|
8
|
+
description: '检查 SillySpec 配置、构建环境和外部依赖',
|
|
9
|
+
auxiliary: true,
|
|
10
|
+
steps: [
|
|
11
|
+
{
|
|
12
|
+
name: 'SillySpec 内部检查',
|
|
13
|
+
prompt: `运行 SillySpec 内部检查。逐项执行以下命令并汇总结果:
|
|
14
|
+
|
|
15
|
+
### 1. 目录结构完整性
|
|
16
|
+
\`\`\`bash
|
|
17
|
+
# 检查 .sillyspec/ 及子目录
|
|
18
|
+
for d in .sillyspec .sillyspec/projects .sillyspec/docs .sillyspec/changes .sillyspec/.runtime; do
|
|
19
|
+
[ -d "$d" ] && echo "✅ $d" || echo "❌ $d"
|
|
20
|
+
done
|
|
21
|
+
# 检查 progress.json
|
|
22
|
+
[ -f .sillyspec/.runtime/progress.json ] && echo "✅ progress.json 存在" || echo "❌ progress.json 不存在"
|
|
23
|
+
node -e "JSON.parse(require('fs').readFileSync('.sillyspec/.runtime/progress.json','utf8')); console.log('✅ progress.json 可解析')" 2>/dev/null || echo "⚠️ progress.json 不可解析"
|
|
24
|
+
\`\`\`
|
|
25
|
+
|
|
26
|
+
### 2. 项目配置检查
|
|
27
|
+
\`\`\`bash
|
|
28
|
+
ls .sillyspec/projects/*.yaml 2>/dev/null
|
|
29
|
+
# 对每个 yaml 文件,检查 name 和 path 字段,验证 path 存在
|
|
30
|
+
for f in .sillyspec/projects/*.yaml; do
|
|
31
|
+
[ -f "$f" ] || continue
|
|
32
|
+
name=$(grep '^name:' "$f" | head -1 | sed 's/^name:[[:space:]]*//')
|
|
33
|
+
p=$(grep '^path:' "$f" | head -1 | sed 's/^path:[[:space:]]*//')
|
|
34
|
+
[ -z "$name" ] && echo "⚠️ $(basename $f) — 缺少 name"
|
|
35
|
+
[ -z "$p" ] && echo "⚠️ $(basename $f) — 缺少 path"
|
|
36
|
+
[ -n "$p" ] && [ ! -d "$p" ] && echo "❌ $(basename $f) — path 不存在: $p"
|
|
37
|
+
[ -n "$name" ] && [ -n "$p" ] && [ -d "$p" ] && echo "✅ $(basename $f) — $name ($p)"
|
|
38
|
+
done
|
|
39
|
+
\`\`\`
|
|
40
|
+
|
|
41
|
+
### 3. 进度数据一致性
|
|
42
|
+
\`\`\`bash
|
|
43
|
+
# 读取 currentChange 并检查目录存在性
|
|
44
|
+
node -e "
|
|
45
|
+
const p = JSON.parse(require('fs').readFileSync('.sillyspec/.runtime/progress.json','utf8'));
|
|
46
|
+
const cc = p.currentChange;
|
|
47
|
+
if (!cc) { console.log('ℹ️ 无当前变更'); process.exit(0); }
|
|
48
|
+
const dir = '.sillyspec/changes/' + cc;
|
|
49
|
+
const exists = require('fs').existsSync(dir);
|
|
50
|
+
console.log(exists ? '✅ currentChange 目录存在: ' + cc : '❌ currentChange 目录不存在: ' + cc);
|
|
51
|
+
// 检查各阶段产出
|
|
52
|
+
const stages = p.stages || {};
|
|
53
|
+
for (const [name, sd] of Object.entries(stages)) {
|
|
54
|
+
if (sd.status === 'completed' && sd.steps.length > 0) {
|
|
55
|
+
const hasOutput = sd.steps.some(s => s.output && s.output.trim());
|
|
56
|
+
console.log(' ' + name + ': ' + (hasOutput ? '✅ 有产出' : '⚠️ 已完成但无产出记录'));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
" 2>/dev/null || echo "⚠️ 无法读取 progress.json"
|
|
60
|
+
\`\`\`
|
|
61
|
+
|
|
62
|
+
### 4. 孤儿文件检查
|
|
63
|
+
\`\`\`bash
|
|
64
|
+
node -e "
|
|
65
|
+
const fs = require('fs');
|
|
66
|
+
const dir = '.sillyspec/changes';
|
|
67
|
+
if (!fs.existsSync(dir)) { console.log('ℹ️ changes/ 目录不存在'); process.exit(0); }
|
|
68
|
+
const subs = fs.readdirSync(dir).filter(f => fs.statSync(dir+'/'+f).isDirectory());
|
|
69
|
+
if (subs.length === 0) { console.log('ℹ️ 无变更目录'); process.exit(0); }
|
|
70
|
+
let progress;
|
|
71
|
+
try { progress = JSON.parse(fs.readFileSync('.sillyspec/.runtime/progress.json','utf8')); } catch { console.log('⚠️ 无法读取 progress.json'); subs.forEach(s => console.log('❓ ' + s)); process.exit(0); }
|
|
72
|
+
const known = new Set();
|
|
73
|
+
if (progress.currentChange) known.add(progress.currentChange);
|
|
74
|
+
for (const sd of Object.values(progress.stages || {})) {
|
|
75
|
+
(sd.steps || []).forEach(s => { if (s.output) known.add(s.output); });
|
|
76
|
+
}
|
|
77
|
+
subs.forEach(s => {
|
|
78
|
+
console.log(known.has(s) ? '✅ ' + s + ' — 已关联' : '⚠️ ' + s + ' — 孤儿目录(可清理)');
|
|
79
|
+
});
|
|
80
|
+
"
|
|
81
|
+
\`\`\`
|
|
82
|
+
|
|
83
|
+
### 5. 配置文件检查
|
|
84
|
+
\`\`\`bash
|
|
85
|
+
# 检查 local.yaml 和 STACK.md
|
|
86
|
+
for f in .sillyspec/projects/*.yaml; do
|
|
87
|
+
[ -f "$f" ] || continue
|
|
88
|
+
name=$(grep '^name:' "$f" | head -1 | sed 's/^name:[[:space:]]*//')
|
|
89
|
+
p=$(grep '^path:' "$f" | head -1 | sed 's/^path:[[:space:]]*//')
|
|
90
|
+
[ -z "$p" ] && continue
|
|
91
|
+
local_yaml="$p/.sillyspec/local.yaml"
|
|
92
|
+
stack_md="$p/.sillyspec/STACK.md"
|
|
93
|
+
[ -f "$local_yaml" ] && echo "✅ local.yaml ($name)" || echo "⚠️ local.yaml ($name) — 不存在"
|
|
94
|
+
if [ -f "$local_yaml" ]; then
|
|
95
|
+
grep -q 'build:' "$local_yaml" && echo " ✅ build 命令已配置" || echo " ⚠️ 缺少 build 命令"
|
|
96
|
+
grep -q 'test:' "$local_yaml" && echo " ✅ test 命令已配置" || echo " ⚠️ 缺少 test 命令"
|
|
97
|
+
fi
|
|
98
|
+
[ -f "$stack_md" ] && echo "✅ STACK.md ($name)" || echo "⚠️ STACK.md ($name) — 不存在"
|
|
99
|
+
done
|
|
100
|
+
\`\`\`
|
|
101
|
+
|
|
102
|
+
### 输出
|
|
103
|
+
汇总所有检查结果,按以下格式:
|
|
104
|
+
\`\`\`
|
|
105
|
+
## SillySpec 内部
|
|
106
|
+
✅/⚠️/❌ 各项状态
|
|
107
|
+
\`\`\`
|
|
108
|
+
|
|
109
|
+
### 注意
|
|
110
|
+
- 不要编造路径或结果,严格基于命令输出
|
|
111
|
+
- 如果 .sillyspec/ 不存在,直接输出 ❌ 并跳过后续检查`,
|
|
112
|
+
outputHint: 'SillySpec 内部检查结果',
|
|
113
|
+
optional: false
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: '构建环境检查',
|
|
117
|
+
prompt: `检查项目构建环境。先探测项目使用的构建工具,再逐项检查可用性。
|
|
118
|
+
|
|
119
|
+
### 1. 探测构建工具
|
|
120
|
+
\`\`\`bash
|
|
121
|
+
# 确定项目路径(使用 progress.json 中的项目或当前目录)
|
|
122
|
+
PROJECT_DIR=$(node -e "
|
|
123
|
+
const fs=require('fs');
|
|
124
|
+
try{const p=JSON.parse(fs.readFileSync('.sillyspec/.runtime/progress.json','utf8'));if(p.project){console.log(p.project);process.exit(0)}}catch{}
|
|
125
|
+
const files=fs.readdirSync('.sillyspec/projects').filter(f=>f.endsWith('.yaml'));
|
|
126
|
+
if(files.length>0){const c=fs.readFileSync('.sillyspec/projects/'+files[0],'utf8');const m=c.match(/^path:\\s*(.+)/m);console.log(m?m[1].trim():'.')}else console.log('.')
|
|
127
|
+
" 2>/dev/null)
|
|
128
|
+
echo "项目目录: $PROJECT_DIR"
|
|
129
|
+
|
|
130
|
+
# 探测构建工具
|
|
131
|
+
for f in pom.xml build.gradle package.json requirements.txt pyproject.toml go.mod Cargo.toml; do
|
|
132
|
+
[ -f "$PROJECT_DIR/$f" ] && echo "检测到: $f"
|
|
133
|
+
done
|
|
134
|
+
[ -f "$PROJECT_DIR/.sillyspec/STACK.md" ] && cat "$PROJECT_DIR/.sillyspec/STACK.md" | head -30
|
|
135
|
+
\`\`\`
|
|
136
|
+
|
|
137
|
+
### 2. 构建工具可用性
|
|
138
|
+
根据上面检测到的工具,运行对应检查(未检测到的跳过):
|
|
139
|
+
|
|
140
|
+
**Maven 项目:**
|
|
141
|
+
\`\`\`bash
|
|
142
|
+
timeout 10 mvn -v 2>/dev/null | head -1 && echo "✅ Maven 可用" || echo "❌ Maven 不可用"
|
|
143
|
+
[ -f ~/.m2/settings.xml ] && echo "✅ Maven settings.xml 存在" || echo "⚠️ Maven settings.xml 不存在"
|
|
144
|
+
timeout 10 java -version 2>&1 | head -1
|
|
145
|
+
\`\`\`
|
|
146
|
+
|
|
147
|
+
**Gradle 项目:**
|
|
148
|
+
\`\`\`bash
|
|
149
|
+
timeout 10 gradle -v 2>/dev/null | head -1 && echo "✅ Gradle 可用" || echo "❌ Gradle 不可用"
|
|
150
|
+
\`\`\`
|
|
151
|
+
|
|
152
|
+
**Node.js 项目:**
|
|
153
|
+
\`\`\`bash
|
|
154
|
+
timeout 5 node -v 2>/dev/null && echo "✅ Node.js 可用" || echo "❌ Node.js 不可用"
|
|
155
|
+
timeout 5 npm -v 2>/dev/null && echo "✅ npm 可用" || echo "❌ npm 不可用"
|
|
156
|
+
timeout 5 pnpm -v 2>/dev/null && echo "✅ pnpm 可用" || echo "ℹ️ pnpm 未安装"
|
|
157
|
+
# 检查 registry
|
|
158
|
+
npm config get registry 2>/dev/null
|
|
159
|
+
\`\`\`
|
|
160
|
+
|
|
161
|
+
**Python 项目:**
|
|
162
|
+
\`\`\`bash
|
|
163
|
+
timeout 5 python3 --version 2>/dev/null && echo "✅ Python3 可用" || echo "❌ Python3 不可用"
|
|
164
|
+
timeout 5 pip3 --version 2>/dev/null && echo "✅ pip3 可用" || echo "❌ pip3 不可用"
|
|
165
|
+
\`\`\`
|
|
166
|
+
|
|
167
|
+
### 3. Maven 私服检查(仅 Maven 项目)
|
|
168
|
+
\`\`\`bash
|
|
169
|
+
# 从 settings.xml 提取仓库地址
|
|
170
|
+
if [ -f ~/.m2/settings.xml ]; then
|
|
171
|
+
grep -oP 'https?://[^<"]+:[0-9]+' ~/.m2/settings.xml 2>/dev/null | sort -u | while read url; do
|
|
172
|
+
timeout 5 curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null
|
|
173
|
+
echo " — $url"
|
|
174
|
+
done
|
|
175
|
+
fi
|
|
176
|
+
# 从 pom.xml 提取
|
|
177
|
+
if [ -f "$PROJECT_DIR/pom.xml" ]; then
|
|
178
|
+
grep -oP 'https?://[^<"]+:[0-9]+' "$PROJECT_DIR/pom.xml" 2>/dev/null | sort -u | while read url; do
|
|
179
|
+
code=$(timeout 5 curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null)
|
|
180
|
+
[ "$code" = "000" ] && echo "❌ 私服不可达: $url(超时)" || echo "✅ 私服可达 ($code): $url"
|
|
181
|
+
done
|
|
182
|
+
fi
|
|
183
|
+
\`\`\`
|
|
184
|
+
|
|
185
|
+
### 4. 运行时环境
|
|
186
|
+
\`\`\`bash
|
|
187
|
+
timeout 5 node -v 2>/dev/null && echo "Node.js: $(node -v)" || echo "❌ Node.js 未安装"
|
|
188
|
+
timeout 5 git --version 2>/dev/null && echo "Git: $(git --version)" || echo "❌ Git 未安装"
|
|
189
|
+
timeout 10 git remote -v 2>/dev/null | head -2
|
|
190
|
+
timeout 5 git ls-remote --heads origin 2>/dev/null >/dev/null && echo "✅ Git remote 可达" || echo "⚠️ Git remote 不可达"
|
|
191
|
+
timeout 5 java -version 2>&1 | head -1
|
|
192
|
+
timeout 5 python3 --version 2>/dev/null
|
|
193
|
+
\`\`\`
|
|
194
|
+
|
|
195
|
+
### 输出
|
|
196
|
+
汇总所有检查结果:
|
|
197
|
+
\`\`\`
|
|
198
|
+
## 构建环境
|
|
199
|
+
✅/⚠️/❌ 各项状态
|
|
200
|
+
\`\`\`
|
|
201
|
+
|
|
202
|
+
### 注意
|
|
203
|
+
- 未检测到的构建工具直接跳过,不要报错
|
|
204
|
+
- timeout 超时的命令视为不可用
|
|
205
|
+
- 不编造结果`,
|
|
206
|
+
outputHint: '构建环境检查结果',
|
|
207
|
+
optional: false
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
name: '外部依赖检查',
|
|
211
|
+
prompt: `检查外部依赖工具是否可用。
|
|
212
|
+
|
|
213
|
+
### 1. Context7 MCP
|
|
214
|
+
\`\`\`bash
|
|
215
|
+
# 检查 MCP 配置
|
|
216
|
+
for f in ~/.config/claude/claude_desktop_config.json ~/.cursor/mcp.json ~/.openclaw/mcp.json; do
|
|
217
|
+
[ -f "$f" ] && echo "MCP 配置文件: $f" && grep -i context7 "$f" 2>/dev/null && echo "✅ Context7 已配置" || true
|
|
218
|
+
done
|
|
219
|
+
# 也检查 sillyspec 自身的 setup
|
|
220
|
+
node -e "
|
|
221
|
+
try{const m=require(require('path').join(require('os').homedir(),'.sillyspec','config.json'));console.log('✅ sillyspec config 存在')}catch{console.log('ℹ️ 无 sillyspec 全局配置')}
|
|
222
|
+
" 2>/dev/null
|
|
223
|
+
\`\`\`
|
|
224
|
+
|
|
225
|
+
### 2. grep.app
|
|
226
|
+
\`\`\`bash
|
|
227
|
+
timeout 5 curl -s -o /dev/null -w "%{http_code}" https://grep.app 2>/dev/null | grep -q "200" && echo "✅ grep.app 可达" || echo "⚠️ grep.app 不可达"
|
|
228
|
+
\`\`\`
|
|
229
|
+
|
|
230
|
+
### 3. 其他 AI 工具(可选)
|
|
231
|
+
\`\`\`bash
|
|
232
|
+
# 检查常用 AI/开发工具
|
|
233
|
+
timeout 5 which gh 2>/dev/null && echo "✅ GitHub CLI 可用" || echo "ℹ️ GitHub CLI 未安装"
|
|
234
|
+
timeout 5 which docker 2>/dev/null && echo "✅ Docker 可用" || echo "ℹ️ Docker 未安装"
|
|
235
|
+
\`\`\`
|
|
236
|
+
|
|
237
|
+
### 输出
|
|
238
|
+
\`\`\`
|
|
239
|
+
## 外部依赖
|
|
240
|
+
✅/⚠️/❌ 各项状态
|
|
241
|
+
\`\`\`
|
|
242
|
+
|
|
243
|
+
### 注意
|
|
244
|
+
- 不编造结果
|
|
245
|
+
- 工具未安装用 ℹ️ 标记(非错误),不可达用 ⚠️`,
|
|
246
|
+
outputHint: '外部依赖检查结果',
|
|
247
|
+
optional: false
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
name: '汇总报告',
|
|
251
|
+
prompt: `汇总前三步的所有检查结果,生成最终的自检报告。
|
|
252
|
+
|
|
253
|
+
### 输出格式
|
|
254
|
+
\`\`\`
|
|
255
|
+
🔍 SillySpec Doctor — 项目自检报告
|
|
256
|
+
|
|
257
|
+
## SillySpec 内部
|
|
258
|
+
✅ .sillyspec/ 目录结构 — 正常
|
|
259
|
+
✅ projects/*.yaml — N 个项目已注册
|
|
260
|
+
⚠️ local.yaml (xxx) — 缺少 test 命令
|
|
261
|
+
❌ progress.json — brainstorm 标记完成但 design.md 不存在
|
|
262
|
+
|
|
263
|
+
## 构建环境
|
|
264
|
+
✅ Node.js v23.4.0 — 可用
|
|
265
|
+
✅ npm 10.x — 可用
|
|
266
|
+
✅ Java 17.0.2 — 可用
|
|
267
|
+
❌ Maven 私服 (10.0.0.1:8081) — 不可达(超时)
|
|
268
|
+
|
|
269
|
+
## 外部依赖
|
|
270
|
+
✅ Context7 MCP — 已配置
|
|
271
|
+
⚠️ grep.app — 不可达
|
|
272
|
+
\`\`\`
|
|
273
|
+
|
|
274
|
+
### 要求
|
|
275
|
+
- 基于前 3 步的实际输出汇总,不要编造
|
|
276
|
+
- 每类问题归入对应分区
|
|
277
|
+
- 全部通过给出 🎉
|
|
278
|
+
- 如果有 ❌ 或 ⚠️,在末尾逐项给出修复建议
|
|
279
|
+
|
|
280
|
+
### 修复建议模板
|
|
281
|
+
根据问题类型给出具体可操作的修复命令:
|
|
282
|
+
|
|
283
|
+
**常见问题及修复:**
|
|
284
|
+
- CLI 未安装 → \`npm install -g sillyspec\` 或 \`npx sillyspec\`
|
|
285
|
+
- 缺少 local.yaml → \`sillyspec init\` 重新生成,或手动创建
|
|
286
|
+
- local.yaml 缺少 build/test → 补充对应命令
|
|
287
|
+
- 缺少 STACK.md → \`sillyspec run scan\` 重新扫描
|
|
288
|
+
- progress.json 不一致 → \`sillyspec run <阶段> --reset\` 重置对应阶段
|
|
289
|
+
- 孤儿目录 → 确认后 \`rm -rf .sillyspec/changes/<目录名>\`
|
|
290
|
+
- Maven 私服不可达 → 检查 VPN、settings.xml 配置、私服状态
|
|
291
|
+
- Git remote 不可达 → 检查网络、SSH key 或凭证
|
|
292
|
+
- 工具未安装 → 给出安装命令(如 \`brew install maven\`)
|
|
293
|
+
|
|
294
|
+
每条建议格式:
|
|
295
|
+
\`\`\`
|
|
296
|
+
💡 修复:<问题描述>
|
|
297
|
+
<具体命令或操作>
|
|
298
|
+
\`\`\``,
|
|
299
|
+
outputHint: '完整自检报告',
|
|
300
|
+
optional: false
|
|
301
|
+
}
|
|
302
|
+
]
|
|
303
|
+
}
|
package/src/stages/execute.js
CHANGED
package/src/stages/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { definition as scan } from './scan.js'
|
|
|
7
7
|
import { definition as quick } from './quick.js'
|
|
8
8
|
import { definition as archive } from './archive.js'
|
|
9
9
|
import { definition as status } from './status.js'
|
|
10
|
+
import { definition as doctor } from './doctor.js'
|
|
10
11
|
|
|
11
12
|
export const stageRegistry = {
|
|
12
13
|
brainstorm,
|
|
@@ -17,7 +18,8 @@ export const stageRegistry = {
|
|
|
17
18
|
scan,
|
|
18
19
|
quick,
|
|
19
20
|
archive,
|
|
20
|
-
status
|
|
21
|
+
status,
|
|
22
|
+
doctor
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
// 流程阶段顺序,用于 getNextStage
|
|
@@ -30,4 +32,4 @@ export function getNextStage(currentStage) {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
// 辅助命令(不影响流程阶段推进)
|
|
33
|
-
export const auxiliaryStages = ['scan', 'quick', 'archive', 'status']
|
|
35
|
+
export const auxiliaryStages = ['scan', 'quick', 'archive', 'status', 'doctor']
|
package/src/stages/plan.js
CHANGED
|
@@ -21,10 +21,9 @@ export const definition = {
|
|
|
21
21
|
prompt: `加载所有规范文件和代码库上下文。
|
|
22
22
|
|
|
23
23
|
### 操作
|
|
24
|
-
1.
|
|
24
|
+
1. 读取 CODEBASE-OVERVIEW.md + 各子项目上下文
|
|
25
25
|
2. 读取 proposal.md、design.md、tasks.md、requirements.md
|
|
26
26
|
3. 读取 CONVENTIONS.md、ARCHITECTURE.md、STACK.md
|
|
27
|
-
4. 工作区模式:额外加载 CODEBASE-OVERVIEW.md + 各子项目上下文
|
|
28
27
|
|
|
29
28
|
### 输出
|
|
30
29
|
已加载的文件清单`,
|
package/src/stages/propose.js
CHANGED
package/src/stages/scan.js
CHANGED
|
@@ -5,18 +5,18 @@ export const definition = {
|
|
|
5
5
|
auxiliary: true,
|
|
6
6
|
steps: [
|
|
7
7
|
{
|
|
8
|
-
name: '
|
|
9
|
-
prompt:
|
|
8
|
+
name: '检查已有扫描文档和子项目列表',
|
|
9
|
+
prompt: `检查已有扫描文档和子项目列表。
|
|
10
10
|
|
|
11
11
|
### 操作
|
|
12
|
-
1. \`ls .sillyspec/projects/*.yaml 2>/dev/null | grep -q .\` —
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
5.
|
|
12
|
+
1. \`ls .sillyspec/projects/*.yaml 2>/dev/null | grep -q .\` — 检查已有文档
|
|
13
|
+
1. \`ls docs/*/scan/ 2>/dev/null\` — 检查已有文档
|
|
14
|
+
2. \`wc -l docs/*/scan/*.md 2>/dev/null\` — 文档行数
|
|
15
|
+
3. 已有 3 份 → 建议升级深度扫描;已有 7 份 → 建议刷新或跳过
|
|
16
|
+
5. 显示子项目列表供选择扫描范围
|
|
17
17
|
|
|
18
18
|
### 输出
|
|
19
|
-
|
|
19
|
+
已有文档状态 + 扫描建议`,
|
|
20
20
|
outputHint: '工作区和文档状态',
|
|
21
21
|
optional: false
|
|
22
22
|
},
|
|
@@ -127,7 +127,7 @@ TESTING.md、CONCERNS.md、PROJECT.md 路径`,
|
|
|
127
127
|
1. 检查 7 份文档是否全部生成
|
|
128
128
|
2. 自检门控:ARCHITECTURE(技术栈+Schema摘要)、CONVENTIONS(隐形规则+代码风格)、STRUCTURE(目录结构)、INTEGRATIONS(外部依赖)、TESTING(测试现状)、CONCERNS(技术债务)、PROJECT(项目概览)
|
|
129
129
|
3. 清理:\`rm -f docs/<project>/scan/_env-detect.md\`
|
|
130
|
-
4. \`git add
|
|
130
|
+
4. \`git add .\` — **不要 commit**,由用户通过统一提交工具处理
|
|
131
131
|
|
|
132
132
|
### 输出
|
|
133
133
|
扫描完整性报告 + commit hash
|
package/src/stages/status.js
CHANGED
|
@@ -4,33 +4,6 @@ export const definition = {
|
|
|
4
4
|
description: '查看项目进度和状态',
|
|
5
5
|
auxiliary: true,
|
|
6
6
|
steps: [
|
|
7
|
-
{
|
|
8
|
-
name: '检查工作区模式',
|
|
9
|
-
prompt: `判断是否为工作区模式。
|
|
10
|
-
|
|
11
|
-
### 操作
|
|
12
|
-
1. \`ls .sillyspec/projects/*.yaml 2>/dev/null | grep -q .\`
|
|
13
|
-
2. 是 → 工作区模式,对每个子项目执行状态检查
|
|
14
|
-
3. 否 → 单项目模式,继续后续步骤
|
|
15
|
-
|
|
16
|
-
### 工作区模式输出格式:
|
|
17
|
-
\`\`\`
|
|
18
|
-
🏢 工作区状态
|
|
19
|
-
📦 子项目:
|
|
20
|
-
✅ frontend ./frontend
|
|
21
|
-
📋 项目:已初始化
|
|
22
|
-
📂 代码库:已扫描(7 份文档)
|
|
23
|
-
🔄 进行中:1 个变更
|
|
24
|
-
⚠️ backend ./backend
|
|
25
|
-
📂 代码库:未扫描
|
|
26
|
-
📄 共享规范:2 份
|
|
27
|
-
\`\`\`
|
|
28
|
-
|
|
29
|
-
### 输出
|
|
30
|
-
工作区/单项目判断`,
|
|
31
|
-
outputHint: '模式判断',
|
|
32
|
-
optional: false
|
|
33
|
-
},
|
|
34
7
|
{
|
|
35
8
|
name: '项目基础信息',
|
|
36
9
|
prompt: `收集项目基础信息。
|