sillyspec 3.7.14 → 3.7.16

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.
Files changed (85) hide show
  1. package/.claude/skills/sillyspec-archive/SKILL.md +77 -0
  2. package/.claude/skills/sillyspec-brainstorm/SKILL.md +591 -0
  3. package/.claude/skills/sillyspec-continue/SKILL.md +44 -0
  4. package/.claude/skills/sillyspec-execute/SKILL.md +233 -0
  5. package/.claude/skills/sillyspec-explore/SKILL.md +96 -0
  6. package/.claude/skills/sillyspec-export/SKILL.md +53 -0
  7. package/.claude/skills/sillyspec-init/SKILL.md +171 -0
  8. package/.claude/skills/sillyspec-plan/SKILL.md +263 -0
  9. package/.claude/skills/sillyspec-propose/SKILL.md +248 -0
  10. package/.claude/skills/sillyspec-quick/SKILL.md +102 -0
  11. package/.claude/skills/sillyspec-resume/SKILL.md +111 -0
  12. package/{templates/scan.md → .claude/skills/sillyspec-scan/SKILL.md} +22 -60
  13. package/.claude/skills/sillyspec-state/SKILL.md +54 -0
  14. package/.claude/skills/sillyspec-status/SKILL.md +131 -0
  15. package/.claude/skills/sillyspec-verify/SKILL.md +146 -0
  16. package/.claude/skills/sillyspec-workspace/SKILL.md +149 -0
  17. package/.sillyspec/changes/run-command-design/design.md +1230 -0
  18. package/.sillyspec/docs/sillyspec/scan/.gitkeep +0 -0
  19. package/.sillyspec/knowledge/INDEX.md +8 -0
  20. package/.sillyspec/knowledge/uncategorized.md +3 -0
  21. package/.sillyspec/projects/sillyspec.yaml +3 -0
  22. package/package.json +1 -1
  23. package/packages/dashboard/dist/assets/index-Bx0cgoK_.js +7446 -0
  24. package/packages/dashboard/dist/assets/index-DbkUSsNO.css +1 -0
  25. package/packages/dashboard/dist/index.html +2 -2
  26. package/packages/dashboard/package-lock.json +220 -0
  27. package/packages/dashboard/package.json +8 -5
  28. package/packages/dashboard/server/index.js +91 -3
  29. package/packages/dashboard/server/parser.js +252 -28
  30. package/packages/dashboard/src/App.vue +54 -8
  31. package/packages/dashboard/src/components/ActionBar.vue +23 -39
  32. package/packages/dashboard/src/components/CommandPalette.vue +40 -65
  33. package/packages/dashboard/src/components/DetailPanel.vue +68 -53
  34. package/packages/dashboard/src/components/DocPreview.vue +137 -20
  35. package/packages/dashboard/src/components/DocTree.vue +48 -26
  36. package/packages/dashboard/src/components/LogStream.vue +12 -32
  37. package/packages/dashboard/src/components/PipelineStage.vue +8 -8
  38. package/packages/dashboard/src/components/PipelineView.vue +35 -43
  39. package/packages/dashboard/src/components/ProjectList.vue +51 -77
  40. package/packages/dashboard/src/components/ProjectOverview.vue +178 -0
  41. package/packages/dashboard/src/components/StageBadge.vue +13 -13
  42. package/packages/dashboard/src/components/StepCard.vue +11 -11
  43. package/packages/dashboard/src/components/detail/DocsDetail.vue +48 -0
  44. package/packages/dashboard/src/components/detail/GitDetail.vue +61 -0
  45. package/packages/dashboard/src/components/detail/TechDetail.vue +43 -0
  46. package/packages/dashboard/src/main.js +4 -1
  47. package/packages/dashboard/src/style.css +14 -14
  48. package/src/index.js +55 -8
  49. package/src/init.js +69 -196
  50. package/src/migrate.js +1 -18
  51. package/src/progress.js +279 -281
  52. package/src/run.js +320 -0
  53. package/src/setup.js +1 -9
  54. package/src/stages/brainstorm.js +210 -0
  55. package/src/stages/execute.js +190 -0
  56. package/src/stages/index.js +22 -0
  57. package/src/stages/plan.js +118 -0
  58. package/src/stages/propose.js +115 -0
  59. package/src/stages/verify.js +98 -0
  60. package/packages/dashboard/dist/assets/index-hNnQCobe.css +0 -1
  61. package/packages/dashboard/dist/assets/index-qgPzQGjk.js +0 -17
  62. package/templates/archive.md +0 -121
  63. package/templates/brainstorm.md +0 -246
  64. package/templates/commit.md +0 -123
  65. package/templates/continue.md +0 -32
  66. package/templates/execute.md +0 -314
  67. package/templates/explore.md +0 -60
  68. package/templates/export.md +0 -21
  69. package/templates/init.md +0 -61
  70. package/templates/plan.md +0 -157
  71. package/templates/progress-format.md +0 -90
  72. package/templates/propose.md +0 -73
  73. package/templates/quick.md +0 -135
  74. package/templates/resume-dialog.md +0 -55
  75. package/templates/resume.md +0 -53
  76. package/templates/scan-quick.md +0 -49
  77. package/templates/skills/playwright-e2e/SKILL.md +0 -340
  78. package/templates/status.md +0 -72
  79. package/templates/verify.md +0 -253
  80. package/templates/workspace-sync.md +0 -89
  81. package/templates/workspace.md +0 -67
  82. /package/.sillyspec/{docs/sillyspec/brainstorm → changes/brainstorm-archive}/2026-04-05-dashboard-design.md +0 -0
  83. /package/.sillyspec/{docs/sillyspec/brainstorm → changes/brainstorm-archive}/2026-04-05-unified-docs-design.md +0 -0
  84. /package/.sillyspec/{specs/2026-04-05-dashboard-design.md → changes/dashboard/design.md.braindraft} +0 -0
  85. /package/.sillyspec/{specs/2026-04-05-unified-docs-design.md → changes/unified-docs-design/design.md} +0 -0
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <div v-if="data?.length" class="px-4 py-3">
3
+ <div v-for="group in data" :key="group.key" class="mb-4">
4
+ <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">
5
+ {{ group.icon }} {{ group.label }} ({{ group.files.length }})
6
+ </h4>
7
+ <div class="space-y-1">
8
+ <div
9
+ v-for="f in group.files"
10
+ :key="f.path"
11
+ class="flex items-center gap-2 px-2 py-1.5 rounded text-[11px] cursor-pointer hover:bg-[#FEF3C7] transition-colors"
12
+ @click="$emit('open-file', f)"
13
+ >
14
+ <svg class="w-3 h-3 flex-shrink-0" fill="none" stroke="#9CA3AF" viewBox="0 0 24 24">
15
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
16
+ </svg>
17
+ <span class="truncate" style="color: #1C1C1E;">{{ f.name }}</span>
18
+ <span class="ml-auto flex-shrink-0 font-mono text-[10px]" style="color: #9CA3AF;">{{ formatSize(f.size) }}</span>
19
+ <span class="flex-shrink-0 text-[10px]" style="color: #9CA3AF;">{{ relativeTime(f.mtime) }}</span>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ <n-empty v-else description="无文档" style="padding: 48px 0;" />
25
+ </template>
26
+
27
+ <script setup>
28
+ defineProps({ data: { type: Array, default: () => [] } })
29
+ defineEmits(['open-file'])
30
+
31
+ function formatSize(bytes) {
32
+ if (!bytes) return '—'
33
+ if (bytes < 1024) return bytes + ' B'
34
+ if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'
35
+ return (bytes / 1048576).toFixed(1) + ' MB'
36
+ }
37
+
38
+ function relativeTime(iso) {
39
+ if (!iso) return ''
40
+ const d = new Date(iso)
41
+ const diff = Date.now() - d.getTime()
42
+ if (diff < 60000) return '刚刚'
43
+ if (diff < 3600000) return `${Math.floor(diff / 60000)} 分钟前`
44
+ if (diff < 86400000) return `${Math.floor(diff / 3600000)} 小时前`
45
+ if (diff < 604800000) return `${Math.floor(diff / 86400000)} 天前`
46
+ return `${d.getMonth() + 1}/${d.getDate()}`
47
+ }
48
+ </script>
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <div v-if="data" class="px-4 py-3">
3
+ <!-- Branch -->
4
+ <div class="mb-4">
5
+ <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">当前分支</h4>
6
+ <div class="text-[18px] font-bold font-[JetBrains_Mono,monospace]" style="color: #D97706;">{{ data.branch || '—' }}</div>
7
+ </div>
8
+
9
+ <!-- Commits -->
10
+ <div v-if="data.commits?.length" class="mb-4">
11
+ <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">最近提交</h4>
12
+ <div class="space-y-2">
13
+ <div v-for="c in data.commits" :key="c.hash" class="px-3 py-2 rounded-md" style="background: #F5F5F7;">
14
+ <div class="flex items-center gap-2">
15
+ <span class="text-[11px] font-mono font-semibold" style="color: #D97706;">{{ c.hash }}</span>
16
+ <span class="text-[11px] flex-1 truncate" style="color: #1C1C1E;">{{ c.message }}</span>
17
+ </div>
18
+ <div class="flex items-center gap-2 mt-1 text-[10px]" style="color: #6B7280;">
19
+ <span>{{ c.author }}</span>
20
+ <span>·</span>
21
+ <span>{{ relativeTime(c.date) }}</span>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+
27
+ <!-- Untracked -->
28
+ <div v-if="data.untracked?.length">
29
+ <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">未提交文件</h4>
30
+ <div class="space-y-1">
31
+ <div v-for="f in data.untracked" :key="f.file" class="flex items-center gap-2 px-2 py-1 rounded text-[11px] font-[JetBrains_Mono,monospace]">
32
+ <span class="font-semibold w-5 text-center" :style="{ color: statusColor(f.status) }">{{ f.status }}</span>
33
+ <span class="truncate" style="color: #1C1C1E;">{{ f.file }}</span>
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ <n-empty v-else description="无 Git 信息" style="padding: 48px 0;" />
39
+ </template>
40
+
41
+ <script setup>
42
+ defineProps({ data: { type: Object, default: null } })
43
+
44
+ function statusColor(s) {
45
+ if (s.includes('M')) return '#F59E0B'
46
+ if (s.includes('A') || s === '?') return '#10B981'
47
+ if (s.includes('D')) return '#EF4444'
48
+ return '#9CA3AF'
49
+ }
50
+
51
+ function relativeTime(iso) {
52
+ if (!iso) return ''
53
+ const d = new Date(iso)
54
+ const diff = Date.now() - d.getTime()
55
+ if (diff < 60000) return '刚刚'
56
+ if (diff < 3600000) return `${Math.floor(diff / 60000)} 分钟前`
57
+ if (diff < 86400000) return `${Math.floor(diff / 3600000)} 小时前`
58
+ if (diff < 604800000) return `${Math.floor(diff / 86400000)} 天前`
59
+ return `${d.getMonth() + 1}/${d.getDate()}`
60
+ }
61
+ </script>
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <div v-if="data" class="px-4 py-3">
3
+ <!-- Frameworks -->
4
+ <div v-if="data.frameworks?.length" class="mb-4">
5
+ <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">识别框架</h4>
6
+ <div class="flex flex-wrap gap-2">
7
+ <n-tag v-for="f in data.frameworks" :key="f" type="warning" size="small" round>{{ f }}</n-tag>
8
+ </div>
9
+ </div>
10
+
11
+ <!-- Dependencies -->
12
+ <div v-if="depEntries.length" class="mb-4">
13
+ <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">dependencies ({{ depEntries.length }})</h4>
14
+ <div class="space-y-1">
15
+ <div v-for="[name, ver] in depEntries" :key="name" class="flex items-center gap-2 px-2 py-1 rounded text-[11px]" style="background: #F5F5F7;">
16
+ <span class="font-mono font-medium truncate" style="color: #1C1C1E;">{{ name }}</span>
17
+ <span class="font-mono ml-auto flex-shrink-0" style="color: #9CA3AF;">{{ ver }}</span>
18
+ </div>
19
+ </div>
20
+ </div>
21
+
22
+ <!-- Dev Dependencies -->
23
+ <div v-if="devDepEntries.length">
24
+ <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">devDependencies ({{ devDepEntries.length }})</h4>
25
+ <div class="space-y-1">
26
+ <div v-for="[name, ver] in devDepEntries" :key="name" class="flex items-center gap-2 px-2 py-1 rounded text-[11px]" style="background: #F5F5F7;">
27
+ <span class="font-mono font-medium truncate" style="color: #1C1C1E;">{{ name }}</span>
28
+ <span class="font-mono ml-auto flex-shrink-0" style="color: #9CA3AF;">{{ ver }}</span>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </div>
33
+ <n-empty v-else description="无依赖信息" style="padding: 48px 0;" />
34
+ </template>
35
+
36
+ <script setup>
37
+ import { computed } from 'vue'
38
+
39
+ const props = defineProps({ data: { type: Object, default: null } })
40
+
41
+ const depEntries = computed(() => props.data ? Object.entries(props.data.dependencies || {}) : [])
42
+ const devDepEntries = computed(() => props.data ? Object.entries(props.data.devDependencies || {}) : [])
43
+ </script>
@@ -1,5 +1,8 @@
1
1
  import { createApp } from 'vue'
2
+ import naive from 'naive-ui'
2
3
  import App from './App.vue'
3
4
  import './style.css'
4
5
 
5
- createApp(App).mount('#app')
6
+ const app = createApp(App)
7
+ app.use(naive)
8
+ app.mount('#app')
@@ -1,20 +1,20 @@
1
1
  @import "tailwindcss";
2
2
 
3
3
  @theme {
4
- --color-bg: #111318;
5
- --color-primary: #FBBF24;
6
- --color-primary-dim: #B45309;
7
- --color-warning: #FB923C;
8
- --color-danger: #EF4444;
9
- --color-muted: #8B8FA3;
10
- --color-surface: #1A1D24;
11
- --color-surface-2: #23272F;
12
- --color-border: #2E3340;
13
- --color-border-light: #3D4455;
14
- --color-text: #EAEAEF;
15
- --color-text-secondary: #B0B4C3;
16
- --color-info: #38BDF8;
17
- --color-success: #34D399;
4
+ --color-bg: #F5F5F7;
5
+ --color-primary: #D97706;
6
+ --color-primary-dim: #92400E;
7
+ --color-warning: #EA580C;
8
+ --color-danger: #DC2626;
9
+ --color-muted: #6B7280;
10
+ --color-surface: #FFFFFF;
11
+ --color-surface-2: #F0F0F3;
12
+ --color-border: #E5E5EA;
13
+ --color-border-light: #D1D1D6;
14
+ --color-text: #1C1C1E;
15
+ --color-text-secondary: #636366;
16
+ --color-info: #2563EB;
17
+ --color-success: #16A34A;
18
18
 
19
19
  --font-display: 'JetBrains Mono', monospace;
20
20
  --font-body: 'DM Sans', sans-serif;
package/src/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * SillySpec CLI — 安装工具
5
5
  *
6
6
  * 只负责两件事:init(安装命令模板)和 setup(安装 MCP 工具)。
7
- * 状态管理由 AI 直接读文件(STATE.md)完成,不需要 CLI。
7
+ * 状态管理通过 progress.json 完成,使用 `sillyspec progress` 命令。
8
8
  */
9
9
  import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
10
10
  import { join, resolve } from 'path';
@@ -25,11 +25,15 @@ SillySpec CLI — 规范驱动开发工具包
25
25
  [--dir <path>] 指定目录
26
26
  sillyspec setup [--list] 安装推荐 MCP 工具
27
27
  [--list] 查看已安装状态
28
- sillyspec progress <cmd> 进度恢复管理
29
- init 初始化进度文件
30
- status 查看当前进度
31
- validate 校验并修复进度文件
32
- reset [--stage X] 重置进度(全部或指定阶段)
28
+ sillyspec progress <cmd> 进度管理
29
+ init 初始化 progress.json
30
+ show 查看当前进度
31
+ set-stage <stage> 设置当前阶段
32
+ add-step <stage> <name> 添加步骤
33
+ update-step <s> <n> --status <st> [--output <t>]
34
+ complete-stage <stage> 完成阶段并推进
35
+ validate 校验并修复
36
+ reset [--stage X] 重置进度
33
37
  complete --stage X 归档已完成阶段
34
38
  sillyspec docs migrate 迁移旧文档到统一结构
35
39
  sillyspec dashboard 启动 Dashboard Web UI
@@ -93,6 +97,11 @@ async function main() {
93
97
  }
94
98
 
95
99
  const command = filteredArgs[0];
100
+ // 支持 sillyspec init /path/to/project 语法:如果第二个参数看起来像路径,当作 targetDir
101
+ if (command === 'init' && filteredArgs[1] && !filteredArgs[1].startsWith('-')) {
102
+ targetDir = resolve(filteredArgs[1]);
103
+ filteredArgs.splice(1, 1);
104
+ }
96
105
  const dir = targetDir;
97
106
 
98
107
  if (!existsSync(dir)) {
@@ -119,7 +128,8 @@ async function main() {
119
128
  pm.init(dir);
120
129
  break;
121
130
  case 'status':
122
- pm.status(dir);
131
+ case 'show':
132
+ pm.show(dir);
123
133
  break;
124
134
  case 'validate':
125
135
  pm.validate(dir);
@@ -130,8 +140,40 @@ async function main() {
130
140
  case 'complete':
131
141
  pm.complete(dir, stage);
132
142
  break;
143
+ case 'set-stage': {
144
+ const setStageName = filteredArgs[2];
145
+ if (!setStageName) { console.log('❌ 用法: sillyspec progress set-stage <stage>'); break; }
146
+ pm.setStage(dir, setStageName);
147
+ break;
148
+ }
149
+ case 'add-step': {
150
+ const addStepStage = filteredArgs[2];
151
+ const addStepName = filteredArgs[3];
152
+ if (!addStepStage || !addStepName) { console.log('❌ 用法: sillyspec progress add-step <stage> <step-name>'); break; }
153
+ pm.addStep(dir, addStepStage, addStepName);
154
+ break;
155
+ }
156
+ case 'update-step': {
157
+ const updStepStage = filteredArgs[2];
158
+ const updStepName = filteredArgs[3];
159
+ if (!updStepStage || !updStepName) { console.log('❌ 用法: sillyspec progress update-step <stage> <step-name> --status <status> [--output <text>]'); break; }
160
+ // Parse --status and --output from args
161
+ let updStatus = null, updOutput = undefined;
162
+ for (let ai = 0; ai < args.length; ai++) {
163
+ if (args[ai] === '--status' && args[ai + 1]) { updStatus = args[ai + 1]; ai++; }
164
+ if (args[ai] === '--output' && args[ai + 1]) { updOutput = args[ai + 1]; ai++; }
165
+ }
166
+ pm.updateStep(dir, updStepStage, updStepName, { status: updStatus, output: updOutput });
167
+ break;
168
+ }
169
+ case 'complete-stage': {
170
+ const compStageName = filteredArgs[2];
171
+ if (!compStageName) { console.log('❌ 用法: sillyspec progress complete-stage <stage>'); break; }
172
+ pm.completeStage(dir, compStageName);
173
+ break;
174
+ }
133
175
  default:
134
- console.log('用法: sillyspec progress <init|status|validate|reset|complete> [--stage <stage>]');
176
+ console.log('用法: sillyspec progress <init|show|validate|reset|complete|set-stage|add-step|update-step|complete-stage>');
135
177
  }
136
178
  break;
137
179
  }
@@ -145,6 +187,11 @@ async function main() {
145
187
  }
146
188
  break;
147
189
  }
190
+ case 'run': {
191
+ const { runCommand } = await import('./run.js')
192
+ runCommand(filteredArgs.slice(1), dir)
193
+ break
194
+ }
148
195
  case 'dashboard': {
149
196
  // Parse dashboard options
150
197
  let port = 3456;