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,48 +1,48 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div v-if="data?.length" class="px-4 py-3">
|
|
3
|
-
<div v-for="group in data" :key="group.key" class="mb-4">
|
|
4
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">
|
|
5
|
-
{{ group.icon }} {{ group.label }} ({{ group.files.length }})
|
|
6
|
-
</h4>
|
|
7
|
-
<div class="space-y-1">
|
|
8
|
-
<div
|
|
9
|
-
v-for="f in group.files"
|
|
10
|
-
:key="f.path"
|
|
11
|
-
class="flex items-center gap-2 px-2 py-1.5 rounded text-[11px] cursor-pointer hover:bg-[#FEF3C7] transition-colors"
|
|
12
|
-
@click="$emit('open-file', f)"
|
|
13
|
-
>
|
|
14
|
-
<svg class="w-3 h-3 flex-shrink-0" fill="none" stroke="#9CA3AF" viewBox="0 0 24 24">
|
|
15
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
|
|
16
|
-
</svg>
|
|
17
|
-
<span class="truncate" style="color: #1C1C1E;">{{ f.name }}</span>
|
|
18
|
-
<span class="ml-auto flex-shrink-0 font-mono text-[10px]" style="color: #9CA3AF;">{{ formatSize(f.size) }}</span>
|
|
19
|
-
<span class="flex-shrink-0 text-[10px]" style="color: #9CA3AF;">{{ relativeTime(f.mtime) }}</span>
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
</div>
|
|
24
|
-
<n-empty v-else description="无文档" style="padding: 48px 0;" />
|
|
25
|
-
</template>
|
|
26
|
-
|
|
27
|
-
<script setup>
|
|
28
|
-
defineProps({ data: { type: Array, default: () => [] } })
|
|
29
|
-
defineEmits(['open-file'])
|
|
30
|
-
|
|
31
|
-
function formatSize(bytes) {
|
|
32
|
-
if (!bytes) return '—'
|
|
33
|
-
if (bytes < 1024) return bytes + ' B'
|
|
34
|
-
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'
|
|
35
|
-
return (bytes / 1048576).toFixed(1) + ' MB'
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function relativeTime(iso) {
|
|
39
|
-
if (!iso) return ''
|
|
40
|
-
const d = new Date(iso)
|
|
41
|
-
const diff = Date.now() - d.getTime()
|
|
42
|
-
if (diff < 60000) return '刚刚'
|
|
43
|
-
if (diff < 3600000) return `${Math.floor(diff / 60000)} 分钟前`
|
|
44
|
-
if (diff < 86400000) return `${Math.floor(diff / 3600000)} 小时前`
|
|
45
|
-
if (diff < 604800000) return `${Math.floor(diff / 86400000)} 天前`
|
|
46
|
-
return `${d.getMonth() + 1}/${d.getDate()}`
|
|
47
|
-
}
|
|
48
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="data?.length" class="px-4 py-3">
|
|
3
|
+
<div v-for="group in data" :key="group.key" class="mb-4">
|
|
4
|
+
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">
|
|
5
|
+
{{ group.icon }} {{ group.label }} ({{ group.files.length }})
|
|
6
|
+
</h4>
|
|
7
|
+
<div class="space-y-1">
|
|
8
|
+
<div
|
|
9
|
+
v-for="f in group.files"
|
|
10
|
+
:key="f.path"
|
|
11
|
+
class="flex items-center gap-2 px-2 py-1.5 rounded text-[11px] cursor-pointer hover:bg-[#FEF3C7] transition-colors"
|
|
12
|
+
@click="$emit('open-file', f)"
|
|
13
|
+
>
|
|
14
|
+
<svg class="w-3 h-3 flex-shrink-0" fill="none" stroke="#9CA3AF" viewBox="0 0 24 24">
|
|
15
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
|
|
16
|
+
</svg>
|
|
17
|
+
<span class="truncate" style="color: #1C1C1E;">{{ f.name }}</span>
|
|
18
|
+
<span class="ml-auto flex-shrink-0 font-mono text-[10px]" style="color: #9CA3AF;">{{ formatSize(f.size) }}</span>
|
|
19
|
+
<span class="flex-shrink-0 text-[10px]" style="color: #9CA3AF;">{{ relativeTime(f.mtime) }}</span>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
<n-empty v-else description="无文档" style="padding: 48px 0;" />
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script setup>
|
|
28
|
+
defineProps({ data: { type: Array, default: () => [] } })
|
|
29
|
+
defineEmits(['open-file'])
|
|
30
|
+
|
|
31
|
+
function formatSize(bytes) {
|
|
32
|
+
if (!bytes) return '—'
|
|
33
|
+
if (bytes < 1024) return bytes + ' B'
|
|
34
|
+
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'
|
|
35
|
+
return (bytes / 1048576).toFixed(1) + ' MB'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function relativeTime(iso) {
|
|
39
|
+
if (!iso) return ''
|
|
40
|
+
const d = new Date(iso)
|
|
41
|
+
const diff = Date.now() - d.getTime()
|
|
42
|
+
if (diff < 60000) return '刚刚'
|
|
43
|
+
if (diff < 3600000) return `${Math.floor(diff / 60000)} 分钟前`
|
|
44
|
+
if (diff < 86400000) return `${Math.floor(diff / 3600000)} 小时前`
|
|
45
|
+
if (diff < 604800000) return `${Math.floor(diff / 86400000)} 天前`
|
|
46
|
+
return `${d.getMonth() + 1}/${d.getDate()}`
|
|
47
|
+
}
|
|
48
|
+
</script>
|
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div v-if="data" class="px-4 py-3">
|
|
3
|
-
<!-- Branch -->
|
|
4
|
-
<div class="mb-4">
|
|
5
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">当前分支</h4>
|
|
6
|
-
<div class="text-[18px] font-bold font-[JetBrains_Mono,monospace]" style="color: #D97706;">{{ data.branch || '—' }}</div>
|
|
7
|
-
</div>
|
|
8
|
-
|
|
9
|
-
<!-- Commits -->
|
|
10
|
-
<div v-if="data.commits?.length" class="mb-4">
|
|
11
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">最近提交</h4>
|
|
12
|
-
<div class="space-y-2">
|
|
13
|
-
<div v-for="c in data.commits" :key="c.hash" class="px-3 py-2 rounded-md" style="background: #F5F5F7;">
|
|
14
|
-
<div class="flex items-center gap-2">
|
|
15
|
-
<span class="text-[11px] font-mono font-semibold" style="color: #D97706;">{{ c.hash }}</span>
|
|
16
|
-
<span class="text-[11px] flex-1 truncate" style="color: #1C1C1E;">{{ c.message }}</span>
|
|
17
|
-
</div>
|
|
18
|
-
<div class="flex items-center gap-2 mt-1 text-[10px]" style="color: #6B7280;">
|
|
19
|
-
<span>{{ c.author }}</span>
|
|
20
|
-
<span>·</span>
|
|
21
|
-
<span>{{ relativeTime(c.date) }}</span>
|
|
22
|
-
</div>
|
|
23
|
-
</div>
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
<!-- Untracked -->
|
|
28
|
-
<div v-if="data.untracked?.length">
|
|
29
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">未提交文件</h4>
|
|
30
|
-
<div class="space-y-1">
|
|
31
|
-
<div v-for="f in data.untracked" :key="f.file" class="flex items-center gap-2 px-2 py-1 rounded text-[11px] font-[JetBrains_Mono,monospace]">
|
|
32
|
-
<span class="font-semibold w-5 text-center" :style="{ color: statusColor(f.status) }">{{ f.status }}</span>
|
|
33
|
-
<span class="truncate" style="color: #1C1C1E;">{{ f.file }}</span>
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
</div>
|
|
37
|
-
</div>
|
|
38
|
-
<n-empty v-else description="无 Git 信息" style="padding: 48px 0;" />
|
|
39
|
-
</template>
|
|
40
|
-
|
|
41
|
-
<script setup>
|
|
42
|
-
defineProps({ data: { type: Object, default: null } })
|
|
43
|
-
|
|
44
|
-
function statusColor(s) {
|
|
45
|
-
if (s.includes('M')) return '#F59E0B'
|
|
46
|
-
if (s.includes('A') || s === '?') return '#10B981'
|
|
47
|
-
if (s.includes('D')) return '#EF4444'
|
|
48
|
-
return '#9CA3AF'
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function relativeTime(iso) {
|
|
52
|
-
if (!iso) return ''
|
|
53
|
-
const d = new Date(iso)
|
|
54
|
-
const diff = Date.now() - d.getTime()
|
|
55
|
-
if (diff < 60000) return '刚刚'
|
|
56
|
-
if (diff < 3600000) return `${Math.floor(diff / 60000)} 分钟前`
|
|
57
|
-
if (diff < 86400000) return `${Math.floor(diff / 3600000)} 小时前`
|
|
58
|
-
if (diff < 604800000) return `${Math.floor(diff / 86400000)} 天前`
|
|
59
|
-
return `${d.getMonth() + 1}/${d.getDate()}`
|
|
60
|
-
}
|
|
61
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="data" class="px-4 py-3">
|
|
3
|
+
<!-- Branch -->
|
|
4
|
+
<div class="mb-4">
|
|
5
|
+
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-1.5 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">当前分支</h4>
|
|
6
|
+
<div class="text-[18px] font-bold font-[JetBrains_Mono,monospace]" style="color: #D97706;">{{ data.branch || '—' }}</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<!-- Commits -->
|
|
10
|
+
<div v-if="data.commits?.length" class="mb-4">
|
|
11
|
+
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">最近提交</h4>
|
|
12
|
+
<div class="space-y-2">
|
|
13
|
+
<div v-for="c in data.commits" :key="c.hash" class="px-3 py-2 rounded-md" style="background: #F5F5F7;">
|
|
14
|
+
<div class="flex items-center gap-2">
|
|
15
|
+
<span class="text-[11px] font-mono font-semibold" style="color: #D97706;">{{ c.hash }}</span>
|
|
16
|
+
<span class="text-[11px] flex-1 truncate" style="color: #1C1C1E;">{{ c.message }}</span>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="flex items-center gap-2 mt-1 text-[10px]" style="color: #6B7280;">
|
|
19
|
+
<span>{{ c.author }}</span>
|
|
20
|
+
<span>·</span>
|
|
21
|
+
<span>{{ relativeTime(c.date) }}</span>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<!-- Untracked -->
|
|
28
|
+
<div v-if="data.untracked?.length">
|
|
29
|
+
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">未提交文件</h4>
|
|
30
|
+
<div class="space-y-1">
|
|
31
|
+
<div v-for="f in data.untracked" :key="f.file" class="flex items-center gap-2 px-2 py-1 rounded text-[11px] font-[JetBrains_Mono,monospace]">
|
|
32
|
+
<span class="font-semibold w-5 text-center" :style="{ color: statusColor(f.status) }">{{ f.status }}</span>
|
|
33
|
+
<span class="truncate" style="color: #1C1C1E;">{{ f.file }}</span>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<n-empty v-else description="无 Git 信息" style="padding: 48px 0;" />
|
|
39
|
+
</template>
|
|
40
|
+
|
|
41
|
+
<script setup>
|
|
42
|
+
defineProps({ data: { type: Object, default: null } })
|
|
43
|
+
|
|
44
|
+
function statusColor(s) {
|
|
45
|
+
if (s.includes('M')) return '#F59E0B'
|
|
46
|
+
if (s.includes('A') || s === '?') return '#10B981'
|
|
47
|
+
if (s.includes('D')) return '#EF4444'
|
|
48
|
+
return '#9CA3AF'
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function relativeTime(iso) {
|
|
52
|
+
if (!iso) return ''
|
|
53
|
+
const d = new Date(iso)
|
|
54
|
+
const diff = Date.now() - d.getTime()
|
|
55
|
+
if (diff < 60000) return '刚刚'
|
|
56
|
+
if (diff < 3600000) return `${Math.floor(diff / 60000)} 分钟前`
|
|
57
|
+
if (diff < 86400000) return `${Math.floor(diff / 3600000)} 小时前`
|
|
58
|
+
if (diff < 604800000) return `${Math.floor(diff / 86400000)} 天前`
|
|
59
|
+
return `${d.getMonth() + 1}/${d.getDate()}`
|
|
60
|
+
}
|
|
61
|
+
</script>
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div v-if="data" class="px-4 py-3">
|
|
3
|
-
<!-- Frameworks -->
|
|
4
|
-
<div v-if="data.frameworks?.length" class="mb-4">
|
|
5
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">识别框架</h4>
|
|
6
|
-
<div class="flex flex-wrap gap-2">
|
|
7
|
-
<n-tag v-for="f in data.frameworks" :key="f" type="warning" size="small" round>{{ f }}</n-tag>
|
|
8
|
-
</div>
|
|
9
|
-
</div>
|
|
10
|
-
|
|
11
|
-
<!-- Dependencies -->
|
|
12
|
-
<div v-if="depEntries.length" class="mb-4">
|
|
13
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">dependencies ({{ depEntries.length }})</h4>
|
|
14
|
-
<div class="space-y-1">
|
|
15
|
-
<div v-for="[name, ver] in depEntries" :key="name" class="flex items-center gap-2 px-2 py-1 rounded text-[11px]" style="background: #F5F5F7;">
|
|
16
|
-
<span class="font-mono font-medium truncate" style="color: #1C1C1E;">{{ name }}</span>
|
|
17
|
-
<span class="font-mono ml-auto flex-shrink-0" style="color: #9CA3AF;">{{ ver }}</span>
|
|
18
|
-
</div>
|
|
19
|
-
</div>
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
<!-- Dev Dependencies -->
|
|
23
|
-
<div v-if="devDepEntries.length">
|
|
24
|
-
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">devDependencies ({{ devDepEntries.length }})</h4>
|
|
25
|
-
<div class="space-y-1">
|
|
26
|
-
<div v-for="[name, ver] in devDepEntries" :key="name" class="flex items-center gap-2 px-2 py-1 rounded text-[11px]" style="background: #F5F5F7;">
|
|
27
|
-
<span class="font-mono font-medium truncate" style="color: #1C1C1E;">{{ name }}</span>
|
|
28
|
-
<span class="font-mono ml-auto flex-shrink-0" style="color: #9CA3AF;">{{ ver }}</span>
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
32
|
-
</div>
|
|
33
|
-
<n-empty v-else description="无依赖信息" style="padding: 48px 0;" />
|
|
34
|
-
</template>
|
|
35
|
-
|
|
36
|
-
<script setup>
|
|
37
|
-
import { computed } from 'vue'
|
|
38
|
-
|
|
39
|
-
const props = defineProps({ data: { type: Object, default: null } })
|
|
40
|
-
|
|
41
|
-
const depEntries = computed(() => props.data ? Object.entries(props.data.dependencies || {}) : [])
|
|
42
|
-
const devDepEntries = computed(() => props.data ? Object.entries(props.data.devDependencies || {}) : [])
|
|
43
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="data" class="px-4 py-3">
|
|
3
|
+
<!-- Frameworks -->
|
|
4
|
+
<div v-if="data.frameworks?.length" class="mb-4">
|
|
5
|
+
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">识别框架</h4>
|
|
6
|
+
<div class="flex flex-wrap gap-2">
|
|
7
|
+
<n-tag v-for="f in data.frameworks" :key="f" type="warning" size="small" round>{{ f }}</n-tag>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<!-- Dependencies -->
|
|
12
|
+
<div v-if="depEntries.length" class="mb-4">
|
|
13
|
+
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">dependencies ({{ depEntries.length }})</h4>
|
|
14
|
+
<div class="space-y-1">
|
|
15
|
+
<div v-for="[name, ver] in depEntries" :key="name" class="flex items-center gap-2 px-2 py-1 rounded text-[11px]" style="background: #F5F5F7;">
|
|
16
|
+
<span class="font-mono font-medium truncate" style="color: #1C1C1E;">{{ name }}</span>
|
|
17
|
+
<span class="font-mono ml-auto flex-shrink-0" style="color: #9CA3AF;">{{ ver }}</span>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<!-- Dev Dependencies -->
|
|
23
|
+
<div v-if="devDepEntries.length">
|
|
24
|
+
<h4 class="text-[9px] font-semibold uppercase tracking-[0.2em] mb-2 font-[JetBrains_Mono,monospace]" style="color: #6B7280;">devDependencies ({{ devDepEntries.length }})</h4>
|
|
25
|
+
<div class="space-y-1">
|
|
26
|
+
<div v-for="[name, ver] in devDepEntries" :key="name" class="flex items-center gap-2 px-2 py-1 rounded text-[11px]" style="background: #F5F5F7;">
|
|
27
|
+
<span class="font-mono font-medium truncate" style="color: #1C1C1E;">{{ name }}</span>
|
|
28
|
+
<span class="font-mono ml-auto flex-shrink-0" style="color: #9CA3AF;">{{ ver }}</span>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
<n-empty v-else description="无依赖信息" style="padding: 48px 0;" />
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script setup>
|
|
37
|
+
import { computed } from 'vue'
|
|
38
|
+
|
|
39
|
+
const props = defineProps({ data: { type: Object, default: null } })
|
|
40
|
+
|
|
41
|
+
const depEntries = computed(() => props.data ? Object.entries(props.data.dependencies || {}) : [])
|
|
42
|
+
const devDepEntries = computed(() => props.data ? Object.entries(props.data.devDependencies || {}) : [])
|
|
43
|
+
</script>
|