sillyspec 3.8.4 → 3.8.6
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/README.md +0 -6
- package/docs/.vitepress/config.mts +45 -0
- package/docs/.vitepress/dist/404.html +25 -0
- package/docs/.vitepress/dist/assets/app.YytxICdd.js +1 -0
- package/docs/.vitepress/dist/assets/chunks/framework.Czhw_PXq.js +19 -0
- package/docs/.vitepress/dist/assets/chunks/theme.DusTRZQk.js +1 -0
- package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.js +1 -0
- package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.lean.js +1 -0
- 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 +15 -0
- package/docs/.vitepress/dist/assets/sillyspec_commands.md.CXFFsj08.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.js +4 -0
- package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.js +4 -0
- package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.js +5 -0
- package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.js +28 -0
- package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.lean.js +1 -0
- package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.js +30 -0
- package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.lean.js +1 -0
- package/docs/.vitepress/dist/assets/style.DFTx90Kk.css +1 -0
- package/docs/.vitepress/dist/hashmap.json +1 -0
- package/docs/.vitepress/dist/index.html +28 -0
- package/docs/.vitepress/dist/sillyspec/commands.html +42 -0
- package/docs/.vitepress/dist/sillyspec/dashboard.html +31 -0
- package/docs/.vitepress/dist/sillyspec/file-io.html +28 -0
- package/docs/.vitepress/dist/sillyspec/getting-started.html +31 -0
- package/docs/.vitepress/dist/sillyspec/install.html +32 -0
- package/docs/.vitepress/dist/sillyspec/lifecycle.html +55 -0
- package/docs/.vitepress/dist/sillyspec/structure.html +57 -0
- package/docs/.vitepress/dist/vp-icons.css +1 -0
- package/docs/index.md +34 -0
- package/docs/sillyspec/commands.md +218 -0
- package/docs/sillyspec/dashboard.md +51 -0
- package/docs/sillyspec/file-io.md +34 -0
- package/docs/sillyspec/getting-started.md +61 -0
- package/docs/sillyspec/install.md +51 -0
- package/docs/sillyspec/lifecycle.md +146 -0
- package/docs/sillyspec/structure.md +62 -0
- package/package.json +11 -9
- package/packages/dashboard/dist/assets/index-Bh-GPjKY.css +1 -0
- package/packages/dashboard/dist/assets/index-CrCn5Gg6.js +17 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/package-lock.json +0 -220
- package/packages/dashboard/package.json +5 -8
- package/packages/dashboard/server/index.js +106 -255
- package/packages/dashboard/server/parser.js +29 -333
- package/packages/dashboard/server/watcher.js +131 -203
- package/packages/dashboard/src/App.vue +10 -181
- package/packages/dashboard/src/components/ActionBar.vue +42 -26
- package/packages/dashboard/src/components/CommandPalette.vue +65 -40
- package/packages/dashboard/src/components/DetailPanel.vue +53 -68
- package/packages/dashboard/src/components/LogStream.vue +33 -13
- package/packages/dashboard/src/components/PipelineStage.vue +8 -8
- package/packages/dashboard/src/components/PipelineView.vue +45 -80
- package/packages/dashboard/src/components/ProjectList.vue +45 -103
- package/packages/dashboard/src/components/StageBadge.vue +13 -13
- package/packages/dashboard/src/components/StepCard.vue +15 -15
- package/packages/dashboard/src/composables/useDashboard.js +6 -20
- package/packages/dashboard/src/composables/useKeyboard.js +4 -6
- package/packages/dashboard/src/main.js +1 -4
- package/packages/dashboard/src/style.css +17 -17
- package/src/index.js +12 -123
- package/src/init.js +227 -86
- package/src/setup.js +9 -1
- package/templates/archive.md +121 -0
- package/templates/brainstorm.md +240 -0
- package/{.claude/skills/sillyspec-commit/SKILL.md → templates/commit.md} +47 -29
- package/templates/continue.md +32 -0
- package/templates/execute.md +314 -0
- package/templates/explore.md +60 -0
- package/templates/export.md +21 -0
- package/templates/init.md +61 -0
- package/templates/plan.md +157 -0
- package/templates/quick.md +135 -0
- package/templates/scan-quick.md +49 -0
- package/templates/scan.md +172 -0
- package/templates/skills/playwright-e2e/SKILL.md +340 -0
- package/templates/status.md +75 -0
- package/templates/verify.md +253 -0
- package/templates/workspace-sync.md +99 -0
- package/templates/workspace.md +70 -0
- package/.claude/skills/sillyspec-archive/SKILL.md +0 -17
- package/.claude/skills/sillyspec-auto/SKILL.md +0 -77
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +0 -17
- package/.claude/skills/sillyspec-continue/SKILL.md +0 -44
- package/.claude/skills/sillyspec-doctor/SKILL.md +0 -22
- package/.claude/skills/sillyspec-execute/SKILL.md +0 -17
- package/.claude/skills/sillyspec-explore/SKILL.md +0 -96
- package/.claude/skills/sillyspec-export/SKILL.md +0 -53
- package/.claude/skills/sillyspec-init/SKILL.md +0 -170
- package/.claude/skills/sillyspec-plan/SKILL.md +0 -52
- package/.claude/skills/sillyspec-propose/SKILL.md +0 -17
- package/.claude/skills/sillyspec-quick/SKILL.md +0 -17
- package/.claude/skills/sillyspec-resume/SKILL.md +0 -111
- package/.claude/skills/sillyspec-scan/SKILL.md +0 -17
- package/.claude/skills/sillyspec-state/SKILL.md +0 -54
- package/.claude/skills/sillyspec-status/SKILL.md +0 -17
- package/.claude/skills/sillyspec-verify/SKILL.md +0 -17
- package/.claude/skills/sillyspec-workspace/SKILL.md +0 -149
- package/.sillyspec/changes/archive/2026-04-08-derive-state/design.md +0 -97
- package/.sillyspec/changes/archive/2026-04-08-derive-state/plan.md +0 -51
- package/.sillyspec/changes/archive/2026-04-08-derive-state/proposal.md +0 -29
- package/.sillyspec/changes/archive/2026-04-08-derive-state/requirements.md +0 -34
- package/.sillyspec/changes/archive/2026-04-08-derive-state/tasks.md +0 -13
- package/.sillyspec/changes/archive/2026-04-08-derive-state/verify-result.md +0 -43
- package/.sillyspec/changes/auto-mode/design.md +0 -50
- package/.sillyspec/changes/auto-mode/proposal.md +0 -19
- package/.sillyspec/changes/auto-mode/requirements.md +0 -21
- package/.sillyspec/changes/auto-mode/tasks.md +0 -7
- package/.sillyspec/changes/brainstorm-archive/2026-04-05-unified-docs-design.md +0 -199
- package/.sillyspec/changes/dashboard/design.md.braindraft +0 -206
- package/.sillyspec/changes/run-command-design/design.md +0 -1230
- package/.sillyspec/changes/unified-docs-design/design.md +0 -199
- package/.sillyspec/docs/sillyspec/scan/.gitkeep +0 -0
- package/.sillyspec/knowledge/INDEX.md +0 -8
- package/.sillyspec/knowledge/uncategorized.md +0 -3
- package/.sillyspec/projects/sillyspec.yaml +0 -3
- package/packages/dashboard/dist/assets/index-D1EVTLmc.js +0 -7446
- package/packages/dashboard/dist/assets/index-DGe8CqeP.css +0 -1
- package/packages/dashboard/public/logo.jpg +0 -0
- package/packages/dashboard/src/components/DocPreview.vue +0 -160
- package/packages/dashboard/src/components/DocTree.vue +0 -58
- package/packages/dashboard/src/components/ProjectOverview.vue +0 -178
- package/packages/dashboard/src/components/detail/DocsDetail.vue +0 -48
- package/packages/dashboard/src/components/detail/GitDetail.vue +0 -61
- package/packages/dashboard/src/components/detail/TechDetail.vue +0 -43
- package/src/derive.js +0 -147
- package/src/migrate.js +0 -117
- package/src/progress.js +0 -495
- package/src/run.js +0 -640
- package/src/stages/archive.js +0 -54
- package/src/stages/brainstorm.js +0 -239
- package/src/stages/doctor.js +0 -312
- package/src/stages/execute.js +0 -258
- package/src/stages/index.js +0 -35
- package/src/stages/plan.js +0 -259
- package/src/stages/propose.js +0 -115
- package/src/stages/quick.js +0 -64
- package/src/stages/scan.js +0 -141
- package/src/stages/status.js +0 -65
- package/src/stages/verify.js +0 -135
- /package/.sillyspec/{changes/brainstorm-archive → specs}/2026-04-05-dashboard-design.md +0 -0
- /package/{packages/dashboard → docs/.vitepress}/dist/favicon.jpg +0 -0
- /package/{logo.jpg → docs/.vitepress/dist/logo.jpg} +0 -0
- /package/{packages/dashboard → docs}/public/favicon.jpg +0 -0
- /package/{packages/dashboard/dist → docs/public}/logo.jpg +0 -0
|
@@ -1,59 +1,75 @@
|
|
|
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 #
|
|
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;">
|
|
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: #
|
|
10
|
-
<span style="color: #
|
|
9
|
+
<span class="text-[11px] font-[JetBrains_Mono,monospace]" style="color: #525252;">{{ project.name }}</span>
|
|
10
|
+
<span style="color: #1F1F22;">|</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: #
|
|
14
|
-
|
|
13
|
+
<div v-else class="text-[10px] font-[JetBrains_Mono,monospace]" style="color: #3A3A3D;">
|
|
14
|
+
no project
|
|
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: #
|
|
22
|
-
<span class="text-[10px] font-[JetBrains_Mono,monospace]" style="color: #
|
|
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>
|
|
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 ? '#
|
|
26
|
-
{{ executionResult.exitCode === 0 ? '●
|
|
25
|
+
<span class="text-[10px] font-[JetBrains_Mono,monospace]" :style="{ color: executionResult.exitCode === 0 ? '#34D399' : '#EF4444' }">
|
|
26
|
+
{{ executionResult.exitCode === 0 ? '● done' : `● exit ${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
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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>
|
|
40
45
|
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
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>
|
|
44
54
|
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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>
|
|
52
67
|
</div>
|
|
53
68
|
</div>
|
|
54
69
|
</template>
|
|
55
70
|
|
|
56
71
|
<script setup>
|
|
72
|
+
import { computed } from 'vue'
|
|
57
73
|
import StageBadge from './StageBadge.vue'
|
|
58
74
|
|
|
59
75
|
const props = defineProps({
|
|
@@ -1,49 +1,67 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
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>
|
|
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>
|
|
14
6
|
|
|
15
|
-
|
|
16
|
-
<div class="max-
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
<div
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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>
|
|
29
26
|
</div>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
</div>
|
|
28
|
+
|
|
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>
|
|
33
|
+
</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>
|
|
33
52
|
</div>
|
|
34
|
-
<StageBadge v-if="item.status" :status="item.status" size="sm" />
|
|
35
53
|
</div>
|
|
36
|
-
</div>
|
|
37
|
-
</div>
|
|
38
54
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
44
62
|
</div>
|
|
45
|
-
</
|
|
46
|
-
</
|
|
63
|
+
</Transition>
|
|
64
|
+
</Teleport>
|
|
47
65
|
</template>
|
|
48
66
|
|
|
49
67
|
<script setup>
|
|
@@ -88,5 +106,12 @@ function handleKeydown(e) {
|
|
|
88
106
|
else if (e.key === 'Escape') { e.preventDefault(); close() }
|
|
89
107
|
}
|
|
90
108
|
watch(filteredItems, () => { selectedIndex.value = 0 })
|
|
91
|
-
watch(() => props.isOpen, (v) => { if (v)
|
|
109
|
+
watch(() => props.isOpen, (v) => { if (v) nextTick(() => { searchInput.value?.focus() }) })
|
|
92
110
|
</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: #
|
|
4
|
+
style="background: #111113;"
|
|
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 #
|
|
8
|
-
<h2 class="text-[11px] font-semibold uppercase tracking-[0.2em] font-[JetBrains_Mono,monospace]" style="color: #
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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>
|
|
16
18
|
</div>
|
|
17
19
|
|
|
18
20
|
<!-- Content -->
|
|
19
21
|
<div class="flex-1 overflow-y-auto">
|
|
20
22
|
<!-- Empty state -->
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<DocsDetail :data="detailData" @open-file="$emit('open-doc-file', $event)" />
|
|
32
|
-
</template>
|
|
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>
|
|
33
33
|
|
|
34
|
-
<!-- Step detail
|
|
35
|
-
<div v-else
|
|
34
|
+
<!-- Step detail -->
|
|
35
|
+
<div v-else>
|
|
36
36
|
<!-- Title -->
|
|
37
|
-
<div class="px-4 py-3" style="border-bottom: 1px solid #
|
|
38
|
-
<h3 class="text-[13px] font-semibold font-[JetBrains_Mono,monospace]" style="color: #
|
|
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;">
|
|
39
39
|
{{ activeStep.title || activeStep.name }}
|
|
40
40
|
</h3>
|
|
41
41
|
<div v-if="activeStep.status" class="mt-2">
|
|
@@ -44,46 +44,48 @@
|
|
|
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 #
|
|
48
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #
|
|
49
|
-
<p class="text-[11px] leading-relaxed" style="color: #
|
|
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>
|
|
50
50
|
</div>
|
|
51
51
|
|
|
52
52
|
<!-- Conclusion -->
|
|
53
|
-
<div v-if="activeStep.conclusion" class="px-4 py-3" style="border-bottom: 1px solid #
|
|
54
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #
|
|
55
|
-
<p class="text-[11px] leading-relaxed" style="color: #
|
|
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>
|
|
56
56
|
</div>
|
|
57
57
|
|
|
58
58
|
<!-- Decision -->
|
|
59
|
-
<div v-if="activeStep.decision" class="px-4 py-3" style="border-bottom: 1px solid #
|
|
60
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #
|
|
61
|
-
<p class="text-[11px] leading-relaxed" style="color: #
|
|
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>
|
|
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 #
|
|
66
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #
|
|
67
|
-
<div class="px-3 py-2 rounded-md" style="background: #
|
|
68
|
-
<p class="text-[11px] italic" style="color: #
|
|
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>
|
|
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 #
|
|
74
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #
|
|
75
|
-
<div class="space-y-1 text-[11px]" style="color: #
|
|
76
|
-
<div v-if="activeStep.duration"><span style="color: #
|
|
77
|
-
<div v-if="activeStep.timestamp"><span style="color: #
|
|
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>
|
|
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 #
|
|
83
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #
|
|
84
|
-
<
|
|
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>
|
|
85
87
|
<div v-if="activeStep.files" class="mt-2 space-y-1">
|
|
86
|
-
<div v-for="(file, i) in activeStep.files" :key="i" class="flex items-center gap-2 text-[10px]" style="color: #
|
|
88
|
+
<div v-for="(file, i) in activeStep.files" :key="i" class="flex items-center gap-2 text-[10px]" style="color: #525252;">
|
|
87
89
|
<svg class="w-3 h-3 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
88
90
|
<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"/>
|
|
89
91
|
</svg>
|
|
@@ -95,40 +97,23 @@
|
|
|
95
97
|
</div>
|
|
96
98
|
|
|
97
99
|
<!-- Log Stream -->
|
|
98
|
-
<div class="flex-shrink-0" style="height: 200px; border-top: 1px solid #
|
|
100
|
+
<div class="flex-shrink-0" style="height: 200px; border-top: 1px solid #1F1F22;">
|
|
99
101
|
<LogStream :logs="logs" @clear="$emit('clear-logs')" />
|
|
100
102
|
</div>
|
|
101
103
|
</div>
|
|
102
104
|
</template>
|
|
103
105
|
|
|
104
106
|
<script setup>
|
|
105
|
-
import { computed } from 'vue'
|
|
106
107
|
import StageBadge from './StageBadge.vue'
|
|
107
108
|
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'
|
|
111
109
|
|
|
112
110
|
const props = defineProps({
|
|
113
111
|
isOpen: { type: Boolean, default: true },
|
|
114
112
|
activeStep: { type: Object, default: null },
|
|
115
|
-
logs: { type: Array, default: () => [] }
|
|
116
|
-
detailType: { type: String, default: null },
|
|
117
|
-
detailData: { type: [Object, Array], default: null }
|
|
113
|
+
logs: { type: Array, default: () => [] }
|
|
118
114
|
})
|
|
119
115
|
|
|
120
|
-
const emit = defineEmits(['close', 'clear-logs'
|
|
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
|
-
}
|
|
116
|
+
const emit = defineEmits(['close', 'clear-logs'])
|
|
132
117
|
|
|
133
118
|
function formatTimestamp(ts) {
|
|
134
119
|
if (!ts) return ''
|
|
@@ -1,31 +1,51 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="flex flex-col h-full" style="background: #
|
|
2
|
+
<div class="flex flex-col h-full" style="background: #0E0E10;">
|
|
3
3
|
<!-- Header -->
|
|
4
|
-
<div class="px-3 py-2 flex items-center gap-2" style="border-bottom: 1px solid #
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
<div class="px-3 py-2 flex items-center gap-2" style="border-bottom: 1px solid #1F1F22;">
|
|
5
|
+
<input
|
|
6
|
+
v-model="searchQuery"
|
|
7
|
+
type="text"
|
|
8
|
+
placeholder="filter logs..."
|
|
9
|
+
class="flex-1 px-2 py-1 rounded-sm text-[10px] font-mono-log outline-none transition-colors duration-100"
|
|
10
|
+
style="background: #141416; border: 1px solid #1F1F22; color: #8B8B8E;"
|
|
11
|
+
/>
|
|
12
|
+
<button
|
|
13
|
+
@click="clearLogs"
|
|
14
|
+
class="px-2 py-1 text-[10px] rounded-sm transition-colors duration-100"
|
|
15
|
+
style="color: #525252; border: 1px solid #1F1F22;"
|
|
16
|
+
>
|
|
17
|
+
clear
|
|
18
|
+
</button>
|
|
19
|
+
<button
|
|
20
|
+
@click="toggleAutoScroll"
|
|
21
|
+
class="px-2 py-1 text-[10px] rounded-sm font-mono-log transition-colors duration-100"
|
|
22
|
+
:style="{
|
|
23
|
+
color: autoScroll ? '#FBBF24' : '#525252',
|
|
24
|
+
background: autoScroll ? 'rgba(251,191,36,0.08)' : 'transparent',
|
|
25
|
+
border: autoScroll ? '1px solid rgba(251,191,36,0.2)' : '1px solid #1F1F22'
|
|
26
|
+
}"
|
|
27
|
+
>
|
|
28
|
+
{{ autoScroll ? 'auto' : 'pause' }}
|
|
29
|
+
</button>
|
|
10
30
|
</div>
|
|
11
31
|
|
|
12
32
|
<!-- Log output -->
|
|
13
|
-
<div ref="logContainer" class="flex-1 overflow-y-auto px-2 py-1.5 font-mono-log text-[10px]" style="background: #
|
|
33
|
+
<div ref="logContainer" class="flex-1 overflow-y-auto px-2 py-1.5 font-mono-log text-[10px]" style="background: #0A0A0B;" @scroll="handleScroll">
|
|
14
34
|
<div v-if="filteredLogs.length === 0" class="flex items-center justify-center h-full">
|
|
15
|
-
<span class="font-mono-log" style="color: #
|
|
35
|
+
<span class="font-mono-log" style="color: #2A2A2D;">{{ logs.length === 0 ? 'no logs' : 'no match' }}</span>
|
|
16
36
|
</div>
|
|
17
37
|
<div v-else class="space-y-px">
|
|
18
38
|
<div v-for="log in filteredLogs" :key="log.id" class="px-1.5 py-px rounded-sm" :style="{ background: logBg(log.type) }">
|
|
19
|
-
<span style="color: #
|
|
39
|
+
<span style="color: #3A3A3D;" class="select-none">[{{ formatTime(log.timestamp) }}]</span>
|
|
20
40
|
<span :style="{ color: logColor(log.type) }">{{ escapeHtml(log.content) }}</span>
|
|
21
41
|
</div>
|
|
22
42
|
</div>
|
|
23
43
|
</div>
|
|
24
44
|
|
|
25
45
|
<!-- Footer -->
|
|
26
|
-
<div class="px-3 py-1 flex items-center justify-between text-[9px] font-mono-log" style="border-top: 1px solid #
|
|
46
|
+
<div class="px-3 py-1 flex items-center justify-between text-[9px] font-mono-log" style="border-top: 1px solid #1F1F22; background: #0E0E10; color: #3A3A3D;">
|
|
27
47
|
<span>{{ filteredLogs.length }}/{{ logs.length }}</span>
|
|
28
|
-
<span v-if="!autoScroll" style="color: #
|
|
48
|
+
<span v-if="!autoScroll" style="color: #FB923C;">paused</span>
|
|
29
49
|
</div>
|
|
30
50
|
</div>
|
|
31
51
|
</template>
|
|
@@ -49,7 +69,7 @@ const filteredLogs = computed(() => {
|
|
|
49
69
|
function formatTime(ts) { if (!ts) return ''; const d = new Date(ts); return d.toLocaleTimeString('zh-CN', { hour12: false }) }
|
|
50
70
|
function escapeHtml(t) { if (!t) return ''; return t.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') }
|
|
51
71
|
function logBg(t) { return t === 'error' ? 'rgba(239,68,68,0.05)' : t === 'warn' ? 'rgba(251,146,60,0.05)' : 'transparent' }
|
|
52
|
-
function logColor(t) { return t === 'error' ? '#
|
|
72
|
+
function logColor(t) { return t === 'error' ? '#EF4444' : t === 'warn' ? '#FB923C' : t === 'debug' ? '#525252' : '#8B8B8E' }
|
|
53
73
|
function clearLogs() { emit('clear') }
|
|
54
74
|
function toggleAutoScroll() { autoScroll.value = !autoScroll.value; if (autoScroll.value) scrollToBottom() }
|
|
55
75
|
function handleScroll() {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<div class="flex items-center gap-2.5 mb-3">
|
|
17
17
|
<span
|
|
18
18
|
class="text-[12px] font-semibold font-[JetBrains_Mono,monospace] tracking-tight"
|
|
19
|
-
:style="{ color: isActive ? '#
|
|
19
|
+
:style="{ color: isActive ? '#FBBF24' : '#E4E4E7' }"
|
|
20
20
|
>
|
|
21
21
|
{{ title }}
|
|
22
22
|
</span>
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
<!-- Steps -->
|
|
27
27
|
<div class="space-y-1">
|
|
28
|
-
<div v-if="steps.length === 0" class="text-[11px] italic py-1" style="color: #
|
|
28
|
+
<div v-if="steps.length === 0" class="text-[11px] italic py-1" style="color: #525252;">
|
|
29
29
|
No steps yet
|
|
30
30
|
</div>
|
|
31
31
|
<StepCard
|
|
@@ -58,13 +58,13 @@ const props = defineProps({
|
|
|
58
58
|
const emit = defineEmits(['select-step'])
|
|
59
59
|
|
|
60
60
|
const nodeStyle = computed(() => {
|
|
61
|
-
if (props.isActive) return { background: '#
|
|
61
|
+
if (props.isActive) return { background: '#FBBF24', boxShadow: '0 0 8px rgba(251,191,36,0.4)' }
|
|
62
62
|
const colors = {
|
|
63
|
-
'completed': '#
|
|
64
|
-
'in-progress': '#
|
|
65
|
-
'blocked': '#
|
|
66
|
-
'failed': '#
|
|
67
|
-
'pending': '#
|
|
63
|
+
'completed': '#34D399',
|
|
64
|
+
'in-progress': '#FBBF24',
|
|
65
|
+
'blocked': '#FB923C',
|
|
66
|
+
'failed': '#EF4444',
|
|
67
|
+
'pending': '#2A2A2D'
|
|
68
68
|
}
|
|
69
69
|
return { background: colors[props.status] || colors.pending }
|
|
70
70
|
})
|