sillyspec 3.20.3 → 3.20.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/sillyspec-archive/SKILL.md +21 -17
- package/.claude/skills/sillyspec-auto/SKILL.md +83 -77
- package/.claude/skills/sillyspec-brainstorm/SKILL.md +44 -17
- package/.claude/skills/sillyspec-commit/SKILL.md +106 -105
- package/.claude/skills/sillyspec-continue/SKILL.md +45 -44
- package/.claude/skills/sillyspec-doctor/SKILL.md +31 -22
- package/.claude/skills/sillyspec-execute/SKILL.md +30 -17
- package/.claude/skills/sillyspec-explore/SKILL.md +109 -96
- package/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
- package/.claude/skills/sillyspec-plan/SKILL.md +21 -52
- package/.claude/skills/sillyspec-propose/SKILL.md +21 -17
- package/.claude/skills/sillyspec-quick/SKILL.md +21 -17
- package/.claude/skills/sillyspec-resume/SKILL.md +68 -111
- package/.claude/skills/sillyspec-scan/SKILL.md +21 -17
- package/.claude/skills/sillyspec-state/SKILL.md +54 -54
- package/.claude/skills/sillyspec-status/SKILL.md +21 -17
- package/.claude/skills/sillyspec-verify/SKILL.md +21 -17
- package/.claude/skills/sillyspec-workspace/SKILL.md +157 -149
- package/.husky/pre-push +13 -0
- package/CLAUDE.md +18 -0
- package/README.md +198 -186
- package/SKILL.md +90 -87
- package/bin/sillyspec.js +2 -2
- package/docs/brainstorm-plan-contract.md +64 -0
- package/docs/plan-execute-contract.md +123 -0
- package/docs/platform-scan-protocol.md +298 -0
- package/docs/revision-mode.md +115 -0
- package/docs/sillyspec/file-lifecycle/known-implementation-gaps.md +99 -0
- package/docs/sillyspec/file-lifecycle/platform-workflows-sync.md +218 -0
- package/docs/sillyspec/file-lifecycle/stage-artifacts.md +167 -0
- package/docs/sillyspec/file-lifecycle/storage-and-state.md +148 -0
- package/docs/sillyspec/file-lifecycle/worktree-and-guard.md +211 -0
- package/docs/sillyspec/file-lifecycle.md +131 -0
- package/docs/workflow-contract-regression.md +106 -0
- package/docs/worktree-isolation.md +252 -0
- package/package.json +40 -34
- package/packages/dashboard/dist/assets/{index-D1EVTLmc.js → index-Bq_Z2hne.js} +7446 -7446
- package/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
- package/packages/dashboard/dist/index.html +16 -16
- package/packages/dashboard/dist/prototype-dashboard.html +836 -0
- package/packages/dashboard/dist/prototype-overview.html +256 -0
- package/packages/dashboard/index.html +15 -15
- package/packages/dashboard/package-lock.json +2384 -2384
- package/packages/dashboard/package.json +25 -25
- package/packages/dashboard/public/prototype-dashboard.html +836 -0
- package/packages/dashboard/public/prototype-overview.html +256 -0
- package/packages/dashboard/server/executor.js +86 -86
- package/packages/dashboard/server/index.js +588 -508
- package/packages/dashboard/server/parser.js +526 -458
- package/packages/dashboard/server/watcher.js +350 -342
- package/packages/dashboard/src/App.vue +558 -325
- package/packages/dashboard/src/components/ActionBar.vue +93 -84
- package/packages/dashboard/src/components/CommandPalette.vue +96 -92
- package/packages/dashboard/src/components/DetailPanel.vue +137 -137
- package/packages/dashboard/src/components/DocPreview.vue +105 -8
- package/packages/dashboard/src/components/DocTree.vue +75 -19
- package/packages/dashboard/src/components/HResizeHandle.vue +48 -0
- package/packages/dashboard/src/components/LogStream.vue +65 -65
- package/packages/dashboard/src/components/PipelineStage.vue +95 -75
- package/packages/dashboard/src/components/PipelineView.vue +156 -129
- package/packages/dashboard/src/components/ProjectCard.vue +187 -0
- package/packages/dashboard/src/components/ProjectList.vue +210 -210
- package/packages/dashboard/src/components/ProjectOverview.vue +113 -139
- package/packages/dashboard/src/components/StageBadge.vue +67 -53
- package/packages/dashboard/src/components/StepCard.vue +94 -89
- package/packages/dashboard/src/components/VResizeHandle.vue +61 -0
- package/packages/dashboard/src/components/detail/DocsDetail.vue +48 -48
- package/packages/dashboard/src/components/detail/GitDetail.vue +61 -61
- package/packages/dashboard/src/components/detail/TechDetail.vue +43 -43
- package/packages/dashboard/src/composables/useDashboard.js +192 -164
- package/packages/dashboard/src/composables/useKeyboard.js +119 -119
- package/packages/dashboard/src/composables/useLayout.js +131 -0
- package/packages/dashboard/src/composables/useWebSocket.js +129 -129
- package/packages/dashboard/src/main.js +8 -8
- package/packages/dashboard/src/style.css +132 -132
- package/packages/dashboard/vite.config.js +18 -18
- package/src/brainstorm-postcheck.js +158 -0
- package/src/change-list.js +52 -0
- package/src/change-risk-profile.js +352 -0
- package/src/classify-change.js +73 -0
- package/src/constants.js +70 -0
- package/src/contract-matrix.js +278 -0
- package/src/db.js +201 -0
- package/src/endpoint-extractor.js +315 -0
- package/src/hooks/claude-pre-tool-use.cjs +125 -0
- package/src/hooks/worktree-guard.js +761 -0
- package/src/index.js +922 -252
- package/src/init.js +470 -375
- package/src/knowledge-match.js +130 -0
- package/src/migrate.js +117 -117
- package/src/modules.js +482 -0
- package/src/progress.js +1734 -508
- package/src/run.js +3465 -652
- package/src/scan-postcheck.js +387 -0
- package/src/setup.js +398 -460
- package/src/stage-contract.js +700 -0
- package/src/stages/archive.js +160 -54
- package/src/stages/brainstorm-auto.js +229 -0
- package/src/stages/brainstorm.js +645 -239
- package/src/stages/doctor.js +365 -312
- package/src/stages/execute.js +634 -264
- package/src/stages/explore.js +34 -0
- package/src/stages/index.js +29 -35
- package/src/stages/knowledge.js +498 -0
- package/src/stages/plan-postcheck.js +518 -0
- package/src/stages/plan.js +582 -279
- package/src/stages/propose.js +174 -115
- package/src/stages/quick.js +102 -63
- package/src/stages/scan.js +558 -141
- package/src/stages/status.js +65 -65
- package/src/stages/verify.js +322 -135
- package/src/sync.js +497 -0
- package/src/task-review.js +346 -0
- package/src/workflow.js +785 -0
- package/src/worktree-apply.js +549 -0
- package/src/worktree-deps.js +185 -0
- package/src/worktree.js +982 -0
- package/templates/workflows/archive-impact.yaml +79 -0
- package/templates/workflows/scan-docs.yaml +132 -0
- package/test/brainstorm-plan-contract.test.mjs +273 -0
- package/test/check-syntax.mjs +26 -0
- package/test/cli-top-level-aliases.test.mjs +174 -0
- package/test/contract-artifacts.test.mjs +323 -0
- package/test/decision-supersede.test.mjs +277 -0
- package/test/knowledge-match.test.mjs +231 -0
- package/test/plan-execute-contract.test.mjs +357 -0
- package/test/plan-optimization.test.mjs +572 -0
- package/test/platform-artifacts.test.mjs +190 -0
- package/test/platform-failure-samples.test.mjs +199 -0
- package/test/platform-recovery-chain.test.mjs +179 -0
- package/test/platform-recovery.test.mjs +167 -0
- package/test/platform-scan-p0.test.mjs +175 -0
- package/test/revision-v1.test.mjs +1145 -0
- package/test/run-sanitize-project-name.test.mjs +51 -0
- package/test/run-scan-postcheck-fail.test.mjs +64 -0
- package/test/run-scan-project-parse.test.mjs +200 -0
- package/test/run-tests.mjs +48 -0
- package/test/runtime-cleanup-keeps-worktree.test.mjs +107 -0
- package/test/scan-docs-yaml-placeholders.test.mjs +84 -0
- package/test/scan-knowledge.test.mjs +175 -0
- package/test/scan-paths.test.mjs +68 -0
- package/test/scan-postcheck-project-priority.test.mjs +85 -0
- package/test/scan-postcheck.test.mjs +197 -0
- package/test/scan-workflow-anyfailed-block.test.mjs +52 -0
- package/test/spec-dir.test.mjs +206 -0
- package/test/stage-contract-failed-post-check.test.mjs +102 -0
- package/test/stage-contract.test.mjs +299 -0
- package/test/stage-definitions.test.mjs +39 -0
- package/test/wait-gates.test.mjs +501 -0
- package/test/workflow-spec-base.test.mjs +142 -0
- package/test/worktree-deps-provision.test.mjs +148 -0
- package/test/worktree-guard.test.mjs +136 -0
- package/test/worktree-native-overlay.test.mjs +188 -0
- 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-dashboard-design.md +0 -206
- package/.sillyspec/changes/brainstorm-archive/2026-04-05-unified-docs-design.md +0 -199
- package/.sillyspec/changes/dashboard/design.md +0 -219
- 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/plans/2026-04-05-dashboard.md +0 -737
- package/.sillyspec/projects/sillyspec.yaml +0 -3
- package/dist/steps/brainstorm/01-load-context.md +0 -30
- package/dist/steps/brainstorm/02-reuse-check.md +0 -6
- package/dist/steps/brainstorm/03-prototype-analysis.md +0 -11
- package/dist/steps/brainstorm/04-module-split.md +0 -23
- package/dist/steps/brainstorm/05-dialog-explore.md +0 -8
- package/dist/steps/brainstorm/06-propose-approaches.md +0 -3
- package/dist/steps/brainstorm/07-present-design.md +0 -3
- package/dist/steps/brainstorm/08-write-design.md +0 -21
- package/dist/steps/brainstorm/09-self-review.md +0 -15
- package/dist/steps/brainstorm/10-user-confirm.md +0 -3
- package/dist/steps/brainstorm/11-output-spec.md +0 -7
- package/dist/steps/brainstorm/manifest.yaml +0 -26
- package/dist/steps/execute/01-load-context.md +0 -41
- package/dist/steps/execute/02-scan-conventions.md +0 -47
- package/dist/steps/execute/03-skill-mcp.md +0 -19
- package/dist/steps/execute/04-assign-task.md +0 -22
- package/dist/steps/execute/04b-prompt-template.md +0 -54
- package/dist/steps/execute/05-write-test.md +0 -7
- package/dist/steps/execute/06-write-code.md +0 -8
- package/dist/steps/execute/07-run-test.md +0 -26
- package/dist/steps/execute/08-fix-issues.md +0 -28
- package/dist/steps/execute/09-next-task.md +0 -33
- package/dist/steps/execute/manifest.yaml +0 -28
- package/dist/steps/plan/01-load-context.md +0 -22
- package/dist/steps/plan/02-anchor-confirm.md +0 -1
- package/dist/steps/plan/03-expand-tasks.md +0 -33
- package/dist/steps/plan/04-mark-order.md +0 -15
- package/dist/steps/plan/05-e2e-planning.md +0 -17
- package/dist/steps/plan/06-self-check.md +0 -16
- package/dist/steps/plan/07-save.md +0 -1
- package/dist/steps/plan/manifest.yaml +0 -18
- package/dist/steps/scan/01-env-detect.md +0 -51
- package/dist/steps/scan/02-tech-stack.md +0 -16
- package/dist/steps/scan/03-conventions.md +0 -16
- package/dist/steps/scan/04-structure.md +0 -19
- package/dist/steps/scan/05-quality.md +0 -18
- package/dist/steps/scan/06-complete.md +0 -49
- package/dist/steps/scan/manifest.yaml +0 -16
- package/dist/steps/verify/01-load-specs.md +0 -28
- package/dist/steps/verify/02-check-tasks.md +0 -1
- package/dist/steps/verify/03-check-design.md +0 -6
- package/dist/steps/verify/04-run-tests.md +0 -7
- package/dist/steps/verify/05-e2e-tests.md +0 -27
- package/dist/steps/verify/05b-e2e-fix.md +0 -33
- package/dist/steps/verify/06-code-quality.md +0 -25
- package/dist/steps/verify/07-lint-check.md +0 -27
- package/dist/steps/verify/08-output-report.md +0 -14
- package/dist/steps/verify/manifest.yaml +0 -22
- package/packages/dashboard/dist/assets/index-DGe8CqeP.css +0 -1
- package/src/derive.js +0 -147
- package/src/step.js +0 -543
|
@@ -1,178 +1,152 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
<!--
|
|
4
|
-
<div class="
|
|
5
|
-
<
|
|
6
|
-
|
|
2
|
+
<div class="overview-section">
|
|
3
|
+
<!-- 头部 -->
|
|
4
|
+
<div class="section-header">
|
|
5
|
+
<h1 class="section-title">
|
|
6
|
+
项目概览
|
|
7
|
+
<span class="badge">{{ projects.length }} 个项目</span>
|
|
8
|
+
</h1>
|
|
9
|
+
<div class="section-actions">
|
|
10
|
+
<button class="btn btn-icon" title="刷新" @click="refresh">↻</button>
|
|
11
|
+
<button class="btn btn-secondary" @click="resetLayout">重置布局</button>
|
|
12
|
+
</div>
|
|
7
13
|
</div>
|
|
8
|
-
<div class="ov-divider" />
|
|
9
14
|
|
|
10
|
-
<!--
|
|
11
|
-
<div class="
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<span class="ov-label">阶段</span>
|
|
20
|
-
<span class="ov-value">{{ project.state.currentStage }}</span>
|
|
21
|
-
</div>
|
|
22
|
-
<div v-else-if="project.state" class="ov-section">
|
|
23
|
-
<span class="ov-label">阶段</span>
|
|
24
|
-
<span class="ov-value" style="color:#9CA3AF;">未执行</span>
|
|
25
|
-
</div>
|
|
26
|
-
<div v-if="project.state?.currentStage" class="ov-divider" />
|
|
27
|
-
|
|
28
|
-
<!-- Last Active -->
|
|
29
|
-
<div v-if="overview.lastActive" class="ov-section">
|
|
30
|
-
<span class="ov-label">最近活跃</span>
|
|
31
|
-
<span class="ov-value">{{ formatTime(overview.lastActive) }}</span>
|
|
32
|
-
</div>
|
|
33
|
-
<div v-if="overview.lastActive" class="ov-divider" />
|
|
34
|
-
|
|
35
|
-
<!-- Doc Stats -->
|
|
36
|
-
<div v-if="overview.docStats.total > 0" class="ov-section ov-clickable" @click="$emit('show-detail', 'docs')">
|
|
37
|
-
<span class="ov-label">文档</span>
|
|
38
|
-
<span class="ov-value">{{ docSummary }}</span>
|
|
39
|
-
</div>
|
|
40
|
-
<div v-if="overview.docStats.total > 0" class="ov-divider" />
|
|
41
|
-
|
|
42
|
-
<!-- Git -->
|
|
43
|
-
<div class="ov-section ov-git ov-clickable" @click="$emit('show-detail', 'git')">
|
|
44
|
-
<span v-if="overview.git.branch" class="ov-branch">{{ overview.git.branch }}</span>
|
|
45
|
-
<span v-if="overview.git.lastCommit" class="ov-commit" :title="overview.git.lastCommit">{{ truncate(overview.git.lastCommit, 40) }}</span>
|
|
46
|
-
<span v-if="overview.git.dirtyCount > 0" class="ov-dirty">{{ overview.git.dirtyCount }} 未提交</span>
|
|
15
|
+
<!-- 卡片容器 -->
|
|
16
|
+
<div class="cards-container">
|
|
17
|
+
<ProjectCard
|
|
18
|
+
v-for="project in projects"
|
|
19
|
+
:key="project.name"
|
|
20
|
+
:project="project"
|
|
21
|
+
:is-selected="activeProject?.name === project.name"
|
|
22
|
+
@select="handleSelect"
|
|
23
|
+
/>
|
|
47
24
|
</div>
|
|
48
25
|
</div>
|
|
49
26
|
</template>
|
|
50
27
|
|
|
51
28
|
<script setup>
|
|
52
|
-
import {
|
|
29
|
+
import { defineProps, defineEmits } from 'vue'
|
|
30
|
+
import ProjectCard from './ProjectCard.vue'
|
|
31
|
+
import { useLayout } from '../composables/useLayout.js'
|
|
53
32
|
|
|
54
33
|
const props = defineProps({
|
|
55
|
-
|
|
34
|
+
projects: { type: Array, default: () => [] },
|
|
35
|
+
activeProject: { type: Object, default: null }
|
|
56
36
|
})
|
|
57
37
|
|
|
58
|
-
defineEmits(['
|
|
59
|
-
|
|
60
|
-
const overview = computed(() => props.project?.overview || { techStack: [], lastActive: null, docStats: { design: 0, plan: 0, archive: 0, changes: 0, scan: 0, quicklog: 0, total: 0 }, git: { branch: '', lastCommit: '', dirtyCount: 0 } })
|
|
61
|
-
|
|
62
|
-
const shortPath = computed(() => {
|
|
63
|
-
const p = props.project?.path || ''
|
|
64
|
-
return p.replace(/^\/Users\/[^/]+/, '~')
|
|
65
|
-
})
|
|
38
|
+
const emit = defineEmits(['select'])
|
|
66
39
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (s.design) parts.push(`设计 ${s.design}`)
|
|
71
|
-
if (s.plan) parts.push(`计划 ${s.plan}`)
|
|
72
|
-
if (s.archive) parts.push(`归档 ${s.archive}`)
|
|
73
|
-
if (s.changes) parts.push(`变更 ${s.changes}`)
|
|
74
|
-
return parts.join(' / ') || `${s.total} 篇`
|
|
75
|
-
})
|
|
40
|
+
function handleSelect(project) {
|
|
41
|
+
emit('select', project)
|
|
42
|
+
}
|
|
76
43
|
|
|
77
|
-
function
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const now = new Date()
|
|
81
|
-
const diffMs = now - d
|
|
82
|
-
if (diffMs < 60000) return '刚刚'
|
|
83
|
-
if (diffMs < 3600000) return `${Math.floor(diffMs / 60000)} 分钟前`
|
|
84
|
-
if (diffMs < 86400000) return `${Math.floor(diffMs / 3600000)} 小时前`
|
|
85
|
-
if (diffMs < 604800000) return `${Math.floor(diffMs / 86400000)} 天前`
|
|
86
|
-
return `${d.getMonth() + 1}/${d.getDate()}`
|
|
44
|
+
function refresh() {
|
|
45
|
+
// TODO: 实现刷新逻辑
|
|
46
|
+
window.location.reload()
|
|
87
47
|
}
|
|
88
48
|
|
|
89
|
-
function
|
|
90
|
-
|
|
49
|
+
function resetLayout() {
|
|
50
|
+
if (confirm('确定要重置布局吗?')) {
|
|
51
|
+
useLayout().resetLayout()
|
|
52
|
+
}
|
|
91
53
|
}
|
|
92
54
|
</script>
|
|
93
55
|
|
|
94
56
|
<style scoped>
|
|
95
|
-
.
|
|
57
|
+
.overview-section {
|
|
58
|
+
height: 100%;
|
|
59
|
+
background: #FFFFFF;
|
|
60
|
+
padding: 16px 24px;
|
|
61
|
+
display: flex;
|
|
62
|
+
flex-direction: column;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.section-header {
|
|
66
|
+
display: flex;
|
|
67
|
+
justify-content: space-between;
|
|
68
|
+
align-items: center;
|
|
69
|
+
margin-bottom: 16px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.section-title {
|
|
73
|
+
font-size: 18px;
|
|
74
|
+
font-weight: 600;
|
|
75
|
+
color: #1A1A1A;
|
|
96
76
|
display: flex;
|
|
97
77
|
align-items: center;
|
|
98
|
-
background: #FFFFFF;
|
|
99
|
-
border-bottom: 1px solid #E5E5EA;
|
|
100
|
-
padding: 8px 16px;
|
|
101
|
-
min-height: 48px;
|
|
102
78
|
gap: 8px;
|
|
103
|
-
flex-shrink: 0;
|
|
104
|
-
overflow-x: auto;
|
|
105
79
|
}
|
|
106
|
-
|
|
80
|
+
|
|
81
|
+
.badge {
|
|
82
|
+
font-size: 12px;
|
|
83
|
+
padding: 2px 8px;
|
|
84
|
+
background: #E5E7EB;
|
|
85
|
+
border-radius: 10px;
|
|
86
|
+
color: #6B7280;
|
|
87
|
+
font-weight: 500;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.section-actions {
|
|
107
91
|
display: flex;
|
|
92
|
+
gap: 8px;
|
|
108
93
|
align-items: center;
|
|
109
|
-
gap: 6px;
|
|
110
|
-
white-space: nowrap;
|
|
111
|
-
flex-shrink: 0;
|
|
112
94
|
}
|
|
113
|
-
|
|
95
|
+
|
|
96
|
+
.btn {
|
|
97
|
+
padding: 6px 12px;
|
|
98
|
+
border-radius: 6px;
|
|
99
|
+
border: none;
|
|
114
100
|
cursor: pointer;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
transition: background 0.15s;
|
|
101
|
+
font-size: 13px;
|
|
102
|
+
font-weight: 500;
|
|
103
|
+
transition: all 0.2s;
|
|
119
104
|
}
|
|
120
|
-
|
|
121
|
-
|
|
105
|
+
|
|
106
|
+
.btn:hover {
|
|
107
|
+
opacity: 0.9;
|
|
122
108
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
color: #
|
|
109
|
+
|
|
110
|
+
.btn-secondary {
|
|
111
|
+
background: #E5E7EB;
|
|
112
|
+
color: #374151;
|
|
127
113
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
114
|
+
|
|
115
|
+
.btn-icon {
|
|
116
|
+
padding: 6px;
|
|
117
|
+
width: 32px;
|
|
118
|
+
height: 32px;
|
|
119
|
+
display: flex;
|
|
120
|
+
align-items: center;
|
|
121
|
+
justify-content: center;
|
|
122
|
+
background: #F3F4F6;
|
|
123
|
+
border-radius: 6px;
|
|
131
124
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
125
|
+
|
|
126
|
+
.btn-icon:hover {
|
|
127
|
+
background: #E5E7EB;
|
|
135
128
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
129
|
+
|
|
130
|
+
.cards-container {
|
|
131
|
+
flex: 1;
|
|
132
|
+
display: flex;
|
|
133
|
+
gap: 16px;
|
|
134
|
+
overflow-x: auto;
|
|
135
|
+
overflow-y: hidden;
|
|
136
|
+
padding-bottom: 8px;
|
|
140
137
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
border-radius: 10px;
|
|
145
|
-
background: rgba(217,119,6,0.08);
|
|
146
|
-
color: #D97706;
|
|
147
|
-
font-weight: 500;
|
|
138
|
+
|
|
139
|
+
.cards-container::-webkit-scrollbar {
|
|
140
|
+
height: 8px;
|
|
148
141
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
background: #E5E5EA;
|
|
153
|
-
flex-shrink: 0;
|
|
154
|
-
}
|
|
155
|
-
.ov-git {
|
|
156
|
-
margin-left: auto;
|
|
157
|
-
gap: 10px;
|
|
158
|
-
}
|
|
159
|
-
.ov-branch {
|
|
160
|
-
font-size: 11px;
|
|
161
|
-
color: #636366;
|
|
162
|
-
background: #F5F5F7;
|
|
163
|
-
padding: 1px 8px;
|
|
142
|
+
|
|
143
|
+
.cards-container::-webkit-scrollbar-track {
|
|
144
|
+
background: #F3F4F6;
|
|
164
145
|
border-radius: 4px;
|
|
165
146
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
overflow: hidden;
|
|
171
|
-
text-overflow: ellipsis;
|
|
172
|
-
}
|
|
173
|
-
.ov-dirty {
|
|
174
|
-
font-size: 11px;
|
|
175
|
-
color: #D97706;
|
|
176
|
-
font-weight: 500;
|
|
147
|
+
|
|
148
|
+
.cards-container::-webkit-scrollbar-thumb {
|
|
149
|
+
background: #D1D5DB;
|
|
150
|
+
border-radius: 4px;
|
|
177
151
|
}
|
|
178
152
|
</style>
|
|
@@ -1,53 +1,67 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<span
|
|
3
|
-
:class="['inline-flex items-center gap-1.5 rounded-sm text-[10px] font-medium font-[JetBrains_Mono,monospace] uppercase tracking-wider transition-colors duration-150', sizeClass]"
|
|
4
|
-
:style="badgeStyle"
|
|
5
|
-
>
|
|
6
|
-
<span :class="['w-1 h-1 rounded-full', dotClass]" :style="dotStyle" />
|
|
7
|
-
<span>{{ displayLabel }}</span>
|
|
8
|
-
</span>
|
|
9
|
-
</template>
|
|
10
|
-
|
|
11
|
-
<script setup>
|
|
12
|
-
import { computed } from 'vue'
|
|
13
|
-
|
|
14
|
-
const props = defineProps({
|
|
15
|
-
status: { type: String, default: 'pending' },
|
|
16
|
-
label: { type: String, default: '' },
|
|
17
|
-
size: { type: String, default: 'md' }
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
const displayLabel = computed(() => {
|
|
21
|
-
if (props.label) return props.label
|
|
22
|
-
const labels = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
'
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return
|
|
52
|
-
})
|
|
53
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<span
|
|
3
|
+
:class="['inline-flex items-center gap-1.5 rounded-sm text-[10px] font-medium font-[JetBrains_Mono,monospace] uppercase tracking-wider transition-colors duration-150', sizeClass]"
|
|
4
|
+
:style="badgeStyle"
|
|
5
|
+
>
|
|
6
|
+
<span :class="['w-1 h-1 rounded-full', dotClass]" :style="dotStyle" />
|
|
7
|
+
<span>{{ displayLabel }}</span>
|
|
8
|
+
</span>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup>
|
|
12
|
+
import { computed } from 'vue'
|
|
13
|
+
|
|
14
|
+
const props = defineProps({
|
|
15
|
+
status: { type: String, default: 'pending' },
|
|
16
|
+
label: { type: String, default: '' },
|
|
17
|
+
size: { type: String, default: 'md' }
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const displayLabel = computed(() => {
|
|
21
|
+
if (props.label) return props.label
|
|
22
|
+
const labels = {
|
|
23
|
+
'completed': 'done',
|
|
24
|
+
'in-progress': 'running',
|
|
25
|
+
'blocked': 'blocked',
|
|
26
|
+
'failed': 'error',
|
|
27
|
+
'revising': 'revising',
|
|
28
|
+
'stale': 'stale',
|
|
29
|
+
'waiting': 'waiting',
|
|
30
|
+
}
|
|
31
|
+
return labels[props.status] || ''
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const sizeClass = computed(() => props.size === 'sm' ? 'px-1.5 py-0.5' : 'px-2 py-1')
|
|
35
|
+
|
|
36
|
+
const badgeStyle = computed(() => {
|
|
37
|
+
const styles = {
|
|
38
|
+
'completed': { background: 'rgba(22,163,74,0.1)', color: '#16A34A' },
|
|
39
|
+
'in-progress': { background: 'rgba(251,191,36,0.1)', color: '#D97706' },
|
|
40
|
+
'blocked': { background: 'rgba(251,146,60,0.1)', color: '#EA580C' },
|
|
41
|
+
'failed': { background: 'rgba(239,68,68,0.1)', color: '#DC2626' },
|
|
42
|
+
'pending': { background: 'rgba(82,82,82,0.15)', color: '#6B7280' },
|
|
43
|
+
'revising': { background: 'rgba(139,92,246,0.1)', color: '#7C3AED' },
|
|
44
|
+
'stale': { background: 'rgba(234,179,8,0.1)', color: '#CA8A04' },
|
|
45
|
+
'waiting': { background: 'rgba(59,130,246,0.1)', color: '#2563EB' },
|
|
46
|
+
}
|
|
47
|
+
return styles[props.status] || styles.pending
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const dotClass = computed(() => {
|
|
51
|
+
return props.status === 'in-progress' ? 'animate-pulse-dot' : ''
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const dotStyle = computed(() => {
|
|
55
|
+
const colors = {
|
|
56
|
+
'completed': '#16A34A',
|
|
57
|
+
'in-progress': '#D97706',
|
|
58
|
+
'blocked': '#EA580C',
|
|
59
|
+
'failed': '#DC2626',
|
|
60
|
+
'pending': '#6B7280',
|
|
61
|
+
'revising': '#7C3AED',
|
|
62
|
+
'stale': '#CA8A04',
|
|
63
|
+
'waiting': '#2563EB',
|
|
64
|
+
}
|
|
65
|
+
return { background: colors[props.status] || '#6B7280' }
|
|
66
|
+
})
|
|
67
|
+
</script>
|
|
@@ -1,89 +1,94 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
:class="['group relative rounded-md cursor-pointer transition-all duration-200']"
|
|
4
|
-
:style="cardStyle"
|
|
5
|
-
@mouseenter="hovered = true"
|
|
6
|
-
@mouseleave="hovered = false"
|
|
7
|
-
@click="handleClick"
|
|
8
|
-
>
|
|
9
|
-
<!-- Left accent bar -->
|
|
10
|
-
<div class="absolute left-0 top-0 bottom-0 w-[2px]" :style="{ background: barColor }" />
|
|
11
|
-
|
|
12
|
-
<div class="pl-4 pr-4 py-3">
|
|
13
|
-
<div class="flex items-center gap-2">
|
|
14
|
-
<h3 class="text-[12px] font-medium transition-colors duration-150" :style="{ color: isActive ? '#D97706' : '#1C1C1E', fontFamily: '\'JetBrains Mono\', monospace' }">
|
|
15
|
-
{{ step.title || step.name }}
|
|
16
|
-
</h3>
|
|
17
|
-
<StageBadge v-if="step.status" :status="step.status" :label="statusLabel" />
|
|
18
|
-
</div>
|
|
19
|
-
|
|
20
|
-
<!-- Hover summary -->
|
|
21
|
-
<div
|
|
22
|
-
v-if="step.summary || step.description"
|
|
23
|
-
class="transition-all duration-200"
|
|
24
|
-
:style="{ maxHeight: hovered ? '80px' : '0', opacity: hovered ? 1 : 0, overflow: 'hidden' }"
|
|
25
|
-
>
|
|
26
|
-
<p class="mt-1.5 text-[11px] line-clamp-2" style="color: #636366;">
|
|
27
|
-
{{ step.summary || step.description }}
|
|
28
|
-
</p>
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<!-- Active details -->
|
|
32
|
-
<div v-if="isActive" class="mt-2 space-y-1">
|
|
33
|
-
<p v-if="step.conclusion" class="text-[11px]" style="color: #1C1C1E;">
|
|
34
|
-
<span style="color: #D97706; font-weight: 600;">结论:</span> {{ step.conclusion }}
|
|
35
|
-
</p>
|
|
36
|
-
<p v-if="step.decision" class="text-[11px]" style="color: #1C1C1E;">
|
|
37
|
-
<span style="color: #D97706; font-weight: 600;">决策:</span> {{ step.decision }}
|
|
38
|
-
</p>
|
|
39
|
-
<p v-if="step.userQuery" class="text-[11px] italic" style="color: #636366;">
|
|
40
|
-
"{{ step.userQuery }}"
|
|
41
|
-
</p>
|
|
42
|
-
</div>
|
|
43
|
-
|
|
44
|
-
<div v-if="step.duration" class="mt-1 text-[10px] font-mono-log" style="color: #6B7280;">
|
|
45
|
-
{{ step.duration }}
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
</template>
|
|
50
|
-
|
|
51
|
-
<script setup>
|
|
52
|
-
import { ref, computed } from 'vue'
|
|
53
|
-
import StageBadge from './StageBadge.vue'
|
|
54
|
-
|
|
55
|
-
const props = defineProps({
|
|
56
|
-
step: { type: Object, required: true },
|
|
57
|
-
isActive: { type: Boolean, default: false },
|
|
58
|
-
isClickable: { type: Boolean, default: true }
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
const emit = defineEmits(['select'])
|
|
62
|
-
const hovered = ref(false)
|
|
63
|
-
|
|
64
|
-
const barColor = computed(() => {
|
|
65
|
-
const colors = {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:class="['group relative rounded-md cursor-pointer transition-all duration-200']"
|
|
4
|
+
:style="cardStyle"
|
|
5
|
+
@mouseenter="hovered = true"
|
|
6
|
+
@mouseleave="hovered = false"
|
|
7
|
+
@click="handleClick"
|
|
8
|
+
>
|
|
9
|
+
<!-- Left accent bar -->
|
|
10
|
+
<div class="absolute left-0 top-0 bottom-0 w-[2px]" :style="{ background: barColor }" />
|
|
11
|
+
|
|
12
|
+
<div class="pl-4 pr-4 py-3">
|
|
13
|
+
<div class="flex items-center gap-2">
|
|
14
|
+
<h3 class="text-[12px] font-medium transition-colors duration-150" :style="{ color: isActive ? '#D97706' : '#1C1C1E', fontFamily: '\'JetBrains Mono\', monospace' }">
|
|
15
|
+
{{ step.title || step.name }}
|
|
16
|
+
</h3>
|
|
17
|
+
<StageBadge v-if="step.status" :status="step.status" :label="statusLabel" />
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<!-- Hover summary -->
|
|
21
|
+
<div
|
|
22
|
+
v-if="step.summary || step.description"
|
|
23
|
+
class="transition-all duration-200"
|
|
24
|
+
:style="{ maxHeight: hovered ? '80px' : '0', opacity: hovered ? 1 : 0, overflow: 'hidden' }"
|
|
25
|
+
>
|
|
26
|
+
<p class="mt-1.5 text-[11px] line-clamp-2" style="color: #636366;">
|
|
27
|
+
{{ step.summary || step.description }}
|
|
28
|
+
</p>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<!-- Active details -->
|
|
32
|
+
<div v-if="isActive" class="mt-2 space-y-1">
|
|
33
|
+
<p v-if="step.conclusion" class="text-[11px]" style="color: #1C1C1E;">
|
|
34
|
+
<span style="color: #D97706; font-weight: 600;">结论:</span> {{ step.conclusion }}
|
|
35
|
+
</p>
|
|
36
|
+
<p v-if="step.decision" class="text-[11px]" style="color: #1C1C1E;">
|
|
37
|
+
<span style="color: #D97706; font-weight: 600;">决策:</span> {{ step.decision }}
|
|
38
|
+
</p>
|
|
39
|
+
<p v-if="step.userQuery" class="text-[11px] italic" style="color: #636366;">
|
|
40
|
+
"{{ step.userQuery }}"
|
|
41
|
+
</p>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div v-if="step.duration" class="mt-1 text-[10px] font-mono-log" style="color: #6B7280;">
|
|
45
|
+
{{ step.duration }}
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<script setup>
|
|
52
|
+
import { ref, computed } from 'vue'
|
|
53
|
+
import StageBadge from './StageBadge.vue'
|
|
54
|
+
|
|
55
|
+
const props = defineProps({
|
|
56
|
+
step: { type: Object, required: true },
|
|
57
|
+
isActive: { type: Boolean, default: false },
|
|
58
|
+
isClickable: { type: Boolean, default: true }
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const emit = defineEmits(['select'])
|
|
62
|
+
const hovered = ref(false)
|
|
63
|
+
|
|
64
|
+
const barColor = computed(() => {
|
|
65
|
+
const colors = {
|
|
66
|
+
'completed': '#16A34A', 'in-progress': '#D97706', 'blocked': '#EA580C', 'failed': '#DC2626', 'pending': '#E5E5EA',
|
|
67
|
+
'revising': '#7C3AED', 'stale': '#CA8A04', 'waiting': '#2563EB',
|
|
68
|
+
}
|
|
69
|
+
return colors[props.step.status] || colors.pending
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const cardStyle = computed(() => ({
|
|
73
|
+
background: props.isActive ? 'rgba(217,119,6,0.08)' : (hovered.value ? 'rgba(0,0,0,0.02)' : '#FFFFFF'),
|
|
74
|
+
border: `1px solid ${props.isActive ? 'rgba(251,191,36,0.2)' : '#F0F0F3'}`,
|
|
75
|
+
}))
|
|
76
|
+
|
|
77
|
+
const statusLabel = computed(() => {
|
|
78
|
+
const labels = { 'completed': '完成', 'in-progress': '进行中', 'blocked': '阻塞', 'failed': '失败', 'pending': '待办',
|
|
79
|
+
'revising': '修订中', 'stale': '已失效', 'waiting': '等待中',
|
|
80
|
+
}
|
|
81
|
+
return labels[props.step.status] || '待办'
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
function handleClick() { if (props.isClickable) emit('select', props.step) }
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<style scoped>
|
|
88
|
+
.line-clamp-2 {
|
|
89
|
+
display: -webkit-box;
|
|
90
|
+
-webkit-line-clamp: 2;
|
|
91
|
+
-webkit-box-orient: vertical;
|
|
92
|
+
overflow: hidden;
|
|
93
|
+
}
|
|
94
|
+
</style>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="v-resize-handle"
|
|
4
|
+
:class="{ 'dragging': isDragging }"
|
|
5
|
+
@mousedown="handleMouseDown"
|
|
6
|
+
>
|
|
7
|
+
<div class="drag-indicator"></div>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup>
|
|
12
|
+
const props = defineProps({
|
|
13
|
+
isDragging: { type: Boolean, default: false }
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const emit = defineEmits(['drag-start', 'drag-end', 'resize'])
|
|
17
|
+
|
|
18
|
+
function handleMouseDown(e) {
|
|
19
|
+
emit('drag-start', { type: 'vertical', startY: e.clientY })
|
|
20
|
+
|
|
21
|
+
const onMove = (ev) => {
|
|
22
|
+
emit('resize', { deltaY: ev.clientY - e.clientY })
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const onUp = () => {
|
|
26
|
+
emit('drag-end')
|
|
27
|
+
window.removeEventListener('mousemove', onMove)
|
|
28
|
+
window.removeEventListener('mouseup', onUp)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
window.addEventListener('mousemove', onMove)
|
|
32
|
+
window.addEventListener('mouseup', onUp)
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<style scoped>
|
|
37
|
+
.v-resize-handle {
|
|
38
|
+
height: 6px;
|
|
39
|
+
background: #2A3040;
|
|
40
|
+
cursor: row-resize;
|
|
41
|
+
position: relative;
|
|
42
|
+
transition: background 0.2s;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.v-resize-handle:hover,
|
|
46
|
+
.v-resize-handle.dragging {
|
|
47
|
+
background: #D97706;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.drag-indicator {
|
|
51
|
+
position: absolute;
|
|
52
|
+
top: 50%;
|
|
53
|
+
left: 50%;
|
|
54
|
+
transform: translate(-50%, -50%);
|
|
55
|
+
width: 40px;
|
|
56
|
+
height: 4px;
|
|
57
|
+
background: rgba(255, 255, 255, 0.3);
|
|
58
|
+
border-radius: 2px;
|
|
59
|
+
pointer-events: none;
|
|
60
|
+
}
|
|
61
|
+
</style>
|