sillyspec 3.9.0 → 3.10.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.
Files changed (206) hide show
  1. package/.claude/skills/sillyspec-archive/SKILL.md +17 -0
  2. package/.claude/skills/sillyspec-auto/SKILL.md +78 -0
  3. package/.claude/skills/sillyspec-brainstorm/SKILL.md +17 -0
  4. package/{templates/commit.md → .claude/skills/sillyspec-commit/SKILL.md} +32 -47
  5. package/.claude/skills/sillyspec-continue/SKILL.md +45 -0
  6. package/.claude/skills/sillyspec-doctor/SKILL.md +27 -0
  7. package/.claude/skills/sillyspec-execute/SKILL.md +17 -0
  8. package/.claude/skills/sillyspec-explore/SKILL.md +105 -0
  9. package/.claude/skills/sillyspec-export/SKILL.md +53 -0
  10. package/.claude/skills/sillyspec-init/SKILL.md +170 -0
  11. package/.claude/skills/sillyspec-plan/SKILL.md +17 -0
  12. package/.claude/skills/sillyspec-propose/SKILL.md +17 -0
  13. package/.claude/skills/sillyspec-quick/SKILL.md +17 -0
  14. package/.claude/skills/sillyspec-resume/SKILL.md +111 -0
  15. package/.claude/skills/sillyspec-scan/SKILL.md +17 -0
  16. package/.claude/skills/sillyspec-state/SKILL.md +54 -0
  17. package/.claude/skills/sillyspec-status/SKILL.md +17 -0
  18. package/.claude/skills/sillyspec-verify/SKILL.md +17 -0
  19. package/.claude/skills/sillyspec-workspace/SKILL.md +149 -0
  20. package/README.md +19 -11
  21. package/SKILL.md +15 -10
  22. package/package.json +7 -9
  23. package/packages/dashboard/dist/assets/index-BcM2J-hv.css +1 -0
  24. package/packages/dashboard/dist/assets/index-DpLHK4jv.js +7446 -0
  25. package/packages/dashboard/dist/index.html +16 -16
  26. package/packages/dashboard/dist/prototype-dashboard.html +836 -0
  27. package/packages/dashboard/dist/prototype-overview.html +256 -0
  28. package/packages/dashboard/package-lock.json +226 -6
  29. package/packages/dashboard/package.json +8 -5
  30. package/packages/dashboard/public/logo.jpg +0 -0
  31. package/packages/dashboard/public/prototype-dashboard.html +836 -0
  32. package/packages/dashboard/public/prototype-overview.html +256 -0
  33. package/packages/dashboard/server/executor.js +1 -1
  34. package/packages/dashboard/server/index.js +341 -113
  35. package/packages/dashboard/server/parser.js +442 -30
  36. package/packages/dashboard/server/watcher.js +214 -134
  37. package/packages/dashboard/src/App.vue +475 -71
  38. package/packages/dashboard/src/components/ActionBar.vue +36 -43
  39. package/packages/dashboard/src/components/CommandPalette.vue +45 -66
  40. package/packages/dashboard/src/components/DetailPanel.vue +68 -53
  41. package/packages/dashboard/src/components/DocPreview.vue +257 -0
  42. package/packages/dashboard/src/components/DocTree.vue +114 -0
  43. package/packages/dashboard/src/components/HResizeHandle.vue +48 -0
  44. package/packages/dashboard/src/components/LogStream.vue +13 -33
  45. package/packages/dashboard/src/components/PipelineStage.vue +8 -8
  46. package/packages/dashboard/src/components/PipelineView.vue +99 -45
  47. package/packages/dashboard/src/components/ProjectCard.vue +187 -0
  48. package/packages/dashboard/src/components/ProjectList.vue +103 -45
  49. package/packages/dashboard/src/components/ProjectOverview.vue +152 -0
  50. package/packages/dashboard/src/components/StageBadge.vue +13 -13
  51. package/packages/dashboard/src/components/StepCard.vue +15 -15
  52. package/packages/dashboard/src/components/VResizeHandle.vue +61 -0
  53. package/packages/dashboard/src/components/detail/DocsDetail.vue +48 -0
  54. package/packages/dashboard/src/components/detail/GitDetail.vue +61 -0
  55. package/packages/dashboard/src/components/detail/TechDetail.vue +43 -0
  56. package/packages/dashboard/src/composables/useDashboard.js +48 -6
  57. package/packages/dashboard/src/composables/useKeyboard.js +6 -4
  58. package/packages/dashboard/src/composables/useLayout.js +131 -0
  59. package/packages/dashboard/src/main.js +4 -1
  60. package/packages/dashboard/src/style.css +17 -17
  61. package/src/index.js +141 -22
  62. package/src/init.js +93 -231
  63. package/src/migrate.js +117 -0
  64. package/src/progress.js +460 -0
  65. package/src/run.js +635 -0
  66. package/src/setup.js +2 -72
  67. package/src/stages/archive.js +54 -0
  68. package/src/stages/brainstorm.js +264 -0
  69. package/src/stages/doctor.js +303 -0
  70. package/src/stages/execute.js +287 -0
  71. package/src/stages/explore.js +34 -0
  72. package/src/stages/index.js +28 -0
  73. package/src/stages/plan.js +354 -0
  74. package/src/stages/propose.js +115 -0
  75. package/src/stages/quick.js +64 -0
  76. package/src/stages/scan.js +141 -0
  77. package/src/stages/status.js +65 -0
  78. package/src/stages/verify.js +135 -0
  79. package/.sillyspec/changes/dashboard/design.md +0 -219
  80. package/.sillyspec/plans/2026-04-05-dashboard.md +0 -737
  81. package/.sillyspec/specs/2026-04-05-dashboard-design.md +0 -206
  82. package/dist/steps/brainstorm/01-load-context.md +0 -30
  83. package/dist/steps/brainstorm/02-reuse-check.md +0 -6
  84. package/dist/steps/brainstorm/03-prototype-analysis.md +0 -11
  85. package/dist/steps/brainstorm/04-module-split.md +0 -23
  86. package/dist/steps/brainstorm/05-dialog-explore.md +0 -8
  87. package/dist/steps/brainstorm/06-propose-approaches.md +0 -3
  88. package/dist/steps/brainstorm/07-present-design.md +0 -3
  89. package/dist/steps/brainstorm/08-write-design.md +0 -21
  90. package/dist/steps/brainstorm/09-self-review.md +0 -15
  91. package/dist/steps/brainstorm/10-user-confirm.md +0 -3
  92. package/dist/steps/brainstorm/11-output-spec.md +0 -7
  93. package/dist/steps/brainstorm/manifest.yaml +0 -26
  94. package/dist/steps/execute/01-load-context.md +0 -41
  95. package/dist/steps/execute/02-scan-conventions.md +0 -47
  96. package/dist/steps/execute/03-skill-mcp.md +0 -19
  97. package/dist/steps/execute/04-assign-task.md +0 -22
  98. package/dist/steps/execute/04b-prompt-template.md +0 -54
  99. package/dist/steps/execute/05-write-test.md +0 -7
  100. package/dist/steps/execute/06-write-code.md +0 -8
  101. package/dist/steps/execute/07-run-test.md +0 -26
  102. package/dist/steps/execute/08-fix-issues.md +0 -28
  103. package/dist/steps/execute/09-next-task.md +0 -33
  104. package/dist/steps/execute/manifest.yaml +0 -28
  105. package/dist/steps/plan/01-load-context.md +0 -22
  106. package/dist/steps/plan/02-anchor-confirm.md +0 -1
  107. package/dist/steps/plan/03-expand-tasks.md +0 -33
  108. package/dist/steps/plan/04-mark-order.md +0 -15
  109. package/dist/steps/plan/05-e2e-planning.md +0 -17
  110. package/dist/steps/plan/06-self-check.md +0 -16
  111. package/dist/steps/plan/07-save.md +0 -1
  112. package/dist/steps/plan/manifest.yaml +0 -18
  113. package/dist/steps/scan/01-env-detect.md +0 -51
  114. package/dist/steps/scan/02-tech-stack.md +0 -16
  115. package/dist/steps/scan/03-conventions.md +0 -16
  116. package/dist/steps/scan/04-structure.md +0 -19
  117. package/dist/steps/scan/05-quality.md +0 -18
  118. package/dist/steps/scan/06-complete.md +0 -49
  119. package/dist/steps/scan/manifest.yaml +0 -16
  120. package/dist/steps/verify/01-load-specs.md +0 -28
  121. package/dist/steps/verify/02-check-tasks.md +0 -1
  122. package/dist/steps/verify/03-check-design.md +0 -6
  123. package/dist/steps/verify/04-run-tests.md +0 -7
  124. package/dist/steps/verify/05-e2e-tests.md +0 -27
  125. package/dist/steps/verify/05b-e2e-fix.md +0 -33
  126. package/dist/steps/verify/06-code-quality.md +0 -25
  127. package/dist/steps/verify/07-lint-check.md +0 -27
  128. package/dist/steps/verify/08-output-report.md +0 -14
  129. package/dist/steps/verify/manifest.yaml +0 -22
  130. package/docs/.vitepress/config.mts +0 -45
  131. package/docs/.vitepress/dist/404.html +0 -25
  132. package/docs/.vitepress/dist/assets/app.YytxICdd.js +0 -1
  133. package/docs/.vitepress/dist/assets/chunks/framework.Czhw_PXq.js +0 -19
  134. package/docs/.vitepress/dist/assets/chunks/theme.DusTRZQk.js +0 -1
  135. package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.js +0 -1
  136. package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.lean.js +0 -1
  137. package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  138. package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  139. package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  140. package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  141. package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  142. package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  143. package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  144. package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  145. package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  146. package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  147. package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  148. package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  149. package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  150. package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  151. package/docs/.vitepress/dist/assets/sillyspec_commands.md.CXFFsj08.js +0 -15
  152. package/docs/.vitepress/dist/assets/sillyspec_commands.md.CXFFsj08.lean.js +0 -1
  153. package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.js +0 -4
  154. package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.lean.js +0 -1
  155. package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.js +0 -1
  156. package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.lean.js +0 -1
  157. package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.js +0 -4
  158. package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.lean.js +0 -1
  159. package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.js +0 -5
  160. package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.lean.js +0 -1
  161. package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.js +0 -28
  162. package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.lean.js +0 -1
  163. package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.js +0 -30
  164. package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.lean.js +0 -1
  165. package/docs/.vitepress/dist/assets/style.DFTx90Kk.css +0 -1
  166. package/docs/.vitepress/dist/hashmap.json +0 -1
  167. package/docs/.vitepress/dist/index.html +0 -28
  168. package/docs/.vitepress/dist/sillyspec/commands.html +0 -42
  169. package/docs/.vitepress/dist/sillyspec/dashboard.html +0 -31
  170. package/docs/.vitepress/dist/sillyspec/file-io.html +0 -28
  171. package/docs/.vitepress/dist/sillyspec/getting-started.html +0 -31
  172. package/docs/.vitepress/dist/sillyspec/install.html +0 -32
  173. package/docs/.vitepress/dist/sillyspec/lifecycle.html +0 -55
  174. package/docs/.vitepress/dist/sillyspec/structure.html +0 -57
  175. package/docs/.vitepress/dist/vp-icons.css +0 -1
  176. package/docs/index.md +0 -34
  177. package/docs/sillyspec/commands.md +0 -218
  178. package/docs/sillyspec/dashboard.md +0 -51
  179. package/docs/sillyspec/file-io.md +0 -34
  180. package/docs/sillyspec/getting-started.md +0 -61
  181. package/docs/sillyspec/install.md +0 -51
  182. package/docs/sillyspec/lifecycle.md +0 -146
  183. package/docs/sillyspec/structure.md +0 -62
  184. package/packages/dashboard/dist/assets/index-Bh-GPjKY.css +0 -1
  185. package/packages/dashboard/dist/assets/index-CrCn5Gg6.js +0 -17
  186. package/src/step.js +0 -543
  187. package/templates/archive.md +0 -120
  188. package/templates/brainstorm.md +0 -170
  189. package/templates/continue.md +0 -32
  190. package/templates/execute.md +0 -304
  191. package/templates/explore.md +0 -59
  192. package/templates/export.md +0 -21
  193. package/templates/init.md +0 -61
  194. package/templates/plan.md +0 -146
  195. package/templates/quick.md +0 -135
  196. package/templates/scan-quick.md +0 -49
  197. package/templates/scan.md +0 -156
  198. package/templates/skills/playwright-e2e/SKILL.md +0 -340
  199. package/templates/status.md +0 -75
  200. package/templates/verify.md +0 -236
  201. package/templates/workspace-sync.md +0 -99
  202. package/templates/workspace.md +0 -70
  203. /package/{docs/.vitepress/dist/logo.jpg → logo.jpg} +0 -0
  204. /package/{docs/.vitepress → packages/dashboard}/dist/favicon.jpg +0 -0
  205. /package/{docs/public → packages/dashboard/dist}/logo.jpg +0 -0
  206. /package/{docs → packages/dashboard}/public/favicon.jpg +0 -0
@@ -1,75 +1,59 @@
1
1
  <template>
2
- <div class="h-12 flex items-center justify-between px-5 relative" style="background: rgba(17,17,19,0.9); backdrop-filter: blur(20px); border-top: 1px solid #1F1F22;">
2
+ <div class="h-12 flex items-center justify-between px-5 relative" style="background: rgba(17,17,19,0.9); backdrop-filter: blur(20px); border-top: 1px solid #F0F0F3;">
3
3
  <!-- Ambient top glow -->
4
4
  <div class="absolute inset-x-0 top-0 h-px" style="background: linear-gradient(90deg, transparent, rgba(251,191,36,0.1), transparent);"></div>
5
5
 
6
6
  <!-- Left: Status -->
7
7
  <div class="flex items-center gap-3">
8
8
  <div v-if="project" class="flex items-center gap-2">
9
- <span class="text-[11px] font-[JetBrains_Mono,monospace]" style="color: #525252;">{{ project.name }}</span>
10
- <span style="color: #1F1F22;">|</span>
9
+ <span class="text-[11px] font-[JetBrains_Mono,monospace]" style="color: #6B7280;">{{ project.name }}</span>
10
+ <span style="color: #F0F0F3;">|</span>
11
11
  <StageBadge v-if="project.state?.currentStage" :status="getProjectStatus()" :label="stageLabel()" />
12
12
  </div>
13
- <div v-else class="text-[10px] font-[JetBrains_Mono,monospace]" style="color: #3A3A3D;">
14
- no project
13
+ <div v-else class="text-[10px] font-[JetBrains_Mono,monospace]" style="color: #D1D1D6;">
14
+ 未选择项目
15
15
  </div>
16
16
  </div>
17
17
 
18
18
  <!-- Center: Execution -->
19
19
  <div class="flex items-center gap-2">
20
20
  <div v-if="isExecuting" class="flex items-center gap-2">
21
- <div class="w-1 h-1 rounded-full animate-pulse-dot" style="background: #FBBF24;" />
22
- <span class="text-[10px] font-[JetBrains_Mono,monospace]" style="color: #FBBF24;">running</span>
21
+ <div class="w-1 h-1 rounded-full animate-pulse-dot" style="background: #D97706;" />
22
+ <span class="text-[10px] font-[JetBrains_Mono,monospace]" style="color: #D97706;">执行中...</span>
23
23
  </div>
24
24
  <div v-else-if="executionResult" class="flex items-center gap-1.5">
25
- <span class="text-[10px] font-[JetBrains_Mono,monospace]" :style="{ color: executionResult.exitCode === 0 ? '#34D399' : '#EF4444' }">
26
- {{ executionResult.exitCode === 0 ? '● done' : `● exit ${executionResult.exitCode}` }}
25
+ <span class="text-[10px] font-[JetBrains_Mono,monospace]" :style="{ color: executionResult.exitCode === 0 ? '#16A34A' : '#DC2626' }">
26
+ {{ executionResult.exitCode === 0 ? '● 完成' : `● 失败 (${executionResult.exitCode})` }}
27
27
  </span>
28
28
  </div>
29
29
  </div>
30
30
 
31
31
  <!-- Right: Actions -->
32
32
  <div class="flex items-center gap-1">
33
- <button
34
- @click="$emit('toggle-panel')"
35
- class="p-1.5 rounded-sm transition-colors duration-100"
36
- style="color: #525252;"
37
- @mouseenter="$event.target.style.color='#FBBF24';$event.target.style.background='rgba(251,191,36,0.06)'"
38
- @mouseleave="$event.target.style.color='#525252';$event.target.style.background='transparent'"
39
- title="Toggle detail panel"
40
- >
41
- <svg :class="['w-3.5 h-3.5 transition-transform duration-200', { 'rotate-180': !isPanelOpen }]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
42
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
43
- </svg>
44
- </button>
33
+ <n-button quaternary size="tiny" @click="$emit('toggle-panel')" title="切换详情面板">
34
+ <template #icon>
35
+ <svg :class="['w-3.5 h-3.5 transition-transform duration-200', { 'rotate-180': !isPanelOpen }]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
36
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
37
+ </svg>
38
+ </template>
39
+ </n-button>
45
40
 
46
- <button
47
- v-if="isExecuting"
48
- @click="$emit('kill')"
49
- class="px-2.5 py-1 rounded-sm text-[10px] font-[JetBrains_Mono,monospace] transition-colors duration-100"
50
- style="background: rgba(239,68,68,0.08); border: 1px solid rgba(239,68,68,0.2); color: #EF4444;"
51
- >
52
- kill
53
- </button>
41
+ <n-button v-if="isExecuting" size="tiny" type="error" @click="$emit('kill')">
42
+ 停止
43
+ </n-button>
54
44
 
55
- <button
56
- @click="$emit('open-palette')"
57
- class="p-1.5 rounded-sm transition-colors duration-100"
58
- style="color: #525252;"
59
- @mouseenter="$event.target.style.color='#FBBF24';$event.target.style.background='rgba(251,191,36,0.06)'"
60
- @mouseleave="$event.target.style.color='#525252';$event.target.style.background='transparent'"
61
- title="Command palette (⌘K)"
62
- >
63
- <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
64
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
65
- </svg>
66
- </button>
45
+ <n-button quaternary size="tiny" @click="$emit('open-palette')" title="命令面板 (⌘K)">
46
+ <template #icon>
47
+ <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
48
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
49
+ </svg>
50
+ </template>
51
+ </n-button>
67
52
  </div>
68
53
  </div>
69
54
  </template>
70
55
 
71
56
  <script setup>
72
- import { computed } from 'vue'
73
57
  import StageBadge from './StageBadge.vue'
74
58
 
75
59
  const props = defineProps({
@@ -94,7 +78,16 @@ function getProjectStatus() {
94
78
 
95
79
  function stageLabel() {
96
80
  const stage = props.project?.state?.currentStage
97
- const labels = { 'brainstorm': '头脑风暴', 'plan': '规划', 'execute': '执行', 'verify': '验证' }
81
+ const labels = {
82
+ scan: '代码扫描',
83
+ brainstorm: '头脑风暴',
84
+ plan: '规划',
85
+ execute: '执行',
86
+ verify: '验证',
87
+ archive: '归档',
88
+ quick: '快速任务',
89
+ explore: '自由探索'
90
+ }
98
91
  return labels[stage] || stage || '未知'
99
92
  }
100
93
  </script>
@@ -1,67 +1,49 @@
1
1
  <template>
2
- <Teleport to="body">
3
- <Transition name="backdrop">
4
- <div v-if="isOpen" class="fixed inset-0 z-40" style="background: rgba(0,0,0,0.7); backdrop-filter: blur(4px);" @click="close" />
5
- </Transition>
6
-
7
- <Transition name="palette">
8
- <div v-if="isOpen" class="fixed left-1/2 top-[18%] -translate-x-1/2 w-full max-w-md z-50">
9
- <div class="overflow-hidden rounded-md" style="background: #141416; border: 1px solid #2A2A2D; box-shadow: 0 25px 60px rgba(0,0,0,0.5), 0 0 0 1px rgba(251,191,36,0.05);">
10
- <!-- Search -->
11
- <div class="px-4 py-3" style="border-bottom: 1px solid #1F1F22;">
12
- <div class="flex items-center gap-3">
13
- <svg class="w-3.5 h-3.5 flex-shrink-0" style="color: #525252;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
14
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
15
- </svg>
16
- <input
17
- ref="searchInput"
18
- v-model="searchQuery"
19
- type="text"
20
- placeholder="Search projects or stages..."
21
- class="flex-1 bg-transparent border-none outline-none text-[12px] font-[JetBrains_Mono,monospace]"
22
- style="color: #E4E4E7;"
23
- @keydown="handleKeydown"
24
- />
25
- <kbd v-if="searchQuery" class="text-[9px] px-1 py-0.5 rounded-sm font-mono-log" style="color: #525252; background: #0A0A0B; border: 1px solid #2A2A2D;">ESC</kbd>
26
- </div>
27
- </div>
2
+ <n-modal :show="isOpen" @update:show="$emit('close')" :mask-closable="true" transform-origin="center" style="max-width: 480px;">
3
+ <div class="overflow-hidden rounded-md" style="background: #FFFFFF; border: 1px solid #E5E5EA; box-shadow: 0 25px 60px rgba(0,0,0,0.1);">
4
+ <!-- Search -->
5
+ <div class="px-4 py-3" style="border-bottom: 1px solid #F0F0F3;">
6
+ <n-input v-model:value="searchQuery" placeholder="搜索项目或命令..." ref="searchInput" @keydown="handleKeydown" size="small">
7
+ <template #prefix>
8
+ <svg class="w-3.5 h-3.5" style="color: #6B7280;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
9
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/>
10
+ </svg>
11
+ </template>
12
+ </n-input>
13
+ </div>
28
14
 
29
- <!-- Results -->
30
- <div class="max-h-72 overflow-y-auto">
31
- <div v-if="filteredItems.length === 0" class="py-10 text-center">
32
- <p class="text-[11px] font-[JetBrains_Mono,monospace]" style="color: #3A3A3D;">No results</p>
15
+ <!-- Results -->
16
+ <div class="max-h-72 overflow-y-auto">
17
+ <n-empty v-if="filteredItems.length === 0" description="无结果" style="padding: 40px 0;" />
18
+ <div v-else class="py-0.5">
19
+ <div
20
+ v-for="(item, index) in filteredItems"
21
+ :key="item.id"
22
+ :class="['px-4 py-2.5 cursor-pointer transition-colors duration-100 flex items-center gap-3']"
23
+ :style="{ background: selectedIndex === index ? 'rgba(217,119,6,0.06)' : 'transparent' }"
24
+ @click="selectItem(item)"
25
+ @mouseenter="selectedIndex = index"
26
+ >
27
+ <div class="w-6 h-6 rounded-sm flex items-center justify-center text-[10px] font-[JetBrains_Mono,monospace] flex-shrink-0" style="background: #F0F0F3; border: 1px solid #F0F0F3; color: #6B7280;">
28
+ {{ item.type === 'project' ? '□' : '◇' }}
33
29
  </div>
34
- <div v-else class="py-0.5">
35
- <div
36
- v-for="(item, index) in filteredItems"
37
- :key="item.id"
38
- :class="['px-4 py-2.5 cursor-pointer transition-colors duration-100 flex items-center gap-3']"
39
- :style="{ background: selectedIndex === index ? 'rgba(251,191,36,0.06)' : 'transparent' }"
40
- @click="selectItem(item)"
41
- @mouseenter="selectedIndex = index"
42
- >
43
- <div class="w-6 h-6 rounded-sm flex items-center justify-center text-[10px] font-[JetBrains_Mono,monospace] flex-shrink-0" style="background: #0A0A0B; border: 1px solid #1F1F22; color: #525252;">
44
- {{ item.type === 'project' ? '□' : '◇' }}
45
- </div>
46
- <div class="flex-1 min-w-0">
47
- <div class="text-[12px] font-medium truncate font-[JetBrains_Mono,monospace]" style="color: #E4E4E7;">{{ item.title }}</div>
48
- <div class="text-[10px] truncate" style="color: #525252;">{{ item.subtitle }}</div>
49
- </div>
50
- <StageBadge v-if="item.status" :status="item.status" size="sm" />
51
- </div>
30
+ <div class="flex-1 min-w-0">
31
+ <div class="text-[12px] font-medium truncate font-[JetBrains_Mono,monospace]" style="color: #1C1C1E;">{{ item.title }}</div>
32
+ <div class="text-[10px] truncate" style="color: #6B7280;">{{ item.subtitle }}</div>
52
33
  </div>
53
- </div>
54
-
55
- <!-- Footer -->
56
- <div class="px-4 py-2 flex items-center gap-4 text-[9px] font-mono-log" style="border-top: 1px solid #1F1F22; color: #3A3A3D;">
57
- <span><kbd class="px-1 rounded-sm" style="background: #0A0A0B; border: 1px solid #1F1F22;">↑↓</kbd> nav</span>
58
- <span><kbd class="px-1 rounded-sm" style="background: #0A0A0B; border: 1px solid #1F1F22;">↵</kbd> open</span>
59
- <span><kbd class="px-1 rounded-sm" style="background: #0A0A0B; border: 1px solid #1F1F22;">esc</kbd> close</span>
34
+ <StageBadge v-if="item.status" :status="item.status" size="sm" />
60
35
  </div>
61
36
  </div>
62
37
  </div>
63
- </Transition>
64
- </Teleport>
38
+
39
+ <!-- Footer -->
40
+ <div class="px-4 py-2 flex items-center gap-4 text-[9px] font-mono-log" style="border-top: 1px solid #F0F0F3; color: #D1D1D6;">
41
+ <span><kbd class="px-1 rounded-sm" style="background: #F0F0F3; border: 1px solid #F0F0F3;">↑↓</kbd> 导航</span>
42
+ <span><kbd class="px-1 rounded-sm" style="background: #F0F0F3; border: 1px solid #F0F0F3;">↵</kbd> 打开</span>
43
+ <span><kbd class="px-1 rounded-sm" style="background: #F0F0F3; border: 1px solid #F0F0F3;">esc</kbd> 关闭</span>
44
+ </div>
45
+ </div>
46
+ </n-modal>
65
47
  </template>
66
48
 
67
49
  <script setup>
@@ -76,10 +58,14 @@ const searchInput = ref(null)
76
58
  const selectedIndex = ref(0)
77
59
 
78
60
  const stageNames = [
61
+ { id: 'scan', name: '代码扫描' },
79
62
  { id: 'brainstorm', name: '头脑风暴' },
80
63
  { id: 'plan', name: '规划' },
81
64
  { id: 'execute', name: '执行' },
82
- { id: 'verify', name: '验证' }
65
+ { id: 'verify', name: '验证' },
66
+ { id: 'archive', name: '归档' },
67
+ { id: 'quick', name: '快速任务' },
68
+ { id: 'explore', name: '自由探索' }
83
69
  ]
84
70
 
85
71
  const filteredItems = computed(() => {
@@ -106,12 +92,5 @@ function handleKeydown(e) {
106
92
  else if (e.key === 'Escape') { e.preventDefault(); close() }
107
93
  }
108
94
  watch(filteredItems, () => { selectedIndex.value = 0 })
109
- watch(() => props.isOpen, (v) => { if (v) nextTick(() => { searchInput.value?.focus() }) })
95
+ watch(() => props.isOpen, (v) => { if (v) { nextTick(() => { searchInput.value?.focus() }) } })
110
96
  </script>
111
-
112
- <style scoped>
113
- .backdrop-enter-active, .backdrop-leave-active { transition: opacity 150ms ease; }
114
- .backdrop-enter-from, .backdrop-leave-to { opacity: 0; }
115
- .palette-enter-active, .palette-leave-active { transition: all 200ms cubic-bezier(0.16, 1, 0.3, 1); }
116
- .palette-enter-from, .palette-leave-to { opacity: 0; transform: translate(-50%, -8px) scale(0.98); }
117
- </style>
@@ -1,41 +1,41 @@
1
1
  <template>
2
2
  <div
3
3
  :class="['flex flex-col transition-all duration-300', isOpen ? 'w-[340px]' : 'w-0 opacity-0 overflow-hidden']"
4
- style="background: #111113;"
4
+ style="background: #F5F5F7;"
5
5
  >
6
6
  <!-- Header -->
7
- <div class="px-4 py-3 flex items-center justify-between flex-shrink-0" style="border-bottom: 1px solid #1F1F22;">
8
- <h2 class="text-[11px] font-semibold uppercase tracking-[0.2em] font-[JetBrains_Mono,monospace]" style="color: #525252;">Detail</h2>
9
- <button
10
- @click="$emit('close')"
11
- class="p-1 rounded-sm transition-colors duration-100 hover:bg-white/5"
12
- style="color: #525252;"
13
- >
14
- <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
15
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
16
- </svg>
17
- </button>
7
+ <div class="px-4 py-3 flex items-center justify-between flex-shrink-0" style="border-bottom: 1px solid #F0F0F3;">
8
+ <h2 class="text-[11px] font-semibold uppercase tracking-[0.2em] font-[JetBrains_Mono,monospace]" style="color: #6B7280;">{{ detailType ? detailTitle : '详情' }}</h2>
9
+ <n-button quaternary size="tiny" @click="handleClose">
10
+ <template #icon>
11
+ <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
12
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
13
+ </svg>
14
+ </template>
15
+ </n-button>
18
16
  </div>
19
17
 
20
18
  <!-- Content -->
21
19
  <div class="flex-1 overflow-y-auto">
22
20
  <!-- Empty state -->
23
- <div v-if="!activeStep" class="flex items-center justify-center h-full">
24
- <div class="text-center">
25
- <div class="w-10 h-10 mx-auto mb-3 rounded-md flex items-center justify-center" style="border: 1px dashed #2A2A2D; transform: rotate(45deg);">
26
- <svg class="w-4 h-4" style="color: #3A3A3D; transform: rotate(-45deg);" fill="none" stroke="currentColor" viewBox="0 0 24 24">
27
- <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"/>
28
- </svg>
29
- </div>
30
- <p class="text-[11px] font-[JetBrains_Mono,monospace]" style="color: #3A3A3D;">Select a step</p>
31
- </div>
32
- </div>
21
+ <n-empty v-if="!activeStep && !detailType" description="选择一个步骤" style="margin: auto; padding: 48px 0;" />
33
22
 
34
- <!-- Step detail -->
35
- <div v-else>
23
+ <!-- Detail views -->
24
+ <template v-if="detailType === 'git'">
25
+ <GitDetail :data="detailData" />
26
+ </template>
27
+ <template v-else-if="detailType === 'tech'">
28
+ <TechDetail :data="detailData" />
29
+ </template>
30
+ <template v-else-if="detailType === 'docs'">
31
+ <DocsDetail :data="detailData" @open-file="$emit('open-doc-file', $event)" />
32
+ </template>
33
+
34
+ <!-- Step detail (original) -->
35
+ <div v-else-if="activeStep">
36
36
  <!-- Title -->
37
- <div class="px-4 py-3" style="border-bottom: 1px solid #1F1F22;">
38
- <h3 class="text-[13px] font-semibold font-[JetBrains_Mono,monospace]" style="color: #FBBF24;">
37
+ <div class="px-4 py-3" style="border-bottom: 1px solid #F0F0F3;">
38
+ <h3 class="text-[13px] font-semibold font-[JetBrains_Mono,monospace]" style="color: #D97706;">
39
39
  {{ activeStep.title || activeStep.name }}
40
40
  </h3>
41
41
  <div v-if="activeStep.status" class="mt-2">
@@ -44,48 +44,46 @@
44
44
  </div>
45
45
 
46
46
  <!-- Description -->
47
- <div v-if="activeStep.description || activeStep.summary" class="px-4 py-3" style="border-bottom: 1px solid #1F1F22;">
48
- <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #525252;">Description</h4>
49
- <p class="text-[11px] leading-relaxed" style="color: #8B8B8E;">{{ activeStep.description || activeStep.summary }}</p>
47
+ <div v-if="activeStep.description || activeStep.summary" class="px-4 py-3" style="border-bottom: 1px solid #F0F0F3;">
48
+ <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">描述</h4>
49
+ <p class="text-[11px] leading-relaxed" style="color: #636366;">{{ activeStep.description || activeStep.summary }}</p>
50
50
  </div>
51
51
 
52
52
  <!-- Conclusion -->
53
- <div v-if="activeStep.conclusion" class="px-4 py-3" style="border-bottom: 1px solid #1F1F22;">
54
- <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #525252;">Conclusion</h4>
55
- <p class="text-[11px] leading-relaxed" style="color: #E4E4E7;">{{ activeStep.conclusion }}</p>
53
+ <div v-if="activeStep.conclusion" class="px-4 py-3" style="border-bottom: 1px solid #F0F0F3;">
54
+ <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">结论</h4>
55
+ <p class="text-[11px] leading-relaxed" style="color: #1C1C1E;">{{ activeStep.conclusion }}</p>
56
56
  </div>
57
57
 
58
58
  <!-- Decision -->
59
- <div v-if="activeStep.decision" class="px-4 py-3" style="border-bottom: 1px solid #1F1F22;">
60
- <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #525252;">Decision</h4>
61
- <p class="text-[11px] leading-relaxed" style="color: #E4E4E7;">{{ activeStep.decision }}</p>
59
+ <div v-if="activeStep.decision" class="px-4 py-3" style="border-bottom: 1px solid #F0F0F3;">
60
+ <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">决策</h4>
61
+ <p class="text-[11px] leading-relaxed" style="color: #1C1C1E;">{{ activeStep.decision }}</p>
62
62
  </div>
63
63
 
64
64
  <!-- User Query -->
65
- <div v-if="activeStep.userQuery" class="px-4 py-3" style="border-bottom: 1px solid #1F1F22;">
66
- <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #525252;">User Query</h4>
67
- <div class="px-3 py-2 rounded-md" style="background: #0E0E10; border: 1px solid #1F1F22;">
68
- <p class="text-[11px] italic" style="color: #8B8B8E;">"{{ activeStep.userQuery }}"</p>
65
+ <div v-if="activeStep.userQuery" class="px-4 py-3" style="border-bottom: 1px solid #F0F0F3;">
66
+ <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">用户提问</h4>
67
+ <div class="px-3 py-2 rounded-md" style="background: #F5F5F7; border: 1px solid #F0F0F3;">
68
+ <p class="text-[11px] italic" style="color: #636366;">"{{ activeStep.userQuery }}"</p>
69
69
  </div>
70
70
  </div>
71
71
 
72
72
  <!-- Metadata -->
73
- <div v-if="activeStep.duration || activeStep.timestamp" class="px-4 py-3" style="border-bottom: 1px solid #1F1F22;">
74
- <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #525252;">Meta</h4>
75
- <div class="space-y-1 text-[11px]" style="color: #525252;">
76
- <div v-if="activeStep.duration"><span style="color: #8B8B8E;">Time:</span> {{ activeStep.duration }}</div>
77
- <div v-if="activeStep.timestamp"><span style="color: #8B8B8E;">At:</span> {{ formatTimestamp(activeStep.timestamp) }}</div>
73
+ <div v-if="activeStep.duration || activeStep.timestamp" class="px-4 py-3" style="border-bottom: 1px solid #F0F0F3;">
74
+ <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">元信息</h4>
75
+ <div class="space-y-1 text-[11px]" style="color: #6B7280;">
76
+ <div v-if="activeStep.duration"><span style="color: #636366;">耗时:</span> {{ activeStep.duration }}</div>
77
+ <div v-if="activeStep.timestamp"><span style="color: #636366;">时间:</span> {{ formatTimestamp(activeStep.timestamp) }}</div>
78
78
  </div>
79
79
  </div>
80
80
 
81
81
  <!-- Output -->
82
- <div v-if="activeStep.output || activeStep.files" class="px-4 py-3" style="border-bottom: 1px solid #1F1F22;">
83
- <h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #525252;">Output</h4>
84
- <div v-if="activeStep.output" class="px-3 py-2 rounded-md max-h-40 overflow-y-auto" style="background: #0E0E10; border: 1px solid #1F1F22;">
85
- <pre class="text-[10px] whitespace-pre-wrap font-mono-log" style="color: #8B8B8E;">{{ activeStep.output }}</pre>
86
- </div>
82
+ <div v-if="activeStep.output || activeStep.files" class="px-4 py-3" style="border-bottom: 1px solid #F0F0F3;">
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: 300px; overflow-y: auto; padding: 8px; border-radius: 4px; background: #F5F5F7;" />
87
85
  <div v-if="activeStep.files" class="mt-2 space-y-1">
88
- <div v-for="(file, i) in activeStep.files" :key="i" class="flex items-center gap-2 text-[10px]" style="color: #525252;">
86
+ <div v-for="(file, i) in activeStep.files" :key="i" class="flex items-center gap-2 text-[10px]" style="color: #6B7280;">
89
87
  <svg class="w-3 h-3 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
90
88
  <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"/>
91
89
  </svg>
@@ -97,23 +95,40 @@
97
95
  </div>
98
96
 
99
97
  <!-- Log Stream -->
100
- <div class="flex-shrink-0" style="height: 200px; border-top: 1px solid #1F1F22;">
98
+ <div class="flex-shrink-0" style="height: 200px; border-top: 1px solid #F0F0F3;">
101
99
  <LogStream :logs="logs" @clear="$emit('clear-logs')" />
102
100
  </div>
103
101
  </div>
104
102
  </template>
105
103
 
106
104
  <script setup>
105
+ import { computed } from 'vue'
107
106
  import StageBadge from './StageBadge.vue'
108
107
  import LogStream from './LogStream.vue'
108
+ import GitDetail from './detail/GitDetail.vue'
109
+ import TechDetail from './detail/TechDetail.vue'
110
+ import DocsDetail from './detail/DocsDetail.vue'
109
111
 
110
112
  const props = defineProps({
111
113
  isOpen: { type: Boolean, default: true },
112
114
  activeStep: { type: Object, default: null },
113
- logs: { type: Array, default: () => [] }
115
+ logs: { type: Array, default: () => [] },
116
+ detailType: { type: String, default: null },
117
+ detailData: { type: [Object, Array], default: null }
114
118
  })
115
119
 
116
- const emit = defineEmits(['close', 'clear-logs'])
120
+ const emit = defineEmits(['close', 'clear-logs', 'open-doc-file'])
121
+
122
+ const detailTitle = computed(() => {
123
+ if (props.detailType === 'git') return 'Git 详情'
124
+ if (props.detailType === 'tech') return '技术栈详情'
125
+ if (props.detailType === 'docs') return '文档列表'
126
+ return '详情'
127
+ })
128
+
129
+ function handleClose() {
130
+ emit('close')
131
+ }
117
132
 
118
133
  function formatTimestamp(ts) {
119
134
  if (!ts) return ''